luci-base: form.js: save parent map on opening nested modal map
authorJo-Philipp Wich <jo@mein.io>
Mon, 16 May 2022 11:10:20 +0000 (13:10 +0200)
committerJo-Philipp Wich <jo@mein.io>
Mon, 16 May 2022 11:43:09 +0000 (13:43 +0200)
Before opening (rendering) a nested modal map, make sure to save the parent
modal map in order to persist any structural uci changes, such as newly added
anonymous sections to prevent the nested map from operating on stale values
or ephemeral config section IDs.

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

index 3b2e89eccdb74d1feb150cc660e85ed1f15a8eaf..a09c805938c679c4d8256ef5873704a3e0db93e3 100644 (file)
@@ -3206,63 +3206,70 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p
        /** @private */
        renderMoreOptionsModal: function(section_id, ev) {
                var parent = this.map,
-                   title = parent.title,
-                   name = null,
-                   m = new CBIMap(this.map.config, null, null),
-                   s = m.section(CBINamedSection, section_id, this.sectiontype);
+                   sref = parent.data.get(parent.config, section_id),
+                   mapNode = this.getActiveModalMap(),
+                   activeMap = mapNode ? dom.findClassInstance(mapNode) : null,
+                   stackedMap = activeMap && (activeMap.parent !== parent || activeMap.section !== section_id);
 
-               m.parent = parent;
-               m.section = section_id;
-               m.readonly = parent.readonly;
+               return (stackedMap ? activeMap.save(null, true) : Promise.resolve()).then(L.bind(function() {
+                       section_id = sref['.name'];
 
-               s.tabs = this.tabs;
-               s.tab_names = this.tab_names;
+                       var m = new CBIMap(parent.config, null, null),
+                           s = m.section(CBINamedSection, section_id, this.sectiontype);
 
-               if ((name = this.titleFn('modaltitle', section_id)) != null)
-                       title = name;
-               else if ((name = this.titleFn('sectiontitle', section_id)) != null)
-                       title = '%s - %s'.format(parent.title, name);
-               else if (!this.anonymous)
-                       title = '%s - %s'.format(parent.title, section_id);
+                       m.parent = parent;
+                       m.section = section_id;
+                       m.readonly = parent.readonly;
 
-               this.cloneOptions(this, s);
+                       s.tabs = this.tabs;
+                       s.tab_names = this.tab_names;
 
-               return Promise.resolve(this.addModalOptions(s, section_id, ev)).then(L.bind(m.render, m)).then(L.bind(function(nodes) {
-                       var mapNode = this.getActiveModalMap(),
-                           activeMap = mapNode ? dom.findClassInstance(mapNode) : null;
+                       this.cloneOptions(this, s);
 
-                       if (activeMap && (activeMap.parent !== parent || activeMap.section !== section_id)) {
-                               mapNode.parentNode
-                                       .querySelector('h4')
-                                       .appendChild(E('span', title ? ' » ' + title : ''));
+                       return Promise.resolve(this.addModalOptions(s, section_id, ev)).then(function() {
+                               return m.render();
+                       }).then(L.bind(function(nodes) {
+                               var title = parent.title,
+                                   name = null;
 
-                               mapNode.parentNode
-                                       .querySelector('div.right > button')
-                                       .firstChild.data = _('Back');
+                               if ((name = this.titleFn('modaltitle', section_id)) != null)
+                                       title = name;
+                               else if ((name = this.titleFn('sectiontitle', section_id)) != null)
+                                       title = '%s - %s'.format(parent.title, name);
+                               else if (!this.anonymous)
+                                       title = '%s - %s'.format(parent.title, section_id);
+
+                               if (stackedMap) {
+                                       mapNode.parentNode
+                                               .querySelector('h4')
+                                               .appendChild(E('span', title ? ' » ' + title : ''));
 
-                               mapNode.classList.add('hidden');
-                               mapNode.parentNode.insertBefore(nodes, mapNode.nextElementSibling);
+                                       mapNode.parentNode
+                                               .querySelector('div.right > button')
+                                               .firstChild.data = _('Back');
+
+                                       mapNode.classList.add('hidden');
+                                       mapNode.parentNode.insertBefore(nodes, mapNode.nextElementSibling);
 
-                               return activeMap.save(null, true).then(function() {
                                        nodes.classList.add('flash');
-                               }, function() {});
-                       }
-                       else {
-                               ui.showModal(title, [
-                                       nodes,
-                                       E('div', { 'class': 'right' }, [
-                                               E('button', {
-                                                       'class': 'cbi-button',
-                                                       'click': ui.createHandlerFn(this, 'handleModalCancel', m)
-                                               }, [ _('Dismiss') ]), ' ',
-                                               E('button', {
-                                                       'class': 'cbi-button cbi-button-positive important',
-                                                       'click': ui.createHandlerFn(this, 'handleModalSave', m),
-                                                       'disabled': m.readonly || null
-                                               }, [ _('Save') ])
-                                       ])
-                               ], 'cbi-modal');
-                       }
+                               }
+                               else {
+                                       ui.showModal(title, [
+                                               nodes,
+                                               E('div', { 'class': 'right' }, [
+                                                       E('button', {
+                                                               'class': 'cbi-button',
+                                                               'click': ui.createHandlerFn(this, 'handleModalCancel', m)
+                                                       }, [ _('Dismiss') ]), ' ',
+                                                       E('button', {
+                                                               'class': 'cbi-button cbi-button-positive important',
+                                                               'click': ui.createHandlerFn(this, 'handleModalSave', m),
+                                                               'disabled': m.readonly || null
+                                                       }, [ _('Save') ])
+                                               ])
+                                       ], 'cbi-modal');
+                               }
+                       }, this));
                }, this)).catch(L.error);
        }
 });