OLD | NEW |
(Empty) | |
| 1 |
| 2 |
| 3 (function() { |
| 4 |
| 5 'use strict'; |
| 6 |
| 7 function classNames(obj) { |
| 8 var classNames = []; |
| 9 for (var key in obj) { |
| 10 if (obj.hasOwnProperty(key) && obj[key]) { |
| 11 classNames.push(key); |
| 12 } |
| 13 } |
| 14 |
| 15 return classNames.join(' '); |
| 16 } |
| 17 |
| 18 Polymer({ |
| 19 |
| 20 is: 'paper-drawer-panel', |
| 21 |
| 22 /** |
| 23 * Fired when the narrow layout changes. |
| 24 * |
| 25 * @event paper-responsive-change |
| 26 * @param {Object} detail |
| 27 * @param {boolean} detail.narrow true if the panel is in narrow layout. |
| 28 */ |
| 29 |
| 30 /** |
| 31 * Fired when the selected panel changes. |
| 32 * |
| 33 * Listening for this event is an alternative to observing changes in the
`selected` attribute. |
| 34 * This event is fired both when a panel is selected and deselected. |
| 35 * The `isSelected` detail property contains the selection state. |
| 36 * |
| 37 * @event paper-select |
| 38 * @param {Object} detail |
| 39 * @param {boolean} detail.isSelected true for selection and false for des
election |
| 40 * @param {Object} detail.item the panel that the event refers to |
| 41 */ |
| 42 |
| 43 properties: { |
| 44 |
| 45 /** |
| 46 * The panel to be selected when `paper-drawer-panel` changes to narrow |
| 47 * layout. |
| 48 * |
| 49 * @attribute defaultSelected |
| 50 * @type string |
| 51 * @default 'main' |
| 52 */ |
| 53 defaultSelected: { |
| 54 type: String, |
| 55 value: 'main' |
| 56 }, |
| 57 |
| 58 /** |
| 59 * If true, swipe from the edge is disable. |
| 60 * |
| 61 * @attribute disableEdgeSwipe |
| 62 * @type boolean |
| 63 * @default false |
| 64 */ |
| 65 disableEdgeSwipe: Boolean, |
| 66 |
| 67 /** |
| 68 * If true, swipe to open/close the drawer is disabled. |
| 69 * |
| 70 * @attribute disableSwipe |
| 71 * @type boolean |
| 72 * @default false |
| 73 */ |
| 74 disableSwipe: Boolean, |
| 75 |
| 76 // Whether the user is dragging the drawer interactively. |
| 77 dragging: { |
| 78 value: false |
| 79 }, |
| 80 |
| 81 /** |
| 82 * Width of the drawer panel. |
| 83 * |
| 84 * @attribute drawerWidth |
| 85 * @type string |
| 86 * @default '256px' |
| 87 */ |
| 88 drawerWidth: { |
| 89 type: String, |
| 90 value: '256px' |
| 91 }, |
| 92 |
| 93 // How many pixels on the side of the screen are sensitive to edge |
| 94 // swipes and peek. |
| 95 edgeSwipeSensitivity: { |
| 96 value: 30 |
| 97 }, |
| 98 |
| 99 /** |
| 100 * If true, ignore `responsiveWidth` setting and force the narrow layout
. |
| 101 * |
| 102 * @attribute forceNarrow |
| 103 * @type boolean |
| 104 * @default false |
| 105 */ |
| 106 forceNarrow: { |
| 107 observer: 'forceNarrowChanged', |
| 108 type: Boolean, |
| 109 value: false |
| 110 }, |
| 111 |
| 112 // Whether the browser has support for the transform CSS property. |
| 113 hasTransform: { |
| 114 value: function() { |
| 115 return 'transform' in this.style; |
| 116 } |
| 117 }, |
| 118 |
| 119 // Whether the browser has support for the will-change CSS property. |
| 120 hasWillChange: { |
| 121 value: function() { |
| 122 return 'willChange' in this.style; |
| 123 } |
| 124 }, |
| 125 |
| 126 /** |
| 127 * Returns true if the panel is in narrow layout. This is useful if you |
| 128 * need to show/hide elements based on the layout. |
| 129 * |
| 130 * @attribute narrow |
| 131 * @type boolean |
| 132 * @default false |
| 133 */ |
| 134 narrow: { |
| 135 reflectToAttribute: true, |
| 136 type: Boolean, |
| 137 value: false |
| 138 }, |
| 139 |
| 140 // Whether the drawer is peeking out from the edge. |
| 141 peeking: false, |
| 142 |
| 143 /** |
| 144 * Max-width when the panel changes to narrow layout. |
| 145 * |
| 146 * @attribute responsiveWidth |
| 147 * @type string |
| 148 * @default '640px' |
| 149 */ |
| 150 responsiveWidth: { |
| 151 type: String, |
| 152 value: '640px' |
| 153 }, |
| 154 |
| 155 /** |
| 156 * If true, position the drawer to the right. |
| 157 * |
| 158 * @attribute rightDrawer |
| 159 * @type boolean |
| 160 * @default false |
| 161 */ |
| 162 rightDrawer: { |
| 163 type: Boolean, |
| 164 value: false |
| 165 }, |
| 166 |
| 167 /** |
| 168 * The panel that is being selected. `drawer` for the drawer panel and |
| 169 * `main` for the main panel. |
| 170 * |
| 171 * @attribute selected |
| 172 * @type string |
| 173 * @default null |
| 174 */ |
| 175 selected: { |
| 176 reflectToAttribute: true, |
| 177 type: String, |
| 178 value: null |
| 179 }, |
| 180 |
| 181 /** |
| 182 * The attribute on elements that should toggle the drawer on tap, also
elements will |
| 183 * automatically be hidden in wide layout. |
| 184 */ |
| 185 drawerToggleAttribute: { |
| 186 value: 'paper-drawer-toggle' |
| 187 }, |
| 188 |
| 189 /** |
| 190 * Whether the transition is enabled. |
| 191 */ |
| 192 transition: false, |
| 193 |
| 194 /** |
| 195 * Starting X coordinate of a tracking gesture. It is non-null only betw
een trackStart and |
| 196 * trackEnd events. |
| 197 */ |
| 198 _startX: { |
| 199 value: null |
| 200 } |
| 201 |
| 202 }, |
| 203 |
| 204 listeners: { |
| 205 click: 'onClick', |
| 206 track: 'onTrack' |
| 207 |
| 208 // TODO: Implement tap handlers when taps are supported. |
| 209 // |
| 210 // down: 'downHandler', |
| 211 // up: 'upHandler' |
| 212 }, |
| 213 |
| 214 _computeIronSelectorClass: function(narrow, transition, dragging, rightDra
wer) { |
| 215 return classNames({ |
| 216 dragging: dragging, |
| 217 'narrow-layout': narrow, |
| 218 'right-drawer': rightDrawer, |
| 219 transition: transition |
| 220 }); |
| 221 }, |
| 222 |
| 223 _computeDrawerStyle: function(drawerWidth) { |
| 224 return 'width:' + drawerWidth + ';'; |
| 225 }, |
| 226 |
| 227 _computeMainStyle: function(narrow, rightDrawer, drawerWidth) { |
| 228 var style = ''; |
| 229 |
| 230 style += 'left:' + ((narrow || rightDrawer) ? '0' : drawerWidth) + ';' |
| 231 |
| 232 if (rightDrawer) { |
| 233 style += 'right:' + (narrow ? '' : drawerWidth) + ';'; |
| 234 } else { |
| 235 style += 'right:;' |
| 236 } |
| 237 |
| 238 return style; |
| 239 }, |
| 240 |
| 241 _computeMediaQuery: function(forceNarrow, responsiveWidth) { |
| 242 return forceNarrow ? '' : '(max-width: ' + responsiveWidth + ')'; |
| 243 }, |
| 244 |
| 245 _computeSwipeOverlayHidden: function(narrow, disableEdgeSwipe) { |
| 246 return !narrow || disableEdgeSwipe; |
| 247 }, |
| 248 |
| 249 onTrack: function(event) { |
| 250 switch (event.detail.state) { |
| 251 case 'end': |
| 252 this.trackEnd(event); |
| 253 break; |
| 254 case 'move': |
| 255 this.trackX(event); |
| 256 break; |
| 257 case 'start': |
| 258 this.trackStart(event); |
| 259 break; |
| 260 } |
| 261 }, |
| 262 |
| 263 ready: function() { |
| 264 // Avoid transition at the beginning e.g. page loads and enable |
| 265 // transitions only after the element is rendered and ready. |
| 266 this.transition = true; |
| 267 }, |
| 268 |
| 269 /** |
| 270 * Toggles the panel open and closed. |
| 271 * |
| 272 * @method togglePanel |
| 273 */ |
| 274 togglePanel: function() { |
| 275 if (this.isMainSelected()) { |
| 276 this.openDrawer(); |
| 277 } else { |
| 278 this.closeDrawer(); |
| 279 } |
| 280 }, |
| 281 |
| 282 /** |
| 283 * Opens the drawer. |
| 284 * |
| 285 * @method openDrawer |
| 286 */ |
| 287 openDrawer: function() { |
| 288 this.selected = 'drawer'; |
| 289 }, |
| 290 |
| 291 /** |
| 292 * Closes the drawer. |
| 293 * |
| 294 * @method closeDrawer |
| 295 */ |
| 296 closeDrawer: function() { |
| 297 this.selected = 'main'; |
| 298 }, |
| 299 |
| 300 _responsiveChange: function(narrow) { |
| 301 this.narrow = narrow; |
| 302 |
| 303 if (this.narrow) { |
| 304 this.selected = this.defaultSelected; |
| 305 } |
| 306 |
| 307 this.setAttribute('touch-action', this.swipeAllowed() ? 'pan-y' : ''); |
| 308 this.fire('paper-responsive-change', {narrow: this.narrow}); |
| 309 }, |
| 310 |
| 311 onQueryMatchesChanged: function(e) { |
| 312 this._responsiveChange(e.detail.value); |
| 313 }, |
| 314 |
| 315 forceNarrowChanged: function() { |
| 316 this._responsiveChange(this.forceNarrow); |
| 317 }, |
| 318 |
| 319 swipeAllowed: function() { |
| 320 return this.narrow && !this.disableSwipe; |
| 321 }, |
| 322 |
| 323 isMainSelected: function() { |
| 324 return this.selected === 'main'; |
| 325 }, |
| 326 |
| 327 startEdgePeek: function() { |
| 328 this.width = this.$.drawer.offsetWidth; |
| 329 this.moveDrawer(this.translateXForDeltaX(this.rightDrawer ? |
| 330 -this.edgeSwipeSensitivity : this.edgeSwipeSensitivity)); |
| 331 this.peeking = true; |
| 332 }, |
| 333 |
| 334 stopEdgePeek: function() { |
| 335 if (this.peeking) { |
| 336 this.peeking = false; |
| 337 this.moveDrawer(null); |
| 338 } |
| 339 }, |
| 340 |
| 341 // TODO: Implement tap handlers when taps are supported. |
| 342 // |
| 343 // downHandler: function(e) { |
| 344 // if (!this.dragging && this.isMainSelected() && this.isEdgeTouch(e)) { |
| 345 // this.startEdgePeek(); |
| 346 // } |
| 347 // }, |
| 348 // |
| 349 // upHandler: function(e) { |
| 350 // this.stopEdgePeek(); |
| 351 // }, |
| 352 |
| 353 onClick: function(e) { |
| 354 var isTargetToggleElement = e.target && |
| 355 this.drawerToggleAttribute && |
| 356 e.target.hasAttribute(this.drawerToggleAttribute); |
| 357 |
| 358 if (isTargetToggleElement) { |
| 359 this.togglePanel(); |
| 360 } |
| 361 }, |
| 362 |
| 363 isEdgeTouch: function(event) { |
| 364 var x = event.detail.x; |
| 365 |
| 366 return !this.disableEdgeSwipe && this.swipeAllowed() && |
| 367 (this.rightDrawer ? |
| 368 x >= this.offsetWidth - this.edgeSwipeSensitivity : |
| 369 x <= this.edgeSwipeSensitivity); |
| 370 }, |
| 371 |
| 372 trackStart: function(event) { |
| 373 if (this.swipeAllowed()) { |
| 374 this.dragging = true; |
| 375 this._startX = event.detail.x; |
| 376 |
| 377 if (this.isMainSelected()) { |
| 378 this.dragging = this.peeking || this.isEdgeTouch(event); |
| 379 } |
| 380 |
| 381 if (this.dragging) { |
| 382 this.width = this.$.drawer.offsetWidth; |
| 383 this.transition = false; |
| 384 |
| 385 // TODO: Re-enable when tap gestures are implemented. |
| 386 // |
| 387 // e.preventTap(); |
| 388 } |
| 389 } |
| 390 }, |
| 391 |
| 392 translateXForDeltaX: function(deltaX) { |
| 393 var isMain = this.isMainSelected(); |
| 394 |
| 395 if (this.rightDrawer) { |
| 396 return Math.max(0, isMain ? this.width + deltaX : deltaX); |
| 397 } else { |
| 398 return Math.min(0, isMain ? deltaX - this.width : deltaX); |
| 399 } |
| 400 }, |
| 401 |
| 402 trackX: function(event) { |
| 403 var dx = event.detail.x - this._startX; |
| 404 |
| 405 if (this.dragging) { |
| 406 if (this.peeking) { |
| 407 if (Math.abs(dx) <= this.edgeSwipeSensitivity) { |
| 408 // Ignore trackx until we move past the edge peek. |
| 409 return; |
| 410 } |
| 411 |
| 412 this.peeking = false; |
| 413 } |
| 414 |
| 415 this.moveDrawer(this.translateXForDeltaX(dx)); |
| 416 } |
| 417 }, |
| 418 |
| 419 trackEnd: function(event) { |
| 420 if (this.dragging) { |
| 421 var xDirection = (event.detail.x - this._startX) > 0; |
| 422 |
| 423 this.dragging = false; |
| 424 this._startX = null; |
| 425 this.transition = true; |
| 426 this.moveDrawer(null); |
| 427 |
| 428 if (this.rightDrawer) { |
| 429 this[(xDirection > 0) ? 'closeDrawer' : 'openDrawer'](); |
| 430 } else { |
| 431 this[(xDirection > 0) ? 'openDrawer' : 'closeDrawer'](); |
| 432 } |
| 433 } |
| 434 }, |
| 435 |
| 436 transformForTranslateX: function(translateX) { |
| 437 if (translateX === null) { |
| 438 return ''; |
| 439 } |
| 440 |
| 441 return this.hasWillChange ? 'translateX(' + translateX + 'px)' : |
| 442 'translate3d(' + translateX + 'px, 0, 0)'; |
| 443 }, |
| 444 |
| 445 moveDrawer: function(translateX) { |
| 446 var s = this.$.drawer.style; |
| 447 |
| 448 if (this.hasTransform) { |
| 449 s.transform = this.transformForTranslateX(translateX); |
| 450 } else { |
| 451 s.webkitTransform = this.transformForTranslateX(translateX); |
| 452 } |
| 453 }, |
| 454 |
| 455 onSelect: function(e) { |
| 456 e.preventDefault(); |
| 457 this.selected = e.detail.selected; |
| 458 } |
| 459 |
| 460 }); |
| 461 |
| 462 }()); |
| 463 |
OLD | NEW |