1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.javascript.host.dom;
16
17 import java.io.Serializable;
18 import java.util.ArrayList;
19 import java.util.HashMap;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Objects;
23 import java.util.function.Supplier;
24
25 import org.htmlunit.SgmlPage;
26 import org.htmlunit.corejs.javascript.Context;
27 import org.htmlunit.corejs.javascript.Function;
28 import org.htmlunit.corejs.javascript.Scriptable;
29 import org.htmlunit.html.DomDocumentFragment;
30 import org.htmlunit.html.DomElement;
31 import org.htmlunit.html.DomNode;
32 import org.htmlunit.html.HtmlElement;
33 import org.htmlunit.html.HtmlInlineFrame;
34 import org.htmlunit.javascript.HtmlUnitScriptable;
35 import org.htmlunit.javascript.JavaScriptEngine;
36 import org.htmlunit.javascript.configuration.JsxClass;
37 import org.htmlunit.javascript.configuration.JsxConstant;
38 import org.htmlunit.javascript.configuration.JsxConstructor;
39 import org.htmlunit.javascript.configuration.JsxFunction;
40 import org.htmlunit.javascript.configuration.JsxGetter;
41 import org.htmlunit.javascript.configuration.JsxSetter;
42 import org.htmlunit.javascript.host.Element;
43 import org.htmlunit.javascript.host.NamedNodeMap;
44 import org.htmlunit.javascript.host.event.EventTarget;
45 import org.htmlunit.javascript.host.html.HTMLCollection;
46 import org.htmlunit.javascript.host.html.HTMLDocument;
47 import org.htmlunit.javascript.host.html.HTMLHtmlElement;
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 @JsxClass
65 public class Node extends EventTarget {
66
67
68
69
70 @JsxConstant
71 public static final int ELEMENT_NODE = org.w3c.dom.Node.ELEMENT_NODE;
72
73
74
75
76 @JsxConstant
77 public static final int ATTRIBUTE_NODE = org.w3c.dom.Node.ATTRIBUTE_NODE;
78
79
80
81
82 @JsxConstant
83 public static final int TEXT_NODE = org.w3c.dom.Node.TEXT_NODE;
84
85
86
87
88 @JsxConstant
89 public static final int CDATA_SECTION_NODE = org.w3c.dom.Node.CDATA_SECTION_NODE;
90
91
92
93
94 @JsxConstant
95 public static final int ENTITY_REFERENCE_NODE = org.w3c.dom.Node.ENTITY_REFERENCE_NODE;
96
97
98
99
100 @JsxConstant
101 public static final int ENTITY_NODE = org.w3c.dom.Node.ENTITY_NODE;
102
103
104
105
106 @JsxConstant
107 public static final int PROCESSING_INSTRUCTION_NODE = org.w3c.dom.Node.PROCESSING_INSTRUCTION_NODE;
108
109
110
111
112 @JsxConstant
113 public static final int COMMENT_NODE = org.w3c.dom.Node.COMMENT_NODE;
114
115
116
117
118 @JsxConstant
119 public static final int DOCUMENT_NODE = org.w3c.dom.Node.DOCUMENT_NODE;
120
121
122
123
124 @JsxConstant
125 public static final int DOCUMENT_TYPE_NODE = org.w3c.dom.Node.DOCUMENT_TYPE_NODE;
126
127
128
129
130 @JsxConstant
131 public static final int DOCUMENT_FRAGMENT_NODE = org.w3c.dom.Node.DOCUMENT_FRAGMENT_NODE;
132
133
134
135
136 @JsxConstant
137 public static final int NOTATION_NODE = org.w3c.dom.Node.NOTATION_NODE;
138
139
140
141
142 @JsxConstant
143 public static final int DOCUMENT_POSITION_DISCONNECTED = org.w3c.dom.Node.DOCUMENT_POSITION_DISCONNECTED;
144
145
146
147
148 @JsxConstant
149 public static final int DOCUMENT_POSITION_PRECEDING = org.w3c.dom.Node.DOCUMENT_POSITION_PRECEDING;
150
151
152
153
154 @JsxConstant
155 public static final int DOCUMENT_POSITION_FOLLOWING = org.w3c.dom.Node.DOCUMENT_POSITION_FOLLOWING;
156
157
158
159
160 @JsxConstant
161 public static final int DOCUMENT_POSITION_CONTAINS = org.w3c.dom.Node.DOCUMENT_POSITION_CONTAINS;
162
163
164
165
166 @JsxConstant
167 public static final int DOCUMENT_POSITION_CONTAINED_BY = org.w3c.dom.Node.DOCUMENT_POSITION_CONTAINED_BY;
168
169
170
171
172 @JsxConstant
173 public static final int DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
174 = org.w3c.dom.Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
175
176
177 private NodeList childNodes_;
178
179
180
181
182 @Override
183 @JsxConstructor
184 public void jsConstructor() {
185 super.jsConstructor();
186 }
187
188
189
190
191
192 @JsxGetter
193 public int getNodeType() {
194 return getDomNodeOrDie().getNodeType();
195 }
196
197
198
199
200
201 @JsxGetter
202 public String getNodeName() {
203 return getDomNodeOrDie().getNodeName();
204 }
205
206
207
208
209
210 @JsxGetter
211 public String getNodeValue() {
212 return getDomNodeOrDie().getNodeValue();
213 }
214
215
216
217
218
219 @JsxSetter
220 public void setNodeValue(final String newValue) {
221 getDomNodeOrDie().setNodeValue(newValue);
222 }
223
224
225
226
227
228
229 @JsxFunction
230 public Node appendChild(final Object childObject) {
231 if (childObject instanceof Node) {
232 final Node childNode = (Node) childObject;
233
234
235 if (!isNodeInsertable(childNode)) {
236 throw JavaScriptEngine.asJavaScriptException(
237 getWindow(),
238 "Node cannot be inserted at the specified point in the hierarchy",
239 DOMException.HIERARCHY_REQUEST_ERR);
240 }
241
242
243 final DomNode childDomNode = childNode.getDomNodeOrDie();
244
245
246 final DomNode parentNode = getDomNodeOrDie();
247
248
249 try {
250 parentNode.appendChild(childDomNode);
251 }
252 catch (final org.w3c.dom.DOMException e) {
253 throw JavaScriptEngine.asJavaScriptException(getWindow(), e.getMessage(), e.code);
254 }
255
256 initInlineFrameIfNeeded(childDomNode);
257 for (final HtmlElement htmlElement : childDomNode.getHtmlElementDescendants()) {
258 initInlineFrameIfNeeded(htmlElement);
259 }
260 return childNode;
261 }
262 return null;
263 }
264
265
266
267
268
269
270 private static void initInlineFrameIfNeeded(final DomNode childDomNode) {
271 if (childDomNode instanceof HtmlInlineFrame) {
272 final HtmlInlineFrame frame = (HtmlInlineFrame) childDomNode;
273 if (DomElement.ATTRIBUTE_NOT_DEFINED == frame.getSrcAttribute()) {
274 frame.loadInnerPage();
275 }
276 }
277 }
278
279
280
281
282
283
284
285
286
287
288
289 @JsxFunction
290 public static Node insertBefore(final Context context, final Scriptable scope,
291 final Scriptable thisObj, final Object[] args, final Function function) {
292 return ((Node) thisObj).insertBeforeImpl(args);
293 }
294
295
296
297
298
299
300
301 protected Node insertBeforeImpl(final Object[] args) {
302 if (args.length < 1) {
303 throw JavaScriptEngine.typeError(
304 "Failed to execute 'insertBefore' on 'Node': 2 arguments required, but only 0 present.");
305 }
306
307 final Object newChildObject = args[0];
308 final Object refChildObject;
309 if (args.length > 1) {
310 refChildObject = args[1];
311 }
312 else {
313 refChildObject = JavaScriptEngine.UNDEFINED;
314 }
315
316 if (newChildObject instanceof Node) {
317 final Node newChild = (Node) newChildObject;
318
319
320 if (!isNodeInsertable(newChild)) {
321 throw JavaScriptEngine.asJavaScriptException(
322 getWindow(),
323 "Node cannot be inserted at the specified point in the hierarchy",
324 DOMException.HIERARCHY_REQUEST_ERR);
325 }
326
327 final DomNode newChildNode = newChild.getDomNodeOrDie();
328 if (newChildNode instanceof DomDocumentFragment) {
329 final DomDocumentFragment fragment = (DomDocumentFragment) newChildNode;
330 for (final DomNode child : fragment.getChildren()) {
331 if (!isNodeInsertable(child.getScriptableObject())) {
332 throw JavaScriptEngine.asJavaScriptException(
333 getWindow(),
334 "Node cannot be inserted at the specified point in the hierarchy",
335 DOMException.HIERARCHY_REQUEST_ERR);
336 }
337 }
338 }
339
340
341 final DomNode refChildNode;
342 if (JavaScriptEngine.isUndefined(refChildObject)) {
343 if (args.length == 2) {
344 refChildNode = null;
345 }
346 else {
347 throw JavaScriptEngine.typeError(
348 "Failed to execute 'insertBefore' on 'Node': 2 arguments required, but only 1 present.");
349 }
350 }
351 else if (refChildObject == null) {
352 refChildNode = null;
353 }
354 else {
355 refChildNode = ((Node) refChildObject).getDomNodeOrDie();
356 }
357
358 final DomNode domNode = getDomNodeOrDie();
359
360 try {
361 domNode.insertBefore(newChildNode, refChildNode);
362 }
363 catch (final org.w3c.dom.DOMException e) {
364 throw JavaScriptEngine.asJavaScriptException(getWindow(), e.getMessage(), DOMException.NOT_FOUND_ERR);
365 }
366 return newChild;
367 }
368 return null;
369 }
370
371
372
373
374
375
376 private static boolean isNodeInsertable(final Node childObject) {
377 if (childObject instanceof HTMLHtmlElement) {
378 final DomNode domNode = childObject.getDomNodeOrDie();
379 return domNode.getPage().getDocumentElement() != domNode;
380 }
381 return true;
382 }
383
384
385
386
387
388 protected void remove() {
389 getDomNodeOrDie().remove();
390 }
391
392
393
394
395
396
397 @JsxFunction
398 public Node removeChild(final Object childObject) {
399 if (!(childObject instanceof Node)) {
400 return null;
401 }
402
403
404 final Node childObjectNode = (Node) childObject;
405 final DomNode childDomNode = childObjectNode.getDomNodeOrDie();
406
407 if (!getDomNodeOrDie().isAncestorOf(childDomNode)) {
408 throw JavaScriptEngine.asJavaScriptException(
409 getWindow(),
410 "Failed to execute 'removeChild' on '"
411 + this + "': The node to be removed is not a child of this node.",
412 DOMException.NOT_FOUND_ERR);
413 }
414
415 childDomNode.remove();
416 return childObjectNode;
417 }
418
419
420
421
422
423
424
425 @JsxFunction
426 public Node replaceChild(final Object newChildObject, final Object oldChildObject) {
427 if (newChildObject instanceof DocumentFragment) {
428 final DocumentFragment fragment = (DocumentFragment) newChildObject;
429 Node firstNode = null;
430
431 final Node oldChildNode = (Node) oldChildObject;
432 final Node refChildObject = oldChildNode.getNextSibling();
433 for (final DomNode node : fragment.getDomNodeOrDie().getChildren()) {
434 if (firstNode == null) {
435 replaceChild(node.getScriptableObject(), oldChildObject);
436 firstNode = node.getScriptableObject();
437 }
438 else {
439 insertBeforeImpl(new Object[] {node.getScriptableObject(), refChildObject});
440 }
441 }
442 if (firstNode == null) {
443 removeChild(oldChildObject);
444 }
445
446 return oldChildNode;
447 }
448
449 if (newChildObject instanceof Node && oldChildObject instanceof Node) {
450 final Node newChild = (Node) newChildObject;
451
452
453 if (!isNodeInsertable(newChild)) {
454 throw JavaScriptEngine.asJavaScriptException(
455 getWindow(),
456 "Node cannot be inserted at the specified point in the hierarchy",
457 DOMException.HIERARCHY_REQUEST_ERR);
458 }
459
460
461 final DomNode newChildDomNode = newChild.getDomNodeOrDie();
462 final Node oldChildNode = (Node) oldChildObject;
463 final DomNode oldChildDomNode = oldChildNode.getDomNodeOrDie();
464
465
466 oldChildDomNode.replace(newChildDomNode);
467
468 return oldChildNode;
469 }
470
471 return null;
472 }
473
474
475
476
477
478
479 @JsxFunction
480 public Node cloneNode(final boolean deep) {
481 final DomNode domNode = getDomNodeOrDie();
482 final DomNode clonedNode = domNode.cloneNode(deep);
483
484 return getJavaScriptNode(clonedNode);
485 }
486
487
488
489
490
491
492
493
494 @JsxFunction
495 public boolean isEqualNode(final Node other) {
496 if (isSameNode(other)) {
497 return true;
498 }
499
500 if (other == null) {
501 return false;
502 }
503
504 if (!getClassName().equals(other.getClassName())) {
505 return false;
506 }
507
508 if (this instanceof DocumentType) {
509 final DocumentType docType = (DocumentType) this;
510 final DocumentType otherDocType = (DocumentType) other;
511 if (!Objects.equals(docType.getName(), otherDocType.getName())
512 || !Objects.equals(docType.getPublicId(), otherDocType.getPublicId())
513 || !Objects.equals(docType.getSystemId(), otherDocType.getSystemId())) {
514 return false;
515 }
516
517 }
518 else if (this instanceof Element) {
519 final Element element = (Element) this;
520 final Element otherElement = (Element) other;
521 if (!Objects.equals(element.getNodeName(), otherElement.getNodeName())
522 || !Objects.equals(element.getPrefix(), otherElement.getPrefix())
523 || !Objects.equals(element.getLocalName(), otherElement.getLocalName())) {
524 return false;
525 }
526
527 final NamedNodeMap attributesMap = element.getAttributes();
528 final NamedNodeMap otherAttributesMap = otherElement.getAttributes();
529 if (attributesMap != null || otherAttributesMap != null) {
530 if (attributesMap == null || otherAttributesMap == null) {
531 return false;
532 }
533
534 final int length = attributesMap.getLength();
535 if (length != otherAttributesMap.getLength()) {
536 return false;
537 }
538
539 final Map<String, Attr> name2Attributes = new HashMap<>();
540 for (int i = 0; i < length; i++) {
541 final Attr attribute = (Attr) attributesMap.item(i);
542 name2Attributes.put(attribute.getName(), attribute);
543 }
544
545 for (int i = 0; i < length; i++) {
546 final Attr otherAttribute = (Attr) otherAttributesMap.item(i);
547 final Attr attribute = name2Attributes.get(otherAttribute.getName());
548 if (attribute == null) {
549 return false;
550 }
551 if (!attribute.isEqualNode(otherAttribute)) {
552 return false;
553 }
554 }
555 }
556
557 }
558 else if (this instanceof Attr) {
559 final Attr attr = (Attr) this;
560 final Attr otherAttr = (Attr) other;
561 if (!Objects.equals(attr.getName(), otherAttr.getName())
562 || !Objects.equals(attr.getLocalName(), otherAttr.getLocalName())
563 || !Objects.equals(attr.getValue(), otherAttr.getValue())) {
564 return false;
565 }
566
567 }
568 else if (this instanceof ProcessingInstruction) {
569 final ProcessingInstruction instruction = (ProcessingInstruction) this;
570 final ProcessingInstruction otherInstruction = (ProcessingInstruction) other;
571 if (!Objects.equals(instruction.getTarget(), otherInstruction.getTarget())
572 || !Objects.equals(instruction.getData(), otherInstruction.getData())) {
573 return false;
574 }
575
576 }
577 else if (this instanceof Text || this instanceof Comment) {
578 final CharacterData data = (CharacterData) this;
579 final CharacterData otherData = (CharacterData) other;
580 if (!Objects.equals(data.getData(), otherData.getData())) {
581 return false;
582 }
583 }
584
585 final NodeList childNodes = getChildNodes();
586 final NodeList otherChildNodes = other.getChildNodes();
587 if (childNodes != null || otherChildNodes != null) {
588 if (childNodes == null || otherChildNodes == null) {
589 return false;
590 }
591
592 final int length = childNodes.getLength();
593 final int otherLength = otherChildNodes.getLength();
594 if (length != otherLength) {
595 return false;
596 }
597
598 for (int i = 0; i < length; i++) {
599 final Node childNode = (Node) childNodes.item(i);
600 final Node otherChildNode = (Node) otherChildNodes.item(i);
601 if (!childNode.isEqualNode(otherChildNode)) {
602 return false;
603 }
604 }
605 }
606
607 return true;
608 }
609
610
611
612
613
614
615
616
617
618
619
620
621 @JsxFunction
622 public boolean isSameNode(final Object other) {
623 return this == other;
624 }
625
626
627
628
629
630 @JsxFunction
631 public boolean hasChildNodes() {
632 return getDomNodeOrDie().getChildren().iterator().hasNext();
633 }
634
635
636
637
638
639
640
641 @JsxFunction
642 public String lookupPrefix(final String namespace) {
643 return null;
644 }
645
646
647
648
649
650 @JsxGetter
651 public NodeList getChildNodes() {
652 if (childNodes_ == null) {
653 final DomNode node = getDomNodeOrDie();
654 childNodes_ = new NodeList(node, false);
655 childNodes_.setElementsSupplier(
656 (Supplier<List<DomNode>> & Serializable)
657 () -> {
658 final List<DomNode> response = new ArrayList<>();
659 for (final DomNode child : node.getChildren()) {
660 response.add(child);
661 }
662
663 return response;
664 });
665 }
666 return childNodes_;
667 }
668
669
670
671
672
673 public final Node getParent() {
674 return getJavaScriptNode(getDomNodeOrDie().getParentNode());
675 }
676
677
678
679
680
681
682 @JsxGetter
683 public Object getParentNode() {
684 return getJavaScriptNode(getDomNodeOrDie().getParentNode());
685 }
686
687
688
689
690
691
692
693 @JsxGetter
694 public Node getNextSibling() {
695 return getJavaScriptNode(getDomNodeOrDie().getNextSibling());
696 }
697
698
699
700
701
702
703
704 @JsxGetter
705 public Node getPreviousSibling() {
706 return getJavaScriptNode(getDomNodeOrDie().getPreviousSibling());
707 }
708
709
710
711
712
713
714
715 @JsxGetter
716 public Node getFirstChild() {
717 return getJavaScriptNode(getDomNodeOrDie().getFirstChild());
718 }
719
720
721
722
723
724
725
726 @JsxGetter
727 public Node getLastChild() {
728 return getJavaScriptNode(getDomNodeOrDie().getLastChild());
729 }
730
731
732
733
734
735
736 protected Node getJavaScriptNode(final DomNode domNode) {
737 if (domNode == null) {
738 return null;
739 }
740 return (Node) getScriptableFor(domNode);
741 }
742
743
744
745
746
747 @JsxGetter
748 public HtmlUnitScriptable getOwnerDocument() {
749 final Object document = getDomNodeOrDie().getOwnerDocument();
750 if (document != null) {
751 return ((SgmlPage) document).getScriptableObject();
752 }
753 return null;
754 }
755
756
757
758
759
760 @JsxFunction
761 public Node getRootNode() {
762 Node parent = this;
763 while (parent != null) {
764 if (parent instanceof Document || parent instanceof DocumentFragment) {
765 return parent;
766 }
767 parent = parent.getParent();
768 }
769 return this;
770 }
771
772
773
774
775
776
777
778
779 @JsxFunction
780 public int compareDocumentPosition(final Object node) {
781 if (!(node instanceof Node)) {
782 throw JavaScriptEngine.typeError("Could not convert JavaScript argument arg 0");
783 }
784 return getDomNodeOrDie().compareDocumentPosition(((Node) node).getDomNodeOrDie());
785 }
786
787
788
789
790 @JsxFunction
791 public void normalize() {
792 getDomNodeOrDie().normalize();
793 }
794
795
796
797
798
799 @JsxGetter
800 public String getTextContent() {
801 return getDomNodeOrDie().getTextContent();
802 }
803
804
805
806
807
808 @JsxSetter
809 public void setTextContent(final Object value) {
810 getDomNodeOrDie().setTextContent(value == null ? null : JavaScriptEngine.toString(value));
811 }
812
813
814
815
816
817
818 @JsxGetter
819 public Element getParentElement() {
820 final Node parent = getParent();
821 if (!(parent instanceof Element)) {
822 return null;
823 }
824 return (Element) parent;
825 }
826
827
828
829
830
831
832 public NamedNodeMap getAttributes() {
833 return null;
834 }
835
836
837
838
839
840
841 @JsxFunction
842 public boolean contains(final Object element) {
843 if (element == null || JavaScriptEngine.isUndefined(element)) {
844 return false;
845 }
846
847 if (!(element instanceof Node)) {
848 throw JavaScriptEngine.reportRuntimeError("Could not convert JavaScript argument arg 0");
849 }
850
851 for (Node parent = (Node) element; parent != null; parent = parent.getParentElement()) {
852 if (this == parent) {
853 return true;
854 }
855 }
856 return false;
857 }
858
859
860
861
862
863 @JsxGetter
864 public String getBaseURI() {
865 return getDomNodeOrDie().getBaseURI();
866 }
867
868
869
870
871
872 public boolean hasAttributes() {
873 return getDomNodeOrDie().hasAttributes();
874 }
875
876
877
878
879
880 public String getPrefix() {
881 return getDomNodeOrDie().getPrefix();
882 }
883
884
885
886
887
888 public String getLocalName() {
889 return getDomNodeOrDie().getLocalName();
890 }
891
892
893
894
895
896 public String getNamespaceURI() {
897 return getDomNodeOrDie().getNamespaceURI();
898 }
899
900
901
902
903
904 protected int getChildElementCount() {
905 final DomNode domNode = getDomNodeOrDie();
906 if (domNode instanceof DomElement) {
907 return ((DomElement) domNode).getChildElementCount();
908 }
909
910 int counter = 0;
911 for (final DomNode child : getDomNodeOrDie().getChildren()) {
912 if (child != null) {
913 final HtmlUnitScriptable scriptable = child.getScriptableObject();
914 if (scriptable instanceof Element) {
915 counter++;
916 }
917 }
918 }
919 return counter;
920 }
921
922
923
924
925
926 protected Element getFirstElementChild() {
927 final DomNode domNode = getDomNodeOrDie();
928 if (domNode instanceof DomElement) {
929 final DomElement child = ((DomElement) domNode).getFirstElementChild();
930 if (child != null) {
931 return child.getScriptableObject();
932 }
933 return null;
934 }
935
936 for (final DomNode child : domNode.getChildren()) {
937 if (child != null) {
938 final HtmlUnitScriptable scriptable = child.getScriptableObject();
939 if (scriptable instanceof Element) {
940 return (Element) scriptable;
941 }
942 }
943 }
944 return null;
945 }
946
947
948
949
950
951 protected Element getLastElementChild() {
952 final DomNode domNode = getDomNodeOrDie();
953 if (domNode instanceof DomElement) {
954 final DomElement child = ((DomElement) getDomNodeOrDie()).getLastElementChild();
955 if (child != null) {
956 return child.getScriptableObject();
957 }
958 return null;
959 }
960
961 Element result = null;
962 for (final DomNode child : domNode.getChildren()) {
963 final HtmlUnitScriptable scriptable = child.getScriptableObject();
964 if (scriptable instanceof Element) {
965 result = (Element) scriptable;
966 }
967 }
968 return result;
969 }
970
971
972
973
974
975
976 protected HTMLCollection getChildren() {
977 final DomNode node = getDomNodeOrDie();
978 final HTMLCollection childrenColl = new HTMLCollection(node, false);
979 childrenColl.setElementsSupplier(
980 (Supplier<List<DomNode>> & Serializable)
981 () -> {
982 final List<DomNode> children = new ArrayList<>();
983 for (final DomNode domNode : node.getChildNodes()) {
984 if (domNode instanceof DomElement) {
985 children.add(domNode);
986 }
987 }
988 return children;
989 });
990 return childrenColl;
991 }
992
993
994
995
996
997
998
999
1000
1001 protected static void after(final Context context, final Scriptable thisObj, final Object[] args,
1002 final Function function) {
1003 final DomNode thisDomNode = ((Node) thisObj).getDomNodeOrDie();
1004 final DomNode parentNode = thisDomNode.getParentNode();
1005 final DomNode nextSibling = thisDomNode.getNextSibling();
1006 for (final Object arg : args) {
1007 final Node node = toNodeOrTextNode((Node) thisObj, arg);
1008 final DomNode newNode = node.getDomNodeOrDie();
1009 if (nextSibling == null) {
1010 parentNode.appendChild(newNode);
1011 }
1012 else {
1013 nextSibling.insertBefore(newNode);
1014 }
1015 }
1016 }
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026 protected static void append(final Context context, final Scriptable thisObj, final Object[] args,
1027 final Function function) {
1028 if (!(thisObj instanceof Node)) {
1029 throw JavaScriptEngine.typeError("Illegal invocation");
1030 }
1031
1032 final Node thisNode = (Node) thisObj;
1033 final DomNode thisDomNode = thisNode.getDomNodeOrDie();
1034
1035 for (final Object arg : args) {
1036 final Node node = toNodeOrTextNode(thisNode, arg);
1037 thisDomNode.appendChild(node.getDomNodeOrDie());
1038 }
1039 }
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049 protected static void prepend(final Context context, final Scriptable thisObj, final Object[] args,
1050 final Function function) {
1051 if (!(thisObj instanceof Node)) {
1052 throw JavaScriptEngine.typeError("Illegal invocation");
1053 }
1054
1055 final Node thisNode = (Node) thisObj;
1056 final DomNode thisDomNode = thisNode.getDomNodeOrDie();
1057 final DomNode firstChild = thisDomNode.getFirstChild();
1058
1059 for (final Object arg : args) {
1060 final Node node = toNodeOrTextNode(thisNode, arg);
1061 final DomNode newNode = node.getDomNodeOrDie();
1062 if (firstChild == null) {
1063 thisDomNode.appendChild(newNode);
1064 }
1065 else {
1066 firstChild.insertBefore(newNode);
1067 }
1068 }
1069 }
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079 protected static void replaceChildren(final Context context, final Scriptable thisObj, final Object[] args,
1080 final Function function) {
1081 if (!(thisObj instanceof Node)) {
1082 throw JavaScriptEngine.typeError("Illegal invocation");
1083 }
1084
1085 final Node thisNode = (Node) thisObj;
1086 final DomNode thisDomNode = thisNode.getDomNodeOrDie();
1087 thisDomNode.removeAllChildren();
1088
1089 for (final Object arg : args) {
1090 final Node node = toNodeOrTextNode(thisNode, arg);
1091 thisDomNode.appendChild(node.getDomNodeOrDie());
1092 }
1093 }
1094
1095 private static Node toNodeOrTextNode(final Node thisObj, final Object obj) {
1096 if (obj instanceof Node) {
1097 return (Node) obj;
1098 }
1099 return (Node)
1100 ((HTMLDocument) thisObj.getOwnerDocument()).createTextNode(JavaScriptEngine.toString(obj));
1101 }
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111 protected static void before(final Context context, final Scriptable thisObj, final Object[] args,
1112 final Function function) {
1113 for (final Object arg : args) {
1114 final Node node = toNodeOrTextNode((Node) thisObj, arg);
1115 ((Node) thisObj).getDomNodeOrDie().insertBefore(node.getDomNodeOrDie());
1116 }
1117 }
1118
1119
1120
1121
1122
1123
1124
1125
1126 protected static void replaceWith(final Context context, final Scriptable thisObj, final Object[] args,
1127 final Function function) {
1128 final DomNode thisDomNode = ((Node) thisObj).getDomNodeOrDie();
1129 final DomNode parentNode = thisDomNode.getParentNode();
1130
1131 if (args.length == 0) {
1132 parentNode.removeChild(thisDomNode);
1133 return;
1134 }
1135
1136 final DomNode nextSibling = thisDomNode.getNextSibling();
1137 boolean isFirst = true;
1138 for (final Object arg : args) {
1139 final DomNode newNode = toNodeOrTextNode((Node) thisObj, arg).getDomNodeOrDie();
1140 if (isFirst) {
1141 isFirst = false;
1142 thisDomNode.replace(newNode);
1143 }
1144 else {
1145 if (nextSibling == null) {
1146 parentNode.appendChild(newNode);
1147 }
1148 else {
1149 nextSibling.insertBefore(newNode);
1150 }
1151 }
1152 }
1153 }
1154 }