]> Lady’s Gitweb - Lemon/blob - window/mod.js
[window] Polyfill top‐level D·O·M interfaces
[Lemon] / window / mod.js
1 // 🍋🏷 Lemon ∷ window/mod.js
2 // ====================================================================
3 //
4 // Copyright © 2022 Lady [@ Lady’s Computer].
5 //
6 // This Source Code Form is subject to the terms of the Mozilla Public
7 // License, v. 2.0. If a copy of the MPL was not distributed with this
8 // file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
9
10 import {
11 DOMImplementation,
12 DOMParser,
13 xhtmlNamespace,
14 XMLSerializer,
15 } from "./deps.js";
16
17 { // Polyfill global interfaces.
18 Object.assign(globalThis, {
19 DOMImplementation,
20 DOMParser,
21 XMLSerializer,
22 });
23 }
24
25 { // Polyfill document.
26 globalThis.document = new DOMImplementation().createDocument(
27 xhtmlNamespace,
28 "html",
29 null,
30 );
31 const { documentElement } = document;
32 documentElement.appendChild(
33 document.createElementNS(xhtmlNamespace, "head"),
34 );
35 documentElement.appendChild(
36 document.createElementNS(xhtmlNamespace, "body"),
37 );
38 }
39
40 { // Polyfill Element::append.
41 Object.getPrototypeOf(
42 globalThis.document.documentElement,
43 ).append = function (...children) {
44 for (const child of children) {
45 this.appendChild(
46 typeof child === "string"
47 ? this.ownerDocument.createTextNode(child)
48 : child,
49 );
50 }
51 };
52 }
53
54 { // Apply patches to Node::nodeType and Node::normalize.
55 const nodePrototype = Object.getPrototypeOf(
56 Object.getPrototypeOf(document.createDocumentFragment()),
57 );
58 const originalNodeTypeGetter = Object.getOwnPropertyDescriptor(
59 nodePrototype,
60 "nodeType",
61 )?.get ?? (() => {
62 const { nodeType: originalNodeTypeValue } = nodePrototype;
63 return () => originalNodeTypeValue;
64 })();
65 Object.defineProperty(nodePrototype, "nodeType", {
66 configurable: true,
67 enumerable: true,
68 /**
69 * To simulate restrictions on calling `nodeType` only on actual
70 * Nodes, check for inheritance first.
71 */
72 get() {
73 if (
74 !(() => {
75 // Test whether this object has the node prototype in its
76 // prototype chain.
77 for (
78 let prototype = this === Object(this)
79 ? Object.getPrototypeOf(this)
80 : null;
81 prototype != null;
82 prototype = Object.getPrototypeOf(prototype)
83 ) {
84 if (prototype === nodePrototype) {
85 // This object inherits from the Node prototype.
86 return true;
87 } else {
88 // This object is not yet known to inherits from the Node
89 // prototype.
90 continue;
91 }
92 }
93 })()
94 ) {
95 // This is not a Node.
96 throw new TypeError("nodeType requires this be a Node.");
97 } else {
98 // This is a Node; walk the prototype chain and attempt to get
99 // the node type.
100 for (
101 //deno-lint-ignore no-this-alias
102 let target = this;
103 target != null && target != nodePrototype;
104 target = Object.getPrototypeOf(target)
105 ) {
106 if (Object.hasOwn(target, "nodeType")) {
107 return Reflect.get(target, "nodeType", this);
108 } else {
109 continue;
110 }
111 }
112 return originalNodeTypeGetter.call(this);
113 }
114 },
115 set: undefined,
116 });
117 nodePrototype.normalize = function () {
118 let child = this.firstChild;
119 while (child) {
120 const next = child.nextSibling;
121 if (next && next.nodeType == 3 && child.nodeType == 3) {
122 this.removeChild(next);
123 child.appendData(next.data);
124 } else {
125 if (child.nodeType == 3 && !child.data) {
126 this.removeChild(child);
127 } else {
128 child.normalize();
129 }
130 child = next;
131 }
132 }
133 };
134 }
This page took 0.182714 seconds and 5 git commands to generate.