• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/**
2@license
3Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
4This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
5The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
7Code distributed by Google as part of the polymer project is also
8subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
9*/
10
11'use strict';
12
13import ApplyShim from '../src/apply-shim.js';
14import templateMap from '../src/template-map.js';
15import {getIsExtends, toCssText, elementHasBuiltCss} from '../src/style-util.js';
16import * as ApplyShimUtils from '../src/apply-shim-utils.js';
17import {getComputedStyleValue, updateNativeProperties} from '../src/common-utils.js';
18import {CustomStyleInterfaceInterface} from '../src/custom-style-interface.js'; // eslint-disable-line no-unused-vars
19import {nativeCssVariables, nativeShadow, cssBuild} from '../src/style-settings.js';
20
21/** @const {ApplyShim} */
22const applyShim = new ApplyShim();
23
24class ApplyShimInterface {
25  constructor() {
26    /** @type {?CustomStyleInterfaceInterface} */
27    this.customStyleInterface = null;
28    applyShim['invalidCallback'] = ApplyShimUtils.invalidate;
29  }
30  ensure() {
31    if (this.customStyleInterface) {
32      return;
33    }
34    if (window.ShadyCSS.CustomStyleInterface) {
35      this.customStyleInterface =
36          /** @type {!CustomStyleInterfaceInterface} */ (
37              window.ShadyCSS.CustomStyleInterface);
38      this.customStyleInterface['transformCallback'] = (style) => {
39        applyShim.transformCustomStyle(style);
40      };
41      this.customStyleInterface['validateCallback'] = () => {
42        requestAnimationFrame(() => {
43          if (this.customStyleInterface['enqueued']) {
44            this.flushCustomStyles();
45          }
46        });
47      }
48    }
49  }
50  /**
51   * @param {!HTMLTemplateElement} template
52   * @param {string} elementName
53   */
54  prepareTemplate(template, elementName) {
55    this.ensure();
56    if (elementHasBuiltCss(template)) {
57      return;
58    }
59    templateMap[elementName] = template;
60    let ast = applyShim.transformTemplate(template, elementName);
61    // save original style ast to use for revalidating instances
62    template['_styleAst'] = ast;
63  }
64  flushCustomStyles() {
65    this.ensure();
66    if (!this.customStyleInterface) {
67      return;
68    }
69    let styles = this.customStyleInterface['processStyles']();
70    if (!this.customStyleInterface['enqueued']) {
71      return;
72    }
73    for (let i = 0; i < styles.length; i++ ) {
74      let cs = styles[i];
75      let style = this.customStyleInterface['getStyleForCustomStyle'](cs);
76      if (style) {
77        applyShim.transformCustomStyle(style);
78      }
79    }
80    this.customStyleInterface['enqueued'] = false;
81  }
82  /**
83   * @param {HTMLElement} element
84   * @param {Object=} properties
85   */
86  styleSubtree(element, properties) {
87    this.ensure();
88    if (properties) {
89      updateNativeProperties(element, properties);
90    }
91    if (element.shadowRoot) {
92      this.styleElement(element);
93      let shadowChildren =
94          /** @type {!ParentNode} */ (element.shadowRoot).children ||
95          element.shadowRoot.childNodes;
96      for (let i = 0; i < shadowChildren.length; i++) {
97        this.styleSubtree(/** @type {HTMLElement} */(shadowChildren[i]));
98      }
99    } else {
100      let children = element.children || element.childNodes;
101      for (let i = 0; i < children.length; i++) {
102        this.styleSubtree(/** @type {HTMLElement} */(children[i]));
103      }
104    }
105  }
106  /**
107   * @param {HTMLElement} element
108   */
109  styleElement(element) {
110    this.ensure();
111    let {is} = getIsExtends(element);
112    let template = templateMap[is];
113    if (template && elementHasBuiltCss(template)) {
114      return;
115    }
116    if (template && !ApplyShimUtils.templateIsValid(template)) {
117      // only revalidate template once
118      if (!ApplyShimUtils.templateIsValidating(template)) {
119        this.prepareTemplate(template, is);
120        ApplyShimUtils.startValidatingTemplate(template);
121      }
122      // update this element instance
123      let root = element.shadowRoot;
124      if (root) {
125        let style = /** @type {HTMLStyleElement} */(root.querySelector('style'));
126        if (style) {
127          // reuse the template's style ast, it has all the original css text
128          style['__cssRules'] = template['_styleAst'];
129          style.textContent = toCssText(template['_styleAst'])
130        }
131      }
132    }
133  }
134  /**
135   * @param {Object=} properties
136   */
137  styleDocument(properties) {
138    this.ensure();
139    this.styleSubtree(document.body, properties);
140  }
141}
142
143if (!window.ShadyCSS || !window.ShadyCSS.ScopingShim) {
144  const applyShimInterface = new ApplyShimInterface();
145  let CustomStyleInterface = window.ShadyCSS && window.ShadyCSS.CustomStyleInterface;
146
147  /** @suppress {duplicate} */
148  window.ShadyCSS = {
149    /**
150     * @param {!HTMLTemplateElement} template
151     * @param {string} elementName
152     * @param {string=} elementExtends
153     */
154    prepareTemplate(template, elementName, elementExtends) { // eslint-disable-line no-unused-vars
155      applyShimInterface.flushCustomStyles();
156      applyShimInterface.prepareTemplate(template, elementName);
157    },
158
159    /**
160     * @param {!HTMLTemplateElement} template
161     * @param {string} elementName
162     * @param {string=} elementExtends
163     */
164    prepareTemplateStyles(template, elementName, elementExtends) {
165      window.ShadyCSS.prepareTemplate(template, elementName, elementExtends);
166    },
167
168    /**
169     * @param {!HTMLTemplateElement} template
170     * @param {string} elementName
171     */
172    prepareTemplateDom(template, elementName) {}, // eslint-disable-line no-unused-vars
173
174    /**
175     * @param {!HTMLElement} element
176     * @param {Object=} properties
177     */
178    styleSubtree(element, properties) {
179      applyShimInterface.flushCustomStyles();
180      applyShimInterface.styleSubtree(element, properties);
181    },
182
183    /**
184     * @param {!HTMLElement} element
185     */
186    styleElement(element) {
187      applyShimInterface.flushCustomStyles();
188      applyShimInterface.styleElement(element);
189    },
190
191    /**
192     * @param {Object=} properties
193     */
194    styleDocument(properties) {
195      applyShimInterface.flushCustomStyles();
196      applyShimInterface.styleDocument(properties);
197    },
198
199    /**
200     * @param {Element} element
201     * @param {string} property
202     * @return {string}
203     */
204    getComputedStyleValue(element, property) {
205      return getComputedStyleValue(element, property);
206    },
207
208    flushCustomStyles() {
209      applyShimInterface.flushCustomStyles();
210    },
211
212    nativeCss: nativeCssVariables,
213    nativeShadow: nativeShadow,
214    cssBuild: cssBuild
215  };
216
217  if (CustomStyleInterface) {
218    window.ShadyCSS.CustomStyleInterface = CustomStyleInterface;
219  }
220}
221
222window.ShadyCSS.ApplyShim = applyShim;
223