Merge branch 'upstream' into relative_path_resolving_in_css

This commit is contained in:
Nazar Mokrynskyi
2015-02-24 08:19:07 +01:00
29 changed files with 997 additions and 38 deletions

21
.autoclave-build.sh Executable file
View 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
View 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.

View File

@@ -1,6 +1,8 @@
webcomponents.js
================
[![Join the chat at https://gitter.im/webcomponents/webcomponentsjs](https://badges.gitter.im/Join%20Chat.svg)](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.

View File

@@ -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"

View File

@@ -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"
},

View File

@@ -28,7 +28,6 @@ var file = 'CustomElements.js';
var modules = [
'../WeakMap/WeakMap.js',
'../MutationObserver/MutationObserver.js',
'base.js',
'traverse.js',
'observe.js',

View File

@@ -1,6 +1,5 @@
[
"../WeakMap/WeakMap.js",
"../MutationObserver/MutationObserver.js",
"base.js",
"traverse.js",
"observe.js",

View File

@@ -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;

View File

@@ -27,7 +27,6 @@ var file = 'HTMLImports.js';
var modules = [
'../WeakMap/WeakMap.js',
'../MutationObserver/MutationObserver.js',
'base.js',
'module.js',
'path.js',

View File

@@ -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);
});

View File

@@ -1,6 +1,5 @@
[
"../WeakMap/WeakMap.js",
"../MutationObserver/MutationObserver.js",
"base.js",
"module.js",
"path.js",

View File

@@ -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});
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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
});
}

View File

@@ -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;

View File

@@ -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
View 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);

View File

@@ -1,5 +1,6 @@
[
"build/boot.js",
"../MutationObserver/MutationObserver.js",
"../HTMLImports/build.json",
"../CustomElements/build.json",
"../Template/Template.js",

View 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>

View 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>

View 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>

View File

@@ -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');

View File

@@ -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);
}
});
});

View File

@@ -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>

View File

@@ -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');

View File

@@ -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>';

View File

@@ -84,5 +84,4 @@ suite('SVGElement', function() {
assert.equal(g.ownerSVGElement, el2);
});
});