I'm making a way for users to insert a footnote in the text (as implemented in scientific articles). I'm using tinymce for this, and it functions as a plugin. It works fine when I type the text itself. But as soon as I try to insert a footnote with it into the copied text (that is, I copied text from another site and want to insert a footnote), it gives me an error - Uncaught ReferenceError: $node is not defined
I've already tried many attempts, but I can't get it to work. Can you please tell me what I am doing wrong?
footnote.min.js
! function () {
"use strict";
var t, e = tinymce.util.Tools.resolve("tinymce.PluginManager");
"function" != typeof Array.prototype.forEach && (Array.prototype.forEach = function (t) {
for (var e = 0; e < this.length; e++) t.apply(this, [this[e], e, this])
}), Object.defineProperty && Object.getOwnPropertyDescriptor && Object.getOwnPropertyDescriptor(Element.prototype, "textContent") && !Object.getOwnPropertyDescriptor(Element.prototype, "textContent").get && (t = Object.getOwnPropertyDescriptor(Element.prototype, "innerText"), Object.defineProperty(Element.prototype, "textContent", {
get: function () {
return t.get.call(this)
},
set: function (e) {
return t.set.call(this, e)
}
}));
var n = function (t, e) {
var n = t;
for (var o in e) n = n.replace(/\{(\/?[^\}]+)\}/gm, e[o]);
return n
},
o = function (t) {
var e = t.selection.getNode(),
o = "",
r = "SPAN" == e.tagName && "fnoteWrap" === t.dom.getAttrib(e, "class"),
i = "fnoteWrap" == e.className ? e.childNodes[0].firstChild.nodeValue.replace(/[^0-9]/g, "") : e.childNodes[0];
r && (o = e.name || decodeURIComponent(e.childNodes[0].getAttribute("data-content")) || ""), t.windowManager.open({
title: "Insert Contents",
size: "normal",
body: {
type: "panel",
items: [{
type: "textarea",
name: "name",
multiline: !0,
minWidth: 520,
minHeight: 100
}]
},
buttons: [{
type: "cancel",
name: "cancel",
text: "Cancel"
}, {
type: "submit",
name: "save",
text: "Save",
primary: !0
}],
initialData: {
name: o
},
onSubmit: function (e) {
var o, r, a, c, l = e.getData().name,
s = '<span class="fnoteWrap" id="#wk_ft{FOOTNOTE_INDEX}" contenteditable="false"><button type="button" class="fnoteBtn" data-content="' + l + '">{FOOTNOTE_INDEX}</button></span>',
f = t.getDoc().querySelectorAll(".fnoteBtn"),
u = f.length,
p = (r = t.selection.getNode(), a = function (t) {
var e = !1;
return (e = [].filter.call(t.parentNode.children, function (n) {
return n.previousElementSibling === t ? e = !0 : e
})).map(e => Array.from(e.querySelectorAll("fnoteBtn").length) > 0 ? $node.nextElementSibling.classList.contains("fnoteBtn") ? $node.nextElementSibling.children.children : e.querySelectorAll(".fnoteBtn") : "BODY" === t.nodeName ? [] : a(t.parentNode))
}, c = function (t, e) {
if (!e) return !1;
if (e) return $node;
var n = null;
return e.children.forEach(function () {
e && (n = c(t, this))
}), n
}, function (t, e) {
for (var n = a(e); 0 !== n.length;) {
var o = c(t, n);
if (null !== o) return o;
n = a(n)
}
return n
}(".fnoteBtn", r));
if (p.length) {
var d;
for (p = p[0], d = 0; d < u && p != f[d]; d++);
i < u ? o = n(s, {
FOOTNOTE_INDEX: $(f[i - 1]).html()
}) : (o = n(s, {
FOOTNOTE_INDEX: $(f[d]).html()
}), t.selection.collapse(0))
} else o = n(s, {
FOOTNOTE_INDEX: u + 1
}), t.selection.collapse(0);
t.execCommand("mceInsertContent", !1, o), e.close(), Array.from(t.getDoc().querySelectorAll(".fnoteBtn")).forEach(function (t, e) {
t.textContent = e + 1, t.parentNode.setAttribute("id", "#wk_ft" + (e + 1))
})
}
})
},
r = {
register: function (t) {
t.addCommand("footnotes", function () {
o(t)
})
}
},
i = {
register: function (t) {
t.ui.registry.addToggleButton("footnotes", {
icon: "fnote",
tooltip: "Footnote",
onAction: function () {
return t.execCommand("footnotes")
},
onSetup: function (e) {
return t.selection.selectorChangedWithUnbind("span.fnoteWrap", e.setActive).unbind
}
}), t.ui.registry.addMenuItem("footnotes", {
icon: "fnote",
onAction: function () {
return t.execCommand("footnotes")
}
})
}
};
e.add("footnotes", function (t) {
t.ui.registry.addIcon("fnote", '<img src="' + tinyMCE.baseURL + '/plugins/footnotes/img/fn.png">'), r.register(t), i.register(t)
})
}();
footnote.js
(function(){
'use strict';
var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
if (typeof Array.prototype.forEach !== 'function') {
Array.prototype.forEach = function(cb){
for (var i = 0; i < this.length; i++){
cb.apply(this, [this[i], i, this]);
}
};
}
if (Object.defineProperty
&& Object.getOwnPropertyDescriptor
&& Object.getOwnPropertyDescriptor(Element.prototype, "textContent")
&& !Object.getOwnPropertyDescriptor(Element.prototype, "textContent").get) {
(function() {
var innerText = Object.getOwnPropertyDescriptor(Element.prototype, "innerText");
Object.defineProperty(Element.prototype, "textContent",
{
get: function() {
return innerText.get.call(this);
},
set: function(s) {
return innerText.set.call(this, s);
}
}
);
})();
}
/**
*
* #param str
* #param data
* #returns {*}
*/
var replaceTmpl = function(str, data) {
var result = str;
for (var key in data) {
result = result.replace(/\{(\/?[^\}]+)\}/gm,data[key]);
}
return result;
};
/**
*
* #param editor
*/
var open = function (editor) {
var selectedNode = editor.selection.getNode(), name = '',
isFootNotes = selectedNode.tagName == 'SPAN' && editor.dom.getAttrib(selectedNode, 'class') === 'fnoteWrap';
var selectIndex = (function(){
if (selectedNode.className == 'fnoteWrap') {
var num = selectedNode.childNodes[0].firstChild.nodeValue.replace(/[^0-9]/g,'');
return num;
}
else {
return selectedNode.childNodes[0];
}
}());
if (isFootNotes) {
name = selectedNode.name || decodeURIComponent(selectedNode.childNodes[0].getAttribute('data-content')) || '';
}
editor.windowManager.open({
title: 'Insert Contents',
size: 'normal',
body: {
type: 'panel',
items : [
{
type:'textarea',
name: 'name',
multiline: true,
minWidth: 520,
minHeight: 100,
}
],
},
buttons: [
{
type: 'cancel',
name: 'cancel',
text: 'Cancel'
},
{
type: 'submit',
name: 'save',
text: 'Save',
primary: true
}
],
initialData: { name: name },
onSubmit: function (e) {
var newfootnoteContent = e.getData().name,
fixFootnoteContent = (function () {
return encodeURIComponent(newfootnoteContent);
}()),
htmlTemplate = '<span class="fnoteWrap" id="#wk_ft{FOOTNOTE_INDEX}" contenteditable="false"><button type="button" class="fnoteBtn" data-content="'+fixFootnoteContent+'">{FOOTNOTE_INDEX}</button></span>',
totalFootNote = editor.getDoc().querySelectorAll('.fnoteBtn'),
totalCount = totalFootNote.length,
html;
function findNextFD(node) {
var getNext = function(el) {
var nextAll = false,
elements;
nextAll = [].filter.call(el.parentNode.children, function (htmlElement) {
return (htmlElement.previousElementSibling === el) ? nextAll = true : nextAll;
});
return nextAll.map(v => {
if (Array.from(v.querySelectorAll('fnoteBtn').length) > 0) {
$node.nextElementSibling.classList.contains('fnoteBtn') ?
elements = $node.nextElementSibling.children.children :
elements = v.querySelectorAll('.fnoteBtn');
return elements
}
else {
if (el.nodeName === 'BODY') return [];
return getNext(el.parentNode);
}
})
}
var nextInDOM = function(_selector, el) {
var next = getNext(el);
while(next.length !== 0) {
var found = searchFor(_selector, next);
if(found !== null) {
return found;
}
next = getNext(next);
}
return next;
}
var searchFor = function(_selector, el) {
if (!el) {return false};
if(el) {
return $node;
}
else {
var found = null;
el.children.forEach(function() {
if (el)
found = searchFor(_selector, this);
});
return found;
}
return null;
}
var currentClassNot_NextClass = nextInDOM('.fnoteBtn', node);
return currentClassNot_NextClass;
}
var nextFD = findNextFD(editor.selection.getNode());
if(nextFD.length) {
nextFD = nextFD[0];
var foundIdx;
for(foundIdx = 0; foundIdx < totalCount; foundIdx++) {
if(nextFD == totalFootNote[foundIdx]) {
break;
}
}
if (selectIndex < totalCount) {
// modify
html = replaceTmpl(htmlTemplate,{FOOTNOTE_INDEX : $(totalFootNote[selectIndex-1]).html()});
}
else {
// anywhere add
html = replaceTmpl(htmlTemplate,{FOOTNOTE_INDEX : $(totalFootNote[foundIdx]).html()});
editor.selection.collapse(0);
}
} else {
// last add
html = replaceTmpl(htmlTemplate,{FOOTNOTE_INDEX : totalCount + 1});
editor.selection.collapse(0);
}
editor.execCommand('mceInsertContent', false, html);
e.close()
// index realignment
var fnoteBtn = Array.from(editor.getDoc().querySelectorAll('.fnoteBtn'));
fnoteBtn.forEach(function(value,idx){
value.textContent = idx+1;
value.parentNode.setAttribute('id','#wk_ft' + (idx +1))
})
}
});
};
var Dialog = { open: open };
var register$1 = function (editor) {
editor.ui.registry.addToggleButton('footnotes', {
icon : 'fnote',
tooltip : 'Footnote',
onAction: function () {
return editor.execCommand('footnotes');
},
onSetup: function (buttonApi) {
return editor.selection.selectorChangedWithUnbind('span.fnoteWrap', buttonApi.setActive).unbind;
}
});
editor.ui.registry.addMenuItem('footnotes', {
icon: 'fnote',
onAction: function () {
return editor.execCommand('footnotes');
}
});
};
var register = function (editor) {
editor.addCommand('footnotes', function () {
Dialog.open(editor);
});
};
var Commands = { register: register };
var Buttons = { register: register$1 };
function Plugin () {
global.add('footnotes', function (editor) {
editor.ui.registry.addIcon('fnote','<img src="'+ tinyMCE.baseURL + '/plugins/footnotes/img/fn.png' +'">')
Commands.register(editor);
Buttons.register(editor);
});
}
Plugin();
})()
You are passing in findNextFD(node) there is no variable named $node inside that function. Try it without the $ in front of node, and add some logic to make sure node !== null at the beginning of the function for debugging.
If you are trying to use the jQuery function $ make sure it is imported properly and that the $ is defined.
Some examples:
// Select all "p" elements and write "Hello"
$( "p" ).text( "Hello" );
// Change the color of all "p" elements to red
$( "p" ).css( "color", "red" );
// Hide all elements with the ".shy" class
$( ".shy" ).hide();
// Show the element with the "#nav" id
$( "#nav" ).show();
Related
I am using the following code
(function(e, t) {
"use strict";
var n = t.selection;
var i = t.getSelection;
var o = i || n;
var r = function(e) {
var t = Object.prototype.toString.call(e);
return typeof e === "object" && /^\[object (HTMLCollection|NodeList|Object)\]$/.test(t) && e.hasOwnProperty("length") && (e.length === 0 || typeof e[0] === "object" && e[0].nodeType > 0)
};
var c = function(e, t) {
var n;
return function() {
var i = this,
o = arguments;
var r = function() {
n = null;
e.apply(i, o)
};
clearTimeout(n);
n = setTimeout(r, t)
}
};
var s = function(t, n) {
this.element = t;
this.callback = n || function() {};
this.isTouch = "ontouchstart" in e;
this.hasLib = e.jQuery && t instanceof e.jQuery || e.Zepto && t instanceof e.Zepto
};
s.prototype = {
events: function() {
var e = this.callback;
var t = this.getText;
this[this.isTouch ? "bindTouch" : "bindMouseUp"](function() {
e(t())
})
},
getText: function() {
var n = "";
if (i) {
n = e.getSelection().toString()
} else if (t.selection && t.selection.type !== "Control") {
n = t.selection.createRange().text
}
return n
},
checkForSelections: function(e, t, n) {
var i;
var o = function(e) {
var n = t();
var i = setInterval(function() {
if (t() !== n) {
e(t());
n = t()
} else if (t() === "") {
clearInterval(i)
}
}, 100)
};
var r = function() {
e.removeEventListener("touchend", c, false);
e.addEventListener("touchend", c, false);
if (i) {
clearInterval(i)
}
i = setInterval(function() {
var e = t();
if (e !== "") {
n(e);
c();
o(n)
}
}, 100)
};
var c = function() {
clearInterval(i);
e.removeEventListener("touchend", c, false)
};
e.addEventListener("touchstart", r, false)
},
bindTouch: function(e) {
var t = this.checkForSelections;
var n = this.getText;
if (this.hasLib) {
this.element.each(function() {
t(this, n, e)
});
return
}
var i = function(i) {
t(i, n, e)
};
if (!r(this.element)) {
i(this.element);
return
} [].forEach.call(this.element, function(e) {
i(e)
})
},
bindMouseUp: function(e) {
if (this.hasLib) {
this.element.on("mouseup", c(e, 150));
return
}
var t = function(t) {
t.addEventListener("mouseup", c(e, 150), false)
};
if (!r(this.element)) {
t(this.element);
return
} [].forEach.call(this.element, function(e) {
t(e)
})
}
};
e.selecting = function(e, t) {
if (!o) {
return
}
new s(e, t).events()
}
})(window, document);
And :
var myElement = document.body;
window.selecting(myElement, function(selector) {
var text = selector;
instance.publishState("text", text);
});
to basically get the selected/highlighted text by the user in the browser. I then use the selected text to work with it, make API calls etc.
Getting the selected text is fine, but unfortunately the number of lines in the returned text is usually incorrect which makes it impossible for me to work with.
Let me give you an example:
The user highlights the following text on the page:
Hello this is a test
Hello this is another test
The returned value from my code however than displays this text but with more line breaks in between. So for example I get returned:
Hello this is a test
Hello this is another test
This completely breaks my functionality, as I have to exactly know how many line breaks there actually are in order to work with the text. Any ideas what could be wrong or how I can access the browsers selected text with the correct number of line breaks?
The code
window.getSelection().toString()
will return the correct selection, which will produce in your case
Hello this is a test\n\nHello this is another test
Notice how you have two \n corresponding to the 2 newlines you have.
So if you do anything like this to display what the user has selected:
console.dir(window.getSelection().toString());
You will see correctly what the user has selected
Hello this is a test
Hello this is another test
How do I redirect to any page after the script below got sucess?
Something like: If the code below did everything right, I need to go to the thanks page. Please help me. Thanks
jQuery(function(t) {
var e = function() {
var e = ("https:" == location.protocol ? "https:" : "http:") + "//formoid.net/api/push",
a = function() {
var e = (/MSIE (\d+)\./.exec(navigator.userAgent) || [0, 0])[1]
return 8 == e || 9 == e && "file:" != location.protocol ? function(e, a) {
var n = new XDomainRequest,
r = t.Deferred()
return n.open(a.type, e), n.onload = function() {
r.resolve(this.responseText)
}, n.onerror = function() {
r.reject()
}, n.send(a.data), r
} : (t.support.cors = !0, t.ajax)
}(),
n = function(t, e) {
return t = "__" + t + "__", e.length ? (this[t] = e[0], this) : this[t]
},
r = function(e, a, n) {
return t.each(n, function(t, n) {
e[n] = function() {
return a[n].apply(a, arguments)
}
}), e
},
i = function(t) {
t = t || {}, this.__email__ = t.email || "", this.__title__ = t.title || "", this.__data__ = t.data || []
}
return i.prototype.email = function(t) {
return n.call(this, "email", arguments)
}, i.prototype.title = function(t) {
return n.call(this, "title", arguments)
}, i.prototype.data = function(t) {
return n.call(this, "data", arguments)
}, i.prototype.send = function(n, i) {
var o = r(t.Deferred(), this, ["email", "title", "data", "send"])
return i && (i.call(this, o), "pending" != o.state()) ? o : (a(e, {
type: "POST",
data: JSON.stringify({
email: this.__email__,
form: {
title: this.__title__,
data: arguments.length ? n : this.__data__
}
})
}).done(function(t) {
try {
var e = JSON.parse(t)
e.error ? o.reject(e.error) : o.resolve(e.response)
} catch (a) {
o.reject("Incorrect server response.")
}
}).fail(function() {
var t = "Failed to query the server. "
t += "onLine" in navigator && !navigator.onLine ? "No connection to the Internet." : "Check the connection and try again.", o.reject(t)
}), o)
}, {
Form: function(t) {
return new i(t)
}
}
}(),
a = function(e) {
if (e.checkValidity) return e.checkValidity()
var a = !0,
n = t(e).val(),
r = t(e).attr("type")
return n ? a = !("email" === r && !/^([^#]+?)#(([a-z0-9]-*)*[a-z0-9]+\.)+([a-z0-9]+)$/i.test(n)) : t(e).attr("required") && (a = !1), t(e)[(a ? "remove" : "add") + "Class"]("form-invalid"), a
}
t('[data-form-type="formoid"]').each(function() {
var n, r = t(this),
i = r.is("form") ? r : r.find("form"),
o = r.find("[data-form-alert]"),
s = r.is("[data-form-title]") ? r : r.find("[data-form-title]"),
l = r.find('[type="submit"]'),
c = o.attr("data-success") || o.find("[data-form-alert-success]").html()
l.html('<span class="btn-text">' + l.html() + '</span><i class="btn-loader"></i>').click(function() {
i.addClass("form-active")
}), i.submit(function(d) {
if (d.preventDefault(), i.addClass("form-active"), !l.hasClass("btn-loading")) {
var f = !0,
u = []
n = n || e.Form({
email: r.find("[data-form-email]").val(),
title: s.attr("data-form-title") || s.text()
}), o.html(""), r.find("[data-form-field]").each(function() {
a(this) || (f = !1), u.push([t(this).attr("data-form-field") || t(this).attr("name"), t(this).val()])
}), f && (l.addClass("btn-loading").prop("disabled", !0), n.send(u).done(function(e) {
i.removeClass("form-active"), r.find("[data-form-field]").val(""), o.append(t('<div class="alert alert-form alert-success text-xs-center"/>').text(c || e))
}).fail(function(e) {
o.append(t('<div class="alert alert-form alert-danger text-xs-center"/>').text(e))
}).always(function() {
l.removeClass("btn-loading").prop("disabled", !1)
}))
}
})
})
})
Everything works fine but in the end I want to redirect to a page right after the form data has been sent. Can you help me? Thanks
Bind an event to the submit of the form, if you have one, or run a callback after a successful response comes back from the server and use window.location to send the user to your desired URL. More information on window.location can be found here: https://developer.mozilla.org/en-US/docs/Web/API/Window/location. (Look at the example #1)
I can't say more than that from the code you shared.
I'm working on my first Chrome extension to help me on my job.
Well, I have a HTML file as the extension pop-up and a .JS file to do all the magic. When I run the HTML in the browser, it works fine (it has to autocomplete the keywords are being typed) but when I run it as a Chrome extension it does not work at all.
Any idea?
JSON file
{
"name": "Autocompleter",
"version": "0",
"description": "It completes!",
"manifest_version": 2,
"browser_action": {
"name": "project with jquery",
"icons": ["icon.png"],
"default_icon": "icon.png",
"default_popup": "home.html"
},
"content_scripts": [ {
"js": [ "awesomplete.js" ],
"matches": [ "http://*/*", "https://*/*"]
}]
}
HTML
<!doctype html>
<html lang="en">
<head>
<script src="awesomplete.js"></script>
<link rel="stylesheet" href="awesomplete.css" />
</head>
<body>
<section id="multiple-values">
<input data-list="Brazil, Argentina, Uruguai, Paraguai, Nova Zelândia, Canadá" data-multiple data-minchars="1" /></label>
<pre class="language-javascript"><code><script>new Awesomplete('input[data-multiple]', {
filter: function(text, input) {
return Awesomplete.FILTER_CONTAINS(text, input.match(/[^,]*$/)[0]);
},
replace: function(text) {
var before = this.input.value.match(/^.+,\s*|/)[0];
this.input.value = before + text + ", ";
}
});</script></code></pre>
</section>
</body>
</html>
.JS file
(function () {
var _ = function (input, o) {
var me = this;
// Setup
this.isOpened = false;
this.input = $(input);
this.input.setAttribute("autocomplete", "off");
this.input.setAttribute("aria-autocomplete", "list");
o = o || {};
configure(this, {
minChars: 2,
maxItems: 10,
autoFirst: false,
data: _.DATA,
filter: _.FILTER_CONTAINS,
sort: _.SORT_BYLENGTH,
item: _.ITEM,
replace: _.REPLACE
}, o);
this.index = -1;
// Create necessary elements
this.container = $.create("div", {
className: "awesomplete",
around: input
});
this.ul = $.create("ul", {
hidden: "hidden",
inside: this.container
});
this.status = $.create("span", {
className: "visually-hidden",
role: "status",
"aria-live": "assertive",
"aria-relevant": "additions",
inside: this.container
});
// Bind events
$.bind(this.input, {
"input": this.evaluate.bind(this),
"blur": this.close.bind(this, { reason: "blur" }),
"keydown": function(evt) {
var c = evt.keyCode;
// If the dropdown `ul` is in view, then act on keydown for the following keys:
// Enter / Esc / Up / Down
if(me.opened) {
if (c === 13 && me.selected) { // Enter
evt.preventDefault();
me.select();
}
else if (c === 27) { // Esc
me.close({ reason: "esc" });
}
else if (c === 38 || c === 40) { // Down/Up arrow
evt.preventDefault();
me[c === 38? "previous" : "next"]();
}
}
}
});
$.bind(this.input.form, {"submit": this.close.bind(this, { reason: "submit" })});
$.bind(this.ul, {"mousedown": function(evt) {
var li = evt.target;
if (li !== this) {
while (li && !/li/i.test(li.nodeName)) {
li = li.parentNode;
}
if (li && evt.button === 0) { // Only select on left click
evt.preventDefault();
me.select(li, evt.target);
}
}
}});
if (this.input.hasAttribute("list")) {
this.list = "#" + this.input.getAttribute("list");
this.input.removeAttribute("list");
}
else {
this.list = this.input.getAttribute("data-list") || o.list || [];
}
_.all.push(this);
};
_.prototype = {
set list(list) {
if (Array.isArray(list)) {
this._list = list;
}
else if (typeof list === "string" && list.indexOf(",") > -1) {
this._list = list.split(/\s*,\s*/);
}
else { // Element or CSS selector
list = $(list);
if (list && list.children) {
var items = [];
slice.apply(list.children).forEach(function (el) {
if (!el.disabled) {
var text = el.textContent.trim();
var value = el.value || text;
var label = el.label || text;
if (value !== "") {
items.push({ label: label, value: value });
}
}
});
this._list = items;
}
}
if (document.activeElement === this.input) {
this.evaluate();
}
},
get selected() {
return this.index > -1;
},
get opened() {
return this.isOpened;
},
close: function (o) {
if (!this.opened) {
return;
}
this.ul.setAttribute("hidden", "");
this.isOpened = false;
this.index = -1;
$.fire(this.input, "awesomplete-close", o || {});
},
open: function () {
this.ul.removeAttribute("hidden");
this.isOpened = true;
if (this.autoFirst && this.index === -1) {
this.goto(0);
}
$.fire(this.input, "awesomplete-open");
},
next: function () {
var count = this.ul.children.length;
this.goto(this.index < count - 1 ? this.index + 1 : (count ? 0 : -1) );
},
previous: function () {
var count = this.ul.children.length;
var pos = this.index - 1;
this.goto(this.selected && pos !== -1 ? pos : count - 1);
},
// Should not be used, highlights specific item without any checks!
goto: function (i) {
var lis = this.ul.children;
if (this.selected) {
lis[this.index].setAttribute("aria-selected", "false");
}
this.index = i;
if (i > -1 && lis.length > 0) {
lis[i].setAttribute("aria-selected", "true");
this.status.textContent = lis[i].textContent;
$.fire(this.input, "awesomplete-highlight", {
text: this.suggestions[this.index]
});
}
},
select: function (selected, origin) {
if (selected) {
this.index = $.siblingIndex(selected);
} else {
selected = this.ul.children[this.index];
}
if (selected) {
var suggestion = this.suggestions[this.index];
var allowed = $.fire(this.input, "awesomplete-select", {
text: suggestion,
origin: origin || selected
});
if (allowed) {
this.replace(suggestion);
this.close({ reason: "select" });
$.fire(this.input, "awesomplete-selectcomplete", {
text: suggestion
});
}
}
},
evaluate: function() {
var me = this;
var value = this.input.value;
if (value.length >= this.minChars && this._list.length > 0) {
this.index = -1;
// Populate list with options that match
this.ul.innerHTML = "";
this.suggestions = this._list
.map(function(item) {
return new Suggestion(me.data(item, value));
})
.filter(function(item) {
return me.filter(item, value);
})
.sort(this.sort)
.slice(0, this.maxItems);
this.suggestions.forEach(function(text) {
me.ul.appendChild(me.item(text, value));
});
if (this.ul.children.length === 0) {
this.close({ reason: "nomatches" });
} else {
this.open();
}
}
else {
this.close({ reason: "nomatches" });
}
}
};
// Static methods/properties
_.all = [];
_.FILTER_CONTAINS = function (text, input) {
return RegExp($.regExpEscape(input.trim()), "i").test(text);
};
_.FILTER_STARTSWITH = function (text, input) {
return RegExp("^" + $.regExpEscape(input.trim()), "i").test(text);
};
_.SORT_BYLENGTH = function (a, b) {
if (a.length !== b.length) {
return a.length - b.length;
}
return a < b? -1 : 1;
};
_.ITEM = function (text, input) {
var html = input === '' ? text : text.replace(RegExp($.regExpEscape(input.trim()), "gi"), "<mark>$&</mark>");
return $.create("li", {
innerHTML: html,
"aria-selected": "false"
});
};
_.REPLACE = function (text) {
this.input.value = text.value;
};
_.DATA = function (item/*, input*/) { return item; };
// Private functions
function Suggestion(data) {
var o = Array.isArray(data)
? { label: data[0], value: data[1] }
: typeof data === "object" && "label" in data && "value" in data ? data : { label: data, value: data };
this.label = o.label || o.value;
this.value = o.value;
}
Object.defineProperty(Suggestion.prototype = Object.create(String.prototype), "length", {
get: function() { return this.label.length; }
});
Suggestion.prototype.toString = Suggestion.prototype.valueOf = function () {
return "" + this.label;
};
function configure(instance, properties, o) {
for (var i in properties) {
var initial = properties[i],
attrValue = instance.input.getAttribute("data-" + i.toLowerCase());
if (typeof initial === "number") {
instance[i] = parseInt(attrValue);
}
else if (initial === false) { // Boolean options must be false by default anyway
instance[i] = attrValue !== null;
}
else if (initial instanceof Function) {
instance[i] = null;
}
else {
instance[i] = attrValue;
}
if (!instance[i] && instance[i] !== 0) {
instance[i] = (i in o)? o[i] : initial;
}
}
}
// Helpers
var slice = Array.prototype.slice;
function $(expr, con) {
return typeof expr === "string"? (con || document).querySelector(expr) : expr || null;
}
function $$(expr, con) {
return slice.call((con || document).querySelectorAll(expr));
}
$.create = function(tag, o) {
var element = document.createElement(tag);
for (var i in o) {
var val = o[i];
if (i === "inside") {
$(val).appendChild(element);
}
else if (i === "around") {
var ref = $(val);
ref.parentNode.insertBefore(element, ref);
element.appendChild(ref);
}
else if (i in element) {
element[i] = val;
}
else {
element.setAttribute(i, val);
}
}
return element;
};
$.bind = function(element, o) {
if (element) {
for (var event in o) {
var callback = o[event];
event.split(/\s+/).forEach(function (event) {
element.addEventListener(event, callback);
});
}
}
};
$.fire = function(target, type, properties) {
var evt = document.createEvent("HTMLEvents");
evt.initEvent(type, true, true );
for (var j in properties) {
evt[j] = properties[j];
}
return target.dispatchEvent(evt);
};
$.regExpEscape = function (s) {
return s.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&");
};
$.siblingIndex = function (el) {
/* eslint-disable no-cond-assign */
for (var i = 0; el = el.previousElementSibling; i++);
return i;
};
// Initialization
function init() {
$$("input.awesomplete").forEach(function (input) {
new _(input);
});
}
// Are we in a browser? Check for Document constructor
if (typeof Document !== "undefined") {
// DOM already loaded?
if (document.readyState !== "loading") {
init();
}
else {
// Wait for it
document.addEventListener("DOMContentLoaded", init);
}
}
_.$ = $;
_.$$ = $$;
// Make sure to export Awesomplete on self when in a browser
if (typeof self !== "undefined") {
self.Awesomplete = _;
}
// Expose Awesomplete as a CJS module
if (typeof module === "object" && module.exports) {
module.exports = _;
}
return _;
}());
Prints:
Working
Not working (as a Chrome Extension)
How would I apply a tree filter a tree panel?
I know this may seem like a simple question, but I'm new to extjs dealing with some complex code (from my perspective). I can't figure out how to apply a tree filter to a tree panel. I found the documentation on tree filters here, but I don't know how to use one on a tree panel.
Here's the code of my tree panel:
{
xtype: 'treepanel',
loader: new Ext.tree.TreeLoader(),
itemId:'TreePanelThisUserCanSee',
rootVisible: false,
border: true,
autoScroll: true,
hideCollapseTool: true,
animate: false,
getSelectedArray: function () {
var selNodes = this.getChecked();
var msg = '';
var assignArray = new Array();
Ext.each(selNodes, function(node) {
if(!node.disabled) {
if(msg.length > 0){
msg += ', ';
}
msg += node.id;
assignArray[assignArray.length] = node.id;
}
});
return assignArray;
},
root: new Ext.tree.AsyncTreeNode({
text: 'Locations',
draggable: false,
id: 'root*node',
leaf: false,
expanded: true,
expandable: false,
children: [] // must have this to programatically add
}),
listeners: {
'checkchange': function(node, checked) {
if(checked) {
if( node.hasChildNodes() ) {
node.expand(false, false);
node.eachChild(function () {
this.ui.toggleCheck(true);
if(this.hasChildNodes()) {
this.eachChild(function () {
this.ui.toggleCheck(true);
});
}
});
}
} else {
node.eachChild(function () {
this.ui.toggleCheck(false);
if(this.hasChildNodes()) {
this.eachChild(function () {
this.ui.toggleCheck(false);
});
}
});
}
}
}
}
Read this thread and check this example of remote tree with filter.
Also you can check this code:
var config = {
readOnly: false,
isExpand: false,
mode: 'local',
treeFilter: new Ext.tree.TreeFilter(this.getTree(), {
autoClear: true,
filterBy : function(fn, scope, startNode){
startNode = startNode || this.tree.root;
if(this.autoClear){
this.clear();
}
var found = {};
var af = this.filtered, rv = this.reverse;
var f = function(n){
if(n == startNode){
return true;
}
if(af[n.id]){
return false;
}
var m = fn.call(scope || n, n);
if(!m || rv){
af[n.id] = n;
// n.ui.hide();
// return false;
return true;
}
found[n.id] = n;
return true;
};
startNode.cascade(f);
for(var idf in found){
if(typeof idf != "function"){
var curFoundItem = found[idf];
var p = curFoundItem.parentNode;
while(p){
delete af[p.id];
p = p.parentNode;
}
}
}
for(var id in af){
if(typeof id != "function"){
var n = af[id];
n.ui.hide();
}
}
//startNode.cascade(f2);
if(this.remove){
for(var id in af){
if(typeof id != "function"){
var n = af[id];
if(n && n.parentNode){
n.parentNode.removeChild(n);
}
}
}
}
}
}),
listeners: {
scope: this,
beforequery: function(){
return false;
},
keyup: {
fn: function(field, key){
if(!this.isExpand)
this.expand();
var value = field.getRawValue();
if(Ext.isEmpty(value) && !Ext.isEmpty(field.treeFilter)){
field.treeFilter.clear();
return;
}
var re = new RegExp('' + value + '', 'i');
var tree = field.getTree();
tree.expandAll();
field.treeFilter.filter(re);
},
buffer: 250
}
}
}
I hope that this will help you!
I'm trying to save the tags from jQuery TagBox Plugin (from geektantra.com/2011/05/jquery-tagbox-plugin/)
(function(jQuery) {
jQuery.fn.tagBox = function(options) {
var defaults = {
separator: ',',
className: 'tagBox',
tagInputClassName: '',
tagButtonClassName: '',
tagButtonTitle: 'Add Tag',
confirmRemoval: false,
confirmRemovalText: 'Do you really want to remove the tag?',
completeOnSeparator: true,
completeOnBlur: false,
readonly: false,
enableDropdown: false,
dropdownSource: function() {},
dropdownOptionsAttribute: "title",
removeTagText: "X",
maxTags: -1,
maxTagsErr: function(max_tags) { alert("A maximum of "+max_tags+" tags can be added!"); },
beforeTagAdd: function(tag_to_add) {},
afterTagAdd: function(added_tag) {}
}
if (options) {
options = jQuery.extend(defaults, options);
} else {
options = defaults;
}
options.tagInputClassName = ( options.tagInputClassName != '' ) ? options.tagInputClassName + ' ' : '';
options.tagButtonClassName = ( options.tagButtonClassName != '' ) ? options.tagButtonClassName + ' ' : '';
// Hide Element
var $elements = this;
if($elements.length < 1) return;
$elements.each(function(){
var uuid = Math.round( Math.random()*0x10000 ).toString(16) + Math.round( Math.random()*0x10000 ).toString(16);
var $element = jQuery(this);
$element.hide();
try {
var options_from_attribute = jQuery.parseJSON($element.attr(options.dropdownOptionsAttribute));
options = jQuery.extend(options_from_attribute, options);
} catch(e) {
console.log(e);
}
if($element.is(":disabled"))
options.readonly = true;
if( (jQuery.isArray($element)) && $element[0].hasAttribute("readonly") )
options.readonly = true
// Create DOM Elements
if( (options.enableDropdown) && options.dropdownSource() != null ) {
if(options.dropdownSource().jquery) {
var $tag_input_elem = (options.readonly) ? '' : options.dropdownSource();
$tag_input_elem.attr("id", options.className+'-input-'+uuid);
$tag_input_elem.addClass(options.className+'-input');
} else {
var tag_dropdown_items_obj = jQuery.parseJSON(options.dropdownSource());
var tag_dropdown_options = new Array('<option value=""></option>');
jQuery.each(tag_dropdown_items_obj, function(i, v){
if((jQuery.isArray(v)) && v.length == 2 ) {
tag_dropdown_options.push( '<option value="'+v[0]+'">'+v[1]+'</option>' );
} else if ( !jQuery.isArray(v) ) {
tag_dropdown_options.push( '<option value="'+i+'">'+v+'</option>' );
}
});
var tag_dropdown = '<select class="'+options.tagInputClassName+' '+options.className+'-input" id="'+options.className+'-input-'+uuid+'">'+tag_dropdown_options.join("")+'</select>';
var $tag_input_elem = (options.readonly) ? '' : jQuery(tag_dropdown);
}
} else {
var $tag_input_elem = (options.readonly) ? '' : jQuery('<input type="text" class="'+options.tagInputClassName+' '+options.className+'-input" value="" id="'+options.className+'-input-'+uuid+'" />');
}
var $tag_add_elem = (options.readonly) ? '' : jQuery(''+options.tagButtonTitle+'');
var $tag_list_elem = jQuery('<span class="'+options.className+'-list" id="'+options.className+'-list-'+uuid+'"></span>');
var $tagBox = jQuery('<span class="'+options.className+'-container"></span>').append($tag_input_elem).append($tag_add_elem).append($tag_list_elem);
$element.before($tagBox);
$element.addClass("jQTagBox");
$element.unbind('reloadTagBox');
$element.bind('reloadTagBox', function(){
$tagBox.remove();
$element.tagBox(options);
});
// Generate Tags List from Input item
generate_tags_list( get_current_tags_list() );
if(!options.readonly) {
$tag_add_elem.click(function() {
var selected_tag = $tag_input_elem.val();
options.beforeTagAdd(selected_tag);
add_tag(selected_tag);
if($tag_input_elem.is("select")) {
$tag_input_elem.find('option[value="'+selected_tag+'"]').attr("disabled", "disabled");
}
$tag_input_elem.val('');
options.afterTagAdd(selected_tag);
});
$tag_input_elem.keypress(function(e) {
var code = (e.keyCode ? e.keyCode : e.which);
var this_val = jQuery(this).val();
if(code==13 || (code == options.separator.charCodeAt(0) && options.completeOnSeparator) ) {
$tag_add_elem.trigger("click");
return false;
}
});
if( options.completeOnBlur ) {
$tag_input_elem.blur(function() {
if(jQuery(this).val() != "")
$tag_add_elem.trigger("click");
});
}
jQuery('.'+options.className+'-remove-'+uuid).live( "click", function () {
if(options.confirmRemoval) {
var c = confirm(options.confirmRemovalText);
if(!c) return false;
}
var tag_item = jQuery(this).attr('rel');
if($tag_input_elem.is("select")) {
$tag_input_elem.find('option[value="'+tag_item+'"]').removeAttr("disabled");
}
$tag_input_elem.val('');
remove_tag(tag_item);
});
}
// Methods
function separator_encountered(val) {
return (val.indexOf( options.separator ) != "-1") ? true : false;
}
function get_current_tags_list() {
var tags_list = $element.val().split(options.separator);
tags_list = jQuery.map(tags_list, function (item) { return jQuery.trim(item); });
return tags_list;
}
function generate_tags_list(tags_list) {
var tags_list = jQuery.unique( tags_list.sort() ).sort();
$tag_list_elem.html('');
jQuery.each(tags_list, function(key, val) {
if(val != "") {
var remove_tag_link = (options.readonly) ? '' : ''+options.removeTagText+'';
if((options.enableDropdown) && jQuery('#'+options.className+'-input-'+uuid).find("option").length > 0) {
var display_val = jQuery('#'+options.className+'-input-'+uuid).find("option[value='"+val+"']").text();
} else {
var display_val = val;
}
$tag_list_elem.append('<span class="'+options.className+'-item"><span class="'+options.className+'-bullet">•</span><span class="'+options.className+'-item-content">'+remove_tag_link+''+display_val+'</span></span>');
}
});
$element.val(tags_list.join(options.separator));
}
function add_tag(new_tag_items) {
var tags_list = get_current_tags_list();
new_tag_items = new_tag_items.split(options.separator);
new_tag_items = jQuery.map(new_tag_items, function (item) { return jQuery.trim(item); });
tags_list = tags_list.concat(new_tag_items);
tags_list = jQuery.map( tags_list, function(item) { if(item != "") return item } );
if( tags_list.length > options.maxTags && options.maxTags != -1 ) {
options.maxTagsErr(options.maxTags);
return;
}
generate_tags_list(tags_list);
}
function remove_tag(old_tag_items) {
var tags_list = get_current_tags_list();
old_tag_items = old_tag_items.split(options.separator);
old_tag_items = jQuery.map(old_tag_items, function (item) { return jQuery.trim(item); });
jQuery.each( old_tag_items, function(key, val) {
tags_list = jQuery.grep(tags_list, function(value) { return value != val; })
});
generate_tags_list(tags_list);
}
});
}
})(jQuery);
What I want to do is save the new tags using cookies with jquerycooie.js or using localStorage, but after this:
<div class="row">
<label for="jquery-tagbox-text">Text TagBox (Comma Separated)</label>
<input id="jquery-tagbox-text" type="text" />
</div>
if I add
$.cookie('thetags', 'tags');
and than refresh the page nothing is saved. Any idea or help?
Probably the easiest way to do this would be to use the afterTagAdd callback and (adding) a afterTagRemove callback.
afterTagAdd: function() {
$.cookie('tags', this.get_current_tags_list().join(','));
added_tag();
}
afterTagRemove: function() {
$.cookie('tags', this.get_current_tags_list().join(','));
}
When you load the page, you need to add logic to add all of the cookie-cached values to the tags.
tagBox.add_tag($.cookie('tags'));
All of this is assuming that the separator you passed to TagBox is ','.