| /** |
| @license |
| Copyright (c) 2017 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 |
| */ |
| |
| 'use strict'; |
| import templateMap from './template-map.js'; |
| import {StyleNode} from './css-parse.js'; // eslint-disable-line no-unused-vars |
| |
| /* |
| * Utilities for handling invalidating apply-shim mixins for a given template. |
| * |
| * The invalidation strategy involves keeping track of the "current" version of a template's mixins, and updating that count when a mixin is invalidated. |
| * The template |
| */ |
| |
| /** @const {string} */ |
| const CURRENT_VERSION = '_applyShimCurrentVersion'; |
| |
| /** @const {string} */ |
| const NEXT_VERSION = '_applyShimNextVersion'; |
| |
| /** @const {string} */ |
| const VALIDATING_VERSION = '_applyShimValidatingVersion'; |
| |
| /** |
| * @const {Promise<void>} |
| */ |
| const promise = Promise.resolve(); |
| |
| /** |
| * @param {string} elementName |
| */ |
| export function invalidate(elementName){ |
| let template = templateMap[elementName]; |
| if (template) { |
| invalidateTemplate(template); |
| } |
| } |
| |
| /** |
| * This function can be called multiple times to mark a template invalid |
| * and signal that the style inside must be regenerated. |
| * |
| * Use `startValidatingTemplate` to begin an asynchronous validation cycle. |
| * During that cycle, call `templateIsValidating` to see if the template must |
| * be revalidated |
| * @param {HTMLTemplateElement} template |
| */ |
| export function invalidateTemplate(template) { |
| // default the current version to 0 |
| template[CURRENT_VERSION] = template[CURRENT_VERSION] || 0; |
| // ensure the "validating for" flag exists |
| template[VALIDATING_VERSION] = template[VALIDATING_VERSION] || 0; |
| // increment the next version |
| template[NEXT_VERSION] = (template[NEXT_VERSION] || 0) + 1; |
| } |
| |
| /** |
| * @param {string} elementName |
| * @return {boolean} |
| */ |
| export function isValid(elementName) { |
| let template = templateMap[elementName]; |
| if (template) { |
| return templateIsValid(template); |
| } |
| return true; |
| } |
| |
| /** |
| * @param {HTMLTemplateElement} template |
| * @return {boolean} |
| */ |
| export function templateIsValid(template) { |
| return template[CURRENT_VERSION] === template[NEXT_VERSION]; |
| } |
| |
| /** |
| * @param {string} elementName |
| * @return {boolean} |
| */ |
| export function isValidating(elementName) { |
| let template = templateMap[elementName]; |
| if (template) { |
| return templateIsValidating(template); |
| } |
| return false; |
| } |
| |
| /** |
| * Returns true if the template is currently invalid and `startValidating` has been called since the last invalidation. |
| * If false, the template must be validated. |
| * @param {HTMLTemplateElement} template |
| * @return {boolean} |
| */ |
| export function templateIsValidating(template) { |
| return !templateIsValid(template) && template[VALIDATING_VERSION] === template[NEXT_VERSION]; |
| } |
| |
| /** |
| * 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. |
| * @param {string} elementName |
| */ |
| export function startValidating(elementName) { |
| let template = templateMap[elementName]; |
| startValidatingTemplate(template); |
| } |
| |
| /** |
| * Begin an asynchronous invalidation cycle. |
| * This should be called after every validation of a template |
| * |
| * After one microtask, the template will be marked as valid until the next call to `invalidateTemplate` |
| * @param {HTMLTemplateElement} template |
| */ |
| export function startValidatingTemplate(template) { |
| // remember that the current "next version" is the reason for this validation cycle |
| template[VALIDATING_VERSION] = template[NEXT_VERSION]; |
| // however, there only needs to be one async task to clear the counters |
| if (!template._validating) { |
| template._validating = true; |
| promise.then(function() { |
| // sync the current version to let future invalidations cause a refresh cycle |
| template[CURRENT_VERSION] = template[NEXT_VERSION]; |
| template._validating = false; |
| }); |
| } |
| } |
| |
| /** |
| * @return {boolean} |
| */ |
| export function elementsAreInvalid() { |
| for (let elementName in templateMap) { |
| let template = templateMap[elementName]; |
| if (!templateIsValid(template)) { |
| return true; |
| } |
| } |
| return false; |
| } |