mirror of
https://github.com/Polymer/polymer.git
synced 2025-02-25 18:55:30 -06:00
Merge branch 'master' into shady-linked
This commit is contained in:
commit
34031414e5
@ -11,11 +11,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
|
||||
/*
|
||||
Extremely simple css parser. Intended to be not more than what we need
|
||||
and definitely not necessarly correct =).
|
||||
and definitely not necessarily correct =).
|
||||
*/
|
||||
Polymer.CssParse = (function() {
|
||||
|
||||
var api = {
|
||||
return {
|
||||
// given a string of css, return a simple rule tree
|
||||
parse: function(text) {
|
||||
text = this._clean(text);
|
||||
@ -31,7 +31,7 @@ Polymer.CssParse = (function() {
|
||||
_lex: function(text) {
|
||||
var root = {start: 0, end: text.length};
|
||||
var n = root;
|
||||
for (var i=0, s=0, l=text.length; i < l; i++) {
|
||||
for (var i=0, l=text.length; i < l; i++) {
|
||||
switch (text[i]) {
|
||||
case this.OPEN_BRACE:
|
||||
//console.group(i);
|
||||
@ -123,7 +123,7 @@ Polymer.CssParse = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
// emit rule iff there is cssText
|
||||
// emit rule if there is cssText
|
||||
if (cssText) {
|
||||
if (node.selector) {
|
||||
text += node.selector + ' ' + this.OPEN_BRACE + '\n';
|
||||
@ -185,10 +185,6 @@ Polymer.CssParse = (function() {
|
||||
|
||||
};
|
||||
|
||||
|
||||
// exports
|
||||
return api;
|
||||
|
||||
})();
|
||||
|
||||
</script>
|
||||
|
@ -1,200 +1,200 @@
|
||||
<!--
|
||||
@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
|
||||
-->
|
||||
<link rel="import" href="style-util.html">
|
||||
<link rel="import" href="style-transformer.html">
|
||||
<link rel="import" href="style-defaults.html">
|
||||
|
||||
<!--
|
||||
|
||||
The `custom-style` extension of the native `<style>` element allows defining styles
|
||||
in the main document that can take advantage of several special features of
|
||||
Polymer's styling system:
|
||||
|
||||
* Document styles defined in a `custom-style` will be shimmed to ensure they do
|
||||
not leak into local DOM when running on browsers without non-native Shadow DOM.
|
||||
* Shadow DOM-specific `/deep/` and `::shadow` combinators will be shimmed on
|
||||
browsers without non-native Shadow DOM.
|
||||
* Custom properties used by Polymer's shim for cross-scope styling
|
||||
may be defined in an `custom-style`.
|
||||
* An `include` attribute may be specified to pull in style data from a
|
||||
`dom-module` matching the include attribute. By using `include`, style data
|
||||
can be shared between multiple `custom-style` elements.
|
||||
|
||||
Example:
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<script src="components/webcomponentsjs/webcomponents-lite.js"></script>
|
||||
<link rel="import" href="components/polymer/polymer.html">
|
||||
|
||||
<style is="custom-style">
|
||||
|
||||
/* Will be prevented from affecting local DOM of Polymer elements */
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Can use /deep/ and ::shadow combinators */
|
||||
body /deep/ .my-special-view::shadow #thing-inside {
|
||||
background: yellow;
|
||||
}
|
||||
|
||||
/* Custom properties that inherit down the document tree may be defined */
|
||||
body {
|
||||
--my-toolbar-title-color: green;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
...
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
Note, all features of `custom-style` are available when defining styles as part of Polymer elements (e.g. `<style>` elements within `<dom-module>`'s used for defining Polymer elements. The `custom-style` extension should only be used for defining document styles, outside of a custom element's local DOM.
|
||||
|
||||
-->
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
|
||||
var nativeShadow = Polymer.Settings.useNativeShadow;
|
||||
var propertyUtils = Polymer.StyleProperties;
|
||||
var styleUtil = Polymer.StyleUtil;
|
||||
var cssParse = Polymer.CssParse;
|
||||
var styleDefaults = Polymer.StyleDefaults;
|
||||
var styleTransformer = Polymer.StyleTransformer;
|
||||
|
||||
Polymer({
|
||||
|
||||
is: 'custom-style',
|
||||
extends: 'style',
|
||||
_template: null,
|
||||
|
||||
properties: {
|
||||
// include is a property so that it deserializes
|
||||
/**
|
||||
* Specify `include` to identify a `dom-module` containing style data which
|
||||
* should be used within the `custom-style`. By using `include` style data
|
||||
* may be shared between multiple different `custom-style` elements.
|
||||
*/
|
||||
include: String
|
||||
},
|
||||
|
||||
ready: function() {
|
||||
// NOTE: we cannot just check attached because custom elements in
|
||||
// HTMLImports do not get attached.
|
||||
this._tryApply();
|
||||
},
|
||||
|
||||
attached: function() {
|
||||
this._tryApply();
|
||||
},
|
||||
|
||||
_tryApply: function() {
|
||||
if (!this._appliesToDocument) {
|
||||
// only apply variables iff this style is not inside a dom-module
|
||||
if (this.parentNode &&
|
||||
(this.parentNode.localName !== 'dom-module')) {
|
||||
this._appliesToDocument = true;
|
||||
// used applied element from HTMLImports polyfill or this
|
||||
var e = this.__appliedElement || this;
|
||||
styleDefaults.addStyle(e);
|
||||
// we may not have any textContent yet due to parser yielding
|
||||
// if so, wait until we do...
|
||||
if (e.textContent || this.include) {
|
||||
this._apply(true);
|
||||
} else {
|
||||
var self = this;
|
||||
var observer = new MutationObserver(function() {
|
||||
observer.disconnect();
|
||||
self._apply(true);
|
||||
});
|
||||
observer.observe(e, {childList: true});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// polyfill this style with root scoping and
|
||||
// apply custom properties!
|
||||
_apply: function(deferProperties) {
|
||||
// used applied element from HTMLImports polyfill or this
|
||||
var e = this.__appliedElement || this;
|
||||
if (this.include) {
|
||||
e.textContent = styleUtil.cssFromModules(this.include, true) +
|
||||
e.textContent;
|
||||
}
|
||||
if (e.textContent) {
|
||||
styleUtil.forEachStyleRule(styleUtil.rulesForStyle(e), function(rule) {
|
||||
styleTransformer.documentRule(rule);
|
||||
});
|
||||
// Allow all custom-styles defined in this turn to register
|
||||
// before applying any properties. This helps ensure that all properties
|
||||
// are defined before any are consumed.
|
||||
// Premature application of properties can occur in 2 cases:
|
||||
// (1) A property `--foo` is consumed in a custom-style
|
||||
// before another custom-style produces `--foo`.
|
||||
// In general, we require custom properties to be defined before being
|
||||
// used in elements so supporting this for custom-style
|
||||
// is dubious but is slightly more like native properties where this
|
||||
// is supported.
|
||||
// (2) A set of in order styles (A, B) are re-ordered due to a parser
|
||||
// yield that makes A wait for textContent. This reorders its
|
||||
// `_apply` after B.
|
||||
// This case should only occur with native webcomponents.
|
||||
var self = this;
|
||||
function fn() {
|
||||
self._applyCustomProperties(e);
|
||||
}
|
||||
if (this._pendingApplyProperties) {
|
||||
cancelAnimationFrame(this._pendingApplyProperties);
|
||||
this._pendingApplyProperties = null;
|
||||
}
|
||||
if (deferProperties) {
|
||||
this._pendingApplyProperties = requestAnimationFrame(fn);
|
||||
} else {
|
||||
fn();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_applyCustomProperties: function(element) {
|
||||
this._computeStyleProperties();
|
||||
var props = this._styleProperties;
|
||||
var rules = styleUtil.rulesForStyle(element);
|
||||
element.textContent = styleUtil.toCssText(rules, function(rule) {
|
||||
var css = rule.cssText = rule.parsedCssText;
|
||||
if (rule.propertyInfo && rule.propertyInfo.cssText) {
|
||||
// remove property assignments
|
||||
// so next function isn't confused
|
||||
// NOTE: we have 3 categories of css:
|
||||
// (1) normal properties,
|
||||
// (2) custom property assignments (--foo: red;),
|
||||
// (3) custom property usage: border: var(--foo); @apply(--foo);
|
||||
// In elements, 1 and 3 are separated for efficiency; here they
|
||||
// are not and this makes this case unique.
|
||||
css = cssParse.removeCustomPropAssignment(css);
|
||||
// replace with reified properties, scenario is same as mixin
|
||||
rule.cssText = propertyUtils.valueForProperties(css, props);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
})();
|
||||
</script>
|
||||
<!--
|
||||
@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
|
||||
-->
|
||||
<link rel="import" href="style-util.html">
|
||||
<link rel="import" href="style-transformer.html">
|
||||
<link rel="import" href="style-defaults.html">
|
||||
|
||||
<!--
|
||||
|
||||
The `custom-style` extension of the native `<style>` element allows defining styles
|
||||
in the main document that can take advantage of several special features of
|
||||
Polymer's styling system:
|
||||
|
||||
* Document styles defined in a `custom-style` will be shimmed to ensure they do
|
||||
not leak into local DOM when running on browsers without non-native Shadow DOM.
|
||||
* Shadow DOM-specific `/deep/` and `::shadow` combinators will be shimmed on
|
||||
browsers without non-native Shadow DOM.
|
||||
* Custom properties used by Polymer's shim for cross-scope styling
|
||||
may be defined in an `custom-style`.
|
||||
* An `include` attribute may be specified to pull in style data from a
|
||||
`dom-module` matching the include attribute. By using `include`, style data
|
||||
can be shared between multiple `custom-style` elements.
|
||||
|
||||
Example:
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<script src="components/webcomponentsjs/webcomponents-lite.js"></script>
|
||||
<link rel="import" href="components/polymer/polymer.html">
|
||||
|
||||
<style is="custom-style">
|
||||
|
||||
/* Will be prevented from affecting local DOM of Polymer elements */
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Can use /deep/ and ::shadow combinators */
|
||||
body /deep/ .my-special-view::shadow #thing-inside {
|
||||
background: yellow;
|
||||
}
|
||||
|
||||
/* Custom properties that inherit down the document tree may be defined */
|
||||
body {
|
||||
--my-toolbar-title-color: green;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
...
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
Note, all features of `custom-style` are available when defining styles as part of Polymer elements (e.g. `<style>` elements within `<dom-module>`'s used for defining Polymer elements. The `custom-style` extension should only be used for defining document styles, outside of a custom element's local DOM.
|
||||
|
||||
-->
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
|
||||
var nativeShadow = Polymer.Settings.useNativeShadow;
|
||||
var propertyUtils = Polymer.StyleProperties;
|
||||
var styleUtil = Polymer.StyleUtil;
|
||||
var cssParse = Polymer.CssParse;
|
||||
var styleDefaults = Polymer.StyleDefaults;
|
||||
var styleTransformer = Polymer.StyleTransformer;
|
||||
|
||||
Polymer({
|
||||
|
||||
is: 'custom-style',
|
||||
extends: 'style',
|
||||
_template: null,
|
||||
|
||||
properties: {
|
||||
// include is a property so that it deserializes
|
||||
/**
|
||||
* Specify `include` to identify a `dom-module` containing style data which
|
||||
* should be used within the `custom-style`. By using `include` style data
|
||||
* may be shared between multiple different `custom-style` elements.
|
||||
*/
|
||||
include: String
|
||||
},
|
||||
|
||||
ready: function() {
|
||||
// NOTE: we cannot just check attached because custom elements in
|
||||
// HTMLImports do not get attached.
|
||||
this._tryApply();
|
||||
},
|
||||
|
||||
attached: function() {
|
||||
this._tryApply();
|
||||
},
|
||||
|
||||
_tryApply: function() {
|
||||
if (!this._appliesToDocument) {
|
||||
// only apply variables iff this style is not inside a dom-module
|
||||
if (this.parentNode &&
|
||||
(this.parentNode.localName !== 'dom-module')) {
|
||||
this._appliesToDocument = true;
|
||||
// used applied element from HTMLImports polyfill or this
|
||||
var e = this.__appliedElement || this;
|
||||
styleDefaults.addStyle(e);
|
||||
// we may not have any textContent yet due to parser yielding
|
||||
// if so, wait until we do...
|
||||
if (e.textContent || this.include) {
|
||||
this._apply(true);
|
||||
} else {
|
||||
var self = this;
|
||||
var observer = new MutationObserver(function() {
|
||||
observer.disconnect();
|
||||
self._apply(true);
|
||||
});
|
||||
observer.observe(e, {childList: true});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// polyfill this style with root scoping and
|
||||
// apply custom properties!
|
||||
_apply: function(deferProperties) {
|
||||
// used applied element from HTMLImports polyfill or this
|
||||
var e = this.__appliedElement || this;
|
||||
if (this.include) {
|
||||
e.textContent = styleUtil.cssFromModules(this.include, true) +
|
||||
e.textContent;
|
||||
}
|
||||
if (e.textContent) {
|
||||
styleUtil.forEachStyleRule(styleUtil.rulesForStyle(e), function(rule) {
|
||||
styleTransformer.documentRule(rule);
|
||||
});
|
||||
// Allow all custom-styles defined in this turn to register
|
||||
// before applying any properties. This helps ensure that all properties
|
||||
// are defined before any are consumed.
|
||||
// Premature application of properties can occur in 2 cases:
|
||||
// (1) A property `--foo` is consumed in a custom-style
|
||||
// before another custom-style produces `--foo`.
|
||||
// In general, we require custom properties to be defined before being
|
||||
// used in elements so supporting this for custom-style
|
||||
// is dubious but is slightly more like native properties where this
|
||||
// is supported.
|
||||
// (2) A set of in order styles (A, B) are re-ordered due to a parser
|
||||
// yield that makes A wait for textContent. This reorders its
|
||||
// `_apply` after B.
|
||||
// This case should only occur with native webcomponents.
|
||||
var self = this;
|
||||
var fn = function fn() {
|
||||
self._applyCustomProperties(e);
|
||||
}
|
||||
if (this._pendingApplyProperties) {
|
||||
cancelAnimationFrame(this._pendingApplyProperties);
|
||||
this._pendingApplyProperties = null;
|
||||
}
|
||||
if (deferProperties) {
|
||||
this._pendingApplyProperties = requestAnimationFrame(fn);
|
||||
} else {
|
||||
fn();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_applyCustomProperties: function(element) {
|
||||
this._computeStyleProperties();
|
||||
var props = this._styleProperties;
|
||||
var rules = styleUtil.rulesForStyle(element);
|
||||
element.textContent = styleUtil.toCssText(rules, function(rule) {
|
||||
var css = rule.cssText = rule.parsedCssText;
|
||||
if (rule.propertyInfo && rule.propertyInfo.cssText) {
|
||||
// remove property assignments
|
||||
// so next function isn't confused
|
||||
// NOTE: we have 3 categories of css:
|
||||
// (1) normal properties,
|
||||
// (2) custom property assignments (--foo: red;),
|
||||
// (3) custom property usage: border: var(--foo); @apply(--foo);
|
||||
// In elements, 1 and 3 are separated for efficiency; here they
|
||||
// are not and this makes this case unique.
|
||||
css = cssParse.removeCustomPropAssignment(css);
|
||||
// replace with reified properties, scenario is same as mixin
|
||||
rule.cssText = propertyUtils.valueForProperties(css, props);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
})();
|
||||
</script>
|
||||
|
@ -87,9 +87,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
var parts = cssText.split(';');
|
||||
for (var i=0, p; i<parts.length; i++) {
|
||||
p = parts[i];
|
||||
if (p.match(this.rx.MIXIN_MATCH) || p.match(this.rx.VAR_MATCH)) {
|
||||
customCssText += p + ';\n';
|
||||
}
|
||||
customCssText += p + ';\n';
|
||||
}
|
||||
return customCssText;
|
||||
},
|
||||
@ -166,7 +164,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
p || '';
|
||||
}
|
||||
}
|
||||
return parts.filter(function(v) {return v;}).join(';');
|
||||
return parts.join(';');
|
||||
},
|
||||
|
||||
applyProperties: function(rule, props) {
|
||||
@ -181,7 +179,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
rule.cssText = output;
|
||||
},
|
||||
|
||||
// Test if the rules in these styles matche the given `element` and if so,
|
||||
// Test if the rules in these styles matches the given `element` and if so,
|
||||
// collect any custom properties into `props`.
|
||||
propertyDataFromStyles: function(styles, element) {
|
||||
var props = {}, self = this;
|
||||
@ -208,7 +206,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
return {properties: props, key: o};
|
||||
},
|
||||
|
||||
// Test if a rule matches scope crteria (* or :root) and if so,
|
||||
// Test if a rule matches scope criteria (* or :root) and if so,
|
||||
// collect any custom properties into `props`.
|
||||
scopePropertiesFromStyles: function(styles) {
|
||||
if (!styles._scopeStyleProperties) {
|
||||
@ -218,7 +216,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
return styles._scopeStyleProperties;
|
||||
},
|
||||
|
||||
// Test if a rule matches host crteria (:host) and if so,
|
||||
// Test if a rule matches host criteria (:host) and if so,
|
||||
// collect any custom properties into `props`.
|
||||
//
|
||||
// TODO(sorvell): this should change to collecting properties from any
|
||||
@ -319,7 +317,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
// otherwise, if we have css to apply, do so
|
||||
} else if (cssText) {
|
||||
// apply css after the scope style of the element to help with
|
||||
// style predence rules.
|
||||
// style precedence rules.
|
||||
style = styleUtil.applyCss(cssText, selector,
|
||||
nativeShadow ? element.root : null, element._scopeStyle);
|
||||
}
|
||||
@ -356,7 +354,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
// var(--a)
|
||||
// var(--a, --b)
|
||||
// var(--a, fallback-literal)
|
||||
// var(--a, fallback-literal(with-one-nested-parens))
|
||||
// var(--a, fallback-literal(with-one-nested-parentheses))
|
||||
VAR_MATCH: /(^|\W+)var\([\s]*([^,)]*)[\s]*,?[\s]*((?:[^,)]*)|(?:[^;]*\([^;)]*\)))[\s]*?\)/gi,
|
||||
VAR_CAPTURE: /\([\s]*(--[^,\s)]*)(?:,[\s]*(--[^,\s)]*))?(?:\)|,)/gi,
|
||||
IS_VAR: /^--/,
|
||||
|
@ -34,7 +34,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
cannot otherwise be scoped:
|
||||
e.g. :host ::content > .bar -> x-foo > .bar
|
||||
|
||||
* ::shadow, /deep/: processed simimlar to ::content
|
||||
* ::shadow, /deep/: processed similar to ::content
|
||||
|
||||
* :host-context(...): scopeName..., ... scopeName
|
||||
|
||||
@ -97,7 +97,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
elementStyles: function(element, callback) {
|
||||
var styles = element._styles;
|
||||
var cssText = '';
|
||||
for (var i=0, l=styles.length, s, text; (i<l) && (s=styles[i]); i++) {
|
||||
for (var i=0, l=styles.length, s; (i<l) && (s=styles[i]); i++) {
|
||||
var rules = styleUtil.rulesForStyle(s);
|
||||
cssText += nativeShadow ?
|
||||
styleUtil.toCssText(rules, callback) :
|
||||
@ -152,7 +152,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
p$[i] = transformer.call(this, p, scope, hostScope);
|
||||
}
|
||||
// NOTE: save transformedSelector for subsequent matching of elements
|
||||
// agsinst selectors (e.g. when calculating style properties)
|
||||
// against selectors (e.g. when calculating style properties)
|
||||
rule.selector = rule.transformedSelector =
|
||||
p$.join(COMPLEX_SELECTOR_SEP);
|
||||
},
|
||||
@ -258,9 +258,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
// parsing which seems like overkill
|
||||
var HOST_PAREN = /(\:host)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/g;
|
||||
var HOST_CONTEXT = ':host-context';
|
||||
var HOST_CONTEXT_PAREN = /(.*)(?:\:host-context)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))(.*)/;
|
||||
var HOST_CONTEXT_PAREN = /(.*)(?::host-context)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))(.*)/;
|
||||
var CONTENT = '::content';
|
||||
var SCOPE_JUMP = /\:\:content|\:\:shadow|\/deep\//;
|
||||
var SCOPE_JUMP = /::content|::shadow|\/deep\//;
|
||||
var CSS_CLASS_PREFIX = '.';
|
||||
var CSS_ATTR_PREFIX = '[' + SCOPE_NAME + '~=';
|
||||
var CSS_ATTR_SUFFIX = ']';
|
||||
|
@ -44,15 +44,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
return style.__cssRules;
|
||||
},
|
||||
|
||||
clearStyleRules: function(style) {
|
||||
style.__cssRules = null;
|
||||
},
|
||||
|
||||
forEachStyleRule: function(node, callback) {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
var s = node.parsedSelector;
|
||||
var skipRules = false;
|
||||
if (node.type === this.ruleTypes.STYLE_RULE) {
|
||||
callback(node);
|
||||
|
@ -73,13 +73,14 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
},
|
||||
|
||||
detached: function() {
|
||||
// TODO(kschaaf): add logic to re-stamp in attached?
|
||||
this._teardownInstance();
|
||||
if (!this.parentNode) {
|
||||
this._teardownInstance();
|
||||
}
|
||||
},
|
||||
|
||||
attached: function() {
|
||||
if (this.if && this.ctor) {
|
||||
// TODO(sorvell): should not be async, but node can be attached
|
||||
// NOTE: ideally should not be async, but node can be attached
|
||||
// when shady dom is in the act of distributing/composing so push it out
|
||||
this.async(this._ensureInstance);
|
||||
}
|
||||
@ -116,16 +117,25 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
},
|
||||
|
||||
_ensureInstance: function() {
|
||||
if (!this._instance) {
|
||||
var parentNode = Polymer.dom(this).parentNode;
|
||||
// Guard against element being detached while render was queued
|
||||
if (parentNode) {
|
||||
var parent = Polymer.dom(parentNode);
|
||||
// TODO(sorvell): pickup stamping logic from x-repeat
|
||||
var parentNode = Polymer.dom(this).parentNode;
|
||||
// Guard against element being detached while render was queued
|
||||
if (parentNode) {
|
||||
var parent = Polymer.dom(parentNode);
|
||||
if (!this._instance) {
|
||||
this._instance = this.stamp();
|
||||
var root = this._instance.root;
|
||||
// TODO(sorvell): this incantation needs to be simpler.
|
||||
parent.insertBefore(root, this);
|
||||
} else {
|
||||
var c$ = this._instance._children;
|
||||
if (c$ && c$.length) {
|
||||
// Detect case where dom-if was re-attached in new position
|
||||
var lastChild = Polymer.dom(this).previousSibling;
|
||||
if (lastChild !== c$[c$.length-1]) {
|
||||
for (var i=0, n; (i<c$.length) && (n=c$[i]); i++) {
|
||||
parent.insertBefore(n, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -133,7 +143,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
_teardownInstance: function() {
|
||||
if (this._instance) {
|
||||
var c$ = this._instance._children;
|
||||
if (c$) {
|
||||
if (c$ && c$.length) {
|
||||
// use first child parent, for case when dom-if may have been detached
|
||||
var parent = Polymer.dom(Polymer.dom(c$[0]).parentNode);
|
||||
for (var i=0, n; (i<c$.length) && (n=c$[i]); i++) {
|
||||
|
@ -124,6 +124,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
archetype._scopeElementClass = this._scopeElementClassImpl;
|
||||
archetype.listen = this._listenImpl;
|
||||
archetype._showHideChildren = this._showHideChildrenImpl;
|
||||
archetype.__setPropertyOrig = this.__setProperty;
|
||||
archetype.__setProperty = this.__setPropertyImpl;
|
||||
// boilerplate code
|
||||
var _constructor = this._constructorImpl;
|
||||
var ctor = function TemplateInstance(model, host) {
|
||||
@ -168,6 +170,13 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
}
|
||||
},
|
||||
|
||||
__setPropertyImpl: function(property, value, fromAbove, node) {
|
||||
if (node && node.__hideTemplateChildren__ && property == 'textContent') {
|
||||
property = '__polymerTextContent__';
|
||||
}
|
||||
this.__setPropertyOrig(property, value, fromAbove, node);
|
||||
},
|
||||
|
||||
_debounceTemplate: function(fn) {
|
||||
Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', fn));
|
||||
},
|
||||
@ -242,7 +251,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
}, {
|
||||
kind: 'notify',
|
||||
fn: Polymer.Bind._notifyEffect,
|
||||
effect: {event:
|
||||
effect: {event:
|
||||
Polymer.CaseMap.camelToDashCase(parentProp) + '-changed'}
|
||||
}];
|
||||
Polymer.Bind._createAccessors(proto, parentProp, effects);
|
||||
@ -259,7 +268,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
}
|
||||
this._extendTemplate(template, proto);
|
||||
template._pathEffector = function(path, value, fromAbove) {
|
||||
return self._pathEffectorImpl(path, value, fromAbove);
|
||||
return self._pathEffectorImpl(path, value, fromAbove);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -130,8 +130,8 @@ TODO(sjmiles): this module should produce either syntactic metadata
|
||||
this._notes = this._template._content._notes;
|
||||
} else {
|
||||
this._notes = Polymer.Annotations.parseAnnotations(this._template);
|
||||
this._processAnnotations(this._notes);
|
||||
}
|
||||
this._processAnnotations(this._notes);
|
||||
Polymer.Annotations.prepElement = null;
|
||||
}
|
||||
},
|
||||
@ -188,10 +188,15 @@ TODO(sjmiles): this module should produce either syntactic metadata
|
||||
if (p.signature) {
|
||||
var args = p.signature.args;
|
||||
for (var kk=0; kk<args.length; kk++) {
|
||||
pp[args[kk].model] = true;
|
||||
var model = args[kk].model;
|
||||
if (model) {
|
||||
pp[model] = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pp[p.model] = true;
|
||||
if (p.model) {
|
||||
pp[p.model] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
// method expressions are of the form: `name([arg1, arg2, .... argn])`
|
||||
_parseMethod: function(expression) {
|
||||
// tries to match valid javascript property names
|
||||
var m = expression.match(/([^\s]+)\((.*)\)/);
|
||||
var m = expression.match(/([^\s]+?)\((.*)\)/);
|
||||
if (m) {
|
||||
var sig = { method: m[1], static: true };
|
||||
if (m[2].trim()) {
|
||||
@ -222,8 +222,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
;
|
||||
// basic argument descriptor
|
||||
var a = {
|
||||
name: arg,
|
||||
model: this._modelForPath(arg)
|
||||
name: arg
|
||||
};
|
||||
// detect literal value (must be String or Number)
|
||||
var fc = arg[0];
|
||||
@ -246,6 +245,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
}
|
||||
// if not literal, look for structured path
|
||||
if (!a.literal) {
|
||||
a.model = this._modelForPath(arg);
|
||||
// detect structured path (has dots)
|
||||
a.structured = arg.indexOf('.') > 0;
|
||||
if (a.structured) {
|
||||
|
@ -79,6 +79,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
style.textContent = cssText;
|
||||
// extends!!
|
||||
if (styleExtends.hasExtends(style.textContent)) {
|
||||
// TODO(sorvell): variable is not used, should it update `style.textContent`?
|
||||
cssText = styleExtends.transform(style);
|
||||
}
|
||||
styles.push(style);
|
||||
@ -109,7 +110,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
|
||||
/**
|
||||
* Apply style scoping to the specified `container` and all its
|
||||
* descendants. If `shoudlObserve` is true, changes to the container are
|
||||
* descendants. If `shouldObserve` is true, changes to the container are
|
||||
* monitored via mutation observer and scoping is applied.
|
||||
*
|
||||
* This method is useful for ensuring proper local DOM CSS scoping
|
||||
|
@ -139,7 +139,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
|
||||
behaviors: [
|
||||
Polymer.BehaviorA,
|
||||
null,
|
||||
Polymer.BehaviorB
|
||||
],
|
||||
|
||||
@ -260,4 +259,4 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
</script>
|
||||
|
@ -127,6 +127,27 @@ suite('multi-behaviors element', function() {
|
||||
assert.equal(el.attributes.user.value, 'user', 'Behavior hostAttribute overrode user attribute');
|
||||
});
|
||||
|
||||
test('behaviour is null generates warning', function() {
|
||||
var warned = false, oldWarn = Polymer.Base._warn;
|
||||
Polymer.Base._warn = function (message) {
|
||||
assert.match(message, /behavior is null/);
|
||||
warned = true;
|
||||
};
|
||||
|
||||
Polymer({
|
||||
|
||||
behaviors: [
|
||||
null
|
||||
],
|
||||
|
||||
is: 'behavior-null'
|
||||
|
||||
});
|
||||
|
||||
assert.equal(warned, true, 'Null behaviour should generate warning');
|
||||
Polymer.Base._warn = oldWarn;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
@ -43,6 +43,7 @@
|
||||
<span id="boundText">{{text}}</span>
|
||||
<span idtest id="{{boundId}}"></span>
|
||||
<s id="computedContent">{{computeFromTrickyLiterals(3, 'tricky\,\'zot\'')}}</s>
|
||||
<s id="computedContent2">{{computeFromTrickyLiterals("(",3)}}</s>
|
||||
<input id="boundInput" value="{{text::input}}">
|
||||
<div id="compound1">{{cpnd1}}{{cpnd2}}{{cpnd3.prop}}{{computeCompound(cpnd4, cpnd5, 'literal')}}</div>
|
||||
<div id="compound2">
|
||||
|
@ -174,6 +174,7 @@ suite('single-element binding effects', function() {
|
||||
assert.equal(el.$.boundChild.computedFromTrickyLiterals, '3tricky,\'zot\'', 'Wrong result from tricky literal arg computation');
|
||||
assert.equal(el.$.boundChild.computedFromTrickyLiterals2, '3tricky,\'zot\'', 'Wrong result from tricky literal arg computation');
|
||||
assert.equal(el.$.computedContent.textContent, '3tricky,\'zot\'', 'Wrong textContent from tricky literal arg computation');
|
||||
assert.equal(el.$.computedContent2.textContent, '(3', 'Wrong textContent from tricky literal arg computation');
|
||||
});
|
||||
|
||||
test('computed annotation with no args', function() {
|
||||
@ -675,7 +676,6 @@ suite('warnings', function() {
|
||||
var warned = false;
|
||||
el._warn = function() {
|
||||
warned = true;
|
||||
warn.apply(el, arguments);
|
||||
};
|
||||
el.noObserver = 42;
|
||||
assert.equal(warned, true, 'no warning for undefined observer');
|
||||
@ -685,7 +685,6 @@ suite('warnings', function() {
|
||||
var warned = false;
|
||||
el._warn = function() {
|
||||
warned = true;
|
||||
warn.apply(el, arguments);
|
||||
};
|
||||
el.noComplexObserver = {};
|
||||
assert.equal(warned, true, 'no warning for undefined complex observer');
|
||||
@ -695,7 +694,6 @@ suite('warnings', function() {
|
||||
var warned = false;
|
||||
el._warn = function() {
|
||||
warned = true;
|
||||
warn.apply(el, arguments);
|
||||
};
|
||||
el.noComputed = 99;
|
||||
assert.equal(warned, true, 'no warning for undefined computed function');
|
||||
@ -705,7 +703,6 @@ suite('warnings', function() {
|
||||
var warned = false;
|
||||
el._warn = function() {
|
||||
warned = true;
|
||||
warn.apply(el, arguments);
|
||||
};
|
||||
el.noInlineComputed = 99;
|
||||
assert.equal(warned, true, 'no warning for undefined computed function');
|
||||
|
@ -116,7 +116,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
assert.equal(tree.rules.length, 4, 'unexpected number of rules');
|
||||
assert.equal(tree.rules[2].rules.length, 8, 'unexpected number of rules in keyframes');
|
||||
assert.equal(tree.rules[3].rules.length, 1, 'unexpected number of rules in @media');
|
||||
console.log('test');
|
||||
});
|
||||
|
||||
test('rule selectors parse', function() {
|
||||
@ -166,7 +165,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
assert.equal(t.rules[3].selector, '.\\0c3333d-model');
|
||||
assert.equal(t.rules[4].selector, '.\\d33333d-model');
|
||||
assert.equal(t.rules[5].selector, '.\\e33333d-model');
|
||||
});
|
||||
});
|
||||
|
||||
test('multiple consequent spaces in CSS selector', function() {
|
||||
var s4 = document.querySelector('#multiple-spaces');
|
||||
var t = css.parse(s4.textContent);
|
||||
|
@ -1,5 +1,4 @@
|
||||
<script>
|
||||
console.log('x-needs-repeat loaded')
|
||||
Polymer({
|
||||
is: 'x-needs-host',
|
||||
ready: function() {
|
||||
@ -9,4 +8,4 @@ console.log('x-needs-repeat loaded')
|
||||
this.config = this.dataHost.getAttribute('config');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
@ -226,6 +226,5 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
</script>
|
||||
|
||||
<link rel="import" href="dom-bind-elements2.html">
|
||||
<link rel="import" href="should-404.html">
|
||||
</body>
|
||||
</html>
|
||||
|
@ -165,13 +165,42 @@
|
||||
<div>1</div>
|
||||
<div>2</div>
|
||||
<div>3</div>
|
||||
Stuff
|
||||
{{text}}
|
||||
<div>4</div>
|
||||
</template>
|
||||
</template>
|
||||
<script>
|
||||
Polymer({
|
||||
is: 'x-textcontent'
|
||||
is: 'x-textcontent',
|
||||
properties: {
|
||||
text: {
|
||||
value: 'Stuff'
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</dom-module>
|
||||
|
||||
<dom-module id="x-host">
|
||||
<template>
|
||||
<template id="domif" is="dom-if" if>
|
||||
<x-client></x-client>
|
||||
<x-client></x-client>
|
||||
<x-client></x-client>
|
||||
</template>
|
||||
</template>
|
||||
<script>
|
||||
Polymer({
|
||||
is: 'x-host'
|
||||
});
|
||||
Polymer({
|
||||
is: 'x-client',
|
||||
statics: {
|
||||
uid: 0
|
||||
},
|
||||
ready: function() {
|
||||
this.uid = this.statics.uid++;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</dom-module>
|
||||
|
@ -56,9 +56,16 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<template is="dom-if" id="simple">
|
||||
<div></div>
|
||||
</template>
|
||||
<div id="outerContainer">
|
||||
<template is="dom-if" id="simple">
|
||||
<x-client></x-client>
|
||||
<x-client></x-client>
|
||||
<x-client></x-client>
|
||||
</template>
|
||||
|
||||
<div id="innerContainer">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
@ -495,21 +502,155 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
document.body.removeChild(x);
|
||||
});
|
||||
|
||||
test('binding to text nodes changed while if=false', function() {
|
||||
var x = document.createElement('x-textcontent');
|
||||
document.body.appendChild(x);
|
||||
x.$.domIf.render();
|
||||
var stamped = Polymer.dom(x.root).childNodes;
|
||||
assert.equal(stamped.length, 12);
|
||||
assert.equal(stamped[7].textContent.trim(), 'Stuff');
|
||||
x.$.domIf.if = false;
|
||||
x.$.domIf.render();
|
||||
x.text = 'Hollaaaaa!';
|
||||
stamped = Polymer.dom(x.root).childNodes;
|
||||
assert.equal(stamped.length, 12);
|
||||
assert.equal(stamped[7].textContent.trim(), '');
|
||||
x.$.domIf.if = true;
|
||||
x.$.domIf.render();
|
||||
stamped = Polymer.dom(x.root).childNodes;
|
||||
assert.equal(stamped.length, 12);
|
||||
assert.equal(stamped[7].textContent.trim(), 'Hollaaaaa!');
|
||||
document.body.removeChild(x);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
suite('queueing race conditions', function() {
|
||||
suite('attach/detach tests', function() {
|
||||
|
||||
test('domif=true, attach, detach', function(done) {
|
||||
test('remove, append domif', function(done) {
|
||||
var domif = document.querySelector('#simple');
|
||||
domif.if = true;
|
||||
document.body.appendChild(domif);
|
||||
document.body.removeChild(domif);
|
||||
outerContainer.removeChild(domif);
|
||||
setTimeout(function() {
|
||||
document.body.appendChild(domif);
|
||||
var clients = outerContainer.querySelectorAll('x-client');
|
||||
assert.equal(clients.length, 0);
|
||||
outerContainer.appendChild(domif);
|
||||
setTimeout(function() {
|
||||
var clients = outerContainer.querySelectorAll('x-client');
|
||||
assert.equal(clients[0].uid, 0);
|
||||
assert.equal(clients[1].uid, 1);
|
||||
assert.equal(clients[2].uid, 2);
|
||||
assert.equal(clients[1].previousElementSibling, clients[0]);
|
||||
assert.equal(clients[2].previousElementSibling, clients[1]);
|
||||
assert.equal(domif.previousElementSibling, clients[2]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('move domif (clients persist)', function(done) {
|
||||
var domif = document.querySelector('#simple');
|
||||
domif.if = true;
|
||||
Polymer.dom(innerContainer).appendChild(domif);
|
||||
setTimeout(function() {
|
||||
var clients = innerContainer.querySelectorAll('x-client');
|
||||
// Same clients as before since move happened in one turn
|
||||
assert.equal(clients[0].uid, 0);
|
||||
assert.equal(clients[1].uid, 1);
|
||||
assert.equal(clients[2].uid, 2);
|
||||
assert.equal(clients[1].previousElementSibling, clients[0]);
|
||||
assert.equal(clients[2].previousElementSibling, clients[1]);
|
||||
assert.equal(domif.previousElementSibling, clients[2]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('remove, wait, append domif (clients recreated)', function(done) {
|
||||
var domif = document.querySelector('#simple');
|
||||
domif.if = true;
|
||||
Polymer.dom(innerContainer).removeChild(domif);
|
||||
setTimeout(function() {
|
||||
var clients = innerContainer.querySelectorAll('x-client');
|
||||
assert.equal(clients.length, 0);
|
||||
Polymer.dom(innerContainer).appendChild(domif);
|
||||
setTimeout(function() {
|
||||
var clients = outerContainer.querySelectorAll('x-client');
|
||||
// New clients since removed for a turn
|
||||
assert.equal(clients[0].uid, 3);
|
||||
assert.equal(clients[1].uid, 4);
|
||||
assert.equal(clients[2].uid, 5);
|
||||
assert.equal(clients[1].previousElementSibling, clients[0]);
|
||||
assert.equal(clients[2].previousElementSibling, clients[1]);
|
||||
assert.equal(domif.previousElementSibling, clients[2]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('move host with domif (clients persist)', function(done) {
|
||||
var host = document.createElement('x-host');
|
||||
Polymer.dom(outerContainer).appendChild(host);
|
||||
setTimeout(function() {
|
||||
var clients = Polymer.dom(host.root).querySelectorAll('x-client');
|
||||
// New clients created in host instance
|
||||
assert.equal(clients[0].uid, 6);
|
||||
assert.equal(clients[1].uid, 7);
|
||||
assert.equal(clients[2].uid, 8);
|
||||
assert.equal(clients[1].previousElementSibling, clients[0]);
|
||||
assert.equal(clients[2].previousElementSibling, clients[1]);
|
||||
assert.equal(host.$.domif.previousElementSibling, clients[2]);
|
||||
Polymer.dom(innerContainer).appendChild(host);
|
||||
setTimeout(function() {
|
||||
var clients = Polymer.dom(host.root).querySelectorAll('x-client');
|
||||
// Clients in removed host persist
|
||||
assert.equal(clients[0].uid, 6);
|
||||
assert.equal(clients[1].uid, 7);
|
||||
assert.equal(clients[2].uid, 8);
|
||||
assert.equal(clients[1].previousElementSibling, clients[0]);
|
||||
assert.equal(clients[2].previousElementSibling, clients[1]);
|
||||
assert.equal(host.$.domif.previousElementSibling, clients[2]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('remove, wait, append host with domif (clients persist)', function(done) {
|
||||
var host = document.createElement('x-host');
|
||||
Polymer.dom(outerContainer).appendChild(host);
|
||||
setTimeout(function() {
|
||||
var clients = Polymer.dom(host.root).querySelectorAll('x-client');
|
||||
// New clients created in host instance
|
||||
assert.equal(clients[0].uid, 9);
|
||||
assert.equal(clients[1].uid, 10);
|
||||
assert.equal(clients[2].uid, 11);
|
||||
assert.equal(clients[1].previousElementSibling, clients[0]);
|
||||
assert.equal(clients[2].previousElementSibling, clients[1]);
|
||||
assert.equal(host.$.domif.previousElementSibling, clients[2]);
|
||||
Polymer.dom(outerContainer).removeChild(host);
|
||||
setTimeout(function() {
|
||||
// Clients in removed host persist
|
||||
assert.equal(clients[0].uid, 9);
|
||||
assert.equal(clients[1].uid, 10);
|
||||
assert.equal(clients[2].uid, 11);
|
||||
assert.equal(clients[1].previousElementSibling, clients[0]);
|
||||
assert.equal(clients[2].previousElementSibling, clients[1]);
|
||||
assert.equal(host.$.domif.previousElementSibling, clients[2]);
|
||||
Polymer.dom(innerContainer).appendChild(host);
|
||||
setTimeout(function() {
|
||||
// Clients in removed host persist
|
||||
var clients = Polymer.dom(host.root).querySelectorAll('x-client');
|
||||
assert.equal(clients[0].uid, 9);
|
||||
assert.equal(clients[1].uid, 10);
|
||||
assert.equal(clients[2].uid, 11);
|
||||
assert.equal(clients[1].previousElementSibling, clients[0]);
|
||||
assert.equal(clients[2].previousElementSibling, clients[1]);
|
||||
assert.equal(host.$.domif.previousElementSibling, clients[2]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
@ -103,9 +103,13 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
suite('errors', function() {
|
||||
|
||||
test('items must be array', function() {
|
||||
assert.throws(function() {
|
||||
inDocumentRepeater.items = {};
|
||||
}, /expected array/, 'should warn when items is not array');
|
||||
var warned = false;
|
||||
inDocumentRepeater._error = function(message) {
|
||||
assert.match(message, /expected array/)
|
||||
warned = true;
|
||||
}
|
||||
inDocumentRepeater.items = {};
|
||||
assert.equal(warned, true, 'should warn when items is not array');
|
||||
});
|
||||
|
||||
});
|
||||
@ -3646,207 +3650,204 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
|
||||
});
|
||||
|
||||
suite('chunked rendering', function() {
|
||||
// TODO(kschaaf): This test suite has proven to be flaky only on IE, only
|
||||
// on CI (Sauce) presumably because of rAF handling in the CI environment
|
||||
// disabling for IE for now to avoid Polymer tests being flaky
|
||||
if (!/Trident/.test(navigator.userAgent)) {
|
||||
|
||||
// Patch requestAnimationFrame to setTimeout to reduce IE test flakiness on CI
|
||||
var rAF;
|
||||
suiteSetup(function() {
|
||||
rAF = window.requestAnimationFrame;
|
||||
window.requestAnimationFrame = setTimeout;
|
||||
});
|
||||
suiteTeardown(function() {
|
||||
window.requestAnimationFrame = rAF;
|
||||
});
|
||||
suite('chunked rendering', function() {
|
||||
|
||||
test('basic chunked rendering', function(done) {
|
||||
test('basic chunked rendering', function(done) {
|
||||
|
||||
var checkItemOrder = function(stamped) {
|
||||
for (var i=0; i<stamped.length; i++) {
|
||||
assert.equal(stamped[i].textContent, i);
|
||||
}
|
||||
};
|
||||
|
||||
var lastLength = 0;
|
||||
var checkCount = function() {
|
||||
var stamped = Polymer.dom(chunked.root).querySelectorAll('*:not(template)');
|
||||
checkItemOrder(stamped);
|
||||
if (stamped.length && lastLength === 0) {
|
||||
// Initial rendering of initial count
|
||||
assert.equal(stamped.length, 10);
|
||||
} else {
|
||||
// Remaining rendering incremenets
|
||||
assert.isTrue(stamped.length > lastLength);
|
||||
}
|
||||
if (stamped.length < 100) {
|
||||
lastLength = stamped.length;
|
||||
checkUntilComplete();
|
||||
} else {
|
||||
// Final rendering at exact item count
|
||||
assert.equal(stamped.length, 100);
|
||||
done();
|
||||
}
|
||||
};
|
||||
var checkUntilComplete = function() {
|
||||
// On polyfilled MO, need to wait one setTimeout before rAF
|
||||
if (MutationObserver._isPolyfilled) {
|
||||
setTimeout(function() {
|
||||
requestAnimationFrame(checkCount);
|
||||
});
|
||||
} else {
|
||||
requestAnimationFrame(checkCount);
|
||||
}
|
||||
};
|
||||
|
||||
chunked.items = chunked.preppedItems.slice();
|
||||
checkUntilComplete();
|
||||
|
||||
});
|
||||
|
||||
test('mutations during chunked rendering', function(done) {
|
||||
|
||||
var checkItemOrder = function(stamped) {
|
||||
var last = -1;
|
||||
for (var i=0; i<stamped.length; i++) {
|
||||
var curr = parseFloat(stamped[i].textContent);
|
||||
assert.isTrue(curr > last);
|
||||
last = curr;
|
||||
}
|
||||
};
|
||||
|
||||
var mutateArray = function(repeater, renderedCount) {
|
||||
// The goal here is to remove & add some, and do it over
|
||||
// the threshold of where we have currently rendered items, and
|
||||
// ensure that the prop values of the newly inserted items are in
|
||||
// ascending order so we can do a simple check in checkItemOrder
|
||||
var overlap = 2;
|
||||
var remove = 4;
|
||||
var add = 6;
|
||||
var start = renderedCount.length - overlap;
|
||||
if (start + add < repeater.items.length) {
|
||||
var end = start + remove;
|
||||
var args = ['items', start, remove];
|
||||
var startVal = repeater.items[start].prop;
|
||||
var endVal = repeater.items[end].prop;
|
||||
var delta = (endVal - startVal) / add;
|
||||
for (var i=0; i<add; i++) {
|
||||
args.push({prop: startVal + i*delta});
|
||||
var checkItemOrder = function(stamped) {
|
||||
for (var i=0; i<stamped.length; i++) {
|
||||
assert.equal(stamped[i].textContent, i);
|
||||
}
|
||||
repeater.splice.apply(repeater, args);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var lastLength = 0;
|
||||
var mutateCount = 5;
|
||||
var checkCount = function() {
|
||||
var stamped = Polymer.dom(chunked.root).querySelectorAll('*:not(template)');
|
||||
checkItemOrder(stamped);
|
||||
if (stamped.length && lastLength === 0) {
|
||||
// Initial rendering of initial count
|
||||
assert.equal(stamped.length, 10);
|
||||
} else {
|
||||
// Remaining rendering incremenets
|
||||
assert.isTrue(stamped.length > lastLength);
|
||||
}
|
||||
if (stamped.length < chunked.items.length) {
|
||||
if (mutateCount-- > 0) {
|
||||
mutateArray(chunked, stamped);
|
||||
}
|
||||
lastLength = stamped.length;
|
||||
checkUntilComplete();
|
||||
} else {
|
||||
// Final rendering at exact item count
|
||||
assert.equal(stamped.length, chunked.items.length);
|
||||
done();
|
||||
}
|
||||
};
|
||||
var checkUntilComplete = function() {
|
||||
// On polyfilled MO, need to wait one setTimeout before rAF
|
||||
if (MutationObserver._isPolyfilled) {
|
||||
setTimeout(function() {
|
||||
requestAnimationFrame(checkCount);
|
||||
});
|
||||
} else {
|
||||
requestAnimationFrame(checkCount);
|
||||
}
|
||||
};
|
||||
|
||||
chunked.items = chunked.preppedItems.slice();
|
||||
checkUntilComplete();
|
||||
|
||||
});
|
||||
|
||||
|
||||
test('mutations during chunked rendering, sort & filtered', function(done) {
|
||||
|
||||
var checkItemOrder = function(stamped) {
|
||||
var last = Infinity;
|
||||
for (var i=0; i<stamped.length; i++) {
|
||||
var curr = parseFloat(stamped[i].textContent);
|
||||
assert.isTrue(curr <= last);
|
||||
assert.strictEqual(curr % 2, 0);
|
||||
last = curr;
|
||||
}
|
||||
};
|
||||
|
||||
var mutateArray = function(repeater, stamped) {
|
||||
var start = parseInt(stamped[0].textContent);
|
||||
var end = parseInt(stamped[stamped.length-1].textContent);
|
||||
var mid = (end-start)/2;
|
||||
for (var i=0; i<5; i++) {
|
||||
chunked.push('items', {prop: mid + 1});
|
||||
}
|
||||
chunked.splice('items', Math.round(stamped.length/2), 3);
|
||||
};
|
||||
|
||||
var lastLength = 0;
|
||||
var mutateCount = 5;
|
||||
var checkCount = function() {
|
||||
var stamped = Polymer.dom(chunked.root).querySelectorAll('*:not(template)');
|
||||
checkItemOrder(stamped);
|
||||
var filteredLength = chunked.items.filter(chunked.$.repeater.filter).length;
|
||||
if (stamped.length && lastLength === 0) {
|
||||
// Initial rendering of initial count
|
||||
assert.equal(stamped.length, 10);
|
||||
} else {
|
||||
// Remaining rendering incremenets
|
||||
if (stamped.length < filteredLength) {
|
||||
var lastLength = 0;
|
||||
var checkCount = function() {
|
||||
var stamped = Polymer.dom(chunked.root).querySelectorAll('*:not(template)');
|
||||
checkItemOrder(stamped);
|
||||
if (stamped.length && lastLength === 0) {
|
||||
// Initial rendering of initial count
|
||||
assert.equal(stamped.length, 10);
|
||||
} else {
|
||||
// Remaining rendering incremenets
|
||||
assert.isTrue(stamped.length > lastLength);
|
||||
}
|
||||
}
|
||||
if (stamped.length < filteredLength) {
|
||||
if (mutateCount-- > 0) {
|
||||
mutateArray(chunked, stamped);
|
||||
if (stamped.length < 100) {
|
||||
lastLength = stamped.length;
|
||||
checkUntilComplete();
|
||||
} else {
|
||||
// Final rendering at exact item count
|
||||
assert.equal(stamped.length, 100);
|
||||
done();
|
||||
}
|
||||
lastLength = stamped.length;
|
||||
checkUntilComplete();
|
||||
} else {
|
||||
assert.equal(stamped.length, filteredLength);
|
||||
done();
|
||||
}
|
||||
};
|
||||
var checkUntilComplete = function() {
|
||||
// On polyfilled MO, need to wait one setTimeout before rAF
|
||||
if (MutationObserver._isPolyfilled) {
|
||||
setTimeout(function() {
|
||||
};
|
||||
var checkUntilComplete = function() {
|
||||
// On polyfilled MO, need to wait one setTimeout before rAF
|
||||
if (MutationObserver._isPolyfilled) {
|
||||
setTimeout(function() {
|
||||
requestAnimationFrame(checkCount);
|
||||
});
|
||||
} else {
|
||||
requestAnimationFrame(checkCount);
|
||||
});
|
||||
} else {
|
||||
requestAnimationFrame(checkCount);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
chunked.$.repeater.sort = function(a, b) {
|
||||
return b.prop - a.prop;
|
||||
};
|
||||
chunked.$.repeater.filter = function(a) {
|
||||
return (a.prop % 2) === 0;
|
||||
};
|
||||
chunked.items = chunked.preppedItems.slice();
|
||||
checkUntilComplete();
|
||||
chunked.items = chunked.preppedItems.slice();
|
||||
checkUntilComplete();
|
||||
|
||||
});
|
||||
|
||||
test('mutations during chunked rendering', function(done) {
|
||||
|
||||
var checkItemOrder = function(stamped) {
|
||||
var last = -1;
|
||||
for (var i=0; i<stamped.length; i++) {
|
||||
var curr = parseFloat(stamped[i].textContent);
|
||||
assert.isTrue(curr > last);
|
||||
last = curr;
|
||||
}
|
||||
};
|
||||
|
||||
var mutateArray = function(repeater, renderedCount) {
|
||||
// The goal here is to remove & add some, and do it over
|
||||
// the threshold of where we have currently rendered items, and
|
||||
// ensure that the prop values of the newly inserted items are in
|
||||
// ascending order so we can do a simple check in checkItemOrder
|
||||
var overlap = 2;
|
||||
var remove = 4;
|
||||
var add = 6;
|
||||
var start = renderedCount.length - overlap;
|
||||
if (start + add < repeater.items.length) {
|
||||
var end = start + remove;
|
||||
var args = ['items', start, remove];
|
||||
var startVal = repeater.items[start].prop;
|
||||
var endVal = repeater.items[end].prop;
|
||||
var delta = (endVal - startVal) / add;
|
||||
for (var i=0; i<add; i++) {
|
||||
args.push({prop: startVal + i*delta});
|
||||
}
|
||||
repeater.splice.apply(repeater, args);
|
||||
}
|
||||
};
|
||||
|
||||
var lastLength = 0;
|
||||
var mutateCount = 5;
|
||||
var checkCount = function() {
|
||||
var stamped = Polymer.dom(chunked.root).querySelectorAll('*:not(template)');
|
||||
checkItemOrder(stamped);
|
||||
if (stamped.length && lastLength === 0) {
|
||||
// Initial rendering of initial count
|
||||
assert.equal(stamped.length, 10);
|
||||
} else {
|
||||
// Remaining rendering incremenets
|
||||
assert.isTrue(stamped.length > lastLength);
|
||||
}
|
||||
if (stamped.length < chunked.items.length) {
|
||||
if (mutateCount-- > 0) {
|
||||
mutateArray(chunked, stamped);
|
||||
}
|
||||
lastLength = stamped.length;
|
||||
checkUntilComplete();
|
||||
} else {
|
||||
// Final rendering at exact item count
|
||||
assert.equal(stamped.length, chunked.items.length);
|
||||
done();
|
||||
}
|
||||
};
|
||||
var checkUntilComplete = function() {
|
||||
// On polyfilled MO, need to wait one setTimeout before rAF
|
||||
if (MutationObserver._isPolyfilled) {
|
||||
setTimeout(function() {
|
||||
requestAnimationFrame(checkCount);
|
||||
});
|
||||
} else {
|
||||
requestAnimationFrame(checkCount);
|
||||
}
|
||||
};
|
||||
|
||||
chunked.items = chunked.preppedItems.slice();
|
||||
checkUntilComplete();
|
||||
|
||||
});
|
||||
|
||||
|
||||
test('mutations during chunked rendering, sort & filtered', function(done) {
|
||||
|
||||
var checkItemOrder = function(stamped) {
|
||||
var last = Infinity;
|
||||
for (var i=0; i<stamped.length; i++) {
|
||||
var curr = parseFloat(stamped[i].textContent);
|
||||
assert.isTrue(curr <= last);
|
||||
assert.strictEqual(curr % 2, 0);
|
||||
last = curr;
|
||||
}
|
||||
};
|
||||
|
||||
var mutateArray = function(repeater, stamped) {
|
||||
var start = parseInt(stamped[0].textContent);
|
||||
var end = parseInt(stamped[stamped.length-1].textContent);
|
||||
var mid = (end-start)/2;
|
||||
for (var i=0; i<5; i++) {
|
||||
chunked.push('items', {prop: mid + 1});
|
||||
}
|
||||
chunked.splice('items', Math.round(stamped.length/2), 3);
|
||||
};
|
||||
|
||||
var lastLength = 0;
|
||||
var mutateCount = 5;
|
||||
var checkCount = function() {
|
||||
var stamped = Polymer.dom(chunked.root).querySelectorAll('*:not(template)');
|
||||
checkItemOrder(stamped);
|
||||
var filteredLength = chunked.items.filter(chunked.$.repeater.filter).length;
|
||||
if (stamped.length && lastLength === 0) {
|
||||
// Initial rendering of initial count
|
||||
assert.equal(stamped.length, 10);
|
||||
} else {
|
||||
// Remaining rendering incremenets
|
||||
if (stamped.length < filteredLength) {
|
||||
assert.isTrue(stamped.length > lastLength);
|
||||
}
|
||||
}
|
||||
if (stamped.length < filteredLength) {
|
||||
if (mutateCount-- > 0) {
|
||||
mutateArray(chunked, stamped);
|
||||
}
|
||||
lastLength = stamped.length;
|
||||
checkUntilComplete();
|
||||
} else {
|
||||
assert.equal(stamped.length, filteredLength);
|
||||
done();
|
||||
}
|
||||
};
|
||||
var checkUntilComplete = function() {
|
||||
// On polyfilled MO, need to wait one setTimeout before rAF
|
||||
if (MutationObserver._isPolyfilled) {
|
||||
setTimeout(function() {
|
||||
requestAnimationFrame(checkCount);
|
||||
});
|
||||
} else {
|
||||
requestAnimationFrame(checkCount);
|
||||
}
|
||||
};
|
||||
|
||||
chunked.$.repeater.sort = function(a, b) {
|
||||
return b.prop - a.prop;
|
||||
};
|
||||
chunked.$.repeater.filter = function(a) {
|
||||
return (a.prop % 2) === 0;
|
||||
};
|
||||
chunked.items = chunked.preppedItems.slice();
|
||||
checkUntilComplete();
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
@ -57,7 +57,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
test(':host, :host(...)', function() {
|
||||
assertComputed(styled, '1px');
|
||||
assertComputed(styledWide, '2px');
|
||||
|
||||
|
||||
});
|
||||
|
||||
test('scoped selectors, simple and complex', function() {
|
||||
@ -209,7 +209,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
@ -286,7 +286,6 @@
|
||||
})();
|
||||
</script>
|
||||
|
||||
|
||||
<template id="dynamic-style-template">
|
||||
<style>
|
||||
:host {
|
||||
@ -346,3 +345,100 @@
|
||||
})();
|
||||
</script>
|
||||
</dom-module>
|
||||
|
||||
<dom-module id="x-specificity">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
border-top: 1px solid red;
|
||||
}
|
||||
:host(.bar) {
|
||||
border-top: 2px solid red;
|
||||
}
|
||||
</style>
|
||||
<content></content>
|
||||
</template>
|
||||
<script>
|
||||
Polymer({is: 'x-specificity'});
|
||||
</script>
|
||||
</dom-module>
|
||||
|
||||
<style is="custom-style">
|
||||
:root {
|
||||
--x-specificity-parent : {
|
||||
border: 10px solid blue;
|
||||
};
|
||||
--x-specificity-nested : {
|
||||
border: 3px solid red;
|
||||
};
|
||||
}
|
||||
</style>
|
||||
|
||||
<dom-module id="x-specificity-parent">
|
||||
<template>
|
||||
<style>
|
||||
/* TODO remove `:host` when https://github.com/Polymer/polymer/pull/2419 merged */
|
||||
:host ::content > :not(template) {
|
||||
@apply(--x-specificity-parent);
|
||||
}
|
||||
</style>
|
||||
<content></content>
|
||||
</template>
|
||||
<script>
|
||||
Polymer({is: 'x-specificity-parent', extends: 'div'});
|
||||
</script>
|
||||
</dom-module>
|
||||
|
||||
<dom-module id="x-specificity-nested">
|
||||
<template>
|
||||
<style>
|
||||
:host {
|
||||
@apply(--x-specificity-nested);
|
||||
}
|
||||
</style>
|
||||
</template>
|
||||
<script>
|
||||
Polymer({is: 'x-specificity-nested', extends: 'div'});
|
||||
</script>
|
||||
</dom-module>
|
||||
|
||||
<style is="custom-style">
|
||||
:root {
|
||||
--x-overriding : {
|
||||
border-top: 1px solid red;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<dom-module id="x-overriding">
|
||||
<template>
|
||||
<style>
|
||||
.red {
|
||||
@apply(--x-overriding);
|
||||
}
|
||||
.green {
|
||||
@apply(--x-overriding);
|
||||
border-top: 2px solid green;
|
||||
}
|
||||
.red-2 {
|
||||
border-top: 2px solid green;
|
||||
@apply(--x-overriding);
|
||||
}
|
||||
.blue {
|
||||
@apply(--x-overriding);
|
||||
border-top: 3px solid blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="red">red</div>
|
||||
<div class="green">green</div>
|
||||
<div class="red-2">green-2</div>
|
||||
<div class="blue">blue</div>
|
||||
</template>
|
||||
</dom-module>
|
||||
|
||||
<script>
|
||||
Polymer({
|
||||
is: 'x-overriding'
|
||||
});
|
||||
</script>
|
||||
|
@ -44,6 +44,12 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
</template>
|
||||
|
||||
<x-dynamic-svg></x-dynamic-svg>
|
||||
<x-specificity></x-specificity>
|
||||
<x-specificity class="bar"></x-specificity>
|
||||
<div is="x-specificity-parent">
|
||||
<div is="x-specificity-nested"></div>
|
||||
</div>
|
||||
<x-overriding></x-overriding>
|
||||
|
||||
<script>
|
||||
suite('scoped-styling', function() {
|
||||
@ -212,9 +218,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
|
||||
test('styles shimmed in registration order', function() {
|
||||
var s$ = document.head.querySelectorAll('style[scope]');
|
||||
var expected = ['x-gchild', 'x-child2', 'x-styled', 'x-button',
|
||||
'x-mixed-case', 'x-mixed-case-button', 'x-dynamic-scope',
|
||||
'x-dynamic-template', 'x-dynamic-svg'];
|
||||
var expected = ['x-gchild', 'x-child2', 'x-styled', 'x-button', 'x-mixed-case',
|
||||
'x-mixed-case-button', 'x-dynamic-scope', 'x-dynamic-template',
|
||||
'x-dynamic-svg', 'x-specificity', 'x-overriding',
|
||||
'x-overriding-0', 'x-specificity-parent-0', 'x-specificity-nested-0'];
|
||||
var actual = [];
|
||||
for (var i=0; i<s$.length; i++) {
|
||||
actual.push(s$[i].getAttribute('scope'));
|
||||
@ -255,7 +262,23 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
x = document.createElement('button', 'x-mixed-case-button');
|
||||
document.body.appendChild(x);
|
||||
assertComputed(x, '14px');
|
||||
});
|
||||
|
||||
test('specificity of :host selector with class', function() {
|
||||
assertComputed(document.querySelector('x-specificity'), '1px');
|
||||
assertComputed(document.querySelector('x-specificity.bar'), '2px');
|
||||
});
|
||||
|
||||
test('specificity of ::content > :not(template) selector', function() {
|
||||
assertComputed(document.querySelector('[is=x-specificity-nested]'), '10px');
|
||||
});
|
||||
|
||||
test('overwriting mixin properties', function() {
|
||||
var root = document.querySelector('x-overriding');
|
||||
assertComputed(root.querySelector('.red'), '1px');
|
||||
assertComputed(root.querySelector('.green'), '2px');
|
||||
assertComputed(root.querySelector('.red-2'), '1px');
|
||||
assertComputed(root.querySelector('.blue'), '3px');
|
||||
});
|
||||
});
|
||||
|
||||
@ -269,7 +292,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
computed = getComputedStyle(circle);
|
||||
assert.equal(computed['fill-opacity'], '0.5');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
0
test/unit/sub/foo.png
Normal file
0
test/unit/sub/foo.png
Normal file
0
test/unit/sub/foo.z
Normal file
0
test/unit/sub/foo.z
Normal file
0
test/unit/sub/google.png
Normal file
0
test/unit/sub/google.png
Normal file
@ -11,6 +11,7 @@
|
||||
obj="{{obj}}"
|
||||
obj-prop="{{obj.prop}}"
|
||||
conflict="{{outerInnerConflict.prop}}"
|
||||
computed-from-literal="{{computeFromLiteral(33, prop)}}"
|
||||
></x-child>
|
||||
</template>
|
||||
</x-templatizer>
|
||||
@ -238,7 +239,8 @@
|
||||
],
|
||||
outerObjChanged: function() {},
|
||||
objAChanged: function() {},
|
||||
objBChanged: function() {}
|
||||
objBChanged: function() {},
|
||||
computeFromLiteral: function() {}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
@ -250,6 +250,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
||||
assert.equal(childA.conflict, 'bar');
|
||||
});
|
||||
|
||||
test('ensure literals are not forwarded to templates', function() {
|
||||
assert.notOk(host._propertyEffects[33]);
|
||||
assert.notOk(Object.getOwnPropertyDescriptor(Object.getPrototypeOf(host), 33));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
Loading…
Reference in New Issue
Block a user