]> Lady’s Gitweb - Lemon/blobdiff - window/mod.js
Allow document specification and binding
[Lemon] / window / mod.js
diff --git a/window/mod.js b/window/mod.js
new file mode 100644 (file)
index 0000000..5e97d4f
--- /dev/null
@@ -0,0 +1,101 @@
+// 🍋🏷 Lemon ∷ window/mod.js
+// ====================================================================
+//
+// Copyright © 2022 Lady [@ Lady’s Computer].
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
+
+import { DOMImplementation, Node, xhtmlNamespace } from "./deps.js";
+
+{ // Polyfill document.
+  globalThis.document = new DOMImplementation().createDocument(
+    xhtmlNamespace,
+    "html",
+    null,
+  );
+  const { documentElement } = document;
+  documentElement.appendChild(
+    document.createElementNS(xhtmlNamespace, "head"),
+  );
+  documentElement.appendChild(
+    document.createElementNS(xhtmlNamespace, "body"),
+  );
+}
+
+{ // Polyfill `element.append`.
+  Object.getPrototypeOf(
+    globalThis.document.documentElement,
+  ).append = function (...children) {
+    for (const child of children) {
+      this.appendChild(
+        typeof child === "string"
+          ? this.ownerDocument.createTextNode(child)
+          : child,
+      );
+    }
+  };
+}
+
+{ // Apply patches to `Node.nodeType` and `Node.normalize`.
+  const { TEXT_NODE, prototype: nodePrototype } = Node;
+  const originalNodeTypeGetter = Object.getOwnPropertyDescriptor(
+    nodePrototype,
+    "nodeType",
+  )?.get ?? (() => {
+    const originalNodeTypeValue = nodePrototype.nodeType;
+    return () => originalNodeTypeValue;
+  })();
+  Object.defineProperty(nodePrototype, "nodeType", {
+    configurable: true,
+    enumerable: true,
+    /**
+     * To simulate restrictions on calling `nodeType` only on actual
+     * Nodes, check for inheritance first.
+     */
+    get() {
+      if (!(this instanceof Node)) {
+        // This is not a Node.
+        throw new TypeError("nodeType requires this be a Node.");
+      } else {
+        // This is a Node; walk the prototype chain and attempt to get
+        // the node type.
+        for (
+          //deno-lint-ignore no-this-alias
+          let target = this;
+          target != null && target != nodePrototype;
+          target = Object.getPrototypeOf(target)
+        ) {
+          if (Object.hasOwn(target, "nodeType")) {
+            return Reflect.get(target, "nodeType", this);
+          } else {
+            continue;
+          }
+        }
+        return originalNodeTypeGetter.call(this);
+      }
+    },
+    set: undefined,
+  });
+  nodePrototype.normalize = function () {
+    let child = this.firstChild;
+    while (child) {
+      const next = child.nextSibling;
+      if (
+        next && next.nodeType == TEXT_NODE &&
+        child.nodeType == TEXT_NODE
+      ) {
+        this.removeChild(next);
+        child.appendData(next.data);
+      } else {
+        if (child.nodeType == TEXT_NODE && !child.data) {
+          this.removeChild(child);
+        } else {
+          child.normalize();
+        }
+        child = next;
+      }
+    }
+  };
+}
This page took 0.212797 seconds and 4 git commands to generate.