diff --git a/core/modules/widgets/widget.js b/core/modules/widgets/widget.js index 09b5364e0..b838f53ac 100755 --- a/core/modules/widgets/widget.js +++ b/core/modules/widgets/widget.js @@ -787,9 +787,9 @@ Widget.prototype.findNextSiblingDomNode = function(startIndex) { // Refer to this widget by its index within its parents children var parent = this.parentWidget, index = startIndex !== undefined ? startIndex : parent.children.indexOf(this); -if(index === -1) { - throw "node not found in parents children"; -} + if(index === -1) { + throw "node not found in parents children"; + } // Look for a DOM node in the later siblings while(++index < parent.children.length) { var domNode = parent.children[index].findFirstDomNode(); @@ -827,21 +827,60 @@ Widget.prototype.findFirstDomNode = function() { }; /* -Remove any DOM nodes created by this widget or its children +Entry into destroy procedure +options include: + removeDOMNodes: boolean (default true) +*/ +Widget.prototype.destroyChildren = function(options) { + $tw.utils.each(this.children,function(childWidget) { + childWidget.destroy(options); + }); +}; + +/* +Legacy entry into destroy procedure */ Widget.prototype.removeChildDomNodes = function() { - // If this widget has directly created DOM nodes, delete them and exit. This assumes that any child widgets are contained within the created DOM nodes, which would normally be the case - if(this.domNodes.length > 0) { - $tw.utils.each(this.domNodes,function(domNode) { - domNode.parentNode.removeChild(domNode); - }); - this.domNodes = []; - } else { - // Otherwise, ask the child widgets to delete their DOM nodes - $tw.utils.each(this.children,function(childWidget) { - childWidget.removeChildDomNodes(); - }); + this.destroy({removeDOMNodes: true}); +}; + +/* +Default destroy +options include: +- removeDOMNodes: boolean (default true) +*/ +Widget.prototype.destroy = function(options) { + const { removeDOMNodes = true } = options || {}; + let removeChildDOMNodes = removeDOMNodes; + if(removeDOMNodes && this.domNodes.length > 0) { + // If this widget will remove its own DOM nodes, children should not remove theirs + removeChildDOMNodes = false; } + // Destroy children first + this.destroyChildren({removeDOMNodes: removeChildDOMNodes}); + this.children = []; + + // Call custom cleanup method if implemented + if(typeof this.onDestroy === "function") { + this.onDestroy(); + } + + // Remove our DOM nodes if needed + if(removeDOMNodes) { + this.removeLocalDomNodes(); + } +}; + +/* +Remove any DOM nodes created by this widget +*/ +Widget.prototype.removeLocalDomNodes = function() { + for(const domNode of this.domNodes) { + if(domNode.parentNode) { + domNode.parentNode.removeChild(domNode); + } + } + this.domNodes = []; }; /* diff --git a/editions/tw5.com/tiddlers/releasenotes/5.4.0/#9097.tid b/editions/tw5.com/tiddlers/releasenotes/5.4.0/#9097.tid new file mode 100644 index 000000000..8fe8db405 --- /dev/null +++ b/editions/tw5.com/tiddlers/releasenotes/5.4.0/#9097.tid @@ -0,0 +1,13 @@ +change-category: internal +change-type: enhancement +created: 20260120153052332 +description: Adds a destroy method for widgets allowing for clean up of resources when a widget is removed. +github-contributors: saqimtiaz +github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9097 +modified: 20260125212701672 +release: 5.4.0 +tags: $:/tags/ChangeNote +title: $:/changenotes/5.4.0/#9097 +type: text/vnd.tiddlywiki + +Adds a destroy method for widgets allowing for clean up of resources when a widget is removed. \ No newline at end of file