* The environment settings to use for the LuCI runtime.
*/
-(function(window, document, undefined) {
+((window, document, undefined) => {
'use strict';
- var env = {};
-
- /* Object.assign polyfill for IE */
- if (typeof Object.assign !== 'function') {
- Object.defineProperty(Object, 'assign', {
- value: function assign(target, varArgs) {
- if (target == null)
- throw new TypeError('Cannot convert undefined or null to object');
-
- var to = Object(target);
-
- for (var index = 1; index < arguments.length; index++)
- if (arguments[index] != null)
- for (var nextKey in arguments[index])
- if (Object.prototype.hasOwnProperty.call(arguments[index], nextKey))
- to[nextKey] = arguments[index][nextKey];
-
- return to;
- },
- writable: true,
- configurable: true
- });
- }
-
- /* Promise.finally polyfill */
- if (typeof Promise.prototype.finally !== 'function') {
- Promise.prototype.finally = function(fn) {
- var onFinally = function(cb) {
- return Promise.resolve(fn.call(this)).then(cb);
- };
-
- return this.then(
- function(result) { return onFinally.call(this, function() { return result }) },
- function(reason) { return onFinally.call(this, function() { return Promise.reject(reason) }) }
- );
- };
- }
+ const env = {};
/*
* Class declaration and inheritance helper
*/
- var toCamelCase = function(s) {
- return s.replace(/(?:^|[\. -])(.)/g, function(m0, m1) { return m1.toUpperCase() });
- };
+ const toCamelCase = s => s.replace(/(?:^|[\. -])(.)/g, (m0, m1) => m1.toUpperCase());
/**
* @class baseclass
* It provides simple means to create subclasses of given classes and
* implements prototypal inheritance.
*/
- var superContext = {}, classIndex = 0, Class = Object.assign(function() {}, {
+ const superContext = {};
+
+ let classIndex = 0;
+
+ const Class = Object.assign(function() {}, {
/**
* Extends this base class with the properties described in
* `properties` and returns a new subclassed Class instance
* class to enable inheritance. The resulting value represents a
* class constructor and can be instantiated with `new`.
*/
- extend: function(properties) {
- var props = {
+ extend(properties) {
+ const props = {
__id__: { value: classIndex },
__base__: { value: this.prototype },
- __name__: { value: properties.__name__ || 'anonymous' + classIndex++ }
+ __name__: { value: properties.__name__ ?? `anonymous${classIndex++}` }
};
- var ClassConstructor = function() {
+ const ClassConstructor = function() {
if (!(this instanceof ClassConstructor))
throw new TypeError('Constructor must not be called without "new"');
}
};
- for (var key in properties)
+ for (const key in properties)
if (!props[key] && properties.hasOwnProperty(key))
props[key] = { value: properties[key], writable: true };
ClassConstructor.prototype = Object.create(this.prototype, props);
ClassConstructor.prototype.constructor = ClassConstructor;
Object.assign(ClassConstructor, this);
- ClassConstructor.displayName = toCamelCase(props.__name__.value + 'Class');
+ ClassConstructor.displayName = toCamelCase(`${props.__name__.value}Class`);
return ClassConstructor;
},
* properties with its prototype set to this base class to
* enable inheritance.
*/
- singleton: function(properties /*, ... */) {
- return Class.extend(properties)
- .instantiate(Class.prototype.varargs(arguments, 1));
+ singleton(properties, ...new_args) {
+ return Class.extend(properties).instantiate(new_args);
},
/**
* An array of arbitrary values which will be passed as arguments
* to the constructor function.
*
- * @param {...*} [new_args]
- * Specifies arguments to be passed to the subclass constructor
- * as-is in order to instantiate the new subclass.
- *
* @returns {LuCI.baseclass}
* Returns a new LuCI.baseclass instance extended by the given
* properties with its prototype set to this base class to
* enable inheritance.
*/
- instantiate: function(args) {
- return new (Function.prototype.bind.apply(this,
- Class.prototype.varargs(args, 0, null)))();
+ instantiate(args) {
+ return new (Function.prototype.bind.call(this, null, ...args))();
},
/* unused */
- call: function(self, method) {
+ call(self, method, ...args) {
if (typeof(this.prototype[method]) != 'function')
- throw new ReferenceError(method + ' is not defined in class');
+ throw new ReferenceError(`${method} is not defined in class`);
- return this.prototype[method].apply(self, self.varargs(arguments, 1));
+ return this.prototype[method].call(self, method, ...args);
},
/**
* class or `false` if the given value is not a valid class or not
* a subclass of this class'.
*/
- isSubclass: function(classValue) {
- return (classValue != null &&
- typeof(classValue) == 'function' &&
- classValue.prototype instanceof this);
+ isSubclass(classValue) {
+ return (typeof(classValue) == 'function' && classValue.prototype instanceof this);
},
prototype: {
* and the values extracted from the `args` array beginning with
* `offset`.
*/
- varargs: function(args, offset /*, ... */) {
- return Array.prototype.slice.call(arguments, 2)
- .concat(Array.prototype.slice.call(args, offset));
+ varargs(args, offset, ...extra_args) {
+ return extra_args.concat(Array.prototype.slice.call(args, offset));
},
/**
* This function has two signatures and is sensitive to the
* amount of arguments passed to it:
* - `super('key')` -
- * Returns the value of `key` when found within one of the
- * parent classes.
+ * Returns the value of `key` when found within one of the
+ * parent classes.
* - `super('key', ['arg1', 'arg2'])` -
- * Calls the `key()` method with parameters `arg1` and `arg2`
- * when found within one of the parent classes.
+ * Calls the `key()` method with parameters `arg1` and `arg2`
+ * when found within one of the parent classes.
*
* @memberof LuCI.baseclass
* @instance
* was found in the parent class chain or when the call to the
* superclass method returned `null`.
*/
- super: function(key, callArgs) {
+ super(key, ...callArgs) {
if (key == null)
return null;
- var slotIdx = this.__id__ + '.' + key,
- symStack = superContext[slotIdx],
- protoCtx = null;
+ const slotIdx = `${this.__id__}.${key}`;
+ const symStack = superContext[slotIdx];
+ let protoCtx = null;
for (protoCtx = Object.getPrototypeOf(symStack ? symStack[0] : Object.getPrototypeOf(this));
- protoCtx != null && !protoCtx.hasOwnProperty(key);
- protoCtx = Object.getPrototypeOf(protoCtx)) {}
+ protoCtx != null && !protoCtx.hasOwnProperty(key);
+ protoCtx = Object.getPrototypeOf(protoCtx)) {}
if (protoCtx == null)
return null;
- var res = protoCtx[key];
+ let res = protoCtx[key];
- if (arguments.length > 1) {
+ if (callArgs.length > 0) {
if (typeof(res) != 'function')
- throw new ReferenceError(key + ' is not a function in base class');
+ throw new ReferenceError(`${key} is not a function in base class`);
- if (typeof(callArgs) != 'object')
- callArgs = this.varargs(arguments, 1);
+ if (Array.isArray(callArgs[0]) || LuCI.prototype.isArguments(callArgs[0]))
+ callArgs = callArgs[0];
if (symStack)
symStack.unshift(protoCtx);
* constructor functions `displayName` and describing the class
* members and their respective types.
*/
- toString: function() {
- var s = '[' + this.constructor.displayName + ']', f = true;
- for (var k in this) {
+ toString() {
+ let s = `[${this.constructor.displayName}]`, f = true;
+ for (const k in this) {
if (this.hasOwnProperty(k)) {
- s += (f ? ' {\n' : '') + ' ' + k + ': ' + typeof(this[k]) + '\n';
+ s += `${f ? ' {\n' : ''} ${k}: ${typeof(this[k])}\n`;
f = false;
}
}
* The `Headers` class is an internal utility class exposed in HTTP
* response objects using the `response.headers` property.
*/
- var Headers = Class.extend(/** @lends LuCI.headers.prototype */ {
+ const Headers = Class.extend(/** @lends LuCI.headers.prototype */ {
__name__: 'LuCI.headers',
- __init__: function(xhr) {
- var hdrs = this.headers = {};
- xhr.getAllResponseHeaders().split(/\r\n/).forEach(function(line) {
- var m = /^([^:]+):(.*)$/.exec(line);
+ __init__(xhr) {
+ const hdrs = this.headers = {};
+ xhr.getAllResponseHeaders().split(/\r\n/).forEach(line => {
+ const m = /^([^:]+):(.*)$/.exec(line);
if (m != null)
hdrs[m[1].trim().toLowerCase()] = m[2].trim();
});
* @returns {boolean}
* Returns `true` if the header name is present, `false` otherwise
*/
- has: function(name) {
+ has(name) {
return this.headers.hasOwnProperty(String(name).toLowerCase());
},
* @returns {string|null}
* The value of the given header name or `null` if the header isn't present.
*/
- get: function(name) {
- var key = String(name).toLowerCase();
+ get(name) {
+ const key = String(name).toLowerCase();
return this.headers.hasOwnProperty(key) ? this.headers[key] : null;
}
});
*
* The `Response` class is an internal utility class representing HTTP responses.
*/
- var Response = Class.extend({
+ const Response = Class.extend({
__name__: 'LuCI.response',
- __init__: function(xhr, url, duration, headers, content) {
+ __init__(xhr, url, duration, headers, content) {
/**
* Describes whether the response is successful (status codes `200..299`) or not
* @instance
* @returns {LuCI.response}
* The cloned `Response` instance.
*/
- clone: function(content) {
- var copy = new Response(this.xhr, this.url, this.duration, this.headers, content);
+ clone(content) {
+ const copy = new Response(this.xhr, this.url, this.duration, this.headers, content);
copy.ok = this.ok;
copy.status = this.status;
* @returns {*}
* The parsed JSON data.
*/
- json: function() {
+ json() {
if (this.responseJSON == null)
this.responseJSON = JSON.parse(this.responseText);
* @returns {string}
* The response content.
*/
- text: function() {
+ text() {
if (this.responseText == null && this.responseJSON != null)
this.responseText = JSON.stringify(this.responseJSON);
* @returns {Blob}
* The response content as blob.
*/
- blob: function() {
+ blob() {
return this.responseBlob;
}
});
- var requestQueue = [];
+ const requestQueue = [];
function isQueueableRequest(opt) {
if (!classes.rpc)
if (opt.nobatch === true)
return false;
- var rpcBaseURL = Request.expandURL(classes.rpc.getBaseURL());
+ const rpcBaseURL = Request.expandURL(classes.rpc.getBaseURL());
return (rpcBaseURL != null && opt.url.indexOf(rpcBaseURL) == 0);
}
if (!requestQueue.length)
return;
- var reqopt = Object.assign({}, requestQueue[0][0], { content: [], nobatch: true }),
- batch = [];
+ const reqopt = Object.assign({}, requestQueue[0][0], { content: [], nobatch: true }), batch = [];
- for (var i = 0; i < requestQueue.length; i++) {
+ for (let i = 0; i < requestQueue.length; i++) {
batch[i] = requestQueue[i];
reqopt.content[i] = batch[i][0].content;
}
requestQueue.length = 0;
- Request.request(rpcBaseURL, reqopt).then(function(reply) {
- var json = null, req = null;
+ Request.request(rpcBaseURL, reqopt).then(reply => {
+ let json = null, req = null;
try { json = reply.json() }
catch(e) { }
req[2].call(reqopt, reply.clone(json.shift()));
else
req[1].call(reqopt, new Error('No related RPC reply'));
- }).catch(function(error) {
- var req = null;
+ }).catch(error => {
+ let req = null;
while ((req = batch.shift()) != null)
req[1].call(reqopt, error);
* The `Request` class allows initiating HTTP requests and provides utilities
* for dealing with responses.
*/
- var Request = Class.singleton(/** @lends LuCI.request.prototype */ {
+ const Request = Class.singleton(/** @lends LuCI.request.prototype */ {
__name__: 'LuCI.request',
interceptors: [],
* The absolute URL derived from the given one, or the original URL
* if it already was absolute.
*/
- expandURL: function(url) {
+ expandURL(url) {
if (!/^(?:[^/]+:)?\/\//.test(url))
- url = location.protocol + '//' + location.host + url;
+ url = `${location.protocol}//${location.host}${url}`;
return url;
},
* @returns {Promise<LuCI.response>}
* The resulting HTTP response.
*/
- request: function(target, options) {
- return Promise.resolve(target).then((function(url) {
- var state = { xhr: new XMLHttpRequest(), url: this.expandURL(url), start: Date.now() },
- opt = Object.assign({}, options, state),
- content = null,
- contenttype = null,
- callback = this.handleReadyStateChange;
+ request(target, options) {
+ return Promise.resolve(target).then(url => {
+ const state = { xhr: new XMLHttpRequest(), url: this.expandURL(url), start: Date.now() };
+ const opt = Object.assign({}, options, state);
+ let content = null;
+ let contenttype = null;
+ const callback = this.handleReadyStateChange;
- return new Promise(function(resolveFn, rejectFn) {
+ return new Promise((resolveFn, rejectFn) => {
opt.xhr.onreadystatechange = callback.bind(opt, resolveFn, rejectFn);
- opt.method = String(opt.method || 'GET').toUpperCase();
+ opt.method = String(opt.method ?? 'GET').toUpperCase();
if ('query' in opt) {
- var q = (opt.query != null) ? Object.keys(opt.query).map(function(k) {
+ const q = (opt.query != null) ? Object.keys(opt.query).map(k => {
if (opt.query[k] != null) {
- var v = (typeof(opt.query[k]) == 'object')
+ const v = (typeof(opt.query[k]) == 'object')
? JSON.stringify(opt.query[k])
: String(opt.query[k]);
else
opt.xhr.open(opt.method, opt.url, true);
- opt.xhr.responseType = opt.responseType || 'text';
+ opt.xhr.responseType = opt.responseType ?? 'text';
if ('overrideMimeType' in opt.xhr)
opt.xhr.overrideMimeType('application/octet-stream');
}
if ('headers' in opt)
- for (var header in opt.headers)
+ for (const header in opt.headers)
if (opt.headers.hasOwnProperty(header)) {
if (header.toLowerCase() != 'content-type')
opt.xhr.setRequestHeader(header, opt.headers[header]);
rejectFn.call(opt, e);
}
});
- }).bind(this));
+ });
},
- handleReadyStateChange: function(resolveFn, rejectFn, ev) {
- var xhr = this.xhr,
- duration = Date.now() - this.start;
+ handleReadyStateChange(resolveFn, rejectFn, ev) {
+ const xhr = this.xhr, duration = Date.now() - this.start;
if (xhr.readyState !== 4)
return;
rejectFn.call(this, new Error('XHR request aborted by browser'));
}
else {
- var response = new Response(
- xhr, xhr.responseURL || this.url, duration);
+ const response = new Response(
+ xhr, xhr.responseURL ?? this.url, duration);
- Promise.all(Request.interceptors.map(function(fn) { return fn(response) }))
+ Promise.all(Request.interceptors.map(fn => fn(response)))
.then(resolveFn.bind(this, response))
.catch(rejectFn.bind(this));
}
* @returns {Promise<LuCI.response>}
* The resulting HTTP response.
*/
- get: function(url, options) {
+ get(url, options) {
return this.request(url, Object.assign({ method: 'GET' }, options));
},
* @returns {Promise<LuCI.response>}
* The resulting HTTP response.
*/
- post: function(url, data, options) {
+ post(url, data, options) {
return this.request(url, Object.assign({ method: 'POST', content: data }, options));
},
* @returns {LuCI.request.interceptorFn}
* The registered function.
*/
- addInterceptor: function(interceptorFn) {
+ addInterceptor(interceptorFn) {
if (typeof(interceptorFn) == 'function')
this.interceptors.push(interceptorFn);
return interceptorFn;
* @returns {boolean}
* Returns `true` if any function has been removed, else `false`.
*/
- removeInterceptor: function(interceptorFn) {
- var oldlen = this.interceptors.length, i = oldlen;
+ removeInterceptor(interceptorFn) {
+ const oldlen = this.interceptors.length;
+ let i = oldlen;
while (i--)
if (this.interceptors[i] === interceptorFn)
this.interceptors.splice(i, 1);
* @returns {function}
* Returns the internally created poll function.
*/
- add: function(interval, url, options, callback) {
+ add(interval, url, options, callback) {
if (isNaN(interval) || interval <= 0)
throw new TypeError('Invalid poll interval');
- var ival = interval >>> 0,
- opts = Object.assign({}, options, { timeout: ival * 1000 - 5 });
+ const ival = interval >>> 0, opts = Object.assign({}, options, { timeout: ival * 1000 - 5 });
- var fn = function() {
- return Request.request(url, opts).then(function(res) {
- if (!Poll.active())
- return;
+ const fn = () => Request.request(url, opts).then(res => {
+ if (!Poll.active())
+ return;
- var res_json = null;
- try {
- res_json = res.json();
- }
- catch (err) {}
+ let res_json = null;
+ try {
+ res_json = res.json();
+ }
+ catch (err) {}
- callback(res, res_json, res.duration);
- });
- };
+ callback(res, res_json, res.duration);
+ });
return (Poll.add(fn, ival) ? fn : null);
},
* @returns {boolean}
* Returns `true` if any function has been removed, else `false`.
*/
- remove: function(entry) { return Poll.remove(entry) },
+ remove(entry) { return Poll.remove(entry) },
/**
* Alias for {@link LuCI.poll.start LuCI.poll.start()}.
* @instance
* @memberof LuCI.request.poll
*/
- start: function() { return Poll.start() },
+ start() { return Poll.start() },
/**
* Alias for {@link LuCI.poll.stop LuCI.poll.stop()}.
* @instance
* @memberof LuCI.request.poll
*/
- stop: function() { return Poll.stop() },
+ stop() { return Poll.stop() },
/**
* Alias for {@link LuCI.poll.active LuCI.poll.active()}.
* @instance
* @memberof LuCI.request.poll
*/
- active: function() { return Poll.active() }
+ active() { return Poll.active() }
}
});
* as well as starting, stopping and querying the state of the polling
* loop.
*/
- var Poll = Class.singleton(/** @lends LuCI.poll.prototype */ {
+ const Poll = Class.singleton(/** @lends LuCI.poll.prototype */ {
__name__: 'LuCI.poll',
queue: [],
* Returns `true` if the function has been added or `false` if it
* already is registered.
*/
- add: function(fn, interval) {
+ add(fn, interval) {
if (interval == null || interval <= 0)
interval = env.pollinterval || null;
if (isNaN(interval) || typeof(fn) != 'function')
throw new TypeError('Invalid argument to LuCI.poll.add()');
- for (var i = 0; i < this.queue.length; i++)
+ for (let i = 0; i < this.queue.length; i++)
if (this.queue[i].fn === fn)
return false;
- var e = {
+ const e = {
r: true,
i: interval >>> 0,
- fn: fn
+ fn
};
this.queue.push(e);
* Returns `true` if the function has been removed or `false` if it
* wasn't found.
*/
- remove: function(fn) {
+ remove(fn) {
if (typeof(fn) != 'function')
throw new TypeError('Invalid argument to LuCI.poll.remove()');
- var len = this.queue.length;
+ const len = this.queue.length;
- for (var i = len; i > 0; i--)
+ for (let i = len; i > 0; i--)
if (this.queue[i-1].fn === fn)
this.queue.splice(i-1, 1);
* Returns `true` if polling has been started (or if no functions
* where registered) or `false` when the polling loop already runs.
*/
- start: function() {
+ start() {
if (this.active())
return false;
* Returns `true` if polling has been stopped or `false` if it didn't
* run to begin with.
*/
- stop: function() {
+ stop() {
if (!this.active())
return false;
},
/* private */
- step: function() {
- for (var i = 0, e = null; (e = Poll.queue[i]) != null; i++) {
+ step() {
+ for (let i = 0, e = null; (e = Poll.queue[i]) != null; i++) {
if ((Poll.tick % e.i) != 0)
continue;
* @memberof LuCI.poll
* @returns {boolean} - Returns `true` if polling is active, else `false`.
*/
- active: function() {
+ active() {
return (this.timer != null);
}
});
* To import the class in views, use `'require dom'`, to import it in
* external JavaScript, use `L.require("dom").then(...)`.
*/
- var DOM = Class.singleton(/** @lends LuCI.dom.prototype */ {
+ const DOM = Class.singleton(/** @lends LuCI.dom.prototype */ {
__name__: 'LuCI.dom',
/**
* @returns {boolean}
* Returns `true` if the value is a DOM `Node`, else `false`.
*/
- elem: function(e) {
+ elem(e) {
return (e != null && typeof(e) == 'object' && 'nodeType' in e);
},
* Returns the first DOM `Node` extracted from the HTML fragment or
* `null` on parsing failures or if no element could be found.
*/
- parse: function(s) {
- var elem = null;
-
+ parse(s) {
try {
- domParser = domParser || new DOMParser();
- elem = domParser.parseFromString(s, 'text/html').body.firstChild;
+ return domParser.parseFromString(s, 'text/html').body.firstChild;
+ }
+ catch(e) {
+ return null;
}
- catch(e) {}
-
- return elem;
},
/**
* or `false` when the node argument is no valid DOM `Node` or the
* selector didn't match.
*/
- matches: function(node, selector) {
- var m = this.elem(node) ? node.matches || node.msMatchesSelector : null;
+ matches(node, selector) {
+ const m = this.elem(node) ? (node.matches ?? node.msMatchesSelector) : null;
return m ? m.call(node, selector) : false;
},
* `null` when the node argument is no valid DOM `Node` or the
* selector didn't match any parent.
*/
- parent: function(node, selector) {
+ parent(node, selector) {
if (this.elem(node) && node.closest)
return node.closest(selector);
* if either the `node` argument was no valid DOM `node` or if the
* `children` was `null` or didn't result in further DOM nodes.
*/
- append: function(node, children) {
+ append(node, children) {
if (!this.elem(node))
return null;
if (Array.isArray(children)) {
- for (var i = 0; i < children.length; i++)
+ for (let 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]));
+ node.appendChild(document.createTextNode(`${children[i]}`));
return node.lastChild;
}
return node.appendChild(children);
}
else if (children !== null && children !== undefined) {
- node.innerHTML = '' + children;
+ node.innerHTML = `${children}`;
return node.lastChild;
}
* if either the `node` argument was no valid DOM `node` or if the
* `children` was `null` or didn't result in further DOM nodes.
*/
- content: function(node, children) {
+ content(node, children) {
if (!this.elem(node))
return null;
- var dataNodes = node.querySelectorAll('[data-idref]');
+ const dataNodes = node.querySelectorAll('[data-idref]');
- for (var i = 0; i < dataNodes.length; i++)
+ for (let i = 0; i < dataNodes.length; i++)
delete this.registry[dataNodes[i].getAttribute('data-idref')];
while (node.firstChild)
* to the given `node` as-is, with the underlying `setAttribute()`
* call implicitly turning it into a string.
*/
- attr: function(node, key, val) {
+ attr(node, key, val) {
if (!this.elem(node))
return null;
- var attr = null;
+ let attr = null;
if (typeof(key) === 'object' && key !== null)
attr = key;
* @returns {Node}
* Returns the newly created `Node`.
*/
- create: function() {
- var html = arguments[0],
- attr = arguments[1],
- data = arguments[2],
- elem;
+ create() {
+ const html = arguments[0];
+ let attr = arguments[1];
+ let data = arguments[2];
+ let elem;
if (!(attr instanceof Object) || Array.isArray(attr))
data = attr, attr = null;
if (Array.isArray(html)) {
elem = document.createDocumentFragment();
- for (var i = 0; i < html.length; i++)
+ for (let i = 0; i < html.length; i++)
elem.appendChild(this.create(html[i]));
}
else if (this.elem(html)) {
* number of arguments passed to it.
*
* - `dom.data(node)` -
- * Fetches all data associated with the given node.
+ * Fetches all data associated with the given node.
* - `dom.data(node, key)` -
- * Fetches a specific key associated with the given node.
+ * Fetches a specific key associated with the given node.
* - `dom.data(node, key, val)` -
- * Sets a specific key to the given value associated with the
- * given node.
+ * Sets a specific key to the given value associated with the
+ * given node.
* - `dom.data(node, null)` -
- * Clears any data associated with the node.
+ * Clears any data associated with the node.
* - `dom.data(node, key, null)` -
- * Clears the given key associated with the node.
+ * Clears the given key associated with the node.
*
* @instance
* @memberof LuCI.dom
* Returns the get or set value, or `null` when no value could
* be found.
*/
- data: function(node, key, val) {
- if (!node || !node.getAttribute)
+ data(node, key, val) {
+ if (!node?.getAttribute)
return null;
- var id = node.getAttribute('data-idref');
+ let id = node.getAttribute('data-idref');
/* clear all data */
if (arguments.length > 1 && key == null) {
* @returns {Class}
* Returns the bound class instance.
*/
- bindClassInstance: function(node, inst) {
+ bindClassInstance(node, inst) {
if (!(inst instanceof Class))
LuCI.prototype.error('TypeError', 'Argument must be a class instance');
* Returns the founds class instance if any or `null` if no bound
* class could be found on the node itself or any of its parents.
*/
- findClassInstance: function(node) {
- var inst = null;
+ findClassInstance(node) {
+ let inst = null;
do {
inst = this.data(node, '_class');
* no bound class instance could be found, or if the found
* instance didn't have the requested `method`.
*/
- callClassMethod: function(node, method /*, ... */) {
- var inst = this.findClassInstance(node);
+ callClassMethod(node, method, ...args) {
+ const inst = this.findClassInstance(node);
- if (inst == null || typeof(inst[method]) != 'function')
+ if (typeof(inst?.[method]) != 'function')
return null;
- return inst[method].apply(inst, inst.varargs(arguments, 2));
+ return inst[method].call(inst, ...args);
},
/**
* any children node either has a `hidden` CSS class or a `false`
* result when testing it using the given `ignoreFn`.
*/
- isEmpty: function(node, ignoreFn) {
- for (var child = node.firstElementChild; child != null; child = child.nextElementSibling)
- if (!child.classList.contains('hidden') && (!ignoreFn || !ignoreFn(child)))
+ isEmpty(node, ignoreFn) {
+ for (let child = node?.firstElementChild; child != null; child = child.nextElementSibling)
+ if (!child.classList.contains('hidden') && !ignoreFn?.(child))
return false;
return true;
*
* The `session` class provides various session related functionality.
*/
- var Session = Class.singleton(/** @lends LuCI.session.prototype */ {
+ const Session = Class.singleton(/** @lends LuCI.session.prototype */ {
__name__: 'LuCI.session',
/**
* @returns {string}
* Returns the current session ID.
*/
- getID: function() {
- return env.sessionid || '00000000000000000000000000000000';
+ getID() {
+ return env.sessionid ?? '00000000000000000000000000000000';
},
/**
* @returns {string|null}
* Returns the current session token or `null` if not logged in.
*/
- getToken: function() {
- return env.token || null;
+ getToken() {
+ return env.token ?? null;
},
/**
* Returns the stored session data or `null` if the given key wasn't
* found.
*/
- getLocalData: function(key) {
+ getLocalData(key) {
try {
- var sid = this.getID(),
- item = 'luci-session-store',
- data = JSON.parse(window.sessionStorage.getItem(item));
+ const sid = this.getID();
+ const item = 'luci-session-store';
+ let data = JSON.parse(window.sessionStorage.getItem(item));
if (!LuCI.prototype.isObject(data) || !data.hasOwnProperty(sid)) {
data = {};
* @returns {boolean}
* Returns `true` if the data could be stored or `false` on error.
*/
- setLocalData: function(key, value) {
+ setLocalData(key, value) {
if (key == null)
return false;
try {
- var sid = this.getID(),
- item = 'luci-session-store',
- data = JSON.parse(window.sessionStorage.getItem(item));
+ const sid = this.getID();
+ const item = 'luci-session-store';
+ let data = JSON.parse(window.sessionStorage.getItem(item));
if (!LuCI.prototype.isObject(data) || !data.hasOwnProperty(sid)) {
data = {};
* The `view` class forms the basis of views and provides a standard
* set of methods to inherit from.
*/
- var View = Class.extend(/** @lends LuCI.view.prototype */ {
+ const View = Class.extend(/** @lends LuCI.view.prototype */ {
__name__: 'LuCI.view',
- __init__: function() {
- var vp = document.getElementById('view');
+ __init__() {
+ const vp = document.getElementById('view');
DOM.content(vp, E('div', { 'class': 'spinning' }, _('Loading view…')));
return Promise.resolve(this.load())
.then(LuCI.prototype.bind(this.render, this))
.then(LuCI.prototype.bind(function(nodes) {
- var vp = document.getElementById('view');
+ const vp = document.getElementById('view');
DOM.content(vp, nodes);
DOM.append(vp, this.addFooter());
* @returns {*|Promise<*>}
* May return any value or a Promise resolving to any value.
*/
- load: function() {},
+ load() {},
/**
* The render function is invoked after the
* Should return a DOM `Node` value or a `Promise` resolving
* to a `Node` value.
*/
- render: function() {},
+ render() {},
/**
* The handleSave function is invoked when the user clicks
* returned promise runs to completion before the button
* is re-enabled.
*/
- handleSave: function(ev) {
- var tasks = [];
+ handleSave(ev) {
+ const tasks = [];
document.getElementById('maincontent')
- .querySelectorAll('.cbi-map').forEach(function(map) {
+ .querySelectorAll('.cbi-map').forEach(map => {
tasks.push(DOM.callClassMethod(map, 'save'));
});
* returned promise runs to completion before the button
* is re-enabled.
*/
- handleSaveApply: function(ev, mode) {
- return this.handleSave(ev).then(function() {
+ handleSaveApply(ev, mode) {
+ return this.handleSave(ev).then(() => {
classes.ui.changes.apply(mode == '0');
});
},
* returned promise runs to completion before the button
* is re-enabled.
*/
- handleReset: function(ev) {
- var tasks = [];
+ handleReset(ev) {
+ const tasks = [];
document.getElementById('maincontent')
- .querySelectorAll('.cbi-map').forEach(function(map) {
+ .querySelectorAll('.cbi-map').forEach(map => {
tasks.push(DOM.callClassMethod(map, 'reset'));
});
* or an empty `DocumentFragment` if all three `handle*()`
* methods are overwritten with `null`.
*/
- addFooter: function() {
- var footer = E([]),
- vp = document.getElementById('view'),
- hasmap = false,
- readonly = true;
+ addFooter() {
+ const footer = E([]);
+ const vp = document.getElementById('view');
+ let hasmap = false;
+ let readonly = true;
- vp.querySelectorAll('.cbi-map').forEach(function(map) {
- var m = DOM.findClassInstance(map);
+ vp.querySelectorAll('.cbi-map').forEach(map => {
+ const m = DOM.findClassInstance(map);
if (m) {
hasmap = true;
if (!hasmap)
readonly = !LuCI.prototype.hasViewPermission();
- var saveApplyBtn = this.handleSaveApply ? new classes.ui.ComboButton('0', {
+ const saveApplyBtn = this.handleSaveApply ? new classes.ui.ComboButton('0', {
0: [ _('Save & Apply') ],
1: [ _('Apply unchecked') ]
}, {
});
- var dummyElem = null,
- domParser = null,
- originalCBIInit = null,
- rpcBaseURL = null,
- sysFeatures = null,
- preloadClasses = null;
+ const domParser = new DOMParser();
+ let originalCBIInit = null;
+ let rpcBaseURL = null;
+ let sysFeatures = null;
+ let preloadClasses = null;
/* "preload" builtin classes to make the available via require */
- var classes = {
+ const classes = {
baseclass: Class,
dom: DOM,
poll: Poll,
view: View
};
- var naturalCompare = new Intl.Collator(undefined, { numeric: true }).compare;
+ const naturalCompare = new Intl.Collator(undefined, { numeric: true }).compare;
- var LuCI = Class.extend(/** @lends LuCI.prototype */ {
+ const LuCI = Class.extend(/** @lends LuCI.prototype */ {
__name__: 'LuCI',
- __init__: function(setenv) {
+ __init__(setenv) {
- document.querySelectorAll('script[src*="/luci.js"]').forEach(function(s) {
+ document.querySelectorAll('script[src*="/luci.js"]').forEach(s => {
if (setenv.base_url == null || setenv.base_url == '') {
- var m = (s.getAttribute('src') || '').match(/^(.*)\/luci\.js(?:\?v=([^?]+))?$/);
+ const m = (s.getAttribute('src') ?? '').match(/^(.*)\/luci\.js(?:\?v=([^?]+))?$/);
if (m) {
setenv.base_url = m[1];
setenv.resource_version = m[2];
Object.assign(env, setenv);
- var domReady = new Promise(function(resolveFn, rejectFn) {
+ const domReady = new Promise((resolveFn, rejectFn) => {
document.addEventListener('DOMContentLoaded', resolveFn);
});
]).then(this.setupDOM.bind(this)).catch(this.error);
originalCBIInit = window.cbi_init;
- window.cbi_init = function() {};
+ window.cbi_init = () => {};
},
/**
* appended to the message and the type set to the given type
* argument or copied from the given error instance.
*/
- raise: function(type, fmt /*, ...*/) {
- var e = null,
- msg = fmt ? String.prototype.format.apply(fmt, this.varargs(arguments, 2)) : null,
- stack = null;
+ raise(type, fmt, ...args) {
+ let e = null;
+ const msg = fmt ? String.prototype.format.call(fmt, ...args) : null;
+ const stack = [];
if (type instanceof Error) {
e = type;
if (msg)
- e.message = msg + ': ' + e.message;
+ e.message = `${msg}: ${e.message}`;
}
else {
try { throw new Error('stacktrace') }
- catch (e2) { stack = (e2.stack || '').split(/\n/) }
+ catch (e2) { stack.push(...(e2.stack ?? '').split(/\n/)) }
- e = new (window[type || 'Error'] || Error)(msg || 'Unspecified error');
- e.name = type || 'Error';
+ e = new (window[type ?? 'Error'] ?? Error)(msg ?? 'Unspecified error');
+ e.name = type ?? 'Error';
}
- stack = (stack || []).map(function(frame) {
- frame = frame.replace(/(.*?)@(.+):(\d+):(\d+)/g, 'at $1 ($2:$3:$4)').trim();
- return frame ? ' ' + frame : '';
- });
+ for (let i = 0; i < stack.length; i++) {
+ const frame = stack[i].replace(/(.*?)@(.+):(\d+):(\d+)/g, 'at $1 ($2:$3:$4)').trim();
+ stack[i] = frame ? ` ${frame}` : '';
+ }
if (!/^ at /.test(stack[0]))
stack.shift();
stack.shift();
if (stack.length)
- e.message += '\n' + stack.join('\n');
+ e.message += `\n${stack.join('\n')}`;
if (window.console && console.debug)
console.debug(e);
* appended to the message and the type set to the given type
* argument or copied from the given error instance.
*/
- error: function(type, fmt /*, ...*/) {
+ error(type, fmt /*, ...*/) {
try {
LuCI.prototype.raise.apply(LuCI.prototype,
Array.prototype.slice.call(arguments));
* @returns {function}
* Returns the bound function.
*/
- bind: function(fn, self /*, ... */) {
- return Function.prototype.bind.apply(fn, this.varargs(arguments, 2, self));
+ bind(fn, self, ...args) {
+ return Function.prototype.bind.call(fn, self, ...args);
},
/**
* @returns {Promise<LuCI.baseclass>}
* Returns the instantiated class.
*/
- require: function(name, from) {
- var L = this, url = null, from = from || [];
+ require(name, from = []) {
+ const L = this;
+ let url = null;
/* Class already loaded */
if (classes[name] != null) {
return Promise.resolve(classes[name]);
}
- url = '%s/%s.js%s'.format(env.base_url, name.replace(/\./g, '/'), (env.resource_version ? '?v=' + env.resource_version : ''));
+ url = '%s/%s.js%s'.format(env.base_url, name.replace(/\./g, '/'), (env.resource_version ? `?v=${env.resource_version}` : ''));
from = [ name ].concat(from);
- var compileClass = function(res) {
+ const compileClass = res => {
if (!res.ok)
LuCI.prototype.raise('NetworkError',
'HTTP error %d while loading class file "%s"', res.status, url);
- var source = res.text(),
- requirematch = /^require[ \t]+(\S+)(?:[ \t]+as[ \t]+([a-zA-Z_]\S*))?$/,
- strictmatch = /^use[ \t]+strict$/,
- depends = [],
- args = '';
+ const source = res.text();
+ const requirematch = /^require[ \t]+(\S+)(?:[ \t]+as[ \t]+([a-zA-Z_]\S*))?$/;
+ const strictmatch = /^use[ \t]+strict$/;
+ const depends = [];
+ let args = '';
/* find require statements in source */
- for (var i = 0, off = -1, prev = -1, quote = -1, comment = -1, esc = false; i < source.length; i++) {
- var chr = source.charCodeAt(i);
+ for (let i = 0, off = -1, prev = -1, quote = -1, comment = -1, esc = false; i < source.length; i++) {
+ const chr = source.charCodeAt(i);
if (esc) {
esc = false;
esc = true;
}
else if (chr == quote) {
- var s = source.substring(off, i),
- m = requirematch.exec(s);
+ const s = source.substring(off, i), m = requirematch.exec(s);
if (m) {
- var dep = m[1], as = m[2] || dep.replace(/[^a-zA-Z0-9_]/g, '_');
+ const dep = m[1], as = m[2] || dep.replace(/[^a-zA-Z0-9_]/g, '_');
depends.push(LuCI.prototype.require(dep, from));
- args += ', ' + as;
+ args += `, ${as}`;
}
else if (!strictmatch.exec(s)) {
break;
}
/* load dependencies and instantiate class */
- return Promise.all(depends).then(function(instances) {
- var _factory, _class;
+ return Promise.all(depends).then(instances => {
+ let _factory, _class;
try {
_factory = eval(
}
catch (error) {
LuCI.prototype.raise('SyntaxError', '%s\n in %s:%s',
- error.message, res.url, error.lineNumber || '?');
+ error.message, res.url, error.lineNumber ?? '?');
}
- _factory.displayName = toCamelCase(name + 'ClassFactory');
+ _factory.displayName = toCamelCase(`${name}ClassFactory`);
_class = _factory.apply(_factory, [window, document, L].concat(instances));
if (!Class.isSubclass(_class))
- LuCI.prototype.error('TypeError', '"%s" factory yields invalid constructor', name);
+ LuCI.prototype.error('TypeError', '"%s" factory yields invalid constructor', name);
if (_class.displayName == 'AnonymousClass')
- _class.displayName = toCamelCase(name + 'Class');
+ _class.displayName = toCamelCase(`${name}Class`);
- var ptr = Object.getPrototypeOf(L),
- parts = name.split(/\./),
- instance = new _class();
+ let ptr = Object.getPrototypeOf(L);
+ let idx = 0;
+ const parts = name.split(/\./);
+ const instance = new _class();
- for (var i = 0; ptr && i < parts.length - 1; i++)
- ptr = ptr[parts[i]];
+ while (ptr && idx < parts.length - 1)
+ ptr = ptr[parts[idx++]];
if (ptr)
- ptr[parts[i]] = instance;
+ ptr[parts[idx]] = instance;
classes[name] = instance;
},
/* DOM setup */
- probeRPCBaseURL: function() {
+ probeRPCBaseURL() {
if (rpcBaseURL == null)
rpcBaseURL = Session.getLocalData('rpcBaseURL');
if (rpcBaseURL == null) {
- var msg = {
+ const msg = {
jsonrpc: '2.0',
- id: 'init',
+ id: 'init',
method: 'list',
params: undefined
};
- var rpcFallbackURL = this.url('admin/ubus');
+ const rpcFallbackURL = this.url('admin/ubus');
- rpcBaseURL = Request.post(env.ubuspath, msg, { nobatch: true }).then(function(res) {
- return (rpcBaseURL = res.status == 200 ? env.ubuspath : rpcFallbackURL);
- }, function() {
- return (rpcBaseURL = rpcFallbackURL);
- }).then(function(url) {
+ rpcBaseURL = Request.post(env.ubuspath, msg, { nobatch: true }).then(res => rpcBaseURL = res.status == 200 ? env.ubuspath : rpcFallbackURL, () => rpcBaseURL = rpcFallbackURL).then(url => {
Session.setLocalData('rpcBaseURL', url);
return url;
});
return Promise.resolve(rpcBaseURL);
},
- probeSystemFeatures: function() {
+ probeSystemFeatures() {
if (sysFeatures == null)
sysFeatures = Session.getLocalData('features');
object: 'luci',
method: 'getFeatures',
expect: { '': {} }
- })().then(function(features) {
+ })().then(features => {
Session.setLocalData('features', features);
sysFeatures = features;
return Promise.resolve(sysFeatures);
},
- probePreloadClasses: function() {
+ probePreloadClasses() {
if (preloadClasses == null)
preloadClasses = Session.getLocalData('preload');
method: 'list',
params: [ 'path' ],
expect: { 'entries': [] }
- })(this.fspath(this.resource('preload'))), []).then(function(entries) {
- var classes = [];
+ })(this.fspath(this.resource('preload'))), []).then(entries => {
+ const classes = [];
- for (var i = 0; i < entries.length; i++) {
+ for (let i = 0; i < entries.length; i++) {
if (entries[i].type != 'file')
continue;
- var m = entries[i].name.match(/(.+)\.js$/);
+ const m = entries[i].name.match(/(.+)\.js$/);
if (m)
classes.push('preload.%s'.format(m[1]));
* Return `null` when a sub-feature was queried for a feature which
* has no sub-features.
*/
- hasSystemFeature: function() {
- var ft = sysFeatures[arguments[0]];
+ hasSystemFeature() {
+ const ft = sysFeatures[arguments[0]];
if (arguments.length == 2)
return this.isObject(ft) ? ft[arguments[1]] : null;
},
/* private */
- notifySessionExpiry: function() {
+ notifySessionExpiry() {
Poll.stop();
classes.ui.showModal(_('Session expired'), [
E('div', { class: 'right' },
E('div', {
class: 'btn primary',
- click: function() {
- var loc = window.location;
- window.location = loc.protocol + '//' + loc.host + loc.pathname + loc.search;
+ click() {
+ const loc = window.location;
+ window.location = `${loc.protocol}//${loc.host}${loc.pathname}${loc.search}`;
}
}, _('Log in…')))
]);
},
/* private */
- setupDOM: function(res) {
- var domEv = res[0],
- uiClass = res[1],
- rpcClass = res[2],
- formClass = res[3],
- rpcBaseURL = res[4];
+ setupDOM(res) {
+ const domEv = res[0], uiClass = res[1], rpcClass = res[2], formClass = res[3], rpcBaseURL = res[4];
rpcClass.setBaseURL(rpcBaseURL);
- rpcClass.addInterceptor(function(msg, req) {
+ rpcClass.addInterceptor((msg, req) => {
if (!LuCI.prototype.isObject(msg) ||
- !LuCI.prototype.isObject(msg.error) ||
- msg.error.code != -32002)
+ !LuCI.prototype.isObject(msg.error) ||
+ msg.error.code != -32002)
return;
if (!LuCI.prototype.isObject(req) ||
- (req.object == 'session' && req.method == 'access'))
+ (req.object == 'session' && req.method == 'access'))
return;
return rpcClass.declare({
})('uci', 'luci', 'read').catch(LuCI.prototype.notifySessionExpiry);
});
- Request.addInterceptor(function(res) {
- var isDenied = false;
+ Request.addInterceptor(res => {
+ let isDenied = false;
if (res.status == 403 && res.headers.get('X-LuCI-Login-Required') == 'yes')
isDenied = true;
LuCI.prototype.notifySessionExpiry();
});
- document.addEventListener('poll-start', function(ev) {
- uiClass.showIndicator('poll-status', _('Refreshing'), function(ev) {
+ document.addEventListener('poll-start', ev => {
+ uiClass.showIndicator('poll-status', _('Refreshing'), ev => {
Request.poll.active() ? Request.poll.stop() : Request.poll.start();
});
});
- document.addEventListener('poll-stop', function(ev) {
+ document.addEventListener('poll-stop', ev => {
uiClass.showIndicator('poll-status', _('Paused'), null, 'inactive');
});
this.probeSystemFeatures(),
this.probePreloadClasses()
]).finally(LuCI.prototype.bind(function() {
- var tasks = [];
+ const tasks = [];
if (Array.isArray(preloadClasses))
- for (var i = 0; i < preloadClasses.length; i++)
+ for (let i = 0; i < preloadClasses.length; i++)
tasks.push(this.require(preloadClasses[i]));
return Promise.all(tasks);
},
/* private */
- initDOM: function() {
+ initDOM() {
originalCBIInit();
Poll.start();
document.dispatchEvent(new CustomEvent('luci-loaded'));
* @instance
* @memberof LuCI
*/
- env: env,
+ env,
/**
* Construct an absolute filesystem path relative to the server
* @return {string}
* Return the joined path.
*/
- fspath: function(/* ... */) {
- var path = env.documentroot;
+ fspath() /* ... */{
+ let path = env.documentroot;
- for (var i = 0; i < arguments.length; i++)
- path += '/' + arguments[i];
+ for (let i = 0; i < arguments.length; i++)
+ path += `/${arguments[i]}`;
- var p = path.replace(/\/+$/, '').replace(/\/+/g, '/').split(/\//),
- res = [];
+ const p = path.replace(/\/+$/, '').replace(/\/+/g, '/').split(/\//), res = [];
- for (var i = 0; i < p.length; i++)
+ for (let i = 0; i < p.length; i++)
if (p[i] == '..')
res.pop();
else if (p[i] != '.')
* @return {string}
* Return the joined URL path.
*/
- path: function(prefix, parts) {
- var url = [ prefix || '' ];
+ path(prefix = '', parts) {
+ const url = [ prefix ];
- for (var i = 0; i < parts.length; i++)
+ for (let i = 0; i < parts.length; i++)
if (/^(?:[a-zA-Z0-9_.%,;-]+\/)*[a-zA-Z0-9_.%,;-]+$/.test(parts[i]) || /^\?[a-zA-Z0-9_.%=&;-]+$/.test(parts[i]))
url.push(parts[i].startsWith('?') ? parts[i] : '/' + parts[i]);
* @return {string}
* Returns the resulting URL path.
*/
- url: function() {
+ url() {
return this.path(env.scriptname, arguments);
},
* @return {string}
* Returns the resulting URL path.
*/
- resource: function() {
+ resource() {
return this.path(env.resource, arguments);
},
* @return {string}
* Returns the resulting URL path.
*/
- media: function() {
+ media() {
return this.path(env.media, arguments);
},
* @return {string}
* Returns the URL path to the current view.
*/
- location: function() {
+ location() {
return this.path(env.scriptname, env.requestpath);
},
* Returns `true` if the given value is of type object and
* not `null`, else returns `false`.
*/
- isObject: function(val) {
+ isObject(val) {
return (val != null && typeof(val) == 'object');
},
+ /**
+ * Tests whether the passed argument is a function arguments object.
+ *
+ * @instance
+ * @memberof LuCI
+ *
+ * @param {*} [val]
+ * The value to test
+ *
+ * @return {boolean}
+ * Returns `true` if the given value is a function arguments object,
+ * else returns `false`.
+ */
+ isArguments(val) {
+ return (Object.prototype.toString.call(val) == '[object Arguments]');
+ },
+
/**
* Return an array of sorted object keys, optionally sorted by
* a different key or a different sorting mode.
* @return {string[]}
* Returns an array containing the sorted keys of the given object.
*/
- sortedKeys: function(obj, key, sortmode) {
+ sortedKeys(obj, key, sortmode) {
if (obj == null || typeof(obj) != 'object')
return [];
- return Object.keys(obj).map(function(e) {
- var v = (key != null) ? obj[e][key] : e;
+ return Object.keys(obj).map(e => {
+ let v = (key != null) ? obj[e][key] : e;
switch (sortmode) {
case 'addr':
v = (v != null) ? v.replace(/(?:^|[.:])([0-9a-fA-F]{1,4})/g,
- function(m0, m1) { return ('000' + m1.toLowerCase()).substr(-4) }) : null;
+ (m0, m1) => (`000${m1.toLowerCase()}`).substr(-4)) : null;
break;
case 'num':
}
return [ e, v ];
- }).filter(function(e) {
- return (e[1] != null);
- }).sort(function(a, b) {
- return naturalCompare(a[1], b[1]);
- }).map(function(e) {
- return e[0];
- });
+ }).filter(e => e[1] != null).sort((a, b) => naturalCompare(a[1], b[1])).map(e => e[0]);
},
/**
* Returns 0 if both values are equal.
* Returns 1 if the first value is larger than the second one.
*/
- naturalCompare: naturalCompare,
+ naturalCompare,
/**
* Converts the given value to an array using toArray() if needed,
* @return {Array<*>}
* Returns the resulting, numerically sorted array.
*/
- sortedArray: function(val) {
+ sortedArray(val) {
return this.toArray(val).sort(naturalCompare);
},
* @return {Array<*>}
* Returns the resulting array.
*/
- toArray: function(val) {
+ toArray(val) {
if (val == null)
return [];
else if (Array.isArray(val))
else if (typeof(val) == 'object')
return [ val ];
- var s = String(val).trim();
+ const s = String(val).trim();
if (s == '')
return [];
* Returns a new promise resolving either to the given input value or
* to the given default value on error.
*/
- resolveDefault: function(value, defvalue) {
- return Promise.resolve(value).catch(function() { return defvalue });
+ resolveDefault(value, defvalue) {
+ return Promise.resolve(value).catch(() => defvalue);
},
/**
* @return {Promise<null>}
* Returns a promise resolving to `null` when concluded.
*/
- get: function(url, args, cb) {
+ get(url, args, cb) {
return this.poll(null, url, args, cb, false);
},
* @return {Promise<null>}
* Returns a promise resolving to `null` when concluded.
*/
- post: function(url, args, cb) {
+ post(url, args, cb) {
return this.poll(null, url, args, cb, true);
},
* be passed to {@link LuCI.poll.remove Poll.remove()} to remove the
* polling request.
*/
- poll: function(interval, url, args, cb, post) {
+ poll(interval, url, args, cb, post) {
if (interval !== null && interval <= 0)
interval = env.pollinterval;
- var data = post ? { token: env.token } : null,
- method = post ? 'POST' : 'GET';
+ const data = Object.assign(post ? { token: env.token } : {}, args);
+ const method = post ? 'POST' : 'GET';
if (!/^(?:\/|\S+:\/\/)/.test(url))
url = this.url(url);
- if (args != null)
- data = Object.assign(data || {}, args);
-
if (interval !== null)
- return Request.poll.add(interval, url, { method: method, query: data }, cb);
+ return Request.poll.add(interval, url, { method, query: data }, cb);
else
- return Request.request(url, { method: method, query: data })
- .then(function(res) {
- var json = null;
+ return Request.request(url, { method, query: data })
+ .then(res => {
+ let json = null;
if (/^application\/json\b/.test(res.headers.get('Content-Type')))
try { json = res.json() } catch(e) {}
cb(res.xhr, json, res.duration);
* permissions are granted or `true` if at least one required ACL
* group is granted with write permissions.
*/
- hasViewPermission: function() {
+ hasViewPermission() {
if (!this.isObject(env.nodespec) || !env.nodespec.satisfied)
- return null;
+ return null;
return !env.nodespec.readonly;
},
* Returns `true` when the function has been removed or `false` if
* it could not be found.
*/
- stop: function(entry) { return Poll.remove(entry) },
+ stop(entry) { return Poll.remove(entry) },
/**
* Deprecated wrapper around {@link LuCI.poll.stop Poll.stop()}.
* Returns `true` when the polling loop has been stopped or `false`
* when it didn't run to begin with.
*/
- halt: function() { return Poll.stop() },
+ halt() { return Poll.stop() },
/**
* Deprecated wrapper around {@link LuCI.poll.start Poll.start()}.
* Returns `true` when the polling loop has been started or `false`
* when it was already running.
*/
- run: function() { return Poll.start() },
+ run() { return Poll.start() },
/**
* Legacy `L.dom` class alias. New view code should use `'require dom';`
* @memberof LuCI
* @deprecated
*/
- Poll: Poll,
+ Poll,
/**
* Legacy `L.Request` class alias. New view code should use `'require request';`
* @memberof LuCI
* @deprecated
*/
- Request: Request,
+ Request,
/**
* Legacy `L.Class` class alias. New view code should use `'require baseclass';`
* @memberof LuCI
* @deprecated
*/
- Class: Class
+ Class
});
/**
* New code should use {@link LuCI.request} instead to implement HTTP
* request handling.
*/
- var XHR = Class.extend(/** @lends LuCI.xhr.prototype */ {
+ const XHR = Class.extend(/** @lends LuCI.xhr.prototype */ {
__name__: 'LuCI.xhr',
- __init__: function() {
+ __init__() {
if (window.console && console.debug)
console.debug('Direct use XHR() is deprecated, please use L.Request instead');
},
- _response: function(cb, res, json, duration) {
+ _response(cb, res, json, duration) {
if (this.active)
cb(res, json, duration);
delete this.active;
*
* @return {Promise<null>}
*/
- get: function(url, data, callback, timeout) {
+ get(url, data, callback, timeout) {
this.active = true;
LuCI.prototype.get(url, data, this._response.bind(this, callback), timeout);
},
*
* @return {Promise<null>}
*/
- post: function(url, data, callback, timeout) {
+ post(url, data, callback, timeout) {
this.active = true;
LuCI.prototype.post(url, data, this._response.bind(this, callback), timeout);
},
* @deprecated
* @memberof LuCI.xhr
*/
- cancel: function() { delete this.active },
+ cancel() { delete this.active },
/**
* Checks the running state of the request.
* Returns `true` if the request is still running or `false` if it
* already completed.
*/
- busy: function() { return (this.active === true) },
+ busy() { return (this.active === true) },
/**
* Ignored for backwards compatibility.
* @deprecated
* @memberof LuCI.xhr
*/
- abort: function() {},
+ abort() {},
/**
* Existing for backwards compatibility.
* Throws an `InternalError` with the message `Not implemented`
* when invoked.
*/
- send_form: function() { LuCI.prototype.error('InternalError', 'Not implemented') },
+ send_form() { LuCI.prototype.error('InternalError', 'Not implemented') },
});
- XHR.get = function() { return LuCI.prototype.get.apply(LuCI.prototype, arguments) };
- XHR.post = function() { return LuCI.prototype.post.apply(LuCI.prototype, arguments) };
- XHR.poll = function() { return LuCI.prototype.poll.apply(LuCI.prototype, arguments) };
+ XHR.get = (...args) => LuCI.prototype.get.call(LuCI.prototype, ...args);
+ XHR.post = (...args) => LuCI.prototype.post.call(LuCI.prototype, ...args);
+ XHR.poll = (...args) => LuCI.prototype.poll.call(LuCI.prototype, ...args);
XHR.stop = Request.poll.remove.bind(Request.poll);
XHR.halt = Request.poll.stop.bind(Request.poll);
XHR.run = Request.poll.start.bind(Request.poll);