From 683bc54fd9bfc22c900dc0cdfcd660d61da253ef Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Thu, 6 Aug 2020 17:58:47 +0200 Subject: docs: update js api docs Signed-off-by: Jo-Philipp Wich --- docs/jsapi/ui.js.html | 309 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 257 insertions(+), 52 deletions(-) (limited to 'docs/jsapi/ui.js.html') diff --git a/docs/jsapi/ui.js.html b/docs/jsapi/ui.js.html index b58cf93f94..c8df7d7e4d 100644 --- a/docs/jsapi/ui.js.html +++ b/docs/jsapi/ui.js.html @@ -292,8 +292,16 @@
  • cfgsections
  • +
  • cfgvalue
  • +
  • filter
  • +
  • formvalue
  • + +
  • getOption
  • + +
  • getUIElement
  • +
  • load
  • option
  • @@ -333,6 +341,8 @@
  • modalonly
  • +
  • onchange
  • +
  • optional
  • readonly
  • @@ -423,6 +433,8 @@
  • modalonly
  • +
  • onchange
  • +
  • optional
  • password
  • @@ -513,6 +525,8 @@
  • modalonly
  • +
  • onchange
  • +
  • optional
  • password
  • @@ -599,6 +613,8 @@
  • modalonly
  • +
  • onchange
  • +
  • optional
  • password
  • @@ -693,6 +709,8 @@
  • modalonly
  • +
  • onchange
  • +
  • optional
  • password
  • @@ -783,6 +801,8 @@
  • modalonly
  • +
  • onchange
  • +
  • optional
  • password
  • @@ -873,6 +893,8 @@
  • modaltitle
  • +
  • nodescriptions
  • +
  • parentoption
  • rowcolors
  • @@ -900,8 +922,16 @@
  • append
  • +
  • cfgvalue
  • +
  • filter
  • +
  • formvalue
  • + +
  • getOption
  • + +
  • getUIElement
  • +
  • load
  • option
  • @@ -939,6 +969,8 @@
  • modalonly
  • +
  • onchange
  • +
  • optional
  • password
  • @@ -1071,8 +1103,12 @@ Members +
  • orientation
  • +
  • size
  • +
  • widget
  • +
  • datatype
  • default
  • @@ -1081,6 +1117,8 @@
  • modalonly
  • +
  • onchange
  • +
  • optional
  • password
  • @@ -1225,6 +1263,8 @@
  • modalonly
  • +
  • onchange
  • +
  • optional
  • password
  • @@ -1324,8 +1364,16 @@
  • cfgsections
  • +
  • cfgvalue
  • +
  • filter
  • +
  • formvalue
  • + +
  • getOption
  • + +
  • getUIElement
  • +
  • load
  • option
  • @@ -1367,6 +1415,8 @@
  • modalonly
  • +
  • onchange
  • +
  • optional
  • password
  • @@ -1457,6 +1507,8 @@
  • modaltitle
  • +
  • nodescriptions
  • +
  • rowcolors
  • sectiontitle
  • @@ -1492,8 +1544,16 @@
  • append
  • +
  • cfgvalue
  • +
  • filter
  • +
  • formvalue
  • + +
  • getOption
  • + +
  • getUIElement
  • +
  • load
  • option
  • @@ -1539,6 +1599,8 @@
  • modalonly
  • +
  • onchange
  • +
  • optional
  • password
  • @@ -1642,8 +1704,16 @@
  • cfgsections
  • +
  • cfgvalue
  • +
  • filter
  • +
  • formvalue
  • + +
  • getOption
  • + +
  • getUIElement
  • +
  • load
  • option
  • @@ -1687,6 +1757,8 @@
  • modalonly
  • +
  • onchange
  • +
  • optional
  • readonly
  • @@ -2520,6 +2592,8 @@
  • getLocalData
  • +
  • getToken
  • +
  • setLocalData
  • @@ -2670,6 +2744,8 @@
  • getValue
  • +
  • isChanged
  • +
  • isValid
  • registerEvents
  • @@ -2678,6 +2754,8 @@
  • setChangeEvents
  • +
  • setPlaceholder
  • +
  • setUpdateEvents
  • setValue
  • @@ -2748,6 +2826,8 @@
  • getValue
  • +
  • isChanged
  • +
  • isChecked
  • isValid
  • @@ -2758,6 +2838,8 @@
  • setChangeEvents
  • +
  • setPlaceholder
  • +
  • setUpdateEvents
  • setValue
  • @@ -2798,12 +2880,16 @@
  • closeAllDropdowns
  • +
  • isChanged
  • +
  • isValid
  • registerEvents
  • setChangeEvents
  • +
  • setPlaceholder
  • +
  • setUpdateEvents
  • triggerValidation
  • @@ -2842,12 +2928,16 @@
  • closeAllDropdowns
  • +
  • isChanged
  • +
  • isValid
  • registerEvents
  • setChangeEvents
  • +
  • setPlaceholder
  • +
  • setUpdateEvents
  • triggerValidation
  • @@ -2888,6 +2978,8 @@
  • getValue
  • +
  • isChanged
  • +
  • isValid
  • registerEvents
  • @@ -2896,6 +2988,8 @@
  • setChangeEvents
  • +
  • setPlaceholder
  • +
  • setUpdateEvents
  • setValue
  • @@ -2936,6 +3030,8 @@
  • getValue
  • +
  • isChanged
  • +
  • isValid
  • registerEvents
  • @@ -2944,6 +3040,8 @@
  • setChangeEvents
  • +
  • setPlaceholder
  • +
  • setUpdateEvents
  • setValue
  • @@ -2980,6 +3078,8 @@
  • getValue
  • +
  • isChanged
  • +
  • isValid
  • registerEvents
  • @@ -2988,6 +3088,8 @@
  • setChangeEvents
  • +
  • setPlaceholder
  • +
  • setUpdateEvents
  • setValue
  • @@ -3020,6 +3122,8 @@
  • getValue
  • +
  • isChanged
  • +
  • isValid
  • registerEvents
  • @@ -3028,6 +3132,8 @@
  • setChangeEvents
  • +
  • setPlaceholder
  • +
  • setUpdateEvents
  • setValue
  • @@ -3098,6 +3204,8 @@
  • getValue
  • +
  • isChanged
  • +
  • isValid
  • registerEvents
  • @@ -3106,6 +3214,8 @@
  • setChangeEvents
  • +
  • setPlaceholder
  • +
  • setUpdateEvents
  • setValue
  • @@ -3170,6 +3280,8 @@
  • getValue
  • +
  • isChanged
  • +
  • isValid
  • registerEvents
  • @@ -3178,6 +3290,8 @@
  • setChangeEvents
  • +
  • setPlaceholder
  • +
  • setUpdateEvents
  • setValue
  • @@ -3214,6 +3328,8 @@
  • getValue
  • +
  • isChanged
  • +
  • isValid
  • registerEvents
  • @@ -3222,6 +3338,8 @@
  • setChangeEvents
  • +
  • setPlaceholder
  • +
  • setUpdateEvents
  • setValue
  • @@ -3419,6 +3537,47 @@ var UIElement = baseclass.extend(/** @lends LuCI.ui.AbstractElement.prototype */ this.node.value = value; }, + /** + * Set the current placeholder value of the input widget. + * + * @instance + * @memberof LuCI.ui.AbstractElement + * @param {string|string[]|null} value + * The placeholder to set for the input element. Only applicable to text + * inputs, not to radio buttons, selects or similar. + */ + setPlaceholder: function(value) { + var node = this.node ? this.node.querySelector('input,textarea') : null; + if (node) { + switch (node.getAttribute('type') || 'text') { + case 'password': + case 'search': + case 'tel': + case 'text': + case 'url': + if (value != null && value != '') + node.setAttribute('placeholder', value); + else + node.removeAttribute('placeholder'); + } + } + }, + + /** + * Check whether the input value was altered by the user. + * + * @instance + * @memberof LuCI.ui.AbstractElement + * @returns {boolean} + * Returns `true` if the input value has been altered by the user or + * `false` if it is unchaged. Note that if the user modifies the initial + * value and changes it back to the original state, it is still reported + * as changed. + */ + isChanged: function() { + return (this.node ? this.node.getAttribute('data-changed') : null) == 'true'; + }, + /** * Check whether the current input value is valid. * @@ -3628,48 +3787,45 @@ var UITextfield = UIElement.extend(/** @lends LuCI.ui.Textfield.prototype */ { /** @override */ render: function() { var frameEl = E('div', { 'id': this.options.id }); - - if (this.options.password) { - frameEl.classList.add('nowrap'); - frameEl.appendChild(E('input', { - 'type': 'password', - 'style': 'position:absolute; left:-100000px', - 'aria-hidden': true, - 'tabindex': -1, - 'name': this.options.name ? 'password.%s'.format(this.options.name) : null - })); - } - - frameEl.appendChild(E('input', { + var inputEl = E('input', { 'id': this.options.id ? 'widget.' + this.options.id : null, 'name': this.options.name, - 'type': this.options.password ? 'password' : 'text', + 'type': 'text', 'class': this.options.password ? 'cbi-input-password' : 'cbi-input-text', 'readonly': this.options.readonly ? '' : null, 'disabled': this.options.disabled ? '' : null, 'maxlength': this.options.maxlength, 'placeholder': this.options.placeholder, 'value': this.value, - })); + }); - if (this.options.password) - frameEl.appendChild(E('button', { - 'class': 'cbi-button cbi-button-neutral', - 'title': _('Reveal/hide password'), - 'aria-label': _('Reveal/hide password'), - 'click': function(ev) { - var e = this.previousElementSibling; - e.type = (e.type === 'password') ? 'text' : 'password'; - ev.preventDefault(); - } - }, '∗')); + if (this.options.password) { + frameEl.appendChild(E('div', { 'class': 'control-group' }, [ + inputEl, + E('button', { + 'class': 'cbi-button cbi-button-neutral', + 'title': _('Reveal/hide password'), + 'aria-label': _('Reveal/hide password'), + 'click': function(ev) { + var e = this.previousElementSibling; + e.type = (e.type === 'password') ? 'text' : 'password'; + ev.preventDefault(); + } + }, '∗') + ])); + + window.requestAnimationFrame(function() { inputEl.type = 'password' }); + } + else { + frameEl.appendChild(inputEl); + } return this.bind(frameEl); }, /** @private */ bind: function(frameEl) { - var inputEl = frameEl.childNodes[+!!this.options.password]; + var inputEl = frameEl.querySelector('input'); this.node = frameEl; @@ -3683,13 +3839,13 @@ var UITextfield = UIElement.extend(/** @lends LuCI.ui.Textfield.prototype */ { /** @override */ getValue: function() { - var inputEl = this.node.childNodes[+!!this.options.password]; + var inputEl = this.node.querySelector('input'); return inputEl.value; }, /** @override */ setValue: function(value) { - var inputEl = this.node.childNodes[+!!this.options.password]; + var inputEl = this.node.querySelector('input'); inputEl.value = value; } }); @@ -3762,7 +3918,8 @@ var UITextarea = UIElement.extend(/** @lends LuCI.ui.Textarea.prototype */ { /** @override */ render: function() { - var frameEl = E('div', { 'id': this.options.id }), + var style = !this.options.cols ? 'width:100%' : null, + frameEl = E('div', { 'id': this.options.id, 'style': style }), value = (this.value != null) ? String(this.value) : ''; frameEl.appendChild(E('textarea', { @@ -3772,7 +3929,7 @@ var UITextarea = UIElement.extend(/** @lends LuCI.ui.Textarea.prototype */ { 'readonly': this.options.readonly ? '' : null, 'disabled': this.options.disabled ? '' : null, 'placeholder': this.options.placeholder, - 'style': !this.options.cols ? 'width:100%' : null, + 'style': style, 'cols': this.options.cols, 'rows': this.options.rows, 'wrap': this.options.wrap ? '' : null @@ -4029,7 +4186,7 @@ var UISelect = UIElement.extend(/** @lends LuCI.ui.Select.prototype */ { else if (Array.isArray(this.options.sort)) keys = this.options.sort; - if (this.options.widget == 'select') { + if (this.options.widget != 'radio' && this.options.widget != 'checkbox') { frameEl.appendChild(E('select', { 'id': this.options.id ? 'widget.' + this.options.id : null, 'name': this.options.name, @@ -4056,12 +4213,14 @@ var UISelect = UIElement.extend(/** @lends LuCI.ui.Select.prototype */ { } } else { - var brEl = (this.options.orientation === 'horizontal') ? document.createTextNode(' ') : E('br'); + var brEl = (this.options.orientation === 'horizontal') ? document.createTextNode(' \xa0 ') : E('br'); for (var i = 0; i < keys.length; i++) { - frameEl.appendChild(E('label', {}, [ + frameEl.appendChild(E('span', { + 'class': 'cbi-%s'.format(this.options.multiple ? 'checkbox' : 'radio') + }, [ E('input', { - 'id': this.options.id ? 'widget.' + this.options.id : null, + 'id': this.options.id ? 'widget.%s.%d'.format(this.options.id, i) : null, 'name': this.options.id || this.options.name, 'type': this.options.multiple ? 'checkbox' : 'radio', 'class': this.options.multiple ? 'cbi-input-checkbox' : 'cbi-input-radio', @@ -4069,11 +4228,15 @@ var UISelect = UIElement.extend(/** @lends LuCI.ui.Select.prototype */ { 'checked': (this.values.indexOf(keys[i]) > -1) ? '' : null, 'disabled': this.options.disabled ? '' : null }), - this.choices[keys[i]] || keys[i] + E('label', { 'for': this.options.id ? 'widget.%s.%d'.format(this.options.id, i) : null }), + E('span', { + 'click': function(ev) { + ev.currentTarget.previousElementSibling.previousElementSibling.click(); + } + }, [ this.choices[keys[i]] || keys[i] ]) ])); - if (i + 1 == this.options.size) - frameEl.appendChild(brEl); + frameEl.appendChild(brEl.cloneNode()); } } @@ -4084,7 +4247,7 @@ var UISelect = UIElement.extend(/** @lends LuCI.ui.Select.prototype */ { bind: function(frameEl) { this.node = frameEl; - if (this.options.widget == 'select') { + if (this.options.widget != 'radio' && this.options.widget != 'checkbox') { this.setUpdateEvents(frameEl.firstChild, 'change', 'click', 'blur'); this.setChangeEvents(frameEl.firstChild, 'change'); } @@ -4103,10 +4266,10 @@ var UISelect = UIElement.extend(/** @lends LuCI.ui.Select.prototype */ { /** @override */ getValue: function() { - if (this.options.widget == 'select') + if (this.options.widget != 'radio' && this.options.widget != 'checkbox') return this.node.firstChild.value; - var radioEls = frameEl.querySelectorAll('input[type="radio"]'); + var radioEls = this.node.querySelectorAll('input[type="radio"]'); for (var i = 0; i < radioEls.length; i++) if (radioEls[i].checked) return radioEls[i].value; @@ -4116,7 +4279,7 @@ var UISelect = UIElement.extend(/** @lends LuCI.ui.Select.prototype */ { /** @override */ setValue: function(value) { - if (this.options.widget == 'select') { + if (this.options.widget != 'radio' && this.options.widget != 'checkbox') { if (value == null) value = ''; @@ -4490,7 +4653,7 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { ul.style.maxHeight = (vpHeight * 0.5) + 'px'; ul.style.WebkitOverflowScrolling = 'touch'; - function getScrollParent(element) { + var getScrollParent = function(element) { var parent = element, style = getComputedStyle(element), excludeStaticParent = (style.position === 'absolute'); @@ -5925,21 +6088,24 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ { switch (type) { case 'symlink': return E('img', { - 'src': L.resource('cbi/link.gif'), + 'src': L.resource('cbi/link.svg'), + 'width': 16, 'title': _('Symbolic link'), 'class': 'middle' }); case 'directory': return E('img', { - 'src': L.resource('cbi/folder.gif'), + 'src': L.resource('cbi/folder.svg'), + 'width': 16, 'title': _('Directory'), 'class': 'middle' }); default: return E('img', { - 'src': L.resource('cbi/file.gif'), + 'src': L.resource('cbi/file.svg'), + 'width': 16, 'title': _('File'), 'class': 'middle' }); @@ -6262,6 +6428,27 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ { } }); + +function scrubMenu(node) { + var hasSatisfiedChild = false; + + if (L.isObject(node.children)) { + for (var k in node.children) { + var child = scrubMenu(node.children[k]); + + if (child.title) + hasSatisfiedChild = hasSatisfiedChild || child.satisfied; + } + } + + if (L.isObject(node.action) && + node.action.type == 'firstchild' && + hasSatisfiedChild == false) + node.satisfied = false; + + return node; +}; + /** * Handle menu. * @@ -6297,7 +6484,7 @@ var UIMenu = baseclass.singleton(/** @lends LuCI.ui.menu.prototype */ { if (!L.isObject(this.menu)) { this.menu = request.get(L.url('admin/menu')).then(L.bind(function(menu) { - this.menu = menu.json(); + this.menu = scrubMenu(menu.json()); session.setLocalData('menu', this.menu); return this.menu; @@ -6343,7 +6530,13 @@ var UIMenu = baseclass.singleton(/** @lends LuCI.ui.menu.prototype */ { } return children.sort(function(a, b) { - return ((a.order || 1000) - (b.order || 1000)); + var wA = a.order || 1000, + wB = b.order || 1000; + + if (wA != wB) + return wA - wB; + + return a.name > b.name; }); } }); @@ -6425,6 +6618,7 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { dom.append(dlg, children); document.body.classList.add('modal-overlay-active'); + modalDiv.scrollTop = 0; return dlg; }, @@ -6609,12 +6803,23 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { } var handlerFn = (typeof(handler) == 'function') ? handler : null, - indicatorElem = indicatorDiv.querySelector('span[data-indicator="%s"]'.format(id)) || - indicatorDiv.appendChild(E('span', { + indicatorElem = indicatorDiv.querySelector('span[data-indicator="%s"]'.format(id)); + + if (indicatorElem == null) { + var beforeElem = null; + + for (beforeElem = indicatorDiv.firstElementChild; + beforeElem != null; + beforeElem = beforeElem.nextElementSibling) + if (beforeElem.getAttribute('data-indicator') > id) + break; + + indicatorElem = indicatorDiv.insertBefore(E('span', { 'data-indicator': id, 'data-clickable': handlerFn ? true : null, 'click': handlerFn - }, [''])); + }, ['']), beforeElem); + } if (label == indicatorElem.firstChild.data && style == indicatorElem.getAttribute('data-style')) return false; @@ -7732,7 +7937,7 @@ return UI; -- cgit v1.2.3