mirror of
https://github.com/jlengrand/webcomponentsjs.git
synced 2026-03-10 08:51:22 +00:00
Merge branch 'upstream' into relative_path_resolving_in_css
This commit is contained in:
21
.autoclave-build.sh
Executable file
21
.autoclave-build.sh
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# @license
|
||||
# Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||||
# This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||||
# The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||||
# The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||||
# Code distributed by Google as part of the polymer project is also
|
||||
# subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||||
npm install
|
||||
|
||||
node_modules/.bin/gulp release
|
||||
|
||||
lasttag=`git tag -l | sort -t. -k1,1n -k2,2n -k3,3n | tail -n 1`
|
||||
git checkout --detach ${lasttag}
|
||||
git merge -s ours master --no-commit
|
||||
|
||||
files=(`ls dist | sed -e 's/\/dist//'`)
|
||||
mv dist/* .
|
||||
|
||||
git add -f "${files[@]}"
|
||||
19
LICENSE.md
Normal file
19
LICENSE.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# License
|
||||
|
||||
Everything in this repo is BSD style license unless otherwise specified.
|
||||
|
||||
Copyright (c) 2015 The Polymer Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
29
README.md
29
README.md
@@ -1,6 +1,8 @@
|
||||
webcomponents.js
|
||||
================
|
||||
|
||||
[](https://gitter.im/webcomponents/webcomponentsjs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
A suite of polyfills supporting the [Web Components](http://webcomponents.org) specs:
|
||||
|
||||
**Custom Elements**: allows authors to define their own custom tags ([spec](https://w3c.github.io/webcomponents/spec/custom/)).
|
||||
@@ -21,6 +23,28 @@ Pre-built (concatenated & minified) versions of the polyfills are maintained in
|
||||
`webcomponents-lite.js` includes all polyfills except for shadow DOM.
|
||||
|
||||
|
||||
## Browser Support
|
||||
|
||||
Our polyfills are intended to work in the latest versions of evergreen browsers. See below
|
||||
for our complete browser support matrix:
|
||||
|
||||
| Polyfill | IE10 | IE11+ | Chrome* | Firefox* | Safari 7+* | Chrome Android* | Mobile Safari* |
|
||||
| ---------- |:----:|:-----:|:-------:|:--------:|:----------:|:---------------:|:--------------:|
|
||||
| Custom Elements | ~ | ✓ | ✓ | ✓ | ✓ | ✓| ✓ |
|
||||
| HTML Imports | ~ | ✓ | ✓ | ✓ | ✓| ✓| ✓ |
|
||||
| Shadow DOM | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Templates | ✓ | ✓ | ✓ | ✓| ✓ | ✓ | ✓ |
|
||||
|
||||
|
||||
*Indicates the current version of the browser
|
||||
|
||||
~Indicates support may be flaky. If using Custom Elements or HTML Imports with Shadow DOM,
|
||||
you will get the non-flaky Mutation Observer polyfill that Shadow DOM includes.
|
||||
|
||||
The polyfills may work in older browsers, however require additional polyfills (such as classList)
|
||||
to be used. We cannot guarantee support for browsers outside of our compatibility matrix.
|
||||
|
||||
|
||||
### Manually Building
|
||||
|
||||
If you wish to build the polyfills yourself, you'll need `node` and `gulp` on your system:
|
||||
@@ -41,4 +65,9 @@ The builds will be placed into the `dist/` directory.
|
||||
|
||||
See the [contributing guide](CONTRIBUTING.md)
|
||||
|
||||
## License
|
||||
|
||||
Everything in this repository is BSD style license unless otherwise specified.
|
||||
|
||||
Copyright (c) 2015 The Polymer Authors. All rights reserved.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "webcomponentsjs",
|
||||
"main": "webcomponents.js",
|
||||
"version": "0.5.3",
|
||||
"version": "0.5.5",
|
||||
"homepage": "http://webcomponents.org",
|
||||
"authors": [
|
||||
"The Polymer Authors"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "webcomponents.js",
|
||||
"version": "0.5.3",
|
||||
"version": "0.5.5",
|
||||
"description": "webcomponents.js",
|
||||
"main": "gulpfile.js",
|
||||
"main": "webcomponents.js",
|
||||
"directories": {
|
||||
"test": "tests"
|
||||
},
|
||||
|
||||
@@ -28,7 +28,6 @@ var file = 'CustomElements.js';
|
||||
|
||||
var modules = [
|
||||
'../WeakMap/WeakMap.js',
|
||||
'../MutationObserver/MutationObserver.js',
|
||||
'base.js',
|
||||
'traverse.js',
|
||||
'observe.js',
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
[
|
||||
"../WeakMap/WeakMap.js",
|
||||
"../MutationObserver/MutationObserver.js",
|
||||
"base.js",
|
||||
"traverse.js",
|
||||
"observe.js",
|
||||
|
||||
@@ -289,13 +289,17 @@ function upgradeDocumentTree(doc) {
|
||||
}
|
||||
|
||||
|
||||
// ensure that all ShadowRoots watch for CustomElements.
|
||||
// Patch `createShadowRoot()` if Shadow DOM is available, otherwise leave
|
||||
// undefined to aid feature detection of Shadow DOM.
|
||||
var originalCreateShadowRoot = Element.prototype.createShadowRoot;
|
||||
Element.prototype.createShadowRoot = function() {
|
||||
var root = originalCreateShadowRoot.call(this);
|
||||
CustomElements.watchShadow(this);
|
||||
return root;
|
||||
};
|
||||
if (originalCreateShadowRoot) {
|
||||
// ensure that all ShadowRoots watch for CustomElements.
|
||||
Element.prototype.createShadowRoot = function() {
|
||||
var root = originalCreateShadowRoot.call(this);
|
||||
CustomElements.watchShadow(this);
|
||||
return root;
|
||||
};
|
||||
}
|
||||
|
||||
// exports
|
||||
scope.watchShadow = watchShadow;
|
||||
|
||||
@@ -27,7 +27,6 @@ var file = 'HTMLImports.js';
|
||||
|
||||
var modules = [
|
||||
'../WeakMap/WeakMap.js',
|
||||
'../MutationObserver/MutationObserver.js',
|
||||
'base.js',
|
||||
'module.js',
|
||||
'path.js',
|
||||
|
||||
@@ -115,24 +115,35 @@ function markTargetLoaded(event) {
|
||||
// call <callback> when we ensure all imports have loaded
|
||||
function watchImportsLoad(callback, doc) {
|
||||
var imports = doc.querySelectorAll('link[rel=import]');
|
||||
var loaded = 0, l = imports.length;
|
||||
function checkDone(d) {
|
||||
if ((loaded == l) && callback) {
|
||||
callback();
|
||||
var parsedCount = 0, importCount = imports.length, newImports = [], errorImports = [];
|
||||
function checkDone() {
|
||||
if (parsedCount == importCount && callback) {
|
||||
callback({
|
||||
allImports: imports,
|
||||
loadedImports: newImports,
|
||||
errorImports: errorImports
|
||||
});
|
||||
}
|
||||
}
|
||||
function loadedImport(e) {
|
||||
markTargetLoaded(e);
|
||||
loaded++;
|
||||
newImports.push(this);
|
||||
parsedCount++;
|
||||
checkDone();
|
||||
}
|
||||
if (l) {
|
||||
for (var i=0, imp; (i<l) && (imp=imports[i]); i++) {
|
||||
function errorLoadingImport(e) {
|
||||
errorImports.push(this);
|
||||
parsedCount++;
|
||||
checkDone();
|
||||
}
|
||||
if (importCount) {
|
||||
for (var i=0, imp; i<importCount && (imp=imports[i]); i++) {
|
||||
if (isImportLoaded(imp)) {
|
||||
loadedImport.call(imp, {target: imp});
|
||||
parsedCount++;
|
||||
checkDone();
|
||||
} else {
|
||||
imp.addEventListener('load', loadedImport);
|
||||
imp.addEventListener('error', loadedImport);
|
||||
imp.addEventListener('error', errorLoadingImport);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -211,11 +222,11 @@ if (useNative) {
|
||||
// have loaded. This event is required to simulate the script blocking
|
||||
// behavior of native imports. A main document script that needs to be sure
|
||||
// imports have loaded should wait for this event.
|
||||
whenReady(function() {
|
||||
whenReady(function(detail) {
|
||||
HTMLImports.ready = true;
|
||||
HTMLImports.readyTime = new Date().getTime();
|
||||
var evt = rootDocument.createEvent("CustomEvent");
|
||||
evt.initCustomEvent("HTMLImportsLoaded", true, true, {});
|
||||
evt.initCustomEvent("HTMLImportsLoaded", true, true, detail);
|
||||
rootDocument.dispatchEvent(evt);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
[
|
||||
"../WeakMap/WeakMap.js",
|
||||
"../MutationObserver/MutationObserver.js",
|
||||
"base.js",
|
||||
"module.js",
|
||||
"path.js",
|
||||
|
||||
@@ -119,6 +119,10 @@ function isLinkRel(elt, rel) {
|
||||
return elt.localName === 'link' && elt.getAttribute('rel') === rel;
|
||||
}
|
||||
|
||||
function hasBaseURIAccessor(doc) {
|
||||
return !! Object.getOwnPropertyDescriptor(doc, 'baseURI');
|
||||
}
|
||||
|
||||
function makeDocument(resource, url) {
|
||||
// create a new HTML document
|
||||
var doc = document.implementation.createHTMLDocument(IMPORT_LINK_TYPE);
|
||||
@@ -128,7 +132,7 @@ function makeDocument(resource, url) {
|
||||
var base = doc.createElement('base');
|
||||
base.setAttribute('href', url);
|
||||
// add baseURI support to browsers (IE) that lack it.
|
||||
if (!doc.baseURI) {
|
||||
if (!doc.baseURI && !hasBaseURIAccessor(doc)) {
|
||||
// Use defineProperty since Safari throws an exception when using assignment.
|
||||
Object.defineProperty(doc, 'baseURI', {value:url});
|
||||
}
|
||||
|
||||
@@ -524,7 +524,6 @@
|
||||
// Fall through.
|
||||
case 'DOMNodeInserted':
|
||||
// http://dom.spec.whatwg.org/#concept-mo-queue-childlist
|
||||
var target = e.relatedNode;
|
||||
var changedNode = e.target;
|
||||
var addedNodes, removedNodes;
|
||||
if (e.type === 'DOMNodeInserted') {
|
||||
@@ -539,13 +538,13 @@
|
||||
var nextSibling = changedNode.nextSibling;
|
||||
|
||||
// 1.
|
||||
var record = getRecord('childList', target);
|
||||
var record = getRecord('childList', e.target.parentNode);
|
||||
record.addedNodes = addedNodes;
|
||||
record.removedNodes = removedNodes;
|
||||
record.previousSibling = previousSibling;
|
||||
record.nextSibling = nextSibling;
|
||||
|
||||
forEachAncestorAndObserverEnqueueRecord(target, function(options) {
|
||||
forEachAncestorAndObserverEnqueueRecord(e.relatedNode, function(options) {
|
||||
// 2.1, 3.2
|
||||
if (!options.childList)
|
||||
return;
|
||||
|
||||
@@ -457,7 +457,7 @@ var ShadowCSS = {
|
||||
return !selector.match(re);
|
||||
},
|
||||
makeScopeMatcher: function(scopeSelector) {
|
||||
scopeSelector = scopeSelector.replace(/\[/g, '\\[').replace(/\[/g, '\\]');
|
||||
scopeSelector = scopeSelector.replace(/\[/g, '\\[').replace(/\]/g, '\\]');
|
||||
return new RegExp('^(' + scopeSelector + ')' + selectorReSuffix, 'm');
|
||||
},
|
||||
applySelectorScope: function(selector, selectorScope) {
|
||||
@@ -495,7 +495,7 @@ var ShadowCSS = {
|
||||
// remove :host since it should be unnecessary
|
||||
var t = p.trim().replace(polyfillHostRe, '');
|
||||
if (t && (splits.indexOf(t) < 0) && (t.indexOf(attrName) < 0)) {
|
||||
p = t.replace(/([^:]*)(:*)(.*)/, '$1' + attrName + '$2$3')
|
||||
p = t.replace(/([^:]*)(:*)(.*)/, '$1' + attrName + '$2$3');
|
||||
}
|
||||
return p;
|
||||
}).join(sep);
|
||||
|
||||
@@ -49,7 +49,31 @@
|
||||
}
|
||||
|
||||
function shimSelector(selector) {
|
||||
return String(selector).replace(/\/deep\//g, ' ');
|
||||
return String(selector).replace(/\/deep\/|::shadow/g, ' ');
|
||||
}
|
||||
|
||||
function shimMatchesSelector(selector) {
|
||||
return String(selector)
|
||||
// Transform `:host(selector)` to `selector`
|
||||
.replace(
|
||||
/:host\(([^\s]+)\)/g,
|
||||
'$1'
|
||||
)
|
||||
// Transform `selector:host` to `selector`
|
||||
.replace(
|
||||
/([^\s]):host/g,
|
||||
'$1'
|
||||
)
|
||||
// Transform `:host` to `*`
|
||||
.replace(
|
||||
':host',
|
||||
'*'
|
||||
)
|
||||
// From ShadowCSS, will be replaced by space
|
||||
.replace(
|
||||
/\^|\/shadow\/|\/shadow-deep\/|::shadow|\/deep\/|::content/g,
|
||||
' '
|
||||
);
|
||||
}
|
||||
|
||||
function findOne(node, selector) {
|
||||
@@ -105,7 +129,7 @@
|
||||
}
|
||||
|
||||
// find and findAll will only match Simple Selectors,
|
||||
// Structural Pseudo Classes are not guarenteed to be correct
|
||||
// Structural Pseudo Classes are not guaranteed to be correct
|
||||
// http://www.w3.org/TR/css3-selectors/#simple-selectors
|
||||
|
||||
function querySelectorAllFiltered(p, index, result, selector, deep) {
|
||||
@@ -184,6 +208,13 @@
|
||||
}
|
||||
};
|
||||
|
||||
var MatchesInterface = {
|
||||
matches: function(selector) {
|
||||
selector = shimMatchesSelector(selector);
|
||||
return scope.originalMatches.call(unsafeUnwrap(this), selector);
|
||||
}
|
||||
};
|
||||
|
||||
function getElementsByTagNameFiltered(p, index, result, localName,
|
||||
lowercase) {
|
||||
var target = unsafeUnwrap(this);
|
||||
@@ -272,5 +303,6 @@
|
||||
|
||||
scope.GetElementsByInterface = GetElementsByInterface;
|
||||
scope.SelectorsInterface = SelectorsInterface;
|
||||
scope.MatchesInterface = MatchesInterface;
|
||||
|
||||
})(window.ShadowDOMPolyfill);
|
||||
|
||||
@@ -103,6 +103,17 @@ window.ShadowDOMPolyfill = {};
|
||||
|
||||
function getWrapperConstructor(node) {
|
||||
var nativePrototype = node.__proto__ || Object.getPrototypeOf(node);
|
||||
if (isFirefox) {
|
||||
// HTMLEmbedElements will sometimes be [NS Object wrapper class]
|
||||
// which throws an error when getOwnPropertyNames is called on it.
|
||||
// Mozilla handily includes a second HTMLEmbedElementPrototype in
|
||||
// the chain, so we use that one if available.
|
||||
try {
|
||||
getOwnPropertyNames(nativePrototype);
|
||||
} catch (error) {
|
||||
nativePrototype = nativePrototype.__proto__;
|
||||
}
|
||||
}
|
||||
var wrapperConstructor = constructorTable.get(nativePrototype);
|
||||
if (wrapperConstructor)
|
||||
return wrapperConstructor;
|
||||
@@ -226,10 +237,13 @@ window.ShadowDOMPolyfill = {};
|
||||
setter = getSetter(name);
|
||||
}
|
||||
|
||||
// make all descriptors configurable on broken safari
|
||||
var configurable = isBrokenSafari || descriptor.configurable;
|
||||
|
||||
defineProperty(target, name, {
|
||||
get: getter,
|
||||
set: setter,
|
||||
configurable: descriptor.configurable,
|
||||
configurable: configurable,
|
||||
enumerable: descriptor.enumerable
|
||||
});
|
||||
}
|
||||
|
||||
@@ -14,6 +14,12 @@
|
||||
(function(scope) {
|
||||
'use strict';
|
||||
|
||||
if (!window.DOMTokenList) {
|
||||
console.warn('Missing DOMTokenList prototype, please include a ' +
|
||||
'compatible classList polyfill such as http://goo.gl/uTcepH.');
|
||||
return;
|
||||
}
|
||||
|
||||
var unsafeUnwrap = scope.unsafeUnwrap;
|
||||
var enqueueMutation = scope.enqueueMutation;
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
var Node = scope.wrappers.Node;
|
||||
var ParentNodeInterface = scope.ParentNodeInterface;
|
||||
var SelectorsInterface = scope.SelectorsInterface;
|
||||
var MatchesInterface = scope.MatchesInterface;
|
||||
var addWrapNodeListMethod = scope.addWrapNodeListMethod;
|
||||
var enqueueMutation = scope.enqueueMutation;
|
||||
var mixin = scope.mixin;
|
||||
@@ -98,14 +99,11 @@
|
||||
invalidateRendererBasedOnAttribute(this, name);
|
||||
},
|
||||
|
||||
matches: function(selector) {
|
||||
return originalMatches.call(unsafeUnwrap(this), selector);
|
||||
},
|
||||
|
||||
get classList() {
|
||||
var list = classListTable.get(this);
|
||||
if (!list) {
|
||||
list = unsafeUnwrap(this).classList;
|
||||
if (!list) return;
|
||||
list.ownerElement_ = this;
|
||||
classListTable.set(this, list);
|
||||
}
|
||||
@@ -146,11 +144,13 @@
|
||||
mixin(Element.prototype, GetElementsByInterface);
|
||||
mixin(Element.prototype, ParentNodeInterface);
|
||||
mixin(Element.prototype, SelectorsInterface);
|
||||
mixin(Element.prototype, MatchesInterface);
|
||||
|
||||
registerWrapper(OriginalElement, Element,
|
||||
document.createElementNS(null, 'x'));
|
||||
|
||||
scope.invalidateRendererBasedOnAttribute = invalidateRendererBasedOnAttribute;
|
||||
scope.matchesNames = matchesNames;
|
||||
scope.originalMatches = originalMatches;
|
||||
scope.wrappers.Element = Element;
|
||||
})(window.ShadowDOMPolyfill);
|
||||
|
||||
603
src/URL/URL.js
Normal file
603
src/URL/URL.js
Normal file
@@ -0,0 +1,603 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
(function(scope) {
|
||||
'use strict';
|
||||
|
||||
// feature detect for URL constructor
|
||||
var hasWorkingUrl = false;
|
||||
if (!scope.forceJURL) {
|
||||
try {
|
||||
var u = new URL('b', 'http://a');
|
||||
u.pathname = 'c%20d';
|
||||
hasWorkingUrl = u.href === 'http://a/c%20d';
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
if (hasWorkingUrl)
|
||||
return;
|
||||
|
||||
var relative = Object.create(null);
|
||||
relative['ftp'] = 21;
|
||||
relative['file'] = 0;
|
||||
relative['gopher'] = 70;
|
||||
relative['http'] = 80;
|
||||
relative['https'] = 443;
|
||||
relative['ws'] = 80;
|
||||
relative['wss'] = 443;
|
||||
|
||||
var relativePathDotMapping = Object.create(null);
|
||||
relativePathDotMapping['%2e'] = '.';
|
||||
relativePathDotMapping['.%2e'] = '..';
|
||||
relativePathDotMapping['%2e.'] = '..';
|
||||
relativePathDotMapping['%2e%2e'] = '..';
|
||||
|
||||
function isRelativeScheme(scheme) {
|
||||
return relative[scheme] !== undefined;
|
||||
}
|
||||
|
||||
function invalid() {
|
||||
clear.call(this);
|
||||
this._isInvalid = true;
|
||||
}
|
||||
|
||||
function IDNAToASCII(h) {
|
||||
if ('' == h) {
|
||||
invalid.call(this)
|
||||
}
|
||||
// XXX
|
||||
return h.toLowerCase()
|
||||
}
|
||||
|
||||
function percentEscape(c) {
|
||||
var unicode = c.charCodeAt(0);
|
||||
if (unicode > 0x20 &&
|
||||
unicode < 0x7F &&
|
||||
// " # < > ? `
|
||||
[0x22, 0x23, 0x3C, 0x3E, 0x3F, 0x60].indexOf(unicode) == -1
|
||||
) {
|
||||
return c;
|
||||
}
|
||||
return encodeURIComponent(c);
|
||||
}
|
||||
|
||||
function percentEscapeQuery(c) {
|
||||
// XXX This actually needs to encode c using encoding and then
|
||||
// convert the bytes one-by-one.
|
||||
|
||||
var unicode = c.charCodeAt(0);
|
||||
if (unicode > 0x20 &&
|
||||
unicode < 0x7F &&
|
||||
// " # < > ` (do not escape '?')
|
||||
[0x22, 0x23, 0x3C, 0x3E, 0x60].indexOf(unicode) == -1
|
||||
) {
|
||||
return c;
|
||||
}
|
||||
return encodeURIComponent(c);
|
||||
}
|
||||
|
||||
var EOF = undefined,
|
||||
ALPHA = /[a-zA-Z]/,
|
||||
ALPHANUMERIC = /[a-zA-Z0-9\+\-\.]/;
|
||||
|
||||
function parse(input, stateOverride, base) {
|
||||
function err(message) {
|
||||
errors.push(message)
|
||||
}
|
||||
|
||||
var state = stateOverride || 'scheme start',
|
||||
cursor = 0,
|
||||
buffer = '',
|
||||
seenAt = false,
|
||||
seenBracket = false,
|
||||
errors = [];
|
||||
|
||||
loop: while ((input[cursor - 1] != EOF || cursor == 0) && !this._isInvalid) {
|
||||
var c = input[cursor];
|
||||
switch (state) {
|
||||
case 'scheme start':
|
||||
if (c && ALPHA.test(c)) {
|
||||
buffer += c.toLowerCase(); // ASCII-safe
|
||||
state = 'scheme';
|
||||
} else if (!stateOverride) {
|
||||
buffer = '';
|
||||
state = 'no scheme';
|
||||
continue;
|
||||
} else {
|
||||
err('Invalid scheme.');
|
||||
break loop;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'scheme':
|
||||
if (c && ALPHANUMERIC.test(c)) {
|
||||
buffer += c.toLowerCase(); // ASCII-safe
|
||||
} else if (':' == c) {
|
||||
this._scheme = buffer;
|
||||
buffer = '';
|
||||
if (stateOverride) {
|
||||
break loop;
|
||||
}
|
||||
if (isRelativeScheme(this._scheme)) {
|
||||
this._isRelative = true;
|
||||
}
|
||||
if ('file' == this._scheme) {
|
||||
state = 'relative';
|
||||
} else if (this._isRelative && base && base._scheme == this._scheme) {
|
||||
state = 'relative or authority';
|
||||
} else if (this._isRelative) {
|
||||
state = 'authority first slash';
|
||||
} else {
|
||||
state = 'scheme data';
|
||||
}
|
||||
} else if (!stateOverride) {
|
||||
buffer = '';
|
||||
cursor = 0;
|
||||
state = 'no scheme';
|
||||
continue;
|
||||
} else if (EOF == c) {
|
||||
break loop;
|
||||
} else {
|
||||
err('Code point not allowed in scheme: ' + c)
|
||||
break loop;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'scheme data':
|
||||
if ('?' == c) {
|
||||
query = '?';
|
||||
state = 'query';
|
||||
} else if ('#' == c) {
|
||||
this._fragment = '#';
|
||||
state = 'fragment';
|
||||
} else {
|
||||
// XXX error handling
|
||||
if (EOF != c && '\t' != c && '\n' != c && '\r' != c) {
|
||||
this._schemeData += percentEscape(c);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'no scheme':
|
||||
if (!base || !(isRelativeScheme(base._scheme))) {
|
||||
err('Missing scheme.');
|
||||
invalid.call(this);
|
||||
} else {
|
||||
state = 'relative';
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'relative or authority':
|
||||
if ('/' == c && '/' == input[cursor+1]) {
|
||||
state = 'authority ignore slashes';
|
||||
} else {
|
||||
err('Expected /, got: ' + c);
|
||||
state = 'relative';
|
||||
continue
|
||||
}
|
||||
break;
|
||||
|
||||
case 'relative':
|
||||
this._isRelative = true;
|
||||
if ('file' != this._scheme)
|
||||
this._scheme = base._scheme;
|
||||
if (EOF == c) {
|
||||
this._host = base._host;
|
||||
this._port = base._port;
|
||||
this._path = base._path.slice();
|
||||
this._query = base._query;
|
||||
break loop;
|
||||
} else if ('/' == c || '\\' == c) {
|
||||
if ('\\' == c)
|
||||
err('\\ is an invalid code point.');
|
||||
state = 'relative slash';
|
||||
} else if ('?' == c) {
|
||||
this._host = base._host;
|
||||
this._port = base._port;
|
||||
this._path = base._path.slice();
|
||||
this._query = '?';
|
||||
state = 'query';
|
||||
} else if ('#' == c) {
|
||||
this._host = base._host;
|
||||
this._port = base._port;
|
||||
this._path = base._path.slice();
|
||||
this._query = base._query;
|
||||
this._fragment = '#';
|
||||
state = 'fragment';
|
||||
} else {
|
||||
var nextC = input[cursor+1]
|
||||
var nextNextC = input[cursor+2]
|
||||
if (
|
||||
'file' != this._scheme || !ALPHA.test(c) ||
|
||||
(nextC != ':' && nextC != '|') ||
|
||||
(EOF != nextNextC && '/' != nextNextC && '\\' != nextNextC && '?' != nextNextC && '#' != nextNextC)) {
|
||||
this._host = base._host;
|
||||
this._port = base._port;
|
||||
this._path = base._path.slice();
|
||||
this._path.pop();
|
||||
}
|
||||
state = 'relative path';
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'relative slash':
|
||||
if ('/' == c || '\\' == c) {
|
||||
if ('\\' == c) {
|
||||
err('\\ is an invalid code point.');
|
||||
}
|
||||
if ('file' == this._scheme) {
|
||||
state = 'file host';
|
||||
} else {
|
||||
state = 'authority ignore slashes';
|
||||
}
|
||||
} else {
|
||||
if ('file' != this._scheme) {
|
||||
this._host = base._host;
|
||||
this._port = base._port;
|
||||
}
|
||||
state = 'relative path';
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'authority first slash':
|
||||
if ('/' == c) {
|
||||
state = 'authority second slash';
|
||||
} else {
|
||||
err("Expected '/', got: " + c);
|
||||
state = 'authority ignore slashes';
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'authority second slash':
|
||||
state = 'authority ignore slashes';
|
||||
if ('/' != c) {
|
||||
err("Expected '/', got: " + c);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'authority ignore slashes':
|
||||
if ('/' != c && '\\' != c) {
|
||||
state = 'authority';
|
||||
continue;
|
||||
} else {
|
||||
err('Expected authority, got: ' + c);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'authority':
|
||||
if ('@' == c) {
|
||||
if (seenAt) {
|
||||
err('@ already seen.');
|
||||
buffer += '%40';
|
||||
}
|
||||
seenAt = true;
|
||||
for (var i = 0; i < buffer.length; i++) {
|
||||
var cp = buffer[i];
|
||||
if ('\t' == cp || '\n' == cp || '\r' == cp) {
|
||||
err('Invalid whitespace in authority.');
|
||||
continue;
|
||||
}
|
||||
// XXX check URL code points
|
||||
if (':' == cp && null === this._password) {
|
||||
this._password = '';
|
||||
continue;
|
||||
}
|
||||
var tempC = percentEscape(cp);
|
||||
(null !== this._password) ? this._password += tempC : this._username += tempC;
|
||||
}
|
||||
buffer = '';
|
||||
} else if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c) {
|
||||
cursor -= buffer.length;
|
||||
buffer = '';
|
||||
state = 'host';
|
||||
continue;
|
||||
} else {
|
||||
buffer += c;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'file host':
|
||||
if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c) {
|
||||
if (buffer.length == 2 && ALPHA.test(buffer[0]) && (buffer[1] == ':' || buffer[1] == '|')) {
|
||||
state = 'relative path';
|
||||
} else if (buffer.length == 0) {
|
||||
state = 'relative path start';
|
||||
} else {
|
||||
this._host = IDNAToASCII.call(this, buffer);
|
||||
buffer = '';
|
||||
state = 'relative path start';
|
||||
}
|
||||
continue;
|
||||
} else if ('\t' == c || '\n' == c || '\r' == c) {
|
||||
err('Invalid whitespace in file host.');
|
||||
} else {
|
||||
buffer += c;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'host':
|
||||
case 'hostname':
|
||||
if (':' == c && !seenBracket) {
|
||||
// XXX host parsing
|
||||
this._host = IDNAToASCII.call(this, buffer);
|
||||
buffer = '';
|
||||
state = 'port';
|
||||
if ('hostname' == stateOverride) {
|
||||
break loop;
|
||||
}
|
||||
} else if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c) {
|
||||
this._host = IDNAToASCII.call(this, buffer);
|
||||
buffer = '';
|
||||
state = 'relative path start';
|
||||
if (stateOverride) {
|
||||
break loop;
|
||||
}
|
||||
continue;
|
||||
} else if ('\t' != c && '\n' != c && '\r' != c) {
|
||||
if ('[' == c) {
|
||||
seenBracket = true;
|
||||
} else if (']' == c) {
|
||||
seenBracket = false;
|
||||
}
|
||||
buffer += c;
|
||||
} else {
|
||||
err('Invalid code point in host/hostname: ' + c);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'port':
|
||||
if (/[0-9]/.test(c)) {
|
||||
buffer += c;
|
||||
} else if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c || stateOverride) {
|
||||
if ('' != buffer) {
|
||||
var temp = parseInt(buffer, 10);
|
||||
if (temp != relative[this._scheme]) {
|
||||
this._port = temp + '';
|
||||
}
|
||||
buffer = '';
|
||||
}
|
||||
if (stateOverride) {
|
||||
break loop;
|
||||
}
|
||||
state = 'relative path start';
|
||||
continue;
|
||||
} else if ('\t' == c || '\n' == c || '\r' == c) {
|
||||
err('Invalid code point in port: ' + c);
|
||||
} else {
|
||||
invalid.call(this);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'relative path start':
|
||||
if ('\\' == c)
|
||||
err("'\\' not allowed in path.");
|
||||
state = 'relative path';
|
||||
if ('/' != c && '\\' != c) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'relative path':
|
||||
if (EOF == c || '/' == c || '\\' == c || (!stateOverride && ('?' == c || '#' == c))) {
|
||||
if ('\\' == c) {
|
||||
err('\\ not allowed in relative path.');
|
||||
}
|
||||
var tmp;
|
||||
if (tmp = relativePathDotMapping[buffer.toLowerCase()]) {
|
||||
buffer = tmp;
|
||||
}
|
||||
if ('..' == buffer) {
|
||||
this._path.pop();
|
||||
if ('/' != c && '\\' != c) {
|
||||
this._path.push('');
|
||||
}
|
||||
} else if ('.' == buffer && '/' != c && '\\' != c) {
|
||||
this._path.push('');
|
||||
} else if ('.' != buffer) {
|
||||
if ('file' == this._scheme && this._path.length == 0 && buffer.length == 2 && ALPHA.test(buffer[0]) && buffer[1] == '|') {
|
||||
buffer = buffer[0] + ':';
|
||||
}
|
||||
this._path.push(buffer);
|
||||
}
|
||||
buffer = '';
|
||||
if ('?' == c) {
|
||||
this._query = '?';
|
||||
state = 'query';
|
||||
} else if ('#' == c) {
|
||||
this._fragment = '#';
|
||||
state = 'fragment';
|
||||
}
|
||||
} else if ('\t' != c && '\n' != c && '\r' != c) {
|
||||
buffer += percentEscape(c);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'query':
|
||||
if (!stateOverride && '#' == c) {
|
||||
this._fragment = '#';
|
||||
state = 'fragment';
|
||||
} else if (EOF != c && '\t' != c && '\n' != c && '\r' != c) {
|
||||
this._query += percentEscapeQuery(c);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'fragment':
|
||||
if (EOF != c && '\t' != c && '\n' != c && '\r' != c) {
|
||||
this._fragment += c;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
cursor++;
|
||||
}
|
||||
}
|
||||
|
||||
function clear() {
|
||||
this._scheme = '';
|
||||
this._schemeData = '';
|
||||
this._username = '';
|
||||
this._password = null;
|
||||
this._host = '';
|
||||
this._port = '';
|
||||
this._path = [];
|
||||
this._query = '';
|
||||
this._fragment = '';
|
||||
this._isInvalid = false;
|
||||
this._isRelative = false;
|
||||
}
|
||||
|
||||
// Does not process domain names or IP addresses.
|
||||
// Does not handle encoding for the query parameter.
|
||||
function jURL(url, base /* , encoding */) {
|
||||
if (base !== undefined && !(base instanceof jURL))
|
||||
base = new jURL(String(base));
|
||||
|
||||
this._url = url;
|
||||
clear.call(this);
|
||||
|
||||
var input = url.replace(/^[ \t\r\n\f]+|[ \t\r\n\f]+$/g, '');
|
||||
// encoding = encoding || 'utf-8'
|
||||
|
||||
parse.call(this, input, null, base);
|
||||
}
|
||||
|
||||
jURL.prototype = {
|
||||
get href() {
|
||||
if (this._isInvalid)
|
||||
return this._url;
|
||||
|
||||
var authority = '';
|
||||
if ('' != this._username || null != this._password) {
|
||||
authority = this._username +
|
||||
(null != this._password ? ':' + this._password : '') + '@';
|
||||
}
|
||||
|
||||
return this.protocol +
|
||||
(this._isRelative ? '//' + authority + this.host : '') +
|
||||
this.pathname + this._query + this._fragment;
|
||||
},
|
||||
set href(href) {
|
||||
clear.call(this);
|
||||
parse.call(this, href);
|
||||
},
|
||||
|
||||
get protocol() {
|
||||
return this._scheme + ':';
|
||||
},
|
||||
set protocol(protocol) {
|
||||
if (this._isInvalid)
|
||||
return;
|
||||
parse.call(this, protocol + ':', 'scheme start');
|
||||
},
|
||||
|
||||
get host() {
|
||||
return this._isInvalid ? '' : this._port ?
|
||||
this._host + ':' + this._port : this._host;
|
||||
},
|
||||
set host(host) {
|
||||
if (this._isInvalid || !this._isRelative)
|
||||
return;
|
||||
parse.call(this, host, 'host');
|
||||
},
|
||||
|
||||
get hostname() {
|
||||
return this._host;
|
||||
},
|
||||
set hostname(hostname) {
|
||||
if (this._isInvalid || !this._isRelative)
|
||||
return;
|
||||
parse.call(this, hostname, 'hostname');
|
||||
},
|
||||
|
||||
get port() {
|
||||
return this._port;
|
||||
},
|
||||
set port(port) {
|
||||
if (this._isInvalid || !this._isRelative)
|
||||
return;
|
||||
parse.call(this, port, 'port');
|
||||
},
|
||||
|
||||
get pathname() {
|
||||
return this._isInvalid ? '' : this._isRelative ?
|
||||
'/' + this._path.join('/') : this._schemeData;
|
||||
},
|
||||
set pathname(pathname) {
|
||||
if (this._isInvalid || !this._isRelative)
|
||||
return;
|
||||
this._path = [];
|
||||
parse.call(this, pathname, 'relative path start');
|
||||
},
|
||||
|
||||
get search() {
|
||||
return this._isInvalid || !this._query || '?' == this._query ?
|
||||
'' : this._query;
|
||||
},
|
||||
set search(search) {
|
||||
if (this._isInvalid || !this._isRelative)
|
||||
return;
|
||||
this._query = '?';
|
||||
if ('?' == search[0])
|
||||
search = search.slice(1);
|
||||
parse.call(this, search, 'query');
|
||||
},
|
||||
|
||||
get hash() {
|
||||
return this._isInvalid || !this._fragment || '#' == this._fragment ?
|
||||
'' : this._fragment;
|
||||
},
|
||||
set hash(hash) {
|
||||
if (this._isInvalid)
|
||||
return;
|
||||
this._fragment = '#';
|
||||
if ('#' == hash[0])
|
||||
hash = hash.slice(1);
|
||||
parse.call(this, hash, 'fragment');
|
||||
},
|
||||
|
||||
get origin() {
|
||||
var host;
|
||||
if (this._isInvalid || !this._scheme) {
|
||||
return '';
|
||||
}
|
||||
// javascript: Gecko returns String(""), WebKit/Blink String("null")
|
||||
// Gecko throws error for "data://"
|
||||
// data: Gecko returns "", Blink returns "data://", WebKit returns "null"
|
||||
// Gecko returns String("") for file: mailto:
|
||||
// WebKit/Blink returns String("SCHEME://") for file: mailto:
|
||||
switch (this._scheme) {
|
||||
case 'data':
|
||||
case 'file':
|
||||
case 'javascript':
|
||||
case 'mailto':
|
||||
return 'null';
|
||||
}
|
||||
host = this.host;
|
||||
if (!host) {
|
||||
return '';
|
||||
}
|
||||
return this._scheme + '://' + host;
|
||||
}
|
||||
};
|
||||
|
||||
// Copy over the static methods
|
||||
var OriginalURL = scope.URL;
|
||||
if (OriginalURL) {
|
||||
jURL.createObjectURL = function(blob) {
|
||||
// IE extension allows a second optional options argument.
|
||||
// http://msdn.microsoft.com/en-us/library/ie/hh772302(v=vs.85).aspx
|
||||
return OriginalURL.createObjectURL.apply(OriginalURL, arguments);
|
||||
};
|
||||
jURL.revokeObjectURL = function(url) {
|
||||
OriginalURL.revokeObjectURL(url);
|
||||
};
|
||||
}
|
||||
|
||||
scope.URL = jURL;
|
||||
|
||||
})(this);
|
||||
@@ -1,5 +1,6 @@
|
||||
[
|
||||
"build/boot.js",
|
||||
"../MutationObserver/MutationObserver.js",
|
||||
"../HTMLImports/build.json",
|
||||
"../CustomElements/build.json",
|
||||
"../Template/Template.js",
|
||||
|
||||
49
tests/HTMLImports/html/dynamic-all-imports-detail.html
Normal file
49
tests/HTMLImports/html/dynamic-all-imports-detail.html
Normal file
@@ -0,0 +1,49 @@
|
||||
<!doctype html>
|
||||
<!--
|
||||
@license
|
||||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||||
Code distributed by Google as part of the polymer project is also
|
||||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>HTML Imports Dynamic</title>
|
||||
<script src="../../tools/htmltest.js"></script>
|
||||
<script src="../../tools/chai/chai.js"></script>
|
||||
<script src="../../../src/HTMLImports/HTMLImports.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// some time later
|
||||
setTimeout(function() {
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = '<link rel="import" href="imports/load-1.html">' +
|
||||
'<link rel="import" href="imports/load-2.html">';
|
||||
document.body.appendChild(div);
|
||||
var ports = document.querySelectorAll('link[rel=import]');
|
||||
var loads = 0;
|
||||
for (var i=0, l=ports.length, n; (i<l) && (n=ports[i]); i++) {
|
||||
n.addEventListener('load', function(e) {
|
||||
loads++;
|
||||
chai.assert.ok(e.target.import);
|
||||
});
|
||||
}
|
||||
HTMLImports.whenReady(function(detail) {
|
||||
chai.assert.equal(detail.allImports.length, 2);
|
||||
chai.assert.equal(detail.loadedImports.length, 2);
|
||||
|
||||
chai.expect(detail.allImports[0].href).to.contain('imports/load-1.html');
|
||||
chai.expect(detail.allImports[1].href).to.contain('imports/load-2.html');
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
50
tests/HTMLImports/html/dynamic-errors-detail.html
Normal file
50
tests/HTMLImports/html/dynamic-errors-detail.html
Normal file
@@ -0,0 +1,50 @@
|
||||
<!doctype html>
|
||||
<!--
|
||||
@license
|
||||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||||
Code distributed by Google as part of the polymer project is also
|
||||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>HTML Imports Dynamic</title>
|
||||
<script src="../../tools/htmltest.js"></script>
|
||||
<script src="../../tools/chai/chai.js"></script>
|
||||
<script src="../../../src/HTMLImports/HTMLImports.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// some time later
|
||||
setTimeout(function() {
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = '<link rel="import" href="imports/load-1.html">' +
|
||||
'<link rel="import" href="imports/load-does-not-exist.html">';
|
||||
document.body.appendChild(div);
|
||||
var ports = document.querySelectorAll('link[rel=import]');
|
||||
var loads = 0;
|
||||
for (var i=0, l=ports.length, n; (i<l) && (n=ports[i]); i++) {
|
||||
n.addEventListener('load', function(e) {
|
||||
loads++;
|
||||
chai.assert.ok(e.target.import);
|
||||
});
|
||||
}
|
||||
HTMLImports.whenReady(function(detail) {
|
||||
chai.assert.equal(detail.allImports.length, 2);
|
||||
chai.assert.equal(detail.errorImports.length, 1);
|
||||
chai.assert.equal(detail.loadedImports.length, 1);
|
||||
|
||||
var errorImport = detail.errorImports[0];
|
||||
chai.expect(errorImport.href).to.contain('imports/load-does-not-exist.html');
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
50
tests/HTMLImports/html/dynamic-loaded-detail.html
Normal file
50
tests/HTMLImports/html/dynamic-loaded-detail.html
Normal file
@@ -0,0 +1,50 @@
|
||||
<!doctype html>
|
||||
<!--
|
||||
@license
|
||||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||||
Code distributed by Google as part of the polymer project is also
|
||||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>HTML Imports Dynamic</title>
|
||||
<script src="../../tools/htmltest.js"></script>
|
||||
<script src="../../tools/chai/chai.js"></script>
|
||||
<script src="../../../src/HTMLImports/HTMLImports.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// some time later
|
||||
setTimeout(function() {
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = '<link rel="import" href="imports/load-1.html">' +
|
||||
'<link rel="import" href="imports/load-2.html">';
|
||||
document.body.appendChild(div);
|
||||
var ports = document.querySelectorAll('link[rel=import]');
|
||||
var loads = 0;
|
||||
for (var i=0, l=ports.length, n; (i<l) && (n=ports[i]); i++) {
|
||||
n.addEventListener('load', function(e) {
|
||||
loads++;
|
||||
chai.assert.ok(e.target.import);
|
||||
});
|
||||
}
|
||||
HTMLImports.whenReady(function(detail) {
|
||||
chai.assert.equal(detail.allImports.length, 2);
|
||||
chai.assert.equal(detail.errorImports.length, 0);
|
||||
chai.assert.equal(detail.loadedImports.length, 2);
|
||||
|
||||
chai.expect(detail.loadedImports[0].href).to.contain('imports/load-1.html');
|
||||
chai.expect(detail.loadedImports[1].href).to.contain('imports/load-2.html');
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -21,6 +21,9 @@ htmlSuite('HTMLImports', function() {
|
||||
htmlTest('html/currentScript.html');
|
||||
htmlTest('html/dedupe.html');
|
||||
htmlTest('html/dynamic.html');
|
||||
htmlTest('html/dynamic-all-imports-detail.html');
|
||||
htmlTest('html/dynamic-errors-detail.html');
|
||||
htmlTest('html/dynamic-loaded-detail.html');
|
||||
htmlTest('html/csp.html');
|
||||
htmlTest('html/customevent-detail.html');
|
||||
htmlTest('html/encoding.html');
|
||||
|
||||
@@ -378,4 +378,25 @@ suite('JsMutationObserver childList', function() {
|
||||
});
|
||||
});
|
||||
|
||||
test('Append child in child', function() {
|
||||
var div = testDiv.appendChild(document.createElement('div'));
|
||||
|
||||
var observer = new JsMutationObserver(function() {});
|
||||
observer.observe(div, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
var div2 = document.createElement('div')
|
||||
var div3 = div2.appendChild(document.createElement('div'));
|
||||
div.appendChild(div2);
|
||||
var records = observer.takeRecords();
|
||||
|
||||
if(records.length == 1) {
|
||||
assert.strictEqual(records[0].target, div);
|
||||
assert.strictEqual(records[0].addedNodes[0].firstChild, div3);
|
||||
} else {
|
||||
assert.strictEqual(records[0].target, div);
|
||||
assert.strictEqual(records[1].target, div2);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
<script src="../tools/mocha-htmltest.js"></script>
|
||||
|
||||
<!-- MutationObserver -->
|
||||
<script src="../../src/WeakMap/WeakMap.js"></script>
|
||||
<script src="../../src/MutationObserver/MutationObserver.js"></script>
|
||||
<script>
|
||||
|
||||
|
||||
@@ -9,6 +9,13 @@
|
||||
*/
|
||||
|
||||
suite('DOMTokenList', function() {
|
||||
if (!window.DOMTokenList) {
|
||||
test('classList returns undefined if not supported', function() {
|
||||
var div = document.createElement('div');
|
||||
assert.isUndefined(div.classList);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
test('instanceof', function() {
|
||||
var div = document.createElement('div');
|
||||
|
||||
@@ -103,6 +103,19 @@ suite('Element', function() {
|
||||
assert.equal(bb, div.querySelector('div /deep/ bb'));
|
||||
});
|
||||
|
||||
test('querySelector ::shadow', function() {
|
||||
var div = document.createElement('div');
|
||||
var div2 = document.createElement('div');
|
||||
div.appendChild(div2);
|
||||
var sr = div2.createShadowRoot();
|
||||
sr.innerHTML = '<bb></bb>';
|
||||
var bb = sr.firstChild;
|
||||
|
||||
div.offsetHeight;
|
||||
|
||||
assert.equal(bb, div.querySelector('div::shadow bb'));
|
||||
});
|
||||
|
||||
test('querySelectorAll deep', function() {
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = '<aa></aa><aa></aa>';
|
||||
@@ -125,6 +138,33 @@ suite('Element', function() {
|
||||
assert.equal(bb, list[0]);
|
||||
});
|
||||
|
||||
test('querySelectorAll ::shadow', function() {
|
||||
var div = document.createElement('div');
|
||||
var div2 = document.createElement('div');
|
||||
div.appendChild(div2);
|
||||
var sr = div2.createShadowRoot();
|
||||
sr.innerHTML = '<bb></bb><bb></bb>';
|
||||
var bb = sr.firstChild;
|
||||
|
||||
div.offsetHeight;
|
||||
|
||||
var list = div.querySelectorAll('div::shadow bb');
|
||||
assert.equal(2, list.length);
|
||||
assert.equal(bb, list[0]);
|
||||
});
|
||||
|
||||
test('matches', function() {
|
||||
var div = document.createElement('div');
|
||||
div.classList.add('host-class');
|
||||
document.body.appendChild(div);
|
||||
var p = document.createElement('p');
|
||||
p.classList.add('child-class');
|
||||
div.appendChild(p);
|
||||
assert.isTrue(p.matches(':host(.host-class) *'));
|
||||
assert.isTrue(p.matches(':host::shadow .child-class'));
|
||||
assert.isTrue(p.matches('.host-class /deep/ p.child-class'));
|
||||
});
|
||||
|
||||
skipTest('getElementsByTagName', function() {
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = '<a>0</a><a>1</a>';
|
||||
|
||||
@@ -84,5 +84,4 @@ suite('SVGElement', function() {
|
||||
|
||||
assert.equal(g.ownerSVGElement, el2);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user