diff --git a/core/language/en-GB/Misc.multids b/core/language/en-GB/Misc.multids index d8c091375..646336d75 100644 --- a/core/language/en-GB/Misc.multids +++ b/core/language/en-GB/Misc.multids @@ -37,6 +37,7 @@ Error/NetworkErrorAlert: `

''Network Error''

It looks like the connection Error/PutEditConflict: File changed on server Error/PutForbidden: Permission denied Error/PutUnauthorized: Authentication required +Error/RecursiveButton: Possible Recursive Error: Button in button is not allowed Error/RecursiveTransclusion: Recursive transclusion error in transclude widget Error/RetrievingSkinny: Error retrieving skinny tiddler list Error/SavingToTWEdit: Error saving to TWEdit diff --git a/core/modules/widgets/button.js b/core/modules/widgets/button.js index 68f2fcd11..913ae7d9c 100644 --- a/core/modules/widgets/button.js +++ b/core/modules/widgets/button.js @@ -22,6 +22,23 @@ Inherit from the base widget class */ ButtonWidget.prototype = new Widget(); +/* +Detect nested buttons +*/ +ButtonWidget.prototype.isNestedButton = function() { + var pointer = this.parentWidget, + depth = 0; + while(pointer) { + if(pointer instanceof ButtonWidget) { + // we allow 1 nested button + if(depth > 1) return true; + depth += 1; + } + pointer = pointer.parentWidget; + } + return false; +} + /* Render this widget into the DOM */ @@ -34,6 +51,17 @@ ButtonWidget.prototype.render = function(parent,nextSibling) { // Compute attributes and execute state this.computeAttributes(); this.execute(); + // Check "button in button". Return early with an error message + // This check also prevents fatal recursion errors using the transclusion widget + if(this.isNestedButton()) { + var domNode = this.document.createElement("span"); + var textNode = this.document.createTextNode($tw.language.getString("Error/RecursiveButton")); + domNode.appendChild(textNode); + domNode.className = "tc-error"; + parent.insertBefore(domNode,nextSibling); + this.domNodes.push(domNode); + return; // an error message + } // Create element if(this.buttonTag && $tw.config.htmlUnsafeElements.indexOf(this.buttonTag) === -1) { tag = this.buttonTag; @@ -71,7 +99,7 @@ ButtonWidget.prototype.render = function(parent,nextSibling) { if(this["aria-label"]) { domNode.setAttribute("aria-label",this["aria-label"]); } - if (this.role) { + if(this.role) { domNode.setAttribute("role", this.role); } if(this.popup || this.popupTitle) { diff --git a/editions/test/tiddlers/tests/data/transclude/Recursion-Button-Transclusion.tid b/editions/test/tiddlers/tests/data/transclude/Recursion-Button-Transclusion.tid new file mode 100644 index 000000000..737b7cba2 --- /dev/null +++ b/editions/test/tiddlers/tests/data/transclude/Recursion-Button-Transclusion.tid @@ -0,0 +1,15 @@ +title: Transclude/Recursion/Button +description: Transclusion recursion inside a button +type: text/vnd.tiddlywiki-multiple +tags: [[$:/tags/wiki-test-spec]] + +title: Output + +\whitespace trim +<$button> +<$transclude/> + ++ +title: ExpectedResult + +

\ No newline at end of file diff --git a/editions/test/tiddlers/tests/data/transclude/Recursion-Button-in-Button.tid b/editions/test/tiddlers/tests/data/transclude/Recursion-Button-in-Button.tid new file mode 100644 index 000000000..fd1baccd1 --- /dev/null +++ b/editions/test/tiddlers/tests/data/transclude/Recursion-Button-in-Button.tid @@ -0,0 +1,15 @@ +title: Transclude/Recursion/ButtonInButton +description: Button in Button +type: text/vnd.tiddlywiki-multiple +tags: [[$:/tags/wiki-test-spec]] + +title: Output + +\whitespace trim +<$button>Test Button +<$button>Second button + ++ +title: ExpectedResult + +

\ No newline at end of file