| OLD | NEW |
| (Empty) | |
| 1 /** |
| 2 @license |
| 3 Copyright (c) 2017 The Polymer Project Authors. All rights reserved. |
| 4 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt |
| 5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |
| 6 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt |
| 7 Code distributed by Google as part of the polymer project is also |
| 8 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt |
| 9 */ |
| 10 |
| 11 'use strict'; |
| 12 |
| 13 import documentWait from './document-wait.js' |
| 14 |
| 15 /** |
| 16 * @typedef {HTMLStyleElement | {getStyle: function():HTMLStyleElement}} |
| 17 */ |
| 18 export let CustomStyleProvider; |
| 19 |
| 20 const SEEN_MARKER = '__seenByShadyCSS'; |
| 21 const CACHED_STYLE = '__shadyCSSCachedStyle'; |
| 22 |
| 23 /** @type {?function(!HTMLStyleElement)} */ |
| 24 let transformFn = null; |
| 25 |
| 26 /** @type {?function()} */ |
| 27 let validateFn = null; |
| 28 |
| 29 /** |
| 30 This interface is provided to add document-level <style> elements to ShadyCSS fo
r processing. |
| 31 These styles must be processed by ShadyCSS to simulate ShadowRoot upper-bound en
capsulation from outside styles |
| 32 In addition, these styles may also need to be processed for @apply rules and CSS
Custom Properties |
| 33 |
| 34 To add document-level styles to ShadyCSS, one can call `ShadyCSS.addDocumentStyl
e(styleElement)` or `ShadyCSS.addDocumentStyle({getStyle: () => styleElement})` |
| 35 |
| 36 In addition, if the process used to discover document-level styles can be synchr
onously flushed, one should set `ShadyCSS.documentStyleFlush`. |
| 37 This function will be called when calculating styles. |
| 38 |
| 39 An example usage of the document-level styling api can be found in `examples/doc
ument-style-lib.js` |
| 40 |
| 41 @unrestricted |
| 42 */ |
| 43 export default class CustomStyleInterface { |
| 44 constructor() { |
| 45 /** @type {!Array<!CustomStyleProvider>} */ |
| 46 this['customStyles'] = []; |
| 47 this['enqueued'] = false; |
| 48 } |
| 49 /** |
| 50 * Queue a validation for new custom styles to batch style recalculations |
| 51 */ |
| 52 enqueueDocumentValidation() { |
| 53 if (this['enqueued'] || !validateFn) { |
| 54 return; |
| 55 } |
| 56 this['enqueued'] = true; |
| 57 documentWait(validateFn); |
| 58 } |
| 59 /** |
| 60 * @param {!HTMLStyleElement} style |
| 61 */ |
| 62 addCustomStyle(style) { |
| 63 if (!style[SEEN_MARKER]) { |
| 64 style[SEEN_MARKER] = true; |
| 65 this['customStyles'].push(style); |
| 66 this.enqueueDocumentValidation(); |
| 67 } |
| 68 } |
| 69 /** |
| 70 * @param {!CustomStyleProvider} customStyle |
| 71 * @return {HTMLStyleElement} |
| 72 */ |
| 73 getStyleForCustomStyle(customStyle) { |
| 74 if (customStyle[CACHED_STYLE]) { |
| 75 return customStyle[CACHED_STYLE]; |
| 76 } |
| 77 let style; |
| 78 if (customStyle['getStyle']) { |
| 79 style = customStyle['getStyle'](); |
| 80 } else { |
| 81 style = customStyle; |
| 82 } |
| 83 return style; |
| 84 } |
| 85 /** |
| 86 * @return {!Array<!CustomStyleProvider>} |
| 87 */ |
| 88 processStyles() { |
| 89 let cs = this['customStyles']; |
| 90 for (let i = 0; i < cs.length; i++) { |
| 91 let customStyle = cs[i]; |
| 92 if (customStyle[CACHED_STYLE]) { |
| 93 continue; |
| 94 } |
| 95 let style = this.getStyleForCustomStyle(customStyle); |
| 96 if (style) { |
| 97 // HTMLImports polyfill may have cloned the style into the main document
, |
| 98 // which is referenced with __appliedElement. |
| 99 // Also, we must copy over the attributes. |
| 100 let appliedStyle = /** @type {HTMLStyleElement} */(style['__appliedEleme
nt']); |
| 101 if (appliedStyle) { |
| 102 for (let i = 0; i < style.attributes.length; i++) { |
| 103 let attr = style.attributes[i]; |
| 104 appliedStyle.setAttribute(attr.name, attr.value); |
| 105 } |
| 106 } |
| 107 let styleToTransform = appliedStyle || style; |
| 108 if (transformFn) { |
| 109 transformFn(styleToTransform); |
| 110 } |
| 111 customStyle[CACHED_STYLE] = styleToTransform; |
| 112 } |
| 113 } |
| 114 return cs; |
| 115 } |
| 116 } |
| 117 |
| 118 CustomStyleInterface.prototype['addCustomStyle'] = CustomStyleInterface.prototyp
e.addCustomStyle; |
| 119 CustomStyleInterface.prototype['getStyleForCustomStyle'] = CustomStyleInterface.
prototype.getStyleForCustomStyle; |
| 120 CustomStyleInterface.prototype['processStyles'] = CustomStyleInterface.prototype
.processStyles; |
| 121 |
| 122 Object.defineProperties(CustomStyleInterface.prototype, { |
| 123 'transformCallback': { |
| 124 /** @return {?function(!HTMLStyleElement)} */ |
| 125 get() { |
| 126 return transformFn; |
| 127 }, |
| 128 /** @param {?function(!HTMLStyleElement)} fn */ |
| 129 set(fn) { |
| 130 transformFn = fn; |
| 131 } |
| 132 }, |
| 133 'validateCallback': { |
| 134 /** @return {?function()} */ |
| 135 get() { |
| 136 return validateFn; |
| 137 }, |
| 138 /** |
| 139 * @param {?function()} fn |
| 140 * @this {CustomStyleInterface} |
| 141 */ |
| 142 set(fn) { |
| 143 let needsEnqueue = false; |
| 144 if (!validateFn) { |
| 145 needsEnqueue = true; |
| 146 } |
| 147 validateFn = fn; |
| 148 if (needsEnqueue) { |
| 149 this.enqueueDocumentValidation(); |
| 150 } |
| 151 }, |
| 152 } |
| 153 }) |
| 154 |
| 155 /** @typedef {{ |
| 156 * customStyles: !Array<!CustomStyleProvider>, |
| 157 * addCustomStyle: function(!CustomStyleProvider), |
| 158 * getStyleForCustomStyle: function(!CustomStyleProvider): HTMLStyleElement, |
| 159 * findStyles: function(), |
| 160 * transformCallback: ?function(!HTMLStyleElement), |
| 161 * validateCallback: ?function() |
| 162 * }} |
| 163 */ |
| 164 export let CustomStyleInterfaceInterface; |
| OLD | NEW |