mirror of
https://github.com/jlengrand/webcomponentsjs.git
synced 2026-03-10 08:51:22 +00:00
Add Closure Compiler build for Custom Elements v1
This commit is contained in:
1
externs/html5.js
Normal file
1
externs/html5.js
Normal file
@@ -0,0 +1 @@
|
||||
MutationObserver.prototype.takeRecords = function() {};
|
||||
40
gulpfile.js
40
gulpfile.js
@@ -12,17 +12,19 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var
|
||||
audit = require('gulp-audit'),
|
||||
concat = require('gulp-concat'),
|
||||
exec = require('child_process').exec,
|
||||
fs = require('fs'),
|
||||
gulp = require('gulp'),
|
||||
header = require('gulp-header'),
|
||||
path = require('path'),
|
||||
runseq = require('run-sequence'),
|
||||
uglify = require('gulp-uglify')
|
||||
;
|
||||
var audit = require('gulp-audit');
|
||||
var compilerPackage = require('google-closure-compiler');
|
||||
var concat = require('gulp-concat');
|
||||
var exec = require('child_process').exec;
|
||||
var fs = require('fs');
|
||||
var gulp = require('gulp');
|
||||
var header = require('gulp-header');
|
||||
var path = require('path');
|
||||
var rename = require('gulp-rename');
|
||||
var runseq = require('run-sequence');
|
||||
var uglify = require('gulp-uglify');
|
||||
|
||||
var closureCompiler = compilerPackage.gulp();
|
||||
|
||||
// init tests with gulp
|
||||
require('web-component-tester').gulp.init(gulp);
|
||||
@@ -129,7 +131,21 @@ defineBuildTask('HTMLImports');
|
||||
defineBuildTask('ShadowDOM');
|
||||
defineBuildTask('MutationObserver');
|
||||
|
||||
gulp.task('build', ['webcomponents', 'webcomponents-lite', 'CustomElements',
|
||||
gulp.task('CustomElementsV1', function () {
|
||||
return gulp.src('./src/CustomElements/v1/CustomElements.js', {base: './'})
|
||||
.pipe(closureCompiler({
|
||||
compilation_level: 'ADVANCED',
|
||||
warning_level: 'VERBOSE',
|
||||
language_in: 'ECMASCRIPT6_STRICT',
|
||||
language_out: 'ECMASCRIPT5_STRICT',
|
||||
output_wrapper: '(function(){\n%output%\n}).call(this)',
|
||||
externs: 'externs/html5.js',
|
||||
js_output_file: 'CustomElementsV1.min.js'
|
||||
}))
|
||||
.pipe(gulp.dest('./dist'));
|
||||
});
|
||||
|
||||
gulp.task('build', ['webcomponents', 'webcomponents-lite', 'CustomElements',
|
||||
'HTMLImports', 'ShadowDOM', 'copy-bower', 'MutationObserver']);
|
||||
|
||||
gulp.task('release', function(cb) {
|
||||
|
||||
@@ -20,10 +20,12 @@
|
||||
},
|
||||
"homepage": "http://webcomponents.org",
|
||||
"devDependencies": {
|
||||
"google-closure-compiler": "^20160208.7.0",
|
||||
"gulp": "^3.8.8",
|
||||
"gulp-audit": "^1.0.0",
|
||||
"gulp-concat": "^2.4.1",
|
||||
"gulp-header": "^1.1.1",
|
||||
"gulp-rename": "^1.2.2",
|
||||
"gulp-uglify": "^1.0.1",
|
||||
"run-sequence": "^1.0.1",
|
||||
"web-component-tester": "^4.0.1"
|
||||
|
||||
@@ -11,22 +11,25 @@
|
||||
/**
|
||||
* 2.3
|
||||
* http://w3c.github.io/webcomponents/spec/custom/#dfn-element-definition
|
||||
*
|
||||
* @typedef {Object} Definition
|
||||
* @property {Function} name
|
||||
* @property {Function} localName
|
||||
* @property {Function} constructor
|
||||
* @property {Function} connectedCallback
|
||||
* @property {Function} disconnectedCallback
|
||||
* @property {Function} attributeChangedCallback
|
||||
* @property {String[]} observedAttributes
|
||||
* http://w3c.github.io/webcomponents/spec/custom/#dfn-element-definition-construction-stack
|
||||
* @property {Function[]} constructionStack
|
||||
* @typedef {{
|
||||
* name: string,
|
||||
* localName: string,
|
||||
* constructor: Function,
|
||||
* connectedCallback: Function,
|
||||
* disconnectedCallback: Function,
|
||||
* attributeChangedCallback: Function,
|
||||
* observedAttributes: Array<string>,
|
||||
* }}
|
||||
*/
|
||||
var CustomElementDefinition;
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {Array<string>}
|
||||
*/
|
||||
var reservedTagList = [
|
||||
'annotation-xml',
|
||||
'color-profile',
|
||||
@@ -38,11 +41,13 @@
|
||||
'missing-glyph',
|
||||
];
|
||||
|
||||
/**
|
||||
* @const
|
||||
*/
|
||||
var customNameValidation = /^[a-z][.0-9_a-z]*-[\-.0-9_a-z]*$/;
|
||||
|
||||
function checkCallback(callback, elementName, calllbackName) {
|
||||
if (callback !== undefined && typeof callback !== 'function') {
|
||||
console.warn(typeof callback);
|
||||
throw new Error(`TypeError: ${elementName} '${calllbackName}' is not a Function`);
|
||||
}
|
||||
}
|
||||
@@ -51,17 +56,26 @@
|
||||
return reservedTagList.indexOf(name) !== -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @property {Map<String, CustomElementDefinition>} _defintions
|
||||
* @property {MutationObserver} _observer
|
||||
* @property {MutationObserver} _attributeObserver
|
||||
* @property {HTMLElement} _newInstance
|
||||
* @property {string} _newTagName
|
||||
* @property {boolean} polyfilled
|
||||
*/
|
||||
function CustomElementsRegistry() {
|
||||
// @type {Map<String, Definition>}
|
||||
this._definitions = new Map();
|
||||
this._observer = this._observeRoot(document);
|
||||
this._attributeObserver =
|
||||
new MutationObserver(this._handleAttributeChange.bind(this));
|
||||
this._newInstance;
|
||||
this._newTagName;
|
||||
this._newInstance = null;
|
||||
this._newTagName = null;
|
||||
this.polyfilled = true;
|
||||
}
|
||||
|
||||
/** @lends {CustomElementsRegistry.prototype} */
|
||||
CustomElementsRegistry.prototype = {
|
||||
define(name, constructor, options) {
|
||||
// 5.1.1
|
||||
@@ -102,12 +116,12 @@
|
||||
var _extends = options && options.extends || '';
|
||||
|
||||
// 5.1.9
|
||||
if (_extends !== null) {
|
||||
// skip for now
|
||||
}
|
||||
// skip for now
|
||||
// if (_extends !== null) {
|
||||
// }
|
||||
|
||||
// 5.1.10, 5.1.11
|
||||
var observedAttributes = constructor.observedAttributes || [];
|
||||
var observedAttributes = constructor['observedAttributes'] || [];
|
||||
|
||||
// 5.1.12
|
||||
var prototype = constructor.prototype;
|
||||
@@ -115,20 +129,20 @@
|
||||
// 5.1.13?
|
||||
|
||||
// 5.1.14
|
||||
var connectedCallback = prototype.connectedCallback;
|
||||
var connectedCallback = prototype['connectedCallback'];
|
||||
// 5.1.15
|
||||
checkCallback(connectedCallback, localName, 'connectedCallback');
|
||||
// 5.1.16
|
||||
var disconnectedCallback = prototype.disconnectedCallback;
|
||||
var disconnectedCallback = prototype['disconnectedCallback'];
|
||||
// 5.1.17
|
||||
checkCallback(disconnectedCallback, localName, 'disconnectedCallback');
|
||||
// 5.1.18
|
||||
var attributeChangedCallback = prototype.attributeChangedCallback;
|
||||
var attributeChangedCallback = prototype['attributeChangedCallback'];
|
||||
// 5.1.19
|
||||
checkCallback(attributeChangedCallback, localName, 'attributeChangedCallback');
|
||||
|
||||
// 5.1.20
|
||||
// @type {Definition}
|
||||
// @type {CustomElementDefinition}
|
||||
var definition = {
|
||||
name: name,
|
||||
localName: localName,
|
||||
@@ -156,7 +170,6 @@
|
||||
},
|
||||
|
||||
_setNewInstance(instance) {
|
||||
console.assert(this._newInstance == null);
|
||||
this._newInstance = instance;
|
||||
},
|
||||
|
||||
@@ -179,12 +192,15 @@
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {NodeList} nodeList
|
||||
*/
|
||||
_addNodes(nodeList) {
|
||||
for (var i = 0; i < nodeList.length; i++) {
|
||||
var root = nodeList[i];
|
||||
var walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
||||
do {
|
||||
var node = walker.currentNode;
|
||||
var node = /** @type {HTMLElement} */ (walker.currentNode);
|
||||
var definition = this._definitions.get(node.localName);
|
||||
if (!definition) {
|
||||
continue;
|
||||
@@ -202,6 +218,9 @@
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {NodeList} nodeList
|
||||
*/
|
||||
_removeNodes(nodeList) {
|
||||
for (var i = 0; i < nodeList.length; i++) {
|
||||
var root = nodeList[i];
|
||||
@@ -219,9 +238,14 @@
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} element
|
||||
* @param {CustomElementDefinition} definition
|
||||
* @param {boolean} callConstructor
|
||||
*/
|
||||
_upgradeElement(element, definition, callConstructor) {
|
||||
var prototype = definition.constructor.prototype;
|
||||
Object.setPrototypeOf(element, prototype);
|
||||
element.__proto__ = prototype;
|
||||
if (callConstructor) {
|
||||
this._setNewInstance(element);
|
||||
element.__upgraded = true;
|
||||
@@ -237,6 +261,9 @@
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_handleAttributeChange(mutations) {
|
||||
for (var i = 0; i < mutations.length; i++) {
|
||||
var mutation = mutations[i];
|
||||
@@ -246,71 +273,72 @@
|
||||
var target = mutation.target;
|
||||
var newValue = target.getAttribute(name);
|
||||
var namespace = mutation.attributeNamespace;
|
||||
target.attributeChangedCallback(name, oldValue, newValue, namespace);
|
||||
target['attributeChangedCallback'](name, oldValue, newValue, namespace);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
// Closure Compiler Exports
|
||||
window['CustomElementsRegistry'] = CustomElementsRegistry;
|
||||
CustomElementsRegistry.prototype['define'] = CustomElementsRegistry.prototype.define;
|
||||
CustomElementsRegistry.prototype['flush'] = CustomElementsRegistry.prototype.flush;
|
||||
CustomElementsRegistry.prototype['setCurrentTag'] = CustomElementsRegistry.prototype.setCurrentTag;
|
||||
CustomElementsRegistry.prototype['polyfilled'] = CustomElementsRegistry.prototype.polyfilled;
|
||||
|
||||
// patch window.HTMLElement
|
||||
|
||||
// TODO: patch up all built-in subclasses of HTMLElement to use the fake
|
||||
// HTMLElement.prototype
|
||||
var origHTMLElement = window.HTMLElement;
|
||||
window.HTMLElement = function() {
|
||||
if (window['customElements']._newInstance) {
|
||||
var i = window['customElements']._newInstance;
|
||||
window['customElements']._newInstance = null;
|
||||
window['customElements']._newTagName = null;
|
||||
return i;
|
||||
}
|
||||
if (window['customElements']._newTagName) {
|
||||
var tagName = window['customElements']._newTagName.toLowerCase();
|
||||
window['customElements']._newTagName = null;
|
||||
return window.document._createElement(tagName, false);
|
||||
}
|
||||
throw new Error('unknown constructor');
|
||||
}
|
||||
HTMLElement.prototype = Object.create(origHTMLElement.prototype);
|
||||
Object.defineProperty(HTMLElement.prototype, 'constructor', {
|
||||
writable: false,
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
value: HTMLElement,
|
||||
});
|
||||
|
||||
// patch document.createElement
|
||||
|
||||
var rawCreateElement = document.createElement.bind(document);
|
||||
document._createElement = function(tagName, callConstructor) {
|
||||
var element = rawCreateElement.call(document, tagName);
|
||||
var definition = window['customElements']._definitions.get(tagName.toLowerCase());
|
||||
if (definition) {
|
||||
window['customElements']._upgradeElement(element, definition, callConstructor);
|
||||
}
|
||||
return element;
|
||||
};
|
||||
document.createElement = function(tagName) {
|
||||
return document._createElement(tagName, true);
|
||||
}
|
||||
|
||||
// patch document.createElementNS
|
||||
|
||||
var HTMLNS = 'http://www.w3.org/1999/xhtml';
|
||||
var _origCreateElementNS = document.createElementNS;
|
||||
document.createElementNS = function(namespaceURI, qualifiedName) {
|
||||
if (namespaceURI === 'http://www.w3.org/1999/xhtml') {
|
||||
return document.createElement(qualifiedName);
|
||||
} else {
|
||||
return _origCreateElementNS.call(document, namespaceURI, qualifiedName);
|
||||
}
|
||||
};
|
||||
|
||||
function patchHTMLElement(win) {
|
||||
// TODO: patch up all built-in subclasses of HTMLElement to use the fake
|
||||
// HTMLElement.prototype
|
||||
var origHTMLElement = HTMLElement;
|
||||
window.HTMLElement = function() {
|
||||
if (win.customElements._newInstance) {
|
||||
var i = win.customElements._newInstance;
|
||||
win.customElements._newInstance = null;
|
||||
win.customElements._newTagName = null;
|
||||
return i;
|
||||
}
|
||||
if (win.customElements._newTagName) {
|
||||
var tagName = win.customElements._newTagName.toLowerCase();
|
||||
win.customElements._newTagName = null;
|
||||
return win.document._createElement(tagName, false);
|
||||
}
|
||||
throw new Error('unknown constructor');
|
||||
}
|
||||
HTMLElement.prototype = Object.create(origHTMLElement.prototype);
|
||||
Object.defineProperty(HTMLElement.prototype, 'constructor', {
|
||||
writable: false,
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
value: HTMLElement,
|
||||
});
|
||||
}
|
||||
|
||||
function patchCreateElement(win) {
|
||||
var doc = win.document;
|
||||
var rawCreateElement = doc.createElement.bind(document);
|
||||
doc._createElement = function(tagName, callConstructor) {
|
||||
var element = rawCreateElement(tagName);
|
||||
var definition = win.customElements._definitions.get(tagName.toLowerCase());
|
||||
if (definition) {
|
||||
win.customElements._upgradeElement(element, definition, callConstructor);
|
||||
}
|
||||
return element;
|
||||
};
|
||||
doc.createElement = function(tagName) {
|
||||
return doc._createElement(tagName, true);
|
||||
}
|
||||
}
|
||||
|
||||
function patchCreateElementNS(win) {
|
||||
var doc = win.document;
|
||||
var HTMLNS = 'http://www.w3.org/1999/xhtml';
|
||||
var _origCreateElementNS = document.createElementNS;
|
||||
doc.createElementNS = function(namespaceURI, qualifiedName) {
|
||||
if (namespaceURI === 'http://www.w3.org/1999/xhtml') {
|
||||
return doc.createElement(qualifiedName);
|
||||
} else {
|
||||
return _origCreateElementNS(namespaceURI, qualifiedName);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
window.customElements = new CustomElementsRegistry();
|
||||
patchHTMLElement(window);
|
||||
patchCreateElement(window);
|
||||
patchCreateElementNS(window);
|
||||
/** @type {CustomElementsRegistry} */
|
||||
window['customElements'] = new (window['CustomElementsRegistry'])();
|
||||
})();
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<title>CustomElements Tests</title>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<script src="../../../src/CustomElements/v1/CustomElements.js"></script>
|
||||
<script src="../../../dist/CustomElementsV1.min.js"></script>
|
||||
<script src="../../../../web-component-tester/browser.js"></script>
|
||||
|
||||
<script>
|
||||
|
||||
Reference in New Issue
Block a user