Remove LOAD_SUB_FRAME load flag.
[chromium-blink-merge.git] / third_party / polymer / components / core-style / core-style.html
blob2396041eee037171254cb94eac503b258a21f3b8
1 <!--
2 Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
3 This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
4 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
5 The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
6 Code distributed by Google as part of the polymer project is also
7 subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
8 -->
9 <!--
11 The `core-style` element helps manage styling inside other elements and can
12 be used to make themes. The `core-style` element can be either a producer
13 or consumer of styling. If it has its `id` property set, it's a producer.
14 Elements that are producers should include css styling as their text content.
15 If a `core-style` has its `ref` property set, it's a consumer. A `core-style`
16 typically sets its `ref` property to the value of the `id` property of the
17 `core-style` it wants to use. This allows a single producer to be used in
18 multiple places, for example, in many different elements.
20 It's common to place `core-style` producer elements inside HTMLImports.
21 Remote stylesheets should be included this way, the &#64;import css mechanism is
22 not currently supported.
24 Here's a basic example:
26 <polymer-element name="x-test" noscript>
27 <template>
28 <core-style ref="x-test"></core-style>
29 <content></content>
30 </template>
31 </polymer-element>
33 The `x-test` element above will be styled by any `core-style` elements that have
34 `id` set to `x-test`. These `core-style` producers are separate from the element
35 definition, allowing a user of the element to style it independent of the author's
36 styling. For example:
38 <core-style id="x-test">
39 :host {
40 backgound-color: steelblue;
42 </core-style>
44 The content of the `x-test` `core-style` producer gets included inside the
45 shadowRoot of the `x-test` element. If the content of the `x-test` producer
46 `core-style` changes, all consumers of it are automatically kept in sync. This
47 allows updating styling on the fly.
49 The `core-style` element also supports bindings, in which case the producer
50 `core-style` element is the model. Here's an example:
52 <core-style id="x-test">
53 :host {
54 background-color: {{myColor}};
56 </core-style>
57 <script>
58 document._currentScript.ownerDocument.getElementById('x-test').myColor = 'orange';
59 </script>
61 Finally, to facilitate sharing data between `core-style` elements, all
62 `core-style` elements have a `g` property which is set to the global
63 `CoreStyle.g`. Here's an example:
65 <core-style id="x-test">
66 :host {
67 background-color: {{g.myColor}};
69 </core-style>
70 <script>
71 CoreStyle.g.myColor = 'tomato';
72 </script>
74 Finally, one `core-style` can be nested inside another. The `core-style`
75 element has a `list` property which is a map of all the `core-style` producers.
76 A `core-style` producer's content is available via its `cssText` property.
77 Putting this together:
79 <core-style id="common">
80 :host {
81 font-family: sans-serif;
83 </core-style>
85 <core-style id="x-test">
86 {{list.common.cssText}}
88 :host {
89 background-color: {{g.myColor}};
91 </core-style>
94 @group Polymer Core Elements
95 @element core-style
96 @homepage github.io
97 -->
99 <link rel="import" href="../polymer/polymer.html">
101 <polymer-element name="core-style" hidden>
102 <script>
103 (function() {
105 window.CoreStyle = window.CoreStyle || {
106 g: {},
107 list: {},
108 refMap: {}
111 Polymer('core-style', {
113 * The `id` property should be set if the `core-style` is a producer
114 * of styles. In this case, the `core-style` should have text content
115 * that is cssText.
117 * @attribute id
118 * @type string
119 * @default ''
123 publish: {
125 * The `ref` property should be set if the `core-style` element is a
126 * consumer of styles. Set it to the `id` of the desired `core-style`
127 * element.
129 * @attribute ref
130 * @type string
131 * @default ''
133 ref: ''
136 // static
137 g: CoreStyle.g,
138 refMap: CoreStyle.refMap,
141 * The `list` is a map of all `core-style` producers stored by `id`. It
142 * should be considered readonly. It's useful for nesting one `core-style`
143 * inside another.
145 * @attribute list
146 * @type object (readonly)
147 * @default {map of all `core-style` producers}
149 list: CoreStyle.list,
151 // if we have an id, we provide style
152 // if we have a ref, we consume/require style
153 ready: function() {
154 if (this.id) {
155 this.provide();
156 } else {
157 this.registerRef(this.ref);
158 if (!window.ShadowDOMPolyfill) {
159 this.require();
164 // can't shim until attached if using SD polyfill because need to find host
165 attached: function() {
166 if (!this.id && window.ShadowDOMPolyfill) {
167 this.require();
171 /****** producer stuff *******/
173 provide: function() {
174 this.register();
175 // we want to do this asap, especially so we can do so before definitions
176 // that use this core-style are registered.
177 if (this.textContent) {
178 this._completeProvide();
179 } else {
180 this.async(this._completeProvide);
184 register: function() {
185 var i = this.list[this.id];
186 if (i) {
187 if (!Array.isArray(i)) {
188 this.list[this.id] = [i];
190 this.list[this.id].push(this);
191 } else {
192 this.list[this.id] = this;
196 // stamp into a shadowRoot so we can monitor dom of the bound output
197 _completeProvide: function() {
198 this.createShadowRoot();
199 this.domObserver = new MutationObserver(this.domModified.bind(this))
200 .observe(this.shadowRoot, {subtree: true,
201 characterData: true, childList: true});
202 this.provideContent();
205 provideContent: function() {
206 this.ensureTemplate();
207 this.shadowRoot.textContent = '';
208 this.shadowRoot.appendChild(this.instanceTemplate(this.template));
209 this.cssText = this.shadowRoot.textContent;
212 ensureTemplate: function() {
213 if (!this.template) {
214 this.template = this.querySelector('template:not([repeat]):not([bind])');
215 // move content into the template
216 if (!this.template) {
217 this.template = document.createElement('template');
218 var n = this.firstChild;
219 while (n) {
220 this.template.content.appendChild(n.cloneNode(true));
221 n = n.nextSibling;
227 domModified: function() {
228 this.cssText = this.shadowRoot.textContent;
229 this.notify();
232 // notify instances that reference this element
233 notify: function() {
234 var s$ = this.refMap[this.id];
235 if (s$) {
236 for (var i=0, s; (s=s$[i]); i++) {
237 s.require();
242 /****** consumer stuff *******/
244 registerRef: function(ref) {
245 //console.log('register', ref);
246 this.refMap[this.ref] = this.refMap[this.ref] || [];
247 this.refMap[this.ref].push(this);
250 applyRef: function(ref) {
251 this.ref = ref;
252 this.registerRef(this.ref);
253 this.require();
256 require: function() {
257 var cssText = this.cssTextForRef(this.ref);
258 //console.log('require', this.ref, cssText);
259 if (cssText) {
260 this.ensureStyleElement();
261 // do nothing if cssText has not changed
262 if (this.styleElement._cssText === cssText) {
263 return;
265 this.styleElement._cssText = cssText;
266 if (window.ShadowDOMPolyfill) {
267 this.styleElement.textContent = cssText;
268 cssText = WebComponents.ShadowCSS.shimStyle(this.styleElement,
269 this.getScopeSelector());
271 this.styleElement.textContent = cssText;
275 cssTextForRef: function(ref) {
276 var s$ = this.byId(ref);
277 var cssText = '';
278 if (s$) {
279 if (Array.isArray(s$)) {
280 var p = [];
281 for (var i=0, l=s$.length, s; (i<l) && (s=s$[i]); i++) {
282 p.push(s.cssText);
284 cssText = p.join('\n\n');
285 } else {
286 cssText = s$.cssText;
289 if (s$ && !cssText) {
290 console.warn('No styles provided for ref:', ref);
292 return cssText;
295 byId: function(id) {
296 return this.list[id];
299 ensureStyleElement: function() {
300 if (!this.styleElement) {
301 this.styleElement = window.ShadowDOMPolyfill ?
302 this.makeShimStyle() :
303 this.makeRootStyle();
305 if (!this.styleElement) {
306 console.warn(this.localName, 'could not setup style.');
310 makeRootStyle: function() {
311 var style = document.createElement('style');
312 this.appendChild(style);
313 return style;
316 makeShimStyle: function() {
317 var host = this.findHost(this);
318 if (host) {
319 var name = host.localName;
320 var style = document.querySelector('style[' + name + '=' + this.ref +']');
321 if (!style) {
322 style = document.createElement('style');
323 style.setAttribute(name, this.ref);
324 document.head.appendChild(style);
326 return style;
330 getScopeSelector: function() {
331 if (!this._scopeSelector) {
332 var selector = '', host = this.findHost(this);
333 if (host) {
334 var typeExtension = host.hasAttribute('is');
335 var name = typeExtension ? host.getAttribute('is') : host.localName;
336 selector = WebComponents.ShadowCSS.makeScopeSelector(name,
337 typeExtension);
339 this._scopeSelector = selector;
341 return this._scopeSelector;
344 findHost: function(node) {
345 while (node.parentNode) {
346 node = node.parentNode;
348 return node.host || wrap(document.documentElement);
351 /* filters! */
352 // TODO(dfreedm): add more filters!
354 cycle: function(rgb, amount) {
355 if (rgb.match('#')) {
356 var o = this.hexToRgb(rgb);
357 if (!o) {
358 return rgb;
360 rgb = 'rgb(' + o.r + ',' + o.b + ',' + o.g + ')';
363 function cycleChannel(v) {
364 return Math.abs((Number(v) - amount) % 255);
367 return rgb.replace(/rgb\(([^,]*),([^,]*),([^,]*)\)/, function(m, a, b, c) {
368 return 'rgb(' + cycleChannel(a) + ',' + cycleChannel(b) + ', '
369 + cycleChannel(c) + ')';
373 hexToRgb: function(hex) {
374 var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
375 return result ? {
376 r: parseInt(result[1], 16),
377 g: parseInt(result[2], 16),
378 b: parseInt(result[3], 16)
379 } : null;
385 })();
386 </script>
387 </polymer-element>