Skip to content

Commit 4a9fb38

Browse files
committed
DocumentType properties entities and notations are only available in IE
Methods append/prepend/replaceChildren added to Element Element.replaceWith() fixed for the case this was called without any new elements
1 parent 343aa84 commit 4a9fb38

File tree

7 files changed

+1391
-40
lines changed

7 files changed

+1391
-40
lines changed

src/changes/changes.xml

+10-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,16 @@
88

99
<body>
1010
<release version="2.70.0" date="xx, 2023" description="Chrome/Edge 109, Firefox 108, Bugfixes">
11-
<action type="fix" dev="rbri" issue="541">"
11+
<action type="fix" dev="rbri">"
12+
DocumentType properties entities and notations are only available in IE.
13+
</action>
14+
<action type="add" dev="rbri" issue="544">"
15+
Methods append/prepend/replaceChildren added to Element.
16+
</action>
17+
<action type="fix" dev="rbri" >"
18+
Element.replaceWith() fixed for the case this was called without any new elements.
19+
</action>
20+
<action type="fix" dev="rbri" issue="541">
1221
Another Xerces detection fix for JDK 17.
1322
</action>
1423
<action type="add" dev="rbri">

src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Element.java

+55-1
Original file line numberDiff line numberDiff line change
@@ -1962,7 +1962,7 @@ public static void after(final Context context, final Scriptable thisObj, final
19621962
}
19631963

19641964
/**
1965-
* Replaces the node wit a set of Node or DOMString objects.
1965+
* Replaces the node with a set of Node or DOMString objects.
19661966
* @param context the context
19671967
* @param thisObj this object
19681968
* @param args the arguments
@@ -2105,4 +2105,58 @@ public boolean toggleAttribute(final String name, final Object force) {
21052105
return false;
21062106
}
21072107
}
2108+
2109+
/**
2110+
* Inserts a set of Node objects or string objects after the last child of the Element.
2111+
* String objects are inserted as equivalent Text nodes.
2112+
* @param context the context
2113+
* @param thisObj this object
2114+
* @param args the arguments
2115+
* @param function the function
2116+
*/
2117+
@JsxFunction({CHROME, EDGE, FF, FF_ESR})
2118+
public static void append(final Context context, final Scriptable thisObj, final Object[] args,
2119+
final Function function) {
2120+
if (!(thisObj instanceof Element)) {
2121+
throw ScriptRuntime.typeError("Illegal invocation");
2122+
}
2123+
2124+
Node.append(context, thisObj, args, function);
2125+
}
2126+
2127+
/**
2128+
* Inserts a set of Node objects or string objects before the first child of the Element.
2129+
* String objects are inserted as equivalent Text nodes.
2130+
* @param context the context
2131+
* @param thisObj this object
2132+
* @param args the arguments
2133+
* @param function the function
2134+
*/
2135+
@JsxFunction({CHROME, EDGE, FF, FF_ESR})
2136+
public static void prepend(final Context context, final Scriptable thisObj, final Object[] args,
2137+
final Function function) {
2138+
if (!(thisObj instanceof Element)) {
2139+
throw ScriptRuntime.typeError("Illegal invocation");
2140+
}
2141+
2142+
Node.prepend(context, thisObj, args, function);
2143+
}
2144+
2145+
/**
2146+
* Replaces the existing children of a Node with a specified new set of children.
2147+
* These can be string or Node objects.
2148+
* @param context the context
2149+
* @param thisObj this object
2150+
* @param args the arguments
2151+
* @param function the function
2152+
*/
2153+
@JsxFunction({CHROME, EDGE, FF, FF_ESR})
2154+
public static void replaceChildren(final Context context, final Scriptable thisObj, final Object[] args,
2155+
final Function function) {
2156+
if (!(thisObj instanceof Element)) {
2157+
throw ScriptRuntime.typeError("Illegal invocation");
2158+
}
2159+
2160+
Node.replaceChildren(context, thisObj, args, function);
2161+
}
21082162
}

src/main/java/com/gargoylesoftware/htmlunit/javascript/host/dom/DocumentType.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ public String getInternalSubset() {
115115
* Returns entities.
116116
* @return entities
117117
*/
118-
@JsxGetter
118+
@JsxGetter(IE)
119119
public Object getEntities() {
120120
final NamedNodeMap entities = ((DomDocumentType) getDomNodeOrDie()).getEntities();
121121
if (null != entities) {
@@ -132,7 +132,7 @@ public Object getEntities() {
132132
* Returns notations.
133133
* @return notations
134134
*/
135-
@JsxGetter
135+
@JsxGetter(IE)
136136
public Object getNotations() {
137137
final NamedNodeMap notations = ((DomDocumentType) getDomNodeOrDie()).getNotations();
138138
if (null != notations) {

src/main/java/com/gargoylesoftware/htmlunit/javascript/host/dom/Node.java

+80
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,80 @@ protected static void after(final Context context, final Scriptable thisObj, fin
866866
}
867867
}
868868

869+
/**
870+
* Inserts a set of Node objects or string objects after the last child of the Element.
871+
* String objects are inserted as equivalent Text nodes.
872+
* @param context the context
873+
* @param thisObj this object
874+
* @param args the arguments
875+
* @param function the function
876+
*/
877+
protected static void append(final Context context, final Scriptable thisObj, final Object[] args,
878+
final Function function) {
879+
if (!(thisObj instanceof Element)) {
880+
throw ScriptRuntime.typeError("Illegal invocation");
881+
}
882+
883+
final DomNode thisDomNode = ((Node) thisObj).getDomNodeOrDie();
884+
885+
for (final Object arg : args) {
886+
final Node node = toNodeOrTextNode((Node) thisObj, arg);
887+
final DomNode newNode = node.getDomNodeOrDie();
888+
thisDomNode.appendChild(newNode);
889+
}
890+
}
891+
892+
/**
893+
* Inserts a set of Node objects or string objects before the first child of the Element.
894+
* String objects are inserted as equivalent Text nodes.
895+
* @param context the context
896+
* @param thisObj this object
897+
* @param args the arguments
898+
* @param function the function
899+
*/
900+
protected static void prepend(final Context context, final Scriptable thisObj, final Object[] args,
901+
final Function function) {
902+
if (!(thisObj instanceof Element)) {
903+
throw ScriptRuntime.typeError("Illegal invocation");
904+
}
905+
906+
final DomNode thisDomNode = ((Node) thisObj).getDomNodeOrDie();
907+
final DomNode firstChild = thisDomNode.getFirstChild();
908+
for (final Object arg : args) {
909+
final Node node = toNodeOrTextNode((Node) thisObj, arg);
910+
final DomNode newNode = node.getDomNodeOrDie();
911+
if (firstChild == null) {
912+
thisDomNode.appendChild(newNode);
913+
}
914+
else {
915+
firstChild.insertBefore(newNode);
916+
}
917+
}
918+
}
919+
920+
/**
921+
* Replaces the existing children of a Node with a specified new set of children.
922+
* These can be string or Node objects.
923+
* @param context the context
924+
* @param thisObj this object
925+
* @param args the arguments
926+
* @param function the function
927+
*/
928+
protected static void replaceChildren(final Context context, final Scriptable thisObj, final Object[] args,
929+
final Function function) {
930+
if (!(thisObj instanceof Element)) {
931+
throw ScriptRuntime.typeError("Illegal invocation");
932+
}
933+
934+
final DomNode thisDomNode = ((Node) thisObj).getDomNodeOrDie();
935+
thisDomNode.removeAllChildren();
936+
937+
for (final Object arg : args) {
938+
final Node node = toNodeOrTextNode((Node) thisObj, arg);
939+
thisDomNode.appendChild(node.getDomNodeOrDie());
940+
}
941+
}
942+
869943
private static Node toNodeOrTextNode(final Node thisObj, final Object obj) {
870944
if (obj instanceof Node) {
871945
return (Node) obj;
@@ -901,6 +975,12 @@ protected static void replaceWith(final Context context, final Scriptable thisOb
901975
final Function function) {
902976
final DomNode thisDomNode = ((Node) thisObj).getDomNodeOrDie();
903977
final DomNode parentNode = thisDomNode.getParentNode();
978+
979+
if (args.length == 0) {
980+
parentNode.removeChild(thisDomNode);
981+
return;
982+
}
983+
904984
final DomNode nextSibling = thisDomNode.getNextSibling();
905985
boolean isFirst = true;
906986
for (final Object arg : args) {

src/test/java/com/gargoylesoftware/htmlunit/general/ElementOwnPropertiesTest.java

+56-12
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import com.gargoylesoftware.htmlunit.javascript.host.crypto.Crypto;
5252
import com.gargoylesoftware.htmlunit.javascript.host.crypto.SubtleCrypto;
5353
import com.gargoylesoftware.htmlunit.javascript.host.css.ComputedCSSStyleDeclaration;
54+
import com.gargoylesoftware.htmlunit.javascript.host.dom.CDATASection;
5455
import com.gargoylesoftware.htmlunit.javascript.host.dom.NodeList;
5556
import com.gargoylesoftware.htmlunit.javascript.host.dom.XPathResult;
5657
import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLCollection;
@@ -583,7 +584,8 @@ public void htmlElement() throws Exception {
583584
+ "scrollLeft,scrollTop,scrollWidth,setAttribute(),setAttributeNode(),setAttributeNodeNS(),"
584585
+ "setAttributeNS(),setPointerCapture(),"
585586
+ "tagName")
586-
@HtmlUnitNYI(CHROME = "after(),attributes,before(),childElementCount,children,classList,className,clientHeight,"
587+
@HtmlUnitNYI(CHROME = "after(),append(),attributes,before(),"
588+
+ "childElementCount,children,classList,className,clientHeight,"
587589
+ "clientLeft,clientTop,clientWidth,closest(),constructor(),"
588590
+ "firstElementChild,getAttribute(),getAttributeNode(),"
589591
+ "getAttributeNodeNS(),getAttributeNS(),getBoundingClientRect(),getClientRects(),"
@@ -593,12 +595,14 @@ public void htmlElement() throws Exception {
593595
+ "innerHTML,insertAdjacentElement(),insertAdjacentHTML(),insertAdjacentText(),lastElementChild,"
594596
+ "localName,"
595597
+ "matches(),namespaceURI,nextElementSibling,onbeforecopy,onbeforecut,onbeforepaste,"
596-
+ "onsearch,onwebkitfullscreenchange,onwebkitfullscreenerror,outerHTML,prefix,"
598+
+ "onsearch,onwebkitfullscreenchange,onwebkitfullscreenerror,outerHTML,prefix,prepend(),"
597599
+ "previousElementSibling,querySelector(),querySelectorAll(),remove(),removeAttribute(),"
598-
+ "removeAttributeNode(),removeAttributeNS(),replaceWith(),scrollHeight,scrollIntoView(),"
600+
+ "removeAttributeNode(),removeAttributeNS(),replaceChildren(),replaceWith(),"
601+
+ "scrollHeight,scrollIntoView(),"
599602
+ "scrollIntoViewIfNeeded(),scrollLeft,scrollTop,scrollWidth,setAttribute(),setAttributeNode(),"
600603
+ "setAttributeNS(),tagName,toggleAttribute(),webkitMatchesSelector()",
601-
EDGE = "after(),attributes,before(),childElementCount,children,classList,className,clientHeight,"
604+
EDGE = "after(),append(),attributes,before(),"
605+
+ "childElementCount,children,classList,className,clientHeight,"
602606
+ "clientLeft,clientTop,clientWidth,closest(),constructor(),"
603607
+ "firstElementChild,getAttribute(),getAttributeNode(),"
604608
+ "getAttributeNodeNS(),getAttributeNS(),getBoundingClientRect(),getClientRects(),"
@@ -608,33 +612,39 @@ public void htmlElement() throws Exception {
608612
+ "innerHTML,insertAdjacentElement(),insertAdjacentHTML(),insertAdjacentText(),lastElementChild,"
609613
+ "localName,"
610614
+ "matches(),namespaceURI,nextElementSibling,onbeforecopy,onbeforecut,onbeforepaste,"
611-
+ "onsearch,onwebkitfullscreenchange,onwebkitfullscreenerror,outerHTML,prefix,"
615+
+ "onsearch,onwebkitfullscreenchange,onwebkitfullscreenerror,outerHTML,prefix,prepend(),"
612616
+ "previousElementSibling,querySelector(),querySelectorAll(),remove(),removeAttribute(),"
613-
+ "removeAttributeNode(),removeAttributeNS(),replaceWith(),scrollHeight,scrollIntoView(),"
617+
+ "removeAttributeNode(),removeAttributeNS(),replaceChildren(),replaceWith(),"
618+
+ "scrollHeight,scrollIntoView(),"
614619
+ "scrollIntoViewIfNeeded(),scrollLeft,scrollTop,scrollWidth,setAttribute(),setAttributeNode(),"
615620
+ "setAttributeNS(),tagName,toggleAttribute(),webkitMatchesSelector()",
616-
FF = "after(),attributes,before(),childElementCount,children,classList,className,clientHeight,clientLeft,"
621+
FF = "after(),append(),attributes,before(),"
622+
+ "childElementCount,children,classList,className,clientHeight,clientLeft,"
617623
+ "clientTop,clientWidth,closest(),constructor(),"
618624
+ "firstElementChild,getAttribute(),getAttributeNode(),"
619625
+ "getAttributeNodeNS(),getAttributeNS(),getBoundingClientRect(),getClientRects(),"
620626
+ "getElementsByClassName(),getElementsByTagName(),getElementsByTagNameNS(),hasAttribute(),"
621627
+ "hasAttributeNS(),hasAttributes(),id,innerHTML,insertAdjacentElement(),insertAdjacentHTML(),"
622628
+ "insertAdjacentText(),lastElementChild,localName,matches(),mozMatchesSelector(),namespaceURI,"
623-
+ "nextElementSibling,outerHTML,prefix,previousElementSibling,querySelector(),querySelectorAll(),"
629+
+ "nextElementSibling,outerHTML,prefix,prepend(),previousElementSibling,"
630+
+ "querySelector(),querySelectorAll(),"
624631
+ "releaseCapture(),remove(),removeAttribute(),removeAttributeNode(),"
625-
+ "removeAttributeNS(),replaceWith(),"
632+
+ "removeAttributeNS(),replaceChildren(),replaceWith(),"
626633
+ "scrollHeight,scrollIntoView(),scrollLeft,scrollTop,scrollWidth,setAttribute(),setAttributeNode(),"
627634
+ "setAttributeNS(),setCapture(),tagName,toggleAttribute(),webkitMatchesSelector()",
628-
FF_ESR = "after(),attributes,before(),childElementCount,children,"
635+
FF_ESR = "after(),append(),attributes,before(),"
636+
+ "childElementCount,children,"
629637
+ "classList,className,clientHeight,clientLeft,"
630638
+ "clientTop,clientWidth,closest(),constructor(),"
631639
+ "firstElementChild,getAttribute(),getAttributeNode(),"
632640
+ "getAttributeNodeNS(),getAttributeNS(),getBoundingClientRect(),getClientRects(),"
633641
+ "getElementsByClassName(),getElementsByTagName(),getElementsByTagNameNS(),hasAttribute(),"
634642
+ "hasAttributeNS(),hasAttributes(),id,innerHTML,insertAdjacentElement(),insertAdjacentHTML(),"
635643
+ "insertAdjacentText(),lastElementChild,localName,matches(),mozMatchesSelector(),namespaceURI,"
636-
+ "nextElementSibling,outerHTML,prefix,previousElementSibling,querySelector(),querySelectorAll(),"
637-
+ "releaseCapture(),remove(),removeAttribute(),removeAttributeNode(),removeAttributeNS(),replaceWith(),"
644+
+ "nextElementSibling,outerHTML,prefix,prepend(),previousElementSibling,"
645+
+ "querySelector(),querySelectorAll(),"
646+
+ "releaseCapture(),remove(),removeAttribute(),removeAttributeNode(),"
647+
+ "removeAttributeNS(),replaceChildren(),replaceWith(),"
638648
+ "scrollHeight,scrollIntoView(),scrollLeft,scrollTop,scrollWidth,setAttribute(),setAttributeNode(),"
639649
+ "setAttributeNS(),setCapture(),tagName,toggleAttribute(),webkitMatchesSelector()",
640650
IE = "attributes,childElementCount,clientHeight,clientLeft,clientTop,clientWidth,constructor,"
@@ -13037,4 +13047,38 @@ public void cryptoSubtle() throws Exception {
1303713047
public void xPathResult() throws Exception {
1303813048
testString("var res = document.evaluate('/html/body', document, null, XPathResult.ANY_TYPE, null);", "res");
1303913049
}
13050+
13051+
/**
13052+
* Test {@link CDATASection}.
13053+
*
13054+
* @throws Exception if the test fails
13055+
*/
13056+
@Test
13057+
@Alerts(CHROME = "constructor()",
13058+
EDGE = "constructor()",
13059+
FF = "constructor()",
13060+
FF_ESR = "constructor()",
13061+
IE = "constructor")
13062+
public void cDATASection() throws Exception {
13063+
final String setup = " var doc = document.implementation.createDocument('', '', null);\n"
13064+
+ "var root = doc.appendChild(doc.createElement('root'));\n"
13065+
+ "var cdata = root.appendChild(doc.createCDATASection('abcdef'));\n";
13066+
13067+
testString(setup, "cdata");
13068+
}
13069+
13070+
/**
13071+
* Test {@link CDATASection}.
13072+
*
13073+
* @throws Exception if the test fails
13074+
*/
13075+
@Test
13076+
@Alerts(CHROME = "after(),before(),constructor(),name,publicId,remove(),replaceWith(),systemId",
13077+
EDGE = "after(),before(),constructor(),name,publicId,remove(),replaceWith(),systemId",
13078+
FF = "after(),before(),constructor(),name,publicId,remove(),replaceWith(),systemId",
13079+
FF_ESR = "after(),before(),constructor(),name,publicId,remove(),replaceWith(),systemId",
13080+
IE = "constructor,entities,internalSubset,name,notations,publicId,systemId")
13081+
public void documentType() throws Exception {
13082+
testString("", "document.firstChild");
13083+
}
1304013084
}

0 commit comments

Comments
 (0)