summaryrefslogtreecommitdiffhomepage
path: root/modules/luci-base/htdocs/luci-static/resources/luci.js
diff options
context:
space:
mode:
Diffstat (limited to 'modules/luci-base/htdocs/luci-static/resources/luci.js')
-rw-r--r--modules/luci-base/htdocs/luci-static/resources/luci.js176
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;