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