@materializecss/materialize 1.2.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Gruntfile.js +722 -712
- package/LICENSE +21 -21
- package/README.md +91 -91
- package/dist/css/materialize.css +68 -135
- package/dist/css/materialize.min.css +12 -12
- package/dist/js/materialize.js +1112 -1112
- package/dist/js/materialize.min.js +6 -6
- package/extras/noUiSlider/nouislider.css +403 -403
- package/extras/noUiSlider/nouislider.js +2147 -2147
- package/js/anime.min.js +34 -34
- package/js/autocomplete.js +479 -479
- package/js/buttons.js +354 -354
- package/js/cards.js +40 -40
- package/js/carousel.js +732 -732
- package/js/cash.js +960 -960
- package/js/characterCounter.js +136 -136
- package/js/chips.js +486 -486
- package/js/collapsible.js +275 -275
- package/js/component.js +44 -44
- package/js/datepicker.js +983 -983
- package/js/dropdown.js +669 -669
- package/js/forms.js +285 -285
- package/js/global.js +428 -428
- package/js/materialbox.js +453 -453
- package/js/modal.js +382 -382
- package/js/parallax.js +138 -138
- package/js/pushpin.js +148 -148
- package/js/range.js +263 -263
- package/js/scrollspy.js +295 -295
- package/js/select.js +391 -391
- package/js/sidenav.js +583 -583
- package/js/slider.js +359 -359
- package/js/tabs.js +402 -402
- package/js/tapTarget.js +315 -315
- package/js/timepicker.js +712 -712
- package/js/toasts.js +325 -325
- package/js/tooltip.js +320 -320
- package/js/waves.js +614 -614
- package/package.json +87 -84
- package/sass/_style.scss +929 -929
- package/sass/components/_badges.scss +55 -55
- package/sass/components/_buttons.scss +322 -322
- package/sass/components/_cards.scss +195 -195
- package/sass/components/_carousel.scss +90 -90
- package/sass/components/_chips.scss +96 -96
- package/sass/components/_collapsible.scss +91 -91
- package/sass/components/_collection.scss +106 -106
- package/sass/components/_color-classes.scss +32 -32
- package/sass/components/_color-variables.scss +370 -370
- package/sass/components/_datepicker.scss +191 -191
- package/sass/components/_dropdown.scss +84 -84
- package/sass/components/_global.scss +646 -646
- package/sass/components/_grid.scss +158 -158
- package/sass/components/_icons-material-design.scss +5 -5
- package/sass/components/_materialbox.scss +42 -42
- package/sass/components/_modal.scss +97 -97
- package/sass/components/_navbar.scss +208 -208
- package/sass/components/_normalize.scss +447 -447
- package/sass/components/_preloader.scss +334 -334
- package/sass/components/_pulse.scss +34 -34
- package/sass/components/_sidenav.scss +214 -214
- package/sass/components/_slider.scss +91 -91
- package/sass/components/_table_of_contents.scss +33 -33
- package/sass/components/_tabs.scss +99 -99
- package/sass/components/_tapTarget.scss +103 -103
- package/sass/components/_timepicker.scss +199 -199
- package/sass/components/_toast.scss +58 -58
- package/sass/components/_tooltip.scss +32 -32
- package/sass/components/_transitions.scss +12 -12
- package/sass/components/_typography.scss +62 -62
- package/sass/components/_variables.scss +352 -352
- package/sass/components/_waves.scss +187 -187
- package/sass/components/forms/_checkboxes.scss +200 -200
- package/sass/components/forms/_file-input.scss +44 -44
- package/sass/components/forms/_forms.scss +22 -22
- package/sass/components/forms/_input-fields.scss +388 -388
- package/sass/components/forms/_radio-buttons.scss +115 -115
- package/sass/components/forms/_range.scss +161 -161
- package/sass/components/forms/_select.scss +199 -199
- package/sass/components/forms/_switches.scss +91 -91
- package/sass/ghpages-materialize.scss +7 -7
- package/sass/materialize.scss +42 -42
package/js/sidenav.js
CHANGED
|
@@ -1,583 +1,583 @@
|
|
|
1
|
-
(function($, anim) {
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
let _defaults = {
|
|
5
|
-
edge: 'left',
|
|
6
|
-
draggable: true,
|
|
7
|
-
dragTargetWidth: '10px',
|
|
8
|
-
inDuration: 250,
|
|
9
|
-
outDuration: 200,
|
|
10
|
-
onOpenStart: null,
|
|
11
|
-
onOpenEnd: null,
|
|
12
|
-
onCloseStart: null,
|
|
13
|
-
onCloseEnd: null,
|
|
14
|
-
preventScrolling: true
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* @class
|
|
19
|
-
*/
|
|
20
|
-
class Sidenav extends Component {
|
|
21
|
-
/**
|
|
22
|
-
* Construct Sidenav instance and set up overlay
|
|
23
|
-
* @constructor
|
|
24
|
-
* @param {Element} el
|
|
25
|
-
* @param {Object} options
|
|
26
|
-
*/
|
|
27
|
-
constructor(el, options) {
|
|
28
|
-
super(Sidenav, el, options);
|
|
29
|
-
|
|
30
|
-
this.el.M_Sidenav = this;
|
|
31
|
-
this.id = this.$el.attr('id');
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Options for the Sidenav
|
|
35
|
-
* @member Sidenav#options
|
|
36
|
-
* @prop {String} [edge='left'] - Side of screen on which Sidenav appears
|
|
37
|
-
* @prop {Boolean} [draggable=true] - Allow swipe gestures to open/close Sidenav
|
|
38
|
-
* @prop {String} [dragTargetWidth='10px'] - Width of the area where you can start dragging
|
|
39
|
-
* @prop {Number} [inDuration=250] - Length in ms of enter transition
|
|
40
|
-
* @prop {Number} [outDuration=200] - Length in ms of exit transition
|
|
41
|
-
* @prop {Function} onOpenStart - Function called when sidenav starts entering
|
|
42
|
-
* @prop {Function} onOpenEnd - Function called when sidenav finishes entering
|
|
43
|
-
* @prop {Function} onCloseStart - Function called when sidenav starts exiting
|
|
44
|
-
* @prop {Function} onCloseEnd - Function called when sidenav finishes exiting
|
|
45
|
-
*/
|
|
46
|
-
this.options = $.extend({}, Sidenav.defaults, options);
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Describes open/close state of Sidenav
|
|
50
|
-
* @type {Boolean}
|
|
51
|
-
*/
|
|
52
|
-
this.isOpen = false;
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Describes if Sidenav is fixed
|
|
56
|
-
* @type {Boolean}
|
|
57
|
-
*/
|
|
58
|
-
this.isFixed = this.el.classList.contains('sidenav-fixed');
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Describes if Sidenav is being draggeed
|
|
62
|
-
* @type {Boolean}
|
|
63
|
-
*/
|
|
64
|
-
this.isDragged = false;
|
|
65
|
-
|
|
66
|
-
// Window size variables for window resize checks
|
|
67
|
-
this.lastWindowWidth = window.innerWidth;
|
|
68
|
-
this.lastWindowHeight = window.innerHeight;
|
|
69
|
-
|
|
70
|
-
this._createOverlay();
|
|
71
|
-
this._createDragTarget();
|
|
72
|
-
this._setupEventHandlers();
|
|
73
|
-
this._setupClasses();
|
|
74
|
-
this._setupFixed();
|
|
75
|
-
|
|
76
|
-
Sidenav._sidenavs.push(this);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
static get defaults() {
|
|
80
|
-
return _defaults;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
static init(els, options) {
|
|
84
|
-
return super.init(this, els, options);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Get Instance
|
|
89
|
-
*/
|
|
90
|
-
static getInstance(el) {
|
|
91
|
-
let domElem = !!el.jquery ? el[0] : el;
|
|
92
|
-
return domElem.M_Sidenav;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Teardown component
|
|
97
|
-
*/
|
|
98
|
-
destroy() {
|
|
99
|
-
this._removeEventHandlers();
|
|
100
|
-
this._enableBodyScrolling();
|
|
101
|
-
this._overlay.parentNode.removeChild(this._overlay);
|
|
102
|
-
this.dragTarget.parentNode.removeChild(this.dragTarget);
|
|
103
|
-
this.el.M_Sidenav = undefined;
|
|
104
|
-
this.el.style.transform = '';
|
|
105
|
-
|
|
106
|
-
let index = Sidenav._sidenavs.indexOf(this);
|
|
107
|
-
if (index >= 0) {
|
|
108
|
-
Sidenav._sidenavs.splice(index, 1);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
_createOverlay() {
|
|
113
|
-
let overlay = document.createElement('div');
|
|
114
|
-
this._closeBound = this.close.bind(this);
|
|
115
|
-
overlay.classList.add('sidenav-overlay');
|
|
116
|
-
|
|
117
|
-
overlay.addEventListener('click', this._closeBound);
|
|
118
|
-
|
|
119
|
-
document.body.appendChild(overlay);
|
|
120
|
-
this._overlay = overlay;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
_setupEventHandlers() {
|
|
124
|
-
if (Sidenav._sidenavs.length === 0) {
|
|
125
|
-
document.body.addEventListener('click', this._handleTriggerClick);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
this._handleDragTargetDragBound = this._handleDragTargetDrag.bind(this);
|
|
129
|
-
this._handleDragTargetReleaseBound = this._handleDragTargetRelease.bind(this);
|
|
130
|
-
this._handleCloseDragBound = this._handleCloseDrag.bind(this);
|
|
131
|
-
this._handleCloseReleaseBound = this._handleCloseRelease.bind(this);
|
|
132
|
-
this._handleCloseTriggerClickBound = this._handleCloseTriggerClick.bind(this);
|
|
133
|
-
|
|
134
|
-
this.dragTarget.addEventListener('touchmove', this._handleDragTargetDragBound, passiveIfSupported);
|
|
135
|
-
this.dragTarget.addEventListener('touchend', this._handleDragTargetReleaseBound);
|
|
136
|
-
this._overlay.addEventListener('touchmove', this._handleCloseDragBound, passiveIfSupported);
|
|
137
|
-
this._overlay.addEventListener('touchend', this._handleCloseReleaseBound);
|
|
138
|
-
this.el.addEventListener('touchmove', this._handleCloseDragBound, passiveIfSupported);
|
|
139
|
-
this.el.addEventListener('touchend', this._handleCloseReleaseBound);
|
|
140
|
-
this.el.addEventListener('click', this._handleCloseTriggerClickBound);
|
|
141
|
-
|
|
142
|
-
// Add resize for side nav fixed
|
|
143
|
-
if (this.isFixed) {
|
|
144
|
-
this._handleWindowResizeBound = this._handleWindowResize.bind(this);
|
|
145
|
-
window.addEventListener('resize', this._handleWindowResizeBound);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
_removeEventHandlers() {
|
|
150
|
-
if (Sidenav._sidenavs.length === 1) {
|
|
151
|
-
document.body.removeEventListener('click', this._handleTriggerClick);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
this.dragTarget.removeEventListener('touchmove', this._handleDragTargetDragBound);
|
|
155
|
-
this.dragTarget.removeEventListener('touchend', this._handleDragTargetReleaseBound);
|
|
156
|
-
this._overlay.removeEventListener('touchmove', this._handleCloseDragBound);
|
|
157
|
-
this._overlay.removeEventListener('touchend', this._handleCloseReleaseBound);
|
|
158
|
-
this.el.removeEventListener('touchmove', this._handleCloseDragBound);
|
|
159
|
-
this.el.removeEventListener('touchend', this._handleCloseReleaseBound);
|
|
160
|
-
this.el.removeEventListener('click', this._handleCloseTriggerClickBound);
|
|
161
|
-
|
|
162
|
-
// Remove resize for side nav fixed
|
|
163
|
-
if (this.isFixed) {
|
|
164
|
-
window.removeEventListener('resize', this._handleWindowResizeBound);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Handle Trigger Click
|
|
170
|
-
* @param {Event} e
|
|
171
|
-
*/
|
|
172
|
-
_handleTriggerClick(e) {
|
|
173
|
-
let $trigger = $(e.target).closest('.sidenav-trigger');
|
|
174
|
-
if (e.target && $trigger.length) {
|
|
175
|
-
let sidenavId = M.getIdFromTrigger($trigger[0]);
|
|
176
|
-
|
|
177
|
-
let sidenavInstance = document.getElementById(sidenavId).M_Sidenav;
|
|
178
|
-
if (sidenavInstance) {
|
|
179
|
-
sidenavInstance.open($trigger);
|
|
180
|
-
}
|
|
181
|
-
e.preventDefault();
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Set variables needed at the beginning of drag
|
|
187
|
-
* and stop any current transition.
|
|
188
|
-
* @param {Event} e
|
|
189
|
-
*/
|
|
190
|
-
_startDrag(e) {
|
|
191
|
-
let clientX = e.targetTouches[0].clientX;
|
|
192
|
-
this.isDragged = true;
|
|
193
|
-
this._startingXpos = clientX;
|
|
194
|
-
this._xPos = this._startingXpos;
|
|
195
|
-
this._time = Date.now();
|
|
196
|
-
this._width = this.el.getBoundingClientRect().width;
|
|
197
|
-
this._overlay.style.display = 'block';
|
|
198
|
-
this._initialScrollTop = this.isOpen ? this.el.scrollTop : M.getDocumentScrollTop();
|
|
199
|
-
this._verticallyScrolling = false;
|
|
200
|
-
anim.remove(this.el);
|
|
201
|
-
anim.remove(this._overlay);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Set variables needed at each drag move update tick
|
|
206
|
-
* @param {Event} e
|
|
207
|
-
*/
|
|
208
|
-
_dragMoveUpdate(e) {
|
|
209
|
-
let clientX = e.targetTouches[0].clientX;
|
|
210
|
-
let currentScrollTop = this.isOpen ? this.el.scrollTop : M.getDocumentScrollTop();
|
|
211
|
-
this.deltaX = Math.abs(this._xPos - clientX);
|
|
212
|
-
this._xPos = clientX;
|
|
213
|
-
this.velocityX = this.deltaX / (Date.now() - this._time);
|
|
214
|
-
this._time = Date.now();
|
|
215
|
-
if (this._initialScrollTop !== currentScrollTop) {
|
|
216
|
-
this._verticallyScrolling = true;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Handles Dragging of Sidenav
|
|
222
|
-
* @param {Event} e
|
|
223
|
-
*/
|
|
224
|
-
_handleDragTargetDrag(e) {
|
|
225
|
-
// Check if draggable
|
|
226
|
-
if (!this.options.draggable || this._isCurrentlyFixed() || this._verticallyScrolling) {
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// If not being dragged, set initial drag start variables
|
|
231
|
-
if (!this.isDragged) {
|
|
232
|
-
this._startDrag(e);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// Run touchmove updates
|
|
236
|
-
this._dragMoveUpdate(e);
|
|
237
|
-
|
|
238
|
-
// Calculate raw deltaX
|
|
239
|
-
let totalDeltaX = this._xPos - this._startingXpos;
|
|
240
|
-
|
|
241
|
-
// dragDirection is the attempted user drag direction
|
|
242
|
-
let dragDirection = totalDeltaX > 0 ? 'right' : 'left';
|
|
243
|
-
|
|
244
|
-
// Don't allow totalDeltaX to exceed Sidenav width or be dragged in the opposite direction
|
|
245
|
-
totalDeltaX = Math.min(this._width, Math.abs(totalDeltaX));
|
|
246
|
-
if (this.options.edge === dragDirection) {
|
|
247
|
-
totalDeltaX = 0;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* transformX is the drag displacement
|
|
252
|
-
* transformPrefix is the initial transform placement
|
|
253
|
-
* Invert values if Sidenav is right edge
|
|
254
|
-
*/
|
|
255
|
-
let transformX = totalDeltaX;
|
|
256
|
-
let transformPrefix = 'translateX(-100%)';
|
|
257
|
-
if (this.options.edge === 'right') {
|
|
258
|
-
transformPrefix = 'translateX(100%)';
|
|
259
|
-
transformX = -transformX;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// Calculate open/close percentage of sidenav, with open = 1 and close = 0
|
|
263
|
-
this.percentOpen = Math.min(1, totalDeltaX / this._width);
|
|
264
|
-
|
|
265
|
-
// Set transform and opacity styles
|
|
266
|
-
this.el.style.transform = `${transformPrefix} translateX(${transformX}px)`;
|
|
267
|
-
this._overlay.style.opacity = this.percentOpen;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Handle Drag Target Release
|
|
272
|
-
*/
|
|
273
|
-
_handleDragTargetRelease() {
|
|
274
|
-
if (this.isDragged) {
|
|
275
|
-
if (this.percentOpen > 0.2) {
|
|
276
|
-
this.open();
|
|
277
|
-
} else {
|
|
278
|
-
this._animateOut();
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
this.isDragged = false;
|
|
282
|
-
this._verticallyScrolling = false;
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Handle Close Drag
|
|
288
|
-
* @param {Event} e
|
|
289
|
-
*/
|
|
290
|
-
_handleCloseDrag(e) {
|
|
291
|
-
if (this.isOpen) {
|
|
292
|
-
// Check if draggable
|
|
293
|
-
if (!this.options.draggable || this._isCurrentlyFixed() || this._verticallyScrolling) {
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
// If not being dragged, set initial drag start variables
|
|
298
|
-
if (!this.isDragged) {
|
|
299
|
-
this._startDrag(e);
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
// Run touchmove updates
|
|
303
|
-
this._dragMoveUpdate(e);
|
|
304
|
-
|
|
305
|
-
// Calculate raw deltaX
|
|
306
|
-
let totalDeltaX = this._xPos - this._startingXpos;
|
|
307
|
-
|
|
308
|
-
// dragDirection is the attempted user drag direction
|
|
309
|
-
let dragDirection = totalDeltaX > 0 ? 'right' : 'left';
|
|
310
|
-
|
|
311
|
-
// Don't allow totalDeltaX to exceed Sidenav width or be dragged in the opposite direction
|
|
312
|
-
totalDeltaX = Math.min(this._width, Math.abs(totalDeltaX));
|
|
313
|
-
if (this.options.edge !== dragDirection) {
|
|
314
|
-
totalDeltaX = 0;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
let transformX = -totalDeltaX;
|
|
318
|
-
if (this.options.edge === 'right') {
|
|
319
|
-
transformX = -transformX;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// Calculate open/close percentage of sidenav, with open = 1 and close = 0
|
|
323
|
-
this.percentOpen = Math.min(1, 1 - totalDeltaX / this._width);
|
|
324
|
-
|
|
325
|
-
// Set transform and opacity styles
|
|
326
|
-
this.el.style.transform = `translateX(${transformX}px)`;
|
|
327
|
-
this._overlay.style.opacity = this.percentOpen;
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
/**
|
|
332
|
-
* Handle Close Release
|
|
333
|
-
*/
|
|
334
|
-
_handleCloseRelease() {
|
|
335
|
-
if (this.isOpen && this.isDragged) {
|
|
336
|
-
if (this.percentOpen > 0.8) {
|
|
337
|
-
this._animateIn();
|
|
338
|
-
} else {
|
|
339
|
-
this.close();
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
this.isDragged = false;
|
|
343
|
-
this._verticallyScrolling = false;
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* Handles closing of Sidenav when element with class .sidenav-close
|
|
349
|
-
*/
|
|
350
|
-
_handleCloseTriggerClick(e) {
|
|
351
|
-
let $closeTrigger = $(e.target).closest('.sidenav-close');
|
|
352
|
-
if ($closeTrigger.length && !this._isCurrentlyFixed()) {
|
|
353
|
-
this.close();
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
/**
|
|
358
|
-
* Handle Window Resize
|
|
359
|
-
*/
|
|
360
|
-
_handleWindowResize() {
|
|
361
|
-
// Only handle horizontal resizes
|
|
362
|
-
if (this.lastWindowWidth !== window.innerWidth) {
|
|
363
|
-
if (window.innerWidth > 992) {
|
|
364
|
-
this.open();
|
|
365
|
-
} else {
|
|
366
|
-
this.close();
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
this.lastWindowWidth = window.innerWidth;
|
|
371
|
-
this.lastWindowHeight = window.innerHeight;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
_setupClasses() {
|
|
375
|
-
if (this.options.edge === 'right') {
|
|
376
|
-
this.el.classList.add('right-aligned');
|
|
377
|
-
this.dragTarget.classList.add('right-aligned');
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
_removeClasses() {
|
|
382
|
-
this.el.classList.remove('right-aligned');
|
|
383
|
-
this.dragTarget.classList.remove('right-aligned');
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
_setupFixed() {
|
|
387
|
-
if (this._isCurrentlyFixed()) {
|
|
388
|
-
this.open();
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
_isCurrentlyFixed() {
|
|
393
|
-
return this.isFixed && window.innerWidth > 992;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
_createDragTarget() {
|
|
397
|
-
let dragTarget = document.createElement('div');
|
|
398
|
-
dragTarget.classList.add('drag-target');
|
|
399
|
-
dragTarget.style.width = this.options.dragTargetWidth;
|
|
400
|
-
document.body.appendChild(dragTarget);
|
|
401
|
-
this.dragTarget = dragTarget;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
_preventBodyScrolling() {
|
|
405
|
-
let body = document.body;
|
|
406
|
-
body.style.overflow = 'hidden';
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
_enableBodyScrolling() {
|
|
410
|
-
let body = document.body;
|
|
411
|
-
body.style.overflow = '';
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
open() {
|
|
415
|
-
if (this.isOpen === true) {
|
|
416
|
-
return;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
this.isOpen = true;
|
|
420
|
-
|
|
421
|
-
// Run onOpenStart callback
|
|
422
|
-
if (typeof this.options.onOpenStart === 'function') {
|
|
423
|
-
this.options.onOpenStart.call(this, this.el);
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
// Handle fixed Sidenav
|
|
427
|
-
if (this._isCurrentlyFixed()) {
|
|
428
|
-
anim.remove(this.el);
|
|
429
|
-
anim({
|
|
430
|
-
targets: this.el,
|
|
431
|
-
translateX: 0,
|
|
432
|
-
duration: 0,
|
|
433
|
-
easing: 'easeOutQuad'
|
|
434
|
-
});
|
|
435
|
-
this._enableBodyScrolling();
|
|
436
|
-
this._overlay.style.display = 'none';
|
|
437
|
-
|
|
438
|
-
// Handle non-fixed Sidenav
|
|
439
|
-
} else {
|
|
440
|
-
if (this.options.preventScrolling) {
|
|
441
|
-
this._preventBodyScrolling();
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
if (!this.isDragged || this.percentOpen != 1) {
|
|
445
|
-
this._animateIn();
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
close() {
|
|
451
|
-
if (this.isOpen === false) {
|
|
452
|
-
return;
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
this.isOpen = false;
|
|
456
|
-
|
|
457
|
-
// Run onCloseStart callback
|
|
458
|
-
if (typeof this.options.onCloseStart === 'function') {
|
|
459
|
-
this.options.onCloseStart.call(this, this.el);
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
// Handle fixed Sidenav
|
|
463
|
-
if (this._isCurrentlyFixed()) {
|
|
464
|
-
let transformX = this.options.edge === 'left' ? '-105%' : '105%';
|
|
465
|
-
this.el.style.transform = `translateX(${transformX})`;
|
|
466
|
-
|
|
467
|
-
// Handle non-fixed Sidenav
|
|
468
|
-
} else {
|
|
469
|
-
this._enableBodyScrolling();
|
|
470
|
-
|
|
471
|
-
if (!this.isDragged || this.percentOpen != 0) {
|
|
472
|
-
this._animateOut();
|
|
473
|
-
} else {
|
|
474
|
-
this._overlay.style.display = 'none';
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
_animateIn() {
|
|
480
|
-
this._animateSidenavIn();
|
|
481
|
-
this._animateOverlayIn();
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
_animateSidenavIn() {
|
|
485
|
-
let slideOutPercent = this.options.edge === 'left' ? -1 : 1;
|
|
486
|
-
if (this.isDragged) {
|
|
487
|
-
slideOutPercent =
|
|
488
|
-
this.options.edge === 'left'
|
|
489
|
-
? slideOutPercent + this.percentOpen
|
|
490
|
-
: slideOutPercent - this.percentOpen;
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
anim.remove(this.el);
|
|
494
|
-
anim({
|
|
495
|
-
targets: this.el,
|
|
496
|
-
translateX: [`${slideOutPercent * 100}%`, 0],
|
|
497
|
-
duration: this.options.inDuration,
|
|
498
|
-
easing: 'easeOutQuad',
|
|
499
|
-
complete: () => {
|
|
500
|
-
// Run onOpenEnd callback
|
|
501
|
-
if (typeof this.options.onOpenEnd === 'function') {
|
|
502
|
-
this.options.onOpenEnd.call(this, this.el);
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
});
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
_animateOverlayIn() {
|
|
509
|
-
let start = 0;
|
|
510
|
-
if (this.isDragged) {
|
|
511
|
-
start = this.percentOpen;
|
|
512
|
-
} else {
|
|
513
|
-
$(this._overlay).css({
|
|
514
|
-
display: 'block'
|
|
515
|
-
});
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
anim.remove(this._overlay);
|
|
519
|
-
anim({
|
|
520
|
-
targets: this._overlay,
|
|
521
|
-
opacity: [start, 1],
|
|
522
|
-
duration: this.options.inDuration,
|
|
523
|
-
easing: 'easeOutQuad'
|
|
524
|
-
});
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
_animateOut() {
|
|
528
|
-
this._animateSidenavOut();
|
|
529
|
-
this._animateOverlayOut();
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
_animateSidenavOut() {
|
|
533
|
-
let endPercent = this.options.edge === 'left' ? -1 : 1;
|
|
534
|
-
let slideOutPercent = 0;
|
|
535
|
-
if (this.isDragged) {
|
|
536
|
-
slideOutPercent =
|
|
537
|
-
this.options.edge === 'left'
|
|
538
|
-
? endPercent + this.percentOpen
|
|
539
|
-
: endPercent - this.percentOpen;
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
anim.remove(this.el);
|
|
543
|
-
anim({
|
|
544
|
-
targets: this.el,
|
|
545
|
-
translateX: [`${slideOutPercent * 100}%`, `${endPercent * 105}%`],
|
|
546
|
-
duration: this.options.outDuration,
|
|
547
|
-
easing: 'easeOutQuad',
|
|
548
|
-
complete: () => {
|
|
549
|
-
// Run onOpenEnd callback
|
|
550
|
-
if (typeof this.options.onCloseEnd === 'function') {
|
|
551
|
-
this.options.onCloseEnd.call(this, this.el);
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
});
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
_animateOverlayOut() {
|
|
558
|
-
anim.remove(this._overlay);
|
|
559
|
-
anim({
|
|
560
|
-
targets: this._overlay,
|
|
561
|
-
opacity: 0,
|
|
562
|
-
duration: this.options.outDuration,
|
|
563
|
-
easing: 'easeOutQuad',
|
|
564
|
-
complete: () => {
|
|
565
|
-
$(this._overlay).css('display', 'none');
|
|
566
|
-
}
|
|
567
|
-
});
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
/**
|
|
572
|
-
* @static
|
|
573
|
-
* @memberof Sidenav
|
|
574
|
-
* @type {Array.<Sidenav>}
|
|
575
|
-
*/
|
|
576
|
-
Sidenav._sidenavs = [];
|
|
577
|
-
|
|
578
|
-
M.Sidenav = Sidenav;
|
|
579
|
-
|
|
580
|
-
if (M.jQueryLoaded) {
|
|
581
|
-
M.initializeJqueryWrapper(Sidenav, 'sidenav', 'M_Sidenav');
|
|
582
|
-
}
|
|
583
|
-
})(cash, M.anime);
|
|
1
|
+
(function($, anim) {
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
let _defaults = {
|
|
5
|
+
edge: 'left',
|
|
6
|
+
draggable: true,
|
|
7
|
+
dragTargetWidth: '10px',
|
|
8
|
+
inDuration: 250,
|
|
9
|
+
outDuration: 200,
|
|
10
|
+
onOpenStart: null,
|
|
11
|
+
onOpenEnd: null,
|
|
12
|
+
onCloseStart: null,
|
|
13
|
+
onCloseEnd: null,
|
|
14
|
+
preventScrolling: true
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @class
|
|
19
|
+
*/
|
|
20
|
+
class Sidenav extends Component {
|
|
21
|
+
/**
|
|
22
|
+
* Construct Sidenav instance and set up overlay
|
|
23
|
+
* @constructor
|
|
24
|
+
* @param {Element} el
|
|
25
|
+
* @param {Object} options
|
|
26
|
+
*/
|
|
27
|
+
constructor(el, options) {
|
|
28
|
+
super(Sidenav, el, options);
|
|
29
|
+
|
|
30
|
+
this.el.M_Sidenav = this;
|
|
31
|
+
this.id = this.$el.attr('id');
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Options for the Sidenav
|
|
35
|
+
* @member Sidenav#options
|
|
36
|
+
* @prop {String} [edge='left'] - Side of screen on which Sidenav appears
|
|
37
|
+
* @prop {Boolean} [draggable=true] - Allow swipe gestures to open/close Sidenav
|
|
38
|
+
* @prop {String} [dragTargetWidth='10px'] - Width of the area where you can start dragging
|
|
39
|
+
* @prop {Number} [inDuration=250] - Length in ms of enter transition
|
|
40
|
+
* @prop {Number} [outDuration=200] - Length in ms of exit transition
|
|
41
|
+
* @prop {Function} onOpenStart - Function called when sidenav starts entering
|
|
42
|
+
* @prop {Function} onOpenEnd - Function called when sidenav finishes entering
|
|
43
|
+
* @prop {Function} onCloseStart - Function called when sidenav starts exiting
|
|
44
|
+
* @prop {Function} onCloseEnd - Function called when sidenav finishes exiting
|
|
45
|
+
*/
|
|
46
|
+
this.options = $.extend({}, Sidenav.defaults, options);
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Describes open/close state of Sidenav
|
|
50
|
+
* @type {Boolean}
|
|
51
|
+
*/
|
|
52
|
+
this.isOpen = false;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Describes if Sidenav is fixed
|
|
56
|
+
* @type {Boolean}
|
|
57
|
+
*/
|
|
58
|
+
this.isFixed = this.el.classList.contains('sidenav-fixed');
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Describes if Sidenav is being draggeed
|
|
62
|
+
* @type {Boolean}
|
|
63
|
+
*/
|
|
64
|
+
this.isDragged = false;
|
|
65
|
+
|
|
66
|
+
// Window size variables for window resize checks
|
|
67
|
+
this.lastWindowWidth = window.innerWidth;
|
|
68
|
+
this.lastWindowHeight = window.innerHeight;
|
|
69
|
+
|
|
70
|
+
this._createOverlay();
|
|
71
|
+
this._createDragTarget();
|
|
72
|
+
this._setupEventHandlers();
|
|
73
|
+
this._setupClasses();
|
|
74
|
+
this._setupFixed();
|
|
75
|
+
|
|
76
|
+
Sidenav._sidenavs.push(this);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
static get defaults() {
|
|
80
|
+
return _defaults;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
static init(els, options) {
|
|
84
|
+
return super.init(this, els, options);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Get Instance
|
|
89
|
+
*/
|
|
90
|
+
static getInstance(el) {
|
|
91
|
+
let domElem = !!el.jquery ? el[0] : el;
|
|
92
|
+
return domElem.M_Sidenav;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Teardown component
|
|
97
|
+
*/
|
|
98
|
+
destroy() {
|
|
99
|
+
this._removeEventHandlers();
|
|
100
|
+
this._enableBodyScrolling();
|
|
101
|
+
this._overlay.parentNode.removeChild(this._overlay);
|
|
102
|
+
this.dragTarget.parentNode.removeChild(this.dragTarget);
|
|
103
|
+
this.el.M_Sidenav = undefined;
|
|
104
|
+
this.el.style.transform = '';
|
|
105
|
+
|
|
106
|
+
let index = Sidenav._sidenavs.indexOf(this);
|
|
107
|
+
if (index >= 0) {
|
|
108
|
+
Sidenav._sidenavs.splice(index, 1);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
_createOverlay() {
|
|
113
|
+
let overlay = document.createElement('div');
|
|
114
|
+
this._closeBound = this.close.bind(this);
|
|
115
|
+
overlay.classList.add('sidenav-overlay');
|
|
116
|
+
|
|
117
|
+
overlay.addEventListener('click', this._closeBound);
|
|
118
|
+
|
|
119
|
+
document.body.appendChild(overlay);
|
|
120
|
+
this._overlay = overlay;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
_setupEventHandlers() {
|
|
124
|
+
if (Sidenav._sidenavs.length === 0) {
|
|
125
|
+
document.body.addEventListener('click', this._handleTriggerClick);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
this._handleDragTargetDragBound = this._handleDragTargetDrag.bind(this);
|
|
129
|
+
this._handleDragTargetReleaseBound = this._handleDragTargetRelease.bind(this);
|
|
130
|
+
this._handleCloseDragBound = this._handleCloseDrag.bind(this);
|
|
131
|
+
this._handleCloseReleaseBound = this._handleCloseRelease.bind(this);
|
|
132
|
+
this._handleCloseTriggerClickBound = this._handleCloseTriggerClick.bind(this);
|
|
133
|
+
|
|
134
|
+
this.dragTarget.addEventListener('touchmove', this._handleDragTargetDragBound, passiveIfSupported);
|
|
135
|
+
this.dragTarget.addEventListener('touchend', this._handleDragTargetReleaseBound);
|
|
136
|
+
this._overlay.addEventListener('touchmove', this._handleCloseDragBound, passiveIfSupported);
|
|
137
|
+
this._overlay.addEventListener('touchend', this._handleCloseReleaseBound);
|
|
138
|
+
this.el.addEventListener('touchmove', this._handleCloseDragBound, passiveIfSupported);
|
|
139
|
+
this.el.addEventListener('touchend', this._handleCloseReleaseBound);
|
|
140
|
+
this.el.addEventListener('click', this._handleCloseTriggerClickBound);
|
|
141
|
+
|
|
142
|
+
// Add resize for side nav fixed
|
|
143
|
+
if (this.isFixed) {
|
|
144
|
+
this._handleWindowResizeBound = this._handleWindowResize.bind(this);
|
|
145
|
+
window.addEventListener('resize', this._handleWindowResizeBound);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
_removeEventHandlers() {
|
|
150
|
+
if (Sidenav._sidenavs.length === 1) {
|
|
151
|
+
document.body.removeEventListener('click', this._handleTriggerClick);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
this.dragTarget.removeEventListener('touchmove', this._handleDragTargetDragBound);
|
|
155
|
+
this.dragTarget.removeEventListener('touchend', this._handleDragTargetReleaseBound);
|
|
156
|
+
this._overlay.removeEventListener('touchmove', this._handleCloseDragBound);
|
|
157
|
+
this._overlay.removeEventListener('touchend', this._handleCloseReleaseBound);
|
|
158
|
+
this.el.removeEventListener('touchmove', this._handleCloseDragBound);
|
|
159
|
+
this.el.removeEventListener('touchend', this._handleCloseReleaseBound);
|
|
160
|
+
this.el.removeEventListener('click', this._handleCloseTriggerClickBound);
|
|
161
|
+
|
|
162
|
+
// Remove resize for side nav fixed
|
|
163
|
+
if (this.isFixed) {
|
|
164
|
+
window.removeEventListener('resize', this._handleWindowResizeBound);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Handle Trigger Click
|
|
170
|
+
* @param {Event} e
|
|
171
|
+
*/
|
|
172
|
+
_handleTriggerClick(e) {
|
|
173
|
+
let $trigger = $(e.target).closest('.sidenav-trigger');
|
|
174
|
+
if (e.target && $trigger.length) {
|
|
175
|
+
let sidenavId = M.getIdFromTrigger($trigger[0]);
|
|
176
|
+
|
|
177
|
+
let sidenavInstance = document.getElementById(sidenavId).M_Sidenav;
|
|
178
|
+
if (sidenavInstance) {
|
|
179
|
+
sidenavInstance.open($trigger);
|
|
180
|
+
}
|
|
181
|
+
e.preventDefault();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Set variables needed at the beginning of drag
|
|
187
|
+
* and stop any current transition.
|
|
188
|
+
* @param {Event} e
|
|
189
|
+
*/
|
|
190
|
+
_startDrag(e) {
|
|
191
|
+
let clientX = e.targetTouches[0].clientX;
|
|
192
|
+
this.isDragged = true;
|
|
193
|
+
this._startingXpos = clientX;
|
|
194
|
+
this._xPos = this._startingXpos;
|
|
195
|
+
this._time = Date.now();
|
|
196
|
+
this._width = this.el.getBoundingClientRect().width;
|
|
197
|
+
this._overlay.style.display = 'block';
|
|
198
|
+
this._initialScrollTop = this.isOpen ? this.el.scrollTop : M.getDocumentScrollTop();
|
|
199
|
+
this._verticallyScrolling = false;
|
|
200
|
+
anim.remove(this.el);
|
|
201
|
+
anim.remove(this._overlay);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Set variables needed at each drag move update tick
|
|
206
|
+
* @param {Event} e
|
|
207
|
+
*/
|
|
208
|
+
_dragMoveUpdate(e) {
|
|
209
|
+
let clientX = e.targetTouches[0].clientX;
|
|
210
|
+
let currentScrollTop = this.isOpen ? this.el.scrollTop : M.getDocumentScrollTop();
|
|
211
|
+
this.deltaX = Math.abs(this._xPos - clientX);
|
|
212
|
+
this._xPos = clientX;
|
|
213
|
+
this.velocityX = this.deltaX / (Date.now() - this._time);
|
|
214
|
+
this._time = Date.now();
|
|
215
|
+
if (this._initialScrollTop !== currentScrollTop) {
|
|
216
|
+
this._verticallyScrolling = true;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Handles Dragging of Sidenav
|
|
222
|
+
* @param {Event} e
|
|
223
|
+
*/
|
|
224
|
+
_handleDragTargetDrag(e) {
|
|
225
|
+
// Check if draggable
|
|
226
|
+
if (!this.options.draggable || this._isCurrentlyFixed() || this._verticallyScrolling) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// If not being dragged, set initial drag start variables
|
|
231
|
+
if (!this.isDragged) {
|
|
232
|
+
this._startDrag(e);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Run touchmove updates
|
|
236
|
+
this._dragMoveUpdate(e);
|
|
237
|
+
|
|
238
|
+
// Calculate raw deltaX
|
|
239
|
+
let totalDeltaX = this._xPos - this._startingXpos;
|
|
240
|
+
|
|
241
|
+
// dragDirection is the attempted user drag direction
|
|
242
|
+
let dragDirection = totalDeltaX > 0 ? 'right' : 'left';
|
|
243
|
+
|
|
244
|
+
// Don't allow totalDeltaX to exceed Sidenav width or be dragged in the opposite direction
|
|
245
|
+
totalDeltaX = Math.min(this._width, Math.abs(totalDeltaX));
|
|
246
|
+
if (this.options.edge === dragDirection) {
|
|
247
|
+
totalDeltaX = 0;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* transformX is the drag displacement
|
|
252
|
+
* transformPrefix is the initial transform placement
|
|
253
|
+
* Invert values if Sidenav is right edge
|
|
254
|
+
*/
|
|
255
|
+
let transformX = totalDeltaX;
|
|
256
|
+
let transformPrefix = 'translateX(-100%)';
|
|
257
|
+
if (this.options.edge === 'right') {
|
|
258
|
+
transformPrefix = 'translateX(100%)';
|
|
259
|
+
transformX = -transformX;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Calculate open/close percentage of sidenav, with open = 1 and close = 0
|
|
263
|
+
this.percentOpen = Math.min(1, totalDeltaX / this._width);
|
|
264
|
+
|
|
265
|
+
// Set transform and opacity styles
|
|
266
|
+
this.el.style.transform = `${transformPrefix} translateX(${transformX}px)`;
|
|
267
|
+
this._overlay.style.opacity = this.percentOpen;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Handle Drag Target Release
|
|
272
|
+
*/
|
|
273
|
+
_handleDragTargetRelease() {
|
|
274
|
+
if (this.isDragged) {
|
|
275
|
+
if (this.percentOpen > 0.2) {
|
|
276
|
+
this.open();
|
|
277
|
+
} else {
|
|
278
|
+
this._animateOut();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
this.isDragged = false;
|
|
282
|
+
this._verticallyScrolling = false;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Handle Close Drag
|
|
288
|
+
* @param {Event} e
|
|
289
|
+
*/
|
|
290
|
+
_handleCloseDrag(e) {
|
|
291
|
+
if (this.isOpen) {
|
|
292
|
+
// Check if draggable
|
|
293
|
+
if (!this.options.draggable || this._isCurrentlyFixed() || this._verticallyScrolling) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// If not being dragged, set initial drag start variables
|
|
298
|
+
if (!this.isDragged) {
|
|
299
|
+
this._startDrag(e);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Run touchmove updates
|
|
303
|
+
this._dragMoveUpdate(e);
|
|
304
|
+
|
|
305
|
+
// Calculate raw deltaX
|
|
306
|
+
let totalDeltaX = this._xPos - this._startingXpos;
|
|
307
|
+
|
|
308
|
+
// dragDirection is the attempted user drag direction
|
|
309
|
+
let dragDirection = totalDeltaX > 0 ? 'right' : 'left';
|
|
310
|
+
|
|
311
|
+
// Don't allow totalDeltaX to exceed Sidenav width or be dragged in the opposite direction
|
|
312
|
+
totalDeltaX = Math.min(this._width, Math.abs(totalDeltaX));
|
|
313
|
+
if (this.options.edge !== dragDirection) {
|
|
314
|
+
totalDeltaX = 0;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
let transformX = -totalDeltaX;
|
|
318
|
+
if (this.options.edge === 'right') {
|
|
319
|
+
transformX = -transformX;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Calculate open/close percentage of sidenav, with open = 1 and close = 0
|
|
323
|
+
this.percentOpen = Math.min(1, 1 - totalDeltaX / this._width);
|
|
324
|
+
|
|
325
|
+
// Set transform and opacity styles
|
|
326
|
+
this.el.style.transform = `translateX(${transformX}px)`;
|
|
327
|
+
this._overlay.style.opacity = this.percentOpen;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Handle Close Release
|
|
333
|
+
*/
|
|
334
|
+
_handleCloseRelease() {
|
|
335
|
+
if (this.isOpen && this.isDragged) {
|
|
336
|
+
if (this.percentOpen > 0.8) {
|
|
337
|
+
this._animateIn();
|
|
338
|
+
} else {
|
|
339
|
+
this.close();
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
this.isDragged = false;
|
|
343
|
+
this._verticallyScrolling = false;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Handles closing of Sidenav when element with class .sidenav-close
|
|
349
|
+
*/
|
|
350
|
+
_handleCloseTriggerClick(e) {
|
|
351
|
+
let $closeTrigger = $(e.target).closest('.sidenav-close');
|
|
352
|
+
if ($closeTrigger.length && !this._isCurrentlyFixed()) {
|
|
353
|
+
this.close();
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Handle Window Resize
|
|
359
|
+
*/
|
|
360
|
+
_handleWindowResize() {
|
|
361
|
+
// Only handle horizontal resizes
|
|
362
|
+
if (this.lastWindowWidth !== window.innerWidth) {
|
|
363
|
+
if (window.innerWidth > 992) {
|
|
364
|
+
this.open();
|
|
365
|
+
} else {
|
|
366
|
+
this.close();
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
this.lastWindowWidth = window.innerWidth;
|
|
371
|
+
this.lastWindowHeight = window.innerHeight;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
_setupClasses() {
|
|
375
|
+
if (this.options.edge === 'right') {
|
|
376
|
+
this.el.classList.add('right-aligned');
|
|
377
|
+
this.dragTarget.classList.add('right-aligned');
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
_removeClasses() {
|
|
382
|
+
this.el.classList.remove('right-aligned');
|
|
383
|
+
this.dragTarget.classList.remove('right-aligned');
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
_setupFixed() {
|
|
387
|
+
if (this._isCurrentlyFixed()) {
|
|
388
|
+
this.open();
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
_isCurrentlyFixed() {
|
|
393
|
+
return this.isFixed && window.innerWidth > 992;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
_createDragTarget() {
|
|
397
|
+
let dragTarget = document.createElement('div');
|
|
398
|
+
dragTarget.classList.add('drag-target');
|
|
399
|
+
dragTarget.style.width = this.options.dragTargetWidth;
|
|
400
|
+
document.body.appendChild(dragTarget);
|
|
401
|
+
this.dragTarget = dragTarget;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
_preventBodyScrolling() {
|
|
405
|
+
let body = document.body;
|
|
406
|
+
body.style.overflow = 'hidden';
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
_enableBodyScrolling() {
|
|
410
|
+
let body = document.body;
|
|
411
|
+
body.style.overflow = '';
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
open() {
|
|
415
|
+
if (this.isOpen === true) {
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
this.isOpen = true;
|
|
420
|
+
|
|
421
|
+
// Run onOpenStart callback
|
|
422
|
+
if (typeof this.options.onOpenStart === 'function') {
|
|
423
|
+
this.options.onOpenStart.call(this, this.el);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Handle fixed Sidenav
|
|
427
|
+
if (this._isCurrentlyFixed()) {
|
|
428
|
+
anim.remove(this.el);
|
|
429
|
+
anim({
|
|
430
|
+
targets: this.el,
|
|
431
|
+
translateX: 0,
|
|
432
|
+
duration: 0,
|
|
433
|
+
easing: 'easeOutQuad'
|
|
434
|
+
});
|
|
435
|
+
this._enableBodyScrolling();
|
|
436
|
+
this._overlay.style.display = 'none';
|
|
437
|
+
|
|
438
|
+
// Handle non-fixed Sidenav
|
|
439
|
+
} else {
|
|
440
|
+
if (this.options.preventScrolling) {
|
|
441
|
+
this._preventBodyScrolling();
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
if (!this.isDragged || this.percentOpen != 1) {
|
|
445
|
+
this._animateIn();
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
close() {
|
|
451
|
+
if (this.isOpen === false) {
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
this.isOpen = false;
|
|
456
|
+
|
|
457
|
+
// Run onCloseStart callback
|
|
458
|
+
if (typeof this.options.onCloseStart === 'function') {
|
|
459
|
+
this.options.onCloseStart.call(this, this.el);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// Handle fixed Sidenav
|
|
463
|
+
if (this._isCurrentlyFixed()) {
|
|
464
|
+
let transformX = this.options.edge === 'left' ? '-105%' : '105%';
|
|
465
|
+
this.el.style.transform = `translateX(${transformX})`;
|
|
466
|
+
|
|
467
|
+
// Handle non-fixed Sidenav
|
|
468
|
+
} else {
|
|
469
|
+
this._enableBodyScrolling();
|
|
470
|
+
|
|
471
|
+
if (!this.isDragged || this.percentOpen != 0) {
|
|
472
|
+
this._animateOut();
|
|
473
|
+
} else {
|
|
474
|
+
this._overlay.style.display = 'none';
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
_animateIn() {
|
|
480
|
+
this._animateSidenavIn();
|
|
481
|
+
this._animateOverlayIn();
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
_animateSidenavIn() {
|
|
485
|
+
let slideOutPercent = this.options.edge === 'left' ? -1 : 1;
|
|
486
|
+
if (this.isDragged) {
|
|
487
|
+
slideOutPercent =
|
|
488
|
+
this.options.edge === 'left'
|
|
489
|
+
? slideOutPercent + this.percentOpen
|
|
490
|
+
: slideOutPercent - this.percentOpen;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
anim.remove(this.el);
|
|
494
|
+
anim({
|
|
495
|
+
targets: this.el,
|
|
496
|
+
translateX: [`${slideOutPercent * 100}%`, 0],
|
|
497
|
+
duration: this.options.inDuration,
|
|
498
|
+
easing: 'easeOutQuad',
|
|
499
|
+
complete: () => {
|
|
500
|
+
// Run onOpenEnd callback
|
|
501
|
+
if (typeof this.options.onOpenEnd === 'function') {
|
|
502
|
+
this.options.onOpenEnd.call(this, this.el);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
_animateOverlayIn() {
|
|
509
|
+
let start = 0;
|
|
510
|
+
if (this.isDragged) {
|
|
511
|
+
start = this.percentOpen;
|
|
512
|
+
} else {
|
|
513
|
+
$(this._overlay).css({
|
|
514
|
+
display: 'block'
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
anim.remove(this._overlay);
|
|
519
|
+
anim({
|
|
520
|
+
targets: this._overlay,
|
|
521
|
+
opacity: [start, 1],
|
|
522
|
+
duration: this.options.inDuration,
|
|
523
|
+
easing: 'easeOutQuad'
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
_animateOut() {
|
|
528
|
+
this._animateSidenavOut();
|
|
529
|
+
this._animateOverlayOut();
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
_animateSidenavOut() {
|
|
533
|
+
let endPercent = this.options.edge === 'left' ? -1 : 1;
|
|
534
|
+
let slideOutPercent = 0;
|
|
535
|
+
if (this.isDragged) {
|
|
536
|
+
slideOutPercent =
|
|
537
|
+
this.options.edge === 'left'
|
|
538
|
+
? endPercent + this.percentOpen
|
|
539
|
+
: endPercent - this.percentOpen;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
anim.remove(this.el);
|
|
543
|
+
anim({
|
|
544
|
+
targets: this.el,
|
|
545
|
+
translateX: [`${slideOutPercent * 100}%`, `${endPercent * 105}%`],
|
|
546
|
+
duration: this.options.outDuration,
|
|
547
|
+
easing: 'easeOutQuad',
|
|
548
|
+
complete: () => {
|
|
549
|
+
// Run onOpenEnd callback
|
|
550
|
+
if (typeof this.options.onCloseEnd === 'function') {
|
|
551
|
+
this.options.onCloseEnd.call(this, this.el);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
_animateOverlayOut() {
|
|
558
|
+
anim.remove(this._overlay);
|
|
559
|
+
anim({
|
|
560
|
+
targets: this._overlay,
|
|
561
|
+
opacity: 0,
|
|
562
|
+
duration: this.options.outDuration,
|
|
563
|
+
easing: 'easeOutQuad',
|
|
564
|
+
complete: () => {
|
|
565
|
+
$(this._overlay).css('display', 'none');
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* @static
|
|
573
|
+
* @memberof Sidenav
|
|
574
|
+
* @type {Array.<Sidenav>}
|
|
575
|
+
*/
|
|
576
|
+
Sidenav._sidenavs = [];
|
|
577
|
+
|
|
578
|
+
M.Sidenav = Sidenav;
|
|
579
|
+
|
|
580
|
+
if (M.jQueryLoaded) {
|
|
581
|
+
M.initializeJqueryWrapper(Sidenav, 'sidenav', 'M_Sidenav');
|
|
582
|
+
}
|
|
583
|
+
})(cash, M.anime);
|