Files
webcomponentsjs/webcomponents-none.min.js
2017-01-11 15:51:16 -08:00

2294 lines
77 KiB
JavaScript

(function () {
'use strict';
/**
* @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
*/
(function(scope) {
'use strict';
var forceShady = scope.flags.shadydom;
if (forceShady) {
window.ShadyDOM = window.ShadyDOM || {};
ShadyDOM.force = forceShady;
}
var forceCE = scope.flags.register || scope.flags.ce;
if (forceCE && window.customElements) {
customElements.forcePolyfill = forceCE;
}
})(window.WebComponents);
/**
@license
Copyright (c) 2016 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
*/
/*
Extremely simple css parser. Intended to be not more than what we need
and definitely not necessarily correct =).
*/
// given a string of css, return a simple rule tree
function parse(text) {
text = clean(text);
return parseCss(lex(text), text);
}
// remove stuff we don't care about that may hinder parsing
function clean(cssText) {
return cssText.replace(RX.comments, '').replace(RX.port, '');
}
// super simple {...} lexer that returns a node tree
function lex(text) {
let root = {
start: 0,
end: text.length
};
let n = root;
for (let i = 0, l = text.length; i < l; i++) {
if (text[i] === OPEN_BRACE) {
if (!n.rules) {
n.rules = [];
}
let p = n;
let previous = p.rules[p.rules.length - 1];
n = {
start: i + 1,
parent: p,
previous: previous
};
p.rules.push(n);
} else if (text[i] === CLOSE_BRACE) {
n.end = i + 1;
n = n.parent || root;
}
}
return root;
}
// add selectors/cssText to node tree
function parseCss(node, text) {
let t = text.substring(node.start, node.end - 1);
node.parsedCssText = node.cssText = t.trim();
if (node.parent) {
let ss = node.previous ? node.previous.end : node.parent.start;
t = text.substring(ss, node.start - 1);
t = _expandUnicodeEscapes(t);
t = t.replace(RX.multipleSpaces, ' ');
// TODO(sorvell): ad hoc; make selector include only after last ;
// helps with mixin syntax
t = t.substring(t.lastIndexOf(';') + 1);
let s = node.parsedSelector = node.selector = t.trim();
node.atRule = (s.indexOf(AT_START) === 0);
// note, support a subset of rule types...
if (node.atRule) {
if (s.indexOf(MEDIA_START) === 0) {
node.type = types.MEDIA_RULE;
} else if (s.match(RX.keyframesRule)) {
node.type = types.KEYFRAMES_RULE;
node.keyframesName =
node.selector.split(RX.multipleSpaces).pop();
}
} else {
if (s.indexOf(VAR_START) === 0) {
node.type = types.MIXIN_RULE;
} else {
node.type = types.STYLE_RULE;
}
}
}
let r$ = node.rules;
if (r$) {
for (let i = 0, l = r$.length, r;
(i < l) && (r = r$[i]); i++) {
parseCss(r, text);
}
}
return node;
}
// conversion of sort unicode escapes with spaces like `\33 ` (and longer) into
// expanded form that doesn't require trailing space `\000033`
function _expandUnicodeEscapes(s) {
return s.replace(/\\([0-9a-f]{1,6})\s/gi, function() {
let code = arguments[1],
repeat = 6 - code.length;
while (repeat--) {
code = '0' + code;
}
return '\\' + code;
});
}
// stringify parsed css.
function stringify(node, preserveProperties, text) {
text = text || '';
// calc rule cssText
let cssText = '';
if (node.cssText || node.rules) {
let r$ = node.rules;
if (r$ && !_hasMixinRules(r$)) {
for (let i = 0, l = r$.length, r;
(i < l) && (r = r$[i]); i++) {
cssText = stringify(r, preserveProperties, cssText);
}
} else {
cssText = preserveProperties ? node.cssText :
removeCustomProps(node.cssText);
cssText = cssText.trim();
if (cssText) {
cssText = ' ' + cssText + '\n';
}
}
}
// emit rule if there is cssText
if (cssText) {
if (node.selector) {
text += node.selector + ' ' + OPEN_BRACE + '\n';
}
text += cssText;
if (node.selector) {
text += CLOSE_BRACE + '\n\n';
}
}
return text;
}
function _hasMixinRules(rules) {
return rules[0].selector.indexOf(VAR_START) === 0;
}
function removeCustomProps(cssText) {
cssText = removeCustomPropAssignment(cssText);
return removeCustomPropApply(cssText);
}
function removeCustomPropAssignment(cssText) {
return cssText
.replace(RX.customProp, '')
.replace(RX.mixinProp, '');
}
function removeCustomPropApply(cssText) {
return cssText
.replace(RX.mixinApply, '')
.replace(RX.varApply, '');
}
let types = {
STYLE_RULE: 1,
KEYFRAMES_RULE: 7,
MEDIA_RULE: 4,
MIXIN_RULE: 1000
};
let OPEN_BRACE = '{';
let CLOSE_BRACE = '}';
// helper regexp's
let RX = {
comments: /\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim,
port: /@import[^;]*;/gim,
customProp: /(?:^[^;\-\s}]+)?--[^;{}]*?:[^{};]*?(?:[;\n]|$)/gim,
mixinProp: /(?:^[^;\-\s}]+)?--[^;{}]*?:[^{};]*?{[^}]*?}(?:[;\n]|$)?/gim,
mixinApply: /@apply\s*\(?[^);]*\)?\s*(?:[;\n]|$)?/gim,
varApply: /[^;:]*?:[^;]*?var\([^;]*\)(?:[;\n]|$)?/gim,
keyframesRule: /^@[^\s]*keyframes/,
multipleSpaces: /\s+/g
};
let VAR_START = '--';
let MEDIA_START = '@media';
let AT_START = '@';
/**
@license
Copyright (c) 2016 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
*/
let nativeShadow = !(window.ShadyDOM && window.ShadyDOM.inUse);
// chrome 49 has semi-working css vars, check if box-shadow works
// safari 9.1 has a recalc bug: https://bugs.webkit.org/show_bug.cgi?id=155782
let nativeCssVariables = (!navigator.userAgent.match('AppleWebKit/601') &&
window.CSS && CSS.supports && CSS.supports('box-shadow', '0 0 0 var(--foo)'));
// experimental support for native @apply
function detectNativeApply() {
let style = document.createElement('style');
style.textContent = '.foo { @apply --foo }';
document.head.appendChild(style);
let nativeCssApply = (style.sheet.cssRules[0].cssText.indexOf('apply') >= 0);
document.head.removeChild(style);
return nativeCssApply;
}
let nativeCssApply = false && detectNativeApply();
function parseSettings(settings) {
if (settings) {
nativeCssVariables = nativeCssVariables && !settings.shimcssproperties;
nativeShadow = nativeShadow && !settings.shimshadow;
}
}
if (window.ShadyCSS) {
parseSettings(window.ShadyCSS);
} else if (window.WebComponents) {
parseSettings(window.WebComponents.flags);
}
/**
@license
Copyright (c) 2016 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
*/
function toCssText (rules, callback) {
if (typeof rules === 'string') {
rules = parse(rules);
}
if (callback) {
forEachRule(rules, callback);
}
return stringify(rules, nativeCssVariables);
}
function rulesForStyle(style) {
if (!style.__cssRules && style.textContent) {
style.__cssRules = parse(style.textContent);
}
return style.__cssRules;
}
// Tests if a rule is a keyframes selector, which looks almost exactly
// like a normal selector but is not (it has nothing to do with scoping
// for example).
function isKeyframesSelector(rule) {
return rule.parent &&
rule.parent.type === types.KEYFRAMES_RULE;
}
function forEachRule(node, styleRuleCallback, keyframesRuleCallback, onlyActiveRules) {
if (!node) {
return;
}
let skipRules = false;
if (onlyActiveRules) {
if (node.type === types.MEDIA_RULE) {
let matchMedia = node.selector.match(rx.MEDIA_MATCH);
if (matchMedia) {
// if rule is a non matching @media rule, skip subrules
if (!window.matchMedia(matchMedia[1]).matches) {
skipRules = true;
}
}
}
}
if (node.type === types.STYLE_RULE) {
styleRuleCallback(node);
} else if (keyframesRuleCallback &&
node.type === types.KEYFRAMES_RULE) {
keyframesRuleCallback(node);
} else if (node.type === types.MIXIN_RULE) {
skipRules = true;
}
let r$ = node.rules;
if (r$ && !skipRules) {
for (let i=0, l=r$.length, r; (i<l) && (r=r$[i]); i++) {
forEachRule(r, styleRuleCallback, keyframesRuleCallback, onlyActiveRules);
}
}
}
// add a string of cssText to the document.
function applyCss(cssText, moniker, target, contextNode) {
let style = createScopeStyle(cssText, moniker);
return applyStyle(style, target, contextNode);
}
function applyStyle(style, target, contextNode) {
target = target || document.head;
let after = (contextNode && contextNode.nextSibling) ||
target.firstChild;
lastHeadApplyNode = style;
return target.insertBefore(style, after);
}
function createScopeStyle(cssText, moniker) {
let style = document.createElement('style');
if (moniker) {
style.setAttribute('scope', moniker);
}
style.textContent = cssText;
return style;
}
let lastHeadApplyNode = null;
// insert a comment node as a styling position placeholder.
function applyStylePlaceHolder(moniker) {
let placeHolder = document.createComment(' Shady DOM styles for ' +
moniker + ' ');
let after = lastHeadApplyNode ?
lastHeadApplyNode.nextSibling : null;
let scope = document.head;
scope.insertBefore(placeHolder, after || scope.firstChild);
lastHeadApplyNode = placeHolder;
return placeHolder;
}
// cssBuildTypeForModule: function (module) {
// let dm = Polymer.DomModule.import(module);
// if (dm) {
// return getCssBuildType(dm);
// }
// },
//
// Walk from text[start] matching parens
// returns position of the outer end paren
function findMatchingParen(text, start) {
let level = 0;
for (let i=start, l=text.length; i < l; i++) {
if (text[i] === '(') {
level++;
} else if (text[i] === ')') {
if (--level === 0) {
return i;
}
}
}
return -1;
}
function processVariableAndFallback(str, callback) {
// find 'var('
let start = str.indexOf('var(');
if (start === -1) {
// no var?, everything is prefix
return callback(str, '', '', '');
}
//${prefix}var(${inner})${suffix}
let end = findMatchingParen(str, start + 3);
let inner = str.substring(start + 4, end);
let prefix = str.substring(0, start);
// suffix may have other variables
let suffix = processVariableAndFallback(str.substring(end + 1), callback);
let comma = inner.indexOf(',');
// value and fallback args should be trimmed to match in property lookup
if (comma === -1) {
// variable, no fallback
return callback(prefix, inner.trim(), '', suffix);
}
// var(${value},${fallback})
let value = inner.substring(0, comma).trim();
let fallback = inner.substring(comma + 1).trim();
return callback(prefix, value, fallback, suffix);
}
function setElementClassRaw(element, value) {
// use native setAttribute provided by ShadyDOM when setAttribute is patched
if (window.ShadyDOM) {
window.ShadyDOM.nativeMethods.setAttribute.call(element, 'class', value);
} else {
element.setAttribute('class', value);
}
}
let rx = {
VAR_ASSIGN: /(?:^|[;\s{]\s*)(--[\w-]*?)\s*:\s*(?:([^;{]*)|{([^}]*)})(?:(?=[;\s}])|$)/gi,
MIXIN_MATCH: /(?:^|\W+)@apply\s*\(?([^);\n]*)\)?/gi,
VAR_CONSUMED: /(--[\w-]+)\s*([:,;)]|$)/gi,
ANIMATION_MATCH: /(animation\s*:)|(animation-name\s*:)/,
MEDIA_MATCH: /@media[^(]*(\([^)]*\))/,
IS_VAR: /^--/,
BRACKETED: /\{[^}]*\}/g,
HOST_PREFIX: '(?:^|[^.#[:])',
HOST_SUFFIX: '($|[.:[\\s>+~])'
};
/**
@license
Copyright (c) 2016 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
*/
/* Transforms ShadowDOM styling into ShadyDOM styling
* scoping:
* elements in scope get scoping selector class="x-foo-scope"
* selectors re-written as follows:
div button -> div.x-foo-scope button.x-foo-scope
* :host -> scopeName
* :host(...) -> scopeName...
* ::slotted(...) -> scopeName > ...
* ...:dir(ltr|rtl) -> [dir="ltr|rtl"] ..., ...[dir="ltr|rtl"]
* :host(:dir[rtl]) -> scopeName:dir(rtl) -> [dir="rtl"] scopeName, scopeName[dir="rtl"]
*/
const SCOPE_NAME = 'style-scope';
class StyleTransformer {
get SCOPE_NAME() {
return SCOPE_NAME;
}
// Given a node and scope name, add a scoping class to each node
// in the tree. This facilitates transforming css into scoped rules.
dom(node, scope, shouldRemoveScope) {
// one time optimization to skip scoping...
if (node.__styleScoped) {
node.__styleScoped = null;
} else {
this._transformDom(node, scope || '', shouldRemoveScope);
}
}
_transformDom(node, selector, shouldRemoveScope) {
if (node.nodeType === Node.ELEMENT_NODE) {
this.element(node, selector, shouldRemoveScope);
}
let c$ = (node.localName === 'template') ?
(node.content || node._content).childNodes :
node.children || node.childNodes;
if (c$) {
for (let i=0; i<c$.length; i++) {
this._transformDom(c$[i], selector, shouldRemoveScope);
}
}
}
element(element, scope, shouldRemoveScope) {
// note: if using classes, we add both the general 'style-scope' class
// as well as the specific scope. This enables easy filtering of all
// `style-scope` elements
if (scope) {
// note: svg on IE does not have classList so fallback to class
if (element.classList) {
if (shouldRemoveScope) {
element.classList.remove(SCOPE_NAME);
element.classList.remove(scope);
} else {
element.classList.add(SCOPE_NAME);
element.classList.add(scope);
}
} else if (element.getAttribute) {
let c = element.getAttribute(CLASS);
if (shouldRemoveScope) {
if (c) {
let newValue = c.replace(SCOPE_NAME, '').replace(scope, '');
setElementClassRaw(element, newValue);
}
} else {
let newValue = (c ? c + ' ' : '') + SCOPE_NAME + ' ' + scope;
setElementClassRaw(element, newValue);
}
}
}
}
elementStyles(element, styleRules, callback) {
let cssBuildType = element.__cssBuild;
// no need to shim selectors if settings.useNativeShadow, also
// a shady css build will already have transformed selectors
// NOTE: This method may be called as part of static or property shimming.
// When there is a targeted build it will not be called for static shimming,
// but when the property shim is used it is called and should opt out of
// static shimming work when a proper build exists.
let cssText = (nativeShadow || cssBuildType === 'shady') ?
toCssText(styleRules, callback) :
this.css(styleRules, element.is, element.extends, callback) + '\n\n';
return cssText.trim();
}
// Given a string of cssText and a scoping string (scope), returns
// a string of scoped css where each selector is transformed to include
// a class created from the scope. ShadowDOM selectors are also transformed
// (e.g. :host) to use the scoping selector.
css(rules, scope, ext, callback) {
let hostScope = this._calcHostScope(scope, ext);
scope = this._calcElementScope(scope);
let self = this;
return toCssText(rules, function(rule) {
if (!rule.isScoped) {
self.rule(rule, scope, hostScope);
rule.isScoped = true;
}
if (callback) {
callback(rule, scope, hostScope);
}
});
}
_calcElementScope(scope) {
if (scope) {
return CSS_CLASS_PREFIX + scope;
} else {
return '';
}
}
_calcHostScope(scope, ext) {
return ext ? '[is=' + scope + ']' : scope;
}
rule(rule, scope, hostScope) {
this._transformRule(rule, this._transformComplexSelector,
scope, hostScope);
}
// transforms a css rule to a scoped rule.
_transformRule(rule, transformer, scope, hostScope) {
// NOTE: save transformedSelector for subsequent matching of elements
// against selectors (e.g. when calculating style properties)
rule.selector = rule.transformedSelector =
this._transformRuleCss(rule, transformer, scope, hostScope);
}
_transformRuleCss(rule, transformer, scope, hostScope) {
let p$ = rule.selector.split(COMPLEX_SELECTOR_SEP);
// we want to skip transformation of rules that appear in keyframes,
// because they are keyframe selectors, not element selectors.
if (!isKeyframesSelector(rule)) {
for (let i=0, l=p$.length, p; (i<l) && (p=p$[i]); i++) {
p$[i] = transformer.call(this, p, scope, hostScope);
}
}
return p$.join(COMPLEX_SELECTOR_SEP);
}
_transformComplexSelector(selector, scope, hostScope) {
let stop = false;
selector = selector.trim();
// Remove spaces inside of selectors like `:nth-of-type` because it confuses SIMPLE_SELECTOR_SEP
selector = selector.replace(NTH, (m, type, inner) => `:${type}(${inner.replace(/\s/g, '')})`);
selector = selector.replace(SLOTTED_START, `${HOST} $1`);
selector = selector.replace(SIMPLE_SELECTOR_SEP, (m, c, s) => {
if (!stop) {
let info = this._transformCompoundSelector(s, c, scope, hostScope);
stop = stop || info.stop;
c = info.combinator;
s = info.value;
}
return c + s;
});
return selector;
}
_transformCompoundSelector(selector, combinator, scope, hostScope) {
// replace :host with host scoping class
let slottedIndex = selector.indexOf(SLOTTED);
if (selector.indexOf(HOST) >= 0) {
selector = this._transformHostSelector(selector, hostScope);
// replace other selectors with scoping class
} else if (slottedIndex !== 0) {
selector = scope ? this._transformSimpleSelector(selector, scope) :
selector;
}
// mark ::slotted() scope jump to replace with descendant selector + arg
// also ignore left-side combinator
let slotted = false;
if (slottedIndex >= 0) {
combinator = '';
slotted = true;
}
// process scope jumping selectors up to the scope jump and then stop
let stop;
if (slotted) {
stop = true;
if (slotted) {
// .zonk ::slotted(.foo) -> .zonk.scope > .foo
selector = selector.replace(SLOTTED_PAREN, (m, paren) => ` > ${paren}`);
}
}
selector = selector.replace(DIR_PAREN, (m, before, dir) =>
`[dir="${dir}"] ${before}, ${before}[dir="${dir}"]`);
return {value: selector, combinator, stop};
}
_transformSimpleSelector(selector, scope) {
let p$ = selector.split(PSEUDO_PREFIX);
p$[0] += scope;
return p$.join(PSEUDO_PREFIX);
}
// :host(...) -> scopeName...
_transformHostSelector(selector, hostScope) {
let m = selector.match(HOST_PAREN);
let paren = m && m[2].trim() || '';
if (paren) {
if (!paren[0].match(SIMPLE_SELECTOR_PREFIX)) {
// paren starts with a type selector
let typeSelector = paren.split(SIMPLE_SELECTOR_PREFIX)[0];
// if the type selector is our hostScope then avoid pre-pending it
if (typeSelector === hostScope) {
return paren;
// otherwise, this selector should not match in this scope so
// output a bogus selector.
} else {
return SELECTOR_NO_MATCH;
}
} else {
// make sure to do a replace here to catch selectors like:
// `:host(.foo)::before`
return selector.replace(HOST_PAREN, function(m, host, paren) {
return hostScope + paren;
});
}
// if no paren, do a straight :host replacement.
// TODO(sorvell): this should not strictly be necessary but
// it's needed to maintain support for `:host[foo]` type selectors
// which have been improperly used under Shady DOM. This should be
// deprecated.
} else {
return selector.replace(HOST, hostScope);
}
}
documentRule(rule) {
// reset selector in case this is redone.
rule.selector = rule.parsedSelector;
this.normalizeRootSelector(rule);
this._transformRule(rule, this._transformDocumentSelector);
}
normalizeRootSelector(rule) {
if (rule.selector === ROOT) {
rule.selector = 'html';
}
}
_transformDocumentSelector(selector) {
return selector.match(SLOTTED) ?
this._transformComplexSelector(selector, SCOPE_DOC_SELECTOR) :
this._transformSimpleSelector(selector.trim(), SCOPE_DOC_SELECTOR);
}
}
let NTH = /:(nth[-\w]+)\(([^)]+)\)/;
let SCOPE_DOC_SELECTOR = `:not(.${SCOPE_NAME})`;
let COMPLEX_SELECTOR_SEP = ',';
let SIMPLE_SELECTOR_SEP = /(^|[\s>+~]+)((?:\[.+?\]|[^\s>+~=\[])+)/g;
let SIMPLE_SELECTOR_PREFIX = /[[.:#*]/;
let HOST = ':host';
let ROOT = ':root';
let SLOTTED = '::slotted';
let SLOTTED_START = new RegExp(`^(${SLOTTED})`);
// NOTE: this supports 1 nested () pair for things like
// :host(:not([selected]), more general support requires
// parsing which seems like overkill
let HOST_PAREN = /(:host)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/;
// similar to HOST_PAREN
let SLOTTED_PAREN = /(?:::slotted)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/;
let DIR_PAREN = /(.*):dir\((?:(ltr|rtl))\)/;
let CSS_CLASS_PREFIX = '.';
let PSEUDO_PREFIX = ':';
let CLASS = 'class';
let SELECTOR_NO_MATCH = 'should_not_match';
var StyleTransformer$1 = new StyleTransformer();
/**
@license
Copyright (c) 2016 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
*/
var templateMap = {};
/**
@license
Copyright (c) 2016 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
*/
const promise = Promise.resolve();
class StyleInfo {
static get(node) {
return node.__styleInfo;
}
static set(node, styleInfo) {
node.__styleInfo = styleInfo;
return styleInfo;
}
static invalidate(elementName) {
if (templateMap[elementName]) {
templateMap[elementName]._applyShimInvalid = true;
}
}
/*
the template is marked as `validating` for one microtask so that all instances
found in the tree crawl of `applyStyle` will update themselves,
but the template will only be updated once.
*/
static startValidating(elementName) {
const template = templateMap[elementName];
if (!template._validating) {
template._validating = true;
promise.then(() => {
template._applyShimInvalid = false;
template._validating = false;
});
}
}
constructor(ast, placeholder, ownStylePropertyNames, elementName, typeExtension, cssBuild) {
this.styleRules = ast || null;
this.placeholder = placeholder || null;
this.ownStylePropertyNames = ownStylePropertyNames || [];
this.overrideStyleProperties = null;
this.elementName = elementName || '';
this.cssBuild = cssBuild || '';
this.typeExtension = typeExtension || '';
this.styleProperties = null;
this.scopeSelector = null;
this.customStyle = null;
}
}
/**
@license
Copyright (c) 2016 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
*/
// TODO: dedupe with shady
const p = window.Element.prototype;
const matchesSelector = p.matches || p.matchesSelector ||
p.mozMatchesSelector || p.msMatchesSelector ||
p.oMatchesSelector || p.webkitMatchesSelector;
const IS_IE = navigator.userAgent.match('Trident');
const XSCOPE_NAME = 'x-scope';
class StyleProperties {
get XSCOPE_NAME() {
return XSCOPE_NAME;
}
// decorates styles with rule info and returns an array of used style
// property names
decorateStyles(rules) {
let self = this, props = {}, keyframes = [], ruleIndex = 0;
forEachRule(rules, function(rule) {
self.decorateRule(rule);
// mark in-order position of ast rule in styles block, used for cache key
rule.index = ruleIndex++;
self.collectPropertiesInCssText(rule.propertyInfo.cssText, props);
}, function onKeyframesRule(rule) {
keyframes.push(rule);
});
// Cache all found keyframes rules for later reference:
rules._keyframes = keyframes;
// return this list of property names *consumes* in these styles.
let names = [];
for (let i in props) {
names.push(i);
}
return names;
}
// decorate a single rule with property info
decorateRule(rule) {
if (rule.propertyInfo) {
return rule.propertyInfo;
}
let info = {}, properties = {};
let hasProperties = this.collectProperties(rule, properties);
if (hasProperties) {
info.properties = properties;
// TODO(sorvell): workaround parser seeing mixins as additional rules
rule.rules = null;
}
info.cssText = this.collectCssText(rule);
rule.propertyInfo = info;
return info;
}
// collects the custom properties from a rule's cssText
collectProperties(rule, properties) {
let info = rule.propertyInfo;
if (info) {
if (info.properties) {
Object.assign(properties, info.properties);
return true;
}
} else {
let m, rx$$1 = rx.VAR_ASSIGN;
let cssText = rule.parsedCssText;
let value;
let any;
while ((m = rx$$1.exec(cssText))) {
// note: group 2 is var, 3 is mixin
value = (m[2] || m[3]).trim();
// value of 'inherit' or 'unset' is equivalent to not setting the property here
if (value !== 'inherit' || value !== 'unset') {
properties[m[1].trim()] = value;
}
any = true;
}
return any;
}
}
// returns cssText of properties that consume variables/mixins
collectCssText(rule) {
return this.collectConsumingCssText(rule.parsedCssText);
}
// NOTE: we support consumption inside mixin assignment
// but not production, so strip out {...}
collectConsumingCssText(cssText) {
return cssText.replace(rx.BRACKETED, '')
.replace(rx.VAR_ASSIGN, '');
}
collectPropertiesInCssText(cssText, props) {
let m;
while ((m = rx.VAR_CONSUMED.exec(cssText))) {
let name = m[1];
// This regex catches all variable names, and following non-whitespace char
// If next char is not ':', then variable is a consumer
if (m[2] !== ':') {
props[name] = true;
}
}
}
// turns custom properties into realized values.
reify(props) {
// big perf optimization here: reify only *own* properties
// since this object has __proto__ of the element's scope properties
let names = Object.getOwnPropertyNames(props);
for (let i=0, n; i < names.length; i++) {
n = names[i];
props[n] = this.valueForProperty(props[n], props);
}
}
// given a property value, returns the reified value
// a property value may be:
// (1) a literal value like: red or 5px;
// (2) a variable value like: var(--a), var(--a, red), or var(--a, --b) or
// var(--a, var(--b));
// (3) a literal mixin value like { properties }. Each of these properties
// can have values that are: (a) literal, (b) variables, (c) @apply mixins.
valueForProperty(property, props) {
// case (1) default
// case (3) defines a mixin and we have to reify the internals
if (property) {
if (property.indexOf(';') >=0) {
property = this.valueForProperties(property, props);
} else {
// case (2) variable
let self = this;
let fn = function(prefix, value, fallback, suffix) {
if (!value) {
return prefix + suffix;
}
let propertyValue = self.valueForProperty(props[value], props);
// if value is "initial", then the variable should be treated as unset
if (!propertyValue || propertyValue === 'initial') {
// fallback may be --a or var(--a) or literal
propertyValue = self.valueForProperty(props[fallback] || fallback, props) ||
fallback;
} else if (propertyValue === 'apply-shim-inherit') {
// CSS build will replace `inherit` with `apply-shim-inherit`
// for use with native css variables.
// Since we have full control, we can use `inherit` directly.
propertyValue = 'inherit';
}
return prefix + (propertyValue || '') + suffix;
};
property = processVariableAndFallback(property, fn);
}
}
return property && property.trim() || '';
}
// note: we do not yet support mixin within mixin
valueForProperties(property, props) {
let parts = property.split(';');
for (let i=0, p, m; i<parts.length; i++) {
if ((p = parts[i])) {
rx.MIXIN_MATCH.lastIndex = 0;
m = rx.MIXIN_MATCH.exec(p);
if (m) {
p = this.valueForProperty(props[m[1]], props);
} else {
let colon = p.indexOf(':');
if (colon !== -1) {
let pp = p.substring(colon);
pp = pp.trim();
pp = this.valueForProperty(pp, props) || pp;
p = p.substring(0, colon) + pp;
}
}
parts[i] = (p && p.lastIndexOf(';') === p.length - 1) ?
// strip trailing ;
p.slice(0, -1) :
p || '';
}
}
return parts.join(';');
}
applyProperties(rule, props) {
let output = '';
// dynamically added sheets may not be decorated so ensure they are.
if (!rule.propertyInfo) {
this.decorateRule(rule);
}
if (rule.propertyInfo.cssText) {
output = this.valueForProperties(rule.propertyInfo.cssText, props);
}
rule.cssText = output;
}
// Apply keyframe transformations to the cssText of a given rule. The
// keyframeTransforms object is a map of keyframe names to transformer
// functions which take in cssText and spit out transformed cssText.
applyKeyframeTransforms(rule, keyframeTransforms) {
let input = rule.cssText;
let output = rule.cssText;
if (rule.hasAnimations == null) {
// Cache whether or not the rule has any animations to begin with:
rule.hasAnimations = rx.ANIMATION_MATCH.test(input);
}
// If there are no animations referenced, we can skip transforms:
if (rule.hasAnimations) {
let transform;
// If we haven't transformed this rule before, we iterate over all
// transforms:
if (rule.keyframeNamesToTransform == null) {
rule.keyframeNamesToTransform = [];
for (let keyframe in keyframeTransforms) {
transform = keyframeTransforms[keyframe];
output = transform(input);
// If the transform actually changed the CSS text, we cache the
// transform name for future use:
if (input !== output) {
input = output;
rule.keyframeNamesToTransform.push(keyframe);
}
}
} else {
// If we already have a list of keyframe names that apply to this
// rule, we apply only those keyframe name transforms:
for (let i = 0; i < rule.keyframeNamesToTransform.length; ++i) {
transform = keyframeTransforms[rule.keyframeNamesToTransform[i]];
input = transform(input);
}
output = input;
}
}
rule.cssText = output;
}
// Test if the rules in these styles matches the given `element` and if so,
// collect any custom properties into `props`.
propertyDataFromStyles(rules, element) {
let props = {}, self = this;
// generates a unique key for these matches
let o = [];
// note: active rules excludes non-matching @media rules
forEachRule(rules, function(rule) {
// TODO(sorvell): we could trim the set of rules at declaration
// time to only include ones that have properties
if (!rule.propertyInfo) {
self.decorateRule(rule);
}
// match element against transformedSelector: selector may contain
// unwanted uniquification and parsedSelector does not directly match
// for :host selectors.
let selectorToMatch = rule.transformedSelector || rule.parsedSelector;
if (element && rule.propertyInfo.properties && selectorToMatch) {
if (matchesSelector.call(element, selectorToMatch)) {
self.collectProperties(rule, props);
// produce numeric key for these matches for lookup
addToBitMask(rule.index, o);
}
}
}, null, true);
return {properties: props, key: o};
}
whenHostOrRootRule(scope, rule, cssBuild, callback) {
if (!rule.propertyInfo) {
this.decorateRule(rule);
}
if (!rule.propertyInfo.properties) {
return;
}
let hostScope = scope.is ?
StyleTransformer$1._calcHostScope(scope.is, scope.extends) :
'html';
let parsedSelector = rule.parsedSelector;
let isRoot = (parsedSelector === ':host > *' || parsedSelector === 'html');
let isHost = parsedSelector.indexOf(':host') === 0 && !isRoot;
// build info is either in scope (when scope is an element) or in the style
// when scope is the default scope; note: this allows default scope to have
// mixed mode built and unbuilt styles.
if (cssBuild === 'shady') {
// :root -> x-foo > *.x-foo for elements and html for custom-style
isRoot = parsedSelector === (hostScope + ' > *.' + hostScope) || parsedSelector.indexOf('html') !== -1;
// :host -> x-foo for elements, but sub-rules have .x-foo in them
isHost = !isRoot && parsedSelector.indexOf(hostScope) === 0;
}
if (cssBuild === 'shadow') {
isRoot = parsedSelector === ':host > *' || parsedSelector === 'html';
isHost = isHost && !isRoot;
}
if (!isRoot && !isHost) {
return;
}
let selectorToMatch = hostScope;
if (isHost) {
// need to transform :host under ShadowDOM because `:host` does not work with `matches`
if (nativeShadow && !rule.transformedSelector) {
// transform :host into a matchable selector
rule.transformedSelector =
StyleTransformer$1._transformRuleCss(
rule,
StyleTransformer$1._transformComplexSelector,
StyleTransformer$1._calcElementScope(scope.is),
hostScope
);
}
selectorToMatch = rule.transformedSelector || hostScope;
}
callback({
selector: selectorToMatch,
isHost: isHost,
isRoot: isRoot
});
}
hostAndRootPropertiesForScope(scope, rules) {
let hostProps = {}, rootProps = {}, self = this;
// note: active rules excludes non-matching @media rules
let cssBuild = rules && rules.__cssBuild;
forEachRule(rules, function(rule) {
// if scope is StyleDefaults, use _element for matchesSelector
self.whenHostOrRootRule(scope, rule, cssBuild, function(info) {
let element = scope._element || scope;
if (matchesSelector.call(element, info.selector)) {
if (info.isHost) {
self.collectProperties(rule, hostProps);
} else {
self.collectProperties(rule, rootProps);
}
}
});
}, null, true);
return {rootProps: rootProps, hostProps: hostProps};
}
transformStyles(element, properties, scopeSelector) {
let self = this;
let hostSelector = StyleTransformer$1
._calcHostScope(element.is, element.extends);
let rxHostSelector = element.extends ?
'\\' + hostSelector.slice(0, -1) + '\\]' :
hostSelector;
let hostRx = new RegExp(rx.HOST_PREFIX + rxHostSelector +
rx.HOST_SUFFIX);
let rules = StyleInfo.get(element).styleRules;
let keyframeTransforms =
this._elementKeyframeTransforms(element, rules, scopeSelector);
return StyleTransformer$1.elementStyles(element, rules, function(rule) {
self.applyProperties(rule, properties);
if (!nativeShadow &&
!isKeyframesSelector(rule) &&
rule.cssText) {
// NOTE: keyframe transforms only scope munge animation names, so it
// is not necessary to apply them in ShadowDOM.
self.applyKeyframeTransforms(rule, keyframeTransforms);
self._scopeSelector(rule, hostRx, hostSelector, scopeSelector);
}
});
}
_elementKeyframeTransforms(element, rules, scopeSelector) {
let keyframesRules = rules._keyframes;
let keyframeTransforms = {};
if (!nativeShadow && keyframesRules) {
// For non-ShadowDOM, we transform all known keyframes rules in
// advance for the current scope. This allows us to catch keyframes
// rules that appear anywhere in the stylesheet:
for (let i = 0, keyframesRule = keyframesRules[i];
i < keyframesRules.length;
keyframesRule = keyframesRules[++i]) {
this._scopeKeyframes(keyframesRule, scopeSelector);
keyframeTransforms[keyframesRule.keyframesName] =
this._keyframesRuleTransformer(keyframesRule);
}
}
return keyframeTransforms;
}
// Generate a factory for transforming a chunk of CSS text to handle a
// particular scoped keyframes rule.
_keyframesRuleTransformer(keyframesRule) {
return function(cssText) {
return cssText.replace(
keyframesRule.keyframesNameRx,
keyframesRule.transformedKeyframesName);
};
}
// Transforms `@keyframes` names to be unique for the current host.
// Example: @keyframes foo-anim -> @keyframes foo-anim-x-foo-0
_scopeKeyframes(rule, scopeId) {
rule.keyframesNameRx = new RegExp(rule.keyframesName, 'g');
rule.transformedKeyframesName = rule.keyframesName + '-' + scopeId;
rule.transformedSelector = rule.transformedSelector || rule.selector;
rule.selector = rule.transformedSelector.replace(
rule.keyframesName, rule.transformedKeyframesName);
}
// Strategy: x scope shim a selector e.g. to scope `.x-foo-42` (via classes):
// non-host selector: .a.x-foo -> .x-foo-42 .a.x-foo
// host selector: x-foo.wide -> .x-foo-42.wide
// note: we use only the scope class (.x-foo-42) and not the hostSelector
// (x-foo) to scope :host rules; this helps make property host rules
// have low specificity. They are overrideable by class selectors but,
// unfortunately, not by type selectors (e.g. overriding via
// `.special` is ok, but not by `x-foo`).
_scopeSelector(rule, hostRx, hostSelector, scopeId) {
rule.transformedSelector = rule.transformedSelector || rule.selector;
let selector = rule.transformedSelector;
let scope = '.' + scopeId;
let parts = selector.split(',');
for (let i=0, l=parts.length, p; (i<l) && (p=parts[i]); i++) {
parts[i] = p.match(hostRx) ?
p.replace(hostSelector, scope) :
scope + ' ' + p;
}
rule.selector = parts.join(',');
}
applyElementScopeSelector(element, selector, old) {
let c = element.getAttribute('class') || '';
let v = c;
if (old) {
v = c.replace(
new RegExp('\\s*' + XSCOPE_NAME + '\\s*' + old + '\\s*', 'g'), ' ');
}
v += (v ? ' ' : '') + XSCOPE_NAME + ' ' + selector;
if (c !== v) {
setElementClassRaw(element, v);
}
}
applyElementStyle(element, properties, selector, style) {
// calculate cssText to apply
let cssText = style ? style.textContent || '' :
this.transformStyles(element, properties, selector);
// if shady and we have a cached style that is not style, decrement
let styleInfo = StyleInfo.get(element);
let s = styleInfo.customStyle;
if (s && !nativeShadow && (s !== style)) {
s._useCount--;
if (s._useCount <= 0 && s.parentNode) {
s.parentNode.removeChild(s);
}
}
// apply styling always under native or if we generated style
// or the cached style is not in document(!)
if (nativeShadow) {
// update existing style only under native
if (styleInfo.customStyle) {
styleInfo.customStyle.textContent = cssText;
style = styleInfo.customStyle;
// 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 precedence rules.
style = applyCss(cssText, selector, element.shadowRoot,
styleInfo.placeholder);
}
} else {
// shady and no cache hit
if (!style) {
// apply css after the scope style of the element to help with
// style precedence rules.
if (cssText) {
style = applyCss(cssText, selector, null,
styleInfo.placeholder);
}
// shady and cache hit but not in document
} else if (!style.parentNode) {
applyStyle(style, null, styleInfo.placeholder);
}
}
// ensure this style is our custom style and increment its use count.
if (style) {
style._useCount = style._useCount || 0;
// increment use count if we changed styles
if (styleInfo.customStyle != style) {
style._useCount++;
}
styleInfo.customStyle = style;
}
// @media rules may be stale in IE 10 and 11
if (IS_IE) {
style.textContent = style.textContent;
}
return style;
}
applyCustomStyle(style, properties) {
let rules = rulesForStyle(style);
let self = this;
style.textContent = toCssText(rules, function(rule) {
let 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 = removeCustomPropAssignment(css);
// replace with reified properties, scenario is same as mixin
rule.cssText = self.valueForProperties(css, properties);
}
});
}
}
function addToBitMask(n, bits) {
let o = parseInt(n / 32);
let v = 1 << (n % 32);
bits[o] = (bits[o] || 0) | v;
}
var StyleProperties$1 = new StyleProperties();
/**
@license
Copyright (c) 2016 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
*/
let placeholderMap = {};
const ce = window.customElements;
if (ce && !nativeShadow) {
const origDefine = ce.define;
ce.define = function(name, clazz, options) {
placeholderMap[name] = applyStylePlaceHolder(name);
return origDefine.call(ce, name, clazz, options);
};
}
/**
@license
Copyright (c) 2016 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
*/
class StyleCache {
constructor(typeMax = 100) {
// map element name -> [{properties, styleElement, scopeSelector}]
this.cache = {};
this.typeMax = typeMax;
}
_validate(cacheEntry, properties, ownPropertyNames) {
for (let idx = 0; idx < ownPropertyNames.length; idx++) {
let pn = ownPropertyNames[idx];
if (cacheEntry.properties[pn] !== properties[pn]) {
return false;
}
}
return true;
}
store(tagname, properties, styleElement, scopeSelector) {
let list = this.cache[tagname] || [];
list.push({properties, styleElement, scopeSelector});
if (list.length > this.typeMax) {
list.shift();
}
this.cache[tagname] = list;
}
fetch(tagname, properties, ownPropertyNames) {
let list = this.cache[tagname];
if (!list) {
return;
}
// reverse list for most-recent lookups
for (let idx = list.length - 1; idx >= 0; idx--) {
let entry = list[idx];
if (this._validate(entry, properties, ownPropertyNames)) {
return entry;
}
}
}
}
/**
@license
Copyright (c) 2016 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
*/
/**
* The apply shim simulates the behavior of `@apply` proposed at
* https://tabatkins.github.io/specs/css-apply-rule/.
* The approach is to convert a property like this:
*
* --foo: {color: red; background: blue;}
*
* to this:
*
* --foo_-_color: red;
* --foo_-_background: blue;
*
* Then where `@apply --foo` is used, that is converted to:
*
* color: var(--foo_-_color);
* background: var(--foo_-_background);
*
* This approach generally works but there are some issues and limitations.
* Consider, for example, that somewhere *between* where `--foo` is set and used,
* another element sets it to:
*
* --foo: { border: 2px solid red; }
*
* We must now ensure that the color and background from the previous setting
* do not apply. This is accomplished by changing the property set to this:
*
* --foo_-_border: 2px solid red;
* --foo_-_color: initial;
* --foo_-_background: initial;
*
* This works but introduces one new issue.
* Consider this setup at the point where the `@apply` is used:
*
* background: orange;
* @apply --foo;
*
* In this case the background will be unset (initial) rather than the desired
* `orange`. We address this by altering the property set to use a fallback
* value like this:
*
* color: var(--foo_-_color);
* background: var(--foo_-_background, orange);
* border: var(--foo_-_border);
*
* Note that the default is retained in the property set and the `background` is
* the desired `orange`. This leads us to a limitation.
*
* Limitation 1:
* Only properties in the rule where the `@apply`
* is used are considered as default values.
* If another rule matches the element and sets `background` with
* less specificity than the rule in which `@apply` appears,
* the `background` will not be set.
*
* Limitation 2:
*
* When using Polymer's `updateStyles` api, new properties may not be set for
* `@apply` properties.
*/
let MIXIN_MATCH = rx.MIXIN_MATCH;
let VAR_ASSIGN = rx.VAR_ASSIGN;
let APPLY_NAME_CLEAN = /;\s*/m;
let INITIAL_INHERIT = /^\s*(initial)|(inherit)\s*$/;
// separator used between mixin-name and mixin-property-name when producing properties
// NOTE: plain '-' may cause collisions in user styles
let MIXIN_VAR_SEP = '_-_';
// map of mixin to property names
// --foo: {border: 2px} -> {properties: {(--foo, ['border'])}, dependants: {'element-name': proto}}
class MixinMap {
constructor() {
this._map = {};
}
set(name, props) {
name = name.trim();
this._map[name] = {
properties: props,
dependants: {}
};
}
get(name) {
name = name.trim();
return this._map[name];
}
}
class ApplyShim {
constructor() {
this._currentTemplate = null;
this._measureElement = null;
this._map = new MixinMap();
this._separator = MIXIN_VAR_SEP;
this._boundProduceCssProperties = (
matchText, propertyName, valueProperty, valueMixin) =>
this._produceCssProperties(
matchText, propertyName, valueProperty, valueMixin);
}
// return true if `cssText` contains a mixin definition or consumption
detectMixin(cssText) {
const has = MIXIN_MATCH.test(cssText) || VAR_ASSIGN.test(cssText);
// reset state of the regexes
MIXIN_MATCH.lastIndex = 0;
VAR_ASSIGN.lastIndex = 0;
return has;
}
transformStyle(style, elementName) {
let ast = rulesForStyle(style);
this.transformRules(ast, elementName);
return ast;
}
transformRules(rules, elementName) {
this._currentTemplate = templateMap[elementName];
forEachRule(rules, (r) => {
this.transformRule(r);
});
this._currentTemplate = null;
}
transformRule(rule) {
rule.cssText = this.transformCssText(rule.parsedCssText);
// :root was only used for variable assignment in property shim,
// but generates invalid selectors with real properties.
// replace with `:host > *`, which serves the same effect
if (rule.selector === ':root') {
rule.selector = ':host > *';
}
}
transformCssText(cssText) {
// produce variables
cssText = cssText.replace(VAR_ASSIGN, this._boundProduceCssProperties);
// consume mixins
return this._consumeCssProperties(cssText);
}
_getInitialValueForProperty(property) {
if (!this._measureElement) {
this._measureElement = document.createElement('meta');
this._measureElement.style.all = 'initial';
document.head.appendChild(this._measureElement);
}
return window.getComputedStyle(this._measureElement).getPropertyValue(property);
}
// replace mixin consumption with variable consumption
_consumeCssProperties(text) {
let m;
// loop over text until all mixins with defintions have been applied
while((m = MIXIN_MATCH.exec(text))) {
let matchText = m[0];
let mixinName = m[1];
let idx = m.index;
// collect properties before apply to be "defaults" if mixin might override them
// match includes a "prefix", so find the start and end positions of @apply
let applyPos = idx + matchText.indexOf('@apply');
let afterApplyPos = idx + matchText.length;
// find props defined before this @apply
let textBeforeApply = text.slice(0, applyPos);
let textAfterApply = text.slice(afterApplyPos);
let defaults = this._cssTextToMap(textBeforeApply);
let replacement = this._atApplyToCssProperties(mixinName, defaults);
// use regex match position to replace mixin, keep linear processing time
text = [textBeforeApply, replacement, textAfterApply].join('');
// move regex search to _after_ replacement
MIXIN_MATCH.lastIndex = idx + replacement.length;
}
return text;
}
// produce variable consumption at the site of mixin consumption
// @apply --foo; -> for all props (${propname}: var(--foo_-_${propname}, ${fallback[propname]}}))
// Example:
// border: var(--foo_-_border); padding: var(--foo_-_padding, 2px)
_atApplyToCssProperties(mixinName, fallbacks) {
mixinName = mixinName.replace(APPLY_NAME_CLEAN, '');
let vars = [];
let mixinEntry = this._map.get(mixinName);
// if we depend on a mixin before it is created
// make a sentinel entry in the map to add this element as a dependency for when it is defined.
if (!mixinEntry) {
this._map.set(mixinName, {});
mixinEntry = this._map.get(mixinName);
}
if (mixinEntry) {
if (this._currentTemplate) {
mixinEntry.dependants[this._currentTemplate.name] = this._currentTemplate;
}
let p, parts, f;
for (p in mixinEntry.properties) {
f = fallbacks && fallbacks[p];
parts = [p, ': var(', mixinName, MIXIN_VAR_SEP, p];
if (f) {
parts.push(',', f);
}
parts.push(')');
vars.push(parts.join(''));
}
}
return vars.join('; ');
}
_replaceInitialOrInherit(property, value) {
let match = INITIAL_INHERIT.exec(value);
if (match) {
if (match[1]) {
// initial
// replace `initial` with the concrete initial value for this property
value = ApplyShim._getInitialValueForProperty(property);
} else {
// inherit
// with this purposfully illegal value, the variable will be invalid at
// compute time (https://www.w3.org/TR/css-variables/#invalid-at-computed-value-time)
// and for inheriting values, will behave similarly
// we cannot support the same behavior for non inheriting values like 'border'
value = 'apply-shim-inherit';
}
}
return value;
}
// "parse" a mixin definition into a map of properties and values
// cssTextToMap('border: 2px solid black') -> ('border', '2px solid black')
_cssTextToMap(text) {
let props = text.split(';');
let property, value;
let out = {};
for (let i = 0, p, sp; i < props.length; i++) {
p = props[i];
if (p) {
sp = p.split(':');
// ignore lines that aren't definitions like @media
if (sp.length > 1) {
property = sp[0].trim();
// some properties may have ':' in the value, like data urls
value = this._replaceInitialOrInherit(property, sp.slice(1).join(':'));
out[property] = value;
}
}
}
return out;
}
_invalidateMixinEntry(mixinEntry) {
for (let elementName in mixinEntry.dependants) {
if (!this._currentTemplate || elementName !== this._currentTemplate.name) {
StyleInfo.invalidate(elementName);
}
}
}
_produceCssProperties(matchText, propertyName, valueProperty, valueMixin) {
// handle case where property value is a mixin
if (valueProperty) {
// form: --mixin2: var(--mixin1), where --mixin1 is in the map
processVariableAndFallback(valueProperty, (prefix, value) => {
if (value && this._map.get(value)) {
valueMixin = '@apply ' + value + ';';
}
});
}
if (!valueMixin) {
return matchText;
}
let mixinAsProperties = this._consumeCssProperties(valueMixin);
let prefix = matchText.slice(0, matchText.indexOf('--'));
let mixinValues = this._cssTextToMap(mixinAsProperties);
let combinedProps = mixinValues;
let mixinEntry = this._map.get(propertyName);
let oldProps = mixinEntry && mixinEntry.properties;
if (oldProps) {
// NOTE: since we use mixin, the map of properties is updated here
// and this is what we want.
combinedProps = Object.assign(Object.create(oldProps), mixinValues);
} else {
this._map.set(propertyName, combinedProps);
}
let out = [];
let p, v;
// set variables defined by current mixin
let needToInvalidate = false;
for (p in combinedProps) {
v = mixinValues[p];
// if property not defined by current mixin, set initial
if (v === undefined) {
v = 'initial';
}
if (oldProps && !(p in oldProps)) {
needToInvalidate = true;
}
out.push(propertyName + MIXIN_VAR_SEP + p + ': ' + v);
}
if (needToInvalidate) {
this._invalidateMixinEntry(mixinEntry);
}
if (mixinEntry) {
mixinEntry.properties = combinedProps;
}
// because the mixinMap is global, the mixin might conflict with
// a different scope's simple variable definition:
// Example:
// some style somewhere:
// --mixin1:{ ... }
// --mixin2: var(--mixin1);
// some other element:
// --mixin1: 10px solid red;
// --foo: var(--mixin1);
// In this case, we leave the original variable definition in place.
if (valueProperty) {
prefix = matchText + ';' + prefix;
}
return prefix + out.join('; ') + ';';
}
}
let applyShim = new ApplyShim();
window['ApplyShim'] = applyShim;
/**
@license
Copyright (c) 2016 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
*/
let flush = function() {};
if (!nativeShadow) {
let elementNeedsScoping = (element) => {
return (element.classList &&
!element.classList.contains(StyleTransformer$1.SCOPE_NAME) ||
// note: necessary for IE11
(element instanceof SVGElement && (!element.hasAttribute('class') ||
element.getAttribute('class').indexOf(StyleTransformer$1.SCOPE_NAME) < 0)));
};
let handler = (mxns) => {
for (let x=0; x < mxns.length; x++) {
let mxn = mxns[x];
if (mxn.target === document.documentElement ||
mxn.target === document.head) {
continue;
}
for (let i=0; i < mxn.addedNodes.length; i++) {
let n = mxn.addedNodes[i];
if (elementNeedsScoping(n)) {
let root = n.getRootNode();
if (root.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
// may no longer be in a shadowroot
let host = root.host;
if (host) {
let scope = host.is || host.localName;
StyleTransformer$1.dom(n, scope);
}
}
}
}
for (let i=0; i < mxn.removedNodes.length; i++) {
let n = mxn.removedNodes[i];
if (n.nodeType === Node.ELEMENT_NODE) {
let classes = undefined;
if (n.classList) {
classes = Array.from(n.classList);
} else if (n.hasAttribute('class')) {
classes = n.getAttribute('class').split(/\s+/);
}
if (classes !== undefined) {
// NOTE: relies on the scoping class always being adjacent to the
// SCOPE_NAME class.
let classIdx = classes.indexOf(StyleTransformer$1.SCOPE_NAME);
if (classIdx >= 0) {
let scope = classes[classIdx + 1];
if (scope) {
StyleTransformer$1.dom(n, scope, true);
}
}
}
}
}
}
};
let observer = new MutationObserver(handler);
let start = (node) => {
observer.observe(node, {childList: true, subtree: true});
};
let nativeCustomElements = (window.customElements &&
!window.customElements.flush);
// need to start immediately with native custom elements
// TODO(dfreedm): with polyfilled HTMLImports and native custom elements
// excessive mutations may be observed; this can be optimized via cooperation
// with the HTMLImports polyfill.
if (nativeCustomElements) {
start(document);
} else {
let delayedStart = () => {
start(document.body);
};
// use polyfill timing if it's available
if (window.HTMLImports) {
window.HTMLImports.whenReady(delayedStart);
// otherwise push beyond native imports being ready
// which requires RAF + readystate interactive.
} else {
requestAnimationFrame(function() {
if (document.readyState === 'loading') {
let listener = function() {
delayedStart();
document.removeEventListener('readystatechange', listener);
};
document.addEventListener('readystatechange', listener);
} else {
delayedStart();
}
});
}
}
flush = function() {
handler(observer.takeRecords());
};
}
/**
@license
Copyright (c) 2016 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
*/
// TODO(dfreedm): consider spliting into separate global
let styleCache = new StyleCache();
class ShadyCSS {
constructor() {
this._scopeCounter = {};
this._documentOwner = document.documentElement;
this._documentOwnerStyleInfo = StyleInfo.set(document.documentElement, new StyleInfo({rules: []}));
this._elementsHaveApplied = false;
}
get nativeShadow() {
return nativeShadow;
}
get nativeCss() {
return nativeCssVariables;
}
get nativeCssApply() {
return nativeCssApply;
}
flush() {
flush();
}
_generateScopeSelector(name) {
let id = this._scopeCounter[name] = (this._scopeCounter[name] || 0) + 1;
return `${name}-${id}`;
}
getStyleAst(style) {
return rulesForStyle(style);
}
styleAstToString(ast) {
return toCssText(ast);
}
_gatherStyles(template) {
let styles = template.content.querySelectorAll('style');
let cssText = [];
for (let i = 0; i < styles.length; i++) {
let s = styles[i];
cssText.push(s.textContent);
s.parentNode.removeChild(s);
}
return cssText.join('').trim();
}
_getCssBuild(template) {
let style = template.content.querySelector('style');
if (!style) {
return '';
}
return style.getAttribute('css-build') || '';
}
prepareTemplate(template, elementName, typeExtension) {
if (template._prepared) {
return;
}
template._prepared = true;
template.name = elementName;
template.extends = typeExtension;
templateMap[elementName] = template;
let cssBuild = this._getCssBuild(template);
let cssText = this._gatherStyles(template);
let info = {
is: elementName,
extends: typeExtension,
__cssBuild: cssBuild,
};
if (!this.nativeShadow) {
StyleTransformer$1.dom(template.content, elementName);
}
// check if the styling has mixin definitions or uses
let hasMixins = applyShim.detectMixin(cssText);
let ast = parse(cssText);
// only run the applyshim transforms if there is a mixin involved
if (hasMixins && this.nativeCss && !this.nativeCssApply) {
applyShim.transformRules(ast, elementName);
}
template._styleAst = ast;
let ownPropertyNames = [];
if (!this.nativeCss) {
ownPropertyNames = StyleProperties$1.decorateStyles(template._styleAst, info);
}
if (!ownPropertyNames.length || this.nativeCss) {
let root = this.nativeShadow ? template.content : null;
let placeholder = placeholderMap[elementName];
let style = this._generateStaticStyle(info, template._styleAst, root, placeholder);
template._style = style;
}
template._ownPropertyNames = ownPropertyNames;
}
_generateStaticStyle(info, rules, shadowroot, placeholder) {
let cssText = StyleTransformer$1.elementStyles(info, rules);
if (cssText.length) {
return applyCss(cssText, info.is, shadowroot, placeholder);
}
}
_prepareHost(host) {
let is = host.getAttribute('is') || host.localName;
let typeExtension;
if (is !== host.localName) {
typeExtension = host.localName;
}
let placeholder = placeholderMap[is];
let template = templateMap[is];
let ast;
let ownStylePropertyNames;
let cssBuild;
if (template) {
ast = template._styleAst;
ownStylePropertyNames = template._ownPropertyNames;
cssBuild = template._cssBuild;
}
return StyleInfo.set(host,
new StyleInfo(
ast,
placeholder,
ownStylePropertyNames,
is,
typeExtension,
cssBuild
)
);
}
applyStyle(host, overrideProps) {
let is = host.getAttribute('is') || host.localName;
let styleInfo = StyleInfo.get(host);
let hasApplied = Boolean(styleInfo);
if (!styleInfo) {
styleInfo = this._prepareHost(host);
}
// Only trip the `elementsHaveApplied` flag if a node other that the root document has `applyStyle` called
if (!this._isRootOwner(host)) {
this._elementsHaveApplied = true;
}
if (window.CustomStyle) {
let CS = window.CustomStyle;
if (CS._documentDirty) {
CS.findStyles();
if (!this.nativeCss) {
this._updateProperties(this._documentOwner, this._documentOwnerStyleInfo);
} else if (!this.nativeCssApply) {
CS._revalidateApplyShim();
}
CS.applyStyles();
// if no elements have booted yet, we can just update the document and be done
if (!this._elementsHaveApplied) {
return;
}
// if no native css custom properties, we must recalculate the whole tree
if (!this.nativeCss) {
this.updateStyles();
/*
When updateStyles() runs, this element may not have a shadowroot yet.
If not, we need to make sure that this element runs `applyStyle` on itself at least once to generate a style
*/
if (hasApplied) {
return;
}
}
}
}
if (overrideProps) {
styleInfo.overrideStyleProperties =
styleInfo.overrideStyleProperties || {};
Object.assign(styleInfo.overrideStyleProperties, overrideProps);
}
if (this.nativeCss) {
if (styleInfo.overrideStyleProperties) {
this._updateNativeProperties(host, styleInfo.overrideStyleProperties);
}
let template = templateMap[is];
// bail early if there is no shadowroot for this element
if (!template && !this._isRootOwner(host)) {
return;
}
if (template && template._applyShimInvalid && template._style) {
// update template
if (!template._validating) {
applyShim.transformRules(template._styleAst, is);
template._style.textContent = StyleTransformer$1.elementStyles(host, styleInfo.styleRules);
StyleInfo.startValidating(is);
}
// update instance if native shadowdom
if (this.nativeShadow) {
let root = host.shadowRoot;
if (root) {
let style = root.querySelector('style');
style.textContent = StyleTransformer$1.elementStyles(host, styleInfo.styleRules);
}
}
styleInfo.styleRules = template._styleAst;
}
} else {
this._updateProperties(host, styleInfo);
if (styleInfo.ownStylePropertyNames && styleInfo.ownStylePropertyNames.length) {
this._applyStyleProperties(host, styleInfo);
}
}
if (hasApplied) {
let root = this._isRootOwner(host) ? host : host.shadowRoot;
// note: some elements may not have a root!
if (root) {
this._applyToDescendants(root);
}
}
}
_applyToDescendants(root) {
let c$ = root.children;
for (let i = 0, c; i < c$.length; i++) {
c = c$[i];
if (c.shadowRoot) {
this.applyStyle(c);
}
this._applyToDescendants(c);
}
}
_styleOwnerForNode(node) {
let root = node.getRootNode();
let host = root.host;
if (host) {
if (StyleInfo.get(host)) {
return host;
} else {
return this._styleOwnerForNode(host);
}
}
return this._documentOwner;
}
_isRootOwner(node) {
return (node === this._documentOwner);
}
_applyStyleProperties(host, styleInfo) {
let is = host.getAttribute('is') || host.localName;
let cacheEntry = styleCache.fetch(is, styleInfo.styleProperties, styleInfo.ownStylePropertyNames);
let cachedScopeSelector = cacheEntry && cacheEntry.scopeSelector;
let cachedStyle = cacheEntry ? cacheEntry.styleElement : null;
let oldScopeSelector = styleInfo.scopeSelector;
// only generate new scope if cached style is not found
styleInfo.scopeSelector = cachedScopeSelector || this._generateScopeSelector(is);
let style = StyleProperties$1.applyElementStyle(host, styleInfo.styleProperties, styleInfo.scopeSelector, cachedStyle);
if (!this.nativeShadow) {
StyleProperties$1.applyElementScopeSelector(host, styleInfo.scopeSelector, oldScopeSelector);
}
if (!cacheEntry) {
styleCache.store(is, styleInfo.styleProperties, style, styleInfo.scopeSelector);
}
return style;
}
_updateProperties(host, styleInfo) {
let owner = this._styleOwnerForNode(host);
let ownerStyleInfo = StyleInfo.get(owner);
let ownerProperties = ownerStyleInfo.styleProperties;
let props = Object.create(ownerProperties || null);
let hostAndRootProps = StyleProperties$1.hostAndRootPropertiesForScope(host, styleInfo.styleRules);
let propertyData = StyleProperties$1.propertyDataFromStyles(ownerStyleInfo.styleRules, host);
let propertiesMatchingHost = propertyData.properties;
Object.assign(
props,
hostAndRootProps.hostProps,
propertiesMatchingHost,
hostAndRootProps.rootProps
);
this._mixinOverrideStyles(props, styleInfo.overrideStyleProperties);
StyleProperties$1.reify(props);
styleInfo.styleProperties = props;
}
_mixinOverrideStyles(props, overrides) {
for (let p in overrides) {
let v = overrides[p];
// skip override props if they are not truthy or 0
// in order to fall back to inherited values
if (v || v === 0) {
props[p] = v;
}
}
}
_updateNativeProperties(element, properties) {
// remove previous properties
for (let p in properties) {
// NOTE: for bc with shim, don't apply null values.
if (p === null) {
element.style.removeProperty(p);
} else {
element.style.setProperty(p, properties[p]);
}
}
}
updateStyles(properties) {
this.applyStyle(this._documentOwner, properties);
}
/* Custom Style operations */
_transformCustomStyleForDocument(style) {
let ast = rulesForStyle(style);
forEachRule(ast, (rule) => {
if (nativeShadow) {
StyleTransformer$1.normalizeRootSelector(rule);
} else {
StyleTransformer$1.documentRule(rule);
}
if (this.nativeCss && !this.nativeCssApply) {
applyShim.transformRule(rule);
}
});
if (this.nativeCss) {
style.textContent = toCssText(ast);
} else {
this._documentOwnerStyleInfo.styleRules.rules.push(ast);
}
}
_revalidateApplyShim(style) {
if (this.nativeCss && !this.nativeCssApply) {
let ast = rulesForStyle(style);
applyShim.transformRules(ast);
style.textContent = toCssText(ast);
}
}
_applyCustomStyleToDocument(style) {
if (!this.nativeCss) {
StyleProperties$1.applyCustomStyle(style, this._documentOwnerStyleInfo.styleProperties);
}
}
getComputedStyleValue(element, property) {
let value;
if (!this.nativeCss) {
// element is either a style host, or an ancestor of a style host
let styleInfo = StyleInfo.get(element) || StyleInfo.get(this._styleOwnerForNode(element));
value = styleInfo.styleProperties[property];
}
// fall back to the property value from the computed styling
value = value || window.getComputedStyle(element).getPropertyValue(property);
// trim whitespace that can come after the `:` in css
// example: padding: 2px -> " 2px"
return value.trim();
}
// given an element and a classString, replaces
// the element's class with the provided classString and adds
// any necessary ShadyCSS static and property based scoping selectors
setElementClass(element, classString) {
let root = element.getRootNode();
let classes = classString ? classString.split(/\s/) : [];
let scopeName = root.host && root.host.localName;
// If no scope, try to discover scope name from existing class.
// This can occur if, for example, a template stamped element that
// has been scoped is manipulated when not in a root.
if (!scopeName) {
var classAttr = element.getAttribute('class');
if (classAttr) {
let k$ = classAttr.split(/\s/);
for (let i=0; i < k$.length; i++) {
if (k$[i] === StyleTransformer$1.SCOPE_NAME) {
scopeName = k$[i+1];
break;
}
}
}
}
if (scopeName) {
classes.push(StyleTransformer$1.SCOPE_NAME, scopeName);
}
if (!this.nativeCss) {
let styleInfo = StyleInfo.get(element);
if (styleInfo && styleInfo.scopeSelector) {
classes.push(StyleProperties$1.XSCOPE_NAME, styleInfo.scopeSelector);
}
}
setElementClassRaw(element, classes.join(' '));
}
_styleInfoForNode(node) {
return StyleInfo.get(node);
}
}
window['ShadyCSS'] = new ShadyCSS();
/**
* @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
*/
(function(scope) {
'use strict';
if (window.HTMLImports) {
HTMLImports.whenReady(function() {
requestAnimationFrame(function() {
window.dispatchEvent(new CustomEvent('WebComponentsReady'));
});
});
} else {
requestAnimationFrame(function() {
window.dispatchEvent(new CustomEvent('WebComponentsReady'));
});
}
})(window.WebComponents);
/**
* @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
*/
(function(scope) {
// It's desireable to provide a default stylesheet
// that's convenient for styling unresolved elements, but
// it's cumbersome to have to include this manually in every page.
// It would make sense to put inside some HTMLImport but
// the HTMLImports polyfill does not allow loading of stylesheets
// that block rendering. Therefore this injection is tolerated here.
//
// NOTE: position: relative fixes IE's failure to inherit opacity
// when a child is not statically positioned.
var style = document.createElement('style');
style.textContent = ''
+ 'body {'
+ 'transition: opacity ease-in 0.2s;'
+ ' } \n'
+ 'body[unresolved] {'
+ 'opacity: 0; display: block; overflow: hidden; position: relative;'
+ ' } \n'
;
var head = document.querySelector('head');
head.insertBefore(style, head.firstChild);
})(window.WebComponents);
/**
@license
Copyright (c) 2016 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
*/
/*
* Polyfills loaded: None
* Used in: Chrome
*/
// TODO: This needs to not exist at all.
//TODO(notwaldorf): this is temporary and should be removed.
}());
//# sourceMappingURL=webcomponents-none.min.js.map