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 (!getClassName().equals(other.getClassName())) {
501 return false;
502 }
503
504 if (this instanceof DocumentType) {
505 final DocumentType docType = (DocumentType) this;
506 final DocumentType otherDocType = (DocumentType) other;
507 if (!Objects.equals(docType.getName(), otherDocType.getName())
508 || !Objects.equals(docType.getPublicId(), otherDocType.getPublicId())
509 || !Objects.equals(docType.getSystemId(), otherDocType.getSystemId())) {
510 return false;
511 }
512
513 }
514 else if (this instanceof Element) {
515 final Element element = (Element) this;
516 final Element otherElement = (Element) other;
517 if (!Objects.equals(element.getNodeName(), otherElement.getNodeName())
518 || !Objects.equals(element.getPrefix(), otherElement.getPrefix())
519 || !Objects.equals(element.getLocalName(), otherElement.getLocalName())) {
520 return false;
521 }
522
523 final NamedNodeMap attributesMap = element.getAttributes();
524 final NamedNodeMap otherAttributesMap = otherElement.getAttributes();
525 if (attributesMap != null || otherAttributesMap != null) {
526 if (attributesMap == null || otherAttributesMap == null) {
527 return false;
528 }
529
530 final int length = attributesMap.getLength();
531 if (length != otherAttributesMap.getLength()) {
532 return false;
533 }
534
535 final Map<String, Attr> name2Attributes = new HashMap<>();
536 for (int i = 0; i < length; i++) {
537 final Attr attribute = (Attr) attributesMap.item(i);
538 name2Attributes.put(attribute.getName(), attribute);
539 }
540
541 for (int i = 0; i < length; i++) {
542 final Attr otherAttribute = (Attr) otherAttributesMap.item(i);
543 final Attr attribute = name2Attributes.get(otherAttribute.getName());
544 if (attribute == null) {
545 return false;
546 }
547 if (!attribute.isEqualNode(otherAttribute)) {
548 return false;
549 }
550 }
551 }
552
553 }
554 else if (this instanceof Attr) {
555 final Attr attr = (Attr) this;
556 final Attr otherAttr = (Attr) other;
557 if (!Objects.equals(attr.getName(), otherAttr.getName())
558 || !Objects.equals(attr.getLocalName(), otherAttr.getLocalName())
559 || !Objects.equals(attr.getValue(), otherAttr.getValue())) {
560 return false;
561 }
562
563 }
564 else if (this instanceof ProcessingInstruction) {
565 final ProcessingInstruction instruction = (ProcessingInstruction) this;
566 final ProcessingInstruction otherInstruction = (ProcessingInstruction) other;
567 if (!Objects.equals(instruction.getTarget(), otherInstruction.getTarget())
568 || !Objects.equals(instruction.getData(), otherInstruction.getData())) {
569 return false;
570 }
571
572 }
573 else if (this instanceof Text || this instanceof Comment) {
574 final CharacterData data = (CharacterData) this;
575 final CharacterData otherData = (CharacterData) other;
576 if (!Objects.equals(data.getData(), otherData.getData())) {
577 return false;
578 }
579 }
580
581 final NodeList childNodes = getChildNodes();
582 final NodeList otherChildNodes = other.getChildNodes();
583 if (childNodes != null || otherChildNodes != null) {
584 if (childNodes == null || otherChildNodes == null) {
585 return false;
586 }
587
588 final int length = childNodes.getLength();
589 final int otherLength = childNodes.getLength();
590 if (length != otherLength) {
591 return false;
592 }
593
594 for (int i = 0; i < length; i++) {
595 final Node childNode = (Node) childNodes.item(i);
596 final Node otherChildNode = (Node) otherChildNodes.item(i);
597 if (!childNode.isEqualNode(otherChildNode)) {
598 return false;
599 }
600 }
601 }
602
603 return true;
604 }
605
606
607
608
609
610
611
612
613
614
615
616
617 @JsxFunction
618 public boolean isSameNode(final Object other) {
619 return other == this;
620 }
621
622
623
624
625
626 @JsxFunction
627 public boolean hasChildNodes() {
628 return getDomNodeOrDie().getChildren().iterator().hasNext();
629 }
630
631
632
633
634
635
636
637 @JsxFunction
638 public String lookupPrefix(final String namespace) {
639 return null;
640 }
641
642
643
644
645
646 @JsxGetter
647 public NodeList getChildNodes() {
648 if (childNodes_ == null) {
649 final DomNode node = getDomNodeOrDie();
650 childNodes_ = new NodeList(node, false);
651 childNodes_.setElementsSupplier(
652 (Supplier<List<DomNode>> & Serializable)
653 () -> {
654 final List<DomNode> response = new ArrayList<>();
655 for (final DomNode child : node.getChildren()) {
656 response.add(child);
657 }
658
659 return response;
660 });
661 }
662 return childNodes_;
663 }
664
665
666
667
668
669 public final Node getParent() {
670 return getJavaScriptNode(getDomNodeOrDie().getParentNode());
671 }
672
673
674
675
676
677
678 @JsxGetter
679 public Object getParentNode() {
680 return getJavaScriptNode(getDomNodeOrDie().getParentNode());
681 }
682
683
684
685
686
687
688
689 @JsxGetter
690 public Node getNextSibling() {
691 return getJavaScriptNode(getDomNodeOrDie().getNextSibling());
692 }
693
694
695
696
697
698
699
700 @JsxGetter
701 public Node getPreviousSibling() {
702 return getJavaScriptNode(getDomNodeOrDie().getPreviousSibling());
703 }
704
705
706
707
708
709
710
711 @JsxGetter
712 public Node getFirstChild() {
713 return getJavaScriptNode(getDomNodeOrDie().getFirstChild());
714 }
715
716
717
718
719
720
721
722 @JsxGetter
723 public Node getLastChild() {
724 return getJavaScriptNode(getDomNodeOrDie().getLastChild());
725 }
726
727
728
729
730
731
732 protected Node getJavaScriptNode(final DomNode domNode) {
733 if (domNode == null) {
734 return null;
735 }
736 return (Node) getScriptableFor(domNode);
737 }
738
739
740
741
742
743 @JsxGetter
744 public HtmlUnitScriptable getOwnerDocument() {
745 final Object document = getDomNodeOrDie().getOwnerDocument();
746 if (document != null) {
747 return ((SgmlPage) document).getScriptableObject();
748 }
749 return null;
750 }
751
752
753
754
755
756 @JsxFunction
757 public Node getRootNode() {
758 Node parent = this;
759 while (parent != null) {
760 if (parent instanceof Document || parent instanceof DocumentFragment) {
761 return parent;
762 }
763 parent = parent.getParent();
764 }
765 return this;
766 }
767
768
769
770
771
772
773
774
775 @JsxFunction
776 public int compareDocumentPosition(final Object node) {
777 if (!(node instanceof Node)) {
778 throw JavaScriptEngine.typeError("Could not convert JavaScript argument arg 0");
779 }
780 return getDomNodeOrDie().compareDocumentPosition(((Node) node).getDomNodeOrDie());
781 }
782
783
784
785
786 @JsxFunction
787 public void normalize() {
788 getDomNodeOrDie().normalize();
789 }
790
791
792
793
794
795 @JsxGetter
796 public String getTextContent() {
797 return getDomNodeOrDie().getTextContent();
798 }
799
800
801
802
803
804 @JsxSetter
805 public void setTextContent(final Object value) {
806 getDomNodeOrDie().setTextContent(value == null ? null : JavaScriptEngine.toString(value));
807 }
808
809
810
811
812
813
814 @JsxGetter
815 public Element getParentElement() {
816 final Node parent = getParent();
817 if (!(parent instanceof Element)) {
818 return null;
819 }
820 return (Element) parent;
821 }
822
823
824
825
826
827
828 public NamedNodeMap getAttributes() {
829 return null;
830 }
831
832
833
834
835
836
837 @JsxFunction
838 public boolean contains(final Object element) {
839 if (element == null || JavaScriptEngine.isUndefined(element)) {
840 return false;
841 }
842
843 if (!(element instanceof Node)) {
844 throw JavaScriptEngine.reportRuntimeError("Could not convert JavaScript argument arg 0");
845 }
846
847 for (Node parent = (Node) element; parent != null; parent = parent.getParentElement()) {
848 if (this == parent) {
849 return true;
850 }
851 }
852 return false;
853 }
854
855
856
857
858
859 @JsxGetter
860 public String getBaseURI() {
861 return getDomNodeOrDie().getBaseURI();
862 }
863
864
865
866
867
868 public boolean hasAttributes() {
869 return getDomNodeOrDie().hasAttributes();
870 }
871
872
873
874
875
876 public String getPrefix() {
877 return getDomNodeOrDie().getPrefix();
878 }
879
880
881
882
883
884 public String getLocalName() {
885 return getDomNodeOrDie().getLocalName();
886 }
887
888
889
890
891
892 public String getNamespaceURI() {
893 return getDomNodeOrDie().getNamespaceURI();
894 }
895
896
897
898
899
900 protected int getChildElementCount() {
901 final DomNode domNode = getDomNodeOrDie();
902 if (domNode instanceof DomElement) {
903 return ((DomElement) domNode).getChildElementCount();
904 }
905
906 int counter = 0;
907 for (final DomNode child : getDomNodeOrDie().getChildren()) {
908 if (child != null) {
909 final HtmlUnitScriptable scriptable = child.getScriptableObject();
910 if (scriptable instanceof Element) {
911 counter++;
912 }
913 }
914 }
915 return counter;
916 }
917
918
919
920
921
922 protected Element getFirstElementChild() {
923 final DomNode domNode = getDomNodeOrDie();
924 if (domNode instanceof DomElement) {
925 final DomElement child = ((DomElement) domNode).getFirstElementChild();
926 if (child != null) {
927 return child.getScriptableObject();
928 }
929 return null;
930 }
931
932 for (final DomNode child : domNode.getChildren()) {
933 if (child != null) {
934 final HtmlUnitScriptable scriptable = child.getScriptableObject();
935 if (scriptable instanceof Element) {
936 return (Element) scriptable;
937 }
938 }
939 }
940 return null;
941 }
942
943
944
945
946
947 protected Element getLastElementChild() {
948 final DomNode domNode = getDomNodeOrDie();
949 if (domNode instanceof DomElement) {
950 final DomElement child = ((DomElement) getDomNodeOrDie()).getLastElementChild();
951 if (child != null) {
952 return child.getScriptableObject();
953 }
954 return null;
955 }
956
957 Element result = null;
958 for (final DomNode child : domNode.getChildren()) {
959 final HtmlUnitScriptable scriptable = child.getScriptableObject();
960 if (scriptable instanceof Element) {
961 result = (Element) scriptable;
962 }
963 }
964 return result;
965 }
966
967
968
969
970
971
972 protected HTMLCollection getChildren() {
973 final DomNode node = getDomNodeOrDie();
974 final HTMLCollection childrenColl = new HTMLCollection(node, false);
975 childrenColl.setElementsSupplier(
976 (Supplier<List<DomNode>> & Serializable)
977 () -> {
978 final List<DomNode> children = new ArrayList<>();
979 for (final DomNode domNode : node.getChildNodes()) {
980 if (domNode instanceof DomElement) {
981 children.add(domNode);
982 }
983 }
984 return children;
985 });
986 return childrenColl;
987 }
988
989
990
991
992
993
994
995
996
997 protected static void after(final Context context, final Scriptable thisObj, final Object[] args,
998 final Function function) {
999 final DomNode thisDomNode = ((Node) thisObj).getDomNodeOrDie();
1000 final DomNode parentNode = thisDomNode.getParentNode();
1001 final DomNode nextSibling = thisDomNode.getNextSibling();
1002 for (final Object arg : args) {
1003 final Node node = toNodeOrTextNode((Node) thisObj, arg);
1004 final DomNode newNode = node.getDomNodeOrDie();
1005 if (nextSibling == null) {
1006 parentNode.appendChild(newNode);
1007 }
1008 else {
1009 nextSibling.insertBefore(newNode);
1010 }
1011 }
1012 }
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022 protected static void append(final Context context, final Scriptable thisObj, final Object[] args,
1023 final Function function) {
1024 if (!(thisObj instanceof Node)) {
1025 throw JavaScriptEngine.typeError("Illegal invocation");
1026 }
1027
1028 final Node thisNode = (Node) thisObj;
1029 final DomNode thisDomNode = thisNode.getDomNodeOrDie();
1030
1031 for (final Object arg : args) {
1032 final Node node = toNodeOrTextNode(thisNode, arg);
1033 thisDomNode.appendChild(node.getDomNodeOrDie());
1034 }
1035 }
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045 protected static void prepend(final Context context, final Scriptable thisObj, final Object[] args,
1046 final Function function) {
1047 if (!(thisObj instanceof Node)) {
1048 throw JavaScriptEngine.typeError("Illegal invocation");
1049 }
1050
1051 final Node thisNode = (Node) thisObj;
1052 final DomNode thisDomNode = thisNode.getDomNodeOrDie();
1053 final DomNode firstChild = thisDomNode.getFirstChild();
1054
1055 for (final Object arg : args) {
1056 final Node node = toNodeOrTextNode(thisNode, arg);
1057 final DomNode newNode = node.getDomNodeOrDie();
1058 if (firstChild == null) {
1059 thisDomNode.appendChild(newNode);
1060 }
1061 else {
1062 firstChild.insertBefore(newNode);
1063 }
1064 }
1065 }
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075 protected static void replaceChildren(final Context context, final Scriptable thisObj, final Object[] args,
1076 final Function function) {
1077 if (!(thisObj instanceof Node)) {
1078 throw JavaScriptEngine.typeError("Illegal invocation");
1079 }
1080
1081 final Node thisNode = (Node) thisObj;
1082 final DomNode thisDomNode = thisNode.getDomNodeOrDie();
1083 thisDomNode.removeAllChildren();
1084
1085 for (final Object arg : args) {
1086 final Node node = toNodeOrTextNode(thisNode, arg);
1087 thisDomNode.appendChild(node.getDomNodeOrDie());
1088 }
1089 }
1090
1091 private static Node toNodeOrTextNode(final Node thisObj, final Object obj) {
1092 if (obj instanceof Node) {
1093 return (Node) obj;
1094 }
1095 return (Node)
1096 ((HTMLDocument) thisObj.getOwnerDocument()).createTextNode(JavaScriptEngine.toString(obj));
1097 }
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107 protected static void before(final Context context, final Scriptable thisObj, final Object[] args,
1108 final Function function) {
1109 for (final Object arg : args) {
1110 final Node node = toNodeOrTextNode((Node) thisObj, arg);
1111 ((Node) thisObj).getDomNodeOrDie().insertBefore(node.getDomNodeOrDie());
1112 }
1113 }
1114
1115
1116
1117
1118
1119
1120
1121
1122 protected static void replaceWith(final Context context, final Scriptable thisObj, final Object[] args,
1123 final Function function) {
1124 final DomNode thisDomNode = ((Node) thisObj).getDomNodeOrDie();
1125 final DomNode parentNode = thisDomNode.getParentNode();
1126
1127 if (args.length == 0) {
1128 parentNode.removeChild(thisDomNode);
1129 return;
1130 }
1131
1132 final DomNode nextSibling = thisDomNode.getNextSibling();
1133 boolean isFirst = true;
1134 for (final Object arg : args) {
1135 final DomNode newNode = toNodeOrTextNode((Node) thisObj, arg).getDomNodeOrDie();
1136 if (isFirst) {
1137 isFirst = false;
1138 thisDomNode.replace(newNode);
1139 }
1140 else {
1141 if (nextSibling == null) {
1142 parentNode.appendChild(newNode);
1143 }
1144 else {
1145 nextSibling.insertBefore(newNode);
1146 }
1147 }
1148 }
1149 }
1150 }