| Index: third_party/polymer/components/core-style/core-style.html
|
| diff --git a/third_party/polymer/components/core-style/core-style.html b/third_party/polymer/components/core-style/core-style.html
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..d0aaf5295faebe39fd2ea2747783086194ed4991
|
| --- /dev/null
|
| +++ b/third_party/polymer/components/core-style/core-style.html
|
| @@ -0,0 +1,387 @@
|
| +<!--
|
| +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 @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 {
|
| + backgound-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 and it is the producer
|
| +`core-style` element is the model for its content. 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 (readonly)
|
| + * @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 = Platform.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 = Platform.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>
|
|
|