Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(612)

Unified Diff: pkg/web_components/lib/platform.concat.js

Issue 182193002: [polymer] interop with polymer-element and polymer.js (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/web_components/lib/platform.js ('k') | pkg/web_components/lib/platform.concat.js.map » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/web_components/lib/platform.concat.js
diff --git a/pkg/web_components/lib/platform.concat.js b/pkg/web_components/lib/platform.concat.js
index 0be0a0855658dd28524f3a915c89381299ee6dc0..6fa2b7b4f1830554045bbb76fead092f966584bc 100644
--- a/pkg/web_components/lib/platform.concat.js
+++ b/pkg/web_components/lib/platform.concat.js
@@ -494,10 +494,6 @@ if (typeof WeakMap === 'undefined') {
}
function reset() {
- resetScheduled = false;
- if (!resetNeeded)
- return;
-
var objs = toRemove === emptyArray ? [] : toRemove;
toRemove = objects;
objects = objs;
@@ -520,16 +516,26 @@ if (typeof WeakMap === 'undefined') {
toRemove.length = 0;
}
+ function scheduledReset() {
+ resetScheduled = false;
+ if (!resetNeeded)
+ return;
+
+ reset();
+ }
+
function scheduleReset() {
if (resetScheduled)
return;
resetNeeded = true;
resetScheduled = true;
- runEOM(reset);
+ runEOM(scheduledReset);
}
function callback() {
+ reset();
+
var observer;
for (var id in observers) {
@@ -539,8 +545,6 @@ if (typeof WeakMap === 'undefined') {
observer.check_();
}
-
- scheduleReset();
}
var record = {
@@ -1921,6 +1925,8 @@ window.ShadowDOMPolyfill = {};
enumerable: false,
writable: true
});
+ // Set it again. Some VMs optimizes objects that are used as prototypes.
+ wrapperConstructor.prototype = wrapperPrototype;
}
function isWrapperFor(wrapperConstructor, nativeConstructor) {
@@ -1948,9 +1954,9 @@ window.ShadowDOMPolyfill = {};
function GeneratedWrapper(node) {
superWrapperConstructor.call(this, node);
}
- GeneratedWrapper.prototype =
- Object.create(superWrapperConstructor.prototype);
- GeneratedWrapper.prototype.constructor = GeneratedWrapper;
+ var p = Object.create(superWrapperConstructor.prototype);
+ p.constructor = GeneratedWrapper;
+ GeneratedWrapper.prototype = p;
return GeneratedWrapper;
}
@@ -2524,6 +2530,70 @@ window.ShadowDOMPolyfill = {};
})(window.ShadowDOMPolyfill);
+/**
+ * Copyright 2014 The Polymer Authors. All rights reserved.
+ * Use of this source code is goverened by a BSD-style
+ * license that can be found in the LICENSE file.
+ */
+
+(function(scope) {
+ 'use strict';
+
+ /**
+ * A tree scope represents the root of a tree. All nodes in a tree point to
+ * the same TreeScope object. The tree scope of a node get set the first time
+ * it is accessed or when a node is added or remove to a tree.
+ * @constructor
+ */
+ function TreeScope(root, parent) {
+ this.root = root;
+ this.parent = parent;
+ }
+
+ TreeScope.prototype = {
+ get renderer() {
+ if (this.root instanceof scope.wrappers.ShadowRoot) {
+ return scope.getRendererForHost(this.root.host);
+ }
+ return null;
+ },
+
+ contains: function(treeScope) {
+ for (; treeScope; treeScope = treeScope.parent) {
+ if (treeScope === this)
+ return true;
+ }
+ return false;
+ }
+ };
+
+ function setTreeScope(node, treeScope) {
+ if (node.treeScope_ !== treeScope) {
+ node.treeScope_ = treeScope;
+ for (var child = node.firstChild; child; child = child.nextSibling) {
+ setTreeScope(child, treeScope);
+ }
+ }
+ }
+
+ function getTreeScope(node) {
+ if (node.treeScope_)
+ return node.treeScope_;
+ var parent = node.parentNode;
+ var treeScope;
+ if (parent)
+ treeScope = getTreeScope(parent);
+ else
+ treeScope = new TreeScope(node, null);
+ return node.treeScope_ = treeScope;
+ }
+
+ scope.TreeScope = TreeScope;
+ scope.getTreeScope = getTreeScope;
+ scope.setTreeScope = setTreeScope;
+
+})(window.ShadowDOMPolyfill);
+
// Copyright 2013 The Polymer Authors. All rights reserved.
// Use of this source code is goverened by a BSD-style
// license that can be found in the LICENSE file.
@@ -2532,6 +2602,7 @@ window.ShadowDOMPolyfill = {};
'use strict';
var forwardMethodsToWrapper = scope.forwardMethodsToWrapper;
+ var getTreeScope = scope.getTreeScope;
var mixin = scope.mixin;
var registerWrapper = scope.registerWrapper;
var unwrap = scope.unwrap;
@@ -2686,27 +2757,10 @@ window.ShadowDOMPolyfill = {};
return getInsertionParent(node);
}
- function rootOfNode(node) {
- var p;
- while (p = node.parentNode) {
- node = p;
- }
- return node;
- }
-
function inSameTree(a, b) {
- return rootOfNode(a) === rootOfNode(b);
+ return getTreeScope(a) === getTreeScope(b);
}
- function enclosedBy(a, b) {
- if (a === b)
- return true;
- if (a instanceof wrappers.ShadowRoot)
- return enclosedBy(rootOfNode(a.host), b);
- return false;
- }
-
-
function dispatchOriginalEvent(originalEvent) {
// Make sure this event is only dispatched once.
if (handledEventsTable.get(originalEvent))
@@ -2921,12 +2975,12 @@ window.ShadowDOMPolyfill = {};
if (eventPath) {
var index = 0;
var lastIndex = eventPath.length - 1;
- var baseRoot = rootOfNode(currentTargetTable.get(this));
+ var baseRoot = getTreeScope(currentTargetTable.get(this));
for (var i = 0; i <= lastIndex; i++) {
var currentTarget = eventPath[i].currentTarget;
- var currentRoot = rootOfNode(currentTarget);
- if (enclosedBy(baseRoot, currentRoot) &&
+ var currentRoot = getTreeScope(currentTarget);
+ if (currentRoot.contains(baseRoot) &&
// Make sure we do not add Window to the path.
(i !== lastIndex || currentTarget instanceof wrappers.Node)) {
nodeList[index++] = currentTarget;
@@ -3394,22 +3448,27 @@ window.ShadowDOMPolyfill = {};
})(window.ShadowDOMPolyfill);
-// Copyright 2012 The Polymer Authors. All rights reserved.
-// Use of this source code is goverened by a BSD-style
-// license that can be found in the LICENSE file.
+/**
+ * Copyright 2012 The Polymer Authors. All rights reserved.
+ * Use of this source code is goverened by a BSD-style
+ * license that can be found in the LICENSE file.
+ */
(function(scope) {
'use strict';
var EventTarget = scope.wrappers.EventTarget;
var NodeList = scope.wrappers.NodeList;
+ var TreeScope = scope.TreeScope;
var assert = scope.assert;
var defineWrapGetter = scope.defineWrapGetter;
var enqueueMutation = scope.enqueueMutation;
+ var getTreeScope = scope.getTreeScope;
var isWrapper = scope.isWrapper;
var mixin = scope.mixin;
var registerTransientObservers = scope.registerTransientObservers;
var registerWrapper = scope.registerWrapper;
+ var setTreeScope = scope.setTreeScope;
var unwrap = scope.unwrap;
var wrap = scope.wrap;
var wrapIfNeeded = scope.wrapIfNeeded;
@@ -3526,23 +3585,27 @@ window.ShadowDOMPolyfill = {};
}
// http://dom.spec.whatwg.org/#node-is-inserted
- function nodeWasAdded(node) {
+ function nodeWasAdded(node, treeScope) {
+ setTreeScope(node, treeScope);
node.nodeIsInserted_();
}
- function nodesWereAdded(nodes) {
+ function nodesWereAdded(nodes, parent) {
+ var treeScope = getTreeScope(parent);
for (var i = 0; i < nodes.length; i++) {
- nodeWasAdded(nodes[i]);
+ nodeWasAdded(nodes[i], treeScope);
}
}
// http://dom.spec.whatwg.org/#node-is-removed
function nodeWasRemoved(node) {
- // Nothing at this point in time.
+ setTreeScope(node, new TreeScope(node, null));
}
function nodesWereRemoved(nodes) {
- // Nothing at this point in time.
+ for (var i = 0; i < nodes.length; i++) {
+ nodeWasRemoved(nodes[i]);
+ }
}
function ensureSameOwnerDocument(parent, child) {
@@ -3660,6 +3723,17 @@ window.ShadowDOMPolyfill = {};
return clone;
}
+ function contains(self, child) {
+ if (!child || getTreeScope(self) !== getTreeScope(child))
+ return false;
+
+ for (var node = child; node; node = node.parentNode) {
+ if (node === self)
+ return true;
+ }
+ return false;
+ }
+
var OriginalNode = window.Node;
/**
@@ -3706,6 +3780,8 @@ window.ShadowDOMPolyfill = {};
* @private
*/
this.previousSibling_ = undefined;
+
+ this.treeScope_ = undefined;
}
var OriginalDocumentFragment = window.DocumentFragment;
@@ -3794,7 +3870,7 @@ window.ShadowDOMPolyfill = {};
previousSibling: previousNode
});
- nodesWereAdded(nodes);
+ nodesWereAdded(nodes, this);
return childWrapper;
},
@@ -3926,7 +4002,7 @@ window.ShadowDOMPolyfill = {};
});
nodeWasRemoved(oldChildWrapper);
- nodesWereAdded(nodes);
+ nodesWereAdded(nodes, this);
return oldChildWrapper;
},
@@ -4018,7 +4094,7 @@ window.ShadowDOMPolyfill = {};
});
nodesWereRemoved(removedNodes);
- nodesWereAdded(addedNodes);
+ nodesWereAdded(addedNodes, this);
},
get childNodes() {
@@ -4036,18 +4112,7 @@ window.ShadowDOMPolyfill = {};
},
contains: function(child) {
- if (!child)
- return false;
-
- child = wrapIfNeeded(child);
-
- // TODO(arv): Optimize using ownerDocument etc.
- if (child === this)
- return true;
- var parentNode = child.parentNode;
- if (!parentNode)
- return false;
- return this.contains(parentNode);
+ return contains(this, wrapIfNeeded(child));
},
compareDocumentPosition: function(otherNode) {
@@ -4104,13 +4169,13 @@ window.ShadowDOMPolyfill = {};
delete Node.prototype.querySelectorAll;
Node.prototype = mixin(Object.create(EventTarget.prototype), Node.prototype);
+ scope.cloneNode = cloneNode;
scope.nodeWasAdded = nodeWasAdded;
scope.nodeWasRemoved = nodeWasRemoved;
scope.nodesWereAdded = nodesWereAdded;
scope.nodesWereRemoved = nodesWereRemoved;
scope.snapshotNodeList = snapshotNodeList;
scope.wrappers.Node = Node;
- scope.cloneNode = cloneNode;
})(window.ShadowDOMPolyfill);
@@ -4682,7 +4747,7 @@ window.ShadowDOMPolyfill = {};
});
nodesWereRemoved(removedNodes);
- nodesWereAdded(addedNodes);
+ nodesWereAdded(addedNodes, this);
},
get outerHTML() {
@@ -5723,8 +5788,10 @@ window.ShadowDOMPolyfill = {};
'use strict';
var DocumentFragment = scope.wrappers.DocumentFragment;
+ var TreeScope = scope.TreeScope;
var elementFromPoint = scope.elementFromPoint;
var getInnerHTML = scope.getInnerHTML;
+ var getTreeScope = scope.getTreeScope;
var mixin = scope.mixin;
var rewrap = scope.rewrap;
var setInnerHTML = scope.setInnerHTML;
@@ -5743,6 +5810,8 @@ window.ShadowDOMPolyfill = {};
// DocumentFragment instance. Override that.
rewrap(node, this);
+ this.treeScope_ = new TreeScope(this, getTreeScope(hostWrapper));
+
var oldShadowRoot = hostWrapper.shadowRoot;
nextOlderShadowTreeTable.set(this, oldShadowRoot);
@@ -5798,6 +5867,7 @@ window.ShadowDOMPolyfill = {};
var Node = scope.wrappers.Node;
var ShadowRoot = scope.wrappers.ShadowRoot;
var assert = scope.assert;
+ var getTreeScope = scope.getTreeScope;
var mixin = scope.mixin;
var oneOf = scope.oneOf;
var unwrap = scope.unwrap;
@@ -6017,7 +6087,11 @@ window.ShadowDOMPolyfill = {};
// TODO(arv): Order these in document order. That way we do not have to
// render something twice.
for (var i = 0; i < pendingDirtyRenderers.length; i++) {
- pendingDirtyRenderers[i].render();
+ var renderer = pendingDirtyRenderers[i];
+ var parentRenderer = renderer.parentRenderer;
+ if (parentRenderer && parentRenderer.dirty)
+ continue;
+ renderer.render();
}
pendingDirtyRenderers = [];
@@ -6043,10 +6117,9 @@ window.ShadowDOMPolyfill = {};
}
function getShadowRootAncestor(node) {
- for (; node; node = node.parentNode) {
- if (node instanceof ShadowRoot)
- return node;
- }
+ var root = getTreeScope(node).root;
+ if (root instanceof ShadowRoot)
+ return root;
return null;
}
@@ -6163,6 +6236,10 @@ window.ShadowDOMPolyfill = {};
this.dirty = false;
},
+ get parentRenderer() {
+ return getTreeScope(this.host).renderer;
+ },
+
invalidate: function() {
if (!this.dirty) {
this.dirty = true;
@@ -6193,8 +6270,7 @@ window.ShadowDOMPolyfill = {};
if (isShadowHost(node)) {
var renderer = getRendererForHost(node);
- // renderNode.skip = !renderer.dirty;
- renderer.invalidate();
+ renderNode.skip = !renderer.dirty;
renderer.render(renderNode);
} else {
for (var child = node.firstChild; child; child = child.nextSibling) {
@@ -6593,6 +6669,7 @@ window.ShadowDOMPolyfill = {};
var Selection = scope.wrappers.Selection;
var SelectorsInterface = scope.SelectorsInterface;
var ShadowRoot = scope.wrappers.ShadowRoot;
+ var TreeScope = scope.TreeScope;
var cloneNode = scope.cloneNode;
var defineWrapGetter = scope.defineWrapGetter;
var elementFromPoint = scope.elementFromPoint;
@@ -6611,6 +6688,7 @@ window.ShadowDOMPolyfill = {};
function Document(node) {
Node.call(this, node);
+ this.treeScope_ = new TreeScope(this, null);
}
Document.prototype = Object.create(Node.prototype);
@@ -7238,55 +7316,68 @@ var ShadowCSS = {
// 2. optionally tag root nodes with scope name
// 3. shim polyfill directives /* @polyfill */ and /* @polyfill-rule */
// 4. shim :host and scoping
- shimStyling: function(root, name, extendsName, ownSheet) {
+ shimStyling: function(root, name, extendsName) {
+ var scopeStyles = this.prepareRoot(root, name, extendsName);
var typeExtension = this.isTypeExtension(extendsName);
+ var scopeSelector = this.makeScopeSelector(name, typeExtension);
// use caching to make working with styles nodes easier and to facilitate
// lookup of extendee
- var def = this.registerDefinition(root, name, extendsName);
- // find styles and apply shimming...
- if (this.strictStyling) {
- this.applyScopeToContent(root, name);
- }
- var cssText = this.stylesToShimmedCssText(def.rootStyles, def.scopeStyles,
- name, typeExtension);
- // provide shimmedStyle for user extensibility
- def.shimmedStyle = cssTextToStyle(cssText);
+ var cssText = stylesToCssText(scopeStyles, true);
+ cssText = this.scopeCssText(cssText, scopeSelector);
+ // cache shimmed css on root for user extensibility
if (root) {
- root.shimmedStyle = def.shimmedStyle;
- }
- // remove existing style elements
- for (var i=0, l=def.rootStyles.length, s; (i<l) && (s=def.rootStyles[i]);
- i++) {
- s.parentNode.removeChild(s);
+ root.shimmedStyle = cssText;
}
// add style to document
- if (ownSheet) {
- addOwnSheet(cssText, name);
- } else {
- addCssToDocument(cssText);
+ this.addCssToDocument(cssText, name);
+ },
+ /*
+ * Shim a style element with the given selector. Returns cssText that can
+ * be included in the document via Platform.ShadowCSS.addCssToDocument(css).
+ */
+ shimStyle: function(style, selector) {
+ return this.shimCssText(style.textContent, selector);
+ },
+ /*
+ * Shim some cssText with the given selector. Returns cssText that can
+ * be included in the document via Platform.ShadowCSS.addCssToDocument(css).
+ */
+ shimCssText: function(cssText, selector) {
+ cssText = this.insertDirectives(cssText);
+ return this.scopeCssText(cssText, selector);
+ },
+ makeScopeSelector: function(name, typeExtension) {
+ if (name) {
+ return typeExtension ? '[is=' + name + ']' : name;
}
+ return '';
},
- // apply @polyfill rules + :host and scope shimming
- stylesToShimmedCssText: function(rootStyles, scopeStyles, name,
- typeExtension) {
- name = name || '';
- // insert @polyfill and @polyfill-rule rules into style elements
- // scoping process takes care of shimming these
- this.insertPolyfillDirectives(rootStyles);
- this.insertPolyfillRules(rootStyles);
- var cssText = this.shimScoping(scopeStyles, name, typeExtension);
- // note: we only need to do rootStyles since these are unscoped.
- cssText += this.extractPolyfillUnscopedRules(rootStyles);
- return cssText.trim();
+ isTypeExtension: function(extendsName) {
+ return extendsName && extendsName.indexOf('-') < 0;
+ },
+ prepareRoot: function(root, name, extendsName) {
+ var def = this.registerRoot(root, name, extendsName);
+ this.replaceTextInStyles(def.rootStyles, this.insertDirectives);
+ // remove existing style elements
+ this.removeStyles(root, def.rootStyles);
+ // apply strict attr
+ if (this.strictStyling) {
+ this.applyScopeToContent(root, name);
+ }
+ return def.scopeStyles;
},
- registerDefinition: function(root, name, extendsName) {
+ removeStyles: function(root, styles) {
+ for (var i=0, l=styles.length, s; (i<l) && (s=styles[i]); i++) {
+ s.parentNode.removeChild(s);
+ }
+ },
+ registerRoot: function(root, name, extendsName) {
var def = this.registry[name] = {
root: root,
name: name,
extendsName: extendsName
}
- var styles = root ? root.querySelectorAll('style') : [];
- styles = styles ? Array.prototype.slice.call(styles, 0) : [];
+ var styles = this.findStyles(root);
def.rootStyles = styles;
def.scopeStyles = def.rootStyles;
var extendee = this.registry[def.extendsName];
@@ -7295,8 +7386,14 @@ var ShadowCSS = {
}
return def;
},
- isTypeExtension: function(extendsName) {
- return extendsName && extendsName.indexOf('-') < 0;
+ findStyles: function(root) {
+ if (!root) {
+ return [];
+ }
+ var styles = root.querySelectorAll('style');
+ return Array.prototype.filter.call(styles, function(s) {
+ return !s.hasAttribute(NO_SHIM_ATTRIBUTE);
+ });
},
applyScopeToContent: function(root, name) {
if (root) {
@@ -7313,89 +7410,59 @@ var ShadowCSS = {
this);
}
},
+ insertDirectives: function(cssText) {
+ cssText = this.insertPolyfillDirectivesInCssText(cssText);
+ return this.insertPolyfillRulesInCssText(cssText);
+ },
/*
* Process styles to convert native ShadowDOM rules that will trip
- * up the css parser; we rely on decorating the stylesheet with comments.
+ * up the css parser; we rely on decorating the stylesheet with inert rules.
*
* For example, we convert this rule:
*
- * (comment start) @polyfill :host menu-item (comment end)
- * shadow::-webkit-distributed(menu-item) {
+ * polyfill-next-selector { content: ':host menu-item'; }
+ * ::content menu-item {
*
* to this:
*
* scopeName menu-item {
*
**/
- insertPolyfillDirectives: function(styles) {
- if (styles) {
- Array.prototype.forEach.call(styles, function(s) {
- s.textContent = this.insertPolyfillDirectivesInCssText(s.textContent);
- }, this);
- }
- },
insertPolyfillDirectivesInCssText: function(cssText) {
- return cssText.replace(cssPolyfillCommentRe, function(match, p1) {
+ // TODO(sorvell): remove either content or comment
+ cssText = cssText.replace(cssCommentNextSelectorRe, function(match, p1) {
// remove end comment delimiter and add block start
return p1.slice(0, -2) + '{';
});
+ return cssText.replace(cssContentNextSelectorRe, function(match, p1) {
+ return p1 + ' {';
+ });
},
/*
* Process styles to add rules which will only apply under the polyfill
*
* For example, we convert this rule:
*
- * (comment start) @polyfill-rule :host menu-item {
- * ... } (comment end)
+ * polyfill-rule {
+ * content: ':host menu-item';
+ * ...
+ * }
*
* to this:
*
* scopeName menu-item {...}
*
**/
- insertPolyfillRules: function(styles) {
- if (styles) {
- Array.prototype.forEach.call(styles, function(s) {
- s.textContent = this.insertPolyfillRulesInCssText(s.textContent);
- }, this);
- }
- },
insertPolyfillRulesInCssText: function(cssText) {
- return cssText.replace(cssPolyfillRuleCommentRe, function(match, p1) {
+ // TODO(sorvell): remove either content or comment
+ cssText = cssText.replace(cssCommentRuleRe, function(match, p1) {
// remove end comment delimiter
return p1.slice(0, -1);
});
- },
- /*
- * Process styles to add rules which will only apply under the polyfill
- * and do not process via CSSOM. (CSSOM is destructive to rules on rare
- * occasions, e.g. -webkit-calc on Safari.)
- * For example, we convert this rule:
- *
- * (comment start) @polyfill-unscoped-rule menu-item {
- * ... } (comment end)
- *
- * to this:
- *
- * menu-item {...}
- *
- **/
- extractPolyfillUnscopedRules: function(styles) {
- var cssText = '';
- if (styles) {
- Array.prototype.forEach.call(styles, function(s) {
- cssText += this.extractPolyfillUnscopedRulesFromCssText(
- s.textContent) + '\n\n';
- }, this);
- }
- return cssText;
- },
- extractPolyfillUnscopedRulesFromCssText: function(cssText) {
- var r = '', matches;
- while (matches = cssPolyfillUnscopedRuleCommentRe.exec(cssText)) {
- r += matches[1].slice(0, -1) + '\n\n';
- }
- return r;
+ return cssText.replace(cssContentRuleRe, function(match, p1, p2, p3) {
+ var rule = match.replace(p1, '').replace(p2, '');
+ return p3 + rule;
+ });
},
/* Ensure styles are scoped. Pseudo-scoping takes a rule like:
*
@@ -7405,26 +7472,46 @@ var ShadowCSS = {
*
* scopeName .foo { ... }
*/
- shimScoping: function(styles, name, typeExtension) {
- if (styles) {
- return this.convertScopedStyles(styles, name, typeExtension);
- }
- },
- convertScopedStyles: function(styles, name, typeExtension) {
- var cssText = stylesToCssText(styles);
+ scopeCssText: function(cssText, scopeSelector) {
+ var unscoped = this.extractUnscopedRulesFromCssText(cssText);
cssText = this.insertPolyfillHostInCssText(cssText);
cssText = this.convertColonHost(cssText);
cssText = this.convertColonAncestor(cssText);
cssText = this.convertCombinators(cssText);
- if (name) {
+ if (scopeSelector) {
var self = this, cssText;
-
withCssRules(cssText, function(rules) {
- cssText = self.scopeRules(rules, name, typeExtension);
+ cssText = self.scopeRules(rules, scopeSelector);
});
}
- return cssText;
+ cssText = cssText + '\n' + unscoped;
+ return cssText.trim();
+ },
+ /*
+ * Process styles to add rules which will only apply under the polyfill
+ * and do not process via CSSOM. (CSSOM is destructive to rules on rare
+ * occasions, e.g. -webkit-calc on Safari.)
+ * For example, we convert this rule:
+ *
+ * (comment start) @polyfill-unscoped-rule menu-item {
+ * ... } (comment end)
+ *
+ * to this:
+ *
+ * menu-item {...}
+ *
+ **/
+ extractUnscopedRulesFromCssText: function(cssText) {
+ // TODO(sorvell): remove either content or comment
+ var r = '', m;
+ while (m = cssCommentUnscopedRuleRe.exec(cssText)) {
+ r += m[1].slice(0, -1) + '\n\n';
+ }
+ while (m = cssContentUnscopedRuleRe.exec(cssText)) {
+ r += m[0].replace(m[2], '').replace(m[1], m[3]) + '\n\n';
+ }
+ return r;
},
/*
* convert a rule like :host(.foo) > .bar { }
@@ -7489,17 +7576,17 @@ var ShadowCSS = {
return cssText.replace(/\^\^/g, ' ').replace(/\^/g, ' ');
},
// change a selector like 'div' to 'name div'
- scopeRules: function(cssRules, name, typeExtension) {
+ scopeRules: function(cssRules, scopeSelector) {
var cssText = '';
if (cssRules) {
Array.prototype.forEach.call(cssRules, function(rule) {
if (rule.selectorText && (rule.style && rule.style.cssText)) {
- cssText += this.scopeSelector(rule.selectorText, name, typeExtension,
+ cssText += this.scopeSelector(rule.selectorText, scopeSelector,
this.strictStyling) + ' {\n\t';
cssText += this.propertiesFromRule(rule) + '\n}\n\n';
} else if (rule.type === CSSRule.MEDIA_RULE) {
cssText += '@media ' + rule.media.mediaText + ' {\n';
- cssText += this.scopeRules(rule.cssRules, name, typeExtension);
+ cssText += this.scopeRules(rule.cssRules, scopeSelector);
cssText += '\n}\n\n';
} else if (rule.cssText) {
cssText += rule.cssText + '\n\n';
@@ -7508,43 +7595,43 @@ var ShadowCSS = {
}
return cssText;
},
- scopeSelector: function(selector, name, typeExtension, strict) {
+ scopeSelector: function(selector, scopeSelector, strict) {
var r = [], parts = selector.split(',');
parts.forEach(function(p) {
p = p.trim();
- if (this.selectorNeedsScoping(p, name, typeExtension)) {
+ if (this.selectorNeedsScoping(p, scopeSelector)) {
p = (strict && !p.match(polyfillHostNoCombinator)) ?
- this.applyStrictSelectorScope(p, name) :
- this.applySimpleSelectorScope(p, name, typeExtension);
+ this.applyStrictSelectorScope(p, scopeSelector) :
+ this.applySimpleSelectorScope(p, scopeSelector);
}
r.push(p);
}, this);
return r.join(', ');
},
- selectorNeedsScoping: function(selector, name, typeExtension) {
- var re = this.makeScopeMatcher(name, typeExtension);
+ selectorNeedsScoping: function(selector, scopeSelector) {
+ var re = this.makeScopeMatcher(scopeSelector);
return !selector.match(re);
},
- makeScopeMatcher: function(name, typeExtension) {
- var matchScope = typeExtension ? '\\[is=[\'"]?' + name + '[\'"]?\\]' : name;
- return new RegExp('^(' + matchScope + ')' + selectorReSuffix, 'm');
+ makeScopeMatcher: function(scopeSelector) {
+ scopeSelector = scopeSelector.replace(/\[/g, '\\[').replace(/\[/g, '\\]');
+ return new RegExp('^(' + scopeSelector + ')' + selectorReSuffix, 'm');
},
// scope via name and [is=name]
- applySimpleSelectorScope: function(selector, name, typeExtension) {
- var scoper = typeExtension ? '[is=' + name + ']' : name;
+ applySimpleSelectorScope: function(selector, scopeSelector) {
if (selector.match(polyfillHostRe)) {
- selector = selector.replace(polyfillHostNoCombinator, scoper);
- return selector.replace(polyfillHostRe, scoper + ' ');
+ selector = selector.replace(polyfillHostNoCombinator, scopeSelector);
+ return selector.replace(polyfillHostRe, scopeSelector + ' ');
} else {
- return scoper + ' ' + selector;
+ return scopeSelector + ' ' + selector;
}
},
// return a selector with [name] suffix on each simple selector
// e.g. .foo.bar > .zot becomes .foo[name].bar[name] > .zot[name]
- applyStrictSelectorScope: function(selector, name) {
+ applyStrictSelectorScope: function(selector, scopeSelector) {
+ scopeSelector = scopeSelector.replace(/\[is=([^\]]*)\]/g, '$1');
var splits = [' ', '>', '+', '~'],
scoped = selector,
- attrName = '[' + name + ']';
+ attrName = '[' + scopeSelector + ']';
splits.forEach(function(sep) {
var parts = scoped.split(sep);
scoped = parts.map(function(p) {
@@ -7570,14 +7657,37 @@ var ShadowCSS = {
rule.style.content + '\';');
}
return rule.style.cssText;
+ },
+ replaceTextInStyles: function(styles, action) {
+ if (styles && action) {
+ if (!(styles instanceof Array)) {
+ styles = [styles];
+ }
+ Array.prototype.forEach.call(styles, function(s) {
+ s.textContent = action.call(this, s.textContent);
+ }, this);
+ }
+ },
+ addCssToDocument: function(cssText, name) {
+ if (cssText.match('@import')) {
+ addOwnSheet(cssText, name);
+ } else {
+ addCssToDocument(cssText);
+ }
}
};
var selectorRe = /([^{]*)({[\s\S]*?})/gim,
cssCommentRe = /\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim,
- cssPolyfillCommentRe = /\/\*\s*@polyfill ([^*]*\*+([^/*][^*]*\*+)*\/)([^{]*?){/gim,
- cssPolyfillRuleCommentRe = /\/\*\s@polyfill-rule([^*]*\*+([^/*][^*]*\*+)*)\//gim,
- cssPolyfillUnscopedRuleCommentRe = /\/\*\s@polyfill-unscoped-rule([^*]*\*+([^/*][^*]*\*+)*)\//gim,
+ // TODO(sorvell): remove either content or comment
+ cssCommentNextSelectorRe = /\/\*\s*@polyfill ([^*]*\*+([^/*][^*]*\*+)*\/)([^{]*?){/gim,
+ cssContentNextSelectorRe = /polyfill-next-selector[^}]*content\:[\s]*'([^']*)'[^}]*}([^{]*?){/gim,
+ // TODO(sorvell): remove either content or comment
+ cssCommentRuleRe = /\/\*\s@polyfill-rule([^*]*\*+([^/*][^*]*\*+)*)\//gim,
+ cssContentRuleRe = /(polyfill-rule)[^}]*(content\:[\s]*'([^']*)'[^;]*;)[^}]*}/gim,
+ // TODO(sorvell): remove either content or comment
+ cssCommentUnscopedRuleRe = /\/\*\s@polyfill-unscoped-rule([^*]*\*+([^/*][^*]*\*+)*)\//gim,
+ cssContentUnscopedRuleRe = /(polyfill-unscoped-rule)[^}]*(content\:[\s]*'([^']*)'[^;]*;)[^}]*}/gim,
cssPseudoRe = /::(x-[^\s{,(]*)/gim,
cssPartRe = /::part\(([^)]*)\)/gim,
// note: :host pre-processed to -shadowcsshost.
@@ -7595,7 +7705,7 @@ var selectorRe = /([^{]*)({[\s\S]*?})/gim,
colonAncestorRe = /\:ancestor/gim,
/* host name without combinator */
polyfillHostNoCombinator = polyfillHost + '-no-combinator',
- polyfillHostRe = new RegExp(polyfillHost, 'gim');
+ polyfillHostRe = new RegExp(polyfillHost, 'gim'),
polyfillAncestorRe = new RegExp(polyfillAncestor, 'gim');
function stylesToCssText(styles, preserveComments) {
@@ -7700,6 +7810,7 @@ function addOwnSheet(cssText, name) {
var SHIM_ATTRIBUTE = 'shim-shadowdom';
var SHIMMED_ATTRIBUTE = 'shim-shadowdom-css';
+var NO_SHIM_ATTRIBUTE = 'no-shim';
var sheet;
function getSheet() {
@@ -7754,8 +7865,7 @@ if (window.ShadowDOMPolyfill) {
} else {
urlResolver.resolveStyle(style);
}
- var styles = [style];
- style.textContent = ShadowCSS.stylesToShimmedCssText(styles, styles);
+ style.textContent = ShadowCSS.shimStyle(style);
style.removeAttribute(SHIM_ATTRIBUTE, '');
style.setAttribute(SHIMMED_ATTRIBUTE, '');
style[SHIMMED_ATTRIBUTE] = true;
@@ -11712,6 +11822,7 @@ scope.styleResolver = styleResolver;
var ev = new MouseEvent('click', {buttons: 1});
NEW_MOUSE_EVENT = true;
HAS_BUTTONS = ev.buttons === 1;
+ ev = null;
} catch(e) {
}
@@ -11772,10 +11883,9 @@ scope.styleResolver = styleResolver;
// is to call initMouseEvent with a buttonArg value of -1.
//
// This is fixed with DOM Level 4's use of buttons
- var buttons;
- if (inDict.buttons || HAS_BUTTONS) {
- buttons = inDict.buttons;
- } else {
+ var buttons = inDict.buttons;
+ // touch has two possible buttons state: 0 and 1, rely on being told the right one
+ if (!HAS_BUTTONS && !buttons && inType !== 'touch') {
switch (inDict.which) {
case 1: buttons = 1; break;
case 2: buttons = 4; break;
@@ -12320,7 +12430,11 @@ scope.styleResolver = styleResolver;
},
// register all touch-action = none nodes on document load
installOnLoad: function() {
- document.addEventListener('DOMContentLoaded', this.installNewSubtree.bind(this, document));
+ document.addEventListener('readystatechange', function() {
+ if (document.readyState === 'complete') {
+ this.installNewSubtree(document);
+ }
+ }.bind(this));
},
isElement: function(n) {
return n.nodeType === Node.ELEMENT_NODE;
@@ -12605,6 +12719,13 @@ scope.styleResolver = styleResolver;
clearTimeout(this.resetId);
}
},
+ typeToButtons: function(type) {
+ var ret = 0;
+ if (type === 'touchstart' || type === 'touchmove') {
+ ret = 1;
+ }
+ return ret;
+ },
touchToPointer: function(inTouch) {
var e = dispatcher.cloneEvent(inTouch);
// Spec specifies that pointerId 1 is reserved for Mouse.
@@ -12616,7 +12737,7 @@ scope.styleResolver = styleResolver;
e.cancelable = true;
e.detail = this.clickCount;
e.button = 0;
- e.buttons = 1;
+ e.buttons = this.typeToButtons(this.currentTouchEvent);
e.width = inTouch.webkitRadiusX || inTouch.radiusX || 0;
e.height = inTouch.webkitRadiusY || inTouch.radiusY || 0;
e.pressure = inTouch.webkitForce || inTouch.force || 0.5;
@@ -12626,6 +12747,7 @@ scope.styleResolver = styleResolver;
},
processTouches: function(inEvent, inFunction) {
var tl = inEvent.changedTouches;
+ this.currentTouchEvent = inEvent.type;
var pointers = touchMap(tl, this.touchToPointer, this);
// forward touch preventDefaults
pointers.forEach(function(p) {
@@ -13360,9 +13482,11 @@ PointerGestureEvent.prototype.preventTap = function() {
}
};
dispatcher.boundHandler = dispatcher.eventHandler.bind(dispatcher);
+ // recognizers call into the dispatcher and load later
+ // solve the chicken and egg problem by having registerScopes module run last
+ dispatcher.registerQueue = [];
+ dispatcher.immediateRegister = false;
scope.dispatcher = dispatcher;
- var registerQueue = [];
- var immediateRegister = false;
/**
* Enable gesture events for a given scope, typically
* [ShadowRoots](https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#shadow-root-object).
@@ -13373,22 +13497,17 @@ PointerGestureEvent.prototype.preventTap = function() {
* support on.
*/
scope.register = function(inScope) {
- if (immediateRegister) {
+ if (dispatcher.immediateRegister) {
var pe = window.PointerEventsPolyfill;
if (pe) {
pe.register(inScope);
}
scope.dispatcher.registerTarget(inScope);
} else {
- registerQueue.push(inScope);
+ dispatcher.registerQueue.push(inScope);
}
};
- // wait to register scopes until recognizers load
- document.addEventListener('DOMContentLoaded', function() {
- immediateRegister = true;
- registerQueue.push(document);
- registerQueue.forEach(scope.register);
- });
+ scope.register(document);
})(window.PointerGestures);
/*
@@ -14052,6 +14171,7 @@ PointerGestureEvent.prototype.preventTap = function() {
if (inEvent.isPrimary && !inEvent.tapPrevented) {
pointermap.set(inEvent.pointerId, {
target: inEvent.target,
+ buttons: inEvent.buttons,
x: inEvent.clientX,
y: inEvent.clientY
});
@@ -14067,15 +14187,19 @@ PointerGestureEvent.prototype.preventTap = function() {
}
}
},
- shouldTap: function(e) {
+ shouldTap: function(e, downState) {
if (!e.tapPrevented) {
- // only allow left click to tap for mouse
- return e.pointerType === 'mouse' ? e.buttons === 1 : true;
+ if (e.pointerType === 'mouse') {
+ // only allow left click to tap for mouse
+ return downState.buttons === 1;
+ } else {
+ return true;
+ }
}
},
pointerup: function(inEvent) {
var start = pointermap.get(inEvent.pointerId);
- if (start && this.shouldTap(inEvent)) {
+ if (start && this.shouldTap(inEvent, start)) {
var t = scope.findLCA(start.target, inEvent.target);
if (t) {
var e = dispatcher.makeEvent('tap', {
@@ -14114,6 +14238,37 @@ PointerGestureEvent.prototype.preventTap = function() {
dispatcher.registerRecognizer('tap', tap);
})(window.PointerGestures);
+/*
+ * Copyright 2014 The Polymer Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file.
+ */
+
+/**
+ * Because recognizers are loaded after dispatcher, we have to wait to register
+ * scopes until after all the recognizers.
+ */
+(function(scope) {
+ var dispatcher = scope.dispatcher;
+ function registerScopes() {
+ dispatcher.immediateRegister = true;
+ var rq = dispatcher.registerQueue;
+ rq.forEach(scope.register);
+ rq.length = 0;
+ }
+ if (document.readyState === 'complete') {
+ registerScopes();
+ } else {
+ // register scopes after a steadystate is reached
+ // less MutationObserver churn
+ document.addEventListener('readystatechange', function() {
+ if (document.readyState === 'complete') {
+ registerScopes();
+ }
+ });
+ }
+})(window.PointerGestures);
+
// Copyright 2011 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -14141,33 +14296,6 @@ PointerGestureEvent.prototype.preventTap = function() {
return typeof node.getElementById === 'function' ? node : null;
}
- // JScript does not have __proto__. We wrap all object literals with
- // createObject which uses Object.create, Object.defineProperty and
- // Object.getOwnPropertyDescriptor to create a new object that does the exact
- // same thing. The main downside to this solution is that we have to extract
- // all those property descriptors for IE.
- var createObject = ('__proto__' in {}) ?
- function(obj) { return obj; } :
- function(obj) {
- var proto = obj.__proto__;
- if (!proto)
- return obj;
- var newObject = Object.create(proto);
- Object.getOwnPropertyNames(obj).forEach(function(name) {
- Object.defineProperty(newObject, name,
- Object.getOwnPropertyDescriptor(obj, name));
- });
- return newObject;
- };
-
- // IE does not support have Document.prototype.contains.
- if (typeof document.contains != 'function') {
- Document.prototype.contains = function(node) {
- if (node === this || node.parentNode === this)
- return true;
- return this.documentElement.contains(node);
- }
- }
Node.prototype.bind = function(name, observable) {
console.error('Unhandled binding to Node: ', this, name, observable);
« no previous file with comments | « pkg/web_components/lib/platform.js ('k') | pkg/web_components/lib/platform.concat.js.map » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698