You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

106 lines
2.8 KiB
JavaScript

'use strict';
const {ELEMENT_NODE} = require('../shared/constants.js');
const {CUSTOM_ELEMENTS, END, NEXT} = require('../shared/symbols.js');
const {htmlClasses} = require('../shared/register-html-class.js');
const {Document} = require('../interface/document.js');
const {NodeList} = require('../interface/node-list.js');
const {customElements} = require('../interface/custom-element-registry.js');
const {HTMLElement} = require('./element.js');
const createHTMLElement = (ownerDocument, builtin, localName, options) => {
if (!builtin && htmlClasses.has(localName)) {
const Class = htmlClasses.get(localName);
return new Class(ownerDocument, localName);
}
const {[CUSTOM_ELEMENTS]: {active, registry}} = ownerDocument;
if (active) {
const ce = builtin ? options.is : localName;
if (registry.has(ce)) {
const {Class} = registry.get(ce);
const element = new Class(ownerDocument, localName);
customElements.set(element, {connected: false});
return element;
}
}
return new HTMLElement(ownerDocument, localName);
};
/**
* @implements globalThis.HTMLDocument
*/
class HTMLDocument extends Document {
constructor() { super('text/html'); }
get all() {
const nodeList = new NodeList;
let {[NEXT]: next, [END]: end} = this;
while (next !== end) {
switch (next.nodeType) {
case ELEMENT_NODE:
nodeList.push(next);
break;
}
next = next[NEXT];
}
return nodeList;
}
/**
* @type HTMLHeadElement
*/
get head() {
const {documentElement} = this;
let {firstElementChild} = documentElement;
if (!firstElementChild || firstElementChild.tagName !== 'HEAD') {
firstElementChild = this.createElement('head');
documentElement.prepend(firstElementChild);
}
return firstElementChild;
}
/**
* @type HTMLBodyElement
*/
get body() {
const {head} = this;
let {nextElementSibling} = head;
if (!nextElementSibling || nextElementSibling.tagName !== 'BODY') {
nextElementSibling = this.createElement('body');
head.after(nextElementSibling);
}
return nextElementSibling;
}
/**
* @type HTMLTitleElement
*/
get title() {
const {head} = this;
return head.getElementsByTagName('title').at(0)?.textContent || '';
}
set title(textContent) {
const {head} = this;
let title = head.getElementsByTagName('title').at(0);
if (title)
title.textContent = textContent;
else {
head.insertBefore(
this.createElement('title'),
head.firstChild
).textContent = textContent;
}
}
createElement(localName, options) {
const builtin = !!(options && options.is);
const element = createHTMLElement(this, builtin, localName, options);
if (builtin)
element.setAttribute('is', options.is);
return element;
}
}
exports.HTMLDocument = HTMLDocument