xyc
2024-05-17 6b24f642b01cf3cd1be0d5833273fa2867d389e1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// From https://github.com/inexorabletash/polyfill/blob/master/dom.js
 
function mixin (o, ps) {
  if (!o) return;
  Object.keys(ps).forEach((p) => {
    if ((p in o) || (p in o.prototype)) { return; }
    try {
      Object.defineProperty(
        o.prototype,
        p,
        Object.getOwnPropertyDescriptor(ps, p)
      );
    } catch (ex) {
      // Throws in IE8; just copy it
      o[p] = ps[p];
    }
  });
}
 
function convertNodesIntoANode (nodes) {
  nodes = nodes.map((node) => {
    return !(node instanceof Node) ? document.createTextNode(node) : node;
  });
  if (nodes.length === 1) {
    return nodes[0];
  }
  const node = document.createDocumentFragment();
  nodes.forEach((n) => {
    node.appendChild(n);
  });
  return node;
}
 
const ParentNode = {
  prepend (...nodes) {
    nodes = convertNodesIntoANode(nodes);
    this.insertBefore(nodes, this.firstChild);
  },
  append (...nodes) {
    nodes = convertNodesIntoANode(nodes);
    this.appendChild(nodes);
  }
};
 
mixin(Document || HTMLDocument, ParentNode); // HTMLDocument for IE8
mixin(DocumentFragment, ParentNode);
mixin(Element, ParentNode);
 
// Mixin ChildNode
// https://dom.spec.whatwg.org/#interface-childnode
 
const ChildNode = {
  before (...nodes) {
    const parent = this.parentNode;
    if (!parent) return;
    let viablePreviousSibling = this.previousSibling;
    while (nodes.includes(viablePreviousSibling)) {
      viablePreviousSibling = viablePreviousSibling.previousSibling;
    }
    const node = convertNodesIntoANode(nodes);
    parent.insertBefore(
      node,
      viablePreviousSibling
        ? viablePreviousSibling.nextSibling
        : parent.firstChild
    );
  },
  after (...nodes) {
    const parent = this.parentNode;
    if (!parent) return;
    let viableNextSibling = this.nextSibling;
    while (nodes.includes(viableNextSibling)) {
      viableNextSibling = viableNextSibling.nextSibling;
    }
    const node = convertNodesIntoANode(nodes);
    parent.insertBefore(node, viableNextSibling);
  },
  replaceWith (...nodes) {
    const parent = this.parentNode;
    if (!parent) return;
    let viableNextSibling = this.nextSibling;
    while (nodes.includes(viableNextSibling)) {
      viableNextSibling = viableNextSibling.nextSibling;
    }
    const node = convertNodesIntoANode(nodes);
 
    if (this.parentNode === parent) {
      parent.replaceChild(node, this);
    } else {
      parent.insertBefore(node, viableNextSibling);
    }
  },
  remove () {
    if (!this.parentNode) { return; }
    this.parentNode.removeChild(this);
  }
};
 
mixin(DocumentType, ChildNode);
mixin(Element, ChildNode);
mixin(CharacterData, ChildNode);