1 2 Polymer('paper-shadow', { 3 4 publish: { 5 /** 6 * If set, the shadow is applied to this node. 7 * 8 * @attribute target 9 * @type Element 10 * @default null 11 */ 12 target: {value: null, reflect: true}, 13 14 /** 15 * The z-depth of this shadow, from 0-5. 16 * 17 * @attribute z 18 * @type number 19 * @default 1 20 */ 21 z: {value: 1, reflect: true}, 22 23 /** 24 * If true, the shadow animates between z-depth changes. 25 * 26 * @attribute animated 27 * @type boolean 28 * @default false 29 */ 30 animated: {value: false, reflect: true}, 31 32 /** 33 * Workaround: getComputedStyle is wrong sometimes so `paper-shadow` 34 * may overwrite the `position` CSS property. Set this property to 35 * true to prevent this. 36 * 37 * @attribute hasPosition 38 * @type boolean 39 * @default false 40 */ 41 hasPosition: {value: false} 42 }, 43 44 // NOTE: include template so that styles are loaded, but remove 45 // so that we can decide dynamically what part to include 46 registerCallback: function(polymerElement) { 47 var template = polymerElement.querySelector('template'); 48 this._style = template.content.querySelector('style'); 49 this._style.removeAttribute('no-shim'); 50 }, 51 52 fetchTemplate: function() { 53 return null; 54 }, 55 56 attached: function() { 57 this.installScopeStyle(this._style); 58 59 // If no target is bound at attach, default the target to the parent 60 // element or shadow host. 61 if (!this.target) { 62 if (!this.parentElement && this.parentNode.host) { 63 this.target = this.parentNode.host; 64 } else if (this.parentElement && (window.ShadowDOMPolyfill ? this.parentElement !== wrap(document.body) : this.parentElement !== document.body)) { 65 this.target = this.parentElement; 66 } 67 } 68 }, 69 70 targetChanged: function(old) { 71 if (old) { 72 this.removeShadow(old); 73 } 74 if (this.target) { 75 this.addShadow(this.target); 76 } 77 }, 78 79 zChanged: function(old) { 80 if (this.target && this.target._paperShadow) { 81 var shadow = this.target._paperShadow; 82 ['top', 'bottom'].forEach(function(s) { 83 shadow[s].classList.remove('paper-shadow-' + s + '-z-' + old); 84 shadow[s].classList.add('paper-shadow-' + s + '-z-' + this.z); 85 }.bind(this)); 86 } 87 }, 88 89 animatedChanged: function() { 90 if (this.target && this.target._paperShadow) { 91 var shadow = this.target._paperShadow; 92 ['top', 'bottom'].forEach(function(s) { 93 if (this.animated) { 94 shadow[s].classList.add('paper-shadow-animated'); 95 } else { 96 shadow[s].classList.remove('paper-shadow-animated'); 97 } 98 }.bind(this)); 99 } 100 }, 101 102 addShadow: function(node) { 103 if (node._paperShadow) { 104 return; 105 } 106 107 var computed = getComputedStyle(node); 108 if (!this.hasPosition && computed.position === 'static') { 109 node.style.position = 'relative'; 110 } 111 node.style.overflow = 'visible'; 112 113 // Both the top and bottom shadows are children of the target, so 114 // it does not affect the classes and CSS properties of the target. 115 ['top', 'bottom'].forEach(function(s) { 116 var inner = (node._paperShadow && node._paperShadow[s]) || document.createElement('div'); 117 inner.classList.add('paper-shadow'); 118 inner.classList.add('paper-shadow-' + s + '-z-' + this.z); 119 if (this.animated) { 120 inner.classList.add('paper-shadow-animated'); 121 } 122 123 if (node.shadowRoot) { 124 node.shadowRoot.insertBefore(inner, node.shadowRoot.firstChild); 125 } else { 126 node.insertBefore(inner, node.firstChild); 127 } 128 129 node._paperShadow = node._paperShadow || {}; 130 node._paperShadow[s] = inner; 131 }.bind(this)); 132 133 }, 134 135 removeShadow: function(node) { 136 if (!node._paperShadow) { 137 return; 138 } 139 140 ['top', 'bottom'].forEach(function(s) { 141 node._paperShadow[s].remove(); 142 }); 143 node._paperShadow = null; 144 145 node.style.position = null; 146 } 147 148 }); 149