From b5f6e1fc6d2d0eee2b4aee162ed95b2bba50f56c Mon Sep 17 00:00:00 2001 From: Dan Wolff Date: Wed, 10 Jun 2026 12:41:45 +0200 Subject: [PATCH] Fix calculator checkbox order dependency in tree pruning check_select() pruned the decision tree incrementally via the rendered DOM nodes at the toggled decision point's depth, so branches hidden by an earlier selection were never updated and reappeared with stale state when re-checked. Checkboxes therefore only behaved when toggled in decision-point order. Rebuild the pruning for the whole tree from the complete checkbox state on every toggle, walking the tree data (saved _schildren) instead of the rendered nodes, so toggle order no longer matters. --- docs/ssvc-calc/ssvc.js | 56 +++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/docs/ssvc-calc/ssvc.js b/docs/ssvc-calc/ssvc.js index 0115cb71..7c0f9f1c 100644 --- a/docs/ssvc-calc/ssvc.js +++ b/docs/ssvc-calc/ssvc.js @@ -896,42 +896,36 @@ function check_select(ev) { outcome_set(dinput, true); } }); - const finddpIndex = $(input).data("dpdepth"); - const nodes = d3.selectAll("g.node.depth-"+String(finddpIndex)); - function traverse_remove(xnode) { - if(!xnode.__data__) { - console.log("Error no nodes to descend!"); + /* Re-prune the whole tree from the state of every checkbox, walking the + saved _schildren rather than the rendered nodes, so boxes can be + toggled in any order and hidden branches stay in sync. */ + let unchecked = {}; + groupContainer.querySelectorAll('input[type="checkbox"].dp_input').forEach(function(xinput) { + if(!xinput.checked) { + const dpdepth = parseInt($(xinput).data("dpdepth")); + if(!(dpdepth in unchecked)) + unchecked[dpdepth] = []; + unchecked[dpdepth].push(parseInt($(xinput).data("dpvdepth"))); } - if(!xnode.__data__._schildren) { - console.log("Error no node _schildren data to restore from!"); + }); + function prune_tree(xnode, depth) { + if(!xnode._schildren) { + if((!xnode.children) || (!xnode.children.length)) + return; + xnode._schildren = Array.from(xnode.children); } - let removeValues = []; - xnode.__data__.children = Array.from(xnode.__data__._schildren); - dpContainer.querySelectorAll("input").forEach(function(cinput) { - if(!cinput.checked) - removeValues.push($(cinput).data("dpvdepth")); + const removeValues = unchecked[depth] || []; + xnode.children = xnode._schildren.filter(function(_, vindex) { + return !removeValues.includes(vindex); }); - removeValues.reverse().forEach(function(rindex) { - removevalueIndex = parseInt(rindex); - xnode.__data__.children.splice(removevalueIndex,1); - }); - update(xnode.__data__); - } - - if(nodes.length) { - nodes[0].forEach(function(xnode) { - if(xnode.__data__) { - if(xnode.__data__._schildren) { - traverse_remove(xnode); - } else if(xnode.__data__.children) { - let removevalueIndex = $(input).data("dpvdepth"); - xnode.__data__._schildren = Array.from(xnode.__data__.children); - xnode.__data__.children.splice(removevalueIndex,1); - update(xnode.__data__); - } - } + xnode._schildren.forEach(function(child) { + prune_tree(child, depth + 1); }); } + if(root && $("svg.mgraph").length) { + prune_tree(root, 0); + update(root); + } } function process_ssvc(ssvc, winput) { /* Assume flat SSVC namespace for now */