Skip to content

Commit

Permalink
WIP integrate global object
Browse files Browse the repository at this point in the history
  • Loading branch information
pmdartus committed Nov 28, 2019
1 parent 1d00c81 commit 32fb6e4
Show file tree
Hide file tree
Showing 13 changed files with 67 additions and 194 deletions.
7 changes: 4 additions & 3 deletions lib/jsdom/browser/Window.js
Expand Up @@ -117,6 +117,8 @@ function Window(options) {
global: this
}
});
this._documentImpl = idlUtils.implForWrapper(this._document);

// https://html.spec.whatwg.org/#session-history
this._sessionHistory = new SessionHistory({
document: idlUtils.implForWrapper(this._document),
Expand Down Expand Up @@ -528,9 +530,8 @@ function Window(options) {
return declaration;
};

this.customElements = CustomElementRegistry.create([], {
_ownerDocument: idlUtils.implForWrapper(this._document)
});
// TODO: Make it a getter
this.customElements = CustomElementRegistry.create(window);

// The captureEvents() and releaseEvents() methods must do nothing
this.captureEvents = function () {};
Expand Down
7 changes: 0 additions & 7 deletions lib/jsdom/living/attributes/Attr-impl.js
@@ -1,8 +1,6 @@
"use strict";

const { mixin } = require("../../utils");
const attributes = require("../attributes.js");
const { CeReactions } = require("../helpers/custom-elements");

class AttrImpl {
constructor(globalObject, args, privateData) {
Expand Down Expand Up @@ -77,9 +75,4 @@ class AttrImpl {
}
}

// This is theoretically not needed. If the Attr interface would extend the Node interface it would inherit the
// CEReactions mixin.
// TODO: Remove this once the AttrImpl actually inherits from the NodeImpl.
mixin(AttrImpl.prototype, CeReactions.prototype);

exports.implementation = AttrImpl;
5 changes: 0 additions & 5 deletions lib/jsdom/living/attributes/NamedNodeMap-impl.js
Expand Up @@ -4,11 +4,8 @@ const DOMException = require("domexception");

const idlUtils = require("../generated/utils.js");

const { mixin } = require("../../utils");

const attributes = require("../attributes.js");
const { HTML_NS } = require("../helpers/namespaces");
const { CeReactions } = require("../helpers/custom-elements");

class NamedNodeMapImpl {
constructor(globalObject, args, privateData) {
Expand Down Expand Up @@ -74,6 +71,4 @@ class NamedNodeMapImpl {
}
}

mixin(NamedNodeMapImpl.prototype, CeReactions.prototype);

exports.implementation = NamedNodeMapImpl;
29 changes: 15 additions & 14 deletions lib/jsdom/living/create-element.js
Expand Up @@ -444,16 +444,17 @@ function getSVGInterface(name) {
}

// https://dom.spec.whatwg.org/#concept-create-element
function createElement(documentImpl, localName, namespace, prefix = null, isValue = null, synchronousCE = false) {
function createElement(document, localName, namespace, prefix = null, isValue = null, synchronousCE = false) {
let result = null;

const definition = lookupCEDefinition(documentImpl, namespace, localName, isValue);
const { _globalObject } = document;
const definition = lookupCEDefinition(document, namespace, localName, isValue);

if (definition !== null && definition.name !== localName) {
const elementInterface = getHTMLElementInterface(localName);

result = elementInterface.interface.createImpl([], {
ownerDocument: documentImpl,
result = elementInterface.interface.createImpl(_globalObject, [], {
ownerDocument: document,
localName,
namespace: HTML_NS,
prefix,
Expand Down Expand Up @@ -488,7 +489,7 @@ function createElement(documentImpl, localName, namespace, prefix = null, isValu
if (domSymbolTree.parent(result)) {
throw new DOMException("Unexpected element parent.", "NotSupportedError");
}
if (result._ownerDocument !== documentImpl) {
if (result._ownerDocument !== document) {
throw new DOMException("Unexpected element owner document.", "NotSupportedError");
}
if (result._namespaceURI !== namespace) {
Expand All @@ -501,10 +502,10 @@ function createElement(documentImpl, localName, namespace, prefix = null, isValu
result._prefix = prefix;
result._isValue = isValue;
} catch (error) {
reportException(documentImpl._defaultView, error);
reportException(document._defaultView, error);

result = HTMLUnknownElement.interface.createImpl([], {
ownerDocument: documentImpl,
result = HTMLUnknownElement.interface.createImpl(_globalObject, [], {
ownerDocument: document,
localName,
namespace: HTML_NS,
prefix,
Expand All @@ -514,8 +515,8 @@ function createElement(documentImpl, localName, namespace, prefix = null, isValu
});
}
} else {
result = HTMLElement.interface.createImpl([], {
ownerDocument: documentImpl,
result = HTMLElement.interface.createImpl(_globalObject, [], {
ownerDocument: document,
localName,
namespace: HTML_NS,
prefix,
Expand Down Expand Up @@ -543,8 +544,8 @@ function createElement(documentImpl, localName, namespace, prefix = null, isValu
break;
}

result = elementInterface.interface.createImpl([], {
ownerDocument: documentImpl,
result = elementInterface.interface.createImpl(_globalObject, [], {
ownerDocument: document,
localName,
namespace,
prefix,
Expand All @@ -562,15 +563,15 @@ function createElement(documentImpl, localName, namespace, prefix = null, isValu
}

// https://dom.spec.whatwg.org/#internal-createelementns-steps
function createElementNS(documentImpl, namespace, qualifiedName, options) {
function createElementNS(document, namespace, qualifiedName, options) {
const extracted = validateAndExtract(namespace, qualifiedName);

let isValue = null;
if (options && options.is !== undefined) {
isValue = options.is;
}

return createElement(documentImpl, extracted.localName, extracted.namespace, extracted.prefix, isValue, true);
return createElement(document, extracted.localName, extracted.namespace, extracted.prefix, isValue, true);
}

module.exports = {
Expand Down
15 changes: 6 additions & 9 deletions lib/jsdom/living/custom-elements/CustomElementRegistry-impl.js
Expand Up @@ -5,12 +5,10 @@ const webIDLConversions = require("webidl-conversions");

const NODE_TYPE = require("../node-type");
const { getHTMLElementInterface } = require("../create-element");
const { mixin } = require("../../utils");

const { HTML_NS } = require("../helpers/namespaces");
const { CeReactions, isValidCustomElementName, tryUpgradeElement,
enqueueCEUpgradeReaction } = require("../helpers/custom-elements");
const { shadowIncludingInclusiveDescendantsIterator } = require("../helpers/shadow-dom");
const { isValidCustomElementName, tryUpgradeElement, enqueueCEUpgradeReaction } = require("../helpers/custom-elements");

const LIFECYCLE_CALLBACKS = [
"connectedCallback",
Expand Down Expand Up @@ -48,13 +46,12 @@ function isConstructor(value) {

// https://html.spec.whatwg.org/#customelementregistry
class CustomElementRegistryImpl {
constructor(args, privateData) {
constructor(globalObject) {
this._customElementDefinitions = [];
this._elementDefinitionIsRunning = false;
this._whenDefinedPromiseMap = Object.create(null);

const { _ownerDocument } = privateData;
this._ownerDocument = _ownerDocument;
this._globalObject = globalObject;
}

// https://html.spec.whatwg.org/#dom-customelementregistry-define
Expand Down Expand Up @@ -171,8 +168,10 @@ class CustomElementRegistryImpl {

this._customElementDefinitions.push(definition);

const document = this._globalObject._documentImpl;

const upgradeCandidates = [];
for (const candidate of shadowIncludingInclusiveDescendantsIterator(this._ownerDocument)) {
for (const candidate of shadowIncludingInclusiveDescendantsIterator(document)) {
if (
(candidate._namespaceURI === HTML_NS && candidate._localName === localName) &&
(extendsOption === null || candidate._isValue === name)
Expand Down Expand Up @@ -235,8 +234,6 @@ class CustomElementRegistryImpl {
}
}

mixin(CustomElementRegistryImpl.prototype, CeReactions.prototype);

module.exports = {
implementation: CustomElementRegistryImpl
};
38 changes: 17 additions & 21 deletions lib/jsdom/living/helpers/custom-elements.js
Expand Up @@ -10,6 +10,14 @@ const reportException = require("./runtime-script-errors");

const { implForWrapper, wrapperForImpl } = require("../generated/utils");

// https://dom.spec.whatwg.org/#concept-element-custom-element-state
const CUSTOM_ELEMENT_STATE = {
UNDEFINED: "undefined",
FAILED: "failed",
UNCUSTOMIZED: "uncustomized",
CUSTOM: "custom"
};

// https://html.spec.whatwg.org/multipage/custom-elements.html#custom-element-reactions-stack
class CEReactionsStack {
constructor() {
Expand Down Expand Up @@ -40,30 +48,17 @@ class CEReactionsStack {
}
}

// TODO: Attach this the global object.
const CUSTOM_ELEMENT_REACTIONS_STACK = new CEReactionsStack();

// https://html.spec.whatwg.org/multipage/custom-elements.html#cereactions
//
// This class should be applied as a mixin to all the interfaces where on the properties is marked with the
// [CEReactions] IDL extended attribute.
class CeReactions {
_ceReactionsPreSteps() {
CUSTOM_ELEMENT_REACTIONS_STACK.push([]);
}

_ceReactionsPostSteps() {
const queue = CUSTOM_ELEMENT_REACTIONS_STACK.pop();
invokeCEReactions(queue);
}
function ceReactionsPreSteps() {
CUSTOM_ELEMENT_REACTIONS_STACK.push([]);
}
function ceReactionsPostSteps() {
const queue = CUSTOM_ELEMENT_REACTIONS_STACK.pop();
invokeCEReactions(queue);
}

// https://dom.spec.whatwg.org/#concept-element-custom-element-state
const CUSTOM_ELEMENT_STATE = {
UNDEFINED: "undefined",
FAILED: "failed",
UNCUSTOMIZED: "uncustomized",
CUSTOM: "custom"
};

const RESTRICTED_CUSTOM_ELEMENT_NAME = new Set([
"annotation-xml",
Expand Down Expand Up @@ -265,7 +260,8 @@ module.exports = {
CUSTOM_ELEMENT_STATE,
CUSTOM_ELEMENT_REACTIONS_STACK,

CeReactions,
ceReactionsPreSteps,
ceReactionsPostSteps,

isValidCustomElementName,

Expand Down
86 changes: 4 additions & 82 deletions lib/jsdom/living/helpers/html-constructor.js
Expand Up @@ -8,83 +8,12 @@ const { CUSTOM_ELEMENT_STATE } = require("./custom-elements");
const { createElement, INTERFACE_TAG_MAPPING } = require("../create-element");
const { implForWrapper, wrapperForImpl } = require("../generated/utils");

const GENERATED_INTERFACES = [
require("../generated/HTMLElement.js"),
require("../generated/HTMLAnchorElement.js"),
require("../generated/HTMLAreaElement.js"),
require("../generated/HTMLAudioElement.js"),
require("../generated/HTMLBaseElement.js"),
require("../generated/HTMLBodyElement.js"),
require("../generated/HTMLBRElement.js"),
require("../generated/HTMLButtonElement.js"),
require("../generated/HTMLCanvasElement.js"),
require("../generated/HTMLDataElement.js"),
require("../generated/HTMLDataListElement.js"),
require("../generated/HTMLDetailsElement.js"),
require("../generated/HTMLDialogElement.js"),
require("../generated/HTMLDirectoryElement.js"),
require("../generated/HTMLDivElement.js"),
require("../generated/HTMLDListElement.js"),
require("../generated/HTMLEmbedElement.js"),
require("../generated/HTMLFieldSetElement.js"),
require("../generated/HTMLFontElement.js"),
require("../generated/HTMLFormElement.js"),
require("../generated/HTMLFrameElement.js"),
require("../generated/HTMLFrameSetElement.js"),
require("../generated/HTMLHeadingElement.js"),
require("../generated/HTMLHeadElement.js"),
require("../generated/HTMLHRElement.js"),
require("../generated/HTMLHtmlElement.js"),
require("../generated/HTMLIFrameElement.js"),
require("../generated/HTMLImageElement.js"),
require("../generated/HTMLInputElement.js"),
require("../generated/HTMLLabelElement.js"),
require("../generated/HTMLLegendElement.js"),
require("../generated/HTMLLIElement.js"),
require("../generated/HTMLLinkElement.js"),
require("../generated/HTMLMapElement.js"),
require("../generated/HTMLMarqueeElement.js"),
require("../generated/HTMLMenuElement.js"),
require("../generated/HTMLMetaElement.js"),
require("../generated/HTMLMeterElement.js"),
require("../generated/HTMLModElement.js"),
require("../generated/HTMLObjectElement.js"),
require("../generated/HTMLOListElement.js"),
require("../generated/HTMLOptGroupElement.js"),
require("../generated/HTMLOptionElement.js"),
require("../generated/HTMLOutputElement.js"),
require("../generated/HTMLParagraphElement.js"),
require("../generated/HTMLParamElement.js"),
require("../generated/HTMLPictureElement.js"),
require("../generated/HTMLPreElement.js"),
require("../generated/HTMLProgressElement.js"),
require("../generated/HTMLQuoteElement.js"),
require("../generated/HTMLScriptElement.js"),
require("../generated/HTMLSelectElement.js"),
require("../generated/HTMLSlotElement.js"),
require("../generated/HTMLSourceElement.js"),
require("../generated/HTMLSpanElement.js"),
require("../generated/HTMLStyleElement.js"),
require("../generated/HTMLTableCaptionElement.js"),
require("../generated/HTMLTableCellElement.js"),
require("../generated/HTMLTableColElement.js"),
require("../generated/HTMLTableElement.js"),
require("../generated/HTMLTimeElement.js"),
require("../generated/HTMLTitleElement.js"),
require("../generated/HTMLTableRowElement.js"),
require("../generated/HTMLTableSectionElement.js"),
require("../generated/HTMLTemplateElement.js"),
require("../generated/HTMLTextAreaElement.js"),
require("../generated/HTMLTrackElement.js"),
require("../generated/HTMLUListElement.js"),
require("../generated/HTMLVideoElement.js")
];

// https://html.spec.whatwg.org/multipage/custom-elements.html#concept-already-constructed-marker
const ALREADY_CONSTRUCTED_MARKER = Symbol("already-constructed-marker");

// TODO: Evaluate need to pass the constructor name
// https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor
function HTMLConstructor({ globalObject, newTarget, constructorName }) {
function HTMLConstructor(globalObject, newTarget) {
const registry = implForWrapper(globalObject.customElements);

if (newTarget === HTMLConstructor) {
Expand Down Expand Up @@ -121,8 +50,8 @@ function HTMLConstructor({ globalObject, newTarget, constructorName }) {
const documentImpl = implForWrapper(globalObject.document);

const elementImpl = createElement(documentImpl, definition.localName, HTML_NS);
const element = wrapperForImpl(elementImpl);

const element = wrapperForImpl(elementImpl);
Object.setPrototypeOf(element, prototype);

elementImpl._ceState = CUSTOM_ELEMENT_STATE.CUSTOM;
Expand All @@ -147,13 +76,6 @@ function HTMLConstructor({ globalObject, newTarget, constructorName }) {
return element;
}

function installHTMLConstructors(globalObject) {
for (const generatedInterface of GENERATED_INTERFACES) {
generatedInterface.installConstructor(globalObject, HTMLConstructor);
}
}

module.exports = {
HTMLConstructor,
installHTMLConstructors
HTMLConstructor
};
7 changes: 2 additions & 5 deletions lib/jsdom/living/interfaces.js
Expand Up @@ -5,7 +5,6 @@ const DOMException = require("domexception");
const { URL, URLSearchParams } = require("whatwg-url");
const XMLSerializer = require("w3c-xmlserializer/lib/XMLSerializer").interface;

const registerElements = require("./register-elements");
const style = require("../level2/style");
const xpath = require("../level3/xpath");
const nodeFilter = require("./node-filter");
Expand Down Expand Up @@ -165,6 +164,7 @@ const generatedInterfaces = [

require("./generated/Storage"),

require("./generated/CustomElementRegistry"),
require("./generated/ShadowRoot"),

require("./generated/MutationObserver"),
Expand Down Expand Up @@ -200,11 +200,8 @@ exports.installInterfaces = function (window) {
// https://html.spec.whatwg.org/#htmldocument
install(window, "HTMLDocument", window.Document);

// Install Elements
registerElements(window);

// These need to be cleaned up...
style.addToCore(window);
style(window);
xpath(window);

// This one is OK but needs migration to webidl2js eventually.
Expand Down

0 comments on commit 32fb6e4

Please sign in to comment.