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
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
|