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 |