diff --git a/bower.json b/bower.json index 632296058..5e5544e1e 100644 --- a/bower.json +++ b/bower.json @@ -21,6 +21,6 @@ }, "devDependencies": { "web-component-tester": "^4.3.5", - "shadydom": "webcomponents/shadydom" + "webcomponentsjs": "webcomponents/webcomponentsjs#v1" } } diff --git a/shadycss.min.js b/shadycss.min.js index 57483e8ea..d38e834ee 100644 --- a/shadycss.min.js +++ b/shadycss.min.js @@ -432,7 +432,7 @@ var StyleTransformer = { }, _transformDom: function _transformDom(node, selector, shouldRemoveScope) { - if (node.classList) { + if (node.nodeType === Node.ELEMENT_NODE) { this.element(node, selector, shouldRemoveScope); } var c$ = node.localName === 'template' ? (node.content || node._content).childNodes : node.children || node.childNodes; @@ -880,30 +880,6 @@ var set$1 = function set$1(object, property, value, receiver) { return value; }; - - - - - - - - - - - - - - -var toConsumableArray = function (arr) { - if (Array.isArray(arr)) { - for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; - - return arr2; - } else { - return Array.from(arr); - } -}; - /** @license Copyright (c) 2016 The Polymer Project Authors. All rights reserved. @@ -1354,9 +1330,18 @@ var StyleProperties = { applyElementScopeSelector: function applyElementScopeSelector(element, selector, old) { var c = element.getAttribute('class') || ''; - var v = old ? c.replace(old, selector) : (c ? c + ' ' : '') + this.XSCOPE_NAME + ' ' + selector; + var v = c; + if (old) { + v = c.replace(new RegExp('\\s*' + this.XSCOPE_NAME + '\\s*' + old + '\\s*', 'g'), ' '); + } + v += (v ? ' ' : '') + this.XSCOPE_NAME + ' ' + selector; if (c !== v) { - element.setAttribute('class', v); + // hook from ShadyDOM + if (element.__nativeSetAttribute) { + element.__nativeSetAttribute('class', v); + } else { + element.setAttribute('class', v); + } } }, @@ -1920,6 +1905,12 @@ var flush = function flush() {}; if (!nativeShadow) { (function () { + var elementNeedsScoping = function elementNeedsScoping(element) { + return element.classList && !element.classList.contains(StyleTransformer.SCOPE_NAME) || + // note: necessary for IE11 + element instanceof SVGElement && element.getAttribute('class').indexOf(StyleTransformer.SCOPE_NAME) < 0; + }; + var handler = function handler(mxns) { for (var x = 0; x < mxns.length; x++) { var mxn = mxns[x]; @@ -1928,7 +1919,7 @@ if (!nativeShadow) { } for (var i = 0; i < mxn.addedNodes.length; i++) { var n = mxn.addedNodes[i]; - if (n.nodeType === Node.ELEMENT_NODE && !n.classList.contains(StyleTransformer.SCOPE_NAME)) { + if (elementNeedsScoping(n)) { var root = n.getRootNode(); if (root.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { // may no longer be in a shadowroot @@ -2294,42 +2285,38 @@ var ShadyCSS = { // setAttribute('class', ...) and className setter have been overridden so // it cannot rely on those methods. setElementClass: function setElementClass(element, classString) { - // scope by shadyRoot host var root = element.getRootNode(); + var classes = classString ? classString.split(/\s/) : []; var scopeName = root.host && root.host.localName; - // use classList to clear existing classes - while (element.classList.length) { - var k = element.classList[0]; - // if scope not found and element is currently scoped, - // use existing scope (helps catch elements that set `class` while - // inside a disconnected dom fragment) - // NOTE: relies on the scoping class always being adjacent to the - // SCOPE_NAME class. - if (!scopeName && k == StyleTransformer.SCOPE_NAME) { - scopeName = element.classList[1]; - } - element.classList.remove(k); - } - // add user classString - var classes = classString.split(' ').filter(function (c) { - return c; - }); + // try to discover scope name form existing class + if (!scopeName) { + var classAttr = element.getAttribute('class'); + if (classAttr) { + var k$ = classAttr.split(/\s/); + for (var i = 0; i < k$.length; i++) { + if (k$[i] === StyleTransformer.SCOPE_NAME) { + scopeName = k$[i + 1]; + break; + } + } + } + } if (scopeName) { classes.push(StyleTransformer.SCOPE_NAME, scopeName); } - if (classes.length) { - var _element$classList; - - (_element$classList = element.classList).add.apply(_element$classList, toConsumableArray(classes)); - } - - // add property scoping: scope by special selector if (!this.nativeCss) { var styleInfo = StyleInfo.get(element); if (styleInfo && styleInfo.scopeSelector) { - element.classList.add(StyleProperties.XSCOPE_NAME, styleInfo.scopeSelector); + classes.push(StyleProperties.XSCOPE_NAME, styleInfo.scopeSelector); } } + var out = classes.join(' '); + // use native setAttribute provided by ShadyDOM when setAttribute is patched + if (element.__nativeSetAttribute) { + element.__nativeSetAttribute('class', out); + } else { + element.setAttribute('class', out); + } }, _styleInfoForNode: function _styleInfoForNode(node) { return StyleInfo.get(node); diff --git a/shadycss.min.js.map b/shadycss.min.js.map index 55ad88db1..258bc7d9f 100644 --- a/shadycss.min.js.map +++ b/shadycss.min.js.map @@ -1 +1 @@ -{"version":3,"file":"shadycss.min.js","sources":["css-parse.js","style-settings.js","style-util.js","style-transformer.js","style-info.js","style-properties.js","template-map.js","style-placeholder.js","style-cache.js","apply-shim.js","document-watcher.js","ShadyCSS.js","custom-style.js","entry.js"],"sourcesContent":["/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n/*\nExtremely simple css parser. Intended to be not more than what we need\nand definitely not necessarily correct =).\n*/\n\n'use strict';\n\n// given a string of css, return a simple rule tree\nexport function parse(text) {\n text = clean(text);\n return parseCss(lex(text), text);\n}\n\n// remove stuff we don't care about that may hinder parsing\nfunction clean(cssText) {\n return cssText.replace(RX.comments, '').replace(RX.port, '');\n}\n\n// super simple {...} lexer that returns a node tree\nfunction lex(text) {\n let root = {\n start: 0,\n end: text.length\n };\n let n = root;\n for (let i = 0, l = text.length; i < l; i++) {\n if (text[i] === OPEN_BRACE) {\n if (!n.rules) {\n n.rules = [];\n }\n let p = n;\n let previous = p.rules[p.rules.length - 1];\n n = {\n start: i + 1,\n parent: p,\n previous: previous\n };\n p.rules.push(n);\n } else if (text[i] === CLOSE_BRACE) {\n n.end = i + 1;\n n = n.parent || root;\n }\n }\n return root;\n}\n\n// add selectors/cssText to node tree\nfunction parseCss(node, text) {\n let t = text.substring(node.start, node.end - 1);\n node.parsedCssText = node.cssText = t.trim();\n if (node.parent) {\n let ss = node.previous ? node.previous.end : node.parent.start;\n t = text.substring(ss, node.start - 1);\n t = _expandUnicodeEscapes(t);\n t = t.replace(RX.multipleSpaces, ' ');\n // TODO(sorvell): ad hoc; make selector include only after last ;\n // helps with mixin syntax\n t = t.substring(t.lastIndexOf(';') + 1);\n let s = node.parsedSelector = node.selector = t.trim();\n node.atRule = (s.indexOf(AT_START) === 0);\n // note, support a subset of rule types...\n if (node.atRule) {\n if (s.indexOf(MEDIA_START) === 0) {\n node.type = types.MEDIA_RULE;\n } else if (s.match(RX.keyframesRule)) {\n node.type = types.KEYFRAMES_RULE;\n node.keyframesName =\n node.selector.split(RX.multipleSpaces).pop();\n }\n } else {\n if (s.indexOf(VAR_START) === 0) {\n node.type = types.MIXIN_RULE;\n } else {\n node.type = types.STYLE_RULE;\n }\n }\n }\n let r$ = node.rules;\n if (r$) {\n for (let i = 0, l = r$.length, r;\n (i < l) && (r = r$[i]); i++) {\n parseCss(r, text);\n }\n }\n return node;\n}\n\n// conversion of sort unicode escapes with spaces like `\\33 ` (and longer) into\n// expanded form that doesn't require trailing space `\\000033`\nfunction _expandUnicodeEscapes(s) {\n return s.replace(/\\\\([0-9a-f]{1,6})\\s/gi, function() {\n let code = arguments[1],\n repeat = 6 - code.length;\n while (repeat--) {\n code = '0' + code;\n }\n return '\\\\' + code;\n });\n}\n\n// stringify parsed css.\nexport function stringify(node, preserveProperties, text) {\n text = text || '';\n // calc rule cssText\n let cssText = '';\n if (node.cssText || node.rules) {\n let r$ = node.rules;\n if (r$ && !_hasMixinRules(r$)) {\n for (let i = 0, l = r$.length, r;\n (i < l) && (r = r$[i]); i++) {\n cssText = stringify(r, preserveProperties, cssText);\n }\n } else {\n cssText = preserveProperties ? node.cssText :\n removeCustomProps(node.cssText);\n cssText = cssText.trim();\n if (cssText) {\n cssText = ' ' + cssText + '\\n';\n }\n }\n }\n // emit rule if there is cssText\n if (cssText) {\n if (node.selector) {\n text += node.selector + ' ' + OPEN_BRACE + '\\n';\n }\n text += cssText;\n if (node.selector) {\n text += CLOSE_BRACE + '\\n\\n';\n }\n }\n return text;\n}\n\nfunction _hasMixinRules(rules) {\n return rules[0].selector.indexOf(VAR_START) === 0;\n}\n\nfunction removeCustomProps(cssText) {\n cssText = removeCustomPropAssignment(cssText);\n return removeCustomPropApply(cssText);\n}\n\nexport function removeCustomPropAssignment(cssText) {\n return cssText\n .replace(RX.customProp, '')\n .replace(RX.mixinProp, '');\n}\n\nfunction removeCustomPropApply(cssText) {\n return cssText\n .replace(RX.mixinApply, '')\n .replace(RX.varApply, '');\n}\n\nexport let types = {\n STYLE_RULE: 1,\n KEYFRAMES_RULE: 7,\n MEDIA_RULE: 4,\n MIXIN_RULE: 1000\n}\n\nlet OPEN_BRACE = '{';\nlet CLOSE_BRACE = '}';\n\n// helper regexp's\nlet RX = {\n comments: /\\/\\*[^*]*\\*+([^/*][^*]*\\*+)*\\//gim,\n port: /@import[^;]*;/gim,\n customProp: /(?:^[^;\\-\\s}]+)?--[^;{}]*?:[^{};]*?(?:[;\\n]|$)/gim,\n mixinProp: /(?:^[^;\\-\\s}]+)?--[^;{}]*?:[^{};]*?{[^}]*?}(?:[;\\n]|$)?/gim,\n mixinApply: /@apply\\s*\\(?[^);]*\\)?\\s*(?:[;\\n]|$)?/gim,\n varApply: /[^;:]*?:[^;]*?var\\([^;]*\\)(?:[;\\n]|$)?/gim,\n keyframesRule: /^@[^\\s]*keyframes/,\n multipleSpaces: /\\s+/g\n}\n\nlet VAR_START = '--';\nlet MEDIA_START = '@media';\nlet AT_START = '@';\n","/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n'use strict';\n\nexport let nativeShadow = !(window.ShadyDOM && window.ShadyDOM.inUse);\n// chrome 49 has semi-working css vars, check if box-shadow works\n// safari 9.1 has a recalc bug: https://bugs.webkit.org/show_bug.cgi?id=155782\nexport let nativeCssVariables = (!navigator.userAgent.match('AppleWebKit/601') &&\nwindow.CSS && CSS.supports && CSS.supports('box-shadow', '0 0 0 var(--foo)'));\n\n// experimental support for native @apply\nfunction detectNativeApply() {\n let style = document.createElement('style');\n style.textContent = '.foo { @apply --foo }';\n document.head.appendChild(style);\n let nativeCssApply = (style.sheet.cssRules[0].cssText.indexOf('apply') >= 0);\n document.head.removeChild(style);\n return nativeCssApply;\n}\n\nexport let nativeCssApply = false && detectNativeApply();\n\nfunction parseSettings(settings) {\n if (settings) {\n nativeCssVariables = nativeCssVariables && !settings.shimcssproperties;\n nativeShadow = nativeShadow && !settings.shimshadow;\n }\n}\n\nif (window.ShadyCSS) {\n parseSettings(window.ShadyCSS);\n} else if (window.WebComponents) {\n parseSettings(window.WebComponents.flags);\n}\n","/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n'use strict';\n\nimport {nativeShadow, nativeCssVariables} from './style-settings'\nimport {parse, stringify, types} from './css-parse'\n\nexport function toCssText (rules, callback) {\n if (typeof rules === 'string') {\n rules = parse(rules);\n }\n if (callback) {\n forEachRule(rules, callback);\n }\n return stringify(rules, nativeCssVariables);\n}\n\nexport function rulesForStyle(style) {\n if (!style.__cssRules && style.textContent) {\n style.__cssRules = parse(style.textContent);\n }\n return style.__cssRules;\n}\n\n// Tests if a rule is a keyframes selector, which looks almost exactly\n// like a normal selector but is not (it has nothing to do with scoping\n// for example).\nexport function isKeyframesSelector(rule) {\n return rule.parent &&\n rule.parent.type === types.KEYFRAMES_RULE;\n}\n\nexport function forEachRule(node, styleRuleCallback, keyframesRuleCallback, onlyActiveRules) {\n if (!node) {\n return;\n }\n let skipRules = false;\n if (onlyActiveRules) {\n if (node.type === types.MEDIA_RULE) {\n let matchMedia = node.selector.match(rx.MEDIA_MATCH);\n if (matchMedia) {\n // if rule is a non matching @media rule, skip subrules\n if (!window.matchMedia(matchMedia[1]).matches) {\n skipRules = true;\n }\n }\n }\n }\n if (node.type === types.STYLE_RULE) {\n styleRuleCallback(node);\n } else if (keyframesRuleCallback &&\n node.type === types.KEYFRAMES_RULE) {\n keyframesRuleCallback(node);\n } else if (node.type === types.MIXIN_RULE) {\n skipRules = true;\n }\n let r$ = node.rules;\n if (r$ && !skipRules) {\n for (let i=0, l=r$.length, r; (i+~])'\n}\n","/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n'use strict';\n\nimport * as StyleUtil from './style-util'\nimport {nativeShadow} from './style-settings'\n\n/* Transforms ShadowDOM styling into ShadyDOM styling\n\n* scoping:\n\n * elements in scope get scoping selector class=\"x-foo-scope\"\n * selectors re-written as follows:\n\n div button -> div.x-foo-scope button.x-foo-scope\n\n* :host -> scopeName\n\n* :host(...) -> scopeName...\n\n* ::slotted(...) -> scopeName > ...\n\n* ...:dir(ltr|rtl) -> [dir=\"ltr|rtl\"] ..., ...[dir=\"ltr|rtl\"]\n\n* :host(:dir[rtl]) -> scopeName:dir(rtl) -> [dir=\"rtl\"] scopeName, scopeName[dir=\"rtl\"]\n\n*/\nlet SCOPE_NAME = 'style-scope';\n\nexport let StyleTransformer = {\n\n // Given a node and scope name, add a scoping class to each node\n // in the tree. This facilitates transforming css into scoped rules.\n dom: function(node, scope, shouldRemoveScope) {\n // one time optimization to skip scoping...\n if (node.__styleScoped) {\n node.__styleScoped = null;\n } else {\n this._transformDom(node, scope || '', shouldRemoveScope);\n }\n },\n\n _transformDom: function(node, selector, shouldRemoveScope) {\n if (node.classList) {\n this.element(node, selector, shouldRemoveScope);\n }\n let c$ = (node.localName === 'template') ?\n (node.content || node._content).childNodes :\n node.children || node.childNodes;\n if (c$) {\n for (let i=0; i `:${type}(${inner.replace(/\\s/g, '')})`);\n selector = selector.replace(SLOTTED_START, `${HOST} $1`);\n selector = selector.replace(SIMPLE_SELECTOR_SEP, (m, c, s) => {\n if (!stop) {\n let info = this._transformCompoundSelector(s, c, scope, hostScope);\n stop = stop || info.stop;\n c = info.combinator;\n s = info.value;\n }\n return c + s;\n });\n return selector;\n },\n\n _transformCompoundSelector: function(selector, combinator, scope, hostScope) {\n // replace :host with host scoping class\n let slottedIndex = selector.indexOf(SLOTTED);\n if (selector.indexOf(HOST) >= 0) {\n selector = this._transformHostSelector(selector, hostScope);\n // replace other selectors with scoping class\n } else if (slottedIndex !== 0) {\n selector = scope ? this._transformSimpleSelector(selector, scope) :\n selector;\n }\n // mark ::slotted() scope jump to replace with descendant selector + arg\n // also ignore left-side combinator\n let slotted = false;\n if (slottedIndex >= 0) {\n combinator = '';\n slotted = true;\n }\n // process scope jumping selectors up to the scope jump and then stop\n let stop;\n if (slotted) {\n stop = true;\n if (slotted) {\n // .zonk ::slotted(.foo) -> .zonk.scope > .foo\n selector = selector.replace(SLOTTED_PAREN, (m, paren) => ` > ${paren}`);\n }\n }\n selector = selector.replace(DIR_PAREN, (m, before, dir) =>\n `[dir=\"${dir}\"] ${before}, ${before}[dir=\"${dir}\"]`);\n return {value: selector, combinator, stop};\n },\n\n _transformSimpleSelector: function(selector, scope) {\n let p$ = selector.split(PSEUDO_PREFIX);\n p$[0] += scope;\n return p$.join(PSEUDO_PREFIX);\n },\n\n // :host(...) -> scopeName...\n _transformHostSelector: function(selector, hostScope) {\n let m = selector.match(HOST_PAREN);\n let paren = m && m[2].trim() || '';\n if (paren) {\n if (!paren[0].match(SIMPLE_SELECTOR_PREFIX)) {\n // paren starts with a type selector\n let typeSelector = paren.split(SIMPLE_SELECTOR_PREFIX)[0];\n // if the type selector is our hostScope then avoid pre-pending it\n if (typeSelector === hostScope) {\n return paren;\n // otherwise, this selector should not match in this scope so\n // output a bogus selector.\n } else {\n return SELECTOR_NO_MATCH;\n }\n } else {\n // make sure to do a replace here to catch selectors like:\n // `:host(.foo)::before`\n return selector.replace(HOST_PAREN, function(m, host, paren) {\n return hostScope + paren;\n });\n }\n // if no paren, do a straight :host replacement.\n // TODO(sorvell): this should not strictly be necessary but\n // it's needed to maintain support for `:host[foo]` type selectors\n // which have been improperly used under Shady DOM. This should be\n // deprecated.\n } else {\n return selector.replace(HOST, hostScope);\n }\n },\n\n documentRule: function(rule) {\n // reset selector in case this is redone.\n rule.selector = rule.parsedSelector;\n this.normalizeRootSelector(rule);\n this._transformRule(rule, this._transformDocumentSelector);\n },\n\n normalizeRootSelector: function(rule) {\n if (rule.selector === ROOT) {\n rule.selector = 'html';\n }\n },\n\n _transformDocumentSelector: function(selector) {\n return selector.match(SLOTTED) ?\n this._transformComplexSelector(selector, SCOPE_DOC_SELECTOR) :\n this._transformSimpleSelector(selector.trim(), SCOPE_DOC_SELECTOR);\n },\n SCOPE_NAME: SCOPE_NAME\n};\n\nlet NTH = /:(nth[-\\w]+)\\(([^)]+)\\)/;\nlet SCOPE_DOC_SELECTOR = `:not(.${SCOPE_NAME})`;\nlet COMPLEX_SELECTOR_SEP = ',';\nlet SIMPLE_SELECTOR_SEP = /(^|[\\s>+~]+)((?:\\[.+?\\]|[^\\s>+~=\\[])+)/g;\nlet SIMPLE_SELECTOR_PREFIX = /[[.:#*]/;\nlet HOST = ':host';\nlet ROOT = ':root';\nlet SLOTTED = '::slotted';\nlet SLOTTED_START = new RegExp(`^(${SLOTTED})`);\n// NOTE: this supports 1 nested () pair for things like\n// :host(:not([selected]), more general support requires\n// parsing which seems like overkill\nlet HOST_PAREN = /(:host)(?:\\(((?:\\([^)(]*\\)|[^)(]*)+?)\\))/;\n// similar to HOST_PAREN\nlet SLOTTED_PAREN = /(?:::slotted)(?:\\(((?:\\([^)(]*\\)|[^)(]*)+?)\\))/;\nlet DIR_PAREN = /(.*):dir\\((?:(ltr|rtl))\\)/;\nlet CSS_CLASS_PREFIX = '.';\nlet PSEUDO_PREFIX = ':';\nlet CLASS = 'class';\nlet SELECTOR_NO_MATCH = 'should_not_match';\n","/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n'use strict';\n\nexport default class StyleInfo {\n static get(node) {\n return node.__styleInfo;\n }\n static set(node, styleInfo) {\n node.__styleInfo = styleInfo;\n return styleInfo;\n }\n constructor(ast, placeholder, ownStylePropertyNames, elementName, typeExtension, cssBuild) {\n this.styleRules = ast || null;\n this.placeholder = placeholder || null;\n this.ownStylePropertyNames = ownStylePropertyNames || [];\n this.overrideStyleProperties = {};\n this.elementName = elementName || '';\n this.cssBuild = cssBuild || '';\n this.typeExtension = typeExtension || '';\n this.styleProperties = null;\n this.scopeSelector = null;\n this.customStyle = null;\n }\n}\n","/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n'use strict';\n\nimport {removeCustomPropAssignment} from './css-parse'\nimport {nativeShadow} from './style-settings'\nimport {StyleTransformer} from './style-transformer'\nimport * as StyleUtil from './style-util'\nimport StyleInfo from './style-info'\n\n// TODO: dedupe with shady\nlet p = window.Element.prototype;\nlet matchesSelector = p.matches || p.matchesSelector ||\n p.mozMatchesSelector || p.msMatchesSelector ||\n p.oMatchesSelector || p.webkitMatchesSelector;\n\nlet IS_IE = navigator.userAgent.match('Trident');\n\nexport let StyleProperties = {\n\n // decorates styles with rule info and returns an array of used style\n // property names\n decorateStyles: function(rules) {\n let self = this, props = {}, keyframes = [], ruleIndex = 0;\n StyleUtil.forEachRule(rules, function(rule) {\n self.decorateRule(rule);\n // mark in-order position of ast rule in styles block, used for cache key\n rule.index = ruleIndex++;\n self.collectPropertiesInCssText(rule.propertyInfo.cssText, props);\n }, function onKeyframesRule(rule) {\n keyframes.push(rule);\n });\n // Cache all found keyframes rules for later reference:\n rules._keyframes = keyframes;\n // return this list of property names *consumes* in these styles.\n let names = [];\n for (let i in props) {\n names.push(i);\n }\n return names;\n },\n\n // decorate a single rule with property info\n decorateRule: function(rule) {\n if (rule.propertyInfo) {\n return rule.propertyInfo;\n }\n let info = {}, properties = {};\n let hasProperties = this.collectProperties(rule, properties);\n if (hasProperties) {\n info.properties = properties;\n // TODO(sorvell): workaround parser seeing mixins as additional rules\n rule.rules = null;\n }\n info.cssText = this.collectCssText(rule);\n rule.propertyInfo = info;\n return info;\n },\n\n // collects the custom properties from a rule's cssText\n collectProperties: function(rule, properties) {\n let info = rule.propertyInfo;\n if (info) {\n if (info.properties) {\n Object.assign(properties, info.properties);\n return true;\n }\n } else {\n let m, rx = this.rx.VAR_ASSIGN;\n let cssText = rule.parsedCssText;\n let value;\n let any;\n while ((m = rx.exec(cssText))) {\n // note: group 2 is var, 3 is mixin\n value = (m[2] || m[3]).trim();\n // value of 'inherit' or 'unset' is equivalent to not setting the property here\n if (value !== 'inherit' || value !== 'unset') {\n properties[m[1].trim()] = value;\n }\n any = true;\n }\n return any;\n }\n\n },\n\n // returns cssText of properties that consume variables/mixins\n collectCssText: function(rule) {\n return this.collectConsumingCssText(rule.parsedCssText);\n },\n\n // NOTE: we support consumption inside mixin assignment\n // but not production, so strip out {...}\n collectConsumingCssText: function(cssText) {\n return cssText.replace(this.rx.BRACKETED, '')\n .replace(this.rx.VAR_ASSIGN, '');\n },\n\n collectPropertiesInCssText: function(cssText, props) {\n let m;\n while ((m = this.rx.VAR_CONSUMED.exec(cssText))) {\n let name = m[1];\n // This regex catches all variable names, and following non-whitespace char\n // If next char is not ':', then variable is a consumer\n if (m[2] !== ':') {\n props[name] = true;\n }\n }\n },\n\n // turns custom properties into realized values.\n reify: function(props) {\n // big perf optimization here: reify only *own* properties\n // since this object has __proto__ of the element's scope properties\n let names = Object.getOwnPropertyNames(props);\n for (let i=0, n; i < names.length; i++) {\n n = names[i];\n props[n] = this.valueForProperty(props[n], props);\n }\n },\n\n // given a property value, returns the reified value\n // a property value may be:\n // (1) a literal value like: red or 5px;\n // (2) a variable value like: var(--a), var(--a, red), or var(--a, --b) or\n // var(--a, var(--b));\n // (3) a literal mixin value like { properties }. Each of these properties\n // can have values that are: (a) literal, (b) variables, (c) @apply mixins.\n valueForProperty: function(property, props) {\n // case (1) default\n // case (3) defines a mixin and we have to reify the internals\n if (property) {\n if (property.indexOf(';') >=0) {\n property = this.valueForProperties(property, props);\n } else {\n // case (2) variable\n let self = this;\n let fn = function(prefix, value, fallback, suffix) {\n if (!value) {\n return prefix + suffix;\n }\n let propertyValue = self.valueForProperty(props[value], props);\n // if value is \"initial\", then the variable should be treated as unset\n if (!propertyValue || propertyValue === 'initial') {\n // fallback may be --a or var(--a) or literal\n propertyValue = self.valueForProperty(props[fallback] || fallback, props) ||\n fallback;\n } else if (propertyValue === 'apply-shim-inherit') {\n // CSS build will replace `inherit` with `apply-shim-inherit`\n // for use with native css variables.\n // Since we have full control, we can use `inherit` directly.\n propertyValue = 'inherit';\n }\n return prefix + (propertyValue || '') + suffix;\n };\n property = StyleUtil.processVariableAndFallback(property, fn);\n }\n }\n return property && property.trim() || '';\n },\n\n // note: we do not yet support mixin within mixin\n valueForProperties: function(property, props) {\n let parts = property.split(';');\n for (let i=0, p, m; i *' || parsedSelector === 'html');\n let isHost = parsedSelector.indexOf(':host') === 0 && !isRoot;\n // build info is either in scope (when scope is an element) or in the style\n // when scope is the default scope; note: this allows default scope to have\n // mixed mode built and unbuilt styles.\n if (cssBuild === 'shady') {\n // :root -> x-foo > *.x-foo for elements and html for custom-style\n isRoot = parsedSelector === (hostScope + ' > *.' + hostScope) || parsedSelector.indexOf('html') !== -1;\n // :host -> x-foo for elements, but sub-rules have .x-foo in them\n isHost = !isRoot && parsedSelector.indexOf(hostScope) === 0;\n }\n if (cssBuild === 'shadow') {\n isRoot = parsedSelector === ':host > *' || parsedSelector === 'html';\n isHost = isHost && !isRoot;\n }\n if (!isRoot && !isHost) {\n return;\n }\n let selectorToMatch = hostScope;\n if (isHost) {\n // need to transform :host under ShadowDOM because `:host` does not work with `matches`\n if (nativeShadow && !rule.transformedSelector) {\n // transform :host into a matchable selector\n rule.transformedSelector =\n StyleTransformer._transformRuleCss(\n rule,\n StyleTransformer._transformComplexSelector,\n StyleTransformer._calcElementScope(scope.is),\n hostScope\n );\n }\n selectorToMatch = rule.transformedSelector || hostScope;\n }\n callback({\n selector: selectorToMatch,\n isHost: isHost,\n isRoot: isRoot\n });\n },\n\n hostAndRootPropertiesForScope: function(scope, rules) {\n let hostProps = {}, rootProps = {}, self = this;\n // note: active rules excludes non-matching @media rules\n let cssBuild = rules && rules.__cssBuild;\n StyleUtil.forEachRule(rules, function(rule) {\n // if scope is StyleDefaults, use _element for matchesSelector\n self.whenHostOrRootRule(scope, rule, cssBuild, function(info) {\n let element = scope._element || scope;\n if (matchesSelector.call(element, info.selector)) {\n if (info.isHost) {\n self.collectProperties(rule, hostProps);\n } else {\n self.collectProperties(rule, rootProps);\n }\n }\n });\n }, null, true);\n return {rootProps: rootProps, hostProps: hostProps};\n },\n\n transformStyles: function(element, properties, scopeSelector) {\n let self = this;\n let hostSelector = StyleTransformer\n ._calcHostScope(element.is, element.extends);\n let rxHostSelector = element.extends ?\n '\\\\' + hostSelector.slice(0, -1) + '\\\\]' :\n hostSelector;\n let hostRx = new RegExp(this.rx.HOST_PREFIX + rxHostSelector +\n this.rx.HOST_SUFFIX);\n let rules = StyleInfo.get(element).styleRules;\n let keyframeTransforms =\n this._elementKeyframeTransforms(element, rules, scopeSelector);\n return StyleTransformer.elementStyles(element, rules, function(rule) {\n self.applyProperties(rule, properties);\n if (!nativeShadow &&\n !StyleUtil.isKeyframesSelector(rule) &&\n rule.cssText) {\n // NOTE: keyframe transforms only scope munge animation names, so it\n // is not necessary to apply them in ShadowDOM.\n self.applyKeyframeTransforms(rule, keyframeTransforms);\n self._scopeSelector(rule, hostRx, hostSelector, scopeSelector);\n }\n });\n },\n\n _elementKeyframeTransforms: function(element, rules, scopeSelector) {\n let keyframesRules = rules._keyframes;\n let keyframeTransforms = {};\n if (!nativeShadow && keyframesRules) {\n // For non-ShadowDOM, we transform all known keyframes rules in\n // advance for the current scope. This allows us to catch keyframes\n // rules that appear anywhere in the stylesheet:\n for (let i = 0, keyframesRule = keyframesRules[i];\n i < keyframesRules.length;\n keyframesRule = keyframesRules[++i]) {\n this._scopeKeyframes(keyframesRule, scopeSelector);\n keyframeTransforms[keyframesRule.keyframesName] =\n this._keyframesRuleTransformer(keyframesRule);\n }\n }\n return keyframeTransforms;\n },\n\n // Generate a factory for transforming a chunk of CSS text to handle a\n // particular scoped keyframes rule.\n _keyframesRuleTransformer: function(keyframesRule) {\n return function(cssText) {\n return cssText.replace(\n keyframesRule.keyframesNameRx,\n keyframesRule.transformedKeyframesName);\n };\n },\n\n // Transforms `@keyframes` names to be unique for the current host.\n // Example: @keyframes foo-anim -> @keyframes foo-anim-x-foo-0\n _scopeKeyframes: function(rule, scopeId) {\n rule.keyframesNameRx = new RegExp(rule.keyframesName, 'g');\n rule.transformedKeyframesName = rule.keyframesName + '-' + scopeId;\n rule.transformedSelector = rule.transformedSelector || rule.selector;\n rule.selector = rule.transformedSelector.replace(\n rule.keyframesName, rule.transformedKeyframesName);\n },\n\n // Strategy: x scope shim a selector e.g. to scope `.x-foo-42` (via classes):\n // non-host selector: .a.x-foo -> .x-foo-42 .a.x-foo\n // host selector: x-foo.wide -> .x-foo-42.wide\n // note: we use only the scope class (.x-foo-42) and not the hostSelector\n // (x-foo) to scope :host rules; this helps make property host rules\n // have low specificity. They are overrideable by class selectors but,\n // unfortunately, not by type selectors (e.g. overriding via\n // `.special` is ok, but not by `x-foo`).\n _scopeSelector: function(rule, hostRx, hostSelector, scopeId) {\n rule.transformedSelector = rule.transformedSelector || rule.selector;\n let selector = rule.transformedSelector;\n let scope = '.' + scopeId;\n let parts = selector.split(',');\n for (let i=0, l=parts.length, p; (i [{properties, styleElement, scopeSelector}]\n this.cache = {};\n this.typeMax = typeMax;\n }\n\n _validate(cacheEntry, properties, ownPropertyNames) {\n for (let idx = 0; idx < ownPropertyNames.length; idx++) {\n let pn = ownPropertyNames[idx];\n if (cacheEntry.properties[pn] !== properties[pn]) {\n return false;\n }\n }\n return true;\n }\n\n store(tagname, properties, styleElement, scopeSelector) {\n let list = this.cache[tagname] || [];\n list.push({properties, styleElement, scopeSelector});\n if (list.length > this.typeMax) {\n list.shift();\n }\n this.cache[tagname] = list;\n }\n\n fetch(tagname, properties, ownPropertyNames) {\n let list = this.cache[tagname];\n if (!list) {\n return;\n }\n // reverse list for most-recent lookups\n for (let idx = list.length - 1; idx >= 0; idx--) {\n let entry = list[idx];\n if (this._validate(entry, properties, ownPropertyNames)) {\n return entry;\n }\n }\n }\n}\n","/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n/**\n * The apply shim simulates the behavior of `@apply` proposed at\n * https://tabatkins.github.io/specs/css-apply-rule/.\n * The approach is to convert a property like this:\n *\n * --foo: {color: red; background: blue;}\n *\n * to this:\n *\n * --foo_-_color: red;\n * --foo_-_background: blue;\n *\n * Then where `@apply --foo` is used, that is converted to:\n *\n * color: var(--foo_-_color);\n * background: var(--foo_-_background);\n *\n * This approach generally works but there are some issues and limitations.\n * Consider, for example, that somewhere *between* where `--foo` is set and used,\n * another element sets it to:\n *\n * --foo: { border: 2px solid red; }\n *\n * We must now ensure that the color and background from the previous setting\n * do not apply. This is accomplished by changing the property set to this:\n *\n * --foo_-_border: 2px solid red;\n * --foo_-_color: initial;\n * --foo_-_background: initial;\n *\n * This works but introduces one new issue.\n * Consider this setup at the point where the `@apply` is used:\n *\n * background: orange;\n * @apply --foo;\n *\n * In this case the background will be unset (initial) rather than the desired\n * `orange`. We address this by altering the property set to use a fallback\n * value like this:\n *\n * color: var(--foo_-_color);\n * background: var(--foo_-_background, orange);\n * border: var(--foo_-_border);\n *\n * Note that the default is retained in the property set and the `background` is\n * the desired `orange`. This leads us to a limitation.\n *\n * Limitation 1:\n\n * Only properties in the rule where the `@apply`\n * is used are considered as default values.\n * If another rule matches the element and sets `background` with\n * less specificity than the rule in which `@apply` appears,\n * the `background` will not be set.\n *\n * Limitation 2:\n *\n * When using Polymer's `updateStyles` api, new properties may not be set for\n * `@apply` properties.\n\n*/\n\n'use strict';\n\nimport {rx, forEachRule, processVariableAndFallback, rulesForStyle} from './style-util'\nimport templateMap from './template-map'\n\nlet MIXIN_MATCH = rx.MIXIN_MATCH;\nlet VAR_ASSIGN = rx.VAR_ASSIGN;\n\nlet APPLY_NAME_CLEAN = /;\\s*/m;\nlet INITIAL_INHERIT = /^\\s*(initial)|(inherit)\\s*$/;\n\n// separator used between mixin-name and mixin-property-name when producing properties\n// NOTE: plain '-' may cause collisions in user styles\nlet MIXIN_VAR_SEP = '_-_';\n\n// map of mixin to property names\n// --foo: {border: 2px} -> {properties: {(--foo, ['border'])}, dependants: {'element-name': proto}}\nclass MixinMap {\n constructor() {\n this._map = {};\n }\n set(name, props) {\n name = name.trim();\n this._map[name] = {\n properties: props,\n dependants: {}\n }\n }\n get(name) {\n name = name.trim();\n return this._map[name];\n }\n}\n\nclass ApplyShim {\n constructor() {\n this._currentTemplate = null;\n this._measureElement = null;\n this._map = new MixinMap();\n this._separator = MIXIN_VAR_SEP;\n this._boundProduceCssProperties = (\n matchText, propertyName, valueProperty, valueMixin) =>\n this._produceCssProperties(\n matchText, propertyName, valueProperty, valueMixin);\n }\n transformStyle(style, elementName) {\n let ast = rulesForStyle(style);\n this.transformRules(ast, elementName);\n return ast;\n }\n transformRules(rules, elementName) {\n this._currentTemplate = templateMap[elementName];\n forEachRule(rules, (r) => {\n this.transformRule(r);\n });\n if (this._currentTemplate) {\n this._currentTemplate.__applyShimInvalid = false;\n }\n this._currentTemplate = null;\n }\n transformRule(rule) {\n rule.cssText = this.transformCssText(rule.parsedCssText);\n // :root was only used for variable assignment in property shim,\n // but generates invalid selectors with real properties.\n // replace with `:host > *`, which serves the same effect\n if (rule.selector === ':root') {\n rule.selector = ':host > *';\n }\n }\n transformCssText(cssText) {\n // produce variables\n cssText = cssText.replace(VAR_ASSIGN, this._boundProduceCssProperties);\n // consume mixins\n return this._consumeCssProperties(cssText);\n }\n _getInitialValueForProperty(property) {\n if (!this._measureElement) {\n this._measureElement = document.createElement('meta');\n this._measureElement.style.all = 'initial';\n document.head.appendChild(this._measureElement);\n }\n return window.getComputedStyle(this._measureElement).getPropertyValue(property);\n }\n // replace mixin consumption with variable consumption\n _consumeCssProperties(text) {\n let m;\n // loop over text until all mixins with defintions have been applied\n while((m = MIXIN_MATCH.exec(text))) {\n let matchText = m[0];\n let mixinName = m[1];\n let idx = m.index;\n // collect properties before apply to be \"defaults\" if mixin might override them\n // match includes a \"prefix\", so find the start and end positions of @apply\n let applyPos = idx + matchText.indexOf('@apply');\n let afterApplyPos = idx + matchText.length;\n // find props defined before this @apply\n let textBeforeApply = text.slice(0, applyPos);\n let textAfterApply = text.slice(afterApplyPos);\n let defaults = this._cssTextToMap(textBeforeApply);\n let replacement = this._atApplyToCssProperties(mixinName, defaults);\n // use regex match position to replace mixin, keep linear processing time\n text = [textBeforeApply, replacement, textAfterApply].join('');\n // move regex search to _after_ replacement\n MIXIN_MATCH.lastIndex = idx + replacement.length;\n }\n return text;\n }\n // produce variable consumption at the site of mixin consumption\n // @apply --foo; -> for all props (${propname}: var(--foo_-_${propname}, ${fallback[propname]}}))\n // Example:\n // border: var(--foo_-_border); padding: var(--foo_-_padding, 2px)\n _atApplyToCssProperties(mixinName, fallbacks) {\n mixinName = mixinName.replace(APPLY_NAME_CLEAN, '');\n let vars = [];\n let mixinEntry = this._map.get(mixinName);\n // if we depend on a mixin before it is created\n // make a sentinel entry in the map to add this element as a dependency for when it is defined.\n if (!mixinEntry) {\n this._map.set(mixinName, {});\n mixinEntry = this._map.get(mixinName);\n }\n if (mixinEntry) {\n if (this._currentTemplate) {\n mixinEntry.dependants[this._currentTemplate.name] = this._currentTemplate;\n }\n let p, parts, f;\n for (p in mixinEntry.properties) {\n f = fallbacks && fallbacks[p];\n parts = [p, ': var(', mixinName, MIXIN_VAR_SEP, p];\n if (f) {\n parts.push(',', f);\n }\n parts.push(')');\n vars.push(parts.join(''));\n }\n }\n return vars.join('; ');\n }\n\n _replaceInitialOrInherit(property, value) {\n let match = INITIAL_INHERIT.exec(value);\n if (match) {\n if (match[1]) {\n // initial\n // replace `initial` with the concrete initial value for this property\n value = ApplyShim._getInitialValueForProperty(property);\n } else {\n // inherit\n // with this purposfully illegal value, the variable will be invalid at\n // compute time (https://www.w3.org/TR/css-variables/#invalid-at-computed-value-time)\n // and for inheriting values, will behave similarly\n // we cannot support the same behavior for non inheriting values like 'border'\n value = 'apply-shim-inherit';\n }\n }\n return value;\n }\n\n // \"parse\" a mixin definition into a map of properties and values\n // cssTextToMap('border: 2px solid black') -> ('border', '2px solid black')\n _cssTextToMap(text) {\n let props = text.split(';');\n let property, value;\n let out = {};\n for (let i = 0, p, sp; i < props.length; i++) {\n p = props[i];\n if (p) {\n sp = p.split(':');\n // ignore lines that aren't definitions like @media\n if (sp.length > 1) {\n property = sp[0].trim();\n // some properties may have ':' in the value, like data urls\n value = this._replaceInitialOrInherit(property, sp.slice(1).join(':'));\n out[property] = value;\n }\n }\n }\n return out;\n }\n\n _invalidateMixinEntry(mixinEntry) {\n for (let elementName in mixinEntry.dependants) {\n if (elementName !== this._currentTemplate) {\n mixinEntry.dependants[elementName].__applyShimInvalid = true;\n }\n }\n }\n\n _produceCssProperties(matchText, propertyName, valueProperty, valueMixin) {\n // handle case where property value is a mixin\n if (valueProperty) {\n // form: --mixin2: var(--mixin1), where --mixin1 is in the map\n processVariableAndFallback(valueProperty, (prefix, value) => {\n if (value && this._map.get(value)) {\n valueMixin = '@apply ' + value + ';';\n }\n });\n }\n if (!valueMixin) {\n return matchText;\n }\n let mixinAsProperties = this._consumeCssProperties(valueMixin);\n let prefix = matchText.slice(0, matchText.indexOf('--'));\n let mixinValues = this._cssTextToMap(mixinAsProperties);\n let combinedProps = mixinValues;\n let mixinEntry = this._map.get(propertyName);\n let oldProps = mixinEntry && mixinEntry.properties;\n if (oldProps) {\n // NOTE: since we use mixin, the map of properties is updated here\n // and this is what we want.\n combinedProps = Object.assign(Object.create(oldProps), mixinValues);\n } else {\n this._map.set(propertyName, combinedProps);\n }\n let out = [];\n let p, v;\n // set variables defined by current mixin\n let needToInvalidate = false;\n for (p in combinedProps) {\n v = mixinValues[p];\n // if property not defined by current mixin, set initial\n if (v === undefined) {\n v = 'initial';\n }\n if (oldProps && !(p in oldProps)) {\n needToInvalidate = true;\n }\n out.push(propertyName + MIXIN_VAR_SEP + p + ': ' + v);\n }\n if (needToInvalidate) {\n this._invalidateMixinEntry(mixinEntry);\n }\n if (mixinEntry) {\n mixinEntry.properties = combinedProps;\n }\n // because the mixinMap is global, the mixin might conflict with\n // a different scope's simple variable definition:\n // Example:\n // some style somewhere:\n // --mixin1:{ ... }\n // --mixin2: var(--mixin1);\n // some other element:\n // --mixin1: 10px solid red;\n // --foo: var(--mixin1);\n // In this case, we leave the original variable definition in place.\n if (valueProperty) {\n prefix = matchText + ';' + prefix;\n }\n return prefix + out.join('; ') + ';';\n }\n}\n\nlet applyShim = new ApplyShim();\nwindow['ApplyShim'] = applyShim;\nexport default applyShim;\n","/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n'use strict';\n\nimport {nativeShadow} from './style-settings'\nimport {StyleTransformer} from './style-transformer'\n\nexport let flush = function() {};\n\nif (!nativeShadow) {\n let handler = (mxns) => {\n for (let x=0; x < mxns.length; x++) {\n let mxn = mxns[x];\n if (mxn.target === document.documentElement ||\n mxn.target === document.head) {\n continue;\n }\n for (let i=0; i < mxn.addedNodes.length; i++) {\n let n = mxn.addedNodes[i];\n if (n.nodeType === Node.ELEMENT_NODE &&\n !n.classList.contains(StyleTransformer.SCOPE_NAME)) {\n let root = n.getRootNode();\n if (root.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {\n // may no longer be in a shadowroot\n let host = root.host;\n if (host) {\n let scope = host.is || host.localName;\n StyleTransformer.dom(n, scope);\n }\n }\n }\n }\n for (let i=0; i < mxn.removedNodes.length; i++) {\n let n = mxn.removedNodes[i];\n if (n.nodeType === Node.ELEMENT_NODE) {\n let classIdx = Array.from(n.classList)\n .indexOf(StyleTransformer.SCOPE_NAME);\n if (classIdx >= 0) {\n // NOTE: relies on the scoping class always being adjacent to the\n // SCOPE_NAME class.\n let scope = n.classList[classIdx + 1];\n if (scope) {\n StyleTransformer.dom(n, scope, true);\n }\n }\n }\n }\n }\n };\n\n let observer = new MutationObserver(handler);\n let start = (node) => {\n observer.observe(node, {childList: true, subtree: true});\n }\n let nativeCustomElements = (window.customElements &&\n !window.customElements.flush);\n // need to start immediately with native custom elements\n // TODO(dfreedm): with polyfilled HTMLImports and native custom elements\n // excessive mutations may be observed; this can be optimized via cooperation\n // with the HTMLImports polyfill.\n if (nativeCustomElements) {\n start(document);\n } else {\n let delayedStart = () => {\n start(document.body);\n }\n // use polyfill timing if it's available\n if (window.HTMLImports) {\n window.HTMLImports.whenReady(delayedStart);\n // otherwise push beyond native imports being ready\n // which requires RAF + readystate interactive.\n } else {\n requestAnimationFrame(function() {\n if (document.readyState === 'loading') {\n let listener = function() {\n delayedStart();\n document.removeEventListener('readystatechange', listener);\n }\n document.addEventListener('readystatechange', listener);\n } else {\n delayedStart();\n }\n });\n }\n }\n\n flush = function() {\n handler(observer.takeRecords());\n }\n}\n","/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n'use strict';\n\nimport {parse} from './css-parse'\nimport {nativeShadow, nativeCssVariables, nativeCssApply} from './style-settings'\nimport {StyleTransformer} from './style-transformer'\nimport * as StyleUtil from './style-util'\nimport {StyleProperties} from './style-properties'\nimport templateMap from './template-map'\nimport placeholderMap from './style-placeholder'\nimport StyleInfo from './style-info'\nimport StyleCache from './style-cache'\n\n// TODO(dfreedm): consider spliting into separate global\nimport ApplyShim from './apply-shim'\nimport {flush} from './document-watcher'\n\nlet styleCache = new StyleCache();\n\nexport let ShadyCSS = {\n flush: flush,\n scopeCounter: {},\n nativeShadow: nativeShadow,\n nativeCss: nativeCssVariables,\n nativeCssApply: nativeCssApply,\n _documentOwner: document.documentElement,\n _documentOwnerStyleInfo: StyleInfo.set(document.documentElement, new StyleInfo({rules: []})),\n _generateScopeSelector(name) {\n let id = this.scopeCounter[name] = (this.scopeCounter[name] || 0) + 1;\n return name + '-' + id;\n },\n getStyleAst(style) {\n return StyleUtil.rulesForStyle(style);\n },\n styleAstToString(ast) {\n return StyleUtil.toCssText(ast);\n },\n _gatherStyles(template) {\n let styles = template.content.querySelectorAll('style');\n let cssText = [];\n for (let i = 0; i < styles.length; i++) {\n let s = styles[i];\n cssText.push(s.textContent);\n s.parentNode.removeChild(s);\n }\n return cssText.join('').trim();\n },\n _getCssBuild(template) {\n let style = template.content.querySelector('style');\n if (!style) {\n return '';\n }\n return style.getAttribute('css-build') || '';\n },\n prepareTemplate(template, elementName, typeExtension) {\n if (template._prepared) {\n return;\n }\n template._prepared = true;\n template.name = elementName;\n template.extends = typeExtension;\n templateMap[elementName] = template;\n let cssBuild = this._getCssBuild(template);\n let cssText = this._gatherStyles(template);\n let info = {\n is: elementName,\n extends: typeExtension,\n __cssBuild: cssBuild,\n };\n if (!this.nativeShadow) {\n StyleTransformer.dom(template.content, elementName);\n }\n let ast = parse(cssText);\n if (this.nativeCss && !this.nativeCssApply) {\n ApplyShim.transformRules(ast, elementName);\n }\n template._styleAst = ast;\n\n let ownPropertyNames = [];\n if (!this.nativeCss) {\n ownPropertyNames = StyleProperties.decorateStyles(template._styleAst, info);\n }\n if (!ownPropertyNames.length || this.nativeCss) {\n let root = this.nativeShadow ? template.content : null;\n let placeholder = placeholderMap[elementName];\n let style = this._generateStaticStyle(info, template._styleAst, root, placeholder);\n template._style = style;\n }\n template._ownPropertyNames = ownPropertyNames;\n },\n _generateStaticStyle(info, rules, shadowroot, placeholder) {\n let cssText = StyleTransformer.elementStyles(info, rules);\n if (cssText.length) {\n return StyleUtil.applyCss(cssText, info.is, shadowroot, placeholder);\n }\n },\n _prepareHost(host) {\n let is = host.getAttribute('is') || host.localName;\n let typeExtension;\n if (is !== host.localName) {\n typeExtension = host.localName;\n }\n let placeholder = placeholderMap[is];\n let template = templateMap[is];\n let ast;\n let ownStylePropertyNames;\n let cssBuild;\n if (template) {\n ast = template._styleAst;\n ownStylePropertyNames = template._ownPropertyNames;\n cssBuild = template._cssBuild;\n }\n return StyleInfo.set(host,\n new StyleInfo(\n ast,\n placeholder,\n ownStylePropertyNames,\n is,\n typeExtension,\n cssBuild\n )\n );\n },\n applyStyle(host, overrideProps) {\n let is = host.getAttribute('is') || host.localName;\n if (window.CustomStyle) {\n let CS = window.CustomStyle;\n if (CS._documentDirty) {\n CS.findStyles();\n if (!this.nativeCss) {\n this._updateProperties(this._documentOwner, this._documentOwnerStyleInfo);\n } else if (!this.nativeCssApply) {\n CS._revalidateApplyShim();\n }\n CS.applyStyles();\n CS._documentDirty = false;\n }\n }\n let styleInfo = StyleInfo.get(host);\n if (!styleInfo) {\n styleInfo = this._prepareHost(host);\n }\n Object.assign(styleInfo.overrideStyleProperties, overrideProps);\n if (this.nativeCss) {\n let template = templateMap[is];\n if (template && template.__applyShimInvalid && template._style) {\n // update template\n ApplyShim.transformRules(template._styleAst, is);\n template._style.textContent = StyleTransformer.elementStyles(host, styleInfo.styleRules);\n // update instance if native shadowdom\n if (this.nativeShadow) {\n let style = host.shadowRoot.querySelector('style');\n style.textContent = StyleTransformer.elementStyles(host, styleInfo.styleRules);\n }\n styleInfo.styleRules = template._styleAst;\n }\n this._updateNativeProperties(host, styleInfo.overrideStyleProperties);\n } else {\n this._updateProperties(host, styleInfo);\n if (styleInfo.ownStylePropertyNames && styleInfo.ownStylePropertyNames.length) {\n // TODO: use caching\n this._applyStyleProperties(host, styleInfo);\n }\n }\n let root = this._isRootOwner(host) ? host : host.shadowRoot;\n // note: some elements may not have a root!\n if (root) {\n this._applyToDescendants(root);\n }\n },\n _applyToDescendants(root) {\n let c$ = root.children;\n for (let i = 0, c; i < c$.length; i++) {\n c = c$[i];\n if (c.shadowRoot) {\n this.applyStyle(c);\n }\n this._applyToDescendants(c);\n }\n },\n _styleOwnerForNode(node) {\n let root = node.getRootNode();\n let host = root.host;\n if (host) {\n if (StyleInfo.get(host)) {\n return host;\n } else {\n return this._styleOwnerForNode(host);\n }\n }\n return this._documentOwner;\n },\n _isRootOwner(node) {\n return (node === this._documentOwner);\n },\n _applyStyleProperties(host, styleInfo) {\n let is = host.getAttribute('is') || host.localName;\n let cacheEntry = styleCache.fetch(is, styleInfo.styleProperties, styleInfo.ownStylePropertyNames);\n let cachedScopeSelector = cacheEntry && cacheEntry.scopeSelector;\n let cachedStyle = cacheEntry ? cacheEntry.styleElement : null;\n let oldScopeSelector = styleInfo.scopeSelector;\n // only generate new scope if cached style is not found\n styleInfo.scopeSelector = cachedScopeSelector || this._generateScopeSelector(is);\n let style = StyleProperties.applyElementStyle(host, styleInfo.styleProperties, styleInfo.scopeSelector, cachedStyle);\n if (!this.nativeShadow) {\n StyleProperties.applyElementScopeSelector(host, styleInfo.scopeSelector, oldScopeSelector);\n }\n if (!cacheEntry) {\n styleCache.store(is, styleInfo.styleProperties, style, styleInfo.scopeSelector);\n }\n return style;\n },\n _updateProperties(host, styleInfo) {\n let owner = this._styleOwnerForNode(host);\n let ownerStyleInfo = StyleInfo.get(owner);\n let ownerProperties = ownerStyleInfo.styleProperties;\n let props = Object.create(ownerProperties || null);\n let hostAndRootProps = StyleProperties.hostAndRootPropertiesForScope(host, styleInfo.styleRules);\n let propertyData = StyleProperties.propertyDataFromStyles(ownerStyleInfo.styleRules, host);\n let propertiesMatchingHost = propertyData.properties\n Object.assign(\n props,\n hostAndRootProps.hostProps,\n propertiesMatchingHost,\n hostAndRootProps.rootProps\n );\n this._mixinOverrideStyles(props, styleInfo.overrideStyleProperties);\n StyleProperties.reify(props);\n styleInfo.styleProperties = props;\n },\n _mixinOverrideStyles(props, overrides) {\n for (let p in overrides) {\n let v = overrides[p];\n // skip override props if they are not truthy or 0\n // in order to fall back to inherited values\n if (v || v === 0) {\n props[p] = v;\n }\n }\n },\n _updateNativeProperties(element, properties) {\n // remove previous properties\n for (let p in properties) {\n // NOTE: for bc with shim, don't apply null values.\n if (p === null) {\n element.style.removeProperty(p);\n } else {\n element.style.setProperty(p, properties[p]);\n }\n }\n },\n updateStyles(properties) {\n if (window.CustomStyle) {\n window.CustomStyle._documentDirty = true;\n }\n this.applyStyle(this._documentOwner, properties);\n },\n /* Custom Style operations */\n _transformCustomStyleForDocument(style) {\n let ast = StyleUtil.rulesForStyle(style);\n StyleUtil.forEachRule(ast, (rule) => {\n if (nativeShadow) {\n StyleTransformer.normalizeRootSelector(rule);\n } else {\n StyleTransformer.documentRule(rule);\n }\n if (this.nativeCss && !this.nativeCssApply) {\n ApplyShim.transformRule(rule);\n }\n });\n if (this.nativeCss) {\n style.textContent = StyleUtil.toCssText(ast);\n } else {\n this._documentOwnerStyleInfo.styleRules.rules.push(ast);\n }\n },\n _revalidateApplyShim(style) {\n if (this.nativeCss && !this.nativeCssApply) {\n let ast = StyleUtil.rulesForStyle(style);\n ApplyShim.transformRules(ast);\n style.textContent = StyleUtil.toCssText(ast);\n }\n },\n _applyCustomStyleToDocument(style) {\n if (!this.nativeCss) {\n StyleProperties.applyCustomStyle(style, this._documentOwnerStyleInfo.styleProperties);\n }\n },\n getComputedStyleValue(element, property) {\n let value;\n if (!this.nativeCss) {\n // element is either a style host, or an ancestor of a style host\n let styleInfo = StyleInfo.get(element) || StyleInfo.get(this._styleOwnerForNode(element));\n value = styleInfo.styleProperties[property];\n }\n // fall back to the property value from the computed styling\n value = value || window.getComputedStyle(element).getPropertyValue(property);\n // trim whitespace that can come after the `:` in css\n // example: padding: 2px -> \" 2px\"\n return value.trim();\n },\n // given an element and a classString, replaces\n // the element's class with the provided classString and adds\n // any necessary ShadyCSS static and property based scoping selectors\n // NOTE: this method is suitable to be called in an environment in which\n // setAttribute('class', ...) and className setter have been overridden so\n // it cannot rely on those methods.\n setElementClass(element, classString) {\n // scope by shadyRoot host\n let root = element.getRootNode();\n let scopeName = root.host && root.host.localName;\n // use classList to clear existing classes\n while (element.classList.length) {\n let k = element.classList[0];\n // if scope not found and element is currently scoped,\n // use existing scope (helps catch elements that set `class` while\n // inside a disconnected dom fragment)\n // NOTE: relies on the scoping class always being adjacent to the\n // SCOPE_NAME class.\n if (!scopeName && k == StyleTransformer.SCOPE_NAME) {\n scopeName = element.classList[1];\n }\n element.classList.remove(k);\n }\n // add user classString\n let classes = classString.split(' ').filter((c) => c);\n if (scopeName) {\n classes.push(StyleTransformer.SCOPE_NAME, scopeName);\n }\n if (classes.length) {\n element.classList.add(...classes);\n }\n\n // add property scoping: scope by special selector\n if (!this.nativeCss) {\n let styleInfo = StyleInfo.get(element);\n if (styleInfo && styleInfo.scopeSelector) {\n element.classList.add(StyleProperties.XSCOPE_NAME,\n styleInfo.scopeSelector);\n }\n }\n },\n _styleInfoForNode(node) {\n return StyleInfo.get(node);\n }\n}\n\nwindow['ShadyCSS'] = ShadyCSS;\n","/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n/*\nWrapper over \n\n*/\n\n'use strict';\n\nlet ShadyCSS = window.ShadyCSS;\n\nlet enqueued = false;\n\nlet customStyles = [];\n\nlet hookFn = null;\n\n/*\nIf a page only has elements, it will flash unstyled content,\nas all the instances will boot asynchronously after page load.\n\nCalling ShadyCSS.updateStyles() will force the work to happen synchronously\n*/\nfunction enqueueDocumentValidation() {\n if (enqueued) {\n return;\n }\n enqueued = true;\n if (window.HTMLImports) {\n window.HTMLImports.whenReady(validateDocument);\n } else if (document.readyState === 'complete') {\n requestAnimationFrame(validateDocument);\n } else {\n document.addEventListener('readystatechange', function() {\n if (document.readyState === 'complete') {\n validateDocument();\n }\n });\n }\n}\n\n// NOTE: Make sure to enqueue eagerly. This is an optimization that\n// helps ensure that the first run of validateDocument will actually\n// have access to all the custom-style's created via loading imports.\n// If the first created custom-style calls enqueue and HTMLImports.ready\n// is true at that time (which is the case when HTMLImports are polyfilled),\n// then the enqueue immediately calls validateDocument and work that could be\n// batched is not.\nenqueueDocumentValidation();\n\nfunction validateDocument() {\n if (enqueued) {\n ShadyCSS.updateStyles();\n enqueued = false;\n }\n}\n\nfunction CustomStyle() {\n /*\n Use Reflect to invoke the HTMLElement constructor, or rely on the\n CustomElement polyfill replacement that can be `.call`ed\n */\n const self = (window.Reflect && Reflect.construct)\n ? Reflect.construct(HTMLElement, [], this.constructor || CustomStyle)\n : HTMLElement.call(this);\n customStyles.push(self);\n enqueueDocumentValidation();\n return self;\n}\n\nObject.defineProperties(CustomStyle, {\n /*\n CustomStyle.processHook is provided to customize the \n\n*/\n\n'use strict';\n\nlet ShadyCSS = window.ShadyCSS;\n\nlet enqueued = false;\n\nlet customStyles = [];\n\nlet hookFn = null;\n\n/*\nIf a page only has elements, it will flash unstyled content,\nas all the instances will boot asynchronously after page load.\n\nCalling ShadyCSS.updateStyles() will force the work to happen synchronously\n*/\nfunction enqueueDocumentValidation() {\n if (enqueued) {\n return;\n }\n enqueued = true;\n if (window.HTMLImports) {\n window.HTMLImports.whenReady(validateDocument);\n } else if (document.readyState === 'complete') {\n requestAnimationFrame(validateDocument);\n } else {\n document.addEventListener('readystatechange', function() {\n if (document.readyState === 'complete') {\n validateDocument();\n }\n });\n }\n}\n\n// NOTE: Make sure to enqueue eagerly. This is an optimization that\n// helps ensure that the first run of validateDocument will actually\n// have access to all the custom-style's created via loading imports.\n// If the first created custom-style calls enqueue and HTMLImports.ready\n// is true at that time (which is the case when HTMLImports are polyfilled),\n// then the enqueue immediately calls validateDocument and work that could be\n// batched is not.\nenqueueDocumentValidation();\n\nfunction validateDocument() {\n if (enqueued) {\n ShadyCSS.updateStyles();\n enqueued = false;\n }\n}\n\nfunction CustomStyle() {\n /*\n Use Reflect to invoke the HTMLElement constructor, or rely on the\n CustomElement polyfill replacement that can be `.call`ed\n */\n const self = (window.Reflect && Reflect.construct)\n ? Reflect.construct(HTMLElement, [], this.constructor || CustomStyle)\n : HTMLElement.call(this);\n customStyles.push(self);\n enqueueDocumentValidation();\n return self;\n}\n\nObject.defineProperties(CustomStyle, {\n /*\n CustomStyle.processHook is provided to customize the