From f24606b1ffd59cc82c7251243a18f4cfdc4f78d5 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Mon, 16 May 2022 11:55:11 +0200 Subject: [PATCH] luci-base: form.js: handle SectionValue objects in GridSection modals The existing logic for cloning section options into the modal form section container did not properly handle SectionValue objects. Introduce a new `cloneOptions()` helper to recursively traverse and properly clowning such nested sections. Signed-off-by: Jo-Philipp Wich --- .../htdocs/luci-static/resources/form.js | 80 +++++++++++++------ 1 file changed, 55 insertions(+), 25 deletions(-) diff --git a/modules/luci-base/htdocs/luci-static/resources/form.js b/modules/luci-base/htdocs/luci-static/resources/form.js index 6786d3d234..3b2e89eccd 100644 --- a/modules/luci-base/htdocs/luci-static/resources/form.js +++ b/modules/luci-base/htdocs/luci-static/resources/form.js @@ -3149,6 +3149,60 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p return (prevNode && prevNode.matches('.cbi-map.hidden')) ? prevNode : null; }, + /** @private */ + cloneOptions: function(src_section, dest_section) { + for (var i = 0; i < src_section.children.length; i++) { + var o1 = src_section.children[i]; + + if (o1.modalonly === false && src_section === this) + continue; + + var o2; + + if (o1.subsection) { + o2 = dest_section.option(o1.constructor, o1.option, o1.subsection.constructor, o1.subsection.sectiontype, o1.subsection.title, o1.subsection.description); + + for (var k in o1.subsection) { + if (!o1.subsection.hasOwnProperty(k)) + continue; + + switch (k) { + case 'map': + case 'children': + case 'parentoption': + continue; + + default: + o2.subsection[k] = o1.subsection[k]; + } + } + + this.cloneOptions(o1.subsection, o2.subsection); + } + else { + o2 = dest_section.option(o1.constructor, o1.option, o1.title, o1.description); + } + + for (var k in o1) { + if (!o1.hasOwnProperty(k)) + continue; + + switch (k) { + case 'map': + case 'section': + case 'option': + case 'title': + case 'description': + case 'subsection': + continue; + + default: + o2[k] = o1[k]; + } + } + } + }, + /** @private */ renderMoreOptionsModal: function(section_id, ev) { var parent = this.map, @@ -3171,31 +3225,7 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p else if (!this.anonymous) title = '%s - %s'.format(parent.title, section_id); - for (var i = 0; i < this.children.length; i++) { - var o1 = this.children[i]; - - if (o1.modalonly === false) - continue; - - var o2 = s.option(o1.constructor, o1.option, o1.title, o1.description); - - for (var k in o1) { - if (!o1.hasOwnProperty(k)) - continue; - - switch (k) { - case 'map': - case 'section': - case 'option': - case 'title': - case 'description': - continue; - - default: - o2[k] = o1[k]; - } - } - } + this.cloneOptions(this, s); return Promise.resolve(this.addModalOptions(s, section_id, ev)).then(L.bind(m.render, m)).then(L.bind(function(nodes) { var mapNode = this.getActiveModalMap(),