| OLD | NEW |
| (Empty) |
| 1 <!-- | |
| 2 Copyright (c) 2015 The Polymer Project Authors. All rights reserved. | |
| 3 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt | |
| 4 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt | |
| 5 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt | |
| 6 Code distributed by Google as part of the polymer project is also | |
| 7 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt | |
| 8 --> | |
| 9 | |
| 10 <link rel="import" href="../polymer/polymer.html"> | |
| 11 <link rel="import" href="../iron-media-query/iron-media-query.html"> | |
| 12 <link rel="import" href="../iron-selector/iron-selector.html"> | |
| 13 | |
| 14 <!-- | |
| 15 `paper-drawer-panel` contains a drawer panel and a main panel. The drawer | |
| 16 and the main panel are side-by-side with drawer on the left. When the browser | |
| 17 window size is smaller than the `responsiveWidth`, `paper-drawer-panel` | |
| 18 changes to narrow layout. In narrow layout, the drawer will be stacked on top | |
| 19 of the main panel. The drawer will slide in/out to hide/reveal the main | |
| 20 panel. | |
| 21 | |
| 22 Use the attribute `drawer` to indicate that the element is the drawer panel and | |
| 23 `main` to indicate that the element is the main panel. | |
| 24 | |
| 25 Example: | |
| 26 | |
| 27 <paper-drawer-panel> | |
| 28 <div drawer> Drawer panel... </div> | |
| 29 <div main> Main panel... </div> | |
| 30 </paper-drawer-panel> | |
| 31 | |
| 32 The drawer and the main panels are not scrollable. You can set CSS overflow | |
| 33 property on the elements to make them scrollable or use `paper-header-panel`. | |
| 34 | |
| 35 Example: | |
| 36 | |
| 37 <paper-drawer-panel> | |
| 38 <paper-header-panel drawer> | |
| 39 <paper-toolbar></paper-toolbar> | |
| 40 <div> Drawer content... </div> | |
| 41 </paper-header-panel> | |
| 42 <paper-header-panel main> | |
| 43 <paper-toolbar></paper-toolbar> | |
| 44 <div> Main content... </div> | |
| 45 </paper-header-panel> | |
| 46 </paper-drawer-panel> | |
| 47 | |
| 48 An element that should toggle the drawer will automatically do so if it's | |
| 49 given the `paper-drawer-toggle` attribute. Also this element will automatically | |
| 50 be hidden in wide layout. | |
| 51 | |
| 52 Example: | |
| 53 | |
| 54 <paper-drawer-panel> | |
| 55 <paper-header-panel drawer> | |
| 56 <paper-toolbar> | |
| 57 <div>Application</div> | |
| 58 </paper-toolbar> | |
| 59 <div> Drawer content... </div> | |
| 60 </paper-header-panel> | |
| 61 <paper-header-panel main> | |
| 62 <paper-toolbar> | |
| 63 <paper-icon-button icon="menu" paper-drawer-toggle></paper-icon-button
> | |
| 64 <div>Title</div> | |
| 65 </paper-toolbar> | |
| 66 <div> Main content... </div> | |
| 67 </paper-header-panel> | |
| 68 </paper-drawer-panel> | |
| 69 | |
| 70 To position the drawer to the right, add `right-drawer` attribute. | |
| 71 | |
| 72 <paper-drawer-panel right-drawer> | |
| 73 <div drawer> Drawer panel... </div> | |
| 74 <div main> Main panel... </div> | |
| 75 </paper-drawer-panel> | |
| 76 | |
| 77 Styling `paper-drawer-panel` | |
| 78 | |
| 79 To change the main container: | |
| 80 | |
| 81 paper-drawer-panel { | |
| 82 --paper-drawer-panel-main-container: { | |
| 83 background-color: gray; | |
| 84 }; | |
| 85 } | |
| 86 | |
| 87 To change the drawer container when it's in the left side: | |
| 88 | |
| 89 paper-drawer-panel { | |
| 90 --paper-drawer-panel-left-drawer-container: { | |
| 91 background-color: white; | |
| 92 }; | |
| 93 } | |
| 94 | |
| 95 To change the drawer container when it's in the right side: | |
| 96 | |
| 97 paper-drawer-panel { | |
| 98 --paper-drawer-panel-right-drawer-container: { | |
| 99 background-color: white; | |
| 100 }; | |
| 101 } | |
| 102 | |
| 103 @group Paper elements | |
| 104 @element paper-drawer-panel | |
| 105 @demo demo/index.html | |
| 106 @hero hero.svg | |
| 107 --> | |
| 108 | |
| 109 <dom-module id="paper-drawer-panel"> | |
| 110 <link rel="import" type="css" href="paper-drawer-panel.css"> | |
| 111 | |
| 112 <template> | |
| 113 <iron-media-query | |
| 114 id="mq" | |
| 115 on-query-matches-changed="_onQueryMatchesChanged" | |
| 116 query="[[_computeMediaQuery(forceNarrow, responsiveWidth)]]"> | |
| 117 </iron-media-query> | |
| 118 | |
| 119 <iron-selector | |
| 120 attr-for-selected="id" | |
| 121 class$="[[_computeIronSelectorClass(narrow, transition, dragging, rightD
rawer, peeking)]]" | |
| 122 activate-event="" | |
| 123 selected="[[selected]]"> | |
| 124 | |
| 125 <div id="main" style$="[[_computeMainStyle(narrow, rightDrawer, drawerWidt
h)]]"> | |
| 126 <content select="[main]"></content> | |
| 127 <div id="scrim" on-tap="closeDrawer"></div> | |
| 128 </div> | |
| 129 | |
| 130 <div id="drawer" style$="[[_computeDrawerStyle(drawerWidth)]]"> | |
| 131 <content select="[drawer]"></content> | |
| 132 </div> | |
| 133 | |
| 134 </iron-selector> | |
| 135 </template> | |
| 136 | |
| 137 </dom-module> | |
| 138 | |
| 139 <script> | |
| 140 | |
| 141 (function() { | |
| 142 | |
| 143 'use strict'; | |
| 144 | |
| 145 // this would be the only `paper-drawer-panel` in | |
| 146 // the whole app that can be in `dragging` state | |
| 147 var sharedPanel = null; | |
| 148 | |
| 149 function classNames(obj) { | |
| 150 var classes = []; | |
| 151 for (var key in obj) { | |
| 152 if (obj.hasOwnProperty(key) && obj[key]) { | |
| 153 classes.push(key); | |
| 154 } | |
| 155 } | |
| 156 | |
| 157 return classes.join(' '); | |
| 158 } | |
| 159 | |
| 160 Polymer({ | |
| 161 | |
| 162 is: 'paper-drawer-panel', | |
| 163 | |
| 164 /** | |
| 165 * Fired when the narrow layout changes. | |
| 166 * | |
| 167 * @event paper-responsive-change {{narrow: boolean}} detail - | |
| 168 * narrow: true if the panel is in narrow layout. | |
| 169 */ | |
| 170 | |
| 171 /** | |
| 172 * Fired when the a panel is selected. | |
| 173 * | |
| 174 * Listening for this event is an alternative to observing changes in the
`selected` attribute. | |
| 175 * This event is fired both when a panel is selected. | |
| 176 * | |
| 177 * @event iron-select {{item: Object}} detail - | |
| 178 * item: The panel that the event refers to. | |
| 179 */ | |
| 180 | |
| 181 /** | |
| 182 * Fired when a panel is deselected. | |
| 183 * | |
| 184 * Listening for this event is an alternative to observing changes in the
`selected` attribute. | |
| 185 * This event is fired both when a panel is deselected. | |
| 186 * | |
| 187 * @event iron-deselect {{item: Object}} detail - | |
| 188 * item: The panel that the event refers to. | |
| 189 */ | |
| 190 properties: { | |
| 191 | |
| 192 /** | |
| 193 * The panel to be selected when `paper-drawer-panel` changes to narrow | |
| 194 * layout. | |
| 195 */ | |
| 196 defaultSelected: { | |
| 197 type: String, | |
| 198 value: 'main' | |
| 199 }, | |
| 200 | |
| 201 /** | |
| 202 * If true, swipe from the edge is disable. | |
| 203 */ | |
| 204 disableEdgeSwipe: { | |
| 205 type: Boolean, | |
| 206 value: false | |
| 207 }, | |
| 208 | |
| 209 /** | |
| 210 * If true, swipe to open/close the drawer is disabled. | |
| 211 */ | |
| 212 disableSwipe: { | |
| 213 type: Boolean, | |
| 214 value: false | |
| 215 }, | |
| 216 | |
| 217 /** | |
| 218 * Whether the user is dragging the drawer interactively. | |
| 219 */ | |
| 220 dragging: { | |
| 221 type: Boolean, | |
| 222 value: false, | |
| 223 readOnly: true, | |
| 224 notify: true | |
| 225 }, | |
| 226 | |
| 227 /** | |
| 228 * Width of the drawer panel. | |
| 229 */ | |
| 230 drawerWidth: { | |
| 231 type: String, | |
| 232 value: '256px' | |
| 233 }, | |
| 234 | |
| 235 /** | |
| 236 * How many pixels on the side of the screen are sensitive to edge | |
| 237 * swipes and peek. | |
| 238 */ | |
| 239 edgeSwipeSensitivity: { | |
| 240 type: Number, | |
| 241 value: 30 | |
| 242 }, | |
| 243 | |
| 244 /** | |
| 245 * If true, ignore `responsiveWidth` setting and force the narrow layout
. | |
| 246 */ | |
| 247 forceNarrow: { | |
| 248 type: Boolean, | |
| 249 value: false | |
| 250 }, | |
| 251 | |
| 252 /** | |
| 253 * Whether the browser has support for the transform CSS property. | |
| 254 */ | |
| 255 hasTransform: { | |
| 256 type: Boolean, | |
| 257 value: function() { | |
| 258 return 'transform' in this.style; | |
| 259 } | |
| 260 }, | |
| 261 | |
| 262 /** | |
| 263 * Whether the browser has support for the will-change CSS property. | |
| 264 */ | |
| 265 hasWillChange: { | |
| 266 type: Boolean, | |
| 267 value: function() { | |
| 268 return 'willChange' in this.style; | |
| 269 } | |
| 270 }, | |
| 271 | |
| 272 /** | |
| 273 * Returns true if the panel is in narrow layout. This is useful if you | |
| 274 * need to show/hide elements based on the layout. | |
| 275 */ | |
| 276 narrow: { | |
| 277 reflectToAttribute: true, | |
| 278 type: Boolean, | |
| 279 value: false, | |
| 280 readOnly: true, | |
| 281 notify: true | |
| 282 }, | |
| 283 | |
| 284 /** | |
| 285 * Whether the drawer is peeking out from the edge. | |
| 286 */ | |
| 287 peeking: { | |
| 288 type: Boolean, | |
| 289 value: false, | |
| 290 readOnly: true, | |
| 291 notify: true | |
| 292 }, | |
| 293 | |
| 294 /** | |
| 295 * Max-width when the panel changes to narrow layout. | |
| 296 */ | |
| 297 responsiveWidth: { | |
| 298 type: String, | |
| 299 value: '640px' | |
| 300 }, | |
| 301 | |
| 302 /** | |
| 303 * If true, position the drawer to the right. | |
| 304 */ | |
| 305 rightDrawer: { | |
| 306 type: Boolean, | |
| 307 value: false | |
| 308 }, | |
| 309 | |
| 310 /** | |
| 311 * The panel that is being selected. `drawer` for the drawer panel and | |
| 312 * `main` for the main panel. | |
| 313 */ | |
| 314 selected: { | |
| 315 reflectToAttribute: true, | |
| 316 notify: true, | |
| 317 type: String, | |
| 318 value: null | |
| 319 }, | |
| 320 | |
| 321 /** | |
| 322 * The attribute on elements that should toggle the drawer on tap, also
elements will | |
| 323 * automatically be hidden in wide layout. | |
| 324 */ | |
| 325 drawerToggleAttribute: { | |
| 326 type: String, | |
| 327 value: 'paper-drawer-toggle' | |
| 328 }, | |
| 329 | |
| 330 /** | |
| 331 * Whether the transition is enabled. | |
| 332 */ | |
| 333 transition: { | |
| 334 type: Boolean, | |
| 335 value: false | |
| 336 }, | |
| 337 | |
| 338 }, | |
| 339 | |
| 340 listeners: { | |
| 341 tap: '_onTap', | |
| 342 track: '_onTrack', | |
| 343 down: '_downHandler', | |
| 344 up: '_upHandler' | |
| 345 }, | |
| 346 | |
| 347 observers: [ | |
| 348 '_forceNarrowChanged(forceNarrow, defaultSelected)' | |
| 349 ], | |
| 350 | |
| 351 /** | |
| 352 * Toggles the panel open and closed. | |
| 353 * | |
| 354 * @method togglePanel | |
| 355 */ | |
| 356 togglePanel: function() { | |
| 357 if (this._isMainSelected()) { | |
| 358 this.openDrawer(); | |
| 359 } else { | |
| 360 this.closeDrawer(); | |
| 361 } | |
| 362 }, | |
| 363 | |
| 364 /** | |
| 365 * Opens the drawer. | |
| 366 * | |
| 367 * @method openDrawer | |
| 368 */ | |
| 369 openDrawer: function() { | |
| 370 this.selected = 'drawer'; | |
| 371 }, | |
| 372 | |
| 373 /** | |
| 374 * Closes the drawer. | |
| 375 * | |
| 376 * @method closeDrawer | |
| 377 */ | |
| 378 closeDrawer: function() { | |
| 379 this.selected = 'main'; | |
| 380 }, | |
| 381 | |
| 382 ready: function() { | |
| 383 // Avoid transition at the beginning e.g. page loads and enable | |
| 384 // transitions only after the element is rendered and ready. | |
| 385 this.transition = true; | |
| 386 }, | |
| 387 | |
| 388 _computeIronSelectorClass: function(narrow, transition, dragging, rightDra
wer, peeking) { | |
| 389 return classNames({ | |
| 390 dragging: dragging, | |
| 391 'narrow-layout': narrow, | |
| 392 'right-drawer': rightDrawer, | |
| 393 'left-drawer': !rightDrawer, | |
| 394 transition: transition, | |
| 395 peeking: peeking | |
| 396 }); | |
| 397 }, | |
| 398 | |
| 399 _computeDrawerStyle: function(drawerWidth) { | |
| 400 return 'width:' + drawerWidth + ';'; | |
| 401 }, | |
| 402 | |
| 403 _computeMainStyle: function(narrow, rightDrawer, drawerWidth) { | |
| 404 var style = ''; | |
| 405 | |
| 406 style += 'left:' + ((narrow || rightDrawer) ? '0' : drawerWidth) + ';'; | |
| 407 | |
| 408 if (rightDrawer) { | |
| 409 style += 'right:' + (narrow ? '' : drawerWidth) + ';'; | |
| 410 } | |
| 411 | |
| 412 return style; | |
| 413 }, | |
| 414 | |
| 415 _computeMediaQuery: function(forceNarrow, responsiveWidth) { | |
| 416 return forceNarrow ? '' : '(max-width: ' + responsiveWidth + ')'; | |
| 417 }, | |
| 418 | |
| 419 _computeSwipeOverlayHidden: function(narrow, disableEdgeSwipe) { | |
| 420 return !narrow || disableEdgeSwipe; | |
| 421 }, | |
| 422 | |
| 423 _onTrack: function(event) { | |
| 424 if (sharedPanel && this !== sharedPanel) { | |
| 425 return; | |
| 426 } | |
| 427 switch (event.detail.state) { | |
| 428 case 'start': | |
| 429 this._trackStart(event); | |
| 430 break; | |
| 431 case 'track': | |
| 432 this._trackX(event); | |
| 433 break; | |
| 434 case 'end': | |
| 435 this._trackEnd(event); | |
| 436 break; | |
| 437 } | |
| 438 | |
| 439 }, | |
| 440 | |
| 441 _responsiveChange: function(narrow) { | |
| 442 this._setNarrow(narrow); | |
| 443 | |
| 444 if (this.narrow) { | |
| 445 this.selected = this.defaultSelected; | |
| 446 } | |
| 447 | |
| 448 this.setScrollDirection(this._swipeAllowed() ? 'y' : 'all'); | |
| 449 this.fire('paper-responsive-change', {narrow: this.narrow}); | |
| 450 }, | |
| 451 | |
| 452 _onQueryMatchesChanged: function(event) { | |
| 453 this._responsiveChange(event.detail.value); | |
| 454 }, | |
| 455 | |
| 456 _forceNarrowChanged: function() { | |
| 457 // set the narrow mode only if we reached the `responsiveWidth` | |
| 458 this._responsiveChange(this.forceNarrow || this.$.mq.queryMatches); | |
| 459 }, | |
| 460 | |
| 461 _swipeAllowed: function() { | |
| 462 return this.narrow && !this.disableSwipe; | |
| 463 }, | |
| 464 | |
| 465 _isMainSelected: function() { | |
| 466 return this.selected === 'main'; | |
| 467 }, | |
| 468 | |
| 469 _startEdgePeek: function() { | |
| 470 this.width = this.$.drawer.offsetWidth; | |
| 471 this._moveDrawer(this._translateXForDeltaX(this.rightDrawer ? | |
| 472 -this.edgeSwipeSensitivity : this.edgeSwipeSensitivity)); | |
| 473 this._setPeeking(true); | |
| 474 }, | |
| 475 | |
| 476 _stopEdgePeek: function() { | |
| 477 if (this.peeking) { | |
| 478 this._setPeeking(false); | |
| 479 this._moveDrawer(null); | |
| 480 } | |
| 481 }, | |
| 482 | |
| 483 _downHandler: function(event) { | |
| 484 if (!this.dragging && this._isMainSelected() && this._isEdgeTouch(event)
&& !sharedPanel) { | |
| 485 this._startEdgePeek(); | |
| 486 // cancel selection | |
| 487 event.preventDefault(); | |
| 488 // grab this panel | |
| 489 sharedPanel = this; | |
| 490 } | |
| 491 }, | |
| 492 | |
| 493 _upHandler: function() { | |
| 494 this._stopEdgePeek(); | |
| 495 // release the panel | |
| 496 sharedPanel = null; | |
| 497 }, | |
| 498 | |
| 499 _onTap: function(event) { | |
| 500 var targetElement = Polymer.dom(event).localTarget; | |
| 501 var isTargetToggleElement = targetElement && | |
| 502 this.drawerToggleAttribute && | |
| 503 targetElement.hasAttribute(this.drawerToggleAttribute); | |
| 504 | |
| 505 if (isTargetToggleElement) { | |
| 506 this.togglePanel(); | |
| 507 } | |
| 508 }, | |
| 509 | |
| 510 _isEdgeTouch: function(event) { | |
| 511 var x = event.detail.x; | |
| 512 | |
| 513 return !this.disableEdgeSwipe && this._swipeAllowed() && | |
| 514 (this.rightDrawer ? | |
| 515 x >= this.offsetWidth - this.edgeSwipeSensitivity : | |
| 516 x <= this.edgeSwipeSensitivity); | |
| 517 }, | |
| 518 | |
| 519 _trackStart: function(event) { | |
| 520 if (this._swipeAllowed()) { | |
| 521 sharedPanel = this; | |
| 522 this._setDragging(true); | |
| 523 | |
| 524 if (this._isMainSelected()) { | |
| 525 this._setDragging(this.peeking || this._isEdgeTouch(event)); | |
| 526 } | |
| 527 | |
| 528 if (this.dragging) { | |
| 529 this.width = this.$.drawer.offsetWidth; | |
| 530 this.transition = false; | |
| 531 } | |
| 532 } | |
| 533 }, | |
| 534 | |
| 535 _translateXForDeltaX: function(deltaX) { | |
| 536 var isMain = this._isMainSelected(); | |
| 537 | |
| 538 if (this.rightDrawer) { | |
| 539 return Math.max(0, isMain ? this.width + deltaX : deltaX); | |
| 540 } else { | |
| 541 return Math.min(0, isMain ? deltaX - this.width : deltaX); | |
| 542 } | |
| 543 }, | |
| 544 | |
| 545 _trackX: function(event) { | |
| 546 if (this.dragging) { | |
| 547 var dx = event.detail.dx; | |
| 548 | |
| 549 if (this.peeking) { | |
| 550 if (Math.abs(dx) <= this.edgeSwipeSensitivity) { | |
| 551 // Ignore trackx until we move past the edge peek. | |
| 552 return; | |
| 553 } | |
| 554 this._setPeeking(false); | |
| 555 } | |
| 556 | |
| 557 this._moveDrawer(this._translateXForDeltaX(dx)); | |
| 558 } | |
| 559 }, | |
| 560 | |
| 561 _trackEnd: function(event) { | |
| 562 if (this.dragging) { | |
| 563 var xDirection = event.detail.dx > 0; | |
| 564 | |
| 565 this._setDragging(false); | |
| 566 this.transition = true; | |
| 567 sharedPanel = null; | |
| 568 this._moveDrawer(null); | |
| 569 | |
| 570 if (this.rightDrawer) { | |
| 571 this[xDirection ? 'closeDrawer' : 'openDrawer'](); | |
| 572 } else { | |
| 573 this[xDirection ? 'openDrawer' : 'closeDrawer'](); | |
| 574 } | |
| 575 } | |
| 576 }, | |
| 577 | |
| 578 _transformForTranslateX: function(translateX) { | |
| 579 if (translateX === null) { | |
| 580 return ''; | |
| 581 } | |
| 582 | |
| 583 return this.hasWillChange ? 'translateX(' + translateX + 'px)' : | |
| 584 'translate3d(' + translateX + 'px, 0, 0)'; | |
| 585 }, | |
| 586 | |
| 587 _moveDrawer: function(translateX) { | |
| 588 this.transform(this._transformForTranslateX(translateX), this.$.drawer); | |
| 589 } | |
| 590 | |
| 591 }); | |
| 592 | |
| 593 }()); | |
| 594 | |
| 595 </script> | |
| OLD | NEW |