4 window.CoreStyle = window.CoreStyle || {
\r
10 Polymer('core-style', {
\r
12 * The `id` property should be set if the `core-style` is a producer
\r
13 * of styles. In this case, the `core-style` should have text content
\r
24 * The `ref` property should be set if the `core-style` element is a
\r
25 * consumer of styles. Set it to the `id` of the desired `core-style`
\r
37 refMap: CoreStyle.refMap,
\r
40 * The `list` is a map of all `core-style` producers stored by `id`. It
\r
41 * should be considered readonly. It's useful for nesting one `core-style`
\r
45 * @type object (readonly)
\r
46 * @default {map of all `core-style` producers}
\r
48 list: CoreStyle.list,
\r
50 // if we have an id, we provide style
\r
51 // if we have a ref, we consume/require style
\r
56 this.registerRef(this.ref);
\r
57 if (!window.ShadowDOMPolyfill) {
\r
63 // can't shim until attached if using SD polyfill because need to find host
\r
64 attached: function() {
\r
65 if (!this.id && window.ShadowDOMPolyfill) {
\r
70 /****** producer stuff *******/
\r
72 provide: function() {
\r
74 // we want to do this asap, especially so we can do so before definitions
\r
75 // that use this core-style are registered.
\r
76 if (this.textContent) {
\r
77 this._completeProvide();
\r
79 this.async(this._completeProvide);
\r
83 register: function() {
\r
84 var i = this.list[this.id];
\r
86 if (!Array.isArray(i)) {
\r
87 this.list[this.id] = [i];
\r
89 this.list[this.id].push(this);
\r
91 this.list[this.id] = this;
\r
95 // stamp into a shadowRoot so we can monitor dom of the bound output
\r
96 _completeProvide: function() {
\r
97 this.createShadowRoot();
\r
98 this.domObserver = new MutationObserver(this.domModified.bind(this))
\r
99 .observe(this.shadowRoot, {subtree: true,
\r
100 characterData: true, childList: true});
\r
101 this.provideContent();
\r
104 provideContent: function() {
\r
105 this.ensureTemplate();
\r
106 this.shadowRoot.textContent = '';
\r
107 this.shadowRoot.appendChild(this.instanceTemplate(this.template));
\r
108 this.cssText = this.shadowRoot.textContent;
\r
111 ensureTemplate: function() {
\r
112 if (!this.template) {
\r
113 this.template = this.querySelector('template:not([repeat]):not([bind])');
\r
114 // move content into the template
\r
115 if (!this.template) {
\r
116 this.template = document.createElement('template');
\r
117 var n = this.firstChild;
\r
119 this.template.content.appendChild(n.cloneNode(true));
\r
126 domModified: function() {
\r
127 this.cssText = this.shadowRoot.textContent;
\r
131 // notify instances that reference this element
\r
132 notify: function() {
\r
133 var s$ = this.refMap[this.id];
\r
135 for (var i=0, s; (s=s$[i]); i++) {
\r
141 /****** consumer stuff *******/
\r
143 registerRef: function(ref) {
\r
144 //console.log('register', ref);
\r
145 this.refMap[this.ref] = this.refMap[this.ref] || [];
\r
146 this.refMap[this.ref].push(this);
\r
149 applyRef: function(ref) {
\r
151 this.registerRef(this.ref);
\r
155 require: function() {
\r
156 var cssText = this.cssTextForRef(this.ref);
\r
157 //console.log('require', this.ref, cssText);
\r
159 this.ensureStyleElement();
\r
160 // do nothing if cssText has not changed
\r
161 if (this.styleElement._cssText === cssText) {
\r
164 this.styleElement._cssText = cssText;
\r
165 if (window.ShadowDOMPolyfill) {
\r
166 this.styleElement.textContent = cssText;
\r
167 cssText = Platform.ShadowCSS.shimStyle(this.styleElement,
\r
168 this.getScopeSelector());
\r
170 this.styleElement.textContent = cssText;
\r
174 cssTextForRef: function(ref) {
\r
175 var s$ = this.byId(ref);
\r
178 if (Array.isArray(s$)) {
\r
180 for (var i=0, l=s$.length, s; (i<l) && (s=s$[i]); i++) {
\r
183 cssText = p.join('\n\n');
\r
185 cssText = s$.cssText;
\r
188 if (s$ && !cssText) {
\r
189 console.warn('No styles provided for ref:', ref);
\r
194 byId: function(id) {
\r
195 return this.list[id];
\r
198 ensureStyleElement: function() {
\r
199 if (!this.styleElement) {
\r
200 this.styleElement = window.ShadowDOMPolyfill ?
\r
201 this.makeShimStyle() :
\r
202 this.makeRootStyle();
\r
204 if (!this.styleElement) {
\r
205 console.warn(this.localName, 'could not setup style.');
\r
209 makeRootStyle: function() {
\r
210 var style = document.createElement('style');
\r
211 this.appendChild(style);
\r
215 makeShimStyle: function() {
\r
216 var host = this.findHost(this);
\r
218 var name = host.localName;
\r
219 var style = document.querySelector('style[' + name + '=' + this.ref +']');
\r
221 style = document.createElement('style');
\r
222 style.setAttribute(name, this.ref);
\r
223 document.head.appendChild(style);
\r
229 getScopeSelector: function() {
\r
230 if (!this._scopeSelector) {
\r
231 var selector = '', host = this.findHost(this);
\r
233 var typeExtension = host.hasAttribute('is');
\r
234 var name = typeExtension ? host.getAttribute('is') : host.localName;
\r
235 selector = Platform.ShadowCSS.makeScopeSelector(name,
\r
238 this._scopeSelector = selector;
\r
240 return this._scopeSelector;
\r
243 findHost: function(node) {
\r
244 while (node.parentNode) {
\r
245 node = node.parentNode;
\r
247 return node.host || wrap(document.documentElement);
\r
251 // TODO(dfreedm): add more filters!
\r
253 cycle: function(rgb, amount) {
\r
254 if (rgb.match('#')) {
\r
255 var o = this.hexToRgb(rgb);
\r
259 rgb = 'rgb(' + o.r + ',' + o.b + ',' + o.g + ')';
\r
262 function cycleChannel(v) {
\r
263 return Math.abs((Number(v) - amount) % 255);
\r
266 return rgb.replace(/rgb\(([^,]*),([^,]*),([^,]*)\)/, function(m, a, b, c) {
\r
267 return 'rgb(' + cycleChannel(a) + ',' + cycleChannel(b) + ', '
\r
268 + cycleChannel(c) + ')';
\r
272 hexToRgb: function(hex) {
\r
273 var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
\r
275 r: parseInt(result[1], 16),
\r
276 g: parseInt(result[2], 16),
\r
277 b: parseInt(result[3], 16)
\r