summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2018-11-22 08:52:14 +0100
committerJo-Philipp Wich <jo@mein.io>2018-11-22 12:58:34 +0100
commit7c16decdb425b6fa5c61f738f5e3d3c4486543b8 (patch)
tree44b1af37947aaf20d8cec9762069b04d514a9cee
parent14487071db51d4fce258ba5d2531f390ab85fe1a (diff)
luci-base: move DOM manipulation functions to luci.js
Introduce a new luci.dom class which groups the DOM manipulation helpers such as E(), findParent(), matchesElem() etc. Provide wrappers for the old functions to ease the transition to the new functions. Also add a new widget helper function L.itemlist() which consolidates the item enumeration formatting code found on various pages. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r--modules/luci-base/htdocs/luci-static/resources/cbi.js106
-rw-r--r--modules/luci-base/htdocs/luci-static/resources/luci.js190
2 files changed, 179 insertions, 117 deletions
diff --git a/modules/luci-base/htdocs/luci-static/resources/cbi.js b/modules/luci-base/htdocs/luci-static/resources/cbi.js
index 19228a2ff9..edf634ee74 100644
--- a/modules/luci-base/htdocs/luci-static/resources/cbi.js
+++ b/modules/luci-base/htdocs/luci-static/resources/cbi.js
@@ -1478,107 +1478,11 @@ if (!window.requestAnimationFrame) {
}
-var dummyElem, domParser;
-
-function isElem(e)
-{
- return (typeof(e) === 'object' && e !== null && 'nodeType' in e);
-}
-
-function toElem(s)
-{
- var elem;
-
- try {
- domParser = domParser || new DOMParser();
- elem = domParser.parseFromString(s, 'text/html').body.firstChild;
- }
- catch(e) {}
-
- if (!elem) {
- try {
- dummyElem = dummyElem || document.createElement('div');
- dummyElem.innerHTML = s;
- elem = dummyElem.firstChild;
- }
- catch (e) {}
- }
-
- return elem || null;
-}
-
-function matchesElem(node, selector)
-{
- return ((node.matches && node.matches(selector)) ||
- (node.msMatchesSelector && node.msMatchesSelector(selector)));
-}
-
-function findParent(node, selector)
-{
- if (node.closest)
- return node.closest(selector);
-
- while (node)
- if (matchesElem(node, selector))
- return node;
- else
- node = node.parentNode;
-
- return null;
-}
-
-function E()
-{
- var html = arguments[0],
- attr = (arguments[1] instanceof Object && !Array.isArray(arguments[1])) ? arguments[1] : null,
- data = attr ? arguments[2] : arguments[1],
- elem;
-
- if (isElem(html))
- elem = html;
- else if (html.charCodeAt(0) === 60)
- elem = toElem(html);
- else
- elem = document.createElement(html);
-
- if (!elem)
- return null;
-
- if (attr)
- for (var key in attr)
- if (attr.hasOwnProperty(key) && attr[key] !== null && attr[key] !== undefined)
- switch (typeof(attr[key])) {
- case 'function':
- elem.addEventListener(key, attr[key]);
- break;
-
- case 'object':
- elem.setAttribute(key, JSON.stringify(attr[key]));
- break;
-
- default:
- elem.setAttribute(key, attr[key]);
- }
-
- if (typeof(data) === 'function')
- data = data(elem);
-
- if (isElem(data)) {
- elem.appendChild(data);
- }
- else if (Array.isArray(data)) {
- for (var i = 0; i < data.length; i++)
- if (isElem(data[i]))
- elem.appendChild(data[i]);
- else
- elem.appendChild(document.createTextNode('' + data[i]));
- }
- else if (data !== null && data !== undefined) {
- elem.innerHTML = '' + data;
- }
-
- return elem;
-}
+function isElem(e) { return L.dom.elem(e) }
+function toElem(s) { return L.dom.parse(s) }
+function matchesElem(node, selector) { return L.dom.matches(node, selector) }
+function findParent(node, selector) { return L.dom.parent(node, selector) }
+function E() { return L.dom.create.apply(L.dom, arguments) }
if (typeof(window.CustomEvent) !== 'function') {
function CustomEvent(event, params) {
diff --git a/modules/luci-base/htdocs/luci-static/resources/luci.js b/modules/luci-base/htdocs/luci-static/resources/luci.js
index cbf22460e4..dcda941f7b 100644
--- a/modules/luci-base/htdocs/luci-static/resources/luci.js
+++ b/modules/luci-base/htdocs/luci-static/resources/luci.js
@@ -1,7 +1,9 @@
-(function(window, document) {
+(function(window, document, undefined) {
var modalDiv = null,
tooltipDiv = null,
- tooltipTimeout = null;
+ tooltipTimeout = null,
+ dummyElem = null,
+ domParser = null;
LuCI.prototype = {
/* URL construction helpers */
@@ -72,25 +74,18 @@
return XHR.get(url, data, cb);
},
+ halt: function() { XHR.halt() },
+ run: function() { XHR.run() },
+
/* Modal dialog */
showModal: function(title, children) {
var dlg = modalDiv.firstElementChild;
- while (dlg.firstChild)
- dlg.removeChild(dlg.firstChild);
-
dlg.setAttribute('class', 'modal');
- dlg.appendChild(E('h4', {}, title));
- if (!Array.isArray(children))
- children = [ children ];
-
- for (var i = 0; i < children.length; i++)
- if (isElem(children[i]))
- dlg.appendChild(children[i]);
- else
- dlg.appendChild(document.createTextNode('' + children[i]));
+ this.dom.content(dlg, this.dom.create('h4', {}, title));
+ this.dom.append(dlg, children);
document.body.classList.add('modal-overlay-active');
@@ -146,14 +141,177 @@
tooltipDiv.style.opacity = 0;
tooltipTimeout = window.setTimeout(function() { tooltipDiv.removeAttribute('style'); }, 250);
+ },
+
+
+ /* Widget helper */
+ itemlist: function(node, items, separators) {
+ var children = [];
+
+ if (!Array.isArray(separators))
+ separators = [ separators || E('br') ];
+
+ for (var i = 0; i < items.length; i += 2) {
+ if (items[i+1] !== null && items[i+1] !== undefined) {
+ var sep = separators[(i/2) % separators.length],
+ cld = [];
+
+ children.push(E('span', { class: 'nowrap' }, [
+ items[i] ? E('strong', items[i] + ': ') : '',
+ items[i+1]
+ ]));
+
+ if ((i+2) < items.length)
+ children.push(this.dom.elem(sep) ? sep.cloneNode(true) : sep);
+ }
+ }
+
+ this.dom.content(node, children);
+
+ return node;
+ }
+ };
+
+ /* DOM manipulation */
+ LuCI.prototype.dom = {
+ elem: function(e) {
+ return (typeof(e) === 'object' && e !== null && 'nodeType' in e);
+ },
+
+ parse: function(s) {
+ var elem;
+
+ try {
+ domParser = domParser || new DOMParser();
+ elem = domParser.parseFromString(s, 'text/html').body.firstChild;
+ }
+ catch(e) {}
+
+ if (!elem) {
+ try {
+ dummyElem = dummyElem || document.createElement('div');
+ dummyElem.innerHTML = s;
+ elem = dummyElem.firstChild;
+ }
+ catch (e) {}
+ }
+
+ return elem || null;
+ },
+
+ matches: function(node, selector) {
+ var m = this.elem(node) ? node.matches || node.msMatchesSelector : null;
+ return m ? m.call(node, selector) : false;
+ },
+
+ parent: function(node, selector) {
+ if (this.elem(node) && node.closest)
+ return node.closest(selector);
+
+ while (this.elem(node))
+ if (this.matches(node, selector))
+ return node;
+ else
+ node = node.parentNode;
+
+ return null;
+ },
+
+ append: function(node, children) {
+ if (!this.elem(node))
+ return null;
+
+ if (Array.isArray(children)) {
+ for (var i = 0; i < children.length; i++)
+ if (this.elem(children[i]))
+ node.appendChild(children[i]);
+ else if (children !== null && children !== undefined)
+ node.appendChild(document.createTextNode('' + children[i]));
+
+ return node.lastChild;
+ }
+ else if (typeof(children) === 'function') {
+ return this.append(node, children(node));
+ }
+ else if (this.elem(children)) {
+ return node.appendChild(children);
+ }
+ else if (children !== null && children !== undefined) {
+ node.innerHTML = '' + children;
+ return node.lastChild;
+ }
+
+ return null;
+ },
+
+ content: function(node, children) {
+ if (!this.elem(node))
+ return null;
+
+ while (node.firstChild)
+ node.removeChild(node.firstChild);
+
+ return this.append(node, children);
+ },
+
+ attr: function(node, key, val) {
+ if (!this.elem(node))
+ return null;
+
+ var attr = null;
+
+ if (typeof(key) === 'object' && key !== null)
+ attr = key;
+ else if (typeof(key) === 'string')
+ attr = {}, attr[key] = val;
+
+ for (key in attr) {
+ if (!attr.hasOwnProperty(key) || attr[key] === null || attr[key] === undefined)
+ continue;
+
+ switch (typeof(attr[key])) {
+ case 'function':
+ node.addEventListener(key, attr[key]);
+ break;
+
+ case 'object':
+ node.setAttribute(key, JSON.stringify(attr[key]));
+ break;
+
+ default:
+ node.setAttribute(key, attr[key]);
+ }
+ }
+ },
+
+ create: function() {
+ var html = arguments[0],
+ attr = (arguments[1] instanceof Object && !Array.isArray(arguments[1])) ? arguments[1] : null,
+ data = attr ? arguments[2] : arguments[1],
+ elem;
+
+ if (this.elem(html))
+ elem = html;
+ else if (html.charCodeAt(0) === 60)
+ elem = this.parse(html);
+ else
+ elem = document.createElement(html);
+
+ if (!elem)
+ return null;
+
+ this.attr(elem, attr);
+ this.append(elem, data);
+
+ return elem;
}
};
function LuCI(env) {
this.env = env;
- modalDiv = document.body.appendChild(E('div', { id: 'modal_overlay' }, E('div', { class: 'modal' })));
- tooltipDiv = document.body.appendChild(E('div', { 'class': 'cbi-tooltip' }));
+ modalDiv = document.body.appendChild(this.dom.create('div', { id: 'modal_overlay' }, this.dom.create('div', { class: 'modal' })));
+ tooltipDiv = document.body.appendChild(this.dom.create('div', { class: 'cbi-tooltip' }));
document.addEventListener('mouseover', this.showTooltip.bind(this), true);
document.addEventListener('mouseout', this.hideTooltip.bind(this), true);