luci-base: ui.js: rework tab state handling
authorJo-Philipp Wich <jo@mein.io>
Sun, 11 Aug 2019 18:59:45 +0000 (20:59 +0200)
committerJo-Philipp Wich <jo@mein.io>
Wed, 14 Aug 2019 20:58:15 +0000 (22:58 +0200)
Properly preserve the selection state of nested tabs.

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
modules/luci-base/htdocs/luci-static/resources/ui.js

index 2a7c44ad89f801609b4be891300243942a77eff5..23a9d7bfda21592353f1acb304f6e3beb78e4d40 100644 (file)
@@ -1556,9 +1556,6 @@ return L.Class.extend({
                        document.addEventListener('dependency-update', this.updateTabs.bind(this));
 
                        this.updateTabs();
-
-                       if (!groups.length)
-                               this.setActiveTabId(-1, -1);
                },
 
                initTabGroup: function(panes) {
@@ -1576,6 +1573,7 @@ return L.Class.extend({
                                    active = pane.getAttribute('data-tab-active') === 'true';
 
                                menu.appendChild(E('li', {
+                                       'style': L.dom.isEmpty(pane) ? 'display:none' : null,
                                        'class': active ? 'cbi-tab' : 'cbi-tab-disabled',
                                        'data-tab': name
                                }, E('a', {
@@ -1590,7 +1588,7 @@ return L.Class.extend({
                        group.parentNode.insertBefore(menu, group);
 
                        if (selected === null) {
-                               selected = this.getActiveTabId(groupId);
+                               selected = this.getActiveTabId(panes[0]);
 
                                if (selected < 0 || selected >= panes.length || L.dom.isEmpty(panes[selected])) {
                                        for (var i = 0; i < panes.length; i++) {
@@ -1605,8 +1603,24 @@ return L.Class.extend({
                                menu.childNodes[selected].classList.remove('cbi-tab-disabled');
                                panes[selected].setAttribute('data-tab-active', 'true');
 
-                               this.setActiveTabId(groupId, selected);
+                               this.setActiveTabId(panes[selected], selected);
+                       }
+               },
+
+               getPathForPane: function(pane) {
+                       var path = [], node = null;
+
+                       for (node = pane ? pane.parentNode : null;
+                            node != null && node.hasAttribute != null;
+                            node = node.parentNode)
+                       {
+                               if (node.hasAttribute('data-tab'))
+                                       path.unshift(node.getAttribute('data-tab'));
+                               else if (node.hasAttribute('data-section-id'))
+                                       path.unshift(node.getAttribute('data-section-id'));
                        }
+
+                       return path.join('/');
                },
 
                getActiveTabState: function() {
@@ -1614,23 +1628,26 @@ return L.Class.extend({
 
                        try {
                                var val = JSON.parse(window.sessionStorage.getItem('tab'));
-                               if (val.page === page && Array.isArray(val.groups))
+                               if (val.page === page && L.isObject(val.paths))
                                        return val;
                        }
                        catch(e) {}
 
                        window.sessionStorage.removeItem('tab');
-                       return { page: page, groups: [] };
+                       return { page: page, paths: {} };
                },
 
-               getActiveTabId: function(groupId) {
-                       return +this.getActiveTabState().groups[groupId] || 0;
+               getActiveTabId: function(pane) {
+                       var path = this.getPathForPane(pane);
+                       return +this.getActiveTabState().paths[path] || 0;
                },
 
-               setActiveTabId: function(groupId, tabIndex) {
+               setActiveTabId: function(pane, tabIndex) {
+                       var path = this.getPathForPane(pane);
+
                        try {
                                var state = this.getActiveTabState();
-                                   state.groups[groupId] = tabIndex;
+                                   state.paths[path] = tabIndex;
 
                            window.sessionStorage.setItem('tab', JSON.stringify(state));
                        }
@@ -1642,9 +1659,12 @@ return L.Class.extend({
                updateTabs: function(ev, root) {
                        (root || document).querySelectorAll('[data-tab-title]').forEach(function(pane) {
                                var menu = pane.parentNode.previousElementSibling,
-                                   tab = menu.querySelector('[data-tab="%s"]'.format(pane.getAttribute('data-tab'))),
+                                   tab = menu ? menu.querySelector('[data-tab="%s"]'.format(pane.getAttribute('data-tab'))) : null,
                                    n_errors = pane.querySelectorAll('.cbi-input-invalid').length;
 
+                               if (!menu || !tab)
+                                       return;
+
                                if (L.dom.isEmpty(pane)) {
                                        tab.style.display = 'none';
                                        tab.classList.remove('flash');
@@ -1690,7 +1710,7 @@ return L.Class.extend({
                                if (L.dom.matches(pane, '[data-tab]')) {
                                        if (pane.getAttribute('data-tab') === name) {
                                                pane.setAttribute('data-tab-active', 'true');
-                                               L.ui.tabs.setActiveTabId(groupId, index);
+                                               L.ui.tabs.setActiveTabId(pane, index);
                                        }
                                        else {
                                                pane.setAttribute('data-tab-active', 'false');