| OLD | NEW |
| (Empty) |
| 1 <!-- | |
| 2 Copyright 2013 The Polymer Authors. All rights reserved. | |
| 3 Use of this source code is governed by a BSD-style | |
| 4 license that can be found in the LICENSE file. | |
| 5 --> | |
| 6 <!-- | |
| 7 /** | |
| 8 * @module Polymer Elements | |
| 9 */ | |
| 10 /** | |
| 11 * polymer-collapse is used to add collapsible behavior to the | |
| 12 * target element. It adjusts the height or width of the target element | |
| 13 * to make the element collapse and expand. | |
| 14 * | |
| 15 * Example: | |
| 16 * | |
| 17 * <button on-click="{{toggle}}">toggle collapse</button> | |
| 18 * <div id="demo"> | |
| 19 * ... | |
| 20 * </div> | |
| 21 * <polymer-collapse id="collapse" targetId="demo"></polymer-collapse> | |
| 22 * | |
| 23 * ... | |
| 24 * | |
| 25 * toggle: function() { | |
| 26 * this.$.collapse.toggle(); | |
| 27 * } | |
| 28 * | |
| 29 * @class polymer-collapse | |
| 30 */ | |
| 31 --> | |
| 32 <link rel="import" href="../polymer/polymer.html"> | |
| 33 | |
| 34 <polymer-element name="polymer-collapse" attributes="targetId target horizontal
closed duration fixedSize size"> | |
| 35 <template> | |
| 36 <link rel="stylesheet" polymer-scope="controller" href="polymer-collapse.css
"> | |
| 37 <link rel="stylesheet" href="polymer-collapse.css"> | |
| 38 <style> | |
| 39 :host { | |
| 40 display: none; | |
| 41 } | |
| 42 </style> | |
| 43 </template> | |
| 44 <script> | |
| 45 Polymer('polymer-collapse', { | |
| 46 /** | |
| 47 * The id of the target element. | |
| 48 * | |
| 49 * @attribute targetId | |
| 50 * @type string | |
| 51 * @default '' | |
| 52 */ | |
| 53 targetId: '', | |
| 54 /** | |
| 55 * The target element. | |
| 56 * | |
| 57 * @attribute target | |
| 58 * @type object | |
| 59 * @default null | |
| 60 */ | |
| 61 target: null, | |
| 62 /** | |
| 63 * If true, the orientation is horizontal; otherwise is vertical. | |
| 64 * | |
| 65 * @attribute horizontal | |
| 66 * @type boolean | |
| 67 * @default false | |
| 68 */ | |
| 69 horizontal: false, | |
| 70 /** | |
| 71 * If true, the target element is hidden/collapsed. | |
| 72 * | |
| 73 * @attribute closed | |
| 74 * @type boolean | |
| 75 * @default false | |
| 76 */ | |
| 77 closed: false, | |
| 78 /** | |
| 79 * Collapsing/expanding animation duration in second. | |
| 80 * | |
| 81 * @attribute duration | |
| 82 * @type number | |
| 83 * @default 0.33 | |
| 84 */ | |
| 85 duration: 0.33, | |
| 86 /** | |
| 87 * If true, the size of the target element is fixed and is set | |
| 88 * on the element. Otherwise it will try to | |
| 89 * use auto to determine the natural size to use | |
| 90 * for collapsing/expanding. | |
| 91 * | |
| 92 * @attribute fixedSize | |
| 93 * @type boolean | |
| 94 * @default false | |
| 95 */ | |
| 96 fixedSize: false, | |
| 97 size: null, | |
| 98 attached: function() { | |
| 99 this.installControllerStyles(); | |
| 100 this.async(function() { | |
| 101 this.afterInitialUpdate = true; | |
| 102 }); | |
| 103 }, | |
| 104 detached: function() { | |
| 105 if (this.target) { | |
| 106 this.removeListeners(this.target); | |
| 107 } | |
| 108 }, | |
| 109 targetIdChanged: function() { | |
| 110 var p = this.parentNode; | |
| 111 while (p.parentNode) { | |
| 112 p = p.parentNode; | |
| 113 } | |
| 114 this.target = p.querySelector('#' + this.targetId); | |
| 115 }, | |
| 116 targetChanged: function(old) { | |
| 117 if (old) { | |
| 118 this.removeListeners(old); | |
| 119 } | |
| 120 this.horizontalChanged(); | |
| 121 this.isTargetReady = !!this.target; | |
| 122 if (this.target) { | |
| 123 this.target.style.overflow = 'hidden'; | |
| 124 this.addListeners(this.target); | |
| 125 // set polymer-collapse-closed class initially to hide the target | |
| 126 this.toggleClosedClass(true); | |
| 127 } | |
| 128 // don't need to update if the size is already set and it's opened | |
| 129 if (!this.fixedSize || !this.closed) { | |
| 130 this.update(); | |
| 131 } | |
| 132 }, | |
| 133 addListeners: function(node) { | |
| 134 this.transitionEndListener = this.transitionEndListener || | |
| 135 this.transitionEnd.bind(this); | |
| 136 node.addEventListener('webkitTransitionEnd', this.transitionEndListener)
; | |
| 137 node.addEventListener('transitionend', this.transitionEndListener); | |
| 138 }, | |
| 139 removeListeners: function(node) { | |
| 140 node.removeEventListener('webkitTransitionEnd', this.transitionEndListen
er); | |
| 141 node.removeEventListener('transitionend', this.transitionEndListener); | |
| 142 }, | |
| 143 horizontalChanged: function() { | |
| 144 this.dimension = this.horizontal ? 'width' : 'height'; | |
| 145 }, | |
| 146 closedChanged: function() { | |
| 147 this.update(); | |
| 148 }, | |
| 149 /** | |
| 150 * Toggle the closed state of the collapsible. | |
| 151 * | |
| 152 * @method toggle | |
| 153 */ | |
| 154 toggle: function() { | |
| 155 this.closed = !this.closed; | |
| 156 }, | |
| 157 setTransitionDuration: function(duration) { | |
| 158 var s = this.target.style; | |
| 159 s.webkitTransition = s.transition = duration ? | |
| 160 (this.dimension + ' ' + duration + 's') : null; | |
| 161 if (duration === 0) { | |
| 162 this.async('transitionEnd'); | |
| 163 } | |
| 164 }, | |
| 165 transitionEnd: function() { | |
| 166 if (!this.closed && !this.fixedSize) { | |
| 167 this.updateSize('auto', null); | |
| 168 } | |
| 169 this.setTransitionDuration(null); | |
| 170 this.toggleClosedClass(this.closed); | |
| 171 }, | |
| 172 toggleClosedClass: function(add) { | |
| 173 this.hasClosedClass = add; | |
| 174 this.target.classList.toggle('polymer-collapse-closed', add); | |
| 175 }, | |
| 176 updateSize: function(size, duration, forceEnd) { | |
| 177 if (duration) { | |
| 178 this.calcSize(); | |
| 179 } | |
| 180 this.setTransitionDuration(duration); | |
| 181 var s = this.target.style; | |
| 182 var nochange = s[this.dimension] === size; | |
| 183 s[this.dimension] = size; | |
| 184 // transitonEnd will not be called if the size has not changed | |
| 185 if (forceEnd && nochange) { | |
| 186 this.transitionEnd(); | |
| 187 } | |
| 188 }, | |
| 189 update: function() { | |
| 190 if (!this.target) { | |
| 191 return; | |
| 192 } | |
| 193 if (!this.isTargetReady) { | |
| 194 this.targetChanged(); | |
| 195 } | |
| 196 this.horizontalChanged(); | |
| 197 this[this.closed ? 'hide' : 'show'](); | |
| 198 }, | |
| 199 calcSize: function() { | |
| 200 return this.target.getBoundingClientRect()[this.dimension] + 'px'; | |
| 201 }, | |
| 202 getComputedSize: function() { | |
| 203 return getComputedStyle(this.target)[this.dimension]; | |
| 204 }, | |
| 205 show: function() { | |
| 206 this.toggleClosedClass(false); | |
| 207 // for initial update, skip the expanding animation to optimize | |
| 208 // performance e.g. skip calcSize | |
| 209 if (!this.afterInitialUpdate) { | |
| 210 this.transitionEnd(); | |
| 211 return; | |
| 212 } | |
| 213 if (!this.fixedSize) { | |
| 214 this.updateSize('auto', null); | |
| 215 var s = this.calcSize(); | |
| 216 this.updateSize(0, null); | |
| 217 } | |
| 218 this.async(function() { | |
| 219 this.updateSize(this.size || s, this.duration, true); | |
| 220 }); | |
| 221 }, | |
| 222 hide: function() { | |
| 223 // don't need to do anything if it's already hidden | |
| 224 if (this.hasClosedClass && !this.fixedSize) { | |
| 225 return; | |
| 226 } | |
| 227 if (this.fixedSize) { | |
| 228 // save the size before hiding it | |
| 229 this.size = this.getComputedSize(); | |
| 230 } else { | |
| 231 this.updateSize(this.calcSize(), null); | |
| 232 } | |
| 233 this.async(function() { | |
| 234 this.updateSize(0, this.duration); | |
| 235 }); | |
| 236 } | |
| 237 }); | |
| 238 </script> | |
| 239 </polymer-element> | |
| OLD | NEW |