diff options
Diffstat (limited to 'modules/luci-base/htdocs/luci-static/resources/ui.js')
-rw-r--r-- | modules/luci-base/htdocs/luci-static/resources/ui.js | 136 |
1 files changed, 100 insertions, 36 deletions
diff --git a/modules/luci-base/htdocs/luci-static/resources/ui.js b/modules/luci-base/htdocs/luci-static/resources/ui.js index 91a93b9e90..0e909b6dcc 100644 --- a/modules/luci-base/htdocs/luci-static/resources/ui.js +++ b/modules/luci-base/htdocs/luci-static/resources/ui.js @@ -102,6 +102,47 @@ var UIElement = baseclass.extend(/** @lends LuCI.ui.AbstractElement.prototype */ }, /** + * 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. * * @instance @@ -569,6 +610,22 @@ var UICheckbox = UIElement.extend(/** @lends LuCI.ui.Checkbox.prototype */ { frameEl.appendChild(E('label', { 'for': id })); + if (this.options.tooltip != null) { + var icon = "⚠️"; + + if (this.options.tooltipicon != null) + icon = this.options.tooltipicon; + + frameEl.appendChild( + E('label', { 'class': 'cbi-tooltip-container' },[ + icon, + E('div', { 'class': 'cbi-tooltip' }, + this.options.tooltip + ) + ]) + ); + } + return this.bind(frameEl); }, @@ -576,8 +633,9 @@ var UICheckbox = UIElement.extend(/** @lends LuCI.ui.Checkbox.prototype */ { bind: function(frameEl) { this.node = frameEl; - this.setUpdateEvents(frameEl.lastElementChild.previousElementSibling, 'click', 'blur'); - this.setChangeEvents(frameEl.lastElementChild.previousElementSibling, 'change'); + var input = frameEl.querySelector('input[type="checkbox"]'); + this.setUpdateEvents(input, 'click', 'blur'); + this.setChangeEvents(input, 'change'); dom.bindClassInstance(frameEl, this); @@ -593,7 +651,7 @@ var UICheckbox = UIElement.extend(/** @lends LuCI.ui.Checkbox.prototype */ { * Returns `true` when the checkbox is currently checked, otherwise `false`. */ isChecked: function() { - return this.node.lastElementChild.previousElementSibling.checked; + return this.node.querySelector('input[type="checkbox"]').checked; }, /** @override */ @@ -605,7 +663,7 @@ var UICheckbox = UIElement.extend(/** @lends LuCI.ui.Checkbox.prototype */ { /** @override */ setValue: function(value) { - this.node.lastElementChild.previousElementSibling.checked = (value == this.options.value_enabled); + this.node.querySelector('input[type="checkbox"]').checked = (value == this.options.value_enabled); } }); @@ -1144,6 +1202,28 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { }, /** @private */ + getScrollParent: function(element) { + var parent = element, + style = getComputedStyle(element), + excludeStaticParent = (style.position === 'absolute'); + + if (style.position === 'fixed') + return document.body; + + while ((parent = parent.parentElement) != null) { + style = getComputedStyle(parent); + + if (excludeStaticParent && style.position === 'static') + continue; + + if (/(auto|scroll)/.test(style.overflow + style.overflowY + style.overflowX)) + return parent; + } + + return document.body; + }, + + /** @private */ openDropdown: function(sb) { var st = window.getComputedStyle(sb, null), ul = sb.querySelector('ul'), @@ -1151,7 +1231,8 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { fl = findParent(sb, '.cbi-value-field'), sel = ul.querySelector('[selected]'), rect = sb.getBoundingClientRect(), - items = Math.min(this.options.dropdown_items, li.length); + items = Math.min(this.options.dropdown_items, li.length), + scrollParent = this.getScrollParent(sb); document.querySelectorAll('.cbi-dropdown[open]').forEach(function(s) { s.dispatchEvent(new CustomEvent('cbi-dropdown-close', {})); @@ -1176,29 +1257,7 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { ul.style.maxHeight = (vpHeight * 0.5) + 'px'; ul.style.WebkitOverflowScrolling = 'touch'; - var getScrollParent = function(element) { - var parent = element, - style = getComputedStyle(element), - excludeStaticParent = (style.position === 'absolute'); - - if (style.position === 'fixed') - return document.body; - - while ((parent = parent.parentElement) != null) { - style = getComputedStyle(parent); - - if (excludeStaticParent && style.position === 'static') - continue; - - if (/(auto|scroll)/.test(style.overflow + style.overflowY + style.overflowX)) - return parent; - } - - return document.body; - } - - var scrollParent = getScrollParent(sb), - scrollFrom = scrollParent.scrollTop, + var scrollFrom = scrollParent.scrollTop, scrollTo = scrollFrom + rect.top - vpHeight * 0.5; var scrollStep = function(timestamp) { @@ -1224,10 +1283,11 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { ul.style.top = ul.style.bottom = ''; window.requestAnimationFrame(function() { - var itemHeight = li[Math.max(0, li.length - 2)].getBoundingClientRect().height, + var containerRect = scrollParent.getBoundingClientRect(), + itemHeight = li[Math.max(0, li.length - 2)].getBoundingClientRect().height, fullHeight = 0, - spaceAbove = rect.top, - spaceBelow = window.innerHeight - rect.height - rect.top; + spaceAbove = rect.top - containerRect.top, + spaceBelow = containerRect.bottom - rect.bottom; for (var i = 0; i < (items == -1 ? li.length : items); i++) fullHeight += li[i].getBoundingClientRect().height; @@ -1303,6 +1363,8 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { /** @private */ toggleItem: function(sb, li, force_state) { + var ul = li.parentNode; + if (li.hasAttribute('unselectable')) return; @@ -1379,7 +1441,7 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { this.closeDropdown(sb, true); } - this.saveValues(sb, li.parentNode); + this.saveValues(sb, ul); }, /** @private */ @@ -3556,9 +3618,11 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { this.setActiveTabId(panes[selected], selected); } - panes[selected].dispatchEvent(new CustomEvent('cbi-tab-active', { - detail: { tab: panes[selected].getAttribute('data-tab') } - })); + requestAnimationFrame(L.bind(function(pane) { + pane.dispatchEvent(new CustomEvent('cbi-tab-active', { + detail: { tab: pane.getAttribute('data-tab') } + })); + }, this, panes[selected])); this.updateTabs(group); }, @@ -4001,7 +4065,7 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { E('button', { 'class': 'btn', 'click': UI.prototype.hideModal - }, [ _('Dismiss') ]), ' ', + }, [ _('Close') ]), ' ', E('button', { 'class': 'cbi-button cbi-button-positive important', 'click': L.bind(this.apply, this, true) |