Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also .

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also .
base repository: webcomponents/custom-elements
base: master
head repository: bgrins/custom-elements
compare: firefox-browser-chrome
Checking mergeability… Don’t worry, you can still create the pull request.
  • 5 commits
  • 10 files changed
  • 0 comments
  • 1 contributor

Large diffs are not rendered by default.

Large diffs are not rendered by default.

@@ -25,13 +25,25 @@ const CustomElementState = {
*/
let CustomElementDefinition;

let Components = {
interfaces: {
inIDeepTreeWalker: true,
nsIDOMNodeFilter: {
SHOW_ELEMENT: true,
}
},
classes: {},
}

let XULElement;

// These properties are defined in the closure externs so that they will not be
// renamed during minification.

// Used for both Documents and Nodes which represent documents in the HTML
// Imports polyfill.


/** @type {boolean|undefined} */
Node.prototype.__CE_hasRegistry;

@@ -22,7 +22,7 @@ gulp.task('default', () => {
return gulp.src('./src/**/*.js', {base: './'})
.pipe(sourcemaps.init())
.pipe(closureCompiler({
compilation_level: 'ADVANCED',
compilation_level: 'SIMPLE_OPTIMIZATIONS',
warning_level: 'VERBOSE',
language_in: 'ECMASCRIPT6_STRICT',
language_out: 'ECMASCRIPT5_STRICT',
@@ -76,8 +76,8 @@ export default function(internals) {

if (Native.Element_innerHTML && Native.Element_innerHTML.get) {
patch_innerHTML(Element.prototype, Native.Element_innerHTML);
} else if (Native.HTMLElement_innerHTML && Native.HTMLElement_innerHTML.get) {
patch_innerHTML(HTMLElement.prototype, Native.HTMLElement_innerHTML);
} else if (Native.XULElement_innerHTML && Native.XULElement_innerHTML.get) {
patch_innerHTML(XULElement.prototype, Native.XULElement_innerHTML);
} else {

/** @type {HTMLDivElement} */
@@ -219,8 +219,8 @@ export default function(internals) {
});
}

if (Native.HTMLElement_insertAdjacentElement) {
patch_insertAdjacentElement(HTMLElement.prototype, Native.HTMLElement_insertAdjacentElement);
if (Native.XULElement_insertAdjacentElement) {
patch_insertAdjacentElement(XULElement.prototype, Native.XULElement_insertAdjacentElement);
} else if (Native.Element_insertAdjacentElement) {
patch_insertAdjacentElement(Element.prototype, Native.Element_insertAdjacentElement);
} else {
@@ -7,11 +7,11 @@ import AlreadyConstructedMarker from '../AlreadyConstructedMarker.js';
* @param {!CustomElementInternals} internals
*/
export default function(internals) {
window['HTMLElement'] = (function() {
window['XULElement'] = (function() {
/**
* @type {function(new: HTMLElement): !HTMLElement}
* @type {function(new: XULElement): !XULElement}
*/
function HTMLElement() {
function XULElement() {
// This should really be `new.target` but `new.target` can't be emulated
// in ES5. Assuming the user keeps the default value of the constructor's
// prototype's `constructor` property, this is equivalent.
@@ -37,18 +37,18 @@ export default function(internals) {
const lastIndex = constructionStack.length - 1;
const element = constructionStack[lastIndex];
if (element === AlreadyConstructedMarker) {
throw new Error('The HTMLElement constructor was either called reentrantly for this constructor or called multiple times.');
throw new Error('The XULElement constructor was either called reentrantly for this constructor or called multiple times.');
}
constructionStack[lastIndex] = AlreadyConstructedMarker;

Object.setPrototypeOf(element, constructor.prototype);
internals.patch(/** @type {!HTMLElement} */ (element));
internals.patch(/** @type {!XULElement} */ (element));

return element;
}

HTMLElement.prototype = Native.HTMLElement.prototype;
XULElement.prototype = Native.XULElement.prototype;

return HTMLElement;
return XULElement;
})();
};
@@ -25,7 +25,7 @@ export default {
Element_after: window.Element.prototype['after'],
Element_replaceWith: window.Element.prototype['replaceWith'],
Element_remove: window.Element.prototype['remove'],
HTMLElement: window.HTMLElement,
HTMLElement_innerHTML: Object.getOwnPropertyDescriptor(window.HTMLElement.prototype, 'innerHTML'),
HTMLElement_insertAdjacentElement: window.HTMLElement.prototype['insertAdjacentElement'],
XULElement: window.XULElement,
XULElement_innerHTML: Object.getOwnPropertyDescriptor(window.XULElement.prototype, 'innerHTML'),
XULElement_insertAdjacentElement: window.XULElement.prototype['insertAdjacentElement'],
};
@@ -15,7 +15,9 @@ const reservedTagList = new Set([
*/
export function isValidCustomElementName(localName) {
const reserved = reservedTagList.has(localName);
const validForm = /^[a-z][.0-9_a-z]*-[\-.0-9_a-z]*$/.test(localName);
// Allow non-dashed names for testing in browser chrome.
const validForm = true;
// const validForm = /^[a-z][.0-9_a-z]*-[\-.0-9_a-z]*$/.test(localName);
return !reserved && validForm;
}

@@ -67,51 +69,22 @@ function nextNode(root, start) {
* @param {!Set<Node>=} visitedImports
*/
export function walkDeepDescendantElements(root, callback, visitedImports = new Set()) {
let node = root;
while (node) {
if (node.nodeType === Node.ELEMENT_NODE) {
const element = /** @type {!Element} */(node);
// Firefox-specific wrapper to walk tree (including XBL / XUL / anon content)
let Ci = Components.interfaces;
let Cc = Components.classes;
let walker = Components.classes["@mozilla.org/inspector/deep-tree-walker;1"].
createInstance(Components.interfaces.inIDeepTreeWalker);
walker.showAnonymousContent = true;
walker.showSubDocuments = false;
walker.showDocumentsAsNodes = false;
walker.init(root, Ci.nsIDOMNodeFilter.SHOW_ELEMENT);

callback(element);
callback(root);

const localName = element.localName;
if (localName === 'link' && element.getAttribute('rel') === 'import') {
// If this import (polyfilled or not) has it's root node available,
// walk it.
const importNode = /** @type {!Node} */ (element.import);
if (importNode instanceof Node && !visitedImports.has(importNode)) {
// Prevent multiple walks of the same import root.
visitedImports.add(importNode);

for (let child = importNode.firstChild; child; child = child.nextSibling) {
walkDeepDescendantElements(child, callback, visitedImports);
}
}

// Ignore descendants of import links to prevent attempting to walk the
// elements created by the HTML Imports polyfill that we just walked
// above.
node = nextSiblingOrAncestorSibling(root, element);
continue;
} else if (localName === 'template') {
// Ignore descendants of templates. There shouldn't be any descendants
// because they will be moved into `.content` during construction in
// browsers that support template but, in case they exist and are still
// waiting to be moved by a polyfill, they will be ignored.
node = nextSiblingOrAncestorSibling(root, element);
continue;
}

// Walk shadow roots.
const shadowRoot = element.__CE_shadowRoot;
if (shadowRoot) {
for (let child = shadowRoot.firstChild; child; child = child.nextSibling) {
walkDeepDescendantElements(child, callback, visitedImports);
}
}
while (walker.nextNode()) {
if (walker.currentNode instanceof Element) {
callback(walker.currentNode);
}

node = nextNode(root, node);
}
}

@@ -11,7 +11,7 @@
import CustomElementInternals from './CustomElementInternals.js';
import CustomElementRegistry from './CustomElementRegistry.js';

import PatchHTMLElement from './Patch/HTMLElement.js';
import PatchXULElement from './Patch/HTMLElement.js';
import PatchDocument from './Patch/Document.js';
import PatchNode from './Patch/Node.js';
import PatchElement from './Patch/Element.js';
@@ -25,7 +25,7 @@ if (!priorCustomElements ||
/** @type {!CustomElementInternals} */
const internals = new CustomElementInternals();

PatchHTMLElement(internals);
PatchXULElement(internals);
PatchDocument(internals);
PatchNode(internals);
PatchElement(internals);
@@ -13,13 +13,13 @@
* implementations of Custom Elements.
*
* ES5-style classes don't work with native Custom Elements because the
* HTMLElement constructor uses the value of `new.target` to look up the custom
* XULElement constructor uses the value of `new.target` to look up the custom
* element definition for the currently called constructor. `new.target` is only
* set when `new` is called and is only propagated via super() calls. super()
* is not emulatable in ES5. The pattern of `SuperClass.call(this)`` only works
* when extending other ES5-style classes, and does not propagate `new.target`.
*
* This shim allows the native HTMLElement constructor to work by generating and
* This shim allows the native XULElement constructor to work by generating and
* registering a stand-in class instead of the users custom element class. This
* stand-in class's constructor has an actual call to super().
* `customElements.define()` and `customElements.get()` are both overridden to
@@ -29,9 +29,9 @@
* in, the stand-in's constructor swizzles its instances prototype and invokes
* the user-defined constructor. When the user-defined constructor is called
* directly it creates an instance of the stand-in class to get a real extension
* of HTMLElement and returns that.
* of XULElement and returns that.
*
* There are two important constructors: A patched HTMLElement constructor, and
* There are two important constructors: A patched XULElement constructor, and
* the StandInElement constructor. They both will be called to create an element
* but which is called first depends on whether the browser creates the element
* or the user-defined constructor is called directly. The variables
@@ -64,7 +64,7 @@
// Do nothing if `customElements` does not exist.
if (!window.customElements) return;

const NativeHTMLElement = window.HTMLElement;
const NativeXULElement = window.XULElement;
const nativeDefine = window.customElements.define;
const nativeGet = window.customElements.get;

@@ -95,7 +95,7 @@
*/
let userConstruction = false;

window.HTMLElement = function() {
window.XULElement = function() {
if (!browserConstruction) {
const tagname = tagnameByConstructor.get(this.constructor);
const fakeClass = nativeGet.call(window.customElements, tagname);
@@ -106,21 +106,21 @@
return instance;
}
// Else do nothing. This will be reached by ES5-style classes doing
// HTMLElement.call() during initialization
// XULElement.call() during initialization
browserConstruction = false;
};
// By setting the patched HTMLElement's prototype property to the native
// HTMLElement's prototype we make sure that:
// document.createElement('a') instanceof HTMLElement
// works because instanceof uses HTMLElement.prototype, which is on the
// By setting the patched XULElement's prototype property to the native
// XULElement's prototype we make sure that:
// document.createElement('a') instanceof XULElement
// works because instanceof uses XULElement.prototype, which is on the
// ptototype chain of built-in elements.
window.HTMLElement.prototype = NativeHTMLElement.prototype;
window.XULElement.prototype = NativeXULElement.prototype;

const define = (tagname, elementClass) => {
const elementProto = elementClass.prototype;
const StandInElement = class extends NativeHTMLElement {
const StandInElement = class extends NativeXULElement {
constructor() {
// Call the native HTMLElement constructor, this gives us the
// Call the native XULElement constructor, this gives us the
// under-construction instance as `this`:
super();

@@ -130,7 +130,7 @@

if (!userConstruction) {
// Make sure that user-defined constructor bottom's out to a do-nothing
// HTMLElement() call
// XULElement() call
browserConstruction = true;
// Call the user-defined constructor on our instance:
elementClass.call(this);

No commit comments for this range