summaryrefslogtreecommitdiff
path: root/school/node_modules/jsdom/lib/jsdom/living/nodes
diff options
context:
space:
mode:
Diffstat (limited to 'school/node_modules/jsdom/lib/jsdom/living/nodes')
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/CDATASection-impl.js16
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/CharacterData-impl.js118
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/ChildNode-impl.js80
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/Comment-impl.js20
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/DOMImplementation-impl.js120
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/DOMStringMap-impl.js64
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/DOMTokenList-impl.js171
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/Document-impl.js946
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/DocumentFragment-impl.js44
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/DocumentOrShadowRoot-impl.js28
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/DocumentType-impl.js24
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/Element-impl.js578
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/ElementCSSInlineStyle-impl.js25
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/ElementContentEditable-impl.js7
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/GlobalEventHandlers-impl.js95
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLAnchorElement-impl.js50
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLAreaElement-impl.js43
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLAudioElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLBRElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLBaseElement-impl.js27
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLBodyElement-impl.js17
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLButtonElement-impl.js79
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLCanvasElement-impl.js130
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLCollection-impl.js96
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDListElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDataElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDataListElement-impl.js20
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDetailsElement-impl.js35
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDialogElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDirectoryElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDivElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js160
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLEmbedElement-impl.js8
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFieldSetElement-impl.js43
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFontElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFormElement-impl.js226
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFrameElement-impl.js261
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFrameSetElement-impl.js17
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHRElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHeadElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHeadingElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHtmlElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHyperlinkElementUtils-impl.js371
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLIFrameElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLImageElement-impl.js132
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLInputElement-impl.js1128
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLIElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLabelElement-impl.js94
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLegendElement-impl.js18
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLinkElement-impl.js101
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMapElement-impl.js13
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMarqueeElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMediaElement-impl.js138
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMenuElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMetaElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMeterElement-impl.js180
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLModElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOListElement-impl.js22
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLObjectElement-impl.js26
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOptGroupElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOptionElement-impl.js146
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOptionsCollection-impl.js110
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOrSVGElement-impl.js85
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOutputElement-impl.js88
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLParagraphElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLParamElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLPictureElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLPreElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLProgressElement-impl.js74
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLQuoteElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLScriptElement-impl.js265
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSelectElement-impl.js283
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSlotElement-impl.js59
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSourceElement-impl.js8
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSpanElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLStyleElement-impl.js74
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableCaptionElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableCellElement-impl.js73
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableColElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableElement-impl.js236
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableRowElement-impl.js88
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableSectionElement-impl.js61
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTemplateElement-impl.js67
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTextAreaElement-impl.js272
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTimeElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTitleElement-impl.js18
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTrackElement-impl.js13
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLUListElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLUnknownElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLVideoElement-impl.js17
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/LinkStyle-impl.js2
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js1165
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/NodeList-impl.js43
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/NonDocumentTypeChildNode-impl.js28
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/NonElementParentNode-impl.js11
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/ParentNode-impl.js91
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/ProcessingInstruction-impl.js22
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/SVGElement-impl.js64
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/SVGGraphicsElement-impl.js16
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/SVGSVGElement-impl.js42
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/SVGTests-impl.js42
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/SVGTitleElement-impl.js9
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/ShadowRoot-impl.js40
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/Slotable-impl.js48
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/Text-impl.js96
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/WindowEventHandlers-impl.js52
-rw-r--r--school/node_modules/jsdom/lib/jsdom/living/nodes/XMLDocument-impl.js4
107 files changed, 9853 insertions, 0 deletions
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/CDATASection-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/CDATASection-impl.js
new file mode 100644
index 0000000..d9e6248
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/CDATASection-impl.js
@@ -0,0 +1,16 @@
+"use strict";
+
+const TextImpl = require("./Text-impl").implementation;
+const NODE_TYPE = require("../node-type");
+
+class CDATASectionImpl extends TextImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+
+ this.nodeType = NODE_TYPE.CDATA_SECTION_NODE;
+ }
+}
+
+module.exports = {
+ implementation: CDATASectionImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/CharacterData-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/CharacterData-impl.js
new file mode 100644
index 0000000..4c051d8
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/CharacterData-impl.js
@@ -0,0 +1,118 @@
+"use strict";
+
+const DOMException = require("domexception/webidl2js-wrapper");
+
+const { mixin } = require("../../utils");
+const NodeImpl = require("./Node-impl").implementation;
+const ChildNodeImpl = require("./ChildNode-impl").implementation;
+const NonDocumentTypeChildNodeImpl = require("./NonDocumentTypeChildNode-impl").implementation;
+
+const { TEXT_NODE } = require("../node-type");
+const { MUTATION_TYPE, queueMutationRecord } = require("../helpers/mutation-observers");
+
+// https://dom.spec.whatwg.org/#characterdata
+class CharacterDataImpl extends NodeImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+
+ this._data = privateData.data;
+ }
+
+ // https://dom.spec.whatwg.org/#dom-characterdata-data
+ get data() {
+ return this._data;
+ }
+ set data(data) {
+ this.replaceData(0, this.length, data);
+ }
+
+ // https://dom.spec.whatwg.org/#dom-characterdata-length
+ get length() {
+ return this._data.length;
+ }
+
+ // https://dom.spec.whatwg.org/#dom-characterdata-substringdata
+ // https://dom.spec.whatwg.org/#concept-cd-substring
+ substringData(offset, count) {
+ const { length } = this;
+
+ if (offset > length) {
+ throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+ }
+
+ if (offset + count > length) {
+ return this._data.slice(offset);
+ }
+
+ return this._data.slice(offset, offset + count);
+ }
+
+ // https://dom.spec.whatwg.org/#dom-characterdata-appenddata
+ appendData(data) {
+ this.replaceData(this.length, 0, data);
+ }
+
+ // https://dom.spec.whatwg.org/#dom-characterdata-insertdata
+ insertData(offset, data) {
+ this.replaceData(offset, 0, data);
+ }
+
+ // https://dom.spec.whatwg.org/#dom-characterdata-deletedata
+ deleteData(offset, count) {
+ this.replaceData(offset, count, "");
+ }
+
+ // https://dom.spec.whatwg.org/#dom-characterdata-replacedata
+ // https://dom.spec.whatwg.org/#concept-cd-replace
+ replaceData(offset, count, data) {
+ const { length } = this;
+
+ if (offset > length) {
+ throw DOMException.create(this._globalObject, [
+ "The index is not in the allowed range.",
+ "IndexSizeError"
+ ]);
+ }
+
+ if (offset + count > length) {
+ count = length - offset;
+ }
+
+ queueMutationRecord(MUTATION_TYPE.CHARACTER_DATA, this, null, null, this._data, [], [], null, null);
+
+ const start = this._data.slice(0, offset);
+ const end = this._data.slice(offset + count);
+ this._data = start + data + end;
+
+ for (const range of this._referencedRanges) {
+ const { _start, _end } = range;
+
+ if (_start.offset > offset && _start.offset <= offset + count) {
+ range._setLiveRangeStart(this, offset);
+ }
+
+ if (_end.offset > offset && _end.offset <= offset + count) {
+ range._setLiveRangeEnd(this, offset);
+ }
+
+ if (_start.offset > offset + count) {
+ range._setLiveRangeStart(this, _start.offset + data.length - count);
+ }
+
+ if (_end.offset > offset + count) {
+ range._setLiveRangeEnd(this, _end.offset + data.length - count);
+ }
+ }
+
+ if (this.nodeType === TEXT_NODE && this.parentNode) {
+ this.parentNode._childTextContentChangeSteps();
+ }
+ }
+}
+
+mixin(CharacterDataImpl.prototype, NonDocumentTypeChildNodeImpl.prototype);
+mixin(CharacterDataImpl.prototype, ChildNodeImpl.prototype);
+
+module.exports = {
+ implementation: CharacterDataImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/ChildNode-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/ChildNode-impl.js
new file mode 100644
index 0000000..799e44f
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/ChildNode-impl.js
@@ -0,0 +1,80 @@
+"use strict";
+
+const { convertNodesIntoNode } = require("../node");
+
+class ChildNodeImpl {
+ remove() {
+ if (!this.parentNode) {
+ return;
+ }
+
+ this.parentNode._remove(this);
+ }
+
+ after(...nodes) {
+ const parent = this.parentNode;
+ if (parent) {
+ let viableNextSibling = this.nextSibling;
+ let idx = viableNextSibling ? nodes.indexOf(viableNextSibling) : -1;
+
+ while (idx !== -1) {
+ viableNextSibling = viableNextSibling.nextSibling;
+ if (!viableNextSibling) {
+ break;
+ }
+ idx = nodes.indexOf(viableNextSibling);
+ }
+
+ parent._preInsert(convertNodesIntoNode(this._ownerDocument, nodes), viableNextSibling);
+ }
+ }
+
+ before(...nodes) {
+ const parent = this.parentNode;
+ if (parent) {
+ let viablePreviousSibling = this.previousSibling;
+ let idx = viablePreviousSibling ? nodes.indexOf(viablePreviousSibling) : -1;
+
+ while (idx !== -1) {
+ viablePreviousSibling = viablePreviousSibling.previousSibling;
+ if (!viablePreviousSibling) {
+ break;
+ }
+ idx = nodes.indexOf(viablePreviousSibling);
+ }
+
+ parent._preInsert(
+ convertNodesIntoNode(this._ownerDocument, nodes),
+ viablePreviousSibling ? viablePreviousSibling.nextSibling : parent.firstChild
+ );
+ }
+ }
+
+ replaceWith(...nodes) {
+ const parent = this.parentNode;
+ if (parent) {
+ let viableNextSibling = this.nextSibling;
+ let idx = viableNextSibling ? nodes.indexOf(viableNextSibling) : -1;
+
+ while (idx !== -1) {
+ viableNextSibling = viableNextSibling.nextSibling;
+ if (!viableNextSibling) {
+ break;
+ }
+ idx = nodes.indexOf(viableNextSibling);
+ }
+
+ const node = convertNodesIntoNode(this._ownerDocument, nodes);
+
+ if (this.parentNode === parent) {
+ parent._replace(node, this);
+ } else {
+ parent._preInsert(node, viableNextSibling);
+ }
+ }
+ }
+}
+
+module.exports = {
+ implementation: ChildNodeImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/Comment-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/Comment-impl.js
new file mode 100644
index 0000000..b0ab40e
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/Comment-impl.js
@@ -0,0 +1,20 @@
+"use strict";
+const CharacterDataImpl = require("./CharacterData-impl").implementation;
+const idlUtils = require("../generated/utils");
+const NODE_TYPE = require("../node-type");
+
+class CommentImpl extends CharacterDataImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, {
+ data: args[0],
+ ownerDocument: idlUtils.implForWrapper(globalObject._document),
+ ...privateData
+ });
+
+ this.nodeType = NODE_TYPE.COMMENT_NODE;
+ }
+}
+
+module.exports = {
+ implementation: CommentImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/DOMImplementation-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/DOMImplementation-impl.js
new file mode 100644
index 0000000..e65255c
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/DOMImplementation-impl.js
@@ -0,0 +1,120 @@
+"use strict";
+
+const validateNames = require("../helpers/validate-names");
+const { HTML_NS, SVG_NS } = require("../helpers/namespaces");
+const { createElement, internalCreateElementNSSteps } = require("../helpers/create-element");
+const DocumentType = require("../generated/DocumentType");
+const documents = require("../documents.js");
+
+class DOMImplementationImpl {
+ constructor(globalObject, args, privateData) {
+ this._globalObject = globalObject;
+ this._ownerDocument = privateData.ownerDocument;
+ }
+
+ hasFeature() {
+ return true;
+ }
+
+ createDocumentType(qualifiedName, publicId, systemId) {
+ validateNames.qname(this._globalObject, qualifiedName);
+
+ return DocumentType.createImpl(this._globalObject, [], {
+ ownerDocument: this._ownerDocument,
+ name: qualifiedName,
+ publicId,
+ systemId
+ });
+ }
+
+ // https://dom.spec.whatwg.org/#dom-domimplementation-createdocument
+ createDocument(namespace, qualifiedName, doctype) {
+ let contentType = "application/xml";
+
+ if (namespace === HTML_NS) {
+ contentType = "application/xhtml+xml";
+ } else if (namespace === SVG_NS) {
+ contentType = "image/svg+xml";
+ }
+
+ const document = documents.createImpl(this._globalObject, {
+ contentType,
+ parsingMode: "xml",
+ encoding: "UTF-8"
+ });
+
+ let element = null;
+ if (qualifiedName !== "") {
+ element = internalCreateElementNSSteps(document, namespace, qualifiedName, {});
+ }
+
+ if (doctype !== null) {
+ document.appendChild(doctype);
+ }
+
+ if (element !== null) {
+ document.appendChild(element);
+ }
+
+ document._origin = this._ownerDocument._origin;
+
+ return document;
+ }
+
+ // https://dom.spec.whatwg.org/#dom-domimplementation-createhtmldocument
+ createHTMLDocument(title) {
+ // Let doc be a new document that is an HTML document.
+ // Set doc's content type to "text/html".
+ const document = documents.createImpl(this._globalObject, {
+ parsingMode: "html",
+ encoding: "UTF-8"
+ });
+
+ // Create a doctype, with "html" as its name and with its node document set
+ // to doc. Append the newly created node to doc.
+ const doctype = DocumentType.createImpl(this._globalObject, [], {
+ ownerDocument: document,
+ name: "html",
+ publicId: "",
+ systemId: ""
+ });
+
+ document.appendChild(doctype);
+
+ // Create an html element in the HTML namespace, and append it to doc.
+ const htmlElement = createElement(document, "html", HTML_NS);
+ document.appendChild(htmlElement);
+
+ // Create a head element in the HTML namespace, and append it to the html
+ // element created in the previous step.
+ const headElement = createElement(document, "head", HTML_NS);
+ htmlElement.appendChild(headElement);
+
+ // If the title argument is not omitted:
+ if (title !== undefined) {
+ // Create a title element in the HTML namespace, and append it to the head
+ // element created in the previous step.
+ const titleElement = createElement(document, "title", HTML_NS);
+ headElement.appendChild(titleElement);
+
+ // Create a Text node, set its data to title (which could be the empty
+ // string), and append it to the title element created in the previous step.
+ titleElement.appendChild(document.createTextNode(title));
+ }
+
+ // Create a body element in the HTML namespace, and append it to the html
+ // element created in the earlier step.
+ const bodyElement = createElement(document, "body", HTML_NS);
+ htmlElement.appendChild(bodyElement);
+
+ // doc's origin is an alias to the origin of the context object's associated
+ // document, and doc's effective script origin is an alias to the effective
+ // script origin of the context object's associated document.
+
+ return document;
+ }
+}
+
+module.exports = {
+ implementation: DOMImplementationImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/DOMStringMap-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/DOMStringMap-impl.js
new file mode 100644
index 0000000..b8861aa
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/DOMStringMap-impl.js
@@ -0,0 +1,64 @@
+"use strict";
+
+const idlUtils = require("../generated/utils.js");
+const { setAttributeValue, removeAttributeByName } = require("../attributes");
+const validateName = require("../helpers/validate-names").name;
+const DOMException = require("domexception/webidl2js-wrapper");
+
+const dataAttrRe = /^data-([^A-Z]*)$/;
+
+function attrCamelCase(name) {
+ return name.replace(/-([a-z])/g, (match, alpha) => alpha.toUpperCase());
+}
+
+function attrSnakeCase(name) {
+ return name.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`);
+}
+
+exports.implementation = class DOMStringMapImpl {
+ constructor(globalObject, args, privateData) {
+ this._globalObject = globalObject;
+ this._element = privateData.element;
+ }
+ get [idlUtils.supportedPropertyNames]() {
+ const result = new Set();
+ const { attributes } = this._element;
+ for (let i = 0; i < attributes.length; i++) {
+ const attr = attributes.item(i);
+ const matches = dataAttrRe.exec(attr.localName);
+ if (matches) {
+ result.add(attrCamelCase(matches[1]));
+ }
+ }
+ return result;
+ }
+ [idlUtils.namedGet](name) {
+ const { attributes } = this._element;
+ for (let i = 0; i < attributes.length; i++) {
+ const attr = attributes.item(i);
+ const matches = dataAttrRe.exec(attr.localName);
+ if (matches && attrCamelCase(matches[1]) === name) {
+ return attr.value;
+ }
+ }
+ return undefined;
+ }
+ [idlUtils.namedSetNew](name, value) {
+ if (/-[a-z]/.test(name)) {
+ throw DOMException.create(this._globalObject, [
+ `'${name}' is not a valid property name`,
+ "SyntaxError"
+ ]);
+ }
+ name = `data-${attrSnakeCase(name)}`;
+ validateName(this._globalObject, name);
+ setAttributeValue(this._element, name, value);
+ }
+ [idlUtils.namedSetExisting](name, value) {
+ this[idlUtils.namedSetNew](name, value);
+ }
+ [idlUtils.namedDelete](name) {
+ name = `data-${attrSnakeCase(name)}`;
+ removeAttributeByName(this._element, name);
+ }
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/DOMTokenList-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/DOMTokenList-impl.js
new file mode 100644
index 0000000..96dbd44
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/DOMTokenList-impl.js
@@ -0,0 +1,171 @@
+"use strict";
+
+const DOMException = require("domexception/webidl2js-wrapper");
+const OrderedSet = require("../helpers/ordered-set.js");
+const { asciiLowercase } = require("../helpers/strings.js");
+const idlUtils = require("../generated/utils.js");
+
+const { getAttributeValue, setAttributeValue, hasAttributeByName } = require("../attributes.js");
+
+function validateTokens(globalObject, ...tokens) {
+ for (const token of tokens) {
+ if (token === "") {
+ throw DOMException.create(globalObject, ["The token provided must not be empty.", "SyntaxError"]);
+ }
+ }
+ for (const token of tokens) {
+ if (/[\t\n\f\r ]/.test(token)) {
+ throw DOMException.create(globalObject, [
+ "The token provided contains HTML space characters, which are not valid in tokens.",
+ "InvalidCharacterError"
+ ]);
+ }
+ }
+}
+
+// https://dom.spec.whatwg.org/#domtokenlist
+class DOMTokenListImpl {
+ constructor(globalObject, args, privateData) {
+ this._globalObject = globalObject;
+
+ // _syncWithElement() must always be called before any _tokenSet access.
+ this._tokenSet = new OrderedSet();
+ this._element = privateData.element;
+ this._attributeLocalName = privateData.attributeLocalName;
+ this._supportedTokens = privateData.supportedTokens;
+
+ // Needs synchronization with element if token set is to be accessed.
+ this._dirty = true;
+ }
+
+ attrModified() {
+ this._dirty = true;
+ }
+
+ _syncWithElement() {
+ if (!this._dirty) {
+ return;
+ }
+
+ const val = getAttributeValue(this._element, this._attributeLocalName);
+ if (val === null) {
+ this._tokenSet.empty();
+ } else {
+ this._tokenSet = OrderedSet.parse(val);
+ }
+
+ this._dirty = false;
+ }
+
+ _validationSteps(token) {
+ if (!this._supportedTokens) {
+ throw new TypeError(`${this._attributeLocalName} attribute has no supported tokens`);
+ }
+ const lowerToken = asciiLowercase(token);
+ return this._supportedTokens.has(lowerToken);
+ }
+
+ _updateSteps() {
+ if (!hasAttributeByName(this._element, this._attributeLocalName) && this._tokenSet.isEmpty()) {
+ return;
+ }
+ setAttributeValue(this._element, this._attributeLocalName, this._tokenSet.serialize());
+ }
+
+ _serializeSteps() {
+ return getAttributeValue(this._element, this._attributeLocalName);
+ }
+
+ // Used by other parts of jsdom
+ get tokenSet() {
+ this._syncWithElement();
+ return this._tokenSet;
+ }
+
+ get length() {
+ this._syncWithElement();
+ return this._tokenSet.size;
+ }
+
+ get [idlUtils.supportedPropertyIndices]() {
+ this._syncWithElement();
+ return this._tokenSet.keys();
+ }
+
+ item(index) {
+ this._syncWithElement();
+ if (index >= this._tokenSet.size) {
+ return null;
+ }
+ return this._tokenSet.get(index);
+ }
+
+ contains(token) {
+ this._syncWithElement();
+ return this._tokenSet.contains(token);
+ }
+
+ add(...tokens) {
+ for (const token of tokens) {
+ validateTokens(this._globalObject, token);
+ }
+ this._syncWithElement();
+ for (const token of tokens) {
+ this._tokenSet.append(token);
+ }
+ this._updateSteps();
+ }
+
+ remove(...tokens) {
+ for (const token of tokens) {
+ validateTokens(this._globalObject, token);
+ }
+ this._syncWithElement();
+ this._tokenSet.remove(...tokens);
+ this._updateSteps();
+ }
+
+ toggle(token, force = undefined) {
+ validateTokens(this._globalObject, token);
+ this._syncWithElement();
+ if (this._tokenSet.contains(token)) {
+ if (force === undefined || force === false) {
+ this._tokenSet.remove(token);
+ this._updateSteps();
+ return false;
+ }
+ return true;
+ }
+ if (force === undefined || force === true) {
+ this._tokenSet.append(token);
+ this._updateSteps();
+ return true;
+ }
+ return false;
+ }
+
+ replace(token, newToken) {
+ validateTokens(this._globalObject, token, newToken);
+ this._syncWithElement();
+ if (!this._tokenSet.contains(token)) {
+ return false;
+ }
+ this._tokenSet.replace(token, newToken);
+ this._updateSteps();
+ return true;
+ }
+
+ supports(token) {
+ return this._validationSteps(token);
+ }
+
+ get value() {
+ return this._serializeSteps();
+ }
+
+ set value(V) {
+ setAttributeValue(this._element, this._attributeLocalName, V);
+ }
+}
+
+exports.implementation = DOMTokenListImpl;
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/Document-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/Document-impl.js
new file mode 100644
index 0000000..bfa812a
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/Document-impl.js
@@ -0,0 +1,946 @@
+"use strict";
+
+const { CookieJar } = require("tough-cookie");
+
+const NodeImpl = require("./Node-impl").implementation;
+const idlUtils = require("../generated/utils");
+const NODE_TYPE = require("../node-type");
+const { hasWeakRefs, mixin, memoizeQuery } = require("../../utils");
+const { firstChildWithLocalName, firstChildWithLocalNames, firstDescendantWithLocalName } =
+ require("../helpers/traversal");
+const whatwgURL = require("whatwg-url");
+const StyleSheetList = require("../generated/StyleSheetList.js");
+const { domSymbolTree } = require("../helpers/internal-constants");
+const eventAccessors = require("../helpers/create-event-accessor");
+const { asciiLowercase, stripAndCollapseASCIIWhitespace } = require("../helpers/strings");
+const { childTextContent } = require("../helpers/text");
+const { HTML_NS, SVG_NS } = require("../helpers/namespaces");
+const DOMException = require("domexception/webidl2js-wrapper");
+const { parseIntoDocument } = require("../../browser/parser");
+const History = require("../generated/History");
+const Location = require("../generated/Location");
+const HTMLCollection = require("../generated/HTMLCollection");
+const NodeList = require("../generated/NodeList");
+const validateName = require("../helpers/validate-names").name;
+const { validateAndExtract } = require("../helpers/validate-names");
+const { fireAnEvent } = require("../helpers/events");
+const { shadowIncludingInclusiveDescendantsIterator } = require("../helpers/shadow-dom");
+const { enqueueCECallbackReaction } = require("../helpers/custom-elements");
+const { createElement, internalCreateElementNSSteps } = require("../helpers/create-element");
+const IterableWeakSet = require("../helpers/iterable-weak-set");
+
+const DocumentOrShadowRootImpl = require("./DocumentOrShadowRoot-impl").implementation;
+const GlobalEventHandlersImpl = require("./GlobalEventHandlers-impl").implementation;
+const NonElementParentNodeImpl = require("./NonElementParentNode-impl").implementation;
+const ParentNodeImpl = require("./ParentNode-impl").implementation;
+
+const { clone, listOfElementsWithQualifiedName, listOfElementsWithNamespaceAndLocalName,
+ listOfElementsWithClassNames } = require("../node");
+const generatedAttr = require("../generated/Attr");
+const Comment = require("../generated/Comment");
+const ProcessingInstruction = require("../generated/ProcessingInstruction");
+const CDATASection = require("../generated/CDATASection");
+const Text = require("../generated/Text");
+const DocumentFragment = require("../generated/DocumentFragment");
+const DOMImplementation = require("../generated/DOMImplementation");
+const TreeWalker = require("../generated/TreeWalker");
+const NodeIterator = require("../generated/NodeIterator");
+const ShadowRoot = require("../generated/ShadowRoot");
+const Range = require("../generated/Range");
+const documents = require("../documents.js");
+
+const CustomEvent = require("../generated/CustomEvent");
+const ErrorEvent = require("../generated/ErrorEvent");
+const Event = require("../generated/Event");
+const FocusEvent = require("../generated/FocusEvent");
+const HashChangeEvent = require("../generated/HashChangeEvent");
+const KeyboardEvent = require("../generated/KeyboardEvent");
+const MessageEvent = require("../generated/MessageEvent");
+const MouseEvent = require("../generated/MouseEvent");
+const PopStateEvent = require("../generated/PopStateEvent");
+const ProgressEvent = require("../generated/ProgressEvent");
+const TouchEvent = require("../generated/TouchEvent");
+const UIEvent = require("../generated/UIEvent");
+
+const RequestManager = require("../../browser/resources/request-manager");
+const AsyncResourceQueue = require("../../browser/resources/async-resource-queue");
+const ResourceQueue = require("../../browser/resources/resource-queue");
+const PerDocumentResourceLoader = require("../../browser/resources/per-document-resource-loader");
+
+function clearChildNodes(node) {
+ for (let child = domSymbolTree.firstChild(node); child; child = domSymbolTree.firstChild(node)) {
+ node.removeChild(child);
+ }
+}
+
+function pad(number) {
+ if (number < 10) {
+ return "0" + number;
+ }
+ return number;
+}
+
+function toLastModifiedString(date) {
+ return pad(date.getMonth() + 1) +
+ "/" + pad(date.getDate()) +
+ "/" + date.getFullYear() +
+ " " + pad(date.getHours()) +
+ ":" + pad(date.getMinutes()) +
+ ":" + pad(date.getSeconds());
+}
+
+const eventInterfaceTable = {
+ customevent: CustomEvent,
+ errorevent: ErrorEvent,
+ event: Event,
+ events: Event,
+ focusevent: FocusEvent,
+ hashchangeevent: HashChangeEvent,
+ htmlevents: Event,
+ keyboardevent: KeyboardEvent,
+ messageevent: MessageEvent,
+ mouseevent: MouseEvent,
+ mouseevents: MouseEvent,
+ popstateevent: PopStateEvent,
+ progressevent: ProgressEvent,
+ svgevents: Event,
+ touchevent: TouchEvent,
+ uievent: UIEvent,
+ uievents: UIEvent
+};
+
+class DocumentImpl extends NodeImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+
+ this._initGlobalEvents();
+
+ this._ownerDocument = this;
+ this.nodeType = NODE_TYPE.DOCUMENT_NODE;
+ if (!privateData.options) {
+ privateData.options = {};
+ }
+ if (!privateData.options.parsingMode) {
+ privateData.options.parsingMode = "xml";
+ }
+ if (!privateData.options.encoding) {
+ privateData.options.encoding = "UTF-8";
+ }
+ if (!privateData.options.contentType) {
+ privateData.options.contentType = privateData.options.parsingMode === "xml" ? "application/xml" : "text/html";
+ }
+
+ this._parsingMode = privateData.options.parsingMode;
+
+ this._implementation = DOMImplementation.createImpl(this._globalObject, [], {
+ ownerDocument: this
+ });
+
+ this._defaultView = privateData.options.defaultView || null;
+ this._global = privateData.options.global;
+ this._ids = Object.create(null);
+ this._attached = true;
+ this._currentScript = null;
+ this._pageShowingFlag = false;
+ this._cookieJar = privateData.options.cookieJar;
+ this._parseOptions = privateData.options.parseOptions || {};
+ this._scriptingDisabled = privateData.options.scriptingDisabled;
+ if (this._cookieJar === undefined) {
+ this._cookieJar = new CookieJar(null, { looseMode: true });
+ }
+
+ if (this._scriptingDisabled) {
+ this._parseOptions.scriptingEnabled = false;
+ }
+
+ this.contentType = privateData.options.contentType;
+ this._encoding = privateData.options.encoding;
+
+ const urlOption = privateData.options.url === undefined ? "about:blank" : privateData.options.url;
+ const parsed = whatwgURL.parseURL(urlOption);
+ if (parsed === null) {
+ throw new TypeError(`Could not parse "${urlOption}" as a URL`);
+ }
+
+ this._URL = parsed;
+ this._origin = urlOption === "about:blank" && privateData.options.parentOrigin ?
+ privateData.options.parentOrigin :
+ whatwgURL.serializeURLOrigin(this._URL);
+
+ this._location = Location.createImpl(this._globalObject, [], { relevantDocument: this });
+ this._history = History.createImpl(this._globalObject, [], {
+ window: this._defaultView,
+ document: this,
+ actAsIfLocationReloadCalled: () => this._location.reload()
+ });
+
+ if (hasWeakRefs) {
+ this._workingNodeIterators = new IterableWeakSet();
+ } else {
+ this._workingNodeIterators = [];
+ }
+
+ this._referrer = privateData.options.referrer || "";
+ this._lastModified = toLastModifiedString(privateData.options.lastModified || new Date());
+ this._asyncQueue = new AsyncResourceQueue();
+ this._queue = new ResourceQueue({ asyncQueue: this._asyncQueue, paused: false });
+ this._deferQueue = new ResourceQueue({ paused: true });
+ this._requestManager = new RequestManager();
+ this._currentDocumentReadiness = privateData.options.readyState || "loading";
+
+ this._lastFocusedElement = null;
+
+ this._resourceLoader = new PerDocumentResourceLoader(this);
+
+ // Each Document in a browsing context can also have a latest entry. This is the entry for that Document
+ // to which the browsing context's session history was most recently traversed. When a Document is created,
+ // it initially has no latest entry.
+ this._latestEntry = null;
+
+ // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#throw-on-dynamic-markup-insertion-counter
+ this._throwOnDynamicMarkupInsertionCounter = 0;
+ }
+
+ _getTheParent(event) {
+ if (event.type === "load" || !this._defaultView) {
+ return null;
+ }
+
+ return idlUtils.implForWrapper(this._defaultView);
+ }
+
+ get compatMode() {
+ return this._parsingMode === "xml" || this.doctype ? "CSS1Compat" : "BackCompat";
+ }
+ get charset() {
+ return this._encoding;
+ }
+ get characterSet() {
+ return this._encoding;
+ }
+ get inputEncoding() {
+ return this._encoding;
+ }
+ get doctype() {
+ for (const childNode of domSymbolTree.childrenIterator(this)) {
+ if (childNode.nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE) {
+ return childNode;
+ }
+ }
+ return null;
+ }
+ get URL() {
+ return whatwgURL.serializeURL(this._URL);
+ }
+ get documentURI() {
+ return whatwgURL.serializeURL(this._URL);
+ }
+ get location() {
+ return this._defaultView ? this._location : null;
+ }
+
+ // https://dom.spec.whatwg.org/#dom-document-documentelement
+ get documentElement() {
+ for (const childNode of domSymbolTree.childrenIterator(this)) {
+ if (childNode.nodeType === NODE_TYPE.ELEMENT_NODE) {
+ return childNode;
+ }
+ }
+
+ return null;
+ }
+
+ get implementation() {
+ return this._implementation;
+ }
+ set implementation(implementation) {
+ this._implementation = implementation;
+ }
+
+ get defaultView() {
+ return this._defaultView;
+ }
+
+ get currentScript() {
+ return this._currentScript;
+ }
+
+ get readyState() {
+ return this._currentDocumentReadiness;
+ }
+
+ set readyState(state) {
+ this._currentDocumentReadiness = state;
+ fireAnEvent("readystatechange", this);
+ }
+
+ hasFocus() {
+ return Boolean(this._lastFocusedElement);
+ }
+
+ _descendantRemoved(parent, child) {
+ if (child.tagName === "STYLE") {
+ this.styleSheets._remove(child.sheet);
+ }
+
+ super._descendantRemoved(parent, child);
+ }
+
+ write(...args) {
+ let text = "";
+ for (let i = 0; i < args.length; ++i) {
+ text += args[i];
+ }
+
+ if (this._parsingMode === "xml") {
+ throw DOMException.create(this._globalObject, [
+ "Cannot use document.write on XML documents",
+ "InvalidStateError"
+ ]);
+ }
+
+ if (this._throwOnDynamicMarkupInsertionCounter > 0) {
+ throw DOMException.create(this._globalObject, [
+ "Cannot use document.write while a custom element upgrades",
+ "InvalidStateError"
+ ]);
+ }
+
+ if (this._writeAfterElement) {
+ // If called from an script element directly (during the first tick),
+ // the new elements are inserted right after that element.
+ const tempDiv = this.createElement("div");
+ tempDiv.innerHTML = text;
+
+ let child = tempDiv.firstChild;
+ let previous = this._writeAfterElement;
+ const parent = this._writeAfterElement.parentNode;
+
+ while (child) {
+ const node = child;
+ child = child.nextSibling;
+
+ node._isMovingDueToDocumentWrite = true; // hack for script execution
+ parent.insertBefore(node, previous.nextSibling);
+ node._isMovingDueToDocumentWrite = false;
+
+ previous = node;
+ }
+ } else if (this.readyState === "loading") {
+ // During page loading, document.write appends to the current element
+ // Find the last child that has been added to the document.
+ if (this.lastChild) {
+ let node = this;
+ while (node.lastChild && node.lastChild.nodeType === NODE_TYPE.ELEMENT_NODE) {
+ node = node.lastChild;
+ }
+ node.innerHTML = text;
+ } else {
+ clearChildNodes(this);
+ parseIntoDocument(text, this);
+ }
+ } else if (text) {
+ clearChildNodes(this);
+ parseIntoDocument(text, this);
+ }
+ }
+
+ writeln(...args) {
+ this.write(...args, "\n");
+ }
+
+ // This is implemented separately for Document (which has a _ids cache) and DocumentFragment (which does not).
+ getElementById(id) {
+ if (!this._ids[id]) {
+ return null;
+ }
+
+ // Let's find the first element with where it's root is the document.
+ const matchElement = this._ids[id].find(candidate => {
+ let root = candidate;
+ while (domSymbolTree.parent(root)) {
+ root = domSymbolTree.parent(root);
+ }
+
+ return root === this;
+ });
+
+ return matchElement || null;
+ }
+
+ get referrer() {
+ return this._referrer || "";
+ }
+ get lastModified() {
+ return this._lastModified;
+ }
+ get images() {
+ return this.getElementsByTagName("IMG");
+ }
+ get embeds() {
+ return this.getElementsByTagName("EMBED");
+ }
+ get plugins() {
+ return this.embeds;
+ }
+ get links() {
+ return HTMLCollection.createImpl(this._globalObject, [], {
+ element: this,
+ query: () => domSymbolTree.treeToArray(this, {
+ filter: node => (node._localName === "a" || node._localName === "area") &&
+ node.hasAttributeNS(null, "href") &&
+ node._namespaceURI === HTML_NS
+ })
+ });
+ }
+ get forms() {
+ return this.getElementsByTagName("FORM");
+ }
+ get scripts() {
+ return this.getElementsByTagName("SCRIPT");
+ }
+ get anchors() {
+ return HTMLCollection.createImpl(this._globalObject, [], {
+ element: this,
+ query: () => domSymbolTree.treeToArray(this, {
+ filter: node => node._localName === "a" &&
+ node.hasAttributeNS(null, "name") &&
+ node._namespaceURI === HTML_NS
+ })
+ });
+ }
+
+ // The applets attribute must return an
+ // HTMLCollection rooted at the Document node,
+ // whose filter matches nothing.
+ // (It exists for historical reasons.)
+ get applets() {
+ return HTMLCollection.createImpl(this._globalObject, [], {
+ element: this,
+ query: () => []
+ });
+ }
+
+ open() {
+ let child = domSymbolTree.firstChild(this);
+ while (child) {
+ this.removeChild(child);
+ child = domSymbolTree.firstChild(this);
+ }
+ this._modified();
+ return this;
+ }
+ close(noQueue) {
+ // In some cases like when creating an empty iframe, I want to emit the
+ // events right away to avoid problems if later I asign the property src.
+ if (noQueue) {
+ this.readyState = "complete";
+
+ fireAnEvent("DOMContentLoaded", this, undefined, { bubbles: true });
+ fireAnEvent("load", this);
+
+ return;
+ }
+ this._queue.resume();
+
+ const dummyPromise = Promise.resolve();
+
+ const onDOMContentLoad = () => {
+ const doc = this;
+ function dispatchEvent() {
+ // https://html.spec.whatwg.org/#the-end
+ doc.readyState = "interactive";
+ fireAnEvent("DOMContentLoaded", doc, undefined, { bubbles: true });
+ }
+
+ return new Promise(resolve => {
+ if (!this._deferQueue.tail) {
+ dispatchEvent();
+ resolve();
+ return;
+ }
+
+ this._deferQueue.setListener(() => {
+ dispatchEvent();
+ resolve();
+ });
+
+ this._deferQueue.resume();
+ });
+ };
+
+ const onLoad = () => {
+ const doc = this;
+ function dispatchEvent() {
+ doc.readyState = "complete";
+ fireAnEvent("load", doc);
+ }
+
+ return new Promise(resolve => {
+ if (this._asyncQueue.count() === 0) {
+ dispatchEvent();
+ resolve();
+ return;
+ }
+
+ this._asyncQueue.setListener(() => {
+ dispatchEvent();
+ resolve();
+ });
+ });
+ };
+
+ this._queue.push(dummyPromise, onDOMContentLoad, null);
+ // Set the readyState to 'complete' once all resources are loaded.
+ // As a side-effect the document's load-event will be dispatched.
+ this._queue.push(dummyPromise, onLoad, null, true);
+ }
+
+ getElementsByName(elementName) {
+ return NodeList.createImpl(this._globalObject, [], {
+ element: this,
+ query: () => domSymbolTree.treeToArray(this, {
+ filter: node => node.getAttributeNS && node.getAttributeNS(null, "name") === elementName
+ })
+ });
+ }
+
+ get title() {
+ const { documentElement } = this;
+ let value = "";
+
+ if (documentElement && documentElement._localName === "svg") {
+ const svgTitleElement = firstChildWithLocalName(documentElement, "title", SVG_NS);
+
+ if (svgTitleElement) {
+ value = childTextContent(svgTitleElement);
+ }
+ } else {
+ const titleElement = firstDescendantWithLocalName(this, "title");
+
+ if (titleElement) {
+ value = childTextContent(titleElement);
+ }
+ }
+
+ value = stripAndCollapseASCIIWhitespace(value);
+
+ return value;
+ }
+
+ set title(value) {
+ const { documentElement } = this;
+ let element;
+
+ if (documentElement && documentElement._localName === "svg") {
+ element = firstChildWithLocalName(documentElement, "title", SVG_NS);
+
+ if (!element) {
+ element = this.createElementNS(SVG_NS, "title");
+
+ this._insert(element, documentElement.firstChild);
+ }
+
+ element.textContent = value;
+ } else if (documentElement && documentElement._namespaceURI === HTML_NS) {
+ const titleElement = firstDescendantWithLocalName(this, "title");
+ const headElement = this.head;
+
+ if (titleElement === null && headElement === null) {
+ return;
+ }
+
+ if (titleElement !== null) {
+ element = titleElement;
+ } else {
+ element = this.createElement("title");
+ headElement._append(element);
+ }
+
+ element.textContent = value;
+ }
+ }
+
+ get dir() {
+ return this.documentElement ? this.documentElement.dir : "";
+ }
+ set dir(value) {
+ if (this.documentElement) {
+ this.documentElement.dir = value;
+ }
+ }
+
+ get head() {
+ return this.documentElement ? firstChildWithLocalName(this.documentElement, "head") : null;
+ }
+
+ get body() {
+ const { documentElement } = this;
+ if (!documentElement || documentElement._localName !== "html" ||
+ documentElement._namespaceURI !== HTML_NS) {
+ return null;
+ }
+
+ return firstChildWithLocalNames(this.documentElement, new Set(["body", "frameset"]));
+ }
+
+ set body(value) {
+ if (value === null ||
+ value._namespaceURI !== HTML_NS ||
+ (value._localName !== "body" && value._localName !== "frameset")) {
+ throw DOMException.create(this._globalObject, [
+ "Cannot set the body to null or a non-body/frameset element",
+ "HierarchyRequestError"
+ ]);
+ }
+
+ const bodyElement = this.body;
+ if (value === bodyElement) {
+ return;
+ }
+
+ if (bodyElement !== null) {
+ bodyElement.parentNode._replace(value, bodyElement);
+ return;
+ }
+
+ const { documentElement } = this;
+ if (documentElement === null) {
+ throw DOMException.create(this._globalObject, [
+ "Cannot set the body when there is no document element",
+ "HierarchyRequestError"
+ ]);
+ }
+
+ documentElement._append(value);
+ }
+
+ _runPreRemovingSteps(oldNode) {
+ // https://html.spec.whatwg.org/#focus-fixup-rule
+ if (oldNode === this.activeElement) {
+ this._lastFocusedElement = this.body;
+ }
+ for (const activeNodeIterator of this._workingNodeIterators) {
+ activeNodeIterator._preRemovingSteps(oldNode);
+ }
+ }
+
+ createEvent(type) {
+ const typeLower = type.toLowerCase();
+ const eventWrapper = eventInterfaceTable[typeLower] || null;
+
+ if (!eventWrapper) {
+ throw DOMException.create(this._globalObject, [
+ "The provided event type (\"" + type + "\") is invalid",
+ "NotSupportedError"
+ ]);
+ }
+
+ const impl = eventWrapper.createImpl(this._globalObject, [""]);
+ impl._initializedFlag = false;
+ return impl;
+ }
+
+ createRange() {
+ return Range.createImpl(this._globalObject, [], {
+ start: { node: this, offset: 0 },
+ end: { node: this, offset: 0 }
+ });
+ }
+
+ createProcessingInstruction(target, data) {
+ validateName(this._globalObject, target);
+
+ if (data.includes("?>")) {
+ throw DOMException.create(this._globalObject, [
+ "Processing instruction data cannot contain the string \"?>\"",
+ "InvalidCharacterError"
+ ]);
+ }
+
+ return ProcessingInstruction.createImpl(this._globalObject, [], {
+ ownerDocument: this,
+ target,
+ data
+ });
+ }
+
+ // https://dom.spec.whatwg.org/#dom-document-createcdatasection
+ createCDATASection(data) {
+ if (this._parsingMode === "html") {
+ throw DOMException.create(this._globalObject, [
+ "Cannot create CDATA sections in HTML documents",
+ "NotSupportedError"
+ ]);
+ }
+
+ if (data.includes("]]>")) {
+ throw DOMException.create(this._globalObject, [
+ "CDATA section data cannot contain the string \"]]>\"",
+ "InvalidCharacterError"
+ ]);
+ }
+
+ return CDATASection.createImpl(this._globalObject, [], {
+ ownerDocument: this,
+ data
+ });
+ }
+
+ createTextNode(data) {
+ return Text.createImpl(this._globalObject, [], {
+ ownerDocument: this,
+ data
+ });
+ }
+
+ createComment(data) {
+ return Comment.createImpl(this._globalObject, [], {
+ ownerDocument: this,
+ data
+ });
+ }
+
+ // https://dom.spec.whatwg.org/#dom-document-createelement
+ createElement(localName, options) {
+ validateName(this._globalObject, localName);
+
+ if (this._parsingMode === "html") {
+ localName = asciiLowercase(localName);
+ }
+
+ let isValue = null;
+ if (options && options.is !== undefined) {
+ isValue = options.is;
+ }
+
+ const namespace = this._parsingMode === "html" || this.contentType === "application/xhtml+xml" ? HTML_NS : null;
+
+ return createElement(this, localName, namespace, null, isValue, true);
+ }
+
+ // https://dom.spec.whatwg.org/#dom-document-createelementns
+ createElementNS(namespace, qualifiedName, options) {
+ return internalCreateElementNSSteps(this, namespace, qualifiedName, options);
+ }
+
+ createDocumentFragment() {
+ return DocumentFragment.createImpl(this._globalObject, [], { ownerDocument: this });
+ }
+
+ createAttribute(localName) {
+ validateName(this._globalObject, localName);
+
+ if (this._parsingMode === "html") {
+ localName = asciiLowercase(localName);
+ }
+
+ return this._createAttribute({ localName });
+ }
+
+ createAttributeNS(namespace, name) {
+ if (namespace === undefined) {
+ namespace = null;
+ }
+ namespace = namespace !== null ? String(namespace) : namespace;
+
+ const extracted = validateAndExtract(this._globalObject, namespace, name);
+ return this._createAttribute({
+ namespace: extracted.namespace,
+ namespacePrefix: extracted.prefix,
+ localName: extracted.localName
+ });
+ }
+
+ // Using this helper function rather than directly calling generatedAttr.createImpl may be preferred in some files,
+ // to avoid introducing a potentially cyclic dependency on generated/Attr.js.
+ _createAttribute({
+ localName,
+ value,
+ namespace,
+ namespacePrefix
+ }) {
+ return generatedAttr.createImpl(this._globalObject, [], {
+ localName,
+ value,
+ namespace,
+ namespacePrefix,
+ ownerDocument: this
+ });
+ }
+
+ createTreeWalker(root, whatToShow, filter) {
+ return TreeWalker.createImpl(this._globalObject, [], { root, whatToShow, filter });
+ }
+
+ createNodeIterator(root, whatToShow, filter) {
+ const nodeIterator = NodeIterator.createImpl(this._globalObject, [], { root, whatToShow, filter });
+
+ if (hasWeakRefs) {
+ this._workingNodeIterators.add(nodeIterator);
+ } else {
+ this._workingNodeIterators.push(nodeIterator);
+ while (this._workingNodeIterators.length > 10) {
+ const toInactivate = this._workingNodeIterators.shift();
+ toInactivate._working = false;
+ }
+ }
+
+ return nodeIterator;
+ }
+
+ importNode(node, deep) {
+ if (node.nodeType === NODE_TYPE.DOCUMENT_NODE) {
+ throw DOMException.create(this._globalObject, [
+ "Cannot import a document node",
+ "NotSupportedError"
+ ]);
+ } else if (ShadowRoot.isImpl(node)) {
+ throw DOMException.create(this._globalObject, [
+ "Cannot adopt a shadow root",
+ "NotSupportedError"
+ ]);
+ }
+
+ return clone(node, this, deep);
+ }
+
+ // https://dom.spec.whatwg.org/#dom-document-adoptnode
+ adoptNode(node) {
+ if (node.nodeType === NODE_TYPE.DOCUMENT_NODE) {
+ throw DOMException.create(this._globalObject, [
+ "Cannot adopt a document node",
+ "NotSupportedError"
+ ]);
+ } else if (ShadowRoot.isImpl(node)) {
+ throw DOMException.create(this._globalObject, [
+ "Cannot adopt a shadow root",
+ "HierarchyRequestError"
+ ]);
+ }
+
+ this._adoptNode(node);
+
+ return node;
+ }
+
+ // https://dom.spec.whatwg.org/#concept-node-adopt
+ _adoptNode(node) {
+ const newDocument = this;
+ const oldDocument = node._ownerDocument;
+
+ const parent = domSymbolTree.parent(node);
+ if (parent) {
+ parent._remove(node);
+ }
+
+ if (oldDocument !== newDocument) {
+ for (const inclusiveDescendant of shadowIncludingInclusiveDescendantsIterator(node)) {
+ inclusiveDescendant._ownerDocument = newDocument;
+ }
+
+ for (const inclusiveDescendant of shadowIncludingInclusiveDescendantsIterator(node)) {
+ if (inclusiveDescendant._ceState === "custom") {
+ enqueueCECallbackReaction(inclusiveDescendant, "adoptedCallback", [
+ idlUtils.wrapperForImpl(oldDocument),
+ idlUtils.wrapperForImpl(newDocument)
+ ]);
+ }
+ }
+
+ for (const inclusiveDescendant of shadowIncludingInclusiveDescendantsIterator(node)) {
+ if (inclusiveDescendant._adoptingSteps) {
+ inclusiveDescendant._adoptingSteps(oldDocument);
+ }
+ }
+ }
+ }
+
+ get cookie() {
+ return this._cookieJar.getCookieStringSync(this.URL, { http: false });
+ }
+ set cookie(cookieStr) {
+ cookieStr = String(cookieStr);
+ this._cookieJar.setCookieSync(cookieStr, this.URL, {
+ http: false,
+ ignoreError: true
+ });
+ }
+
+ // The clear(), captureEvents(), and releaseEvents() methods must do nothing
+ clear() {}
+
+ captureEvents() {}
+
+ releaseEvents() {}
+
+ get styleSheets() {
+ if (!this._styleSheets) {
+ this._styleSheets = StyleSheetList.createImpl(this._globalObject);
+ }
+
+ // TODO: each style and link element should register its sheet on creation
+ // and remove it on removal.
+ return this._styleSheets;
+ }
+
+ get hidden() {
+ if (this._defaultView && this._defaultView._pretendToBeVisual) {
+ return false;
+ }
+
+ return true;
+ }
+
+ get visibilityState() {
+ if (this._defaultView && this._defaultView._pretendToBeVisual) {
+ return "visible";
+ }
+
+ return "prerender";
+ }
+
+ // https://w3c.github.io/selection-api/#extensions-to-document-interface
+ getSelection() {
+ return this._defaultView ? this._defaultView._selection : null;
+ }
+
+ // Needed to ensure that the resulting document has the correct prototype chain:
+ // https://dom.spec.whatwg.org/#concept-node-clone says "that implements the same interfaces as node".
+ _cloneDocument() {
+ const copy = documents.createImpl(
+ this._globalObject,
+ {
+ contentType: this.contentType,
+ encoding: this._encoding,
+ parsingMode: this._parsingMode
+ }
+ );
+
+ copy._URL = this._URL;
+ copy._origin = this._origin;
+ return copy;
+ }
+}
+
+eventAccessors.createEventAccessor(DocumentImpl.prototype, "readystatechange");
+mixin(DocumentImpl.prototype, DocumentOrShadowRootImpl.prototype);
+mixin(DocumentImpl.prototype, GlobalEventHandlersImpl.prototype);
+mixin(DocumentImpl.prototype, NonElementParentNodeImpl.prototype);
+mixin(DocumentImpl.prototype, ParentNodeImpl.prototype);
+
+DocumentImpl.prototype.getElementsByTagName = memoizeQuery(function (qualifiedName) {
+ return listOfElementsWithQualifiedName(qualifiedName, this);
+});
+
+DocumentImpl.prototype.getElementsByTagNameNS = memoizeQuery(function (namespace, localName) {
+ return listOfElementsWithNamespaceAndLocalName(namespace, localName, this);
+});
+
+DocumentImpl.prototype.getElementsByClassName = memoizeQuery(function getElementsByClassName(classNames) {
+ return listOfElementsWithClassNames(classNames, this);
+});
+
+module.exports = {
+ implementation: DocumentImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/DocumentFragment-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/DocumentFragment-impl.js
new file mode 100644
index 0000000..a2a3870
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/DocumentFragment-impl.js
@@ -0,0 +1,44 @@
+"use strict";
+const { mixin } = require("../../utils");
+const { domSymbolTree } = require("../helpers/internal-constants");
+const NODE_TYPE = require("../node-type");
+const NodeImpl = require("./Node-impl").implementation;
+const NonElementParentNodeImpl = require("./NonElementParentNode-impl").implementation;
+const ParentNodeImpl = require("./ParentNode-impl").implementation;
+const idlUtils = require("../generated/utils");
+
+class DocumentFragmentImpl extends NodeImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, {
+ ownerDocument: idlUtils.implForWrapper(globalObject._document),
+ ...privateData
+ });
+
+ const { host } = privateData;
+ this._host = host;
+
+ this.nodeType = NODE_TYPE.DOCUMENT_FRAGMENT_NODE;
+ }
+
+ // This is implemented separately for Document (which has a _ids cache) and DocumentFragment (which does not).
+ getElementById(id) {
+ if (id === "") {
+ return null;
+ }
+
+ for (const descendant of domSymbolTree.treeIterator(this)) {
+ if (descendant.nodeType === NODE_TYPE.ELEMENT_NODE && descendant.getAttributeNS(null, "id") === id) {
+ return descendant;
+ }
+ }
+
+ return null;
+ }
+}
+
+mixin(DocumentFragmentImpl.prototype, NonElementParentNodeImpl.prototype);
+mixin(DocumentFragmentImpl.prototype, ParentNodeImpl.prototype);
+
+module.exports = {
+ implementation: DocumentFragmentImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/DocumentOrShadowRoot-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/DocumentOrShadowRoot-impl.js
new file mode 100644
index 0000000..4f85495
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/DocumentOrShadowRoot-impl.js
@@ -0,0 +1,28 @@
+"use strict";
+const NODE_TYPE = require("../node-type");
+const { nodeRoot } = require("../helpers/node");
+const { retarget } = require("../helpers/shadow-dom");
+
+class DocumentOrShadowRootImpl {
+ get activeElement() {
+ let candidate = this._ownerDocument._lastFocusedElement || this._ownerDocument.body;
+ if (!candidate) {
+ return null;
+ }
+ candidate = retarget(candidate, this);
+ if (nodeRoot(candidate) !== this) {
+ return null;
+ }
+ if (candidate.nodeType !== NODE_TYPE.DOCUMENT_NODE) {
+ return candidate;
+ }
+ if (candidate.body !== null) {
+ return candidate.body;
+ }
+ return candidate.documentElement;
+ }
+}
+
+module.exports = {
+ implementation: DocumentOrShadowRootImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/DocumentType-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/DocumentType-impl.js
new file mode 100644
index 0000000..77767be
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/DocumentType-impl.js
@@ -0,0 +1,24 @@
+"use strict";
+const { mixin } = require("../../utils");
+const NodeImpl = require("./Node-impl").implementation;
+const ChildNodeImpl = require("./ChildNode-impl").implementation;
+
+const NODE_TYPE = require("../node-type");
+
+class DocumentTypeImpl extends NodeImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+
+ this.nodeType = NODE_TYPE.DOCUMENT_TYPE_NODE;
+
+ this.name = privateData.name;
+ this.publicId = privateData.publicId;
+ this.systemId = privateData.systemId;
+ }
+}
+
+mixin(DocumentTypeImpl.prototype, ChildNodeImpl.prototype);
+
+module.exports = {
+ implementation: DocumentTypeImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/Element-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/Element-impl.js
new file mode 100644
index 0000000..7751817
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/Element-impl.js
@@ -0,0 +1,578 @@
+"use strict";
+const { addNwsapi } = require("../helpers/selectors");
+const { HTML_NS } = require("../helpers/namespaces");
+const { mixin, memoizeQuery } = require("../../utils");
+const idlUtils = require("../generated/utils");
+const NodeImpl = require("./Node-impl").implementation;
+const ParentNodeImpl = require("./ParentNode-impl").implementation;
+const ChildNodeImpl = require("./ChildNode-impl").implementation;
+const attributes = require("../attributes");
+const namedPropertiesWindow = require("../named-properties-window");
+const NODE_TYPE = require("../node-type");
+const { parseFragment } = require("../../browser/parser");
+const InnerHTMLImpl = require("../domparsing/InnerHTML-impl").implementation;
+const { fragmentSerialization } = require("../domparsing/serialization");
+const { domSymbolTree } = require("../helpers/internal-constants");
+const DOMException = require("domexception/webidl2js-wrapper");
+const DOMTokenList = require("../generated/DOMTokenList");
+const NamedNodeMap = require("../generated/NamedNodeMap");
+const validateNames = require("../helpers/validate-names");
+const { asciiLowercase, asciiUppercase } = require("../helpers/strings");
+const { listOfElementsWithQualifiedName, listOfElementsWithNamespaceAndLocalName,
+ listOfElementsWithClassNames } = require("../node");
+const SlotableMixinImpl = require("./Slotable-impl").implementation;
+const NonDocumentTypeChildNode = require("./NonDocumentTypeChildNode-impl").implementation;
+const ShadowRoot = require("../generated/ShadowRoot");
+const Text = require("../generated/Text");
+const { isValidHostElementName } = require("../helpers/shadow-dom");
+const { isValidCustomElementName, lookupCEDefinition } = require("../helpers/custom-elements");
+
+function attachId(id, elm, doc) {
+ if (id && elm && doc) {
+ if (!doc._ids[id]) {
+ doc._ids[id] = [];
+ }
+ doc._ids[id].push(elm);
+ }
+}
+
+function detachId(id, elm, doc) {
+ if (id && elm && doc) {
+ if (doc._ids && doc._ids[id]) {
+ const elms = doc._ids[id];
+ for (let i = 0; i < elms.length; i++) {
+ if (elms[i] === elm) {
+ elms.splice(i, 1);
+ --i;
+ }
+ }
+ if (elms.length === 0) {
+ delete doc._ids[id];
+ }
+ }
+ }
+}
+
+class ElementImpl extends NodeImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+
+ this._initSlotableMixin();
+
+ this._namespaceURI = privateData.namespace;
+ this._prefix = privateData.prefix;
+ this._localName = privateData.localName;
+ this._ceState = privateData.ceState;
+ this._ceDefinition = privateData.ceDefinition;
+ this._isValue = privateData.isValue;
+
+ this._shadowRoot = null;
+ this._ceReactionQueue = [];
+
+ this.nodeType = NODE_TYPE.ELEMENT_NODE;
+ this.scrollTop = 0;
+ this.scrollLeft = 0;
+
+ this._attributeList = [];
+ // Used for caching.
+ this._attributesByNameMap = new Map();
+ this._attributes = NamedNodeMap.createImpl(this._globalObject, [], {
+ element: this
+ });
+
+ this._cachedTagName = null;
+ }
+
+ _attach() {
+ namedPropertiesWindow.nodeAttachedToDocument(this);
+
+ const id = this.getAttributeNS(null, "id");
+ if (id) {
+ attachId(id, this, this._ownerDocument);
+ }
+
+ super._attach();
+ }
+
+ _detach() {
+ super._detach();
+
+ namedPropertiesWindow.nodeDetachedFromDocument(this);
+
+ const id = this.getAttributeNS(null, "id");
+ if (id) {
+ detachId(id, this, this._ownerDocument);
+ }
+ }
+
+ _attrModified(name, value, oldValue) {
+ this._modified();
+ namedPropertiesWindow.elementAttributeModified(this, name, value, oldValue);
+
+ if (name === "id" && this._attached) {
+ const doc = this._ownerDocument;
+ detachId(oldValue, this, doc);
+ attachId(value, this, doc);
+ }
+
+ // update classList
+ if (name === "class" && this._classList !== undefined) {
+ this._classList.attrModified();
+ }
+
+ this._attrModifiedSlotableMixin(name, value, oldValue);
+ }
+
+ get namespaceURI() {
+ return this._namespaceURI;
+ }
+ get prefix() {
+ return this._prefix;
+ }
+ get localName() {
+ return this._localName;
+ }
+ get _qualifiedName() {
+ return this._prefix !== null ? this._prefix + ":" + this._localName : this._localName;
+ }
+ get tagName() {
+ // This getter can be a hotpath in getComputedStyle.
+ // All these are invariants during the instance lifetime so we can safely cache the computed tagName.
+ // We could create it during construction but since we already identified this as potentially slow we do it lazily.
+ if (this._cachedTagName === null) {
+ if (this.namespaceURI === HTML_NS && this._ownerDocument._parsingMode === "html") {
+ this._cachedTagName = asciiUppercase(this._qualifiedName);
+ } else {
+ this._cachedTagName = this._qualifiedName;
+ }
+ }
+ return this._cachedTagName;
+ }
+
+ get attributes() {
+ return this._attributes;
+ }
+
+ // https://w3c.github.io/DOM-Parsing/#dom-element-outerhtml
+ get outerHTML() {
+ // TODO: maybe parse5 can give us a hook where it serializes the node itself too:
+ // https://github.com/inikulin/parse5/issues/230
+ // Alternatively, if we can create a virtual node in domSymbolTree, that'd also work.
+ // It's currently prevented by the fact that a node can't be duplicated in the same tree.
+ // Then we could get rid of all the code for childNodesForSerializing.
+ return fragmentSerialization({ childNodesForSerializing: [this], _ownerDocument: this._ownerDocument }, {
+ requireWellFormed: true,
+ globalObject: this._globalObject
+ });
+ }
+ set outerHTML(markup) {
+ let parent = domSymbolTree.parent(this);
+ const document = this._ownerDocument;
+
+ if (!parent) {
+ return;
+ }
+
+ if (parent.nodeType === NODE_TYPE.DOCUMENT_NODE) {
+ throw DOMException.create(this._globalObject, [
+ "Modifications are not allowed for this document",
+ "NoModificationAllowedError"
+ ]);
+ }
+
+ if (parent.nodeType === NODE_TYPE.DOCUMENT_FRAGMENT_NODE) {
+ parent = document.createElementNS(HTML_NS, "body");
+ }
+
+ const fragment = parseFragment(markup, parent);
+
+ const contextObjectParent = domSymbolTree.parent(this);
+ contextObjectParent._replace(fragment, this);
+ }
+
+ get classList() {
+ if (this._classList === undefined) {
+ this._classList = DOMTokenList.createImpl(this._globalObject, [], {
+ element: this,
+ attributeLocalName: "class"
+ });
+ }
+ return this._classList;
+ }
+
+ hasAttributes() {
+ return attributes.hasAttributes(this);
+ }
+
+ getAttributeNames() {
+ return attributes.attributeNames(this);
+ }
+
+ getAttribute(name) {
+ const attr = attributes.getAttributeByName(this, name);
+ if (!attr) {
+ return null;
+ }
+ return attr._value;
+ }
+
+ getAttributeNS(namespace, localName) {
+ const attr = attributes.getAttributeByNameNS(this, namespace, localName);
+ if (!attr) {
+ return null;
+ }
+ return attr._value;
+ }
+
+ setAttribute(name, value) {
+ validateNames.name(this._globalObject, name);
+
+ if (this._namespaceURI === HTML_NS && this._ownerDocument._parsingMode === "html") {
+ name = asciiLowercase(name);
+ }
+
+ const attribute = attributes.getAttributeByName(this, name);
+
+ if (attribute === null) {
+ const newAttr = this._ownerDocument._createAttribute({
+ localName: name,
+ value
+ });
+ attributes.appendAttribute(this, newAttr);
+ return;
+ }
+
+ attributes.changeAttribute(this, attribute, value);
+ }
+
+ setAttributeNS(namespace, name, value) {
+ const extracted = validateNames.validateAndExtract(this._globalObject, namespace, name);
+
+ // Because of widespread use of this method internally, e.g. to manually implement attribute/content reflection, we
+ // centralize the conversion to a string here, so that all call sites don't have to do it.
+ value = `${value}`;
+
+ attributes.setAttributeValue(this, extracted.localName, value, extracted.prefix, extracted.namespace);
+ }
+
+ removeAttribute(name) {
+ attributes.removeAttributeByName(this, name);
+ }
+
+ removeAttributeNS(namespace, localName) {
+ attributes.removeAttributeByNameNS(this, namespace, localName);
+ }
+
+ toggleAttribute(qualifiedName, force) {
+ validateNames.name(this._globalObject, qualifiedName);
+
+ if (this._namespaceURI === HTML_NS && this._ownerDocument._parsingMode === "html") {
+ qualifiedName = asciiLowercase(qualifiedName);
+ }
+
+ const attribute = attributes.getAttributeByName(this, qualifiedName);
+
+ if (attribute === null) {
+ if (force === undefined || force === true) {
+ const newAttr = this._ownerDocument._createAttribute({
+ localName: qualifiedName,
+ value: ""
+ });
+ attributes.appendAttribute(this, newAttr);
+ return true;
+ }
+ return false;
+ }
+
+ if (force === undefined || force === false) {
+ attributes.removeAttributeByName(this, qualifiedName);
+ return false;
+ }
+
+ return true;
+ }
+
+ hasAttribute(name) {
+ if (this._namespaceURI === HTML_NS && this._ownerDocument._parsingMode === "html") {
+ name = asciiLowercase(name);
+ }
+
+ return attributes.hasAttributeByName(this, name);
+ }
+
+ hasAttributeNS(namespace, localName) {
+ if (namespace === "") {
+ namespace = null;
+ }
+
+ return attributes.hasAttributeByNameNS(this, namespace, localName);
+ }
+
+ getAttributeNode(name) {
+ return attributes.getAttributeByName(this, name);
+ }
+
+ getAttributeNodeNS(namespace, localName) {
+ return attributes.getAttributeByNameNS(this, namespace, localName);
+ }
+
+ setAttributeNode(attr) {
+ // eslint-disable-next-line no-restricted-properties
+ return attributes.setAttribute(this, attr);
+ }
+
+ setAttributeNodeNS(attr) {
+ // eslint-disable-next-line no-restricted-properties
+ return attributes.setAttribute(this, attr);
+ }
+
+ removeAttributeNode(attr) {
+ // eslint-disable-next-line no-restricted-properties
+ if (!attributes.hasAttribute(this, attr)) {
+ throw DOMException.create(this._globalObject, [
+ "Tried to remove an attribute that was not present",
+ "NotFoundError"
+ ]);
+ }
+
+ // eslint-disable-next-line no-restricted-properties
+ attributes.removeAttribute(this, attr);
+
+ return attr;
+ }
+
+ getBoundingClientRect() {
+ return {
+ x: 0,
+ y: 0,
+ bottom: 0,
+ height: 0,
+ left: 0,
+ right: 0,
+ top: 0,
+ width: 0
+ };
+ }
+
+ getClientRects() {
+ return [];
+ }
+
+ get scrollWidth() {
+ return 0;
+ }
+
+ get scrollHeight() {
+ return 0;
+ }
+
+ get clientTop() {
+ return 0;
+ }
+
+ get clientLeft() {
+ return 0;
+ }
+
+ get clientWidth() {
+ return 0;
+ }
+
+ get clientHeight() {
+ return 0;
+ }
+
+ // https://dom.spec.whatwg.org/#dom-element-attachshadow
+ attachShadow(init) {
+ const { _ownerDocument, _namespaceURI, _localName, _isValue } = this;
+
+ if (this.namespaceURI !== HTML_NS) {
+ throw DOMException.create(this._globalObject, [
+ "This element does not support attachShadow. This element is not part of the HTML namespace.",
+ "NotSupportedError"
+ ]);
+ }
+
+ if (!isValidHostElementName(_localName) && !isValidCustomElementName(_localName)) {
+ const message = "This element does not support attachShadow. This element is not a custom element nor " +
+ "a standard element supporting a shadow root.";
+ throw DOMException.create(this._globalObject, [message, "NotSupportedError"]);
+ }
+
+ if (isValidCustomElementName(_localName) || _isValue) {
+ const definition = lookupCEDefinition(_ownerDocument, _namespaceURI, _localName, _isValue);
+
+ if (definition && definition.disableShadow) {
+ throw DOMException.create(this._globalObject, [
+ "Shadow root cannot be create on a custom element with disabled shadow",
+ "NotSupportedError"
+ ]);
+ }
+ }
+
+ if (this._shadowRoot !== null) {
+ throw DOMException.create(this._globalObject, [
+ "Shadow root cannot be created on a host which already hosts a shadow tree.",
+ "NotSupportedError"
+ ]);
+ }
+
+ const shadow = ShadowRoot.createImpl(this._globalObject, [], {
+ ownerDocument: this.ownerDocument,
+ mode: init.mode,
+ host: this
+ });
+
+ this._shadowRoot = shadow;
+
+ return shadow;
+ }
+
+ // https://dom.spec.whatwg.org/#dom-element-shadowroot
+ get shadowRoot() {
+ const shadow = this._shadowRoot;
+
+ if (shadow === null || shadow.mode === "closed") {
+ return null;
+ }
+
+ return shadow;
+ }
+
+ // https://dom.spec.whatwg.org/#insert-adjacent
+ _insertAdjacent(element, where, node) {
+ where = asciiLowercase(where);
+
+ if (where === "beforebegin") {
+ if (element.parentNode === null) {
+ return null;
+ }
+ return element.parentNode._preInsert(node, element);
+ }
+ if (where === "afterbegin") {
+ return element._preInsert(node, element.firstChild);
+ }
+ if (where === "beforeend") {
+ return element._preInsert(node, null);
+ }
+ if (where === "afterend") {
+ if (element.parentNode === null) {
+ return null;
+ }
+ return element.parentNode._preInsert(node, element.nextSibling);
+ }
+
+ throw DOMException.create(this._globalObject, [
+ 'Must provide one of "beforebegin", "afterbegin", "beforeend", or "afterend".',
+ "SyntaxError"
+ ]);
+ }
+
+ insertAdjacentElement(where, element) {
+ return this._insertAdjacent(this, where, element);
+ }
+
+ insertAdjacentText(where, data) {
+ const text = Text.createImpl(this._globalObject, [], { data, ownerDocument: this._ownerDocument });
+
+ this._insertAdjacent(this, where, text);
+ }
+
+ // https://w3c.github.io/DOM-Parsing/#dom-element-insertadjacenthtml
+ insertAdjacentHTML(position, text) {
+ position = asciiLowercase(position);
+
+ let context;
+ switch (position) {
+ case "beforebegin":
+ case "afterend": {
+ context = this.parentNode;
+ if (context === null || context.nodeType === NODE_TYPE.DOCUMENT_NODE) {
+ throw DOMException.create(this._globalObject, [
+ "Cannot insert HTML adjacent to parent-less nodes or children of document nodes.",
+ "NoModificationAllowedError"
+ ]);
+ }
+ break;
+ }
+ case "afterbegin":
+ case "beforeend": {
+ context = this;
+ break;
+ }
+ default: {
+ throw DOMException.create(this._globalObject, [
+ 'Must provide one of "beforebegin", "afterbegin", "beforeend", or "afterend".',
+ "SyntaxError"
+ ]);
+ }
+ }
+
+ if (
+ context.nodeType !== NODE_TYPE.ELEMENT_NODE ||
+ (
+ context._ownerDocument._parsingMode === "html" &&
+ context._localName === "html" &&
+ context._namespaceURI === HTML_NS
+ )
+ ) {
+ context = context._ownerDocument.createElement("body");
+ }
+
+ const fragment = parseFragment(text, context);
+
+ switch (position) {
+ case "beforebegin": {
+ this.parentNode._insert(fragment, this);
+ break;
+ }
+ case "afterbegin": {
+ this._insert(fragment, this.firstChild);
+ break;
+ }
+ case "beforeend": {
+ this._append(fragment);
+ break;
+ }
+ case "afterend": {
+ this.parentNode._insert(fragment, this.nextSibling);
+ break;
+ }
+ }
+ }
+
+ closest(selectors) {
+ const matcher = addNwsapi(this);
+ return matcher.closest(selectors, idlUtils.wrapperForImpl(this));
+ }
+}
+
+mixin(ElementImpl.prototype, NonDocumentTypeChildNode.prototype);
+mixin(ElementImpl.prototype, ParentNodeImpl.prototype);
+mixin(ElementImpl.prototype, ChildNodeImpl.prototype);
+mixin(ElementImpl.prototype, SlotableMixinImpl.prototype);
+mixin(ElementImpl.prototype, InnerHTMLImpl.prototype);
+
+ElementImpl.prototype.getElementsByTagName = memoizeQuery(function (qualifiedName) {
+ return listOfElementsWithQualifiedName(qualifiedName, this);
+});
+
+ElementImpl.prototype.getElementsByTagNameNS = memoizeQuery(function (namespace, localName) {
+ return listOfElementsWithNamespaceAndLocalName(namespace, localName, this);
+});
+
+ElementImpl.prototype.getElementsByClassName = memoizeQuery(function (classNames) {
+ return listOfElementsWithClassNames(classNames, this);
+});
+
+ElementImpl.prototype.matches = function (selectors) {
+ const matcher = addNwsapi(this);
+
+ return matcher.match(selectors, idlUtils.wrapperForImpl(this));
+};
+
+ElementImpl.prototype.webkitMatchesSelector = ElementImpl.prototype.matches;
+
+module.exports = {
+ implementation: ElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/ElementCSSInlineStyle-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/ElementCSSInlineStyle-impl.js
new file mode 100644
index 0000000..66d685d
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/ElementCSSInlineStyle-impl.js
@@ -0,0 +1,25 @@
+"use strict";
+const cssstyle = require("cssstyle");
+
+class ElementCSSInlineStyle {
+ _initElementCSSInlineStyle() {
+ this._settingCssText = false;
+ this._style = new cssstyle.CSSStyleDeclaration(newCssText => {
+ if (!this._settingCssText) {
+ this._settingCssText = true;
+ this.setAttributeNS(null, "style", newCssText);
+ this._settingCssText = false;
+ }
+ });
+ }
+ get style() {
+ return this._style;
+ }
+ set style(value) {
+ this._style.cssText = value;
+ }
+}
+
+module.exports = {
+ implementation: ElementCSSInlineStyle
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/ElementContentEditable-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/ElementContentEditable-impl.js
new file mode 100644
index 0000000..8523c9c
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/ElementContentEditable-impl.js
@@ -0,0 +1,7 @@
+"use strict";
+
+class ElementContentEditableImpl { }
+
+module.exports = {
+ implementation: ElementContentEditableImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/GlobalEventHandlers-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/GlobalEventHandlers-impl.js
new file mode 100644
index 0000000..eebbed8
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/GlobalEventHandlers-impl.js
@@ -0,0 +1,95 @@
+"use strict";
+
+const { appendHandler, createEventAccessor } = require("../helpers/create-event-accessor");
+
+const events = new Set([
+ "abort", "autocomplete",
+ "autocompleteerror", "blur",
+ "cancel", "canplay", "canplaythrough",
+ "change", "click",
+ "close", "contextmenu",
+ "cuechange", "dblclick",
+ "drag", "dragend",
+ "dragenter",
+ "dragleave", "dragover",
+ "dragstart", "drop",
+ "durationchange", "emptied",
+ "ended", "error", "focus",
+ "input", "invalid",
+ "keydown", "keypress",
+ "keyup", "load", "loadeddata",
+ "loadedmetadata", "loadstart",
+ "mousedown", "mouseenter",
+ "mouseleave", "mousemove",
+ "mouseout", "mouseover",
+ "mouseup", "wheel",
+ "pause", "play",
+ "playing", "progress",
+ "ratechange", "reset",
+ "resize", "scroll",
+ "securitypolicyviolation",
+ "seeked", "seeking",
+ "select", "sort", "stalled",
+ "submit", "suspend",
+ "timeupdate", "toggle",
+ "volumechange", "waiting"
+]);
+
+class GlobalEventHandlersImpl {
+ _initGlobalEvents() {
+ this._registeredHandlers = new Set();
+ this._eventHandlers = Object.create(null);
+ }
+
+ _getEventHandlerTarget() {
+ return this;
+ }
+
+ _getEventHandlerFor(event) {
+ const target = this._getEventHandlerTarget(event);
+ if (!target) {
+ return null;
+ }
+
+ return target._eventHandlers[event];
+ }
+
+ _setEventHandlerFor(event, handler) {
+ const target = this._getEventHandlerTarget(event);
+ if (!target) {
+ return;
+ }
+
+ if (!target._registeredHandlers.has(event) && handler !== null) {
+ target._registeredHandlers.add(event);
+ appendHandler(target, event);
+ }
+ target._eventHandlers[event] = handler;
+ }
+
+ _globalEventChanged(event) {
+ const propName = "on" + event;
+ if (!(propName in this)) {
+ return;
+ }
+
+ // Only translate attribute changes into properties when runScripts: "dangerously" is set.
+ // Documents without a browsing context (i.e. without a _defaultView) never run scripts.
+ const runScripts = "_runScripts" in this ? this._runScripts : (this._ownerDocument._defaultView || {})._runScripts;
+ if (runScripts !== "dangerously") {
+ return;
+ }
+
+ const val = this.getAttributeNS(null, propName);
+ const handler = val === null ? null : { body: val };
+ this._setEventHandlerFor(event, handler);
+ }
+}
+
+for (const event of events) {
+ createEventAccessor(GlobalEventHandlersImpl.prototype, event);
+}
+
+module.exports = {
+ implementation: GlobalEventHandlersImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLAnchorElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLAnchorElement-impl.js
new file mode 100644
index 0000000..73b6943
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLAnchorElement-impl.js
@@ -0,0 +1,50 @@
+"use strict";
+const { mixin } = require("../../utils");
+const DOMTokenList = require("../generated/DOMTokenList");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const HTMLHyperlinkElementUtilsImpl = require("./HTMLHyperlinkElementUtils-impl").implementation;
+
+class HTMLAnchorElementImpl extends HTMLElementImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+
+ this._htmlHyperlinkElementUtilsSetup();
+
+ this._hasActivationBehavior = true;
+ }
+
+ _activationBehavior() {
+ this._followAHyperlink();
+ }
+
+ get relList() {
+ if (this._relList === undefined) {
+ this._relList = DOMTokenList.createImpl(this._globalObject, [], {
+ element: this,
+ attributeLocalName: "rel"
+ });
+ }
+ return this._relList;
+ }
+
+ get text() {
+ return this.textContent;
+ }
+ set text(v) {
+ this.textContent = v;
+ }
+
+ _attrModified(name, value, oldValue) {
+ super._attrModified(name, value, oldValue);
+
+ if (name === "rel" && this._relList !== undefined) {
+ this._relList.attrModified();
+ }
+ }
+}
+
+mixin(HTMLAnchorElementImpl.prototype, HTMLHyperlinkElementUtilsImpl.prototype);
+
+module.exports = {
+ implementation: HTMLAnchorElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLAreaElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLAreaElement-impl.js
new file mode 100644
index 0000000..58d5fe1
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLAreaElement-impl.js
@@ -0,0 +1,43 @@
+"use strict";
+const { mixin } = require("../../utils");
+const DOMTokenList = require("../generated/DOMTokenList");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const HTMLHyperlinkElementUtilsImpl = require("./HTMLHyperlinkElementUtils-impl").implementation;
+
+class HTMLAreaElementImpl extends HTMLElementImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+
+ this._htmlHyperlinkElementUtilsSetup();
+
+ this._hasActivationBehavior = true;
+ }
+
+ _activationBehavior() {
+ this._followAHyperlink();
+ }
+
+ get relList() {
+ if (this._relList === undefined) {
+ this._relList = DOMTokenList.createImpl(this._globalObject, [], {
+ element: this,
+ attributeLocalName: "rel"
+ });
+ }
+ return this._relList;
+ }
+
+ _attrModified(name, value, oldValue) {
+ super._attrModified(name, value, oldValue);
+
+ if (name === "rel" && this._relList !== undefined) {
+ this._relList.attrModified();
+ }
+ }
+}
+
+mixin(HTMLAreaElementImpl.prototype, HTMLHyperlinkElementUtilsImpl.prototype);
+
+module.exports = {
+ implementation: HTMLAreaElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLAudioElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLAudioElement-impl.js
new file mode 100644
index 0000000..ad65ff5
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLAudioElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLMediaElementImpl = require("./HTMLMediaElement-impl").implementation;
+
+class HTMLAudioElementImpl extends HTMLMediaElementImpl { }
+
+module.exports = {
+ implementation: HTMLAudioElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLBRElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLBRElement-impl.js
new file mode 100644
index 0000000..c921613
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLBRElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLBRElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLBRElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLBaseElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLBaseElement-impl.js
new file mode 100644
index 0000000..ece7d83
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLBaseElement-impl.js
@@ -0,0 +1,27 @@
+"use strict";
+const whatwgURL = require("whatwg-url");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const { fallbackBaseURL } = require("../helpers/document-base-url");
+
+class HTMLBaseElementImpl extends HTMLElementImpl {
+ get href() {
+ const document = this._ownerDocument;
+
+ const url = this.hasAttributeNS(null, "href") ? this.getAttributeNS(null, "href") : "";
+ const parsed = whatwgURL.parseURL(url, { baseURL: fallbackBaseURL(document) });
+
+ if (parsed === null) {
+ return url;
+ }
+
+ return whatwgURL.serializeURL(parsed);
+ }
+
+ set href(value) {
+ this.setAttributeNS(null, "href", value);
+ }
+}
+
+module.exports = {
+ implementation: HTMLBaseElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLBodyElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLBodyElement-impl.js
new file mode 100644
index 0000000..1ebd0ea
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLBodyElement-impl.js
@@ -0,0 +1,17 @@
+"use strict";
+const { mixin } = require("../../utils");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const WindowEventHandlersImpl = require("./WindowEventHandlers-impl").implementation;
+
+class HTMLBodyElementImpl extends HTMLElementImpl {
+ constructor(...args) {
+ super(...args);
+ this._proxyWindowEventsToWindow();
+ }
+}
+
+mixin(HTMLBodyElementImpl.prototype, WindowEventHandlersImpl.prototype);
+
+module.exports = {
+ implementation: HTMLBodyElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLButtonElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLButtonElement-impl.js
new file mode 100644
index 0000000..783a608
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLButtonElement-impl.js
@@ -0,0 +1,79 @@
+"use strict";
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const DefaultConstraintValidationImpl =
+ require("../constraint-validation/DefaultConstraintValidation-impl").implementation;
+const { mixin } = require("../../utils");
+const { isDisabled, formOwner, getLabelsForLabelable } = require("../helpers/form-controls");
+const { asciiLowercase } = require("../helpers/strings");
+
+class HTMLButtonElementImpl extends HTMLElementImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+
+ this._customValidityErrorMessage = "";
+ this._labels = null;
+
+ this._hasActivationBehavior = true;
+ }
+
+ _activationBehavior() {
+ const { form } = this;
+ if (form && !isDisabled(this)) {
+ if (this.type === "submit") {
+ form._doSubmit();
+ }
+ if (this.type === "reset") {
+ form._doReset();
+ }
+ }
+ }
+
+ _getValue() {
+ const valueAttr = this.getAttributeNS(null, "value");
+ return valueAttr === null ? "" : valueAttr;
+ }
+
+ get labels() {
+ return getLabelsForLabelable(this);
+ }
+
+ get form() {
+ return formOwner(this);
+ }
+
+ get type() {
+ const typeAttr = asciiLowercase(this.getAttributeNS(null, "type") || "");
+ switch (typeAttr) {
+ case "submit":
+ case "reset":
+ case "button":
+ return typeAttr;
+ default:
+ return "submit";
+ }
+ }
+
+ set type(v) {
+ v = asciiLowercase(String(v));
+ switch (v) {
+ case "submit":
+ case "reset":
+ case "button":
+ this.setAttributeNS(null, "type", v);
+ break;
+ default:
+ this.setAttributeNS(null, "type", "submit");
+ break;
+ }
+ }
+
+ _barredFromConstraintValidationSpecialization() {
+ return this.type === "reset" || this.type === "button";
+ }
+}
+
+mixin(HTMLButtonElementImpl.prototype, DefaultConstraintValidationImpl.prototype);
+
+module.exports = {
+ implementation: HTMLButtonElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLCanvasElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLCanvasElement-impl.js
new file mode 100644
index 0000000..5a962e7
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLCanvasElement-impl.js
@@ -0,0 +1,130 @@
+"use strict";
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const notImplemented = require("../../browser/not-implemented");
+const idlUtils = require("../generated/utils");
+const { Canvas } = require("../../utils");
+
+class HTMLCanvasElementImpl extends HTMLElementImpl {
+ _attrModified(name, value, oldValue) {
+ if (this._canvas && (name === "width" || name === "height")) {
+ this._canvas[name] = parseInt(value);
+ }
+
+ super._attrModified(name, value, oldValue);
+ }
+
+ _getCanvas() {
+ if (Canvas && !this._canvas) {
+ this._canvas = Canvas.createCanvas(this.width, this.height);
+ }
+ return this._canvas;
+ }
+
+ getContext(contextId) {
+ const canvas = this._getCanvas();
+ if (canvas) {
+ if (!this._context) {
+ this._context = canvas.getContext(contextId) || null;
+ if (this._context) {
+ // Override the native canvas reference with our wrapper. This is the
+ // reason why we need to locally cache _context, since each call to
+ // canvas.getContext(contextId) would replace this reference again.
+ // Perhaps in the longer term, a better solution would be to create a
+ // full wrapper for the Context object as well.
+ this._context.canvas = idlUtils.wrapperForImpl(this);
+ wrapNodeCanvasMethod(this._context, "createPattern");
+ wrapNodeCanvasMethod(this._context, "drawImage");
+ }
+ }
+ return this._context;
+ }
+
+ notImplemented(
+ "HTMLCanvasElement.prototype.getContext (without installing the canvas npm package)",
+ this._ownerDocument._defaultView
+ );
+ return null;
+ }
+
+ toDataURL(...args) {
+ const canvas = this._getCanvas();
+ if (canvas) {
+ return canvas.toDataURL(...args);
+ }
+
+ notImplemented(
+ "HTMLCanvasElement.prototype.toDataURL (without installing the canvas npm package)",
+ this._ownerDocument._defaultView
+ );
+ return null;
+ }
+
+ toBlob(callback, type, qualityArgument) {
+ const window = this._ownerDocument._defaultView;
+ const canvas = this._getCanvas();
+ if (canvas) {
+ const options = {};
+ switch (type) {
+ case "image/jpg":
+ case "image/jpeg":
+ type = "image/jpeg";
+ options.quality = qualityArgument;
+ break;
+ default:
+ type = "image/png";
+ }
+ canvas.toBuffer((err, buff) => {
+ if (err) {
+ throw err;
+ }
+ callback(new window.Blob([buff], { type }));
+ }, type, options);
+ } else {
+ notImplemented(
+ "HTMLCanvasElement.prototype.toBlob (without installing the canvas npm package)",
+ window
+ );
+ }
+ }
+
+ get width() {
+ const parsed = parseInt(this.getAttributeNS(null, "width"));
+ return isNaN(parsed) || parsed < 0 || parsed > 2147483647 ? 300 : parsed;
+ }
+
+ set width(v) {
+ v = v > 2147483647 ? 300 : v;
+ this.setAttributeNS(null, "width", String(v));
+ }
+
+ get height() {
+ const parsed = parseInt(this.getAttributeNS(null, "height"));
+ return isNaN(parsed) || parsed < 0 || parsed > 2147483647 ? 150 : parsed;
+ }
+
+ set height(v) {
+ v = v > 2147483647 ? 150 : v;
+ this.setAttributeNS(null, "height", String(v));
+ }
+}
+
+// We need to wrap the methods that receive an image or canvas object
+// (luckily, always as the first argument), so that these objects can be
+// unwrapped an the expected types passed.
+function wrapNodeCanvasMethod(ctx, name) {
+ const prev = ctx[name];
+ ctx[name] = function (image, ...rest) {
+ const impl = idlUtils.implForWrapper(image);
+ if (impl) {
+ if (impl instanceof HTMLCanvasElementImpl && !impl._canvas) {
+ impl._getCanvas();
+ }
+ image = impl._image || impl._canvas;
+ }
+ return prev.call(ctx, image, ...rest);
+ };
+}
+
+module.exports = {
+ implementation: HTMLCanvasElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLCollection-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLCollection-impl.js
new file mode 100644
index 0000000..980ebd2
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLCollection-impl.js
@@ -0,0 +1,96 @@
+"use strict";
+
+const idlUtils = require("../generated/utils.js");
+const { HTML_NS } = require("../helpers/namespaces");
+
+exports.implementation = class HTMLCollectionImpl {
+ constructor(globalObject, args, privateData) {
+ this._list = [];
+ this._version = -1;
+ this._element = privateData.element;
+ this._query = privateData.query;
+
+ this._globalObject = globalObject;
+
+ this._update();
+ }
+ get length() {
+ this._update();
+ return this._list.length;
+ }
+ item(index) {
+ this._update();
+ return this._list[index] || null;
+ }
+ namedItem(key) {
+ if (key === "") {
+ return null;
+ }
+ this._update();
+ for (const element of this._list) {
+ if (element.getAttributeNS(null, "id") === key) {
+ return element;
+ }
+ if (element._namespaceURI === HTML_NS) {
+ const name = element.getAttributeNS(null, "name");
+ if (name === key) {
+ return element;
+ }
+ }
+ }
+ return null;
+ }
+ _update() {
+ if (this._version < this._element._version) {
+ const snapshot = this._query();
+ for (let i = 0; i < snapshot.length; i++) {
+ this._list[i] = snapshot[i];
+ }
+ this._list.length = snapshot.length;
+ this._version = this._element._version;
+ }
+ }
+ get [idlUtils.supportedPropertyIndices]() {
+ this._update();
+ return this._list.keys();
+ }
+ get [idlUtils.supportedPropertyNames]() {
+ this._update();
+ const result = new Set();
+ for (const element of this._list) {
+ const id = element.getAttributeNS(null, "id");
+ if (id) {
+ result.add(id);
+ }
+ if (element._namespaceURI === HTML_NS) {
+ const name = element.getAttributeNS(null, "name");
+ if (name) {
+ result.add(name);
+ }
+ }
+ }
+ return result;
+ }
+
+ // Inherit some useful functions from Array.
+ [Symbol.iterator]() {
+ this._update();
+ return this._list[Symbol.iterator]();
+ }
+ entries() {
+ this._update();
+ return this._list.entries();
+ }
+ filter(...args) {
+ this._update();
+ return this._list.filter(...args);
+ }
+ map(...args) {
+ this._update();
+ return this._list.map(...args);
+ }
+ indexOf(...args) {
+ this._update();
+ return this._list.indexOf(...args);
+ }
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDListElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDListElement-impl.js
new file mode 100644
index 0000000..22ee9bd
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDListElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLDListElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLDListElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDataElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDataElement-impl.js
new file mode 100644
index 0000000..2d75abc
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDataElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLDataElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLDataElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDataListElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDataListElement-impl.js
new file mode 100644
index 0000000..ccd2c4c
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDataListElement-impl.js
@@ -0,0 +1,20 @@
+"use strict";
+
+const HTMLCollection = require("../generated/HTMLCollection");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+const { descendantsByLocalName } = require("../helpers/traversal");
+
+class HTMLDataListElementImpl extends HTMLElementImpl {
+ // https://html.spec.whatwg.org/multipage/form-elements.html#dom-datalist-options
+ get options() {
+ return HTMLCollection.createImpl(this._globalObject, [], {
+ element: this,
+ query: () => descendantsByLocalName(this, "option")
+ });
+ }
+}
+
+module.exports = {
+ implementation: HTMLDataListElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDetailsElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDetailsElement-impl.js
new file mode 100644
index 0000000..7a934b4
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDetailsElement-impl.js
@@ -0,0 +1,35 @@
+"use strict";
+
+const { fireAnEvent } = require("../helpers/events");
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLDetailsElementImpl extends HTMLElementImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+
+ this._taskQueue = null;
+ }
+
+ _dispatchToggleEvent() {
+ this._taskQueue = null;
+
+ fireAnEvent("toggle", this);
+ }
+
+ _attrModified(name, value, oldValue) {
+ super._attrModified(name, value, oldValue);
+
+ if (name === "open" && this._taskQueue === null) {
+ // Check that the attribute is added or removed, not merely changed
+ if ((value !== oldValue && value !== null && oldValue === null) ||
+ (value === null && oldValue !== null)) {
+ this._taskQueue = setTimeout(this._dispatchToggleEvent.bind(this), 0);
+ }
+ }
+ }
+}
+
+module.exports = {
+ implementation: HTMLDetailsElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDialogElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDialogElement-impl.js
new file mode 100644
index 0000000..d020e3c
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDialogElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLDialogElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLDialogElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDirectoryElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDirectoryElement-impl.js
new file mode 100644
index 0000000..ea05eb3
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDirectoryElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLDirectoryElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLDirectoryElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDivElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDivElement-impl.js
new file mode 100644
index 0000000..b81a714
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDivElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLDivElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLDivElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js
new file mode 100644
index 0000000..ce25b88
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js
@@ -0,0 +1,160 @@
+"use strict";
+const { mixin } = require("../../utils");
+const ElementImpl = require("./Element-impl").implementation;
+const MouseEvent = require("../generated/MouseEvent");
+const ElementCSSInlineStyleImpl = require("./ElementCSSInlineStyle-impl").implementation;
+const GlobalEventHandlersImpl = require("./GlobalEventHandlers-impl").implementation;
+const HTMLOrSVGElementImpl = require("./HTMLOrSVGElement-impl").implementation;
+const { firstChildWithLocalName } = require("../helpers/traversal");
+const { isDisabled } = require("../helpers/form-controls");
+const { fireAnEvent } = require("../helpers/events");
+const { asciiLowercase } = require("../helpers/strings");
+
+class HTMLElementImpl extends ElementImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+ this._initHTMLOrSVGElement();
+ this._initElementCSSInlineStyle();
+ this._initGlobalEvents();
+
+ this._clickInProgress = false;
+
+ // <summary> uses HTMLElement and has activation behavior
+ this._hasActivationBehavior = this._localName === "summary";
+ }
+
+ _activationBehavior() {
+ const parent = this.parentNode;
+ if (parent && parent._localName === "details" &&
+ this === firstChildWithLocalName(parent, "summary")) {
+ if (parent.hasAttributeNS(null, "open")) {
+ parent.removeAttributeNS(null, "open");
+ } else {
+ parent.setAttributeNS(null, "open", "");
+ }
+ }
+ }
+
+ // https://html.spec.whatwg.org/multipage/dom.html#the-translate-attribute
+ get translate() {
+ const translateAttr = this.getAttributeNS(null, "translate");
+ const translateAttrString = asciiLowercase(translateAttr || "");
+
+ if (translateAttrString === "yes" || (translateAttr && translateAttrString === "")) {
+ return true;
+ } else if (translateAttrString === "no") {
+ return false;
+ }
+
+ if (this === this.ownerDocument.documentElement) {
+ return true;
+ }
+
+ return this.parentElement && this.parentElement.translate;
+ }
+ set translate(value) {
+ if (value === true) {
+ this.setAttributeNS(null, "translate", "yes");
+ } else {
+ this.setAttributeNS(null, "translate", "no");
+ }
+ }
+
+ click() {
+ // https://html.spec.whatwg.org/multipage/interaction.html#dom-click
+ // https://html.spec.whatwg.org/multipage/webappapis.html#fire-a-synthetic-mouse-event
+
+ if (isDisabled(this)) {
+ return;
+ }
+
+ if (this._clickInProgress) {
+ return;
+ }
+
+ this._clickInProgress = true;
+
+ // https://github.com/whatwg/html/issues/4451
+ // https://github.com/whatwg/html/issues/4452
+ fireAnEvent("click", this, MouseEvent, {
+ bubbles: true,
+ cancelable: true,
+ composed: true,
+ isTrusted: false,
+ view: this.ownerDocument.defaultView
+ });
+
+ this._clickInProgress = false;
+ }
+
+ get draggable() {
+ const attributeValue = asciiLowercase(this.getAttributeNS(null, "draggable") || "");
+
+ if (attributeValue === "true") {
+ return true;
+ } else if (attributeValue === "false") {
+ return false;
+ }
+
+ return this._localName === "img" || (this._localName === "a" && this.hasAttributeNS(null, "href"));
+ }
+ set draggable(value) {
+ this.setAttributeNS(null, "draggable", String(value));
+ }
+
+ get dir() {
+ let dirValue = this.getAttributeNS(null, "dir");
+ if (dirValue !== null) {
+ dirValue = dirValue.toLowerCase();
+
+ if (["ltr", "rtl", "auto"].includes(dirValue)) {
+ return dirValue;
+ }
+ }
+ return "";
+ }
+ set dir(value) {
+ this.setAttributeNS(null, "dir", value);
+ }
+
+ // Keep in sync with SVGElement. https://github.com/jsdom/jsdom/issues/2599
+ _attrModified(name, value, oldValue) {
+ if (name === "style" && value !== oldValue && !this._settingCssText) {
+ this._settingCssText = true;
+ this._style.cssText = value;
+ this._settingCssText = false;
+ } else if (name.startsWith("on")) {
+ this._globalEventChanged(name.substring(2));
+ }
+
+ super._attrModified(name, value, oldValue);
+ }
+
+ get offsetParent() {
+ return null;
+ }
+
+ get offsetTop() {
+ return 0;
+ }
+
+ get offsetLeft() {
+ return 0;
+ }
+
+ get offsetWidth() {
+ return 0;
+ }
+
+ get offsetHeight() {
+ return 0;
+ }
+}
+
+mixin(HTMLElementImpl.prototype, ElementCSSInlineStyleImpl.prototype);
+mixin(HTMLElementImpl.prototype, GlobalEventHandlersImpl.prototype);
+mixin(HTMLElementImpl.prototype, HTMLOrSVGElementImpl.prototype);
+
+module.exports = {
+ implementation: HTMLElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLEmbedElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLEmbedElement-impl.js
new file mode 100644
index 0000000..c1c9788
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLEmbedElement-impl.js
@@ -0,0 +1,8 @@
+"use strict";
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLEmbedElementImpl extends HTMLElementImpl {}
+
+module.exports = {
+ implementation: HTMLEmbedElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFieldSetElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFieldSetElement-impl.js
new file mode 100644
index 0000000..360a838
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFieldSetElement-impl.js
@@ -0,0 +1,43 @@
+"use strict";
+const HTMLCollection = require("../generated/HTMLCollection");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const DefaultConstraintValidationImpl =
+ require("../constraint-validation/DefaultConstraintValidation-impl").implementation;
+const { formOwner } = require("../helpers/form-controls");
+const { mixin } = require("../../utils");
+const { descendantsByLocalNames } = require("../helpers/traversal");
+
+const listedElements = new Set(["button", "fieldset", "input", "object", "output", "select", "textarea"]);
+
+class HTMLFieldSetElementImpl extends HTMLElementImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+
+ this._customValidityErrorMessage = "";
+ }
+
+ get elements() {
+ return HTMLCollection.createImpl(this._globalObject, [], {
+ element: this,
+ query: () => descendantsByLocalNames(this, listedElements)
+ });
+ }
+
+ get form() {
+ return formOwner(this);
+ }
+
+ get type() {
+ return "fieldset";
+ }
+
+ _barredFromConstraintValidationSpecialization() {
+ return true;
+ }
+}
+
+mixin(HTMLFieldSetElementImpl.prototype, DefaultConstraintValidationImpl.prototype);
+
+module.exports = {
+ implementation: HTMLFieldSetElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFontElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFontElement-impl.js
new file mode 100644
index 0000000..688773a
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFontElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLFontElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLFontElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFormElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFormElement-impl.js
new file mode 100644
index 0000000..1e7e28e
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFormElement-impl.js
@@ -0,0 +1,226 @@
+"use strict";
+
+const DOMException = require("domexception/webidl2js-wrapper");
+const { serializeURL } = require("whatwg-url");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const { domSymbolTree } = require("../helpers/internal-constants");
+const { fireAnEvent } = require("../helpers/events");
+const { formOwner, isListed, isSubmittable, isSubmitButton } = require("../helpers/form-controls");
+const HTMLCollection = require("../generated/HTMLCollection");
+const notImplemented = require("../../browser/not-implemented");
+const { parseURLToResultingURLRecord } = require("../helpers/document-base-url");
+
+const encTypes = new Set([
+ "application/x-www-form-urlencoded",
+ "multipart/form-data",
+ "text/plain"
+]);
+
+const methods = new Set([
+ "get",
+ "post",
+ "dialog"
+]);
+
+const constraintValidationPositiveResult = Symbol("positive");
+const constraintValidationNegativeResult = Symbol("negative");
+
+class HTMLFormElementImpl extends HTMLElementImpl {
+ _descendantAdded(parent, child) {
+ const form = this;
+ for (const el of domSymbolTree.treeIterator(child)) {
+ if (typeof el._changedFormOwner === "function") {
+ el._changedFormOwner(form);
+ }
+ }
+
+ super._descendantAdded(parent, child);
+ }
+
+ _descendantRemoved(parent, child) {
+ for (const el of domSymbolTree.treeIterator(child)) {
+ if (typeof el._changedFormOwner === "function") {
+ el._changedFormOwner(null);
+ }
+ }
+
+ super._descendantRemoved(parent, child);
+ }
+
+ _getElementNodes() {
+ return domSymbolTree.treeToArray(this.getRootNode({}), {
+ filter: node => {
+ if (!isListed(node) || (node._localName === "input" && node.type === "image")) {
+ return false;
+ }
+
+ return formOwner(node) === this;
+ }
+ });
+ }
+
+ // https://html.spec.whatwg.org/multipage/forms.html#dom-form-elements
+ get elements() {
+ // TODO: Return a HTMLFormControlsCollection
+ return HTMLCollection.createImpl(this._globalObject, [], {
+ element: this.getRootNode({}),
+ query: () => this._getElementNodes()
+ });
+ }
+
+ get length() {
+ return this.elements.length;
+ }
+
+ _doSubmit() {
+ if (!this.isConnected) {
+ return;
+ }
+
+ this.submit();
+ }
+
+ submit() {
+ if (!fireAnEvent("submit", this, undefined, { bubbles: true, cancelable: true })) {
+ return;
+ }
+
+ notImplemented("HTMLFormElement.prototype.submit", this._ownerDocument._defaultView);
+ }
+
+ requestSubmit(submitter = undefined) {
+ if (submitter !== undefined) {
+ if (!isSubmitButton(submitter)) {
+ throw new TypeError("The specified element is not a submit button");
+ }
+ if (submitter.form !== this) {
+ throw DOMException.create(this._globalObject, [
+ "The specified element is not owned by this form element",
+ "NotFoundError"
+ ]);
+ }
+ }
+
+ if (!fireAnEvent("submit", this, undefined, { bubbles: true, cancelable: true })) {
+ return;
+ }
+
+ notImplemented("HTMLFormElement.prototype.requestSubmit", this._ownerDocument._defaultView);
+ }
+
+ _doReset() {
+ if (!this.isConnected) {
+ return;
+ }
+
+ this.reset();
+ }
+
+ reset() {
+ if (!fireAnEvent("reset", this, undefined, { bubbles: true, cancelable: true })) {
+ return;
+ }
+
+ for (const el of this.elements) {
+ if (typeof el._formReset === "function") {
+ el._formReset();
+ }
+ }
+ }
+
+ get method() {
+ let method = this.getAttributeNS(null, "method");
+ if (method) {
+ method = method.toLowerCase();
+ }
+
+ if (methods.has(method)) {
+ return method;
+ }
+ return "get";
+ }
+
+ set method(V) {
+ this.setAttributeNS(null, "method", V);
+ }
+
+ get enctype() {
+ let type = this.getAttributeNS(null, "enctype");
+ if (type) {
+ type = type.toLowerCase();
+ }
+
+ if (encTypes.has(type)) {
+ return type;
+ }
+ return "application/x-www-form-urlencoded";
+ }
+
+ set enctype(V) {
+ this.setAttributeNS(null, "enctype", V);
+ }
+
+ get action() {
+ const attributeValue = this.getAttributeNS(null, "action");
+ if (attributeValue === null || attributeValue === "") {
+ return this._ownerDocument.URL;
+ }
+ const urlRecord = parseURLToResultingURLRecord(attributeValue, this._ownerDocument);
+ if (urlRecord === null) {
+ return attributeValue;
+ }
+ return serializeURL(urlRecord);
+ }
+
+ set action(V) {
+ this.setAttributeNS(null, "action", V);
+ }
+
+ // If the checkValidity() method is invoked, the user agent must statically validate the
+ // constraints of the form element, and return true if the constraint validation returned
+ // a positive result, and false if it returned a negative result.
+ checkValidity() {
+ return this._staticallyValidateConstraints().result === constraintValidationPositiveResult;
+ }
+
+ // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#interactively-validate-the-constraints
+ reportValidity() {
+ return this.checkValidity();
+ }
+
+ // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#statically-validate-the-constraints
+ _staticallyValidateConstraints() {
+ const controls = [];
+ for (const el of this.elements) {
+ if (el.form === this && isSubmittable(el)) {
+ controls.push(el);
+ }
+ }
+
+ const invalidControls = [];
+
+ for (const control of controls) {
+ if (control._isCandidateForConstraintValidation() && !control._satisfiesConstraints()) {
+ invalidControls.push(control);
+ }
+ }
+
+ if (invalidControls.length === 0) {
+ return { result: constraintValidationPositiveResult };
+ }
+
+ const unhandledInvalidControls = [];
+ for (const invalidControl of invalidControls) {
+ const notCancelled = fireAnEvent("invalid", invalidControl, undefined, { cancelable: true });
+ if (notCancelled) {
+ unhandledInvalidControls.push(invalidControl);
+ }
+ }
+
+ return { result: constraintValidationNegativeResult, unhandledInvalidControls };
+ }
+}
+
+module.exports = {
+ implementation: HTMLFormElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFrameElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFrameElement-impl.js
new file mode 100644
index 0000000..67ab547
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFrameElement-impl.js
@@ -0,0 +1,261 @@
+"use strict";
+
+const MIMEType = require("whatwg-mimetype");
+const whatwgEncoding = require("whatwg-encoding");
+const { parseURL, serializeURL } = require("whatwg-url");
+const sniffHTMLEncoding = require("html-encoding-sniffer");
+
+const window = require("../../browser/Window");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const { evaluateJavaScriptURL } = require("../window/navigation");
+const { parseIntoDocument } = require("../../browser/parser");
+const { documentBaseURL } = require("../helpers/document-base-url");
+const { fireAnEvent } = require("../helpers/events");
+const { getAttributeValue } = require("../attributes");
+const idlUtils = require("../generated/utils");
+
+function fireLoadEvent(document, frame, attaching) {
+ if (attaching) {
+ fireAnEvent("load", frame);
+
+ return;
+ }
+
+ const dummyPromise = Promise.resolve();
+
+ function onLoad() {
+ fireAnEvent("load", frame);
+ }
+
+ document._queue.push(dummyPromise, onLoad);
+}
+
+function fetchFrame(serializedURL, frame, document, contentDoc) {
+ const resourceLoader = document._resourceLoader;
+
+ let request;
+
+ function onFrameLoaded(data) {
+ const sniffOptions = {
+ defaultEncoding: document._encoding
+ };
+
+ if (request.response) {
+ const contentType = MIMEType.parse(request.response.headers["content-type"]) || new MIMEType("text/plain");
+ sniffOptions.transportLayerEncodingLabel = contentType.parameters.get("charset");
+
+ if (contentType) {
+ if (contentType.isXML()) {
+ contentDoc._parsingMode = "xml";
+ }
+ contentDoc.contentType = contentType.essence;
+ }
+ }
+
+ const encoding = sniffHTMLEncoding(data, sniffOptions);
+ contentDoc._encoding = encoding;
+
+ const html = whatwgEncoding.decode(data, contentDoc._encoding);
+
+ try {
+ parseIntoDocument(html, contentDoc);
+ } catch (error) {
+ const { DOMException } = contentDoc._globalObject;
+
+ if (
+ error.constructor.name === "DOMException" &&
+ error.code === DOMException.SYNTAX_ERR &&
+ contentDoc._parsingMode === "xml"
+ ) {
+ // As defined (https://html.spec.whatwg.org/#read-xml) parsing error in XML document may be reported inline by
+ // mutating the document.
+ const element = contentDoc.createElementNS("http://www.mozilla.org/newlayout/xml/parsererror.xml", "parsererror");
+ element.textContent = error.message;
+
+ while (contentDoc.childNodes.length > 0) {
+ contentDoc.removeChild(contentDoc.lastChild);
+ }
+ contentDoc.appendChild(element);
+ } else {
+ throw error;
+ }
+ }
+
+ contentDoc.close();
+
+ return new Promise((resolve, reject) => {
+ contentDoc.addEventListener("load", resolve);
+ contentDoc.addEventListener("error", reject);
+ });
+ }
+
+ request = resourceLoader.fetch(serializedURL, {
+ element: frame,
+ onLoad: onFrameLoaded
+ });
+}
+
+function canDispatchEvents(frame, attaching) {
+ if (!attaching) {
+ return false;
+ }
+
+ return Object.keys(frame._eventListeners).length === 0;
+}
+
+function loadFrame(frame, attaching) {
+ if (frame._contentDocument) {
+ if (frame._contentDocument._defaultView) {
+ // close calls delete on its document.
+ frame._contentDocument._defaultView.close();
+ } else {
+ delete frame._contentDocument;
+ }
+ }
+
+ const parentDoc = frame._ownerDocument;
+
+ // https://html.spec.whatwg.org/#process-the-iframe-attributes
+ let url;
+ const srcAttribute = getAttributeValue(frame, "src");
+ if (srcAttribute === "") {
+ url = parseURL("about:blank");
+ } else {
+ url = parseURL(srcAttribute, { baseURL: documentBaseURL(parentDoc) || undefined }) || parseURL("about:blank");
+ }
+ const serializedURL = serializeURL(url);
+
+ const wnd = window.createWindow({
+ parsingMode: "html",
+ url: url.scheme === "javascript" ? parentDoc.URL : serializedURL,
+ parentOrigin: parentDoc._origin,
+ resourceLoader: parentDoc._defaultView._resourceLoader,
+ referrer: parentDoc.URL,
+ cookieJar: parentDoc._cookieJar,
+ pool: parentDoc._pool,
+ encoding: parentDoc._encoding,
+ runScripts: parentDoc._defaultView._runScripts,
+ commonForOrigin: parentDoc._defaultView._commonForOrigin,
+ pretendToBeVisual: parentDoc._defaultView._pretendToBeVisual
+ });
+
+ const contentDoc = frame._contentDocument = idlUtils.implForWrapper(wnd._document);
+ const parent = parentDoc._defaultView;
+ const contentWindow = contentDoc._defaultView;
+ contentWindow._parent = parent;
+ contentWindow._top = parent.top;
+ contentWindow._frameElement = frame;
+ contentWindow._virtualConsole = parent._virtualConsole;
+
+ if (parentDoc._origin === contentDoc._origin) {
+ contentWindow._currentOriginData.windowsInSameOrigin.push(contentWindow);
+ }
+
+ const noQueue = canDispatchEvents(frame, attaching);
+
+ // Handle about:blank with a simulated load of an empty document.
+ if (serializedURL === "about:blank") {
+ // Cannot be done inside the enqueued callback; the documentElement etc. need to be immediately available.
+ parseIntoDocument("<html><head></head><body></body></html>", contentDoc);
+ contentDoc.close(noQueue);
+
+ if (noQueue) {
+ fireLoadEvent(parentDoc, frame, noQueue);
+ } else {
+ contentDoc.addEventListener("load", () => {
+ fireLoadEvent(parentDoc, frame);
+ });
+ }
+ } else if (url.scheme === "javascript") {
+ // Cannot be done inside the enqueued callback; the documentElement etc. need to be immediately available.
+ parseIntoDocument("<html><head></head><body></body></html>", contentDoc);
+ contentDoc.close(noQueue);
+ const result = evaluateJavaScriptURL(contentWindow, url);
+ if (typeof result === "string") {
+ contentDoc.body.textContent = result;
+ }
+ if (noQueue) {
+ fireLoadEvent(parentDoc, frame, noQueue);
+ } else {
+ contentDoc.addEventListener("load", () => {
+ fireLoadEvent(parentDoc, frame);
+ });
+ }
+ } else {
+ fetchFrame(serializedURL, frame, parentDoc, contentDoc);
+ }
+}
+
+function refreshAccessors(document) {
+ const { _defaultView } = document;
+
+ if (!_defaultView) {
+ return;
+ }
+
+ const frames = document.querySelectorAll("iframe,frame");
+
+ // delete accessors for all frames
+ for (let i = 0; i < _defaultView._length; ++i) {
+ delete _defaultView[i];
+ }
+
+ _defaultView._length = frames.length;
+ Array.prototype.forEach.call(frames, (frame, i) => {
+ Object.defineProperty(_defaultView, i, {
+ configurable: true,
+ enumerable: true,
+ get() {
+ return frame.contentWindow;
+ }
+ });
+ });
+}
+
+class HTMLFrameElementImpl extends HTMLElementImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+ this._contentDocument = null;
+ }
+ _attrModified(name, value, oldVal) {
+ super._attrModified(name, value, oldVal);
+ if (name === "src") {
+ // iframe should never load in a document without a Window
+ // (e.g. implementation.createHTMLDocument)
+ if (this._attached && this._ownerDocument._defaultView) {
+ loadFrame(this);
+ }
+ }
+ }
+
+ _detach() {
+ super._detach();
+
+ if (this.contentWindow) {
+ this.contentWindow.close();
+ }
+
+ refreshAccessors(this._ownerDocument);
+ }
+
+ _attach() {
+ super._attach();
+
+ if (this._ownerDocument._defaultView) {
+ loadFrame(this, true);
+ }
+ refreshAccessors(this._ownerDocument);
+ }
+
+ get contentDocument() {
+ return this._contentDocument;
+ }
+
+ get contentWindow() {
+ return this.contentDocument ? this.contentDocument._defaultView : null;
+ }
+}
+
+module.exports = {
+ implementation: HTMLFrameElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFrameSetElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFrameSetElement-impl.js
new file mode 100644
index 0000000..89eee2d
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFrameSetElement-impl.js
@@ -0,0 +1,17 @@
+"use strict";
+const { mixin } = require("../../utils");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const WindowEventHandlersImpl = require("./WindowEventHandlers-impl").implementation;
+
+class HTMLFrameSetElementImpl extends HTMLElementImpl {
+ constructor(...args) {
+ super(...args);
+ this._proxyWindowEventsToWindow();
+ }
+}
+
+mixin(HTMLFrameSetElementImpl.prototype, WindowEventHandlersImpl.prototype);
+
+module.exports = {
+ implementation: HTMLFrameSetElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHRElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHRElement-impl.js
new file mode 100644
index 0000000..8c5d337
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHRElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLHRElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLHRElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHeadElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHeadElement-impl.js
new file mode 100644
index 0000000..6803377
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHeadElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLHeadElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLHeadElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHeadingElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHeadingElement-impl.js
new file mode 100644
index 0000000..4fb4250
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHeadingElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLHeadingElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLHeadingElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHtmlElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHtmlElement-impl.js
new file mode 100644
index 0000000..bda1780
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHtmlElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLHtmlElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLHtmlElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHyperlinkElementUtils-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHyperlinkElementUtils-impl.js
new file mode 100644
index 0000000..004c60c
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHyperlinkElementUtils-impl.js
@@ -0,0 +1,371 @@
+"use strict";
+const whatwgURL = require("whatwg-url");
+const { parseURLToResultingURLRecord } = require("../helpers/document-base-url");
+const { asciiCaseInsensitiveMatch } = require("../helpers/strings");
+const { navigate } = require("../window/navigation");
+
+exports.implementation = class HTMLHyperlinkElementUtilsImpl {
+ _htmlHyperlinkElementUtilsSetup() {
+ this.url = null;
+ }
+
+ // https://html.spec.whatwg.org/multipage/links.html#cannot-navigate
+ _cannotNavigate() {
+ // TODO: Correctly check if the document is fully active
+ return this._localName !== "a" && !this.isConnected;
+ }
+
+ // https://html.spec.whatwg.org/multipage/semantics.html#get-an-element's-target
+ _getAnElementsTarget() {
+ if (this.hasAttributeNS(null, "target")) {
+ return this.getAttributeNS(null, "target");
+ }
+
+ const baseEl = this._ownerDocument.querySelector("base[target]");
+
+ if (baseEl) {
+ return baseEl.getAttributeNS(null, "target");
+ }
+
+ return "";
+ }
+
+ // https://html.spec.whatwg.org/multipage/browsers.html#the-rules-for-choosing-a-browsing-context-given-a-browsing-context-name
+ _chooseABrowsingContext(name, current) {
+ let chosen = null;
+
+ if (name === "" || asciiCaseInsensitiveMatch(name, "_self")) {
+ chosen = current;
+ } else if (asciiCaseInsensitiveMatch(name, "_parent")) {
+ chosen = current.parent;
+ } else if (asciiCaseInsensitiveMatch(name, "_top")) {
+ chosen = current.top;
+ } else if (!asciiCaseInsensitiveMatch(name, "_blank")) {
+ // https://github.com/whatwg/html/issues/1440
+ }
+
+ // TODO: Create new browsing context, handle noopener
+
+ return chosen;
+ }
+
+ // https://html.spec.whatwg.org/multipage/links.html#following-hyperlinks-2
+ _followAHyperlink() {
+ if (this._cannotNavigate()) {
+ return;
+ }
+
+ const source = this._ownerDocument._defaultView;
+ let targetAttributeValue = "";
+
+ if (this._localName === "a" || this._localName === "area") {
+ targetAttributeValue = this._getAnElementsTarget();
+ }
+
+ const noopener = this.relList.contains("noreferrer") || this.relList.contains("noopener");
+
+ const target = this._chooseABrowsingContext(targetAttributeValue, source, noopener);
+
+ if (target === null) {
+ return;
+ }
+
+ const url = parseURLToResultingURLRecord(this.href, this._ownerDocument);
+
+ if (url === null) {
+ return;
+ }
+
+ // TODO: Handle hyperlink suffix and referrerpolicy
+ setTimeout(() => {
+ navigate(target, url, {});
+ }, 0);
+ }
+
+ toString() {
+ return this.href;
+ }
+
+ get href() {
+ reinitializeURL(this);
+ const { url } = this;
+
+ if (url === null) {
+ const href = this.getAttributeNS(null, "href");
+ return href === null ? "" : href;
+ }
+
+ return whatwgURL.serializeURL(url);
+ }
+
+ set href(v) {
+ this.setAttributeNS(null, "href", v);
+ }
+
+ get origin() {
+ reinitializeURL(this);
+
+ if (this.url === null) {
+ return "";
+ }
+
+ return whatwgURL.serializeURLOrigin(this.url);
+ }
+
+ get protocol() {
+ reinitializeURL(this);
+
+ if (this.url === null) {
+ return ":";
+ }
+
+ return this.url.scheme + ":";
+ }
+
+ set protocol(v) {
+ reinitializeURL(this);
+
+ if (this.url === null) {
+ return;
+ }
+
+ whatwgURL.basicURLParse(v + ":", { url: this.url, stateOverride: "scheme start" });
+ updateHref(this);
+ }
+
+ get username() {
+ reinitializeURL(this);
+
+ if (this.url === null) {
+ return "";
+ }
+
+ return this.url.username;
+ }
+
+ set username(v) {
+ reinitializeURL(this);
+ const { url } = this;
+
+ if (url === null || url.host === null || url.host === "" || url.cannotBeABaseURL || url.scheme === "file") {
+ return;
+ }
+
+ whatwgURL.setTheUsername(url, v);
+ updateHref(this);
+ }
+
+ get password() {
+ reinitializeURL(this);
+ const { url } = this;
+
+ if (url === null) {
+ return "";
+ }
+
+ return url.password;
+ }
+
+ set password(v) {
+ reinitializeURL(this);
+ const { url } = this;
+
+ if (url === null || url.host === null || url.host === "" || url.cannotBeABaseURL || url.scheme === "file") {
+ return;
+ }
+
+ whatwgURL.setThePassword(url, v);
+ updateHref(this);
+ }
+
+ get host() {
+ reinitializeURL(this);
+ const { url } = this;
+
+ if (url === null || url.host === null) {
+ return "";
+ }
+
+ if (url.port === null) {
+ return whatwgURL.serializeHost(url.host);
+ }
+
+ return whatwgURL.serializeHost(url.host) + ":" + whatwgURL.serializeInteger(url.port);
+ }
+
+ set host(v) {
+ reinitializeURL(this);
+ const { url } = this;
+
+ if (url === null || url.cannotBeABaseURL) {
+ return;
+ }
+
+ whatwgURL.basicURLParse(v, { url, stateOverride: "host" });
+ updateHref(this);
+ }
+
+ get hostname() {
+ reinitializeURL(this);
+ const { url } = this;
+
+ if (url === null || url.host === null) {
+ return "";
+ }
+
+ return whatwgURL.serializeHost(url.host);
+ }
+
+ set hostname(v) {
+ reinitializeURL(this);
+ const { url } = this;
+
+ if (url === null || url.cannotBeABaseURL) {
+ return;
+ }
+
+ whatwgURL.basicURLParse(v, { url, stateOverride: "hostname" });
+ updateHref(this);
+ }
+
+ get port() {
+ reinitializeURL(this);
+ const { url } = this;
+
+ if (url === null || url.port === null) {
+ return "";
+ }
+
+ return whatwgURL.serializeInteger(url.port);
+ }
+
+ set port(v) {
+ reinitializeURL(this);
+ const { url } = this;
+
+ if (url === null || url.host === null || url.host === "" || url.cannotBeABaseURL || url.scheme === "file") {
+ return;
+ }
+
+ if (v === "") {
+ url.port = null;
+ } else {
+ whatwgURL.basicURLParse(v, { url, stateOverride: "port" });
+ }
+ updateHref(this);
+ }
+
+ get pathname() {
+ reinitializeURL(this);
+ const { url } = this;
+
+ if (url === null) {
+ return "";
+ }
+
+ if (url.cannotBeABaseURL) {
+ return url.path[0];
+ }
+
+ return "/" + url.path.join("/");
+ }
+
+ set pathname(v) {
+ reinitializeURL(this);
+ const { url } = this;
+
+ if (url === null || url.cannotBeABaseURL) {
+ return;
+ }
+
+ url.path = [];
+ whatwgURL.basicURLParse(v, { url, stateOverride: "path start" });
+ updateHref(this);
+ }
+
+ get search() {
+ reinitializeURL(this);
+ const { url } = this;
+
+ if (url === null || url.query === null || url.query === "") {
+ return "";
+ }
+
+ return "?" + url.query;
+ }
+
+ set search(v) {
+ reinitializeURL(this);
+ const { url } = this;
+
+ if (url === null) {
+ return;
+ }
+
+ if (v === "") {
+ url.query = null;
+ } else {
+ const input = v[0] === "?" ? v.substring(1) : v;
+ url.query = "";
+ whatwgURL.basicURLParse(input, {
+ url,
+ stateOverride: "query",
+ encodingOverride: this._ownerDocument.charset
+ });
+ }
+ updateHref(this);
+ }
+
+ get hash() {
+ reinitializeURL(this);
+ const { url } = this;
+
+ if (url === null || url.fragment === null || url.fragment === "") {
+ return "";
+ }
+
+ return "#" + url.fragment;
+ }
+
+ set hash(v) {
+ reinitializeURL(this);
+ const { url } = this;
+
+ if (url === null) {
+ return;
+ }
+
+ if (v === "") {
+ url.fragment = null;
+ } else {
+ const input = v[0] === "#" ? v.substring(1) : v;
+ url.fragment = "";
+ whatwgURL.basicURLParse(input, { url, stateOverride: "fragment" });
+ }
+ updateHref(this);
+ }
+};
+
+function reinitializeURL(hheu) {
+ if (hheu.url !== null && hheu.url.scheme === "blob" && hheu.url.cannotBeABaseURL) {
+ return;
+ }
+
+ setTheURL(hheu);
+}
+
+function setTheURL(hheu) {
+ const href = hheu.getAttributeNS(null, "href");
+ if (href === null) {
+ hheu.url = null;
+ return;
+ }
+
+ const parsed = parseURLToResultingURLRecord(href, hheu._ownerDocument);
+
+ hheu.url = parsed === null ? null : parsed;
+}
+
+function updateHref(hheu) {
+ hheu.setAttributeNS(null, "href", whatwgURL.serializeURL(hheu.url));
+}
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLIFrameElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLIFrameElement-impl.js
new file mode 100644
index 0000000..643e989
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLIFrameElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLFrameElementImpl = require("./HTMLFrameElement-impl").implementation;
+
+class HTMLIFrameElementImpl extends HTMLFrameElementImpl { }
+
+module.exports = {
+ implementation: HTMLIFrameElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLImageElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLImageElement-impl.js
new file mode 100644
index 0000000..43267a9
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLImageElement-impl.js
@@ -0,0 +1,132 @@
+"use strict";
+const conversions = require("webidl-conversions");
+const { serializeURL } = require("whatwg-url");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const { Canvas } = require("../../utils");
+const { parseURLToResultingURLRecord } = require("../helpers/document-base-url");
+
+class HTMLImageElementImpl extends HTMLElementImpl {
+ constructor(...args) {
+ super(...args);
+ this._currentRequestState = "unavailable";
+ }
+
+ _attrModified(name, value, oldVal) {
+ // TODO: handle crossorigin
+ if (name === "src" || ((name === "srcset" || name === "width" || name === "sizes") && value !== oldVal)) {
+ this._updateTheImageData();
+ }
+
+ super._attrModified(name, value, oldVal);
+ }
+
+ get _accept() {
+ return "image/png,image/*;q=0.8,*/*;q=0.5";
+ }
+
+ get height() {
+ // Just like on browsers, if no width / height is defined, we fall back on the
+ // dimensions of the internal image data.
+ return this.hasAttributeNS(null, "height") ?
+ conversions["unsigned long"](this.getAttributeNS(null, "height")) :
+ this.naturalHeight;
+ }
+
+ set height(V) {
+ this.setAttributeNS(null, "height", String(V));
+ }
+
+ get width() {
+ return this.hasAttributeNS(null, "width") ?
+ conversions["unsigned long"](this.getAttributeNS(null, "width")) :
+ this.naturalWidth;
+ }
+
+ set width(V) {
+ this.setAttributeNS(null, "width", String(V));
+ }
+
+ get naturalHeight() {
+ return this._image ? this._image.naturalHeight : 0;
+ }
+
+ get naturalWidth() {
+ return this._image ? this._image.naturalWidth : 0;
+ }
+
+ get complete() {
+ const srcAttributeValue = this.getAttributeNS(null, "src");
+ return srcAttributeValue === null ||
+ srcAttributeValue === "" ||
+ this._currentRequestState === "broken" ||
+ this._currentRequestState === "completely available";
+ }
+
+ get currentSrc() {
+ return this._currentSrc || "";
+ }
+
+ // https://html.spec.whatwg.org/multipage/images.html#updating-the-image-data
+ _updateTheImageData() {
+ const document = this._ownerDocument;
+
+ if (!document._defaultView) {
+ return;
+ }
+
+ if (!Canvas) {
+ return;
+ }
+
+ if (!this._image) {
+ this._image = new Canvas.Image();
+ }
+ this._currentSrc = null;
+ this._currentRequestState = "unavailable";
+ const srcAttributeValue = this.getAttributeNS(null, "src");
+ let urlString = null;
+ if (srcAttributeValue !== null && srcAttributeValue !== "") {
+ const urlRecord = parseURLToResultingURLRecord(srcAttributeValue, this._ownerDocument);
+ if (urlRecord === null) {
+ return;
+ }
+ urlString = serializeURL(urlRecord);
+ }
+ if (urlString !== null) {
+ const resourceLoader = document._resourceLoader;
+ let request;
+
+ const onLoadImage = data => {
+ const { response } = request;
+
+ if (response && response.statusCode !== undefined && response.statusCode !== 200) {
+ throw new Error("Status code: " + response.statusCode);
+ }
+ let error = null;
+ this._image.onerror = function (err) {
+ error = err;
+ };
+ this._image.src = data;
+ if (error) {
+ throw new Error(error);
+ }
+ this._currentSrc = srcAttributeValue;
+ this._currentRequestState = "completely available";
+ };
+
+ request = resourceLoader.fetch(urlString, {
+ element: this,
+ onLoad: onLoadImage,
+ onError: () => {
+ this._currentRequestState = "broken";
+ }
+ });
+ } else {
+ this._image.src = "";
+ }
+ }
+}
+
+module.exports = {
+ implementation: HTMLImageElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLInputElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLInputElement-impl.js
new file mode 100644
index 0000000..edd299d
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLInputElement-impl.js
@@ -0,0 +1,1128 @@
+"use strict";
+const DOMException = require("domexception/webidl2js-wrapper");
+const FileList = require("../generated/FileList");
+const Decimal = require("decimal.js");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const idlUtils = require("../generated/utils");
+const DefaultConstraintValidationImpl =
+ require("../constraint-validation/DefaultConstraintValidation-impl").implementation;
+const ValidityState = require("../generated/ValidityState");
+const { mixin } = require("../../utils");
+const { domSymbolTree, cloningSteps } = require("../helpers/internal-constants");
+const { getLabelsForLabelable, formOwner } = require("../helpers/form-controls");
+const { fireAnEvent } = require("../helpers/events");
+const {
+ isDisabled,
+ isValidEmailAddress,
+ isValidAbsoluteURL,
+ sanitizeValueByType
+} = require("../helpers/form-controls");
+const {
+ asciiCaseInsensitiveMatch,
+ asciiLowercase,
+ parseFloatingPointNumber,
+ splitOnCommas
+} = require("../helpers/strings");
+const { isDate } = require("../helpers/dates-and-times");
+const {
+ convertStringToNumberByType,
+ convertStringToDateByType,
+ serializeDateByType,
+ convertNumberToStringByType
+} = require("../helpers/number-and-date-inputs");
+
+const filesSymbol = Symbol("files");
+
+// https://html.spec.whatwg.org/multipage/input.html#attr-input-type
+const inputAllowedTypes = new Set([
+ "hidden", "text", "search", "tel", "url", "email", "password", "date",
+ "month", "week", "time", "datetime-local", "number", "range", "color", "checkbox", "radio",
+ "file", "submit", "image", "reset", "button"
+]);
+
+// https://html.spec.whatwg.org/multipage/input.html#concept-input-apply
+
+const variableLengthSelectionAllowedTypes = new Set(["text", "search", "url", "tel", "password"]);
+const numericTypes = new Set(["date", "month", "week", "time", "datetime-local", "number", "range"]);
+
+const applicableTypesForIDLMember = {
+ valueAsDate: new Set(["date", "month", "week", "time"]),
+ valueAsNumber: numericTypes,
+
+ select: new Set([
+ "text", "search", "url", "tel", "email", "password", "date", "month", "week",
+ "time", "datetime-local", "number", "color", "file"
+ ]),
+ selectionStart: variableLengthSelectionAllowedTypes,
+ selectionEnd: variableLengthSelectionAllowedTypes,
+ selectionDirection: variableLengthSelectionAllowedTypes,
+ setRangeText: variableLengthSelectionAllowedTypes,
+ setSelectionRange: variableLengthSelectionAllowedTypes,
+ stepDown: numericTypes,
+ stepUp: numericTypes
+};
+
+const lengthPatternSizeTypes = new Set(["text", "search", "url", "tel", "email", "password"]);
+const readonlyTypes =
+ new Set([...lengthPatternSizeTypes, "date", "month", "week", "time", "datetime-local", "number"]);
+
+const applicableTypesForContentAttribute = {
+ list: new Set(["text", "search", "url", "tel", "email", ...numericTypes, "color"]),
+ max: numericTypes,
+ maxlength: lengthPatternSizeTypes,
+ min: numericTypes,
+ minlength: lengthPatternSizeTypes,
+ multiple: new Set(["email", "file"]),
+ pattern: lengthPatternSizeTypes,
+ readonly: readonlyTypes,
+ required: new Set([...readonlyTypes, "checkbox", "radio", "file"]),
+ step: numericTypes
+};
+
+const valueAttributeDefaultMode = new Set(["hidden", "submit", "image", "reset", "button"]);
+const valueAttributeDefaultOnMode = new Set(["checkbox", "radio"]);
+
+function valueAttributeMode(type) {
+ if (valueAttributeDefaultMode.has(type)) {
+ return "default";
+ }
+ if (valueAttributeDefaultOnMode.has(type)) {
+ return "default/on";
+ }
+ if (type === "file") {
+ return "filename";
+ }
+ return "value";
+}
+
+function getTypeFromAttribute(typeAttribute) {
+ if (typeof typeAttribute !== "string") {
+ return "text";
+ }
+ const type = asciiLowercase(typeAttribute);
+ return inputAllowedTypes.has(type) ? type : "text";
+}
+
+class HTMLInputElementImpl extends HTMLElementImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+
+ this._selectionStart = this._selectionEnd = 0;
+ this._selectionDirection = "none";
+ this._value = "";
+ this._dirtyValue = false;
+ this._checkedness = false;
+ this._dirtyCheckedness = false;
+
+ this._preCheckedRadioState = null;
+ this._legacyActivationBehaviorPreviousIndeterminateState = false;
+
+ this.indeterminate = false;
+
+ this._customValidityErrorMessage = "";
+
+ this._labels = null;
+
+ this._hasActivationBehavior = true;
+ }
+
+ // https://html.spec.whatwg.org/multipage/input.html#concept-input-value-string-number
+ get _convertStringToNumber() {
+ return convertStringToNumberByType[this.type];
+ }
+
+ get _convertNumberToString() {
+ return convertNumberToStringByType[this.type];
+ }
+
+ get _convertDateToString() {
+ return serializeDateByType[this.type];
+ }
+
+ get _convertStringToDate() {
+ return convertStringToDateByType[this.type];
+ }
+
+ _isStepAligned(v) {
+ return new Decimal(v).minus(this._stepBase)
+ .modulo(this._allowedValueStep)
+ .isZero();
+ }
+
+ // Returns a Decimal.
+ _stepAlign(v, roundUp) {
+ const allowedValueStep = this._allowedValueStep;
+ const stepBase = this._stepBase;
+
+ return new Decimal(v).minus(stepBase)
+ .toNearest(allowedValueStep, roundUp ? Decimal.ROUND_UP : Decimal.ROUND_DOWN)
+ .add(stepBase);
+ }
+
+ // For <input>, https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-fe-value
+ // is a simple value that is gotten and set, not computed.
+ _getValue() {
+ return this._value;
+ }
+
+ _legacyPreActivationBehavior() {
+ if (this.type === "checkbox") {
+ this.checked = !this.checked;
+ this._legacyActivationBehaviorPreviousIndeterminateState = this.indeterminate;
+ this.indeterminate = false;
+ } else if (this.type === "radio") {
+ this._preCheckedRadioState = this.checked;
+ this.checked = true;
+ }
+ }
+
+ _legacyCanceledActivationBehavior() {
+ if (this.type === "checkbox") {
+ this.checked = !this.checked;
+ this.indeterminate = this._legacyActivationBehaviorPreviousIndeterminateState;
+ } else if (this.type === "radio") {
+ if (this._preCheckedRadioState !== null) {
+ this.checked = this._preCheckedRadioState;
+ this._preCheckedRadioState = null;
+ }
+ }
+ }
+
+ _activationBehavior() {
+ if (!this._mutable && this.type !== "checkbox" && this.type !== "radio") {
+ return;
+ }
+
+ const { form } = this;
+
+ if (this.type === "checkbox" || (this.type === "radio" && !this._preCheckedRadioState)) {
+ if (this.isConnected) {
+ fireAnEvent("input", this, undefined, { bubbles: true });
+ fireAnEvent("change", this, undefined, { bubbles: true });
+ }
+ } else if (form && this.type === "submit") {
+ form._doSubmit();
+ } else if (form && this.type === "reset") {
+ form._doReset();
+ }
+ }
+
+ _attrModified(name, value, oldVal) {
+ const wrapper = idlUtils.wrapperForImpl(this);
+ if (!this._dirtyValue && name === "value") {
+ this._value = sanitizeValueByType(this, wrapper.defaultValue);
+ }
+ if (!this._dirtyCheckedness && name === "checked") {
+ this._checkedness = wrapper.defaultChecked;
+ if (this._checkedness) {
+ this._removeOtherRadioCheckedness();
+ }
+ }
+
+ if (name === "name" || name === "type") {
+ if (this._checkedness) {
+ this._removeOtherRadioCheckedness();
+ }
+ }
+
+ if (name === "type") {
+ const prevType = getTypeFromAttribute(oldVal);
+ const curType = getTypeFromAttribute(value);
+ // When an input element's type attribute changes state…
+ if (prevType !== curType) {
+ const prevValueMode = valueAttributeMode(prevType);
+ const curValueMode = valueAttributeMode(curType);
+ if (prevValueMode === "value" && this._value !== "" &&
+ (curValueMode === "default" || curValueMode === "default/on")) {
+ this.setAttributeNS(null, "value", this._value);
+ } else if (prevValueMode !== "value" && curValueMode === "value") {
+ this._value = this.getAttributeNS(null, "value") || "";
+ this._dirtyValue = false;
+ } else if (prevValueMode !== "filename" && curValueMode === "filename") {
+ this._value = "";
+ }
+
+ this._signalATypeChange();
+
+ this._value = sanitizeValueByType(this, this._value);
+
+ const previouslySelectable = this._idlMemberApplies("setRangeText", prevType);
+ const nowSelectable = this._idlMemberApplies("setRangeText", curType);
+ if (!previouslySelectable && nowSelectable) {
+ this._selectionStart = 0;
+ this._selectionEnd = 0;
+ this._selectionDirection = "none";
+ }
+ }
+ }
+
+ super._attrModified(name, value, oldVal);
+ }
+
+ // https://html.spec.whatwg.org/multipage/input.html#signal-a-type-change
+ _signalATypeChange() {
+ if (this._checkedness) {
+ this._removeOtherRadioCheckedness();
+ }
+ }
+
+ _formReset() {
+ const wrapper = idlUtils.wrapperForImpl(this);
+ this._value = sanitizeValueByType(this, wrapper.defaultValue);
+ this._dirtyValue = false;
+ this._checkedness = wrapper.defaultChecked;
+ this._dirtyCheckedness = false;
+ if (this._checkedness) {
+ this._removeOtherRadioCheckedness();
+ }
+ }
+
+ _changedFormOwner() {
+ if (this._checkedness) {
+ this._removeOtherRadioCheckedness();
+ }
+ }
+
+ get _otherRadioGroupElements() {
+ const wrapper = idlUtils.wrapperForImpl(this);
+ const root = this._radioButtonGroupRoot;
+ if (!root) {
+ return [];
+ }
+
+ const result = [];
+
+ const descendants = domSymbolTree.treeIterator(root);
+ for (const candidate of descendants) {
+ if (candidate._radioButtonGroupRoot !== root) {
+ continue;
+ }
+
+ const candidateWrapper = idlUtils.wrapperForImpl(candidate);
+ if (!candidateWrapper.name || candidateWrapper.name !== wrapper.name) {
+ continue;
+ }
+
+ if (candidate !== this) {
+ result.push(candidate);
+ }
+ }
+ return result;
+ }
+
+ _removeOtherRadioCheckedness() {
+ for (const radioGroupElement of this._otherRadioGroupElements) {
+ radioGroupElement._checkedness = false;
+ }
+ }
+
+ get _radioButtonGroupRoot() {
+ const wrapper = idlUtils.wrapperForImpl(this);
+ if (this.type !== "radio" || !wrapper.name) {
+ return null;
+ }
+
+ let e = domSymbolTree.parent(this);
+ while (e) {
+ // root node of this home sub tree
+ // or the form element we belong to
+ if (!domSymbolTree.parent(e) || e.nodeName.toUpperCase() === "FORM") {
+ return e;
+ }
+ e = domSymbolTree.parent(e);
+ }
+ return null;
+ }
+
+ _someInRadioGroup(name) {
+ if (this[name]) {
+ return true;
+ }
+ return this._otherRadioGroupElements.some(radioGroupElement => radioGroupElement[name]);
+ }
+
+ get _mutable() {
+ return !isDisabled(this) && !this._hasAttributeAndApplies("readonly");
+ }
+
+ get labels() {
+ return getLabelsForLabelable(this);
+ }
+
+ get form() {
+ return formOwner(this);
+ }
+
+ get checked() {
+ return this._checkedness;
+ }
+
+ set checked(checked) {
+ this._checkedness = Boolean(checked);
+ this._dirtyCheckedness = true;
+ if (this._checkedness) {
+ this._removeOtherRadioCheckedness();
+ }
+ }
+
+ get value() {
+ switch (valueAttributeMode(this.type)) {
+ // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-value
+ case "value":
+ return this._getValue();
+ // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-default
+ case "default": {
+ const attr = this.getAttributeNS(null, "value");
+ return attr !== null ? attr : "";
+ }
+ // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-default-on
+ case "default/on": {
+ const attr = this.getAttributeNS(null, "value");
+ return attr !== null ? attr : "on";
+ }
+ // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-filename
+ case "filename":
+ return this.files.length ? "C:\\fakepath\\" + this.files[0].name : "";
+ default:
+ throw new Error("jsdom internal error: unknown value attribute mode");
+ }
+ }
+
+ set value(val) {
+ switch (valueAttributeMode(this.type)) {
+ // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-value
+ case "value": {
+ const oldValue = this._value;
+ this._value = sanitizeValueByType(this, val);
+ this._dirtyValue = true;
+
+ if (oldValue !== this._value) {
+ this._selectionStart = this._selectionEnd = this._getValueLength();
+ this._selectionDirection = "none";
+ }
+ break;
+ }
+
+ // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-default
+ // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-default-on
+ case "default":
+ case "default/on":
+ this.setAttributeNS(null, "value", val);
+ break;
+
+ // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-filename
+ case "filename":
+ if (val === "") {
+ this.files.length = 0;
+ } else {
+ throw DOMException.create(this._globalObject, [
+ "This input element accepts a filename, which may only be programmatically set to the empty string.",
+ "InvalidStateError"
+ ]);
+ }
+ break;
+
+ default:
+ throw new Error("jsdom internal error: unknown value attribute mode");
+ }
+ }
+
+ // https://html.spec.whatwg.org/multipage/input.html#dom-input-valueasdate
+ get valueAsDate() {
+ if (!this._idlMemberApplies("valueAsDate")) {
+ return null;
+ }
+
+ const window = this._ownerDocument._defaultView;
+ const convertedValue = this._convertStringToDate(this._value);
+
+ if (convertedValue instanceof Date) {
+ return new window.Date(convertedValue.getTime());
+ }
+
+ return null;
+ }
+
+ set valueAsDate(v) {
+ if (!this._idlMemberApplies("valueAsDate")) {
+ throw DOMException.create(this._globalObject, [
+ "Failed to set the 'valueAsDate' property on 'HTMLInputElement': This input element does not support Date " +
+ "values.",
+ "InvalidStateError"
+ ]);
+ }
+
+ if (v !== null && !isDate(v)) {
+ throw new TypeError("Failed to set the 'valueAsDate' property on 'HTMLInputElement': The provided value is " +
+ "not a Date.");
+ }
+
+ if (v === null || isNaN(v)) {
+ this._value = "";
+ }
+
+ this._value = this._convertDateToString(v);
+ }
+
+ // https://html.spec.whatwg.org/multipage/input.html#dom-input-valueasnumber
+ get valueAsNumber() {
+ if (!this._idlMemberApplies("valueAsNumber")) {
+ return NaN;
+ }
+
+ const parsedValue = this._convertStringToNumber(this._value);
+ return parsedValue !== null ? parsedValue : NaN;
+ }
+
+ set valueAsNumber(v) {
+ if (!isFinite(v)) {
+ throw new TypeError("Failed to set infinite value as Number");
+ }
+
+ if (!this._idlMemberApplies("valueAsNumber")) {
+ throw DOMException.create(this._globalObject, [
+ "Failed to set the 'valueAsNumber' property on 'HTMLInputElement': This input element does not support " +
+ "Number values.",
+ "InvalidStateError"
+ ]);
+ }
+
+ this._value = this._convertNumberToString(v);
+ }
+
+ // https://html.spec.whatwg.org/multipage/input.html#dom-input-stepup
+ _stepUpdate(n, isUp) {
+ const methodName = isUp ? "stepUp" : "stepDown";
+ if (!this._idlMemberApplies(methodName)) {
+ throw DOMException.create(this._globalObject, [
+ `Failed to invoke '${methodName}' method on 'HTMLInputElement': ` +
+ "This input element does not support Number values.",
+ "InvalidStateError"
+ ]);
+ }
+
+ const allowedValueStep = this._allowedValueStep;
+ if (allowedValueStep === null) {
+ throw DOMException.create(this._globalObject, [
+ `Failed to invoke '${methodName}' method on 'HTMLInputElement': ` +
+ "This input element does not support value step.",
+ "InvalidStateError"
+ ]);
+ }
+
+ const min = this._minimum;
+ const max = this._maximum;
+
+ if (min !== null && max !== null) {
+ if (min > max) {
+ return;
+ }
+
+ const candidateStepValue = this._stepAlign(Decimal.add(min, allowedValueStep), /* roundUp = */ false);
+ if (candidateStepValue.lt(min) || candidateStepValue.gt(max)) {
+ return;
+ }
+ }
+
+ let value = 0;
+ try {
+ value = this.valueAsNumber;
+ if (isNaN(value)) { // Empty value is parsed as NaN.
+ value = 0;
+ }
+ } catch (error) {
+ // Step 5. Default value is 0.
+ }
+ value = new Decimal(value);
+
+ const valueBeforeStepping = value;
+
+ if (!this._isStepAligned(value)) {
+ value = this._stepAlign(value, /* roundUp = */ isUp);
+ } else {
+ let delta = Decimal.mul(n, allowedValueStep);
+ if (!isUp) {
+ delta = delta.neg();
+ }
+ value = value.add(delta);
+ }
+
+ if (min !== null && value.lt(min)) {
+ value = this._stepAlign(min, /* roundUp = */ true);
+ }
+
+ if (max !== null && value.gt(max)) {
+ value = this._stepAlign(max, /* roundUp = */ false);
+ }
+
+ if (isUp ? value.lt(valueBeforeStepping) : value.gt(valueBeforeStepping)) {
+ return;
+ }
+
+ this._value = this._convertNumberToString(value.toNumber());
+ }
+
+ stepDown(n = 1) {
+ return this._stepUpdate(n, false);
+ }
+
+ stepUp(n = 1) {
+ return this._stepUpdate(n, true);
+ }
+
+ get files() {
+ if (this.type === "file") {
+ this[filesSymbol] = this[filesSymbol] || FileList.createImpl(this._globalObject);
+ } else {
+ this[filesSymbol] = null;
+ }
+ return this[filesSymbol];
+ }
+
+ set files(value) {
+ if (this.type === "file" && value !== null) {
+ this[filesSymbol] = value;
+ }
+ }
+
+ get type() {
+ const typeAttribute = this.getAttributeNS(null, "type");
+ return getTypeFromAttribute(typeAttribute);
+ }
+
+ set type(type) {
+ this.setAttributeNS(null, "type", type);
+ }
+
+ _dispatchSelectEvent() {
+ fireAnEvent("select", this, undefined, { bubbles: true, cancelable: true });
+ }
+
+ _getValueLength() {
+ return typeof this.value === "string" ? this.value.length : 0;
+ }
+
+ select() {
+ if (!this._idlMemberApplies("select")) {
+ return;
+ }
+
+ this._selectionStart = 0;
+ this._selectionEnd = this._getValueLength();
+ this._selectionDirection = "none";
+ this._dispatchSelectEvent();
+ }
+
+ get selectionStart() {
+ if (!this._idlMemberApplies("selectionStart")) {
+ return null;
+ }
+
+ return this._selectionStart;
+ }
+
+ set selectionStart(start) {
+ if (!this._idlMemberApplies("selectionStart")) {
+ throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
+ }
+
+ this.setSelectionRange(start, Math.max(start, this._selectionEnd), this._selectionDirection);
+ }
+
+ get selectionEnd() {
+ if (!this._idlMemberApplies("selectionEnd")) {
+ return null;
+ }
+
+ return this._selectionEnd;
+ }
+
+ set selectionEnd(end) {
+ if (!this._idlMemberApplies("selectionEnd")) {
+ throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
+ }
+
+ this.setSelectionRange(this._selectionStart, end, this._selectionDirection);
+ }
+
+ get selectionDirection() {
+ if (!this._idlMemberApplies("selectionDirection")) {
+ return null;
+ }
+
+ return this._selectionDirection;
+ }
+
+ set selectionDirection(dir) {
+ if (!this._idlMemberApplies("selectionDirection")) {
+ throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
+ }
+
+ this.setSelectionRange(this._selectionStart, this._selectionEnd, dir);
+ }
+
+ setSelectionRange(start, end, dir) {
+ if (!this._idlMemberApplies("setSelectionRange")) {
+ throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
+ }
+
+ this._selectionEnd = Math.min(end, this._getValueLength());
+ this._selectionStart = Math.min(start, this._selectionEnd);
+ this._selectionDirection = dir === "forward" || dir === "backward" ? dir : "none";
+ this._dispatchSelectEvent();
+ }
+
+ setRangeText(repl, start, end, selectionMode = "preserve") {
+ if (!this._idlMemberApplies("setRangeText")) {
+ throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
+ }
+
+ if (arguments.length < 2) {
+ start = this._selectionStart;
+ end = this._selectionEnd;
+ } else if (start > end) {
+ throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+ }
+
+ start = Math.min(start, this._getValueLength());
+ end = Math.min(end, this._getValueLength());
+
+ const val = this.value;
+ let selStart = this._selectionStart;
+ let selEnd = this._selectionEnd;
+
+ this.value = val.slice(0, start) + repl + val.slice(end);
+
+ const newEnd = start + this.value.length;
+
+ if (selectionMode === "select") {
+ this.setSelectionRange(start, newEnd);
+ } else if (selectionMode === "start") {
+ this.setSelectionRange(start, start);
+ } else if (selectionMode === "end") {
+ this.setSelectionRange(newEnd, newEnd);
+ } else { // preserve
+ const delta = repl.length - (end - start);
+
+ if (selStart > end) {
+ selStart += delta;
+ } else if (selStart > start) {
+ selStart = start;
+ }
+
+ if (selEnd > end) {
+ selEnd += delta;
+ } else if (selEnd > start) {
+ selEnd = newEnd;
+ }
+
+ this.setSelectionRange(selStart, selEnd);
+ }
+ }
+
+ // https://html.spec.whatwg.org/multipage/input.html#the-list-attribute
+ get list() {
+ const id = this._getAttributeIfApplies("list");
+ if (!id) {
+ return null;
+ }
+
+ const el = this.getRootNode({}).getElementById(id);
+
+ if (el && el.localName === "datalist") {
+ return el;
+ }
+
+ return null;
+ }
+
+ // Reflected IDL attribute does not care about whether the content attribute applies.
+ get maxLength() {
+ if (!this.hasAttributeNS(null, "maxlength")) {
+ return 524288; // stole this from chrome
+ }
+ return parseInt(this.getAttributeNS(null, "maxlength"));
+ }
+
+ set maxLength(value) {
+ if (value < 0) {
+ throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+ }
+ this.setAttributeNS(null, "maxlength", String(value));
+ }
+
+ get minLength() {
+ if (!this.hasAttributeNS(null, "minlength")) {
+ return 0;
+ }
+ return parseInt(this.getAttributeNS(null, "minlength"));
+ }
+
+ set minLength(value) {
+ if (value < 0) {
+ throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+ }
+ this.setAttributeNS(null, "minlength", String(value));
+ }
+
+ get size() {
+ if (!this.hasAttributeNS(null, "size")) {
+ return 20;
+ }
+ return parseInt(this.getAttributeNS(null, "size"));
+ }
+
+ set size(value) {
+ if (value <= 0) {
+ throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+ }
+ this.setAttributeNS(null, "size", String(value));
+ }
+
+ // https://html.spec.whatwg.org/multipage/input.html#the-min-and-max-attributes
+ get _minimum() {
+ let min = this._defaultMinimum;
+ const attr = this._getAttributeIfApplies("min");
+ if (attr !== null && this._convertStringToNumber !== undefined) {
+ const parsed = this._convertStringToNumber(attr);
+ if (parsed !== null) {
+ min = parsed;
+ }
+ }
+ return min;
+ }
+
+ get _maximum() {
+ let max = this._defaultMaximum;
+ const attr = this._getAttributeIfApplies("max");
+ if (attr !== null && this._convertStringToNumber !== undefined) {
+ const parsed = this._convertStringToNumber(attr);
+ if (parsed !== null) {
+ max = parsed;
+ }
+ }
+ return max;
+ }
+
+ get _defaultMinimum() {
+ if (this.type === "range") {
+ return 0;
+ }
+ return null;
+ }
+
+ get _defaultMaximum() {
+ if (this.type === "range") {
+ return 100;
+ }
+ return null;
+ }
+
+ // https://html.spec.whatwg.org/multipage/input.html#concept-input-step
+ get _allowedValueStep() {
+ if (!this._contentAttributeApplies("step")) {
+ return null;
+ }
+ const attr = this.getAttributeNS(null, "step");
+ if (attr === null) {
+ return this._defaultStep * this._stepScaleFactor;
+ }
+ if (asciiCaseInsensitiveMatch(attr, "any")) {
+ return null;
+ }
+ const parsedStep = parseFloatingPointNumber(attr);
+ if (parsedStep === null || parsedStep <= 0) {
+ return this._defaultStep * this._stepScaleFactor;
+ }
+ return parsedStep * this._stepScaleFactor;
+ }
+
+ // https://html.spec.whatwg.org/multipage/input.html#concept-input-step-scale
+ get _stepScaleFactor() {
+ const dayInMilliseconds = 24 * 60 * 60 * 1000;
+ switch (this.type) {
+ case "week":
+ return 7 * dayInMilliseconds;
+ case "date":
+ return dayInMilliseconds;
+ case "datetime-local":
+ case "datetime":
+ case "time":
+ return 1000;
+ }
+ return 1;
+ }
+
+ // https://html.spec.whatwg.org/multipage/input.html#concept-input-step-default
+ get _defaultStep() {
+ if (this.type === "datetime-local" || this.type === "datetime" || this.type === "time") {
+ return 60;
+ }
+ return 1;
+ }
+
+ // https://html.spec.whatwg.org/multipage/input.html#concept-input-min-zero
+ get _stepBase() {
+ if (this._hasAttributeAndApplies("min")) {
+ const min = this._convertStringToNumber(this.getAttributeNS(null, "min"));
+ if (min !== null) {
+ return min;
+ }
+ }
+ if (this.hasAttributeNS(null, "value")) {
+ const value = this._convertStringToNumber(this.getAttributeNS(null, "value"));
+ if (value !== null) {
+ return value;
+ }
+ }
+ if (this._defaultStepBase !== null) {
+ return this._defaultStepBase;
+ }
+ return 0;
+ }
+
+ // https://html.spec.whatwg.org/multipage/input.html#concept-input-step-default-base
+ get _defaultStepBase() {
+ if (this.type === "week") {
+ // The start of week 1970-W01
+ return -259200000;
+ }
+ return null;
+ }
+
+ // https://html.spec.whatwg.org/multipage/input.html#common-input-element-attributes
+ // When an attribute doesn't apply to an input element, user agents must ignore the attribute.
+ _contentAttributeApplies(attribute) {
+ return applicableTypesForContentAttribute[attribute].has(this.type);
+ }
+
+ _hasAttributeAndApplies(attribute) {
+ return this._contentAttributeApplies(attribute) && this.hasAttributeNS(null, attribute);
+ }
+
+ _getAttributeIfApplies(attribute) {
+ if (this._contentAttributeApplies(attribute)) {
+ return this.getAttributeNS(null, attribute);
+ }
+ return null;
+ }
+
+ _idlMemberApplies(member, type = this.type) {
+ return applicableTypesForIDLMember[member].has(type);
+ }
+
+ _barredFromConstraintValidationSpecialization() {
+ // https://html.spec.whatwg.org/multipage/input.html#hidden-state-(type=hidden)
+ // https://html.spec.whatwg.org/multipage/input.html#reset-button-state-(type=reset)
+ // https://html.spec.whatwg.org/multipage/input.html#button-state-(type=button)
+ const willNotValidateTypes = new Set(["hidden", "reset", "button"]);
+ // https://html.spec.whatwg.org/multipage/input.html#attr-input-readonly
+ const readOnly = this._hasAttributeAndApplies("readonly");
+
+ // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-disabled
+ return willNotValidateTypes.has(this.type) || readOnly;
+ }
+
+ // https://html.spec.whatwg.org/multipage/input.html#concept-input-required
+ get _required() {
+ return this._hasAttributeAndApplies("required");
+ }
+
+ // https://html.spec.whatwg.org/multipage/input.html#has-a-periodic-domain
+ get _hasAPeriodicDomain() {
+ return this.type === "time";
+ }
+
+ // https://html.spec.whatwg.org/multipage/input.html#has-a-reversed-range
+ get _hasAReversedRange() {
+ return this._hasAPeriodicDomain && this._maximum < this._minimum;
+ }
+
+ get validity() {
+ if (!this._validity) {
+ // Constraint validation: When an element has a reversed range, and the result of applying
+ // the algorithm to convert a string to a number to the string given by the element's value
+ // is a number, and the number obtained from that algorithm is more than the maximum and less
+ // than the minimum, the element is simultaneously suffering from an underflow and suffering
+ // from an overflow.
+ const reversedRangeSufferingOverUnderflow = () => {
+ const parsedValue = this._convertStringToNumber(this._value);
+ return parsedValue !== null && parsedValue > this._maximum && parsedValue < this._minimum;
+ };
+
+ const state = {
+ // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-being-missing
+ valueMissing: () => {
+ // https://html.spec.whatwg.org/multipage/input.html#the-required-attribute
+ // Constraint validation: If the element is required, and its value IDL attribute applies
+ // and is in the mode value, and the element is mutable, and the element's value is the
+ // empty string, then the element is suffering from being missing.
+ //
+ // Note: As of today, the value IDL attribute always applies.
+ if (this._required && valueAttributeMode(this.type) === "value" && this._mutable && this._value === "") {
+ return true;
+ }
+
+ switch (this.type) {
+ // https://html.spec.whatwg.org/multipage/input.html#checkbox-state-(type=checkbox)
+ // Constraint validation: If the element is required and its checkedness is
+ // false, then the element is suffering from being missing.
+ case "checkbox":
+ if (this._required && !this._checkedness) {
+ return true;
+ }
+ break;
+
+ // https://html.spec.whatwg.org/multipage/input.html#radio-button-state-(type=radio)
+ // Constraint validation: If an element in the radio button group is required,
+ // and all of the input elements in the radio button group have a checkedness
+ // that is false, then the element is suffering from being missing.
+ case "radio":
+ if (this._someInRadioGroup("_required") && !this._someInRadioGroup("checked")) {
+ return true;
+ }
+ break;
+
+ // https://html.spec.whatwg.org/multipage/input.html#file-upload-state-(type=file)
+ // Constraint validation: If the element is required and the list of selected files is
+ // empty, then the element is suffering from being missing.
+ case "file":
+ if (this._required && this.files.length === 0) {
+ return true;
+ }
+ break;
+ }
+
+ return false;
+ },
+
+ // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-being-too-long
+ // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-maxlength
+ // jsdom has no way at the moment to emulate a user interaction, so tooLong/tooShort have
+ // to be set to false.
+ tooLong: () => false,
+
+ // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-being-too-short
+ // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-minlength
+ tooShort: () => false,
+
+ // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-an-overflow
+ rangeOverflow: () => {
+ // https://html.spec.whatwg.org/multipage/input.html#the-min-and-max-attributes
+ if (this._hasAReversedRange) {
+ return reversedRangeSufferingOverUnderflow();
+ }
+ // Constraint validation: When the element has a maximum and does not have a reversed
+ // range, and the result of applying the algorithm to convert a string to a number to the
+ // string given by the element's value is a number, and the number obtained from that
+ // algorithm is more than the maximum, the element is suffering from an overflow.
+ if (this._maximum !== null) {
+ const parsedValue = this._convertStringToNumber(this._value);
+ if (parsedValue !== null && parsedValue > this._maximum) {
+ return true;
+ }
+ }
+ return false;
+ },
+
+ // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-an-underflow
+ rangeUnderflow: () => {
+ // https://html.spec.whatwg.org/multipage/input.html#the-min-and-max-attributes
+ if (this._hasAReversedRange) {
+ return reversedRangeSufferingOverUnderflow();
+ }
+ // Constraint validation: When the element has a minimum and does not have a reversed
+ // range, and the result of applying the algorithm to convert a string to a number to the
+ // string given by the element's value is a number, and the number obtained from that
+ // algorithm is less than the minimum, the element is suffering from an underflow.
+ if (this._minimum !== null) {
+ const parsedValue = this._convertStringToNumber(this._value);
+ if (parsedValue !== null && parsedValue < this._minimum) {
+ return true;
+ }
+ }
+ return false;
+ },
+
+ // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-a-pattern-mismatch
+ patternMismatch: () => {
+ // https://html.spec.whatwg.org/multipage/input.html#the-pattern-attribute
+ if (this._value === "" || !this._hasAttributeAndApplies("pattern")) {
+ return false;
+ }
+ let regExp;
+ try {
+ const pattern = this.getAttributeNS(null, "pattern");
+ // The pattern attribute should be matched against the entire value, not just any
+ // subset, so add ^ and $ anchors. But also check the validity of the regex itself
+ // first.
+ new RegExp(pattern, "u"); // eslint-disable-line no-new
+ regExp = new RegExp("^(?:" + pattern + ")$", "u");
+ } catch (e) {
+ return false;
+ }
+ if (this._hasAttributeAndApplies("multiple")) {
+ return !splitOnCommas(this._value).every(value => regExp.test(value));
+ }
+ return !regExp.test(this._value);
+ },
+
+ // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-a-step-mismatch
+ // https://html.spec.whatwg.org/multipage/input.html#attr-input-step
+ stepMismatch: () => {
+ const allowedValueStep = this._allowedValueStep;
+ if (allowedValueStep === null) {
+ return false;
+ }
+ const number = this._convertStringToNumber(this._value);
+ return number !== null && !this._isStepAligned(number);
+ },
+
+ // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-a-type-mismatch
+ typeMismatch: () => {
+ switch (this.type) {
+ // https://html.spec.whatwg.org/multipage/input.html#url-state-(type=url)
+ // Constraint validation: While the value of the element is neither the empty string
+ // nor a valid absolute URL, the element is suffering from a type mismatch.
+ case "url":
+ if (this._value !== "" && !isValidAbsoluteURL(this._value)) {
+ return true;
+ }
+ break;
+
+ // https://html.spec.whatwg.org/multipage/input.html#e-mail-state-(type=email)
+ // Constraint validation [multiple=false]: While the value of the element is neither the empty
+ // string nor a single valid e - mail address, the element is suffering from a type mismatch.
+ // Constraint validation [multiple=true]: While the value of the element is not a valid e-mail address list,
+ // the element is suffering from a type mismatch.
+ case "email":
+ if (this._value !== "" && !isValidEmailAddress(this._getValue(), this.hasAttributeNS(null, "multiple"))) {
+ return true;
+ }
+ break;
+ }
+ return false;
+ }
+ };
+
+ this._validity = ValidityState.createImpl(this._globalObject, [], {
+ element: this,
+ state
+ });
+ }
+ return this._validity;
+ }
+
+ [cloningSteps](copy, node) {
+ copy._value = node._value;
+ copy._checkedness = node._checkedness;
+ copy._dirtyValue = node._dirtyValue;
+ copy._dirtyCheckedness = node._dirtyCheckedness;
+ }
+}
+
+mixin(HTMLInputElementImpl.prototype, DefaultConstraintValidationImpl.prototype);
+
+module.exports = {
+ implementation: HTMLInputElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLIElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLIElement-impl.js
new file mode 100644
index 0000000..e592582
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLIElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLLIElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLLIElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLabelElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLabelElement-impl.js
new file mode 100644
index 0000000..ba6bcb4
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLabelElement-impl.js
@@ -0,0 +1,94 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const MouseEvent = require("../generated/MouseEvent");
+const { domSymbolTree } = require("../helpers/internal-constants");
+const NODE_TYPE = require("../node-type");
+const { isLabelable, isDisabled, isInteractiveContent } = require("../helpers/form-controls");
+const { isInclusiveAncestor } = require("../helpers/node");
+const { fireAnEvent } = require("../helpers/events");
+
+function sendClickToAssociatedNode(node) {
+ fireAnEvent("click", node, MouseEvent, {
+ bubbles: true,
+ cancelable: true,
+ view: node.ownerDocument ? node.ownerDocument.defaultView : null,
+ screenX: 0,
+ screenY: 0,
+ clientX: 0,
+ clientY: 0,
+ button: 0,
+ detail: 1,
+ relatedTarget: null
+ });
+}
+
+class HTMLLabelElementImpl extends HTMLElementImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+
+ this._hasActivationBehavior = true;
+ }
+
+ get control() {
+ if (this.hasAttributeNS(null, "for")) {
+ const forValue = this.getAttributeNS(null, "for");
+ if (forValue === "") {
+ return null;
+ }
+ const root = this.getRootNode({});
+ for (const descendant of domSymbolTree.treeIterator(root)) {
+ if (descendant.nodeType === NODE_TYPE.ELEMENT_NODE &&
+ descendant.getAttributeNS(null, "id") === forValue) {
+ return isLabelable(descendant) ? descendant : null;
+ }
+ }
+ return null;
+ }
+ for (const descendant of domSymbolTree.treeIterator(this)) {
+ if (isLabelable(descendant)) {
+ return descendant;
+ }
+ }
+ return null;
+ }
+
+ get form() {
+ const node = this.control;
+ if (node) {
+ return node.form;
+ }
+ return null;
+ }
+
+ _activationBehavior(event) {
+ // Check if the event's target is an inclusive descendant of any interactive content descendant of this <label>.
+ // If so, do nothing.
+ if (event.target && event.target !== this && isInclusiveAncestor(this, event.target)) {
+ for (const ancestor of domSymbolTree.ancestorsIterator(event.target)) {
+ if (ancestor === this) {
+ break;
+ }
+ if (isInteractiveContent(ancestor)) {
+ return;
+ }
+ }
+ }
+
+ const node = this.control;
+ if (node && !isDisabled(node)) {
+ // Check if the control is an inclusive ancestor of the event's target (and has already received this event).
+ // If so, do nothing.
+ // See https://github.com/whatwg/html/issues/5415.
+ if (event.target && isInclusiveAncestor(node, event.target)) {
+ return;
+ }
+
+ sendClickToAssociatedNode(node);
+ }
+ }
+}
+
+module.exports = {
+ implementation: HTMLLabelElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLegendElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLegendElement-impl.js
new file mode 100644
index 0000000..e4d23dc
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLegendElement-impl.js
@@ -0,0 +1,18 @@
+"use strict";
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const { formOwner } = require("../helpers/form-controls");
+const { HTML_NS } = require("../helpers/namespaces");
+
+class HTMLLegendElementImpl extends HTMLElementImpl {
+ get form() {
+ const parent = this.parentNode;
+ if (parent && parent._localName === "fieldset" && parent.namespaceURI === HTML_NS) {
+ return formOwner(parent);
+ }
+ return null;
+ }
+}
+
+module.exports = {
+ implementation: HTMLLegendElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLinkElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLinkElement-impl.js
new file mode 100644
index 0000000..53e0b67
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLinkElement-impl.js
@@ -0,0 +1,101 @@
+"use strict";
+const DOMTokenList = require("../generated/DOMTokenList");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const idlUtils = require("../generated/utils");
+const { fetchStylesheet } = require("../helpers/stylesheets");
+const { parseURLToResultingURLRecord } = require("../helpers/document-base-url");
+const whatwgURL = require("whatwg-url");
+
+// Important reading: "appropriate times to obtain the resource" in
+// https://html.spec.whatwg.org/multipage/semantics.html#link-type-stylesheet
+
+class HTMLLinkElementImpl extends HTMLElementImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+
+ this.sheet = null;
+ }
+
+ get relList() {
+ if (this._relList === undefined) {
+ this._relList = DOMTokenList.createImpl(this._globalObject, [], {
+ element: this,
+ attributeLocalName: "rel",
+ supportedTokens: new Set(["stylesheet"])
+ });
+ }
+ return this._relList;
+ }
+
+ _attach() {
+ super._attach();
+ maybeFetchAndProcess(this);
+ }
+
+ _attrModified(name, value, oldValue) {
+ super._attrModified(name, value, oldValue);
+
+ if (name === "href") { // TODO crossorigin="" or type=""
+ maybeFetchAndProcess(this);
+ }
+
+ if (name === "rel" && this._relList !== undefined) {
+ this._relList.attrModified();
+ }
+ }
+
+ get _accept() {
+ return "text/css,*/*;q=0.1";
+ }
+}
+
+module.exports = {
+ implementation: HTMLLinkElementImpl
+};
+
+// https://html.spec.whatwg.org/multipage/links.html#link-type-stylesheet
+function maybeFetchAndProcess(el) {
+ if (!isExternalResourceLink(el)) {
+ return;
+ }
+
+ // Browsing-context connected
+ if (!el.isConnected || !el._ownerDocument._defaultView) {
+ return;
+ }
+
+ fetchAndProcess(el);
+}
+
+// https://html.spec.whatwg.org/multipage/semantics.html#default-fetch-and-process-the-linked-resource
+// TODO: refactor into general link-fetching like the spec.
+function fetchAndProcess(el) {
+ const href = el.getAttributeNS(null, "href");
+
+ if (href === null || href === "") {
+ return;
+ }
+
+ const url = parseURLToResultingURLRecord(href, el._ownerDocument);
+ if (url === null) {
+ return;
+ }
+
+ // TODO handle crossorigin="", nonce, integrity="", referrerpolicy=""
+
+ const serialized = whatwgURL.serializeURL(url);
+
+ fetchStylesheet(el, serialized);
+}
+
+function isExternalResourceLink(el) {
+ // for our purposes, only stylesheets can be external resource links
+ const wrapper = idlUtils.wrapperForImpl(el);
+ if (!/(?:[ \t\n\r\f]|^)stylesheet(?:[ \t\n\r\f]|$)/i.test(wrapper.rel)) {
+ // rel is a space-separated list of tokens, and the original rel types
+ // are case-insensitive.
+ return false;
+ }
+
+ return el.hasAttributeNS(null, "href");
+}
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMapElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMapElement-impl.js
new file mode 100644
index 0000000..b431dad
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMapElement-impl.js
@@ -0,0 +1,13 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLMapElementImpl extends HTMLElementImpl {
+ get areas() {
+ return this.getElementsByTagName("AREA");
+ }
+}
+
+module.exports = {
+ implementation: HTMLMapElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMarqueeElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMarqueeElement-impl.js
new file mode 100644
index 0000000..66371cb
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMarqueeElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLMarqueeElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLMarqueeElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMediaElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMediaElement-impl.js
new file mode 100644
index 0000000..d3ddda8
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMediaElement-impl.js
@@ -0,0 +1,138 @@
+"use strict";
+const DOMException = require("domexception/webidl2js-wrapper");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const notImplemented = require("../../browser/not-implemented");
+const { fireAnEvent } = require("../helpers/events");
+
+function getTimeRangeDummy() {
+ return {
+ length: 0,
+ start() {
+ return 0;
+ },
+ end() {
+ return 0;
+ }
+ };
+}
+
+class HTMLMediaElementImpl extends HTMLElementImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+
+ this._muted = false;
+ this._volume = 1.0;
+ this.readyState = 0;
+ this.networkState = 0;
+ this.currentTime = 0;
+ this.currentSrc = "";
+ this.buffered = getTimeRangeDummy();
+ this.seeking = false;
+ this.duration = NaN;
+ this.paused = true;
+ this.played = getTimeRangeDummy();
+ this.seekable = getTimeRangeDummy();
+ this.ended = false;
+ this.audioTracks = [];
+ this.videoTracks = [];
+ this.textTracks = [];
+ }
+
+ get defaultPlaybackRate() {
+ if (this._defaultPlaybackRate === undefined) {
+ return 1.0;
+ }
+ return this._defaultPlaybackRate;
+ }
+
+ set defaultPlaybackRate(v) {
+ if (v === 0.0) {
+ throw DOMException.create(this._globalObject, ["The operation is not supported.", "NotSupportedError"]);
+ }
+ if (this._defaultPlaybackRate !== v) {
+ this._defaultPlaybackRate = v;
+ this._dispatchRateChange();
+ }
+ }
+
+ get playbackRate() {
+ if (this._playbackRate === undefined) {
+ return 1.0;
+ }
+ return this._playbackRate;
+ }
+
+ set playbackRate(v) {
+ if (v !== this._playbackRate) {
+ this._playbackRate = v;
+ this._dispatchRateChange();
+ }
+ }
+
+ get muted() {
+ return this._muted;
+ }
+
+ set muted(v) {
+ if (v !== this._muted) {
+ this._muted = v;
+ this._dispatchVolumeChange();
+ }
+ }
+
+ get defaultMuted() {
+ return this.getAttributeNS(null, "muted") !== null;
+ }
+
+ set defaultMuted(v) {
+ if (v) {
+ this.setAttributeNS(null, "muted", v);
+ } else {
+ this.removeAttributeNS(null, "muted");
+ }
+ }
+
+ get volume() {
+ return this._volume;
+ }
+
+ set volume(v) {
+ if (v < 0 || v > 1) {
+ throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+ }
+ if (this._volume !== v) {
+ this._volume = v;
+ this._dispatchVolumeChange();
+ }
+ }
+
+ // Not (yet) implemented according to spec
+ // Should return sane default values
+ load() {
+ notImplemented("HTMLMediaElement.prototype.load", this._ownerDocument._defaultView);
+ }
+ canPlayType() {
+ return "";
+ }
+ play() {
+ notImplemented("HTMLMediaElement.prototype.play", this._ownerDocument._defaultView);
+ }
+ pause() {
+ notImplemented("HTMLMediaElement.prototype.pause", this._ownerDocument._defaultView);
+ }
+ addTextTrack() {
+ notImplemented("HTMLMediaElement.prototype.addTextTrack", this._ownerDocument._defaultView);
+ }
+
+ _dispatchRateChange() {
+ fireAnEvent("ratechange", this);
+ }
+
+ _dispatchVolumeChange() {
+ fireAnEvent("volumechange", this);
+ }
+}
+
+module.exports = {
+ implementation: HTMLMediaElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMenuElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMenuElement-impl.js
new file mode 100644
index 0000000..4faf848
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMenuElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLMenuElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLMenuElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMetaElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMetaElement-impl.js
new file mode 100644
index 0000000..ff038f2
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMetaElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLMetaElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLMetaElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMeterElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMeterElement-impl.js
new file mode 100644
index 0000000..25aeef0
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMeterElement-impl.js
@@ -0,0 +1,180 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const { parseFloatingPointNumber } = require("../helpers/strings");
+const { getLabelsForLabelable } = require("../helpers/form-controls");
+
+class HTMLMeterElementImpl extends HTMLElementImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+ this._labels = null;
+ }
+
+ // https://html.spec.whatwg.org/multipage/form-elements.html#concept-meter-minimum
+ get _minimumValue() {
+ const min = this.getAttributeNS(null, "min");
+ if (min !== null) {
+ const parsed = parseFloatingPointNumber(min);
+ if (parsed !== null) {
+ return parsed;
+ }
+ }
+ return 0;
+ }
+
+ // https://html.spec.whatwg.org/multipage/form-elements.html#concept-meter-maximum
+ get _maximumValue() {
+ let candidate = 1.0;
+
+ const max = this.getAttributeNS(null, "max");
+ if (max !== null) {
+ const parsed = parseFloatingPointNumber(max);
+ if (parsed !== null) {
+ candidate = parsed;
+ }
+ }
+
+ const minimumValue = this._minimumValue;
+ return candidate >= minimumValue ? candidate : minimumValue;
+ }
+
+ // https://html.spec.whatwg.org/multipage/form-elements.html#concept-meter-actual
+ get _actualValue() {
+ let candidate = 0;
+
+ const value = this.getAttributeNS(null, "value");
+ if (value !== null) {
+ const parsed = parseFloatingPointNumber(value);
+ if (parsed !== null) {
+ candidate = parsed;
+ }
+ }
+
+ const minimumValue = this._minimumValue;
+ if (candidate < minimumValue) {
+ return minimumValue;
+ }
+
+ const maximumValue = this._maximumValue;
+ return candidate > maximumValue ? maximumValue : candidate;
+ }
+
+ // https://html.spec.whatwg.org/multipage/form-elements.html#concept-meter-low
+ get _lowBoundary() {
+ const minimumValue = this._minimumValue;
+ let candidate = minimumValue;
+
+ const low = this.getAttributeNS(null, "low");
+ if (low !== null) {
+ const parsed = parseFloatingPointNumber(low);
+ if (parsed !== null) {
+ candidate = parsed;
+ }
+ }
+
+ if (candidate < minimumValue) {
+ return minimumValue;
+ }
+
+ const maximumValue = this._maximumValue;
+ return candidate > maximumValue ? maximumValue : candidate;
+ }
+
+ // https://html.spec.whatwg.org/multipage/form-elements.html#concept-meter-high
+ get _highBoundary() {
+ const maximumValue = this._maximumValue;
+ let candidate = maximumValue;
+
+ const high = this.getAttributeNS(null, "high");
+ if (high !== null) {
+ const parsed = parseFloatingPointNumber(high);
+ if (parsed !== null) {
+ candidate = parsed;
+ }
+ }
+
+ const lowBoundary = this._lowBoundary;
+ if (candidate < lowBoundary) {
+ return lowBoundary;
+ }
+
+ return candidate > maximumValue ? maximumValue : candidate;
+ }
+
+ // https://html.spec.whatwg.org/multipage/form-elements.html#concept-meter-optimum
+ get _optimumPoint() {
+ const minimumValue = this._minimumValue;
+ const maximumValue = this._maximumValue;
+ let candidate = (minimumValue + maximumValue) / 2;
+
+ const optimum = this.getAttributeNS(null, "optimum");
+ if (optimum !== null) {
+ const parsed = parseFloatingPointNumber(optimum);
+ if (parsed !== null) {
+ candidate = parsed;
+ }
+ }
+
+ if (candidate < minimumValue) {
+ return minimumValue;
+ }
+
+ return candidate > maximumValue ? maximumValue : candidate;
+ }
+
+ get labels() {
+ return getLabelsForLabelable(this);
+ }
+
+ get value() {
+ return this._actualValue;
+ }
+
+ set value(val) {
+ this.setAttributeNS(null, "value", String(val));
+ }
+
+ get min() {
+ return this._minimumValue;
+ }
+
+ set min(val) {
+ this.setAttributeNS(null, "min", String(val));
+ }
+
+ get max() {
+ return this._maximumValue;
+ }
+
+ set max(val) {
+ this.setAttributeNS(null, "max", String(val));
+ }
+
+ get low() {
+ return this._lowBoundary;
+ }
+
+ set low(val) {
+ this.setAttributeNS(null, "low", String(val));
+ }
+
+ get high() {
+ return this._highBoundary;
+ }
+
+ set high(val) {
+ this.setAttributeNS(null, "high", String(val));
+ }
+
+ get optimum() {
+ return this._optimumPoint;
+ }
+
+ set optimum(val) {
+ this.setAttributeNS(null, "optimum", String(val));
+ }
+}
+
+module.exports = {
+ implementation: HTMLMeterElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLModElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLModElement-impl.js
new file mode 100644
index 0000000..a6cb046
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLModElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLModElementImpl extends HTMLElementImpl {}
+
+module.exports = {
+ implementation: HTMLModElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOListElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOListElement-impl.js
new file mode 100644
index 0000000..b7d207f
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOListElement-impl.js
@@ -0,0 +1,22 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLOListElementImpl extends HTMLElementImpl {
+ get start() {
+ const value = parseInt(this.getAttributeNS(null, "start"));
+
+ if (!isNaN(value)) {
+ return value;
+ }
+
+ return 1;
+ }
+ set start(value) {
+ this.setAttributeNS(null, "start", value);
+ }
+}
+
+module.exports = {
+ implementation: HTMLOListElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLObjectElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLObjectElement-impl.js
new file mode 100644
index 0000000..f9e2249
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLObjectElement-impl.js
@@ -0,0 +1,26 @@
+"use strict";
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const DefaultConstraintValidationImpl =
+ require("../constraint-validation/DefaultConstraintValidation-impl").implementation;
+const { mixin } = require("../../utils");
+const { formOwner } = require("../helpers/form-controls");
+
+class HTMLObjectElementImpl extends HTMLElementImpl {
+ get form() {
+ return formOwner(this);
+ }
+
+ get contentDocument() {
+ return null;
+ }
+
+ _barredFromConstraintValidationSpecialization() {
+ return true;
+ }
+}
+
+mixin(HTMLObjectElementImpl.prototype, DefaultConstraintValidationImpl.prototype);
+
+module.exports = {
+ implementation: HTMLObjectElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOptGroupElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOptGroupElement-impl.js
new file mode 100644
index 0000000..28d9348
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOptGroupElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLOptGroupElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLOptGroupElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOptionElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOptionElement-impl.js
new file mode 100644
index 0000000..8ce4d87
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOptionElement-impl.js
@@ -0,0 +1,146 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const NODE_TYPE = require("../node-type");
+const { stripAndCollapseASCIIWhitespace } = require("../helpers/strings");
+const { domSymbolTree } = require("../helpers/internal-constants");
+const { HTML_NS, SVG_NS } = require("../helpers/namespaces");
+const { closest } = require("../helpers/traversal");
+const { formOwner } = require("../helpers/form-controls");
+
+class HTMLOptionElementImpl extends HTMLElementImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+
+ // whenever selectedness is set to true, make sure all
+ // other options set selectedness to false
+ this._selectedness = false;
+ this._dirtyness = false;
+ }
+
+ _removeOtherSelectedness() {
+ // Remove the selectedness flag from all other options in this select
+ const select = this._selectNode;
+
+ if (select && !select.hasAttributeNS(null, "multiple")) {
+ for (const option of select.options) {
+ if (option !== this) {
+ option._selectedness = false;
+ }
+ }
+ }
+ }
+
+ _askForAReset() {
+ const select = this._selectNode;
+ if (select) {
+ select._askedForAReset();
+ }
+ }
+
+ _attrModified(name, value, oldValue) {
+ if (!this._dirtyness && name === "selected") {
+ this._selectedness = this.hasAttributeNS(null, "selected");
+ if (this._selectedness) {
+ this._removeOtherSelectedness();
+ }
+ this._askForAReset();
+ }
+ super._attrModified(name, value, oldValue);
+ }
+
+ get _selectNode() {
+ let select = domSymbolTree.parent(this);
+ if (!select) {
+ return null;
+ }
+
+ if (select.nodeName.toUpperCase() !== "SELECT") {
+ select = domSymbolTree.parent(select);
+ if (!select || select.nodeName.toUpperCase() !== "SELECT") {
+ return null;
+ }
+ }
+ return select;
+ }
+
+ get form() {
+ return formOwner(this);
+ }
+
+ get text() {
+ return stripAndCollapseASCIIWhitespace(childTextContentExcludingDescendantsOfScript(this));
+ }
+ set text(value) {
+ this.textContent = value;
+ }
+
+ // https://html.spec.whatwg.org/multipage/form-elements.html#concept-option-value
+ _getValue() {
+ if (this.hasAttributeNS(null, "value")) {
+ return this.getAttributeNS(null, "value");
+ }
+
+ return this.text;
+ }
+
+ get value() {
+ return this._getValue();
+ }
+ set value(value) {
+ this.setAttributeNS(null, "value", value);
+ }
+
+ get index() {
+ const select = closest(this, "select");
+ if (select === null) {
+ return 0;
+ }
+
+ return select.options.indexOf(this);
+ }
+
+ get selected() {
+ return this._selectedness;
+ }
+ set selected(s) {
+ this._dirtyness = true;
+ this._selectedness = Boolean(s);
+ if (this._selectedness) {
+ this._removeOtherSelectedness();
+ }
+ this._askForAReset();
+ this._modified();
+ }
+
+ get label() {
+ if (this.hasAttributeNS(null, "label")) {
+ return this.getAttributeNS(null, "label");
+ }
+
+ return this.text;
+ }
+ set label(value) {
+ this.setAttributeNS(null, "label", value);
+ }
+}
+
+function childTextContentExcludingDescendantsOfScript(root) {
+ let text = "";
+ for (const child of domSymbolTree.childrenIterator(root)) {
+ if (child._localName === "script" && (child._namespaceURI === HTML_NS || child._namespaceURI === SVG_NS)) {
+ continue;
+ }
+
+ if (child.nodeType === NODE_TYPE.TEXT_NODE || child.nodeType === NODE_TYPE.CDATA_SECTION_NODE) {
+ text += child.nodeValue;
+ } else {
+ text += childTextContentExcludingDescendantsOfScript(child);
+ }
+ }
+ return text;
+}
+
+module.exports = {
+ implementation: HTMLOptionElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOptionsCollection-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOptionsCollection-impl.js
new file mode 100644
index 0000000..67d51e7
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOptionsCollection-impl.js
@@ -0,0 +1,110 @@
+"use strict";
+
+const idlUtils = require("../generated/utils.js");
+const DOMException = require("domexception/webidl2js-wrapper");
+const { DOCUMENT_POSITION_CONTAINS, DOCUMENT_POSITION_CONTAINED_BY } = require("../node-document-position");
+const Element = require("../generated/Element");
+const Node = require("../generated/Node");
+const HTMLCollectionImpl = require("./HTMLCollection-impl").implementation;
+
+exports.implementation = class HTMLOptionsCollectionImpl extends HTMLCollectionImpl {
+ // inherits supported property indices
+ get length() {
+ this._update();
+ return this._list.length;
+ }
+ set length(value) {
+ this._update();
+ if (value > this._list.length) {
+ const doc = this._element._ownerDocument;
+ for (let i = this._list.length; i < value; i++) {
+ const el = doc.createElement("option");
+ this._element.appendChild(el);
+ }
+ } else if (value < this._list.length) {
+ for (let i = this._list.length - 1; i >= value; i--) {
+ const el = this._list[i];
+ this._element.removeChild(el);
+ }
+ }
+ }
+
+ get [idlUtils.supportedPropertyNames]() {
+ this._update();
+ const result = new Set();
+ for (const element of this._list) {
+ result.add(element.getAttributeNS(null, "id"));
+ result.add(element.getAttributeNS(null, "name"));
+ }
+ return result;
+ }
+ [idlUtils.indexedSetNew](index, value) {
+ if (value === null) {
+ this.remove(index);
+ return;
+ }
+ this._update();
+ const { length } = this._list;
+ const n = index - length;
+ if (n > 0) {
+ const doc = this._element._ownerDocument;
+ const frag = doc.createDocumentFragment();
+ // Spec says n - 1, but n seems to be the right number here.
+ for (let i = 0; i < n; i++) {
+ const el = doc.createElement("option");
+ frag.appendChild(el);
+ }
+ this._element._append(frag);
+ }
+ if (n >= 0) {
+ this._element._append(value);
+ } else {
+ this._element._replace(value, this._list[index]);
+ }
+ }
+ [idlUtils.indexedSetExisting](index, value) {
+ return this[idlUtils.indexedSetNew](index, value);
+ }
+ add(element, before) {
+ if (this._element.compareDocumentPosition(element) & DOCUMENT_POSITION_CONTAINS) {
+ throw DOMException.create(this._globalObject, [
+ "The operation would yield an incorrect node tree.",
+ "HierarchyRequestError"
+ ]);
+ }
+ if (Element.isImpl(before) && !(this._element.compareDocumentPosition(before) & DOCUMENT_POSITION_CONTAINED_BY)) {
+ throw DOMException.create(this._globalObject, ["The object can not be found here.", "NotFoundError"]);
+ }
+ if (element === before) {
+ return;
+ }
+
+ let reference = null;
+ if (Node.isImpl(before)) {
+ reference = before;
+ } else if (typeof before === "number") {
+ this._update();
+ reference = this._list[before] || null;
+ }
+
+ const parent = reference !== null ? reference.parentNode : this._element;
+ parent._preInsert(element, reference);
+ }
+ remove(index) {
+ this._update();
+ if (this._list.length === 0) {
+ return;
+ }
+ if (index < 0 || index >= this._list.length) {
+ return;
+ }
+ const element = this._list[index];
+ element.parentNode._remove(element);
+ }
+ get selectedIndex() {
+ return this._element.selectedIndex;
+ }
+ set selectedIndex(value) {
+ this._element.selectedIndex = value;
+ }
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOrSVGElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOrSVGElement-impl.js
new file mode 100644
index 0000000..1097c82
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOrSVGElement-impl.js
@@ -0,0 +1,85 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const { isSummaryForParentDetails } = require("../helpers/details");
+const focusing = require("../helpers/focusing");
+const { HTML_NS, SVG_NS } = require("../helpers/namespaces");
+const DOMStringMap = require("../generated/DOMStringMap");
+
+const tabIndexReflectAllowedHTMLElements = new Set([
+ "a", "area", "button", "frame", "iframe",
+ "input", "object", "select", "textarea"
+]);
+
+class HTMLOrSVGElementImpl {
+ _initHTMLOrSVGElement() {
+ this._tabIndex = 0;
+ this._dataset = DOMStringMap.createImpl(this._globalObject, [], { element: this });
+ }
+
+ get dataset() {
+ return this._dataset;
+ }
+
+ // TODO this should be [Reflect]able if we added default value support to webidl2js's [Reflect]
+ get tabIndex() {
+ if (!this.hasAttributeNS(null, "tabindex")) {
+ if ((this.namespaceURI === HTML_NS && (tabIndexReflectAllowedHTMLElements.has(this._localName) ||
+ (this._localName === "summary" && isSummaryForParentDetails(this)))) ||
+ (this.namespaceURI === SVG_NS && this._localName === "a")) {
+ return 0;
+ }
+ return -1;
+ }
+ return conversions.long(this.getAttributeNS(null, "tabindex"));
+ }
+
+ set tabIndex(value) {
+ this.setAttributeNS(null, "tabindex", String(value));
+ }
+
+ focus() {
+ if (!focusing.isFocusableAreaElement(this)) {
+ return;
+ }
+ const ownerDocument = this._ownerDocument;
+ const previous = ownerDocument._lastFocusedElement;
+
+ if (previous === this) {
+ return;
+ }
+
+ ownerDocument._lastFocusedElement = null;
+ if (previous) {
+ focusing.fireFocusEventWithTargetAdjustment("blur", previous, this);
+ focusing.fireFocusEventWithTargetAdjustment("focusout", previous, this, { bubbles: true });
+ } else {
+ const frameElement = ownerDocument._defaultView._frameElement;
+ if (frameElement) {
+ const frameLastFocusedElement = frameElement.ownerDocument._lastFocusedElement;
+ frameElement.ownerDocument._lastFocusedElement = null;
+ focusing.fireFocusEventWithTargetAdjustment("blur", frameLastFocusedElement, null);
+ focusing.fireFocusEventWithTargetAdjustment("focusout", frameLastFocusedElement, null, { bubbles: true });
+ frameElement.ownerDocument._lastFocusedElement = frameElement;
+ }
+ }
+
+ ownerDocument._lastFocusedElement = this;
+ focusing.fireFocusEventWithTargetAdjustment("focus", this, previous);
+ focusing.fireFocusEventWithTargetAdjustment("focusin", this, previous, { bubbles: true });
+ }
+
+ blur() {
+ if (this._ownerDocument._lastFocusedElement !== this || !focusing.isFocusableAreaElement(this)) {
+ return;
+ }
+
+ this._ownerDocument._lastFocusedElement = null;
+ focusing.fireFocusEventWithTargetAdjustment("blur", this, this._ownerDocument);
+ focusing.fireFocusEventWithTargetAdjustment("focusout", this, this._ownerDocument, { bubbles: true });
+ focusing.fireFocusEventWithTargetAdjustment("focus", this._ownerDocument, this);
+ focusing.fireFocusEventWithTargetAdjustment("focusin", this._ownerDocument, this, { bubbles: true });
+ }
+}
+
+exports.implementation = HTMLOrSVGElementImpl;
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOutputElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOutputElement-impl.js
new file mode 100644
index 0000000..9752bdb
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOutputElement-impl.js
@@ -0,0 +1,88 @@
+"use strict";
+
+const DOMTokenList = require("../generated/DOMTokenList");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const DefaultConstraintValidationImpl =
+ require("../constraint-validation/DefaultConstraintValidation-impl").implementation;
+const { mixin } = require("../../utils");
+const { getLabelsForLabelable, formOwner } = require("../helpers/form-controls");
+
+class HTMLOutputElementImpl extends HTMLElementImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+ this._labels = null;
+ this._defaultValueOverride = null;
+
+ this._customValidityErrorMessage = "";
+ }
+
+ _attrModified(name, value, oldValue) {
+ super._attrModified(name, value, oldValue);
+
+ if (name === "for" && this._htmlFor !== undefined) {
+ this._htmlFor.attrModified();
+ }
+ }
+
+ _barredFromConstraintValidationSpecialization() {
+ return true;
+ }
+
+ _formReset() {
+ this.textContent = this.defaultValue;
+ this._defaultValueOverride = null;
+ }
+
+ get htmlFor() {
+ if (this._htmlFor === undefined) {
+ this._htmlFor = DOMTokenList.createImpl(this._globalObject, [], {
+ element: this,
+ attributeLocalName: "for"
+ });
+ }
+ return this._htmlFor;
+ }
+
+ get type() {
+ return "output";
+ }
+
+ get labels() {
+ return getLabelsForLabelable(this);
+ }
+
+ get form() {
+ return formOwner(this);
+ }
+
+ get value() {
+ return this.textContent;
+ }
+
+ set value(val) {
+ this._defaultValueOverride = this.defaultValue;
+ this.textContent = val;
+ }
+
+ get defaultValue() {
+ if (this._defaultValueOverride !== null) {
+ return this._defaultValueOverride;
+ }
+ return this.textContent;
+ }
+
+ set defaultValue(val) {
+ if (this._defaultValueOverride === null) {
+ this.textContent = val;
+ return;
+ }
+
+ this._defaultValueOverride = val;
+ }
+}
+
+mixin(HTMLOutputElementImpl.prototype, DefaultConstraintValidationImpl.prototype);
+
+module.exports = {
+ implementation: HTMLOutputElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLParagraphElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLParagraphElement-impl.js
new file mode 100644
index 0000000..01495c6
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLParagraphElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLParagraphElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLParagraphElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLParamElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLParamElement-impl.js
new file mode 100644
index 0000000..05e4f8c
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLParamElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLParamElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLParamElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLPictureElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLPictureElement-impl.js
new file mode 100644
index 0000000..6d2062f
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLPictureElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLPictureElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLPictureElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLPreElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLPreElement-impl.js
new file mode 100644
index 0000000..85b11db
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLPreElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLPreElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLPreElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLProgressElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLProgressElement-impl.js
new file mode 100644
index 0000000..5090442
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLProgressElement-impl.js
@@ -0,0 +1,74 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const { getLabelsForLabelable } = require("../helpers/form-controls");
+const { parseFloatingPointNumber } = require("../helpers/strings");
+
+class HTMLProgressElementImpl extends HTMLElementImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+ this._labels = null;
+ }
+
+ get _isDeterminate() {
+ return this.hasAttributeNS(null, "value");
+ }
+
+ // https://html.spec.whatwg.org/multipage/form-elements.html#concept-progress-value
+ get _value() {
+ const valueAttr = this.getAttributeNS(null, "value");
+ const parsedValue = parseFloatingPointNumber(valueAttr);
+ if (parsedValue !== null && parsedValue > 0) {
+ return parsedValue;
+ }
+ return 0;
+ }
+
+ // https://html.spec.whatwg.org/multipage/form-elements.html#concept-progress-current-value
+ get _currentValue() {
+ const value = this._value;
+ return value > this.max ? this.max : value;
+ }
+
+ get value() {
+ if (this._isDeterminate) {
+ return this._currentValue;
+ }
+ return 0;
+ }
+ set value(value) {
+ this.setAttributeNS(null, "value", value);
+ }
+
+ get max() {
+ const max = this.getAttributeNS(null, "max");
+ if (max !== null) {
+ const parsedMax = parseFloatingPointNumber(max);
+ if (parsedMax !== null && parsedMax > 0) {
+ return parsedMax;
+ }
+ }
+ return 1.0;
+ }
+ set max(value) {
+ if (value > 0) {
+ this.setAttributeNS(null, "max", value);
+ }
+ }
+
+ get position() {
+ if (!this._isDeterminate) {
+ return -1;
+ }
+
+ return this._currentValue / this.max;
+ }
+
+ get labels() {
+ return getLabelsForLabelable(this);
+ }
+}
+
+module.exports = {
+ implementation: HTMLProgressElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLQuoteElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLQuoteElement-impl.js
new file mode 100644
index 0000000..97e96ea
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLQuoteElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLQuoteElementImpl extends HTMLElementImpl {}
+
+module.exports = {
+ implementation: HTMLQuoteElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLScriptElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLScriptElement-impl.js
new file mode 100644
index 0000000..e2e4c00
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLScriptElement-impl.js
@@ -0,0 +1,265 @@
+"use strict";
+const vm = require("vm");
+const whatwgEncoding = require("whatwg-encoding");
+const MIMEType = require("whatwg-mimetype");
+const { serializeURL } = require("whatwg-url");
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const reportException = require("../helpers/runtime-script-errors");
+const { domSymbolTree, cloningSteps } = require("../helpers/internal-constants");
+const { asciiLowercase } = require("../helpers/strings");
+const { childTextContent } = require("../helpers/text");
+const { fireAnEvent } = require("../helpers/events");
+const { parseURLToResultingURLRecord } = require("../helpers/document-base-url");
+const nodeTypes = require("../node-type");
+
+const jsMIMETypes = new Set([
+ "application/ecmascript",
+ "application/javascript",
+ "application/x-ecmascript",
+ "application/x-javascript",
+ "text/ecmascript",
+ "text/javascript",
+ "text/javascript1.0",
+ "text/javascript1.1",
+ "text/javascript1.2",
+ "text/javascript1.3",
+ "text/javascript1.4",
+ "text/javascript1.5",
+ "text/jscript",
+ "text/livescript",
+ "text/x-ecmascript",
+ "text/x-javascript"
+]);
+
+class HTMLScriptElementImpl extends HTMLElementImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+ this._alreadyStarted = false;
+ this._parserInserted = false; // set by the parser
+ }
+
+ _attach() {
+ super._attach();
+
+
+ // In our current terribly-hacky document.write() implementation, we parse in a div them move elements into the main
+ // document. Thus _eval() will bail early when it gets in _poppedOffStackOfOpenElements(), since we're not attached
+ // then. Instead, we'll let it eval here.
+ if (!this._parserInserted || this._isMovingDueToDocumentWrite) {
+ this._eval();
+ }
+ }
+
+ _canRunScript() {
+ const document = this._ownerDocument;
+ // Equivalent to the spec's "scripting is disabled" check.
+ if (!document._defaultView || document._defaultView._runScripts !== "dangerously" || document._scriptingDisabled) {
+ return false;
+ }
+
+ return true;
+ }
+
+ _fetchExternalScript() {
+ const document = this._ownerDocument;
+ const resourceLoader = document._resourceLoader;
+ const defaultEncoding = whatwgEncoding.labelToName(this.getAttributeNS(null, "charset")) || document._encoding;
+ let request;
+
+ if (!this._canRunScript()) {
+ return;
+ }
+
+ const src = this.getAttributeNS(null, "src");
+ const url = parseURLToResultingURLRecord(src, this._ownerDocument);
+ if (url === null) {
+ return;
+ }
+ const urlString = serializeURL(url);
+
+ const onLoadExternalScript = data => {
+ const { response } = request;
+ let contentType;
+
+ if (response && response.statusCode !== undefined && response.statusCode >= 400) {
+ throw new Error("Status code: " + response.statusCode);
+ }
+
+ if (response) {
+ contentType = MIMEType.parse(response.headers["content-type"]) || new MIMEType("text/plain");
+ }
+
+ const encoding = whatwgEncoding.getBOMEncoding(data) ||
+ (contentType && whatwgEncoding.labelToName(contentType.parameters.get("charset"))) ||
+ defaultEncoding;
+ const script = whatwgEncoding.decode(data, encoding);
+
+ this._innerEval(script, urlString);
+ };
+
+ request = resourceLoader.fetch(urlString, {
+ element: this,
+ onLoad: onLoadExternalScript
+ });
+ }
+
+ _fetchInternalScript() {
+ const document = this._ownerDocument;
+
+ if (!this._canRunScript()) {
+ return;
+ }
+
+ document._queue.push(null, () => {
+ this._innerEval(this.text, document.URL);
+
+ fireAnEvent("load", this);
+ }, null, false, this);
+ }
+
+ _attrModified(name, value, oldValue) {
+ super._attrModified(name, value, oldValue);
+
+ if (this._attached && !this._startedEval && name === "src" && oldValue === null && value !== null) {
+ this._fetchExternalScript();
+ }
+ }
+
+ _poppedOffStackOfOpenElements() {
+ // This seems to roughly correspond to
+ // https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-incdata:prepare-a-script, although we certainly
+ // don't implement the full semantics.
+ this._eval();
+ }
+
+ // Vaguely similar to https://html.spec.whatwg.org/multipage/scripting.html#prepare-a-script, but we have a long way
+ // to go before it's aligned.
+ _eval() {
+ if (this._alreadyStarted) {
+ return;
+ }
+
+ // TODO: this text check doesn't seem completely the same as the spec, which e.g. will try to execute scripts with
+ // child element nodes. Spec bug? https://github.com/whatwg/html/issues/3419
+ if (!this.hasAttributeNS(null, "src") && this.text.length === 0) {
+ return;
+ }
+
+ if (!this._attached) {
+ return;
+ }
+
+ const scriptBlocksTypeString = this._getTypeString();
+ const type = getType(scriptBlocksTypeString);
+
+ if (type !== "classic") {
+ // TODO: implement modules, and then change the check to `type === null`.
+ return;
+ }
+
+ this._alreadyStarted = true;
+
+ // TODO: implement nomodule here, **but only after we support modules**.
+
+ // At this point we completely depart from the spec.
+
+ if (this.hasAttributeNS(null, "src")) {
+ this._fetchExternalScript();
+ } else {
+ this._fetchInternalScript();
+ }
+ }
+
+ _innerEval(text, filename) {
+ this._ownerDocument._writeAfterElement = this;
+ processJavaScript(this, text, filename);
+ delete this._ownerDocument._writeAfterElement;
+ }
+
+ _getTypeString() {
+ const typeAttr = this.getAttributeNS(null, "type");
+ const langAttr = this.getAttributeNS(null, "language");
+
+ if (typeAttr === "") {
+ return "text/javascript";
+ }
+
+ if (typeAttr === null && langAttr === "") {
+ return "text/javascript";
+ }
+
+ if (typeAttr === null && langAttr === null) {
+ return "text/javascript";
+ }
+
+ if (typeAttr !== null) {
+ return typeAttr.trim();
+ }
+
+ if (langAttr !== null) {
+ return "text/" + langAttr;
+ }
+
+ return null;
+ }
+
+ get text() {
+ return childTextContent(this);
+ }
+
+ set text(text) {
+ this.textContent = text;
+ }
+
+ // https://html.spec.whatwg.org/multipage/scripting.html#script-processing-model
+ [cloningSteps](copy, node) {
+ copy._alreadyStarted = node._alreadyStarted;
+ }
+}
+
+function processJavaScript(element, code, filename) {
+ const document = element.ownerDocument;
+ const window = document && document._global;
+
+ if (window) {
+ document._currentScript = element;
+
+ let lineOffset = 0;
+ if (!element.hasAttributeNS(null, "src")) {
+ for (const child of domSymbolTree.childrenIterator(element)) {
+ if (child.nodeType === nodeTypes.TEXT_NODE) {
+ if (child.sourceCodeLocation) {
+ lineOffset = child.sourceCodeLocation.startLine - 1;
+ }
+ break;
+ }
+ }
+ }
+
+ try {
+ vm.runInContext(code, window, { filename, lineOffset, displayErrors: false });
+ } catch (e) {
+ reportException(window, e, filename);
+ } finally {
+ document._currentScript = null;
+ }
+ }
+}
+
+function getType(typeString) {
+ const lowercased = asciiLowercase(typeString);
+ // Cannot use whatwg-mimetype parsing because that strips whitespace. The spec demands a strict string comparison.
+ // That is, the type="" attribute is not really related to MIME types at all.
+ if (jsMIMETypes.has(lowercased)) {
+ return "classic";
+ }
+ if (lowercased === "module") {
+ return "module";
+ }
+ return null;
+}
+
+module.exports = {
+ implementation: HTMLScriptElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSelectElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSelectElement-impl.js
new file mode 100644
index 0000000..817985b
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSelectElement-impl.js
@@ -0,0 +1,283 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+
+const idlUtils = require("../generated/utils.js");
+const ValidityState = require("../generated/ValidityState");
+const DefaultConstraintValidationImpl =
+ require("../constraint-validation/DefaultConstraintValidation-impl").implementation;
+const { mixin } = require("../../utils");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const NODE_TYPE = require("../node-type");
+const HTMLCollection = require("../generated/HTMLCollection");
+const HTMLOptionsCollection = require("../generated/HTMLOptionsCollection");
+const { domSymbolTree } = require("../helpers/internal-constants");
+const { getLabelsForLabelable, formOwner, isDisabled } = require("../helpers/form-controls");
+const { parseNonNegativeInteger } = require("../helpers/strings");
+
+class HTMLSelectElementImpl extends HTMLElementImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+ this._options = HTMLOptionsCollection.createImpl(this._globalObject, [], {
+ element: this,
+ query: () => {
+ // Customized domSymbolTree.treeToArray() clone.
+ const array = [];
+ for (const child of domSymbolTree.childrenIterator(this)) {
+ if (child._localName === "option") {
+ array.push(child);
+ } else if (child._localName === "optgroup") {
+ for (const childOfGroup of domSymbolTree.childrenIterator(child)) {
+ if (childOfGroup._localName === "option") {
+ array.push(childOfGroup);
+ }
+ }
+ }
+ }
+ return array;
+ }
+ });
+ this._selectedOptions = null; // lazy
+
+ this._customValidityErrorMessage = "";
+
+ this._labels = null;
+ }
+
+ _formReset() {
+ for (const option of this.options) {
+ option._selectedness = option.hasAttributeNS(null, "selected");
+ option._dirtyness = false;
+ }
+ this._askedForAReset();
+ }
+
+ _askedForAReset() {
+ if (this.hasAttributeNS(null, "multiple")) {
+ return;
+ }
+
+ const selected = this.options.filter(opt => opt._selectedness);
+
+ const size = this._displaySize;
+ if (size === 1 && !selected.length) {
+ // select the first option that is not disabled
+ for (const option of this.options) {
+ let disabled = option.hasAttributeNS(null, "disabled");
+ const parentNode = domSymbolTree.parent(option);
+ if (parentNode &&
+ parentNode.nodeName.toUpperCase() === "OPTGROUP" &&
+ parentNode.hasAttributeNS(null, "disabled")) {
+ disabled = true;
+ }
+
+ if (!disabled) {
+ // (do not set dirty)
+ option._selectedness = true;
+ break;
+ }
+ }
+ } else if (selected.length >= 2) {
+ // select the last selected option
+ selected.forEach((option, index) => {
+ option._selectedness = index === selected.length - 1;
+ });
+ }
+ }
+
+ _descendantAdded(parent, child) {
+ if (child.nodeType === NODE_TYPE.ELEMENT_NODE) {
+ this._askedForAReset();
+ }
+
+ super._descendantAdded(parent, child);
+ }
+
+ _descendantRemoved(parent, child) {
+ if (child.nodeType === NODE_TYPE.ELEMENT_NODE) {
+ this._askedForAReset();
+ }
+
+ super._descendantRemoved(parent, child);
+ }
+
+ _attrModified(name, value, oldValue) {
+ if (name === "multiple" || name === "size") {
+ this._askedForAReset();
+ }
+ super._attrModified(name, value, oldValue);
+ }
+
+ get _displaySize() {
+ if (this.hasAttributeNS(null, "size")) {
+ const size = parseNonNegativeInteger(this.getAttributeNS(null, "size"));
+ if (size !== null) {
+ return size;
+ }
+ }
+ return this.hasAttributeNS(null, "multiple") ? 4 : 1;
+ }
+
+ get _mutable() {
+ return !isDisabled(this);
+ }
+
+ get options() {
+ return this._options;
+ }
+
+ get selectedOptions() {
+ return HTMLCollection.createImpl(this._globalObject, [], {
+ element: this,
+ query: () => domSymbolTree.treeToArray(this, {
+ filter: node => node._localName === "option" && node._selectedness === true
+ })
+ });
+ }
+
+ get selectedIndex() {
+ for (let i = 0; i < this.options.length; i++) {
+ if (this.options.item(i)._selectedness) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ set selectedIndex(index) {
+ for (let i = 0; i < this.options.length; i++) {
+ this.options.item(i)._selectedness = false;
+ }
+
+ const selectedOption = this.options.item(index);
+ if (selectedOption) {
+ selectedOption._selectedness = true;
+ selectedOption._dirtyness = true;
+ }
+ }
+
+ get labels() {
+ return getLabelsForLabelable(this);
+ }
+
+ get value() {
+ for (const option of this.options) {
+ if (option._selectedness) {
+ return option.value;
+ }
+ }
+
+ return "";
+ }
+
+ set value(val) {
+ for (const option of this.options) {
+ if (option.value === val) {
+ option._selectedness = true;
+ option._dirtyness = true;
+ } else {
+ option._selectedness = false;
+ }
+
+ option._modified();
+ }
+ }
+
+ get form() {
+ return formOwner(this);
+ }
+
+ get type() {
+ return this.hasAttributeNS(null, "multiple") ? "select-multiple" : "select-one";
+ }
+
+ get [idlUtils.supportedPropertyIndices]() {
+ return this.options[idlUtils.supportedPropertyIndices];
+ }
+
+ get length() {
+ return this.options.length;
+ }
+
+ set length(value) {
+ this.options.length = value;
+ }
+
+ item(index) {
+ return this.options.item(index);
+ }
+
+ namedItem(name) {
+ return this.options.namedItem(name);
+ }
+
+ [idlUtils.indexedSetNew](index, value) {
+ return this.options[idlUtils.indexedSetNew](index, value);
+ }
+
+ [idlUtils.indexedSetExisting](index, value) {
+ return this.options[idlUtils.indexedSetExisting](index, value);
+ }
+
+ add(opt, before) {
+ this.options.add(opt, before);
+ }
+
+ remove(index) {
+ if (arguments.length > 0) {
+ index = conversions.long(index, {
+ context: "Failed to execute 'remove' on 'HTMLSelectElement': parameter 1"
+ });
+ this.options.remove(index);
+ } else {
+ super.remove();
+ }
+ }
+
+ _barredFromConstraintValidationSpecialization() {
+ return this.hasAttributeNS(null, "readonly");
+ }
+
+ // Constraint validation: If the element has its required attribute specified,
+ // and either none of the option elements in the select element's list of options
+ // have their selectedness set to true, or the only option element in the select
+ // element's list of options with its selectedness set to true is the placeholder
+ // label option, then the element is suffering from being missing.
+ get validity() {
+ if (!this._validity) {
+ const state = {
+ valueMissing: () => {
+ if (!this.hasAttributeNS(null, "required")) {
+ return false;
+ }
+ const selectedOptionIndex = this.selectedIndex;
+ return selectedOptionIndex < 0 || (selectedOptionIndex === 0 && this._hasPlaceholderOption);
+ }
+ };
+
+ this._validity = ValidityState.createImpl(this._globalObject, [], {
+ element: this,
+ state
+ });
+ }
+ return this._validity;
+ }
+
+ // If a select element has a required attribute specified, does not have a multiple attribute
+ // specified, and has a display size of 1; and if the value of the first option element in the
+ // select element's list of options (if any) is the empty string, and that option element's parent
+ // node is the select element(and not an optgroup element), then that option is the select
+ // element's placeholder label option.
+ // https://html.spec.whatwg.org/multipage/form-elements.html#placeholder-label-option
+ get _hasPlaceholderOption() {
+ return this.hasAttributeNS(null, "required") && !this.hasAttributeNS(null, "multiple") &&
+ this._displaySize === 1 && this.options.length > 0 && this.options.item(0).value === "" &&
+ this.options.item(0).parentNode._localName !== "optgroup";
+ }
+}
+
+mixin(HTMLSelectElementImpl.prototype, DefaultConstraintValidationImpl.prototype);
+
+module.exports = {
+ implementation: HTMLSelectElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSlotElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSlotElement-impl.js
new file mode 100644
index 0000000..a926993
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSlotElement-impl.js
@@ -0,0 +1,59 @@
+"use strict";
+
+const idlUtils = require("../generated/utils");
+const HTMLElement = require("../generated/HTMLElement");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+const { nodeRoot } = require("../helpers/node");
+const { assignSlotableForTree, findFlattenedSlotables } = require("../helpers/shadow-dom");
+
+class HTMLSlotElementImpl extends HTMLElementImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+ this._assignedNodes = [];
+ }
+
+ // https://dom.spec.whatwg.org/#slot-name
+ get name() {
+ return this.getAttributeNS(null, "name") || "";
+ }
+
+ _attrModified(name, value, oldValue) {
+ super._attrModified(name, value, oldValue);
+
+ // https://dom.spec.whatwg.org/#slot-name
+ if (name === "name") {
+ if (value === oldValue) {
+ return;
+ }
+
+ if (value === null && oldValue === "") {
+ return;
+ }
+
+ if (value === "" && oldValue === null) {
+ return;
+ }
+
+ assignSlotableForTree(nodeRoot(this));
+ }
+ }
+
+ // https://html.spec.whatwg.org/#dom-slot-assignednodes
+ assignedNodes(options) {
+ if (!options || !options.flatten) {
+ return this._assignedNodes.map(idlUtils.wrapperForImpl);
+ }
+
+ return findFlattenedSlotables(this).map(idlUtils.wrapperForImpl);
+ }
+
+ // https://html.spec.whatwg.org/#dom-slot-assignedelements
+ assignedElements(options) {
+ return this.assignedNodes(options).filter(HTMLElement.is);
+ }
+}
+
+module.exports = {
+ implementation: HTMLSlotElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSourceElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSourceElement-impl.js
new file mode 100644
index 0000000..44f4412
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSourceElement-impl.js
@@ -0,0 +1,8 @@
+"use strict";
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLSourceElementImpl extends HTMLElementImpl {}
+
+module.exports = {
+ implementation: HTMLSourceElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSpanElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSpanElement-impl.js
new file mode 100644
index 0000000..9c00e6e
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSpanElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLSpanElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLSpanElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLStyleElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLStyleElement-impl.js
new file mode 100644
index 0000000..7dcc6fb
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLStyleElement-impl.js
@@ -0,0 +1,74 @@
+"use strict";
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const { removeStylesheet, createStylesheet } = require("../helpers/stylesheets");
+const { documentBaseURL } = require("../helpers/document-base-url");
+const { childTextContent } = require("../helpers/text");
+const { asciiCaseInsensitiveMatch } = require("../helpers/strings");
+
+class HTMLStyleElementImpl extends HTMLElementImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+
+ this.sheet = null;
+ this._isOnStackOfOpenElements = false;
+ }
+
+ _attach() {
+ super._attach();
+ if (!this._isOnStackOfOpenElements) {
+ this._updateAStyleBlock();
+ }
+ }
+
+ _detach() {
+ super._detach();
+ if (!this._isOnStackOfOpenElements) {
+ this._updateAStyleBlock();
+ }
+ }
+
+ _childTextContentChangeSteps() {
+ super._childTextContentChangeSteps();
+
+ // This guard is not required by the spec, but should be unobservable (since you can't run script during the middle
+ // of parsing a <style> element) and saves a bunch of unnecessary work.
+ if (!this._isOnStackOfOpenElements) {
+ this._updateAStyleBlock();
+ }
+ }
+
+ _poppedOffStackOfOpenElements() {
+ this._isOnStackOfOpenElements = false;
+ this._updateAStyleBlock();
+ }
+
+ _pushedOnStackOfOpenElements() {
+ this._isOnStackOfOpenElements = true;
+ }
+
+ _updateAStyleBlock() {
+ if (this.sheet) {
+ removeStylesheet(this.sheet, this);
+ }
+
+ // Browsing-context connected, per https://github.com/whatwg/html/issues/4547
+ if (!this.isConnected || !this._ownerDocument._defaultView) {
+ return;
+ }
+
+ const type = this.getAttributeNS(null, "type");
+ if (type !== null && type !== "" && !asciiCaseInsensitiveMatch(type, "text/css")) {
+ return;
+ }
+
+ // Not implemented: CSP
+
+ const content = childTextContent(this);
+ // Not implemented: a bunch of other state, e.g. title/media attributes
+ createStylesheet(content, this, documentBaseURL(this._ownerDocument));
+ }
+}
+
+module.exports = {
+ implementation: HTMLStyleElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableCaptionElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableCaptionElement-impl.js
new file mode 100644
index 0000000..27ff421
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableCaptionElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLTableCaptionElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLTableCaptionElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableCellElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableCellElement-impl.js
new file mode 100644
index 0000000..6b6c13e
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableCellElement-impl.js
@@ -0,0 +1,73 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+const { asciiLowercase, parseNonNegativeInteger } = require("../helpers/strings");
+const { closest } = require("../helpers/traversal");
+
+function reflectedAttributeClampedToRange(attrValue, min, max, defaultValue = 0) {
+ if (attrValue === null) {
+ return defaultValue;
+ }
+ const parsed = parseNonNegativeInteger(attrValue);
+ if (parsed === null) {
+ return defaultValue;
+ }
+ if (parsed < min) {
+ return min;
+ }
+ if (parsed > max) {
+ return max;
+ }
+ return parsed;
+}
+
+class HTMLTableCellElementImpl extends HTMLElementImpl {
+ get colSpan() {
+ return reflectedAttributeClampedToRange(this.getAttributeNS(null, "colspan"), 1, 1000, 1);
+ }
+
+ set colSpan(V) {
+ this.setAttributeNS(null, "colspan", String(V));
+ }
+
+ get rowSpan() {
+ return reflectedAttributeClampedToRange(this.getAttributeNS(null, "rowspan"), 0, 65534, 1);
+ }
+
+ set rowSpan(V) {
+ this.setAttributeNS(null, "rowspan", String(V));
+ }
+
+ get cellIndex() {
+ const tr = closest(this, "tr");
+ if (tr === null) {
+ return -1;
+ }
+
+ return tr.cells.indexOf(this);
+ }
+
+ get scope() {
+ let value = this.getAttributeNS(null, "scope");
+ if (value === null) {
+ return "";
+ }
+
+ // Enumerated attribute is matched ASCII-case-insensitively.
+ value = asciiLowercase(value);
+ if (value === "row" || value === "col" || value === "rowgroup" || value === "colgroup") {
+ return value;
+ }
+
+ return "";
+ }
+
+ set scope(V) {
+ this.setAttributeNS(null, "scope", V);
+ }
+}
+
+module.exports = {
+ implementation: HTMLTableCellElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableColElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableColElement-impl.js
new file mode 100644
index 0000000..d6cf3af
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableColElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLTableColElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLTableColElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableElement-impl.js
new file mode 100644
index 0000000..12df786
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableElement-impl.js
@@ -0,0 +1,236 @@
+"use strict";
+const DOMException = require("domexception/webidl2js-wrapper");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const { HTML_NS } = require("../helpers/namespaces");
+const { domSymbolTree } = require("../helpers/internal-constants");
+const { firstChildWithLocalName, childrenByLocalName } = require("../helpers/traversal");
+const HTMLCollection = require("../generated/HTMLCollection");
+const NODE_TYPE = require("../node-type");
+
+function tHeadInsertionPoint(table) {
+ const iterator = domSymbolTree.childrenIterator(table);
+ for (const child of iterator) {
+ if (child.nodeType !== NODE_TYPE.ELEMENT_NODE) {
+ continue;
+ }
+
+ if (child._namespaceURI !== HTML_NS || (child._localName !== "caption" && child._localName !== "colgroup")) {
+ return child;
+ }
+ }
+
+ return null;
+}
+
+class HTMLTableElementImpl extends HTMLElementImpl {
+ get caption() {
+ return firstChildWithLocalName(this, "caption");
+ }
+
+ set caption(value) {
+ const currentCaption = this.caption;
+ if (currentCaption !== null) {
+ this.removeChild(currentCaption);
+ }
+
+ if (value !== null) {
+ const insertionPoint = this.firstChild;
+ this.insertBefore(value, insertionPoint);
+ }
+ }
+
+ get tHead() {
+ return firstChildWithLocalName(this, "thead");
+ }
+
+ set tHead(value) {
+ if (value !== null && value._localName !== "thead") {
+ throw DOMException.create(this._globalObject, [
+ "Cannot set a non-thead element as a table header",
+ "HierarchyRequestError"
+ ]);
+ }
+
+ const currentHead = this.tHead;
+ if (currentHead !== null) {
+ this.removeChild(currentHead);
+ }
+
+ if (value !== null) {
+ const insertionPoint = tHeadInsertionPoint(this);
+ this.insertBefore(value, insertionPoint);
+ }
+ }
+
+ get tFoot() {
+ return firstChildWithLocalName(this, "tfoot");
+ }
+
+ set tFoot(value) {
+ if (value !== null && value._localName !== "tfoot") {
+ throw DOMException.create(this._globalObject, [
+ "Cannot set a non-tfoot element as a table footer",
+ "HierarchyRequestError"
+ ]);
+ }
+
+ const currentFoot = this.tFoot;
+ if (currentFoot !== null) {
+ this.removeChild(currentFoot);
+ }
+
+ if (value !== null) {
+ this.appendChild(value);
+ }
+ }
+
+ get rows() {
+ if (!this._rows) {
+ this._rows = HTMLCollection.createImpl(this._globalObject, [], {
+ element: this,
+ query: () => {
+ const headerRows = [];
+ const bodyRows = [];
+ const footerRows = [];
+
+ const iterator = domSymbolTree.childrenIterator(this);
+ for (const child of iterator) {
+ if (child.nodeType !== NODE_TYPE.ELEMENT_NODE || child._namespaceURI !== HTML_NS) {
+ continue;
+ }
+
+ if (child._localName === "thead") {
+ headerRows.push(...childrenByLocalName(child, "tr"));
+ } else if (child._localName === "tbody") {
+ bodyRows.push(...childrenByLocalName(child, "tr"));
+ } else if (child._localName === "tfoot") {
+ footerRows.push(...childrenByLocalName(child, "tr"));
+ } else if (child._localName === "tr") {
+ bodyRows.push(child);
+ }
+ }
+
+ return [...headerRows, ...bodyRows, ...footerRows];
+ }
+ });
+ }
+ return this._rows;
+ }
+
+ get tBodies() {
+ if (!this._tBodies) {
+ this._tBodies = HTMLCollection.createImpl(this._globalObject, [], {
+ element: this,
+ query: () => childrenByLocalName(this, "tbody")
+ });
+ }
+ return this._tBodies;
+ }
+
+ createTBody() {
+ const el = this._ownerDocument.createElement("TBODY");
+
+ const tbodies = childrenByLocalName(this, "tbody");
+ const insertionPoint = tbodies[tbodies.length - 1];
+
+ if (insertionPoint) {
+ this.insertBefore(el, insertionPoint.nextSibling);
+ } else {
+ this.appendChild(el);
+ }
+ return el;
+ }
+
+ createTHead() {
+ let el = this.tHead;
+ if (!el) {
+ el = this.tHead = this._ownerDocument.createElement("THEAD");
+ }
+ return el;
+ }
+
+ deleteTHead() {
+ this.tHead = null;
+ }
+
+ createTFoot() {
+ let el = this.tFoot;
+ if (!el) {
+ el = this.tFoot = this._ownerDocument.createElement("TFOOT");
+ }
+ return el;
+ }
+
+ deleteTFoot() {
+ this.tFoot = null;
+ }
+
+ createCaption() {
+ let el = this.caption;
+ if (!el) {
+ el = this.caption = this._ownerDocument.createElement("CAPTION");
+ }
+ return el;
+ }
+
+ deleteCaption() {
+ const c = this.caption;
+ if (c) {
+ c.parentNode.removeChild(c);
+ }
+ }
+
+ insertRow(index) {
+ if (index < -1 || index > this.rows.length) {
+ throw DOMException.create(this._globalObject, [
+ "Cannot insert a row at an index that is less than -1 or greater than the number of existing rows",
+ "IndexSizeError"
+ ]);
+ }
+
+ const tr = this._ownerDocument.createElement("tr");
+
+ if (this.rows.length === 0 && this.tBodies.length === 0) {
+ const tBody = this._ownerDocument.createElement("tbody");
+ tBody.appendChild(tr);
+ this.appendChild(tBody);
+ } else if (this.rows.length === 0) {
+ const tBody = this.tBodies.item(this.tBodies.length - 1);
+ tBody.appendChild(tr);
+ } else if (index === -1 || index === this.rows.length) {
+ const tSection = this.rows.item(this.rows.length - 1).parentNode;
+ tSection.appendChild(tr);
+ } else {
+ const beforeTR = this.rows.item(index);
+ const tSection = beforeTR.parentNode;
+ tSection.insertBefore(tr, beforeTR);
+ }
+
+ return tr;
+ }
+
+ deleteRow(index) {
+ const rowLength = this.rows.length;
+ if (index < -1 || index >= rowLength) {
+ throw DOMException.create(this._globalObject, [
+ `Cannot delete a row at index ${index}, where no row exists`,
+ "IndexSizeError"
+ ]);
+ }
+
+ if (index === -1) {
+ if (rowLength === 0) {
+ return;
+ }
+
+ index = rowLength - 1;
+ }
+
+ const tr = this.rows.item(index);
+ tr.parentNode.removeChild(tr);
+ }
+}
+
+module.exports = {
+ implementation: HTMLTableElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableRowElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableRowElement-impl.js
new file mode 100644
index 0000000..c65b52c
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableRowElement-impl.js
@@ -0,0 +1,88 @@
+"use strict";
+
+const DOMException = require("domexception/webidl2js-wrapper");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const HTMLCollection = require("../generated/HTMLCollection");
+const { HTML_NS } = require("../helpers/namespaces");
+const { childrenByLocalNames } = require("../helpers/traversal");
+const { domSymbolTree } = require("../helpers/internal-constants");
+
+const cellLocalNames = new Set(["td", "th"]);
+
+class HTMLTableRowElementImpl extends HTMLElementImpl {
+ get cells() {
+ if (!this._cells) {
+ this._cells = HTMLCollection.createImpl(this._globalObject, [], {
+ element: this,
+ query: () => childrenByLocalNames(this, cellLocalNames)
+ });
+ }
+ return this._cells;
+ }
+
+ get rowIndex() {
+ const parent = this.parentElement;
+ if (parent === null || parent.namespaceURI !== HTML_NS) {
+ return -1;
+ }
+
+ let tableElement = parent;
+ if (parent.localName === "thead" || parent.localName === "tbody" || parent.localName === "tfoot") {
+ tableElement = parent.parentElement;
+ }
+ if (tableElement === null || tableElement.namespaceURI !== HTML_NS || tableElement.localName !== "table") {
+ return -1;
+ }
+
+ return tableElement.rows.indexOf(this);
+ }
+
+ get sectionRowIndex() {
+ const parent = domSymbolTree.parent(this);
+ if (parent === null) {
+ return -1;
+ }
+
+ const { rows } = parent;
+ if (!rows) {
+ return -1;
+ }
+
+ return rows.indexOf(this);
+ }
+
+ insertCell(index) {
+ const td = this._ownerDocument.createElement("TD");
+ const { cells } = this;
+ if (index < -1 || index > cells.length) {
+ throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+ }
+ if (index === -1 || index === cells.length) {
+ this._append(td);
+ } else {
+ const ref = cells.item(index);
+ this._insert(td, ref);
+ }
+ return td;
+ }
+
+ deleteCell(index) {
+ const { cells } = this;
+ if (index < -1 || index >= cells.length) {
+ throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+ }
+ if (index === -1) {
+ if (cells.length === 0) {
+ return;
+ }
+
+ index = cells.length - 1;
+ }
+ const td = cells.item(index);
+ this._remove(td);
+ }
+}
+
+module.exports = {
+ implementation: HTMLTableRowElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableSectionElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableSectionElement-impl.js
new file mode 100644
index 0000000..3cf767b
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableSectionElement-impl.js
@@ -0,0 +1,61 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const { childrenByLocalName } = require("../helpers/traversal");
+const HTMLCollection = require("../generated/HTMLCollection");
+const DOMException = require("domexception/webidl2js-wrapper");
+
+class HTMLTableSectionElementImpl extends HTMLElementImpl {
+ get rows() {
+ if (!this._rows) {
+ this._rows = HTMLCollection.createImpl(this._globalObject, [], {
+ element: this,
+ query: () => childrenByLocalName(this, "tr")
+ });
+ }
+ return this._rows;
+ }
+
+ insertRow(index) {
+ if (index < -1 || index > this.rows.length) {
+ throw DOMException.create(this._globalObject, [
+ "Cannot insert a row at an index that is less than -1 or greater than the number of existing rows",
+ "IndexSizeError"
+ ]);
+ }
+
+ const tr = this._ownerDocument.createElement("tr");
+
+ if (index === -1 || index === this.rows.length) {
+ this._append(tr);
+ } else {
+ const beforeTR = this.rows.item(index);
+ this._insert(tr, beforeTR);
+ }
+
+ return tr;
+ }
+
+ deleteRow(index) {
+ if (index < -1 || index >= this.rows.length) {
+ throw DOMException.create(this._globalObject, [
+ `Cannot delete a row at index ${index}, where no row exists`,
+ "IndexSizeError"
+ ]);
+ }
+
+ if (index === -1) {
+ if (this.rows.length > 0) {
+ const tr = this.rows.item(this.rows.length - 1);
+ this._remove(tr);
+ }
+ } else {
+ const tr = this.rows.item(index);
+ this._remove(tr);
+ }
+ }
+}
+
+module.exports = {
+ implementation: HTMLTableSectionElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTemplateElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTemplateElement-impl.js
new file mode 100644
index 0000000..b0a2405
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTemplateElement-impl.js
@@ -0,0 +1,67 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+const Document = require("../generated/Document");
+const DocumentFragment = require("../generated/DocumentFragment");
+
+const { cloningSteps, domSymbolTree } = require("../helpers/internal-constants");
+const { clone } = require("../node");
+
+class HTMLTemplateElementImpl extends HTMLElementImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+
+ const doc = this._appropriateTemplateContentsOwnerDocument(this._ownerDocument);
+ this._templateContents = DocumentFragment.createImpl(this._globalObject, [], {
+ ownerDocument: doc,
+ host: this
+ });
+ }
+
+ // https://html.spec.whatwg.org/multipage/scripting.html#appropriate-template-contents-owner-document
+ _appropriateTemplateContentsOwnerDocument(doc) {
+ if (!doc._isInertTemplateDocument) {
+ if (doc._associatedInertTemplateDocument === undefined) {
+ const newDoc = Document.createImpl(this._globalObject, [], {
+ options: {
+ parsingMode: doc._parsingMode,
+ encoding: doc._encoding
+ }
+ });
+ newDoc._isInertTemplateDocument = true;
+
+ doc._associatedInertTemplateDocument = newDoc;
+ }
+
+ doc = doc._associatedInertTemplateDocument;
+ }
+
+ return doc;
+ }
+
+ // https://html.spec.whatwg.org/multipage/scripting.html#template-adopting-steps
+ _adoptingSteps() {
+ const doc = this._appropriateTemplateContentsOwnerDocument(this._ownerDocument);
+ doc._adoptNode(this._templateContents);
+ }
+
+ get content() {
+ return this._templateContents;
+ }
+
+ [cloningSteps](copy, node, document, cloneChildren) {
+ if (!cloneChildren) {
+ return;
+ }
+
+ for (const child of domSymbolTree.childrenIterator(node._templateContents)) {
+ const childCopy = clone(child, copy._templateContents._ownerDocument, true);
+ copy._templateContents.appendChild(childCopy);
+ }
+ }
+}
+
+module.exports = {
+ implementation: HTMLTemplateElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTextAreaElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTextAreaElement-impl.js
new file mode 100644
index 0000000..427dfa4
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTextAreaElement-impl.js
@@ -0,0 +1,272 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+const DefaultConstraintValidationImpl =
+ require("../constraint-validation/DefaultConstraintValidation-impl").implementation;
+const ValidityState = require("../generated/ValidityState");
+const { mixin } = require("../../utils");
+
+const DOMException = require("domexception/webidl2js-wrapper");
+const { cloningSteps } = require("../helpers/internal-constants");
+const { isDisabled, getLabelsForLabelable, formOwner } = require("../helpers/form-controls");
+const { childTextContent } = require("../helpers/text");
+const { fireAnEvent } = require("../helpers/events");
+
+class HTMLTextAreaElementImpl extends HTMLElementImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+
+ this._selectionStart = this._selectionEnd = 0;
+ this._selectionDirection = "none";
+ this._rawValue = "";
+ this._dirtyValue = false;
+
+ this._customValidityErrorMessage = "";
+
+ this._labels = null;
+ }
+
+ _formReset() {
+ this._rawValue = childTextContent(this);
+ this._dirtyValue = false;
+ }
+
+ _getAPIValue() {
+ return this._rawValue.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
+ }
+
+ // https://html.spec.whatwg.org/multipage/form-elements.html#textarea-wrapping-transformation
+ _getValue() {
+ const apiValue = this._getAPIValue();
+ const wrap = this.getAttributeNS(null, "wrap");
+ return wrap === "hard" ?
+ textareaWrappingTransformation(apiValue, this.cols) :
+ apiValue;
+ }
+
+ _childTextContentChangeSteps() {
+ super._childTextContentChangeSteps();
+
+ if (this._dirtyValue === false) {
+ this._rawValue = childTextContent(this);
+ }
+ }
+
+ get labels() {
+ return getLabelsForLabelable(this);
+ }
+
+ get form() {
+ return formOwner(this);
+ }
+
+ get defaultValue() {
+ return childTextContent(this);
+ }
+
+ set defaultValue(val) {
+ this.textContent = val;
+ }
+
+ get value() {
+ return this._getAPIValue();
+ }
+
+ set value(val) {
+ // https://html.spec.whatwg.org/multipage/form-elements.html#dom-textarea-value
+ const oldAPIValue = this._getAPIValue();
+ this._rawValue = val;
+ this._dirtyValue = true;
+
+ if (oldAPIValue !== this._getAPIValue()) {
+ this._selectionStart = this._selectionEnd = this._getValueLength();
+ this._selectionDirection = "none";
+ }
+ }
+
+ get textLength() {
+ return this.value.length; // code unit length (16 bit)
+ }
+
+ get type() {
+ return "textarea";
+ }
+
+ _dispatchSelectEvent() {
+ fireAnEvent("select", this, undefined, { bubbles: true, cancelable: true });
+ }
+
+ _getValueLength() {
+ return typeof this.value === "string" ? this.value.length : 0;
+ }
+
+ select() {
+ this._selectionStart = 0;
+ this._selectionEnd = this._getValueLength();
+ this._selectionDirection = "none";
+ this._dispatchSelectEvent();
+ }
+
+ get selectionStart() {
+ return this._selectionStart;
+ }
+
+ set selectionStart(start) {
+ this.setSelectionRange(start, Math.max(start, this._selectionEnd), this._selectionDirection);
+ }
+
+ get selectionEnd() {
+ return this._selectionEnd;
+ }
+
+ set selectionEnd(end) {
+ this.setSelectionRange(this._selectionStart, end, this._selectionDirection);
+ }
+
+ get selectionDirection() {
+ return this._selectionDirection;
+ }
+
+ set selectionDirection(dir) {
+ this.setSelectionRange(this._selectionStart, this._selectionEnd, dir);
+ }
+
+ setSelectionRange(start, end, dir) {
+ this._selectionEnd = Math.min(end, this._getValueLength());
+ this._selectionStart = Math.min(start, this._selectionEnd);
+ this._selectionDirection = dir === "forward" || dir === "backward" ? dir : "none";
+ this._dispatchSelectEvent();
+ }
+
+ setRangeText(repl, start, end, selectionMode = "preserve") {
+ if (arguments.length < 2) {
+ start = this._selectionStart;
+ end = this._selectionEnd;
+ } else if (start > end) {
+ throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+ }
+
+ start = Math.min(start, this._getValueLength());
+ end = Math.min(end, this._getValueLength());
+
+ const val = this.value;
+ let selStart = this._selectionStart;
+ let selEnd = this._selectionEnd;
+
+ this.value = val.slice(0, start) + repl + val.slice(end);
+
+ const newEnd = start + this.value.length;
+
+ if (selectionMode === "select") {
+ this.setSelectionRange(start, newEnd);
+ } else if (selectionMode === "start") {
+ this.setSelectionRange(start, start);
+ } else if (selectionMode === "end") {
+ this.setSelectionRange(newEnd, newEnd);
+ } else { // preserve
+ const delta = repl.length - (end - start);
+
+ if (selStart > end) {
+ selStart += delta;
+ } else if (selStart > start) {
+ selStart = start;
+ }
+
+ if (selEnd > end) {
+ selEnd += delta;
+ } else if (selEnd > start) {
+ selEnd = newEnd;
+ }
+
+ this.setSelectionRange(selStart, selEnd);
+ }
+ }
+
+ get cols() {
+ if (!this.hasAttributeNS(null, "cols")) {
+ return 20;
+ }
+ return parseInt(this.getAttributeNS(null, "cols"));
+ }
+
+ set cols(value) {
+ if (value <= 0) {
+ throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+ }
+ this.setAttributeNS(null, "cols", String(value));
+ }
+
+ get rows() {
+ if (!this.hasAttributeNS(null, "rows")) {
+ return 2;
+ }
+ return parseInt(this.getAttributeNS(null, "rows"));
+ }
+
+ set rows(value) {
+ if (value <= 0) {
+ throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+ }
+ this.setAttributeNS(null, "rows", String(value));
+ }
+
+ _barredFromConstraintValidationSpecialization() {
+ return this.hasAttributeNS(null, "readonly");
+ }
+
+ get _mutable() {
+ return !isDisabled(this) && !this.hasAttributeNS(null, "readonly");
+ }
+
+ // https://html.spec.whatwg.org/multipage/form-elements.html#attr-textarea-required
+ get validity() {
+ if (!this._validity) {
+ const state = {
+ valueMissing: () => this.hasAttributeNS(null, "required") && this._mutable && this.value === ""
+ };
+
+ this._validity = ValidityState.createImpl(this._globalObject, [], {
+ element: this,
+ state
+ });
+ }
+ return this._validity;
+ }
+
+ [cloningSteps](copy, node) {
+ copy._dirtyValue = node._dirtyValue;
+ copy._rawValue = node._rawValue;
+ }
+}
+
+mixin(HTMLTextAreaElementImpl.prototype, DefaultConstraintValidationImpl.prototype);
+
+module.exports = {
+ implementation: HTMLTextAreaElementImpl
+};
+
+function textareaWrappingTransformation(text, cols) {
+ let lineStart = 0;
+ let lineEnd = text.indexOf("\n");
+ if (lineEnd === -1) {
+ lineEnd = text.length;
+ }
+
+ while (lineStart < text.length) {
+ const lineLength = lineEnd - lineStart;
+ if (lineLength > cols) {
+ // split the line
+ lineEnd = lineStart + cols;
+ text = text.slice(0, lineEnd) + "\n" + text.slice(lineEnd);
+ }
+ // move to next line
+ lineStart = lineEnd + 1; // step over the newline
+ lineEnd = text.indexOf("\n", lineStart);
+ if (lineEnd === -1) {
+ lineEnd = text.length;
+ }
+ }
+
+ return text;
+}
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTimeElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTimeElement-impl.js
new file mode 100644
index 0000000..0378649
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTimeElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLTimeElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLTimeElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTitleElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTitleElement-impl.js
new file mode 100644
index 0000000..fad736c
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTitleElement-impl.js
@@ -0,0 +1,18 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const { childTextContent } = require("../helpers/text");
+
+class HTMLTitleElementImpl extends HTMLElementImpl {
+ get text() {
+ return childTextContent(this);
+ }
+
+ set text(value) {
+ this.textContent = value;
+ }
+}
+
+module.exports = {
+ implementation: HTMLTitleElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTrackElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTrackElement-impl.js
new file mode 100644
index 0000000..858df85
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTrackElement-impl.js
@@ -0,0 +1,13 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLTrackElementImpl extends HTMLElementImpl {
+ get readyState() {
+ return 0;
+ }
+}
+
+module.exports = {
+ implementation: HTMLTrackElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLUListElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLUListElement-impl.js
new file mode 100644
index 0000000..ed22ec0
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLUListElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLUListElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLUListElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLUnknownElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLUnknownElement-impl.js
new file mode 100644
index 0000000..89b2b2b
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLUnknownElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLUnknownElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+ implementation: HTMLUnknownElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLVideoElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLVideoElement-impl.js
new file mode 100644
index 0000000..d06cd9e
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/HTMLVideoElement-impl.js
@@ -0,0 +1,17 @@
+"use strict";
+
+const HTMLMediaElementImpl = require("./HTMLMediaElement-impl").implementation;
+
+class HTMLVideoElementImpl extends HTMLMediaElementImpl {
+ get videoWidth() {
+ return 0;
+ }
+
+ get videoHeight() {
+ return 0;
+ }
+}
+
+module.exports = {
+ implementation: HTMLVideoElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/LinkStyle-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/LinkStyle-impl.js
new file mode 100644
index 0000000..7a6c5d8
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/LinkStyle-impl.js
@@ -0,0 +1,2 @@
+"use strict";
+module.exports = class LinkStyleImpl {};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js
new file mode 100644
index 0000000..11ce11b
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js
@@ -0,0 +1,1165 @@
+"use strict";
+
+const DOMException = require("domexception/webidl2js-wrapper");
+
+const EventTargetImpl = require("../events/EventTarget-impl").implementation;
+const { simultaneousIterators } = require("../../utils");
+const NODE_TYPE = require("../node-type");
+const NODE_DOCUMENT_POSITION = require("../node-document-position");
+const { clone, locateNamespacePrefix, locateNamespace } = require("../node");
+const { setAnExistingAttributeValue } = require("../attributes");
+
+const NodeList = require("../generated/NodeList");
+
+const { nodeRoot, nodeLength } = require("../helpers/node");
+const { domSymbolTree } = require("../helpers/internal-constants");
+const { documentBaseURLSerialized } = require("../helpers/document-base-url");
+const { queueTreeMutationRecord } = require("../helpers/mutation-observers");
+const { enqueueCECallbackReaction, tryUpgradeElement } = require("../helpers/custom-elements");
+const {
+ isShadowRoot, shadowIncludingRoot, assignSlot, assignSlotableForTree, assignSlotable, signalSlotChange, isSlot,
+ shadowIncludingInclusiveDescendantsIterator, shadowIncludingDescendantsIterator
+} = require("../helpers/shadow-dom");
+
+function isObsoleteNodeType(node) {
+ return node.nodeType === NODE_TYPE.ENTITY_NODE ||
+ node.nodeType === NODE_TYPE.ENTITY_REFERENCE_NODE ||
+ node.nodeType === NODE_TYPE.NOTATION_NODE ||
+ node.nodeType === NODE_TYPE.CDATA_SECTION_NODE;
+}
+
+function nodeEquals(a, b) {
+ if (a.nodeType !== b.nodeType) {
+ return false;
+ }
+
+ switch (a.nodeType) {
+ case NODE_TYPE.DOCUMENT_TYPE_NODE:
+ if (a.name !== b.name || a.publicId !== b.publicId ||
+ a.systemId !== b.systemId) {
+ return false;
+ }
+ break;
+ case NODE_TYPE.ELEMENT_NODE:
+ if (a._namespaceURI !== b._namespaceURI || a._prefix !== b._prefix || a._localName !== b._localName ||
+ a._attributes.length !== b._attributes.length) {
+ return false;
+ }
+ break;
+ case NODE_TYPE.ATTRIBUTE_NODE:
+ if (a._namespace !== b._namespace || a._localName !== b._localName || a._value !== b._value) {
+ return false;
+ }
+ break;
+ case NODE_TYPE.PROCESSING_INSTRUCTION_NODE:
+ if (a._target !== b._target || a._data !== b._data) {
+ return false;
+ }
+ break;
+ case NODE_TYPE.TEXT_NODE:
+ case NODE_TYPE.COMMENT_NODE:
+ if (a._data !== b._data) {
+ return false;
+ }
+ break;
+ }
+
+ if (a.nodeType === NODE_TYPE.ELEMENT_NODE && !attributeListsEqual(a, b)) {
+ return false;
+ }
+
+ for (const nodes of simultaneousIterators(domSymbolTree.childrenIterator(a), domSymbolTree.childrenIterator(b))) {
+ if (!nodes[0] || !nodes[1]) {
+ // mismatch in the amount of childNodes
+ return false;
+ }
+
+ if (!nodeEquals(nodes[0], nodes[1])) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Needed by https://dom.spec.whatwg.org/#concept-node-equals
+function attributeListsEqual(elementA, elementB) {
+ const listA = elementA._attributeList;
+ const listB = elementB._attributeList;
+
+ const lengthA = listA.length;
+ const lengthB = listB.length;
+
+ if (lengthA !== lengthB) {
+ return false;
+ }
+
+ for (let i = 0; i < lengthA; ++i) {
+ const attrA = listA[i];
+
+ if (!listB.some(attrB => nodeEquals(attrA, attrB))) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// https://dom.spec.whatwg.org/#concept-tree-host-including-inclusive-ancestor
+function isHostInclusiveAncestor(nodeImplA, nodeImplB) {
+ for (const ancestor of domSymbolTree.ancestorsIterator(nodeImplB)) {
+ if (ancestor === nodeImplA) {
+ return true;
+ }
+ }
+
+ const rootImplB = nodeRoot(nodeImplB);
+ if (rootImplB._host) {
+ return isHostInclusiveAncestor(nodeImplA, rootImplB._host);
+ }
+
+ return false;
+}
+
+class NodeImpl extends EventTargetImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+
+ domSymbolTree.initialize(this);
+
+ this._ownerDocument = privateData.ownerDocument;
+
+ this._childNodesList = null;
+ this._childrenList = null;
+ this._version = 0;
+ this._memoizedQueries = {};
+ this._registeredObserverList = [];
+ this._referencedRanges = new Set();
+ }
+
+ _getTheParent() {
+ if (this._assignedSlot) {
+ return this._assignedSlot;
+ }
+
+ return domSymbolTree.parent(this);
+ }
+
+ get parentNode() {
+ return domSymbolTree.parent(this);
+ }
+
+ getRootNode(options) {
+ return options.composed ? shadowIncludingRoot(this) : nodeRoot(this);
+ }
+
+ get nodeName() {
+ switch (this.nodeType) {
+ case NODE_TYPE.ELEMENT_NODE:
+ return this.tagName;
+ case NODE_TYPE.ATTRIBUTE_NODE:
+ return this._qualifiedName;
+ case NODE_TYPE.TEXT_NODE:
+ return "#text";
+ case NODE_TYPE.CDATA_SECTION_NODE:
+ return "#cdata-section";
+ case NODE_TYPE.PROCESSING_INSTRUCTION_NODE:
+ return this.target;
+ case NODE_TYPE.COMMENT_NODE:
+ return "#comment";
+ case NODE_TYPE.DOCUMENT_NODE:
+ return "#document";
+ case NODE_TYPE.DOCUMENT_TYPE_NODE:
+ return this.name;
+ case NODE_TYPE.DOCUMENT_FRAGMENT_NODE:
+ return "#document-fragment";
+ }
+
+ // should never happen
+ return null;
+ }
+
+ get firstChild() {
+ return domSymbolTree.firstChild(this);
+ }
+
+ // https://dom.spec.whatwg.org/#connected
+ // https://dom.spec.whatwg.org/#dom-node-isconnected
+ get isConnected() {
+ const root = shadowIncludingRoot(this);
+ return root && root.nodeType === NODE_TYPE.DOCUMENT_NODE;
+ }
+
+ get ownerDocument() {
+ return this.nodeType === NODE_TYPE.DOCUMENT_NODE ? null : this._ownerDocument;
+ }
+
+ get lastChild() {
+ return domSymbolTree.lastChild(this);
+ }
+
+ get childNodes() {
+ if (!this._childNodesList) {
+ this._childNodesList = NodeList.createImpl(this._globalObject, [], {
+ element: this,
+ query: () => domSymbolTree.childrenToArray(this)
+ });
+ } else {
+ this._childNodesList._update();
+ }
+
+ return this._childNodesList;
+ }
+
+ get nextSibling() {
+ return domSymbolTree.nextSibling(this);
+ }
+
+ get previousSibling() {
+ return domSymbolTree.previousSibling(this);
+ }
+
+ _modified() {
+ this._version++;
+ for (const ancestor of domSymbolTree.ancestorsIterator(this)) {
+ ancestor._version++;
+ }
+
+ if (this._childrenList) {
+ this._childrenList._update();
+ }
+ if (this._childNodesList) {
+ this._childNodesList._update();
+ }
+ this._clearMemoizedQueries();
+ }
+
+ _childTextContentChangeSteps() {
+ // Default: do nothing
+ }
+
+ _clearMemoizedQueries() {
+ this._memoizedQueries = {};
+ const myParent = domSymbolTree.parent(this);
+ if (myParent) {
+ myParent._clearMemoizedQueries();
+ }
+ }
+
+ _descendantRemoved(parent, child) {
+ const myParent = domSymbolTree.parent(this);
+ if (myParent) {
+ myParent._descendantRemoved(parent, child);
+ }
+ }
+
+ _descendantAdded(parent, child) {
+ const myParent = domSymbolTree.parent(this);
+ if (myParent) {
+ myParent._descendantAdded(parent, child);
+ }
+ }
+
+ _attach() {
+ this._attached = true;
+
+ for (const child of domSymbolTree.childrenIterator(this)) {
+ if (child._attach) {
+ child._attach();
+ }
+ }
+ }
+
+ _detach() {
+ this._attached = false;
+
+ if (this._ownerDocument && this._ownerDocument._lastFocusedElement === this) {
+ this._ownerDocument._lastFocusedElement = null;
+ }
+
+ for (const child of domSymbolTree.childrenIterator(this)) {
+ if (child._detach) {
+ child._detach();
+ }
+ }
+ }
+
+ hasChildNodes() {
+ return domSymbolTree.hasChildren(this);
+ }
+
+ // https://dom.spec.whatwg.org/#dom-node-normalize
+ normalize() {
+ // It is important to use a treeToArray instead of a treeToIterator here, because the
+ // treeToIterator doesn't support tree mutation in the middle of the traversal.
+ for (const node of domSymbolTree.treeToArray(this)) {
+ const parentNode = domSymbolTree.parent(node);
+ if (parentNode === null || node.nodeType !== NODE_TYPE.TEXT_NODE) {
+ continue;
+ }
+
+ let length = nodeLength(node);
+
+ if (length === 0) {
+ parentNode._remove(node);
+ continue;
+ }
+
+ const continuousExclusiveTextNodes = [];
+
+ for (const currentNode of domSymbolTree.previousSiblingsIterator(node)) {
+ if (currentNode.nodeType !== NODE_TYPE.TEXT_NODE) {
+ break;
+ }
+
+ continuousExclusiveTextNodes.unshift(currentNode);
+ }
+ for (const currentNode of domSymbolTree.nextSiblingsIterator(node)) {
+ if (currentNode.nodeType !== NODE_TYPE.TEXT_NODE) {
+ break;
+ }
+
+ continuousExclusiveTextNodes.push(currentNode);
+ }
+
+ const data = continuousExclusiveTextNodes.reduce((d, n) => d + n._data, "");
+ node.replaceData(length, 0, data);
+
+ let currentNode = domSymbolTree.nextSibling(node);
+ while (currentNode && currentNode.nodeType !== NODE_TYPE.TEXT_NODE) {
+ const currentNodeParent = domSymbolTree.parent(currentNode);
+ const currentNodeIndex = domSymbolTree.index(currentNode);
+
+ for (const range of node._referencedRanges) {
+ const { _start, _end } = range;
+
+ if (_start.node === currentNode) {
+ range._setLiveRangeStart(node, _start.offset + length);
+ }
+ if (_end.node === currentNode) {
+ range._setLiveRangeEnd(node, _end.offset + length);
+ }
+ if (_start.node === currentNodeParent && _start.offset === currentNodeIndex) {
+ range._setLiveRangeStart(node, length);
+ }
+ if (_end.node === currentNodeParent && _end.offset === currentNodeIndex) {
+ range._setLiveRangeStart(node, length);
+ }
+ }
+
+ length += nodeLength(currentNode);
+ currentNode = domSymbolTree.nextSibling(currentNode);
+ }
+
+ for (const continuousExclusiveTextNode of continuousExclusiveTextNodes) {
+ parentNode._remove(continuousExclusiveTextNode);
+ }
+ }
+ }
+
+ get parentElement() {
+ const parentNode = domSymbolTree.parent(this);
+ return parentNode !== null && parentNode.nodeType === NODE_TYPE.ELEMENT_NODE ? parentNode : null;
+ }
+
+ get baseURI() {
+ return documentBaseURLSerialized(this._ownerDocument);
+ }
+
+ compareDocumentPosition(other) {
+ // Let node1 be other and node2 be the context object.
+ let node1 = other;
+ let node2 = this;
+
+ if (isObsoleteNodeType(node2) || isObsoleteNodeType(node1)) {
+ throw new Error("Obsolete node type");
+ }
+
+ let attr1 = null;
+ let attr2 = null;
+
+ if (node1.nodeType === NODE_TYPE.ATTRIBUTE_NODE) {
+ attr1 = node1;
+ node1 = attr1._element;
+ }
+
+ if (node2.nodeType === NODE_TYPE.ATTRIBUTE_NODE) {
+ attr2 = node2;
+ node2 = attr2._element;
+
+ if (attr1 !== null && node1 !== null && node2 === node1) {
+ for (const attr of node2._attributeList) {
+ if (nodeEquals(attr, attr1)) {
+ return NODE_DOCUMENT_POSITION.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC |
+ NODE_DOCUMENT_POSITION.DOCUMENT_POSITION_PRECEDING;
+ }
+
+ if (nodeEquals(attr, attr2)) {
+ return NODE_DOCUMENT_POSITION.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC |
+ NODE_DOCUMENT_POSITION.DOCUMENT_POSITION_FOLLOWING;
+ }
+ }
+ }
+ }
+
+ const result = domSymbolTree.compareTreePosition(node2, node1);
+
+ // “If other and reference are not in the same tree, return the result of adding DOCUMENT_POSITION_DISCONNECTED,
+ // DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC, and either DOCUMENT_POSITION_PRECEDING or
+ // DOCUMENT_POSITION_FOLLOWING, with the constraint that this is to be consistent, together.”
+ if (result === NODE_DOCUMENT_POSITION.DOCUMENT_POSITION_DISCONNECTED) {
+ // symbol-tree does not add these bits required by the spec:
+ return NODE_DOCUMENT_POSITION.DOCUMENT_POSITION_DISCONNECTED |
+ NODE_DOCUMENT_POSITION.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC |
+ NODE_DOCUMENT_POSITION.DOCUMENT_POSITION_FOLLOWING;
+ }
+
+ return result;
+ }
+
+ lookupPrefix(namespace) {
+ if (namespace === null || namespace === "") {
+ return null;
+ }
+
+ switch (this.nodeType) {
+ case NODE_TYPE.ELEMENT_NODE: {
+ return locateNamespacePrefix(this, namespace);
+ }
+ case NODE_TYPE.DOCUMENT_NODE: {
+ return this.documentElement !== null ? locateNamespacePrefix(this.documentElement, namespace) : null;
+ }
+ case NODE_TYPE.DOCUMENT_TYPE_NODE:
+ case NODE_TYPE.DOCUMENT_FRAGMENT_NODE: {
+ return null;
+ }
+ case NODE_TYPE.ATTRIBUTE_NODE: {
+ return this._element !== null ? locateNamespacePrefix(this._element, namespace) : null;
+ }
+ default: {
+ return this.parentElement !== null ? locateNamespacePrefix(this.parentElement, namespace) : null;
+ }
+ }
+ }
+
+ lookupNamespaceURI(prefix) {
+ if (prefix === "") {
+ prefix = null;
+ }
+
+ return locateNamespace(this, prefix);
+ }
+
+ isDefaultNamespace(namespace) {
+ if (namespace === "") {
+ namespace = null;
+ }
+
+ const defaultNamespace = locateNamespace(this, null);
+ return defaultNamespace === namespace;
+ }
+
+ contains(other) {
+ if (other === null) {
+ return false;
+ } else if (this === other) {
+ return true;
+ }
+ return Boolean(this.compareDocumentPosition(other) & NODE_DOCUMENT_POSITION.DOCUMENT_POSITION_CONTAINED_BY);
+ }
+
+ isEqualNode(node) {
+ if (node === null) {
+ return false;
+ }
+
+ // Fast-path, not in the spec
+ if (this === node) {
+ return true;
+ }
+
+ return nodeEquals(this, node);
+ }
+
+ isSameNode(node) {
+ if (this === node) {
+ return true;
+ }
+
+ return false;
+ }
+
+ cloneNode(deep) {
+ if (isShadowRoot(this)) {
+ throw DOMException.create(this._globalObject, ["ShadowRoot nodes are not clonable.", "NotSupportedError"]);
+ }
+
+ deep = Boolean(deep);
+
+ return clone(this, undefined, deep);
+ }
+
+ get nodeValue() {
+ switch (this.nodeType) {
+ case NODE_TYPE.ATTRIBUTE_NODE: {
+ return this._value;
+ }
+ case NODE_TYPE.TEXT_NODE:
+ case NODE_TYPE.CDATA_SECTION_NODE: // CDATASection is a subclass of Text
+ case NODE_TYPE.PROCESSING_INSTRUCTION_NODE:
+ case NODE_TYPE.COMMENT_NODE: {
+ return this._data;
+ }
+ default: {
+ return null;
+ }
+ }
+ }
+
+ set nodeValue(value) {
+ if (value === null) {
+ value = "";
+ }
+
+ switch (this.nodeType) {
+ case NODE_TYPE.ATTRIBUTE_NODE: {
+ setAnExistingAttributeValue(this, value);
+ break;
+ }
+ case NODE_TYPE.TEXT_NODE:
+ case NODE_TYPE.CDATA_SECTION_NODE: // CDATASection is a subclass of Text
+ case NODE_TYPE.PROCESSING_INSTRUCTION_NODE:
+ case NODE_TYPE.COMMENT_NODE: {
+ this.replaceData(0, this.length, value);
+ break;
+ }
+ }
+ }
+
+ // https://dom.spec.whatwg.org/#dom-node-textcontent
+ get textContent() {
+ switch (this.nodeType) {
+ case NODE_TYPE.DOCUMENT_FRAGMENT_NODE:
+ case NODE_TYPE.ELEMENT_NODE: {
+ let text = "";
+ for (const child of domSymbolTree.treeIterator(this)) {
+ if (child.nodeType === NODE_TYPE.TEXT_NODE || child.nodeType === NODE_TYPE.CDATA_SECTION_NODE) {
+ text += child.nodeValue;
+ }
+ }
+ return text;
+ }
+
+ case NODE_TYPE.ATTRIBUTE_NODE: {
+ return this._value;
+ }
+
+ case NODE_TYPE.TEXT_NODE:
+ case NODE_TYPE.CDATA_SECTION_NODE: // CDATASection is a subclass of Text
+ case NODE_TYPE.PROCESSING_INSTRUCTION_NODE:
+ case NODE_TYPE.COMMENT_NODE: {
+ return this._data;
+ }
+
+ default: {
+ return null;
+ }
+ }
+ }
+ set textContent(value) {
+ if (value === null) {
+ value = "";
+ }
+
+ switch (this.nodeType) {
+ case NODE_TYPE.DOCUMENT_FRAGMENT_NODE:
+ case NODE_TYPE.ELEMENT_NODE: {
+ // https://dom.spec.whatwg.org/#string-replace-all
+ let nodeImpl = null;
+
+ if (value !== "") {
+ nodeImpl = this._ownerDocument.createTextNode(value);
+ }
+
+ this._replaceAll(nodeImpl);
+ break;
+ }
+
+ case NODE_TYPE.ATTRIBUTE_NODE: {
+ setAnExistingAttributeValue(this, value);
+ break;
+ }
+
+ case NODE_TYPE.TEXT_NODE:
+ case NODE_TYPE.CDATA_SECTION_NODE: // CDATASection is a subclass of Text
+ case NODE_TYPE.PROCESSING_INSTRUCTION_NODE:
+ case NODE_TYPE.COMMENT_NODE: {
+ this.replaceData(0, this.length, value);
+ break;
+ }
+ }
+ }
+
+ // https://dom.spec.whatwg.org/#dom-node-insertbefore
+ insertBefore(nodeImpl, childImpl) {
+ return this._preInsert(nodeImpl, childImpl);
+ }
+
+ // https://dom.spec.whatwg.org/#dom-node-appendchild
+ appendChild(nodeImpl) {
+ return this._append(nodeImpl);
+ }
+
+ // https://dom.spec.whatwg.org/#dom-node-replacechild
+ replaceChild(nodeImpl, childImpl) {
+ return this._replace(nodeImpl, childImpl);
+ }
+
+ // https://dom.spec.whatwg.org/#dom-node-removechild
+ removeChild(oldChildImpl) {
+ return this._preRemove(oldChildImpl);
+ }
+
+ // https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
+ _preInsertValidity(nodeImpl, childImpl) {
+ const { nodeType, nodeName } = nodeImpl;
+ const { nodeType: parentType, nodeName: parentName } = this;
+
+ if (
+ parentType !== NODE_TYPE.DOCUMENT_NODE &&
+ parentType !== NODE_TYPE.DOCUMENT_FRAGMENT_NODE &&
+ parentType !== NODE_TYPE.ELEMENT_NODE
+ ) {
+ throw DOMException.create(this._globalObject, [
+ `Node can't be inserted in a ${parentName} parent.`,
+ "HierarchyRequestError"
+ ]);
+ }
+
+ if (isHostInclusiveAncestor(nodeImpl, this)) {
+ throw DOMException.create(this._globalObject, [
+ "The operation would yield an incorrect node tree.",
+ "HierarchyRequestError"
+ ]);
+ }
+
+ if (childImpl && domSymbolTree.parent(childImpl) !== this) {
+ throw DOMException.create(this._globalObject, [
+ "The child can not be found in the parent.",
+ "NotFoundError"
+ ]);
+ }
+
+ if (
+ nodeType !== NODE_TYPE.DOCUMENT_FRAGMENT_NODE &&
+ nodeType !== NODE_TYPE.DOCUMENT_TYPE_NODE &&
+ nodeType !== NODE_TYPE.ELEMENT_NODE &&
+ nodeType !== NODE_TYPE.TEXT_NODE &&
+ nodeType !== NODE_TYPE.CDATA_SECTION_NODE && // CData section extends from Text
+ nodeType !== NODE_TYPE.PROCESSING_INSTRUCTION_NODE &&
+ nodeType !== NODE_TYPE.COMMENT_NODE
+ ) {
+ throw DOMException.create(this._globalObject, [
+ `${nodeName} node can't be inserted in parent node.`,
+ "HierarchyRequestError"
+ ]);
+ }
+
+ if (
+ (nodeType === NODE_TYPE.TEXT_NODE && parentType === NODE_TYPE.DOCUMENT_NODE) ||
+ (nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE && parentType !== NODE_TYPE.DOCUMENT_NODE)
+ ) {
+ throw DOMException.create(this._globalObject, [
+ `${nodeName} node can't be inserted in ${parentName} parent.`,
+ "HierarchyRequestError"
+ ]);
+ }
+
+ if (parentType === NODE_TYPE.DOCUMENT_NODE) {
+ const nodeChildren = domSymbolTree.childrenToArray(nodeImpl);
+ const parentChildren = domSymbolTree.childrenToArray(this);
+
+ switch (nodeType) {
+ case NODE_TYPE.DOCUMENT_FRAGMENT_NODE: {
+ const nodeChildrenElements = nodeChildren.filter(child => child.nodeType === NODE_TYPE.ELEMENT_NODE);
+ if (nodeChildrenElements.length > 1) {
+ throw DOMException.create(this._globalObject, [
+ `Invalid insertion of ${nodeName} node in ${parentName} node.`,
+ "HierarchyRequestError"
+ ]);
+ }
+
+ const hasNodeTextChildren = nodeChildren.some(child => child.nodeType === NODE_TYPE.TEXT_NODE);
+ if (hasNodeTextChildren) {
+ throw DOMException.create(this._globalObject, [
+ `Invalid insertion of ${nodeName} node in ${parentName} node.`,
+ "HierarchyRequestError"
+ ]);
+ }
+
+ if (
+ nodeChildrenElements.length === 1 &&
+ (
+ parentChildren.some(child => child.nodeType === NODE_TYPE.ELEMENT_NODE) ||
+ (childImpl && childImpl.nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE) ||
+ (
+ childImpl &&
+ domSymbolTree.nextSibling(childImpl) &&
+ domSymbolTree.nextSibling(childImpl).nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE
+ )
+ )
+ ) {
+ throw DOMException.create(this._globalObject, [
+ `Invalid insertion of ${nodeName} node in ${parentName} node.`,
+ "HierarchyRequestError"
+ ]);
+ }
+ break;
+ }
+
+ case NODE_TYPE.ELEMENT_NODE:
+ if (
+ parentChildren.some(child => child.nodeType === NODE_TYPE.ELEMENT_NODE) ||
+ (childImpl && childImpl.nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE) ||
+ (
+ childImpl &&
+ domSymbolTree.nextSibling(childImpl) &&
+ domSymbolTree.nextSibling(childImpl).nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE
+ )
+ ) {
+ throw DOMException.create(this._globalObject, [
+ `Invalid insertion of ${nodeName} node in ${parentName} node.`,
+ "HierarchyRequestError"
+ ]);
+ }
+ break;
+
+ case NODE_TYPE.DOCUMENT_TYPE_NODE:
+ if (
+ parentChildren.some(child => child.nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE) ||
+ (
+ childImpl &&
+ domSymbolTree.previousSibling(childImpl) &&
+ domSymbolTree.previousSibling(childImpl).nodeType === NODE_TYPE.ELEMENT_NODE
+ ) ||
+ (!childImpl && parentChildren.some(child => child.nodeType === NODE_TYPE.ELEMENT_NODE))
+ ) {
+ throw DOMException.create(this._globalObject, [
+ `Invalid insertion of ${nodeName} node in ${parentName} node.`,
+ "HierarchyRequestError"
+ ]);
+ }
+ break;
+ }
+ }
+ }
+
+ // https://dom.spec.whatwg.org/#concept-node-pre-insert
+ _preInsert(nodeImpl, childImpl) {
+ this._preInsertValidity(nodeImpl, childImpl);
+
+ let referenceChildImpl = childImpl;
+ if (referenceChildImpl === nodeImpl) {
+ referenceChildImpl = domSymbolTree.nextSibling(nodeImpl);
+ }
+
+ this._ownerDocument._adoptNode(nodeImpl);
+
+ this._insert(nodeImpl, referenceChildImpl);
+
+ return nodeImpl;
+ }
+
+ // https://dom.spec.whatwg.org/#concept-node-insert
+ _insert(nodeImpl, childImpl, suppressObservers) {
+ const count = nodeImpl.nodeType === NODE_TYPE.DOCUMENT_FRAGMENT_NODE ?
+ domSymbolTree.childrenCount(nodeImpl) :
+ 1;
+
+ if (childImpl) {
+ const childIndex = domSymbolTree.index(childImpl);
+
+ for (const range of this._referencedRanges) {
+ const { _start, _end } = range;
+
+ if (_start.offset > childIndex) {
+ range._setLiveRangeStart(this, _start.offset + count);
+ }
+
+ if (_end.offset > childIndex) {
+ range._setLiveRangeEnd(this, _end.offset + count);
+ }
+ }
+ }
+
+ const nodesImpl = nodeImpl.nodeType === NODE_TYPE.DOCUMENT_FRAGMENT_NODE ?
+ domSymbolTree.childrenToArray(nodeImpl) :
+ [nodeImpl];
+
+ if (nodeImpl.nodeType === NODE_TYPE.DOCUMENT_FRAGMENT_NODE) {
+ let grandChildImpl;
+ while ((grandChildImpl = domSymbolTree.firstChild(nodeImpl))) {
+ nodeImpl._remove(grandChildImpl, true);
+ }
+ }
+
+ if (nodeImpl.nodeType === NODE_TYPE.DOCUMENT_FRAGMENT_NODE) {
+ queueTreeMutationRecord(nodeImpl, [], nodesImpl, null, null);
+ }
+
+ const previousChildImpl = childImpl ?
+ domSymbolTree.previousSibling(childImpl) :
+ domSymbolTree.lastChild(this);
+
+ for (const node of nodesImpl) {
+ if (!childImpl) {
+ domSymbolTree.appendChild(this, node);
+ } else {
+ domSymbolTree.insertBefore(childImpl, node);
+ }
+
+ if (
+ (this.nodeType === NODE_TYPE.ELEMENT_NODE && this._shadowRoot !== null) &&
+ (node.nodeType === NODE_TYPE.ELEMENT_NODE || node.nodeType === NODE_TYPE.TEXT_NODE)
+ ) {
+ assignSlot(node);
+ }
+
+ this._modified();
+
+ if (node.nodeType === NODE_TYPE.TEXT_NODE ||
+ node.nodeType === NODE_TYPE.CDATA_SECTION_NODE) {
+ this._childTextContentChangeSteps();
+ }
+
+ if (isSlot(this) && this._assignedNodes.length === 0 && isShadowRoot(nodeRoot(this))) {
+ signalSlotChange(this);
+ }
+
+ const root = nodeRoot(node);
+ if (isShadowRoot(root)) {
+ assignSlotableForTree(root);
+ }
+
+ if (this._attached && nodeImpl._attach) {
+ node._attach();
+ }
+
+ this._descendantAdded(this, node);
+
+ for (const inclusiveDescendant of shadowIncludingInclusiveDescendantsIterator(node)) {
+ if (inclusiveDescendant.isConnected) {
+ if (inclusiveDescendant._ceState === "custom") {
+ enqueueCECallbackReaction(inclusiveDescendant, "connectedCallback", []);
+ } else {
+ tryUpgradeElement(inclusiveDescendant);
+ }
+ }
+ }
+ }
+
+ if (!suppressObservers) {
+ queueTreeMutationRecord(this, nodesImpl, [], previousChildImpl, childImpl);
+ }
+ }
+
+ // https://dom.spec.whatwg.org/#concept-node-append
+ _append(nodeImpl) {
+ return this._preInsert(nodeImpl, null);
+ }
+
+ // https://dom.spec.whatwg.org/#concept-node-replace
+ _replace(nodeImpl, childImpl) {
+ const { nodeType, nodeName } = nodeImpl;
+ const { nodeType: parentType, nodeName: parentName } = this;
+
+ // Note: This section differs from the pre-insert validation algorithm.
+ if (
+ parentType !== NODE_TYPE.DOCUMENT_NODE &&
+ parentType !== NODE_TYPE.DOCUMENT_FRAGMENT_NODE &&
+ parentType !== NODE_TYPE.ELEMENT_NODE
+ ) {
+ throw DOMException.create(this._globalObject, [
+ `Node can't be inserted in a ${parentName} parent.`,
+ "HierarchyRequestError"
+ ]);
+ }
+
+ if (isHostInclusiveAncestor(nodeImpl, this)) {
+ throw DOMException.create(this._globalObject, [
+ "The operation would yield an incorrect node tree.",
+ "HierarchyRequestError"
+ ]);
+ }
+
+ if (childImpl && domSymbolTree.parent(childImpl) !== this) {
+ throw DOMException.create(this._globalObject, [
+ "The child can not be found in the parent.",
+ "NotFoundError"
+ ]);
+ }
+
+ if (
+ nodeType !== NODE_TYPE.DOCUMENT_FRAGMENT_NODE &&
+ nodeType !== NODE_TYPE.DOCUMENT_TYPE_NODE &&
+ nodeType !== NODE_TYPE.ELEMENT_NODE &&
+ nodeType !== NODE_TYPE.TEXT_NODE &&
+ nodeType !== NODE_TYPE.CDATA_SECTION_NODE && // CData section extends from Text
+ nodeType !== NODE_TYPE.PROCESSING_INSTRUCTION_NODE &&
+ nodeType !== NODE_TYPE.COMMENT_NODE
+ ) {
+ throw DOMException.create(this._globalObject, [
+ `${nodeName} node can't be inserted in parent node.`,
+ "HierarchyRequestError"
+ ]);
+ }
+
+ if (
+ (nodeType === NODE_TYPE.TEXT_NODE && parentType === NODE_TYPE.DOCUMENT_NODE) ||
+ (nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE && parentType !== NODE_TYPE.DOCUMENT_NODE)
+ ) {
+ throw DOMException.create(this._globalObject, [
+ `${nodeName} node can't be inserted in ${parentName} parent.`,
+ "HierarchyRequestError"
+ ]);
+ }
+
+ if (parentType === NODE_TYPE.DOCUMENT_NODE) {
+ const nodeChildren = domSymbolTree.childrenToArray(nodeImpl);
+ const parentChildren = domSymbolTree.childrenToArray(this);
+
+ switch (nodeType) {
+ case NODE_TYPE.DOCUMENT_FRAGMENT_NODE: {
+ const nodeChildrenElements = nodeChildren.filter(child => child.nodeType === NODE_TYPE.ELEMENT_NODE);
+ if (nodeChildrenElements.length > 1) {
+ throw DOMException.create(this._globalObject, [
+ `Invalid insertion of ${nodeName} node in ${parentName} node.`,
+ "HierarchyRequestError"
+ ]);
+ }
+
+ const hasNodeTextChildren = nodeChildren.some(child => child.nodeType === NODE_TYPE.TEXT_NODE);
+ if (hasNodeTextChildren) {
+ throw DOMException.create(this._globalObject, [
+ `Invalid insertion of ${nodeName} node in ${parentName} node.`,
+ "HierarchyRequestError"
+ ]);
+ }
+
+
+ const parentChildElements = parentChildren.filter(child => child.nodeType === NODE_TYPE.ELEMENT_NODE);
+ if (
+ nodeChildrenElements.length === 1 &&
+ (
+ (parentChildElements.length === 1 && parentChildElements[0] !== childImpl) ||
+ (
+ childImpl &&
+ domSymbolTree.nextSibling(childImpl) &&
+ domSymbolTree.nextSibling(childImpl).nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE
+ )
+ )
+ ) {
+ throw DOMException.create(this._globalObject, [
+ `Invalid insertion of ${nodeName} node in ${parentName} node.`,
+ "HierarchyRequestError"
+ ]);
+ }
+ break;
+ }
+
+ case NODE_TYPE.ELEMENT_NODE:
+ if (
+ parentChildren.some(child => child.nodeType === NODE_TYPE.ELEMENT_NODE && child !== childImpl) ||
+ (
+ childImpl &&
+ domSymbolTree.nextSibling(childImpl) &&
+ domSymbolTree.nextSibling(childImpl).nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE
+ )
+ ) {
+ throw DOMException.create(this._globalObject, [
+ `Invalid insertion of ${nodeName} node in ${parentName} node.`,
+ "HierarchyRequestError"
+ ]);
+ }
+ break;
+
+ case NODE_TYPE.DOCUMENT_TYPE_NODE:
+ if (
+ parentChildren.some(child => child.nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE && child !== childImpl) ||
+ (
+ childImpl &&
+ domSymbolTree.previousSibling(childImpl) &&
+ domSymbolTree.previousSibling(childImpl).nodeType === NODE_TYPE.ELEMENT_NODE
+ )
+ ) {
+ throw DOMException.create(this._globalObject, [
+ `Invalid insertion of ${nodeName} node in ${parentName} node.`,
+ "HierarchyRequestError"
+ ]);
+ }
+ break;
+ }
+ }
+
+ let referenceChildImpl = domSymbolTree.nextSibling(childImpl);
+ if (referenceChildImpl === nodeImpl) {
+ referenceChildImpl = domSymbolTree.nextSibling(nodeImpl);
+ }
+
+ const previousSiblingImpl = domSymbolTree.previousSibling(childImpl);
+
+ this._ownerDocument._adoptNode(nodeImpl);
+
+ let removedNodesImpl = [];
+
+ if (domSymbolTree.parent(childImpl)) {
+ removedNodesImpl = [childImpl];
+ this._remove(childImpl, true);
+ }
+
+ const nodesImpl = nodeImpl.nodeType === NODE_TYPE.DOCUMENT_FRAGMENT_NODE ?
+ domSymbolTree.childrenToArray(nodeImpl) :
+ [nodeImpl];
+
+ this._insert(nodeImpl, referenceChildImpl, true);
+
+ queueTreeMutationRecord(this, nodesImpl, removedNodesImpl, previousSiblingImpl, referenceChildImpl);
+
+ return childImpl;
+ }
+
+ // https://dom.spec.whatwg.org/#concept-node-replace-all
+ _replaceAll(nodeImpl) {
+ if (nodeImpl !== null) {
+ this._ownerDocument._adoptNode(nodeImpl);
+ }
+
+ const removedNodesImpl = domSymbolTree.childrenToArray(this);
+
+ let addedNodesImpl;
+ if (nodeImpl === null) {
+ addedNodesImpl = [];
+ } else if (nodeImpl.nodeType === NODE_TYPE.DOCUMENT_FRAGMENT_NODE) {
+ addedNodesImpl = domSymbolTree.childrenToArray(nodeImpl);
+ } else {
+ addedNodesImpl = [nodeImpl];
+ }
+
+ for (const childImpl of domSymbolTree.childrenIterator(this)) {
+ this._remove(childImpl, true);
+ }
+
+ if (nodeImpl !== null) {
+ this._insert(nodeImpl, null, true);
+ }
+
+ if (addedNodesImpl.length > 0 || removedNodesImpl.length > 0) {
+ queueTreeMutationRecord(this, addedNodesImpl, removedNodesImpl, null, null);
+ }
+ }
+
+ // https://dom.spec.whatwg.org/#concept-node-pre-remove
+ _preRemove(childImpl) {
+ if (domSymbolTree.parent(childImpl) !== this) {
+ throw DOMException.create(this._globalObject, [
+ "The node to be removed is not a child of this node.",
+ "NotFoundError"
+ ]);
+ }
+
+ this._remove(childImpl);
+
+ return childImpl;
+ }
+
+ // https://dom.spec.whatwg.org/#concept-node-remove
+ _remove(nodeImpl, suppressObservers) {
+ const index = domSymbolTree.index(nodeImpl);
+
+ for (const descendant of domSymbolTree.treeIterator(nodeImpl)) {
+ for (const range of descendant._referencedRanges) {
+ const { _start, _end } = range;
+
+ if (_start.node === descendant) {
+ range._setLiveRangeStart(this, index);
+ }
+
+ if (_end.node === descendant) {
+ range._setLiveRangeEnd(this, index);
+ }
+ }
+ }
+
+ for (const range of this._referencedRanges) {
+ const { _start, _end } = range;
+
+ if (_start.node === this && _start.offset > index) {
+ range._setLiveRangeStart(this, _start.offset - 1);
+ }
+
+ if (_end.node === this && _end.offset > index) {
+ range._setLiveRangeEnd(this, _end.offset - 1);
+ }
+ }
+
+ if (this._ownerDocument) {
+ this._ownerDocument._runPreRemovingSteps(nodeImpl);
+ }
+
+ const oldPreviousSiblingImpl = domSymbolTree.previousSibling(nodeImpl);
+ const oldNextSiblingImpl = domSymbolTree.nextSibling(nodeImpl);
+
+ domSymbolTree.remove(nodeImpl);
+
+ if (nodeImpl._assignedSlot) {
+ assignSlotable(nodeImpl._assignedSlot);
+ }
+
+ if (isSlot(this) && this._assignedNodes.length === 0 && isShadowRoot(nodeRoot(this))) {
+ signalSlotChange(this);
+ }
+
+ let hasSlotDescendant = isSlot(nodeImpl);
+ if (!hasSlotDescendant) {
+ for (const child of domSymbolTree.treeIterator(nodeImpl)) {
+ if (isSlot(child)) {
+ hasSlotDescendant = true;
+ break;
+ }
+ }
+ }
+
+ if (hasSlotDescendant) {
+ assignSlotableForTree(nodeRoot(this));
+ assignSlotableForTree(nodeImpl);
+ }
+
+ this._modified();
+ nodeImpl._detach();
+ this._descendantRemoved(this, nodeImpl);
+
+ if (this.isConnected) {
+ if (nodeImpl._ceState === "custom") {
+ enqueueCECallbackReaction(nodeImpl, "disconnectedCallback", []);
+ }
+
+ for (const descendantImpl of shadowIncludingDescendantsIterator(nodeImpl)) {
+ if (descendantImpl._ceState === "custom") {
+ enqueueCECallbackReaction(descendantImpl, "disconnectedCallback", []);
+ }
+ }
+ }
+
+ if (!suppressObservers) {
+ queueTreeMutationRecord(this, [], [nodeImpl], oldPreviousSiblingImpl, oldNextSiblingImpl);
+ }
+
+ if (nodeImpl.nodeType === NODE_TYPE.TEXT_NODE) {
+ this._childTextContentChangeSteps();
+ }
+ }
+}
+
+module.exports = {
+ implementation: NodeImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/NodeList-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/NodeList-impl.js
new file mode 100644
index 0000000..6f83035
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/NodeList-impl.js
@@ -0,0 +1,43 @@
+"use strict";
+
+const idlUtils = require("../generated/utils.js");
+
+exports.implementation = class NodeListImpl {
+ constructor(globalObject, args, privateData) {
+ if (privateData.nodes) {
+ this._list = [...privateData.nodes];
+ this._isLive = false;
+ } else {
+ this._list = [];
+ this._isLive = true;
+ this._version = -1;
+ this._element = privateData.element;
+ this._query = privateData.query;
+ this._update();
+ }
+ }
+ get length() {
+ this._update();
+ return this._list.length;
+ }
+ item(index) {
+ this._update();
+ return this._list[index] || null;
+ }
+ _update() {
+ if (this._isLive) {
+ if (this._version < this._element._version) {
+ const snapshot = this._query();
+ for (let i = 0; i < snapshot.length; i++) {
+ this._list[i] = snapshot[i];
+ }
+ this._list.length = snapshot.length;
+ this._version = this._element._version;
+ }
+ }
+ }
+ get [idlUtils.supportedPropertyIndices]() {
+ this._update();
+ return this._list.keys();
+ }
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/NonDocumentTypeChildNode-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/NonDocumentTypeChildNode-impl.js
new file mode 100644
index 0000000..21bbb15
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/NonDocumentTypeChildNode-impl.js
@@ -0,0 +1,28 @@
+"use strict";
+
+const { domSymbolTree } = require("../helpers/internal-constants");
+const NODE_TYPE = require("../node-type");
+
+class NonDocumentTypeChildNodeImpl {
+ get nextElementSibling() {
+ for (const sibling of domSymbolTree.nextSiblingsIterator(this)) {
+ if (sibling.nodeType === NODE_TYPE.ELEMENT_NODE) {
+ return sibling;
+ }
+ }
+ return null;
+ }
+
+ get previousElementSibling() {
+ for (const sibling of domSymbolTree.previousSiblingsIterator(this)) {
+ if (sibling.nodeType === NODE_TYPE.ELEMENT_NODE) {
+ return sibling;
+ }
+ }
+ return null;
+ }
+}
+
+module.exports = {
+ implementation: NonDocumentTypeChildNodeImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/NonElementParentNode-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/NonElementParentNode-impl.js
new file mode 100644
index 0000000..ca8d578
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/NonElementParentNode-impl.js
@@ -0,0 +1,11 @@
+"use strict";
+
+// https://dom.spec.whatwg.org/#interface-nonelementparentnode
+// getElementById is implemented separately inside Document and DocumentFragment.
+class NonElementParentNodeImpl {
+
+}
+
+module.exports = {
+ implementation: NonElementParentNodeImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/ParentNode-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/ParentNode-impl.js
new file mode 100644
index 0000000..0b7bd65
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/ParentNode-impl.js
@@ -0,0 +1,91 @@
+"use strict";
+
+const idlUtils = require("../generated/utils");
+const NodeList = require("../generated/NodeList");
+const HTMLCollection = require("../generated/HTMLCollection");
+const { addNwsapi } = require("../helpers/selectors");
+const { domSymbolTree } = require("../helpers/internal-constants");
+const NODE_TYPE = require("../node-type");
+const { convertNodesIntoNode } = require("../node");
+
+class ParentNodeImpl {
+ get children() {
+ if (!this._childrenList) {
+ this._childrenList = HTMLCollection.createImpl(this._globalObject, [], {
+ element: this,
+ query: () => domSymbolTree.childrenToArray(this, {
+ filter: node => node.nodeType === NODE_TYPE.ELEMENT_NODE
+ })
+ });
+ } else {
+ this._childrenList._update();
+ }
+ return this._childrenList;
+ }
+
+ get firstElementChild() {
+ for (const child of domSymbolTree.childrenIterator(this)) {
+ if (child.nodeType === NODE_TYPE.ELEMENT_NODE) {
+ return child;
+ }
+ }
+
+ return null;
+ }
+
+ get lastElementChild() {
+ for (const child of domSymbolTree.childrenIterator(this, { reverse: true })) {
+ if (child.nodeType === NODE_TYPE.ELEMENT_NODE) {
+ return child;
+ }
+ }
+
+ return null;
+ }
+
+ get childElementCount() {
+ return this.children.length;
+ }
+
+ prepend(...nodes) {
+ this._preInsert(convertNodesIntoNode(this._ownerDocument, nodes), this.firstChild);
+ }
+
+ append(...nodes) {
+ this._append(convertNodesIntoNode(this._ownerDocument, nodes));
+ }
+
+ replaceChildren(...nodes) {
+ const node = convertNodesIntoNode(this._ownerDocument, nodes);
+ this._preInsertValidity(node, null);
+ this._replaceAll(node);
+ }
+
+ querySelector(selectors) {
+ if (shouldAlwaysSelectNothing(this)) {
+ return null;
+ }
+ const matcher = addNwsapi(this);
+ return idlUtils.implForWrapper(matcher.first(selectors, idlUtils.wrapperForImpl(this)));
+ }
+
+ // Warning for internal users: this returns a NodeList containing IDL wrappers instead of impls
+ querySelectorAll(selectors) {
+ if (shouldAlwaysSelectNothing(this)) {
+ return NodeList.create(this._globalObject, [], { nodes: [] });
+ }
+ const matcher = addNwsapi(this);
+ const list = matcher.select(selectors, idlUtils.wrapperForImpl(this));
+
+ return NodeList.create(this._globalObject, [], { nodes: list.map(n => idlUtils.tryImplForWrapper(n)) });
+ }
+}
+
+function shouldAlwaysSelectNothing(elImpl) {
+ // This is true during initialization.
+ return elImpl === elImpl._ownerDocument && !elImpl.documentElement;
+}
+
+module.exports = {
+ implementation: ParentNodeImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/ProcessingInstruction-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/ProcessingInstruction-impl.js
new file mode 100644
index 0000000..348dadc
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/ProcessingInstruction-impl.js
@@ -0,0 +1,22 @@
+"use strict";
+
+const CharacterDataImpl = require("./CharacterData-impl").implementation;
+
+const NODE_TYPE = require("../node-type");
+
+class ProcessingInstructionImpl extends CharacterDataImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+
+ this.nodeType = NODE_TYPE.PROCESSING_INSTRUCTION_NODE;
+ this._target = privateData.target;
+ }
+
+ get target() {
+ return this._target;
+ }
+}
+
+module.exports = {
+ implementation: ProcessingInstructionImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/SVGElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/SVGElement-impl.js
new file mode 100644
index 0000000..400034d
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/SVGElement-impl.js
@@ -0,0 +1,64 @@
+"use strict";
+
+const { domSymbolTree } = require("../helpers/internal-constants");
+const { SVG_NS } = require("../helpers/namespaces");
+const { mixin } = require("../../utils");
+const SVGAnimatedString = require("../generated/SVGAnimatedString");
+const ElementImpl = require("./Element-impl").implementation;
+const ElementCSSInlineStyleImpl = require("./ElementCSSInlineStyle-impl").implementation;
+const GlobalEventHandlersImpl = require("./GlobalEventHandlers-impl").implementation;
+const HTMLOrSVGElementImpl = require("./HTMLOrSVGElement-impl").implementation;
+
+class SVGElementImpl extends ElementImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+ this._initHTMLOrSVGElement();
+ this._initElementCSSInlineStyle();
+ this._initGlobalEvents();
+ }
+
+ // Keep in sync with HTMLElement. https://github.com/jsdom/jsdom/issues/2599
+ _attrModified(name, value, oldValue) {
+ if (name === "style" && value !== oldValue && !this._settingCssText) {
+ this._settingCssText = true;
+ this._style.cssText = value;
+ this._settingCssText = false;
+ } else if (name.startsWith("on")) {
+ this._globalEventChanged(name.substring(2));
+ }
+
+ super._attrModified(name, value, oldValue);
+ }
+
+ get className() {
+ return SVGAnimatedString.createImpl(this._globalObject, [], {
+ element: this,
+ attribute: "class"
+ });
+ }
+
+ get ownerSVGElement() {
+ let e = domSymbolTree.parent(this);
+ while (e && e.namespaceURI === SVG_NS) {
+ if (e.localName === "svg") {
+ return e;
+ }
+ e = domSymbolTree.parent(e);
+ }
+
+ return null;
+ }
+
+ get viewportElement() {
+ // TODO: <symbol>/<use> may make this different from ownerSVGElement.
+ return this.ownerSVGElement;
+ }
+}
+
+SVGElementImpl.attributeRegistry = new Map();
+
+mixin(SVGElementImpl.prototype, ElementCSSInlineStyleImpl.prototype);
+mixin(SVGElementImpl.prototype, GlobalEventHandlersImpl.prototype);
+mixin(SVGElementImpl.prototype, HTMLOrSVGElementImpl.prototype);
+
+exports.implementation = SVGElementImpl;
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/SVGGraphicsElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/SVGGraphicsElement-impl.js
new file mode 100644
index 0000000..ef0ec1d
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/SVGGraphicsElement-impl.js
@@ -0,0 +1,16 @@
+"use strict";
+
+const { mixin } = require("../../utils");
+const SVGElementImpl = require("./SVGElement-impl").implementation;
+const SVGTestsImpl = require("./SVGTests-impl").implementation;
+
+class SVGGraphicsElementImpl extends SVGElementImpl {}
+
+SVGGraphicsElementImpl.attributeRegistry = new Map([
+ ...SVGElementImpl.attributeRegistry,
+ ...SVGTestsImpl.attributeRegistry
+]);
+
+mixin(SVGGraphicsElementImpl.prototype, SVGTestsImpl.prototype);
+
+exports.implementation = SVGGraphicsElementImpl;
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/SVGSVGElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/SVGSVGElement-impl.js
new file mode 100644
index 0000000..5dbc9e3
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/SVGSVGElement-impl.js
@@ -0,0 +1,42 @@
+"use strict";
+
+const { mixin } = require("../../utils");
+const SVGNumber = require("../generated/SVGNumber");
+const SVGGraphicsElementImpl = require("./SVGGraphicsElement-impl").implementation;
+const WindowEventHandlersImpl = require("./WindowEventHandlers-impl").implementation;
+const { domSymbolTree } = require("../helpers/internal-constants");
+const { ELEMENT_NODE } = require("../node-type");
+
+class SVGSVGElementImpl extends SVGGraphicsElementImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+ this._proxyWindowEventsToWindow();
+ }
+
+ createSVGNumber() {
+ return SVGNumber.createImpl(this._globalObject, [], {});
+ }
+
+ getElementById(elementId) {
+ // TODO: optimize with _ids caching trick; see Document class.
+ for (const node of domSymbolTree.treeIterator(this)) {
+ if (node.nodeType === ELEMENT_NODE && node.getAttributeNS(null, "id") === elementId) {
+ return node;
+ }
+ }
+ return null;
+ }
+
+ suspendRedraw() {
+ return 1;
+ }
+ unsuspendRedraw() {}
+ unsuspendRedrawAll() {}
+ forceRedraw() {}
+}
+
+mixin(SVGSVGElementImpl.prototype, WindowEventHandlersImpl.prototype);
+
+module.exports = {
+ implementation: SVGSVGElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/SVGTests-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/SVGTests-impl.js
new file mode 100644
index 0000000..6ff1182
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/SVGTests-impl.js
@@ -0,0 +1,42 @@
+"use strict";
+
+const { splitOnASCIIWhitespace, splitOnCommas } = require("../helpers/strings");
+const { reserializeCommaSeparatedTokens, reserializeSpaceSeparatedTokens } = require("../helpers/svg/basic-types");
+const SVGStringList = require("../generated/SVGStringList");
+
+class SVGTestsImpl {
+ get requiredExtensions() {
+ return SVGStringList.createImpl(this._globalObject, [], {
+ element: this,
+ attribute: "requiredExtensions"
+ });
+ }
+
+ get systemLanguage() {
+ return SVGStringList.createImpl(this._globalObject, [], {
+ element: this,
+ attribute: "systemLanguage"
+ });
+ }
+}
+
+SVGTestsImpl.attributeRegistry = new Map([
+ // https://svgwg.org/svg2-draft/struct.html#RequiredExtensionsAttribute
+ [
+ "requiredExtensions", {
+ getValue: splitOnASCIIWhitespace,
+ serialize: reserializeSpaceSeparatedTokens,
+ initialValue: undefined
+ }
+ ],
+ // https://svgwg.org/svg2-draft/struct.html#SystemLanguageAttribute
+ [
+ "systemLanguage", {
+ getValue: splitOnCommas,
+ serialize: reserializeCommaSeparatedTokens,
+ initialValue: undefined
+ }
+ ]
+]);
+
+exports.implementation = SVGTestsImpl;
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/SVGTitleElement-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/SVGTitleElement-impl.js
new file mode 100644
index 0000000..7a9187d
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/SVGTitleElement-impl.js
@@ -0,0 +1,9 @@
+"use strict";
+
+const SVGElementImpl = require("./SVGElement-impl").implementation;
+
+class SVGTitleElementImpl extends SVGElementImpl { }
+
+module.exports = {
+ implementation: SVGTitleElementImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/ShadowRoot-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/ShadowRoot-impl.js
new file mode 100644
index 0000000..820deb2
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/ShadowRoot-impl.js
@@ -0,0 +1,40 @@
+"use strict";
+
+const { nodeRoot } = require("../helpers/node");
+const { mixin } = require("../../utils");
+
+const DocumentFragment = require("./DocumentFragment-impl").implementation;
+const DocumentOrShadowRootImpl = require("./DocumentOrShadowRoot-impl").implementation;
+const InnerHTMLImpl = require("../domparsing/InnerHTML-impl").implementation;
+
+class ShadowRootImpl extends DocumentFragment {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, privateData);
+
+ const { mode } = privateData;
+ this._mode = mode;
+ }
+
+ _getTheParent(event) {
+ if (!event.composed && this === nodeRoot(event._path[0].item)) {
+ return null;
+ }
+
+ return this._host;
+ }
+
+ get mode() {
+ return this._mode;
+ }
+
+ get host() {
+ return this._host;
+ }
+}
+
+mixin(ShadowRootImpl.prototype, DocumentOrShadowRootImpl.prototype);
+mixin(ShadowRootImpl.prototype, InnerHTMLImpl.prototype);
+
+module.exports = {
+ implementation: ShadowRootImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/Slotable-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/Slotable-impl.js
new file mode 100644
index 0000000..5746a01
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/Slotable-impl.js
@@ -0,0 +1,48 @@
+"use strict";
+
+const { findSlot, assignSlot, assignSlotable } = require("../helpers/shadow-dom");
+
+// https://dom.spec.whatwg.org/#mixin-slotable
+// https://dom.spec.whatwg.org/#light-tree-slotables
+class SlotableMixinImpl {
+ _initSlotableMixin() {
+ this._slotableName = "";
+ }
+
+ _attrModifiedSlotableMixin(name, value, oldValue) {
+ if (name === "slot") {
+ if (value === oldValue) {
+ return;
+ }
+
+ if (value === null && oldValue === "") {
+ return;
+ }
+
+ if (value === "" && oldValue === null) {
+ return;
+ }
+
+ if (value === null || value === "") {
+ this._slotableName = "";
+ } else {
+ this._slotableName = value;
+ }
+
+
+ if (this._assignedSlot) {
+ assignSlotable(this._assignedSlot);
+ }
+
+ assignSlot(this);
+ }
+ }
+
+ get assignedSlot() {
+ return findSlot(this, "open");
+ }
+}
+
+module.exports = {
+ implementation: SlotableMixinImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/Text-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/Text-impl.js
new file mode 100644
index 0000000..ddd0fff
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/Text-impl.js
@@ -0,0 +1,96 @@
+"use strict";
+const SlotableMixinImpl = require("./Slotable-impl").implementation;
+const CharacterDataImpl = require("./CharacterData-impl").implementation;
+const idlUtils = require("../generated/utils");
+const { domSymbolTree } = require("../helpers/internal-constants");
+const DOMException = require("domexception/webidl2js-wrapper");
+const NODE_TYPE = require("../node-type");
+const { mixin } = require("../../utils");
+
+// https://dom.spec.whatwg.org/#text
+class TextImpl extends CharacterDataImpl {
+ constructor(globalObject, args, privateData) {
+ super(globalObject, args, {
+ data: args[0],
+ ownerDocument: idlUtils.implForWrapper(globalObject._document),
+ ...privateData
+ });
+
+ this._initSlotableMixin();
+
+ this.nodeType = NODE_TYPE.TEXT_NODE;
+ }
+
+ // https://dom.spec.whatwg.org/#dom-text-splittext
+ // https://dom.spec.whatwg.org/#concept-text-split
+ splitText(offset) {
+ const { length } = this;
+
+ if (offset > length) {
+ throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+ }
+
+ const count = length - offset;
+ const newData = this.substringData(offset, count);
+
+ const newNode = this._ownerDocument.createTextNode(newData);
+
+ const parent = domSymbolTree.parent(this);
+
+ if (parent !== null) {
+ parent._insert(newNode, this.nextSibling);
+
+ for (const range of this._referencedRanges) {
+ const { _start, _end } = range;
+
+ if (_start.node === this && _start.offset > offset) {
+ range._setLiveRangeStart(newNode, _start.offset - offset);
+ }
+
+ if (_end.node === this && _end.offset > offset) {
+ range._setLiveRangeEnd(newNode, _end.offset - offset);
+ }
+ }
+
+ const nodeIndex = domSymbolTree.index(this);
+ for (const range of parent._referencedRanges) {
+ const { _start, _end } = range;
+
+ if (_start.node === parent && _start.offset === nodeIndex + 1) {
+ range._setLiveRangeStart(parent, _start.offset + 1);
+ }
+
+ if (_end.node === parent && _end.offset === nodeIndex + 1) {
+ range._setLiveRangeEnd(parent, _end.offset + 1);
+ }
+ }
+ }
+
+ this.replaceData(offset, count, "");
+
+ return newNode;
+ }
+
+ // https://dom.spec.whatwg.org/#dom-text-wholetext
+ get wholeText() {
+ let wholeText = this.textContent;
+ let next;
+ let current = this;
+ while ((next = domSymbolTree.previousSibling(current)) && next.nodeType === NODE_TYPE.TEXT_NODE) {
+ wholeText = next.textContent + wholeText;
+ current = next;
+ }
+ current = this;
+ while ((next = domSymbolTree.nextSibling(current)) && next.nodeType === NODE_TYPE.TEXT_NODE) {
+ wholeText += next.textContent;
+ current = next;
+ }
+ return wholeText;
+ }
+}
+
+mixin(TextImpl.prototype, SlotableMixinImpl.prototype);
+
+module.exports = {
+ implementation: TextImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/WindowEventHandlers-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/WindowEventHandlers-impl.js
new file mode 100644
index 0000000..bce1989
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/WindowEventHandlers-impl.js
@@ -0,0 +1,52 @@
+"use strict";
+
+const { createEventAccessor } = require("../helpers/create-event-accessor");
+
+const events = new Set([
+ // WindowEventHandlers
+ "afterprint",
+ "beforeprint",
+ "beforeunload",
+ "hashchange",
+ "languagechange",
+ "message",
+ "messageerror",
+ "offline",
+ "online",
+ "pagehide",
+ "pageshow",
+ "popstate",
+ "rejectionhandled",
+ "storage",
+ "unhandledrejection",
+ "unload",
+
+ // inherited and overridden
+ "blur",
+ "error",
+ "focus",
+ "load",
+ "resize",
+ "scroll"
+]);
+
+// This class builds on GlobalEventHandlers, which must be mixed in first.
+class WindowEventHandlersImpl {
+ _proxyWindowEventsToWindow() {
+ // We're a <body> or <frameset>, so we need to proxy these specific events to the Window (if it exists)
+ this._getEventHandlerTarget = event => {
+ if (events.has(event)) {
+ return this.ownerDocument.defaultView || null;
+ }
+ return this;
+ };
+ }
+}
+
+for (const event of events) {
+ createEventAccessor(WindowEventHandlersImpl.prototype, event);
+}
+
+module.exports = {
+ implementation: WindowEventHandlersImpl
+};
diff --git a/school/node_modules/jsdom/lib/jsdom/living/nodes/XMLDocument-impl.js b/school/node_modules/jsdom/lib/jsdom/living/nodes/XMLDocument-impl.js
new file mode 100644
index 0000000..487db01
--- /dev/null
+++ b/school/node_modules/jsdom/lib/jsdom/living/nodes/XMLDocument-impl.js
@@ -0,0 +1,4 @@
+"use strict";
+const DocumentImpl = require("./Document-impl").implementation;
+
+exports.implementation = class XMLDocumentImpl extends DocumentImpl {};