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'; 12import templateMap from './template-map.js'; 13import {StyleNode} from './css-parse.js'; // eslint-disable-line no-unused-vars 14 15/* 16 * Utilities for handling invalidating apply-shim mixins for a given template. 17 * 18 * The invalidation strategy involves keeping track of the "current" version of a template's mixins, and updating that count when a mixin is invalidated. 19 * The template 20 */ 21 22/** @const {string} */ 23const CURRENT_VERSION = '_applyShimCurrentVersion'; 24 25/** @const {string} */ 26const NEXT_VERSION = '_applyShimNextVersion'; 27 28/** @const {string} */ 29const VALIDATING_VERSION = '_applyShimValidatingVersion'; 30 31/** 32 * @const {Promise<void>} 33 */ 34const promise = Promise.resolve(); 35 36/** 37 * @param {string} elementName 38 */ 39export function invalidate(elementName){ 40 let template = templateMap[elementName]; 41 if (template) { 42 invalidateTemplate(template); 43 } 44} 45 46/** 47 * This function can be called multiple times to mark a template invalid 48 * and signal that the style inside must be regenerated. 49 * 50 * Use `startValidatingTemplate` to begin an asynchronous validation cycle. 51 * During that cycle, call `templateIsValidating` to see if the template must 52 * be revalidated 53 * @param {HTMLTemplateElement} template 54 */ 55export function invalidateTemplate(template) { 56 // default the current version to 0 57 template[CURRENT_VERSION] = template[CURRENT_VERSION] || 0; 58 // ensure the "validating for" flag exists 59 template[VALIDATING_VERSION] = template[VALIDATING_VERSION] || 0; 60 // increment the next version 61 template[NEXT_VERSION] = (template[NEXT_VERSION] || 0) + 1; 62} 63 64/** 65 * @param {string} elementName 66 * @return {boolean} 67 */ 68export function isValid(elementName) { 69 let template = templateMap[elementName]; 70 if (template) { 71 return templateIsValid(template); 72 } 73 return true; 74} 75 76/** 77 * @param {HTMLTemplateElement} template 78 * @return {boolean} 79 */ 80export function templateIsValid(template) { 81 return template[CURRENT_VERSION] === template[NEXT_VERSION]; 82} 83 84/** 85 * @param {string} elementName 86 * @return {boolean} 87 */ 88export function isValidating(elementName) { 89 let template = templateMap[elementName]; 90 if (template) { 91 return templateIsValidating(template); 92 } 93 return false; 94} 95 96/** 97 * Returns true if the template is currently invalid and `startValidating` has been called since the last invalidation. 98 * If false, the template must be validated. 99 * @param {HTMLTemplateElement} template 100 * @return {boolean} 101 */ 102export function templateIsValidating(template) { 103 return !templateIsValid(template) && template[VALIDATING_VERSION] === template[NEXT_VERSION]; 104} 105 106/** 107 * the template is marked as `validating` for one microtask so that all instances 108 * found in the tree crawl of `applyStyle` will update themselves, 109 * but the template will only be updated once. 110 * @param {string} elementName 111*/ 112export function startValidating(elementName) { 113 let template = templateMap[elementName]; 114 startValidatingTemplate(template); 115} 116 117/** 118 * Begin an asynchronous invalidation cycle. 119 * This should be called after every validation of a template 120 * 121 * After one microtask, the template will be marked as valid until the next call to `invalidateTemplate` 122 * @param {HTMLTemplateElement} template 123 */ 124export function startValidatingTemplate(template) { 125 // remember that the current "next version" is the reason for this validation cycle 126 template[VALIDATING_VERSION] = template[NEXT_VERSION]; 127 // however, there only needs to be one async task to clear the counters 128 if (!template._validating) { 129 template._validating = true; 130 promise.then(function() { 131 // sync the current version to let future invalidations cause a refresh cycle 132 template[CURRENT_VERSION] = template[NEXT_VERSION]; 133 template._validating = false; 134 }); 135 } 136} 137 138/** 139 * @return {boolean} 140 */ 141export function elementsAreInvalid() { 142 for (let elementName in templateMap) { 143 let template = templateMap[elementName]; 144 if (!templateIsValid(template)) { 145 return true; 146 } 147 } 148 return false; 149} 150