From f9b90d28f7bfbe80d8da60eb1b019bcd26b4d198 Mon Sep 17 00:00:00 2001 From: Tim Branyen Date: Sun, 28 May 2017 19:37:06 -0700 Subject: [PATCH] Initial work for Custom Elements support Changes here paired with https://github.com/jsdom/webidl2js/pull/44 will enable `./test-web-components.js` to work. You will need to `npm install` before running `node ./test-web-components.js`. --- lib/jsdom/browser/Window.js | 13 ++++++ lib/jsdom/living/nodes/Document-impl.js | 5 +++ lib/jsdom/living/nodes/HTMLElement-impl.js | 1 + package.json | 2 +- test-web-components.js | 46 ++++++++++++++++++++++ 5 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 test-web-components.js diff --git a/lib/jsdom/browser/Window.js b/lib/jsdom/browser/Window.js index f769b926af..9b69142015 100644 --- a/lib/jsdom/browser/Window.js +++ b/lib/jsdom/browser/Window.js @@ -422,6 +422,19 @@ function Window(options) { }; ///// PUBLIC DATA PROPERTIES (TODO: should be getters) + this.customElements = new class CustomElementsRegistry { + get(tagName) { + return this[idlUtils.registry].get(tagName); + } + + define(tagName, constructor) { + this[idlUtils.registry].set(tagName, constructor); + } + + constructor() { + this[idlUtils.registry] = new Map(); + } + }; this.console = { assert: wrapConsoleMethod("assert"), diff --git a/lib/jsdom/living/nodes/Document-impl.js b/lib/jsdom/living/nodes/Document-impl.js index c0976c2fd7..fe1d682a1e 100644 --- a/lib/jsdom/living/nodes/Document-impl.js +++ b/lib/jsdom/living/nodes/Document-impl.js @@ -381,6 +381,11 @@ class DocumentImpl extends NodeImpl { } _createElementWithCorrectElementInterface(name, namespace) { + let Constructor = null; + + if (Constructor = this._global.window.customElements.get(name)) { + return new Constructor(); + } // https://dom.spec.whatwg.org/#concept-element-interface // TODO: eventually we should re-write the element-builder system to be namespace aware, but for now it is not. const builder = this._elementBuilders[name.toLowerCase()] || this._defaultElementBuilder.bind(this); diff --git a/lib/jsdom/living/nodes/HTMLElement-impl.js b/lib/jsdom/living/nodes/HTMLElement-impl.js index 9838c1dbbd..2efa795230 100644 --- a/lib/jsdom/living/nodes/HTMLElement-impl.js +++ b/lib/jsdom/living/nodes/HTMLElement-impl.js @@ -13,6 +13,7 @@ class HTMLElementImpl extends ElementImpl { constructor(args, privateData) { super(args, privateData); this._initGlobalEvents(); + this._core = this._core || global.window; this._tabIndex = 0; diff --git a/package.json b/package.json index f6a45efeaf..f4b1733b5f 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "st": "^1.2.0", "watchify": "^3.9.0", "wd": "^1.1.3", - "webidl2js": "^7.0.1" + "webidl2js": "jsdom/webidl2js#1868f38611e7d9b6e598036de129100bf5e98b6c" }, "browser": { "canvas": false, diff --git a/test-web-components.js b/test-web-components.js new file mode 100644 index 0000000000..d1fb0fe4cc --- /dev/null +++ b/test-web-components.js @@ -0,0 +1,46 @@ +// Modified JSDOM to allow `super` on `HTMLElement`. +const { JSDOM } = require('./'); +const { window } = new JSDOM('') + +// FIXME Necessary for now to get MyShinyComponent in the shared JSDOM window. +global.window = window; + +// Web Components on the way...! +const { HTMLElement, document, customElements } = window; + +// Plain ole Custom Element... +class MyShinyComponent extends HTMLElement { + constructor(props = { someMessage: 'Set via innerHTML' }) { + super(); + + this.innerHTML = `${props.someMessage}`; + } +} + +// Define into the internal JSDOM CustomElementsRegistry +customElements.define('my-shiny-component', MyShinyComponent); + +// Helper function to create a regular DOM Node or upgraded Custom Element. +function makeElement(tagName, props) { + const Constructor = customElements.get(tagName); + + if (Constructor) { + return new Constructor(props); + } + else { + document.createElement(tagName); + } +} + +//console.log( +// makeElement('my-shiny-component', { someMessage: 'Hello World' }).outerHTML +//); + +document.body.innerHTML = ''; + +/** + * + * + * @return + */ +console.log(document.body.outerHTML);