[Pkg-javascript-commits] [dojo] 79/88: Fixes #16975. Remove leak when calling empty() on SVG elements (all browsers). On IE, use removeChild instead of removeNode on SVG elements since they don't inherit removeNode from HTMLElement and SVG/removeNode is incorrectly implemented. Backport thru 1.6. Add additional strict and quirks automated tests to make sure empty() and destroy() are working correctly with SVG and OBJECT nodes, and since these element's behavior seem dependent on the document's compatMode. !strict

David Prévot taffit at moszumanska.debian.org
Thu Aug 21 17:39:41 UTC 2014


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to annotated tag 1.8.5
in repository dojo.

commit edf4b02d32aab823c2212eca7f6e08ad7bdf7f31
Author: Douglas Hays <doughays at dojotoolkit.org>
Date:   Wed Apr 10 12:05:48 2013 +0000

    Fixes #16975.  Remove leak when calling empty() on SVG elements (all browsers).  On IE, use removeChild instead of removeNode on SVG elements since they don't inherit removeNode from HTMLElement and SVG/removeNode is incorrectly implemented.  Backport thru 1.6.  Add additional strict and quirks automated tests to make sure empty() and destroy() are working correctly with SVG and OBJECT nodes, and since these element's behavior seem dependent on the document's compatMode. !strict
    
    git-svn-id: http://svn.dojotoolkit.org/src/branches/1.8/dojo@31197 560b804f-0ae3-0310-86f3-f6aa0a117693
---
 dom-construct.js             | 33 +++++++++++++---------
 tests/_base/html.html        | 65 ++++++++++++++++++++++++++++++++++++++++++--
 tests/_base/html_quirks.html | 63 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 145 insertions(+), 16 deletions(-)

diff --git a/dom-construct.js b/dom-construct.js
index fc7b539..8aae4f0 100644
--- a/dom-construct.js
+++ b/dom-construct.js
@@ -263,19 +263,22 @@ define(["exports", "./_base/kernel", "./sniff", "./_base/window", "./dom", "./do
 		return tag; // DomNode
 	};
 
-	var _empty = has("ie") ?
-		function(/*DomNode*/ node){
+	function _empty(/*DomNode*/ node){
+		if(node.canHaveChildren){
 			try{
-				node.innerHTML = ""; // really fast when it works
-			}catch(e){ // IE can generate Unknown Error
-				for(var c; c = node.lastChild;){ // intentional assignment
-					_destroy(c, node); // destroy is better than removeChild so TABLE elements are removed in proper order
-				}
+				// fast path
+				node.innerHTML = "";
+				return;
+			}catch(e){
+				// innerHTML is readOnly (e.g. TABLE (sub)elements in quirks mode)
+				// Fall through (saves bytes)
 			}
-		} :
-		function(/*DomNode*/ node){
-			node.innerHTML = "";
-		};
+		}
+		// SVG/strict elements don't support innerHTML/canHaveChildren, and OBJECT/APPLET elements in quirks node have canHaveChildren=false
+		for(var c; c = node.lastChild;){ // intentional assignment
+			_destroy(c, node); // destroy is better than removeChild so TABLE subelements are removed in proper order
+		}
+	}
 
 	exports.empty = function empty(/*DOMNode|String*/ node){
 		 // summary:
@@ -295,12 +298,16 @@ define(["exports", "./_base/kernel", "./sniff", "./_base/window", "./dom", "./do
 
 
 	function _destroy(/*DomNode*/ node, /*DomNode*/ parent){
+		// in IE quirks, node.canHaveChildren can be false but firstChild can be non-null (OBJECT/APPLET)
 		if(node.firstChild){
 			_empty(node);
 		}
 		if(parent){
-			// removeNode(false) doesn't leak in IE 6+, but removeChild() and removeNode(true) are known to leak under IE 8- while 9+ is TBD
-			has("ie") && 'removeNode' in node ? node.removeNode(false) : parent.removeChild(node);
+			// removeNode(false) doesn't leak in IE 6+, but removeChild() and removeNode(true) are known to leak under IE 8- while 9+ is TBD.
+			// In IE quirks mode, PARAM nodes as children of OBJECT/APPLET nodes have a removeNode method that does nothing and
+			// the parent node has canHaveChildren=false even though removeChild correctly removes the PARAM children.
+			// In IE, SVG/strict nodes don't have a removeNode method nor a canHaveChildren boolean.
+			has("ie") && parent.canHaveChildren && "removeNode" in node ? node.removeNode(false) : parent.removeChild(node);
 		}
 	}
 	exports.destroy = function destroy(/*DOMNode|String*/ node){
diff --git a/tests/_base/html.html b/tests/_base/html.html
index fd6e6fd..02ce9ad 100644
--- a/tests/_base/html.html
+++ b/tests/_base/html.html
@@ -626,6 +626,48 @@
 					});
 				});
 
+				doh.register("t",
+					[
+						function emptySvg(t){
+							dojo.empty(dojo.byId("surface"));
+							doh.f(!!dojo.byId("surface").firstChild, "svg firstChild");
+						},
+						function destroySvg(t){
+							dojo.destroy(dojo.byId("surface"));
+							doh.f(!!dojo.byId("surface"), "svg byId");
+						},
+						function emptyObject(t){
+							dojo.empty(dojo.byId("objectToEmpty"));
+							doh.f(!!dojo.byId("objectToEmpty").firstChild, "object firstChild");
+						},
+						function destroyObject(t){
+							dojo.destroy(dojo.byId("objectToEmpty"));
+							doh.f(!!dojo.byId("objectToEmpty"), "object byId");
+						},
+						function destroyIframe(t){
+							dojo.destroy(dojo.byId("iframeToDestroy"));
+							doh.f(!!dojo.byId("iframeToDestroy"), "iframe byId");
+						},
+						function destroyDivNotInDOM(t){
+							var p = dojo.byId("divToRemoveFromDOM");
+							var n = dojo.byId("divToDestroy");
+							p = p.parentNode.removeChild(p);
+							doh.f(!!dojo.byId("divToRemoveFromDOM"), "div byId");
+							doh.t(!!p.firstChild, "div child 1");
+							doh.is(p.firstChild, n, "div 1st child");
+							doh.isNot(p.firstChild, p.lastChild, "div 1st child");
+							dojo.destroy(n);
+							doh.t(!!p.firstChild, "div child 2");
+							doh.isNot(p.firstChild, n, "div 2nd child");
+							doh.is(p.firstChild, p.lastChild, "div 2nd child");
+							dojo.empty(p);
+							doh.f(!!p.firstChild, "div child 3");
+							dojo.destroy(p);
+							doh.t(true, "no exception thrown");
+						}
+					]
+				);
+
 				doh.runOnLoad();
 			});
 		</script>
@@ -863,8 +905,25 @@
 		<div id="iframeContainer"></div>
 
 		<!-- SVG element to test dojo.getComputedStyle on IE9 (#14103) -->
-		<svg id="surface" xmlns="http://www.w3.org/2000/svg" width="100px" height="100px">
-			<rect id="rect1" fill="rgb(255, 0, 0)" x="0" y="0" width="80" height="60" ry="0" rx="0" fill-rule="evenodd"/>
-		</svg>
+		<!-- SVG element to test empty -->
+		<svg id="surface" xmlns="http://www.w3.org/2000/svg" width="100px" height="100px"
+			><rect id="rect1" fill="rgb(255, 0, 0)" x="0" y="0" width="80" height="60" ry="0" rx="0" fill-rule="evenodd"
+		/></svg>
+
+		<!-- OBJECT element to test empty -->
+		<object width="500" height="500" id="objectToEmpty" data="data:application/x-silverlight," type="application/x-silverlight"
+			><param name="background" value="transparent"
+		/></object>
+
+		<!-- IFRAME element to test destroy -->
+		<iframe id="iframeToDestroy" src="about:blank"
+			><span></span
+		></iframe>
+
+		<!-- DIV element to test destroy of element not in the DOM -->
+		<div id="divToRemoveFromDOM"
+			><div id="divToDestroy"></div
+			><div></div
+		></div>
 	</body>
 </html>
diff --git a/tests/_base/html_quirks.html b/tests/_base/html_quirks.html
index 44c135e..6ee6be3 100644
--- a/tests/_base/html_quirks.html
+++ b/tests/_base/html_quirks.html
@@ -135,6 +135,48 @@
 					);
 				}
 
+				doh.register("t",
+					[
+						function emptySvg(t){
+							dojo.empty(dojo.byId("surface"));
+							doh.f(!!dojo.byId("surface").firstChild, "svg firstChild");
+						},
+						function destroySvg(t){
+							dojo.destroy(dojo.byId("surface"));
+							doh.f(!!dojo.byId("surface"), "svg byId");
+						},
+						function emptyObject(t){
+							dojo.empty(dojo.byId("objectToEmpty"));
+							doh.f(!!dojo.byId("objectToEmpty").firstChild, "object firstChild");
+						},
+						function destroyObject(t){
+							dojo.destroy(dojo.byId("objectToEmpty"));
+							doh.f(!!dojo.byId("objectToEmpty"), "object byId");
+						},
+						function destroyIframe(t){
+							dojo.destroy(dojo.byId("iframeToDestroy"));
+							doh.f(!!dojo.byId("iframeToDestroy"), "iframe byId");
+						},
+						function destroyDivNotInDOM(t){
+							var p = dojo.byId("divToRemoveFromDOM");
+							var n = dojo.byId("divToDestroy");
+							p = p.parentNode.removeChild(p);
+							doh.f(!!dojo.byId("divToRemoveFromDOM"), "div byId");
+							doh.t(!!p.firstChild, "div child 1");
+							doh.is(p.firstChild, n, "div 1st child");
+							doh.isNot(p.firstChild, p.lastChild, "div 1st child");
+							dojo.destroy(n);
+							doh.t(!!p.firstChild, "div child 2");
+							doh.isNot(p.firstChild, n, "div 2nd child");
+							doh.is(p.firstChild, p.lastChild, "div 2nd child");
+							dojo.empty(p);
+							doh.f(!!p.firstChild, "div child 3");
+							dojo.destroy(p);
+							doh.t(true, "no exception thrown");
+						}
+					]
+				);
+
 				doh.runOnLoad();
 			});
 		</script>
@@ -323,6 +365,27 @@
 		<div id="sq100nopos">
 			100px square, no positioning
 		</div>
+
+		<!-- SVG element to test empty -->
+		<svg id="surface" xmlns="http://www.w3.org/2000/svg" width="100px" height="100px"
+			><rect id="rect1" fill="rgb(255, 0, 0)" x="0" y="0" width="80" height="60" ry="0" rx="0" fill-rule="evenodd"
+		/></svg>
+
+		<!-- OBJECT element to test empty -->
+		<object width="500" height="500" id="objectToEmpty" data="data:application/x-silverlight," type="application/x-silverlight"
+			><param name="background" value="transparent"
+		/></object>
+
+		<!-- IFRAME element to test destroy -->
+		<iframe id="iframeToDestroy" src="about:blank"
+			><span></span
+		></iframe>
+
+		<!-- DIV element to test destroy of element not in the DOM -->
+		<div id="divToRemoveFromDOM"
+			><div id="divToDestroy"></div
+			><div></div
+		></div>
 	</body>
 </html>
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/dojo.git



More information about the Pkg-javascript-commits mailing list