diff options
Diffstat (limited to 'modules/luci-base/htdocs/luci-static/resources/luci.js')
-rw-r--r-- | modules/luci-base/htdocs/luci-static/resources/luci.js | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/modules/luci-base/htdocs/luci-static/resources/luci.js b/modules/luci-base/htdocs/luci-static/resources/luci.js index c1c1b0dd3..4cb8bf4e5 100644 --- a/modules/luci-base/htdocs/luci-static/resources/luci.js +++ b/modules/luci-base/htdocs/luci-static/resources/luci.js @@ -181,6 +181,175 @@ } }; + /* Tabs */ + LuCI.prototype.tabs = { + init: function() { + var groups = [], prevGroup = null, currGroup = null; + + document.querySelectorAll('[data-tab]').forEach(function(tab) { + var parent = tab.parentNode; + + if (!parent.hasAttribute('data-tab-group')) + parent.setAttribute('data-tab-group', groups.length); + + currGroup = +parent.getAttribute('data-tab-group'); + + if (currGroup !== prevGroup) { + prevGroup = currGroup; + + if (!groups[currGroup]) + groups[currGroup] = []; + } + + groups[currGroup].push(tab); + }); + + for (var i = 0; i < groups.length; i++) + this.initTabGroup(groups[i]); + + document.addEventListener('dependency-update', this.updateTabs.bind(this)); + + this.updateTabs(); + + if (!groups.length) + this.setActiveTabId(-1, -1); + }, + + initTabGroup: function(panes) { + if (!Array.isArray(panes) || panes.length === 0) + return; + + var menu = E('ul', { 'class': 'cbi-tabmenu' }), + group = panes[0].parentNode, + groupId = +group.getAttribute('data-tab-group'), + selected = null; + + for (var i = 0, pane; pane = panes[i]; i++) { + var name = pane.getAttribute('data-tab'), + title = pane.getAttribute('data-tab-title'), + active = pane.getAttribute('data-tab-active') === 'true'; + + menu.appendChild(E('li', { + 'class': active ? 'cbi-tab' : 'cbi-tab-disabled', + 'data-tab': name + }, E('a', { + 'href': '#', + 'click': this.switchTab.bind(this) + }, title))); + + if (active) + selected = i; + } + + group.parentNode.insertBefore(menu, group); + + if (selected === null) { + selected = this.getActiveTabId(groupId); + + if (selected < 0 || selected >= panes.length) + selected = 0; + + menu.childNodes[selected].classList.add('cbi-tab'); + menu.childNodes[selected].classList.remove('cbi-tab-disabled'); + panes[selected].setAttribute('data-tab-active', 'true'); + + this.setActiveTabId(groupId, selected); + } + }, + + getActiveTabState: function() { + var page = document.body.getAttribute('data-page'); + + try { + var val = JSON.parse(window.sessionStorage.getItem('tab')); + if (val.page === page && Array.isArray(val.groups)) + return val; + } + catch(e) {} + + window.sessionStorage.removeItem('tab'); + return { page: page, groups: [] }; + }, + + getActiveTabId: function(groupId) { + return +this.getActiveTabState().groups[groupId] || 0; + }, + + setActiveTabId: function(groupId, tabIndex) { + try { + var state = this.getActiveTabState(); + state.groups[groupId] = tabIndex; + + window.sessionStorage.setItem('tab', JSON.stringify(state)); + } + catch (e) { return false; } + + return true; + }, + + updateTabs: function(ev) { + document.querySelectorAll('[data-tab-title]').forEach(function(pane) { + var menu = pane.parentNode.previousElementSibling, + tab = menu.querySelector('[data-tab="%s"]'.format(pane.getAttribute('data-tab'))), + n_errors = pane.querySelectorAll('.cbi-input-invalid').length; + + if (!pane.firstElementChild) { + tab.style.display = 'none'; + tab.classList.remove('flash'); + } + else if (tab.style.display === 'none') { + tab.style.display = ''; + requestAnimationFrame(function() { tab.classList.add('flash') }); + } + + if (n_errors) { + tab.setAttribute('data-errors', n_errors); + tab.setAttribute('data-tooltip', _('%d invalid field(s)').format(n_errors)); + tab.setAttribute('data-tooltip-style', 'error'); + } + else { + tab.removeAttribute('data-errors'); + tab.removeAttribute('data-tooltip'); + } + }); + }, + + switchTab: function(ev) { + var tab = ev.target.parentNode, + name = tab.getAttribute('data-tab'), + menu = tab.parentNode, + group = menu.nextElementSibling, + groupId = +group.getAttribute('data-tab-group'), + index = 0; + + ev.preventDefault(); + + if (!tab.classList.contains('cbi-tab-disabled')) + return; + + menu.querySelectorAll('[data-tab]').forEach(function(tab) { + tab.classList.remove('cbi-tab'); + tab.classList.remove('cbi-tab-disabled'); + tab.classList.add( + tab.getAttribute('data-tab') === name ? 'cbi-tab' : 'cbi-tab-disabled'); + }); + + group.childNodes.forEach(function(pane) { + if (L.dom.matches(pane, '[data-tab]')) { + if (pane.getAttribute('data-tab') === name) { + pane.setAttribute('data-tab-active', 'true'); + L.tabs.setActiveTabId(groupId, index); + } + else { + pane.setAttribute('data-tab-active', 'false'); + } + + index++; + } + }); + } + }; + /* DOM manipulation */ LuCI.prototype.dom = { elem: function(e) { @@ -316,6 +485,11 @@ } }; + /* Setup */ + LuCI.prototype.setupDOM = function(ev) { + this.tabs.init(); + }; + function LuCI(env) { this.env = env; @@ -329,6 +503,8 @@ document.addEventListener('mouseout', this.hideTooltip.bind(this), true); document.addEventListener('focus', this.showTooltip.bind(this), true); document.addEventListener('blur', this.hideTooltip.bind(this), true); + + document.addEventListener('DOMContentLoaded', this.setupDOM.bind(this)); } window.LuCI = LuCI; |