From: <rb...@us...> - 2014-03-20 20:20:55
|
Revision: 9194 http://sourceforge.net/p/htmlunit/code/9194 Author: rbri Date: 2014-03-20 20:20:52 +0000 (Thu, 20 Mar 2014) Log Message: ----------- setting outerHTML now works also for detached elements Modified Paths: -------------- trunk/htmlunit/src/changes/changes.xml trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/BrowserVersionFeatures.java trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/html/HTMLElement.java trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/html/HTMLElementTest.java Modified: trunk/htmlunit/src/changes/changes.xml =================================================================== --- trunk/htmlunit/src/changes/changes.xml 2014-03-20 18:51:04 UTC (rev 9193) +++ trunk/htmlunit/src/changes/changes.xml 2014-03-20 20:20:52 UTC (rev 9194) @@ -8,6 +8,9 @@ <body> <release version="2.15" date="???" description="Bugfixes"> + <action type="add" dev="rbri" issue="1584" > + JavaScript: setting outerHTML now works also for detached elements. + </action> <action type="add" dev="rbri"> JavaScript: window.navigate(url) for IE browsers added. </action> Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/BrowserVersionFeatures.java =================================================================== --- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/BrowserVersionFeatures.java 2014-03-20 18:51:04 UTC (rev 9193) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/BrowserVersionFeatures.java 2014-03-20 20:20:52 UTC (rev 9194) @@ -1172,6 +1172,10 @@ @BrowserFeature(@WebBrowser(value = IE)) JS_OUTER_HTML_NULL_AS_STRING, + /** element.outerHTML removes all children from detached node (IE). */ + @BrowserFeature(@WebBrowser(value = IE)) + JS_OUTER_HTML_REMOVES_CHILDS_FOR_DETACHED, + /** element.outerHTML throws an exception, if the new tag will close * the outer one when parsing the html source (IE). */ Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/html/HTMLElement.java =================================================================== --- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/html/HTMLElement.java 2014-03-20 18:51:04 UTC (rev 9193) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/html/HTMLElement.java 2014-03-20 20:20:52 UTC (rev 9194) @@ -34,8 +34,9 @@ import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_INNER_HTML_REDUCE_WHITESPACES; import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_NATIVE_FUNCTION_TOSTRING_NEW_LINE; import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_OFFSET_PARENT_THROWS_NOT_ATTACHED; +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_OUTER_HTML_NULL_AS_STRING; +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_OUTER_HTML_REMOVES_CHILDS_FOR_DETACHED; import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_OUTER_HTML_THROW_EXCEPTION_WHEN_CLOSES; -import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_OUTER_HTML_NULL_AS_STRING; import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_PREFIX_RETURNS_EMPTY_WHEN_UNDEFINED; import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_SET_ATTRIBUTE_SUPPORTS_EVENT_HANDLERS; import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_WIDTH_HEIGHT_ACCEPTS_ARBITRARY_VALUES; @@ -1039,6 +1040,13 @@ @JsxSetter public void setOuterHTML(final Object value) { final DomNode domNode = getDomNodeOrDie(); + final DomNode parent = domNode.getParentNode(); + if (null == parent) { + if (getBrowserVersion().hasFeature(JS_OUTER_HTML_REMOVES_CHILDS_FOR_DETACHED)) { + domNode.removeAllChildren(); + } + return; + } if (value == null && !getBrowserVersion().hasFeature(JS_OUTER_HTML_NULL_AS_STRING)) { domNode.remove(); @@ -1050,8 +1058,6 @@ return; } - final DomNode parent = domNode.getParentNode(); - final DomNode nextSibling = domNode.getNextSibling(); domNode.remove(); Modified: trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/html/HTMLElementTest.java =================================================================== --- trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/html/HTMLElementTest.java 2014-03-20 18:51:04 UTC (rev 9193) +++ trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/html/HTMLElementTest.java 2014-03-20 20:20:52 UTC (rev 9194) @@ -1408,9 +1408,179 @@ } /** + * Test setting <code>outerHTML</code> to two XHTML self-closing <code>div</code> (block). * @throws Exception if the test fails */ @Test + @Alerts(DEFAULT = { "Old = <span id=\"innerNode\">Old outerHTML</span>", + "New = <span id=\"innerNode\">Old outerHTML</span>", "Childs: 1" }, + CHROME = { "Old = <span id=\"innerNode\">Old outerHTML</span>", "exception" }, + IE11 = { "Old = <span id=\"innerNode\">Old outerHTML</span>", "New = ", "Childs: 0" }, + IE8 = { "Old = <SPAN id=innerNode>Old outerHTML</SPAN>", "New = ", "Childs: 0" }) + public void setOuterHTMLDetachedElementNull() throws Exception { + final String html = "<html>\n" + + "<head>\n" + + " <title>test</title>\n" + + " <script>\n" + + " function doTest(){\n" + + " var myNode = document.getElementById('myNode');\n" + + " document.body.removeChild(myNode);\n" + + " alert('Old = ' + myNode.innerHTML);\n" + + " try {\n" + + " myNode.outerHTML = null;\n" + + " alert('New = ' + myNode.innerHTML);\n" + + " alert('Childs: ' + myNode.childNodes.length);\n" + + " } catch(e) {alert('exception'); }\n" + + " }\n" + + " </script>\n" + + "</head>\n" + + "<body onload='doTest()'>\n" + + " <div id='myNode'><span id='innerNode'>Old outerHTML</span></div>\n" + + "</body>\n" + + "</html>"; + loadPageWithAlerts2(html); + } + + /** + * Test setting <code>outerHTML</code> to two XHTML self-closing <code>div</code> (block). + * @throws Exception if the test fails + */ + @Test + @Alerts(DEFAULT = { "Old = <span id=\"innerNode\">Old outerHTML</span>", + "New = <span id=\"innerNode\">Old outerHTML</span>", "Childs: 1" }, + CHROME = { "Old = <span id=\"innerNode\">Old outerHTML</span>", "exception" }, + IE11 = { "Old = <span id=\"innerNode\">Old outerHTML</span>", "New = ", "Childs: 0" }, + IE8 = { "Old = <SPAN id=innerNode>Old outerHTML</SPAN>", "New = ", "Childs: 0" }) + public void setOuterHTMLDetachedElementUndefined() throws Exception { + final String html = "<html>\n" + + "<head>\n" + + " <title>test</title>\n" + + " <script>\n" + + " function doTest(){\n" + + " var myNode = document.getElementById('myNode');\n" + + " document.body.removeChild(myNode);\n" + + " alert('Old = ' + myNode.innerHTML);\n" + + " try {\n" + + " myNode.outerHTML = undefined;\n" + + " alert('New = ' + myNode.innerHTML);\n" + + " alert('Childs: ' + myNode.childNodes.length);\n" + + " } catch(e) {alert('exception'); }\n" + + " }\n" + + " </script>\n" + + "</head>\n" + + "<body onload='doTest()'>\n" + + " <div id='myNode'><span id='innerNode'>Old outerHTML</span></div>\n" + + "</body>\n" + + "</html>"; + loadPageWithAlerts2(html); + } + + /** + * Test setting <code>outerHTML</code> to two XHTML self-closing <code>div</code> (block). + * @throws Exception if the test fails + */ + @Test + @Alerts(DEFAULT = { "Old = <span id=\"innerNode\">Old outerHTML</span>", + "New = <span id=\"innerNode\">Old outerHTML</span>", "Childs: 1" }, + CHROME = { "Old = <span id=\"innerNode\">Old outerHTML</span>", "exception" }, + IE11 = { "Old = <span id=\"innerNode\">Old outerHTML</span>", "New = ", "Childs: 0" }, + IE8 = { "Old = <SPAN id=innerNode>Old outerHTML</SPAN>", "New = ", "Childs: 0" }) + public void setOuterHTMLDetachedElementEmpty() throws Exception { + final String html = "<html>\n" + + "<head>\n" + + " <title>test</title>\n" + + " <script>\n" + + " function doTest(){\n" + + " var myNode = document.getElementById('myNode');\n" + + " document.body.removeChild(myNode);\n" + + " alert('Old = ' + myNode.innerHTML);\n" + + " try {\n" + + " myNode.outerHTML = '';\n" + + " alert('New = ' + myNode.innerHTML);\n" + + " alert('Childs: ' + myNode.childNodes.length);\n" + + " } catch(e) {alert('exception'); }\n" + + " }\n" + + " </script>\n" + + "</head>\n" + + "<body onload='doTest()'>\n" + + " <div id='myNode'><span id='innerNode'>Old outerHTML</span></div>\n" + + "</body>\n" + + "</html>"; + loadPageWithAlerts2(html); + } + + /** + * Test setting <code>outerHTML</code> to two XHTML self-closing <code>div</code> (block). + * @throws Exception if the test fails + */ + @Test + @Alerts(DEFAULT = { "Old = <span id=\"innerNode\">Old outerHTML</span>", + "New = <span id=\"innerNode\">Old outerHTML</span>", "Childs: 1" }, + CHROME = { "Old = <span id=\"innerNode\">Old outerHTML</span>", "exception" }, + IE11 = { "Old = <span id=\"innerNode\">Old outerHTML</span>", "New = ", "Childs: 0" }, + IE8 = { "Old = <SPAN id=innerNode>Old outerHTML</SPAN>", "New = ", "Childs: 0" }) + public void setOuterHTMLDetachedElementBlank() throws Exception { + final String html = "<html>\n" + + "<head>\n" + + " <title>test</title>\n" + + " <script>\n" + + " function doTest(){\n" + + " var myNode = document.getElementById('myNode');\n" + + " document.body.removeChild(myNode);\n" + + " alert('Old = ' + myNode.innerHTML);\n" + + " try {\n" + + " myNode.outerHTML = '';\n" + + " alert('New = ' + myNode.innerHTML);\n" + + " alert('Childs: ' + myNode.childNodes.length);\n" + + " } catch(e) {alert('exception'); }\n" + + " }\n" + + " </script>\n" + + "</head>\n" + + "<body onload='doTest()'>\n" + + " <div id='myNode'><span id='innerNode'>Old outerHTML</span></div>\n" + + "</body>\n" + + "</html>"; + loadPageWithAlerts2(html); + } + + /** + * Test setting <code>outerHTML</code> to two XHTML self-closing <code>div</code> (block). + * @throws Exception if the test fails + */ + @Test + @Alerts(DEFAULT = { "Old = <span id=\"innerNode\">Old outerHTML</span>", + "New = <span id=\"innerNode\">Old outerHTML</span>", "Childs: 1" }, + CHROME = { "Old = <span id=\"innerNode\">Old outerHTML</span>", "exception" }, + IE = { "Old = <span id=\"innerNode\">Old outerHTML</span>", "New = ", "Childs: 0" }, + IE8 = { "Old = <SPAN id=innerNode>Old outerHTML</SPAN>", "New = ", "Childs: 0" }) + public void setOuterHTMLDetachedElement() throws Exception { + final String html = "<html>\n" + + "<head>\n" + + " <title>test</title>\n" + + " <script>\n" + + " function doTest(){\n" + + " var myNode = document.getElementById('myNode');\n" + + " document.body.removeChild(myNode);\n" + + " alert('Old = ' + myNode.innerHTML);\n" + + " try {\n" + + " myNode.outerHTML = '<p>test</p>';\n" + + " alert('New = ' + myNode.innerHTML);\n" + + " alert('Childs: ' + myNode.childNodes.length);\n" + + " } catch(e) {alert('exception'); }\n" + + " }\n" + + " </script>\n" + + "</head>\n" + + "<body onload='doTest()'>\n" + + " <div id='myNode'><span id='innerNode'>Old outerHTML</span></div>\n" + + "</body>\n" + + "</html>"; + loadPageWithAlerts2(html); + } + + /** + * @throws Exception if the test fails + */ + @Test public void setOuterHTMLExecuteJavaScript() throws Exception { final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_ + "<html><head><title>foo</title><script>\n" |