UNPKG

five-bells-visualization

Version:
388 lines (333 loc) 10.9 kB
<!-- Copyright (c) 2014 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 --> <!-- The `core-style` element helps manage styling inside other elements and can be used to make themes. The `core-style` element can be either a producer or consumer of styling. If it has its `id` property set, it's a producer. Elements that are producers should include css styling as their text content. If a `core-style` has its `ref` property set, it's a consumer. A `core-style` typically sets its `ref` property to the value of the `id` property of the `core-style` it wants to use. This allows a single producer to be used in multiple places, for example, in many different elements. It's common to place `core-style` producer elements inside HTMLImports. Remote stylesheets should be included this way, the &#64;import css mechanism is not currently supported. Here's a basic example: <polymer-element name="x-test" noscript> <template> <core-style ref="x-test"></core-style> <content></content> </template> </polymer-element> The `x-test` element above will be styled by any `core-style` elements that have `id` set to `x-test`. These `core-style` producers are separate from the element definition, allowing a user of the element to style it independent of the author's styling. For example: <core-style id="x-test"> :host { background-color: steelblue; } </core-style> The content of the `x-test` `core-style` producer gets included inside the shadowRoot of the `x-test` element. If the content of the `x-test` producer `core-style` changes, all consumers of it are automatically kept in sync. This allows updating styling on the fly. The `core-style` element also supports bindings, in which case the producer `core-style` element is the model. Here's an example: <core-style id="x-test"> :host { background-color: {{myColor}}; } </core-style> <script> document._currentScript.ownerDocument.getElementById('x-test').myColor = 'orange'; </script> Finally, to facilitate sharing data between `core-style` elements, all `core-style` elements have a `g` property which is set to the global `CoreStyle.g`. Here's an example: <core-style id="x-test"> :host { background-color: {{g.myColor}}; } </core-style> <script> CoreStyle.g.myColor = 'tomato'; </script> Finally, one `core-style` can be nested inside another. The `core-style` element has a `list` property which is a map of all the `core-style` producers. A `core-style` producer's content is available via its `cssText` property. Putting this together: <core-style id="common"> :host { font-family: sans-serif; } </core-style> <core-style id="x-test"> {{list.common.cssText}} :host { background-color: {{g.myColor}}; } </core-style> @group Polymer Core Elements @element core-style @homepage github.io --> <link rel="import" href="../polymer/polymer.html"> <polymer-element name="core-style" hidden> <script> (function() { window.CoreStyle = window.CoreStyle || { g: {}, list: {}, refMap: {} }; Polymer('core-style', { /** * The `id` property should be set if the `core-style` is a producer * of styles. In this case, the `core-style` should have text content * that is cssText. * * @attribute id * @type string * @default '' */ publish: { /** * The `ref` property should be set if the `core-style` element is a * consumer of styles. Set it to the `id` of the desired `core-style` * element. * * @attribute ref * @type string * @default '' */ ref: '' }, // static g: CoreStyle.g, refMap: CoreStyle.refMap, /** * The `list` is a map of all `core-style` producers stored by `id`. It * should be considered readonly. It's useful for nesting one `core-style` * inside another. * * @attribute list * @type object * @default {map of all `core-style` producers} */ list: CoreStyle.list, // if we have an id, we provide style // if we have a ref, we consume/require style ready: function() { if (this.id) { this.provide(); } else { this.registerRef(this.ref); if (!window.ShadowDOMPolyfill) { this.require(); } } }, // can't shim until attached if using SD polyfill because need to find host attached: function() { if (!this.id && window.ShadowDOMPolyfill) { this.require(); } }, /****** producer stuff *******/ provide: function() { this.register(); // we want to do this asap, especially so we can do so before definitions // that use this core-style are registered. if (this.textContent) { this._completeProvide(); } else { this.async(this._completeProvide); } }, register: function() { var i = this.list[this.id]; if (i) { if (!Array.isArray(i)) { this.list[this.id] = [i]; } this.list[this.id].push(this); } else { this.list[this.id] = this; } }, // stamp into a shadowRoot so we can monitor dom of the bound output _completeProvide: function() { this.createShadowRoot(); this.domObserver = new MutationObserver(this.domModified.bind(this)) .observe(this.shadowRoot, {subtree: true, characterData: true, childList: true}); this.provideContent(); }, provideContent: function() { this.ensureTemplate(); this.shadowRoot.textContent = ''; this.shadowRoot.appendChild(this.instanceTemplate(this.template)); this.cssText = this.shadowRoot.textContent; }, ensureTemplate: function() { if (!this.template) { this.template = this.querySelector('template:not([repeat]):not([bind])'); // move content into the template if (!this.template) { this.template = document.createElement('template'); var n = this.firstChild; while (n) { this.template.content.appendChild(n.cloneNode(true)); n = n.nextSibling; } } } }, domModified: function() { this.cssText = this.shadowRoot.textContent; this.notify(); }, // notify instances that reference this element notify: function() { var s$ = this.refMap[this.id]; if (s$) { for (var i=0, s; (s=s$[i]); i++) { s.require(); } } }, /****** consumer stuff *******/ registerRef: function(ref) { //console.log('register', ref); this.refMap[this.ref] = this.refMap[this.ref] || []; this.refMap[this.ref].push(this); }, applyRef: function(ref) { this.ref = ref; this.registerRef(this.ref); this.require(); }, require: function() { var cssText = this.cssTextForRef(this.ref); //console.log('require', this.ref, cssText); if (cssText) { this.ensureStyleElement(); // do nothing if cssText has not changed if (this.styleElement._cssText === cssText) { return; } this.styleElement._cssText = cssText; if (window.ShadowDOMPolyfill) { this.styleElement.textContent = cssText; cssText = WebComponents.ShadowCSS.shimStyle(this.styleElement, this.getScopeSelector()); } this.styleElement.textContent = cssText; } }, cssTextForRef: function(ref) { var s$ = this.byId(ref); var cssText = ''; if (s$) { if (Array.isArray(s$)) { var p = []; for (var i=0, l=s$.length, s; (i<l) && (s=s$[i]); i++) { p.push(s.cssText); } cssText = p.join('\n\n'); } else { cssText = s$.cssText; } } if (s$ && !cssText) { console.warn('No styles provided for ref:', ref); } return cssText; }, byId: function(id) { return this.list[id]; }, ensureStyleElement: function() { if (!this.styleElement) { this.styleElement = window.ShadowDOMPolyfill ? this.makeShimStyle() : this.makeRootStyle(); } if (!this.styleElement) { console.warn(this.localName, 'could not setup style.'); } }, makeRootStyle: function() { var style = document.createElement('style'); this.appendChild(style); return style; }, makeShimStyle: function() { var host = this.findHost(this); if (host) { var name = host.localName; var style = document.querySelector('style[' + name + '=' + this.ref +']'); if (!style) { style = document.createElement('style'); style.setAttribute(name, this.ref); document.head.appendChild(style); } return style; } }, getScopeSelector: function() { if (!this._scopeSelector) { var selector = '', host = this.findHost(this); if (host) { var typeExtension = host.hasAttribute('is'); var name = typeExtension ? host.getAttribute('is') : host.localName; selector = WebComponents.ShadowCSS.makeScopeSelector(name, typeExtension); } this._scopeSelector = selector; } return this._scopeSelector; }, findHost: function(node) { while (node.parentNode) { node = node.parentNode; } return node.host || wrap(document.documentElement); }, /* filters! */ // TODO(dfreedm): add more filters! cycle: function(rgb, amount) { if (rgb.match('#')) { var o = this.hexToRgb(rgb); if (!o) { return rgb; } rgb = 'rgb(' + o.r + ',' + o.b + ',' + o.g + ')'; } function cycleChannel(v) { return Math.abs((Number(v) - amount) % 255); } return rgb.replace(/rgb\(([^,]*),([^,]*),([^,]*)\)/, function(m, a, b, c) { return 'rgb(' + cycleChannel(a) + ',' + cycleChannel(b) + ', ' + cycleChannel(c) + ')'; }); }, hexToRgb: function(hex) { var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) } : null; } }); })(); </script> </polymer-element>