Vous êtes connecté en tant que anonymous Se Deconnecter
Browse code

intitial commit to branch nude-framework

git authored on 14/03/2019 10:43:54
Showing 1 changed files
1 1
deleted file mode 100644
... ...
@@ -1,799 +0,0 @@
1
-/*!
2
- * meny 1.4
3
- * http://lab.hakim.se/meny
4
- * MIT licensed
5
- *
6
- * Created by Hakim El Hattab (http://hakim.se, @hakimel)
7
- */
8
-
9
-(function( root, factory ) {
10
-    if( typeof define === 'function' && define.amd ) {
11
-        // AMD module
12
-        define( factory );
13
-    } else {
14
-        // Browser global
15
-        root.Meny = factory();
16
-    }
17
-}(this, function () {
18
-
19
-// Date.now polyfill
20
-if( typeof Date.now !== 'function' ) Date.now = function() { return new Date().getTime(); };
21
-
22
-var Meny = {
23
-
24
-	// Creates a new instance of Meny
25
-	create: function( options ) {
26
-		return (function(){
27
-
28
-			// Make sure the required arguments are defined
29
-			if( !options || !options.menuElement || !options.contentsElement ) {
30
-				throw 'You need to specify which menu and contents elements to use.';
31
-			}
32
-
33
-			// Make sure the menu and contents have the same parent
34
-			if( options.menuElement.parentNode !== options.contentsElement.parentNode ) {
35
-				throw 'The menu and contents elements must have the same parent.';
36
-			}
37
-
38
-			// Constants
39
-			var POSITION_T = 'top',
40
-				POSITION_R = 'right',
41
-				POSITION_B = 'bottom',
42
-				POSITION_L = 'left';
43
-
44
-			// Feature detection for 3D transforms
45
-			var supports3DTransforms =  'WebkitPerspective' in document.body.style ||
46
-										'MozPerspective' in document.body.style ||
47
-										'msPerspective' in document.body.style ||
48
-										'OPerspective' in document.body.style ||
49
-										'perspective' in document.body.style;
50
-
51
-			// Default options, gets extended by passed in arguments
52
-			var config = {
53
-				width: 300,
54
-				height: 300,
55
-				position: POSITION_L,
56
-				threshold: 40,
57
-				angle: 30,
58
-				overlap: 6,
59
-				transitionDuration: '0.5s',
60
-				transitionEasing: 'ease',
61
-				gradient: 'rgba(0,0,0,0.20) 0%, rgba(0,0,0,0.65) 100%)',
62
-				mouse: true,
63
-				touch: true
64
-			};
65
-
66
-			// Cache references to DOM elements
67
-			var dom = {
68
-				menu: options.menuElement,
69
-				contents: options.contentsElement,
70
-				wrapper: options.menuElement.parentNode,
71
-				cover: null
72
-			};
73
-
74
-			// State and input
75
-			var indentX = dom.wrapper.offsetLeft,
76
-				indentY = dom.wrapper.offsetTop,
77
-				touchStartX = null,
78
-				touchStartY = null,
79
-				touchMoveX = null,
80
-				touchMoveY = null,
81
-				isOpen = false,
82
-				isMouseDown = false;
83
-
84
-			// Precalculated transform and style states
85
-			var menuTransformOrigin,
86
-				menuTransformClosed,
87
-				menuTransformOpened,
88
-				menuStyleClosed,
89
-				menuStyleOpened,
90
-
91
-				contentsTransformOrigin,
92
-				contentsTransformClosed,
93
-				contentsTransformOpened,
94
-				contentsStyleClosed,
95
-				contentsStyleOpened;
96
-
97
-			var originalStyles = {},
98
-				addedEventListeners = [];
99
-
100
-			// Ongoing animations (for fallback mode)
101
-			var menuAnimation,
102
-				contentsAnimation,
103
-				coverAnimation;
104
-
105
-			configure( options );
106
-
107
-			/**
108
-			 * Initializes Meny with the specified user options,
109
-			 * may be called multiple times as configuration changes.
110
-			 */
111
-			function configure( o ) {
112
-				// Extend the default config object with the passed in
113
-				// options
114
-				Meny.extend( config, o );
115
-
116
-				setupPositions();
117
-				setupWrapper();
118
-				setupCover();
119
-				setupMenu();
120
-				setupContents();
121
-
122
-				bindEvents();
123
-			}
124
-
125
-			/**
126
-			 * Prepares the transforms for the current positioning
127
-			 * settings.
128
-			 */
129
-			function setupPositions() {
130
-				menuTransformOpened = '';
131
-				contentsTransformClosed = '';
132
-				menuAngle = config.angle;
133
-				contentsAngle = config.angle / -2;
134
-
135
-				switch( config.position ) {
136
-					case POSITION_T:
137
-						// Primary transform:
138
-						menuTransformOrigin = '50% 0%';
139
-						menuTransformClosed = 'rotateX( ' + menuAngle + 'deg ) translateY( -100% ) translateY( '+ config.overlap +'px )';
140
-						contentsTransformOrigin = '50% 0';
141
-						contentsTransformOpened = 'translateY( '+ config.height +'px ) rotateX( ' + contentsAngle + 'deg )';
142
-
143
-						// Position fallback:
144
-						menuStyleClosed = { top: '-' + (config.height-config.overlap) + 'px' };
145
-						menuStyleOpened = { top: '0px' };
146
-						contentsStyleClosed = { top: '0px' };
147
-						contentsStyleOpened = { top: config.height + 'px' };
148
-						break;
149
-
150
-					case POSITION_R:
151
-						// Primary transform:
152
-						menuTransformOrigin = '100% 50%';
153
-						menuTransformClosed = 'rotateY( ' + menuAngle + 'deg ) translateX( 100% ) translateX( -2px ) scale( 1.01 )';
154
-						contentsTransformOrigin = '100% 50%';
155
-						contentsTransformOpened = 'translateX( -'+ config.width +'px ) rotateY( ' + contentsAngle + 'deg )';
156
-
157
-						// Position fallback:
158
-						menuStyleClosed = { right: '-' + (config.width-config.overlap) + 'px' };
159
-						menuStyleOpened = { right: '0px' };
160
-						contentsStyleClosed = { left: '0px' };
161
-						contentsStyleOpened = { left: '-' + config.width + 'px' };
162
-						break;
163
-
164
-					case POSITION_B:
165
-						// Primary transform:
166
-						menuTransformOrigin = '50% 100%';
167
-						menuTransformClosed = 'rotateX( ' + -menuAngle + 'deg ) translateY( 100% ) translateY( -'+ config.overlap +'px )';
168
-						contentsTransformOrigin = '50% 100%';
169
-						contentsTransformOpened = 'translateY( -'+ config.height +'px ) rotateX( ' + -contentsAngle + 'deg )';
170
-
171
-						// Position fallback:
172
-						menuStyleClosed = { bottom: '-' + (config.height-config.overlap) + 'px' };
173
-						menuStyleOpened = { bottom: '0px' };
174
-						contentsStyleClosed = { top: '0px' };
175
-						contentsStyleOpened = { top: '-' + config.height + 'px' };
176
-						break;
177
-
178
-					default:
179
-						// Primary transform:
180
-						menuTransformOrigin = '100% 50%';
181
-						menuTransformClosed = 'translateX( -100% ) translateX( '+ config.overlap +'px ) scale( 1.01 ) rotateY( ' + -menuAngle + 'deg )';
182
-						contentsTransformOrigin = '0 50%';
183
-						contentsTransformOpened = 'translateX( '+ config.width +'px ) rotateY( ' + -contentsAngle + 'deg )';
184
-
185
-						// Position fallback:
186
-						menuStyleClosed = { left: '-' + (config.width-config.overlap) + 'px' };
187
-						menuStyleOpened = { left: '0px' };
188
-						contentsStyleClosed = { left: '0px' };
189
-						contentsStyleOpened = { left: config.width + 'px' };
190
-						break;
191
-				}
192
-			}
193
-
194
-			/**
195
-			 * The wrapper element holds the menu and contents.
196
-			 */
197
-			function setupWrapper() {
198
-				// Add a class to allow for custom styles based on
199
-				// position
200
-				Meny.addClass( dom.wrapper, 'meny-' + config.position );
201
-
202
-				originalStyles.wrapper = dom.wrapper.style.cssText;
203
-
204
-				dom.wrapper.style[ Meny.prefix( 'perspective' ) ] = '800px';
205
-				dom.wrapper.style[ Meny.prefix( 'perspectiveOrigin' ) ] = contentsTransformOrigin;
206
-			}
207
-
208
-			/**
209
-			 * The cover is used to obfuscate the contents while
210
-			 * Meny is open.
211
-			 */
212
-			function setupCover() {
213
-				if( dom.cover ) {
214
-					dom.cover.parentNode.removeChild( dom.cover );
215
-				}
216
-
217
-				dom.cover = document.createElement( 'div' );
218
-
219
-				// Disabled until a falback fade in animation is added
220
-				dom.cover.style.position = 'absolute';
221
-				dom.cover.style.display = 'block';
222
-				dom.cover.style.width = '100%';
223
-				dom.cover.style.height = '100%';
224
-				dom.cover.style.left = 0;
225
-				dom.cover.style.top = 0;
226
-				dom.cover.style.zIndex = 1000;
227
-				dom.cover.style.visibility = 'hidden';
228
-				dom.cover.style.opacity = 0;
229
-
230
-				// Silence unimportant errors in IE8
231
-				try {
232
-					dom.cover.style.background = 'rgba( 0, 0, 0, 0.4 )';
233
-					dom.cover.style.background = '-ms-linear-gradient('+ config.position +','+ config.gradient;
234
-					dom.cover.style.background = '-moz-linear-gradient('+ config.position +','+ config.gradient;
235
-					dom.cover.style.background = '-webkit-linear-gradient('+ config.position +','+ config.gradient;
236
-				}
237
-				catch( e ) {}
238
-
239
-				if( supports3DTransforms ) {
240
-					dom.cover.style[ Meny.prefix( 'transition' ) ] = 'all ' + config.transitionDuration +' '+ config.transitionEasing;
241
-				}
242
-
243
-				dom.contents.appendChild( dom.cover );
244
-			}
245
-
246
-			/**
247
-			 * The meny element that folds out upon activation.
248
-			 */
249
-			function setupMenu() {
250
-				// Shorthand
251
-				var style = dom.menu.style;
252
-
253
-				switch( config.position ) {
254
-					case POSITION_T:
255
-						style.width = '100%';
256
-						style.height = config.height + 'px';
257
-						break;
258
-
259
-					case POSITION_R:
260
-						style.right = '0';
261
-						style.width = config.width + 'px';
262
-						style.height = '100%';
263
-						break;
264
-
265
-					case POSITION_B:
266
-						style.bottom = '0';
267
-						style.width = '100%';
268
-						style.height = config.height + 'px';
269
-						break;
270
-
271
-					case POSITION_L:
272
-						style.width = config.width + 'px';
273
-						style.height = '100%';
274
-						break;
275
-				}
276
-
277
-				originalStyles.menu = style.cssText;
278
-
279
-				style.position = 'fixed';
280
-				style.display = 'block';
281
-				style.zIndex = 1;
282
-
283
-				if( supports3DTransforms ) {
284
-					style[ Meny.prefix( 'transform' ) ] = menuTransformClosed;
285
-					style[ Meny.prefix( 'transformOrigin' ) ] = menuTransformOrigin;
286
-					style[ Meny.prefix( 'transition' ) ] = 'all ' + config.transitionDuration +' '+ config.transitionEasing;
287
-				}
288
-				else {
289
-					Meny.extend( style, menuStyleClosed );
290
-				}
291
-			}
292
-
293
-			/**
294
-			 * The contents element which gets pushed aside while
295
-			 * Meny is open.
296
-			 */
297
-			function setupContents() {
298
-				// Shorthand
299
-				var style = dom.contents.style;
300
-
301
-				originalStyles.contents = style.cssText;
302
-
303
-				if( supports3DTransforms ) {
304
-					style[ Meny.prefix( 'transform' ) ] = contentsTransformClosed;
305
-					style[ Meny.prefix( 'transformOrigin' ) ] = contentsTransformOrigin;
306
-					style[ Meny.prefix( 'transition' ) ] = 'all ' + config.transitionDuration +' '+ config.transitionEasing;
307
-				}
308
-				else {
309
-					style.position = style.position.match( /relative|absolute|fixed/gi ) ? style.position : 'relative';
310
-					Meny.extend( style, contentsStyleClosed );
311
-				}
312
-			}
313
-
314
-			/**
315
-			 * Attaches all input event listeners.
316
-			 */
317
-			function bindEvents() {
318
-
319
-				if( 'ontouchstart' in window ) {
320
-					if( config.touch ) {
321
-						Meny.bindEvent( document, 'touchstart', onTouchStart );
322
-						Meny.bindEvent( document, 'touchend', onTouchEnd );
323
-					}
324
-					else {
325
-						Meny.unbindEvent( document, 'touchstart', onTouchStart );
326
-						Meny.unbindEvent( document, 'touchend', onTouchEnd );
327
-					}
328
-				}
329
-
330
-				if( config.mouse ) {
331
-					Meny.bindEvent( document, 'mousedown', onMouseDown );
332
-					Meny.bindEvent( document, 'mouseup', onMouseUp );
333
-					Meny.bindEvent( document, 'mousemove', onMouseMove );
334
-				}
335
-				else {
336
-					Meny.unbindEvent( document, 'mousedown', onMouseDown );
337
-					Meny.unbindEvent( document, 'mouseup', onMouseUp );
338
-					Meny.unbindEvent( document, 'mousemove', onMouseMove );
339
-				}
340
-			}
341
-
342
-			/**
343
-			 * Expands the menu.
344
-			 */
345
-			function open() {
346
-				if( !isOpen ) {
347
-					isOpen = true;
348
-
349
-					Meny.addClass( dom.wrapper, 'meny-active' );
350
-
351
-					dom.cover.style.height = dom.contents.scrollHeight + 'px';
352
-					dom.cover.style.visibility = 'visible';
353
-
354
-					// Use transforms and transitions if available...
355
-					if( supports3DTransforms ) {
356
-						// 'webkitAnimationEnd oanimationend msAnimationEnd animationend transitionend'
357
-						Meny.bindEventOnce( dom.wrapper, 'transitionend', function() {
358
-							Meny.dispatchEvent( dom.menu, 'opened' );
359
-						} );
360
-
361
-						dom.cover.style.opacity = 1;
362
-
363
-						dom.contents.style[ Meny.prefix( 'transform' ) ] = contentsTransformOpened;
364
-						dom.menu.style[ Meny.prefix( 'transform' ) ] = menuTransformOpened;
365
-					}
366
-					// ...fall back on JS animation
367
-					else {
368
-						menuAnimation && menuAnimation.stop();
369
-						menuAnimation = Meny.animate( dom.menu, menuStyleOpened, 500 );
370
-						contentsAnimation && contentsAnimation.stop();
371
-						contentsAnimation = Meny.animate( dom.contents, contentsStyleOpened, 500 );
372
-						coverAnimation && coverAnimation.stop();
373
-						coverAnimation = Meny.animate( dom.cover, { opacity: 1 }, 500 );
374
-					}
375
-
376
-					Meny.dispatchEvent( dom.menu, 'open' );
377
-				}
378
-			}
379
-
380
-			/**
381
-			 * Collapses the menu.
382
-			 */
383
-			function close() {
384
-				if( isOpen ) {
385
-					isOpen = false;
386
-
387
-					Meny.removeClass( dom.wrapper, 'meny-active' );
388
-
389
-					// Use transforms and transitions if available...
390
-					if( supports3DTransforms ) {
391
-						// 'webkitAnimationEnd oanimationend msAnimationEnd animationend transitionend'
392
-						Meny.bindEventOnce( dom.wrapper, 'transitionend', function() {
393
-							Meny.dispatchEvent( dom.menu, 'closed' );
394
-						} );
395
-
396
-						dom.cover.style.visibility = 'hidden';
397
-						dom.cover.style.opacity = 0;
398
-
399
-						dom.contents.style[ Meny.prefix( 'transform' ) ] = contentsTransformClosed;
400
-						dom.menu.style[ Meny.prefix( 'transform' ) ] = menuTransformClosed;
401
-					}
402
-					// ...fall back on JS animation
403
-					else {
404
-						menuAnimation && menuAnimation.stop();
405
-						menuAnimation = Meny.animate( dom.menu, menuStyleClosed, 500 );
406
-						contentsAnimation && contentsAnimation.stop();
407
-						contentsAnimation = Meny.animate( dom.contents, contentsStyleClosed, 500 );
408
-						coverAnimation && coverAnimation.stop();
409
-						coverAnimation = Meny.animate( dom.cover, { opacity: 0 }, 500, function() {
410
-							dom.cover.style.visibility = 'hidden';
411
-							Meny.dispatchEvent( dom.menu, 'closed' );
412
-						} );
413
-					}
414
-					Meny.dispatchEvent( dom.menu, 'close' );
415
-				}
416
-			}
417
-
418
-			/**
419
-			 * Unbinds Meny and resets the DOM to the state it
420
-			 * was at before Meny was initialized.
421
-			 */
422
-			function destroy() {
423
-				dom.wrapper.style.cssText = originalStyles.wrapper
424
-				dom.menu.style.cssText = originalStyles.menu;
425
-				dom.contents.style.cssText = originalStyles.contents;
426
-
427
-				if( dom.cover && dom.cover.parentNode ) {
428
-					dom.cover.parentNode.removeChild( dom.cover );
429
-				}
430
-
431
-				Meny.unbindEvent( document, 'touchstart', onTouchStart );
432
-				Meny.unbindEvent( document, 'touchend', onTouchEnd );
433
-				Meny.unbindEvent( document, 'mousedown', onMouseDown );
434
-				Meny.unbindEvent( document, 'mouseup', onMouseUp );
435
-				Meny.unbindEvent( document, 'mousemove', onMouseMove );
436
-
437
-				for( var i in addedEventListeners ) {
438
-					this.removeEventListener( addedEventListeners[i][0], addedEventListeners[i][1] );
439
-				}
440
-
441
-				addedEventListeners = [];
442
-			}
443
-
444
-
445
-			/// INPUT: /////////////////////////////////
446
-
447
-			function onMouseDown( event ) {
448
-				isMouseDown = true;
449
-			}
450
-
451
-			function onMouseMove( event ) {
452
-				// Prevent opening/closing when mouse is down since
453
-				// the user may be selecting text
454
-				if( !isMouseDown ) {
455
-					var x = event.clientX - indentX,
456
-						y = event.clientY - indentY;
457
-
458
-					switch( config.position ) {
459
-						case POSITION_T:
460
-							if( y > config.height ) {
461
-								close();
462
-							}
463
-							else if( y < config.threshold ) {
464
-								open();
465
-							}
466
-							break;
467
-
468
-						case POSITION_R:
469
-							var w = dom.wrapper.offsetWidth;
470
-							if( x < w - config.width ) {
471
-								close();
472
-							}
473
-							else if( x > w - config.threshold ) {
474
-								open();
475
-							}
476
-							break;
477
-
478
-						case POSITION_B:
479
-							var h = dom.wrapper.offsetHeight;
480
-							if( y < h - config.height ) {
481
-								close();
482
-							}
483
-							else if( y > h - config.threshold ) {
484
-								open();
485
-							}
486
-							break;
487
-
488
-						case POSITION_L:
489
-							if( x > config.width ) {
490
-								close();
491
-							}
492
-							else if( x < config.threshold ) {
493
-								open();
494
-							}
495
-							break;
496
-					}
497
-				}
498
-			}
499
-
500
-			function onMouseUp( event ) {
501
-				isMouseDown = false;
502
-			}
503
-
504
-			function onTouchStart( event ) {
505
-				touchStartX = event.touches[0].clientX - indentX;
506
-				touchStartY = event.touches[0].clientY - indentY;
507
-				touchMoveX = null;
508
-				touchMoveY = null;
509
-
510
-				Meny.bindEvent( document, 'touchmove', onTouchMove );
511
-			}
512
-
513
-			function onTouchMove( event ) {
514
-				touchMoveX = event.touches[0].clientX - indentX;
515
-				touchMoveY = event.touches[0].clientY - indentY;
516
-
517
-				var swipeMethod = null;
518
-
519
-				// Check for swipe gestures in any direction
520
-
521
-				if( Math.abs( touchMoveX - touchStartX ) > Math.abs( touchMoveY - touchStartY ) ) {
522
-					if( touchMoveX < touchStartX - config.threshold ) {
523
-						swipeMethod = onSwipeRight;
524
-					}
525
-					else if( touchMoveX > touchStartX + config.threshold ) {
526
-						swipeMethod = onSwipeLeft;
527
-					}
528
-				}
529
-				else {
530
-					if( touchMoveY < touchStartY - config.threshold ) {
531
-						swipeMethod = onSwipeDown;
532
-					}
533
-					else if( touchMoveY > touchStartY + config.threshold ) {
534
-						swipeMethod = onSwipeUp;
535
-					}
536
-				}
537
-
538
-				if( swipeMethod && swipeMethod() ) {
539
-					event.preventDefault();
540
-				}
541
-			}
542
-
543
-			function onTouchEnd( event ) {
544
-				Meny.unbindEvent( document, 'touchmove', onTouchMove );
545
-
546
-				// If there was no movement this was a tap
547
-				if( touchMoveX === null && touchMoveY === null ) {
548
-					onTap();
549
-				}
550
-			}
551
-
552
-			function onTap() {
553
-				var isOverContent = ( config.position === POSITION_T && touchStartY > config.height ) ||
554
-									( config.position === POSITION_R && touchStartX < dom.wrapper.offsetWidth - config.width ) ||
555
-									( config.position === POSITION_B && touchStartY < dom.wrapper.offsetHeight - config.height ) ||
556
-									( config.position === POSITION_L && touchStartX > config.width );
557
-
558
-				if( isOverContent ) {
559
-					close();
560
-				}
561
-			}
562
-
563
-			function onSwipeLeft() {
564
-				if( config.position === POSITION_R && isOpen ) {
565
-					close();
566
-					return true;
567
-				}
568
-				else if( config.position === POSITION_L && !isOpen ) {
569
-					open();
570
-					return true;
571
-				}
572
-			}
573
-
574
-			function onSwipeRight() {
575
-				if( config.position === POSITION_R && !isOpen ) {
576
-					open();
577
-					return true;
578
-				}
579
-				else if( config.position === POSITION_L && isOpen ) {
580
-					close();
581
-					return true;
582
-				}
583
-			}
584
-
585
-			function onSwipeUp() {
586
-				if( config.position === POSITION_B && isOpen ) {
587
-					close();
588
-					return true;
589
-				}
590
-				else if( config.position === POSITION_T && !isOpen ) {
591
-					open();
592
-					return true;
593
-				}
594
-			}
595
-
596
-			function onSwipeDown() {
597
-				if( config.position === POSITION_B && !isOpen ) {
598
-					open();
599
-					return true;
600
-				}
601
-				else if( config.position === POSITION_T && isOpen ) {
602
-					close();
603
-					return true;
604
-				}
605
-			}
606
-
607
-
608
-			/// API: ///////////////////////////////////
609
-
610
-			return {
611
-				configure: configure,
612
-
613
-				open: open,
614
-				close: close,
615
-				destroy: destroy,
616
-
617
-				isOpen: function() {
618
-					return isOpen;
619
-				},
620
-
621
-				/**
622
-				 * Forward event binding to the menu DOM element.
623
-				 */
624
-				addEventListener: function( type, listener ) {
625
-					addedEventListeners.push( [type, listener] );
626
-					dom.menu && Meny.bindEvent( dom.menu, type, listener );
627
-				},
628
-				removeEventListener: function( type, listener ) {
629
-					dom.menu && Meny.unbindEvent( dom.menu, type, listener );
630
-				}
631
-			};
632
-
633
-		})();
634
-	},
635
-
636
-	/**
637
-	 * Helper method, changes an element style over time.
638
-	 */
639
-	animate: function( element, properties, duration, callback ) {
640
-		return (function() {
641
-			// Will hold start/end values for all properties
642
-			var interpolations = {};
643
-
644
-			// Format properties
645
-			for( var p in properties ) {
646
-				interpolations[p] = {
647
-					start: parseFloat( element.style[p] ) || 0,
648
-					end: parseFloat( properties[p] ),
649
-					unit: ( typeof properties[p] === 'string' && properties[p].match( /px|em|%/gi ) ) ? properties[p].match( /px|em|%/gi )[0] : ''
650
-				};
651
-			}
652
-
653
-			var animationStartTime = Date.now(),
654
-				animationTimeout;
655
-
656
-			// Takes one step forward in the animation
657
-			function step() {
658
-				// Ease out
659
-				var progress = 1 - Math.pow( 1 - ( ( Date.now() - animationStartTime ) / duration ), 5 );
660
-
661
-				// Set style to interpolated value
662
-				for( var p in interpolations ) {
663
-					var property = interpolations[p];
664
-					element.style[p] = property.start + ( ( property.end - property.start ) * progress ) + property.unit;
665
-				}
666
-
667
-				// Continue as long as we're not done
668
-				if( progress < 1 ) {
669
-					animationTimeout = setTimeout( step, 1000 / 60 );
670
-				}
671
-				else {
672
-					callback && callback();
673
-					stop();
674
-				}
675
-			}
676
-
677
-			// Cancels the animation
678
-			function stop() {
679
-				clearTimeout( animationTimeout );
680
-			}
681
-
682
-			// Starts the animation
683
-			step();
684
-
685
-
686
-			/// API: ///////////////////////////////////
687
-
688
-			return {
689
-				stop: stop
690
-			};
691
-		})();
692
-	},
693
-
694
-	/**
695
-	 * Extend object a with the properties of object b.
696
-	 * If there's a conflict, object b takes precedence.
697
-	 */
698
-	extend: function( a, b ) {
699
-		for( var i in b ) {
700
-			a[ i ] = b[ i ];
701
-		}
702
-	},
703
-
704
-	/**
705
-	 * Prefixes a style property with the correct vendor.
706
-	 */
707
-	prefix: function( property, el ) {
708
-		var propertyUC = property.slice( 0, 1 ).toUpperCase() + property.slice( 1 ),
709
-			vendors = [ 'Webkit', 'Moz', 'O', 'ms' ];
710
-
711
-		for( var i = 0, len = vendors.length; i < len; i++ ) {
712
-			var vendor = vendors[i];
713
-
714
-			if( typeof ( el || document.body ).style[ vendor + propertyUC ] !== 'undefined' ) {
715
-				return vendor + propertyUC;
716
-			}
717
-		}
718
-
719
-		return property;
720
-	},
721
-
722
-	/**
723
-	 * Adds a class to the target element.
724
-	 */
725
-	addClass: function( element, name ) {
726
-		element.className = element.className.replace( /\s+$/gi, '' ) + ' ' + name;
727
-	},
728
-
729
-	/**
730
-	 * Removes a class from the target element.
731
-	 */
732
-	removeClass: function( element, name ) {
733
-		element.className = element.className.replace( name, '' );
734
-	},
735
-
736
-	/**
737
-	 * Adds an event listener in a browser safe way.
738
-	 */
739
-	bindEvent: function( element, ev, fn ) {
740
-		if( element.addEventListener ) {
741
-			element.addEventListener( ev, fn, false );
742
-		}
743
-		else {
744
-			element.attachEvent( 'on' + ev, fn );
745
-		}
746
-	},
747
-
748
-	/**
749
-	 * Removes an event listener in a browser safe way.
750
-	 */
751
-	unbindEvent: function( element, ev, fn ) {
752
-		if( element.removeEventListener ) {
753
-			element.removeEventListener( ev, fn, false );
754
-		}
755
-		else {
756
-			element.detachEvent( 'on' + ev, fn );
757
-		}
758
-	},
759
-
760
-	bindEventOnce: function ( element, ev, fn ) {
761
-		var me = this;
762
-		var listener = function() {
763
-			me.unbindEvent( element, ev, listener );
764
-			fn.apply( this, arguments );
765
-		};
766
-		this.bindEvent( element, ev, listener );
767
-	},
768
-
769
-	/**
770
-	 * Dispatches an event of the specified type from the
771
-	 * menu DOM element.
772
-	 */
773
-	dispatchEvent: function( element, type, properties ) {
774
-		if( element ) {
775
-			var event = document.createEvent( "HTMLEvents", 1, 2 );
776
-			event.initEvent( type, true, true );
777
-			Meny.extend( event, properties );
778
-			element.dispatchEvent( event );
779
-		}
780
-	},
781
-
782
-	/**
783
-	 * Retrieves query string as a key/value hash.
784
-	 */
785
-	getQuery: function() {
786
-		var query = {};
787
-
788
-		location.search.replace( /[A-Z0-9]+?=([\w|:|\/\.]*)/gi, function(a) {
789
-			query[ a.split( '=' ).shift() ] = a.split( '=' ).pop();
790
-		} );
791
-
792
-		return query;
793
-	}
794
-
795
-};
796
-
797
-return Meny;
798
-
799
-}));
Browse code

liaison controlleur et vues ok !

git authored on 05/03/2019 16:49:15
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,799 @@
1
+/*!
2
+ * meny 1.4
3
+ * http://lab.hakim.se/meny
4
+ * MIT licensed
5
+ *
6
+ * Created by Hakim El Hattab (http://hakim.se, @hakimel)
7
+ */
8
+
9
+(function( root, factory ) {
10
+    if( typeof define === 'function' && define.amd ) {
11
+        // AMD module
12
+        define( factory );
13
+    } else {
14
+        // Browser global
15
+        root.Meny = factory();
16
+    }
17
+}(this, function () {
18
+
19
+// Date.now polyfill
20
+if( typeof Date.now !== 'function' ) Date.now = function() { return new Date().getTime(); };
21
+
22
+var Meny = {
23
+
24
+	// Creates a new instance of Meny
25
+	create: function( options ) {
26
+		return (function(){
27
+
28
+			// Make sure the required arguments are defined
29
+			if( !options || !options.menuElement || !options.contentsElement ) {
30
+				throw 'You need to specify which menu and contents elements to use.';
31
+			}
32
+
33
+			// Make sure the menu and contents have the same parent
34
+			if( options.menuElement.parentNode !== options.contentsElement.parentNode ) {
35
+				throw 'The menu and contents elements must have the same parent.';
36
+			}
37
+
38
+			// Constants
39
+			var POSITION_T = 'top',
40
+				POSITION_R = 'right',
41
+				POSITION_B = 'bottom',
42
+				POSITION_L = 'left';
43
+
44
+			// Feature detection for 3D transforms
45
+			var supports3DTransforms =  'WebkitPerspective' in document.body.style ||
46
+										'MozPerspective' in document.body.style ||
47
+										'msPerspective' in document.body.style ||
48
+										'OPerspective' in document.body.style ||
49
+										'perspective' in document.body.style;
50
+
51
+			// Default options, gets extended by passed in arguments
52
+			var config = {
53
+				width: 300,
54
+				height: 300,
55
+				position: POSITION_L,
56
+				threshold: 40,
57
+				angle: 30,
58
+				overlap: 6,
59
+				transitionDuration: '0.5s',
60
+				transitionEasing: 'ease',
61
+				gradient: 'rgba(0,0,0,0.20) 0%, rgba(0,0,0,0.65) 100%)',
62
+				mouse: true,
63
+				touch: true
64
+			};
65
+
66
+			// Cache references to DOM elements
67
+			var dom = {
68
+				menu: options.menuElement,
69
+				contents: options.contentsElement,
70
+				wrapper: options.menuElement.parentNode,
71
+				cover: null
72
+			};
73
+
74
+			// State and input
75
+			var indentX = dom.wrapper.offsetLeft,
76
+				indentY = dom.wrapper.offsetTop,
77
+				touchStartX = null,
78
+				touchStartY = null,
79
+				touchMoveX = null,
80
+				touchMoveY = null,
81
+				isOpen = false,
82
+				isMouseDown = false;
83
+
84
+			// Precalculated transform and style states
85
+			var menuTransformOrigin,
86
+				menuTransformClosed,
87
+				menuTransformOpened,
88
+				menuStyleClosed,
89
+				menuStyleOpened,
90
+
91
+				contentsTransformOrigin,
92
+				contentsTransformClosed,
93
+				contentsTransformOpened,
94
+				contentsStyleClosed,
95
+				contentsStyleOpened;
96
+
97
+			var originalStyles = {},
98
+				addedEventListeners = [];
99
+
100
+			// Ongoing animations (for fallback mode)
101
+			var menuAnimation,
102
+				contentsAnimation,
103
+				coverAnimation;
104
+
105
+			configure( options );
106
+
107
+			/**
108
+			 * Initializes Meny with the specified user options,
109
+			 * may be called multiple times as configuration changes.
110
+			 */
111
+			function configure( o ) {
112
+				// Extend the default config object with the passed in
113
+				// options
114
+				Meny.extend( config, o );
115
+
116
+				setupPositions();
117
+				setupWrapper();
118
+				setupCover();
119
+				setupMenu();
120
+				setupContents();
121
+
122
+				bindEvents();
123
+			}
124
+
125
+			/**
126
+			 * Prepares the transforms for the current positioning
127
+			 * settings.
128
+			 */
129
+			function setupPositions() {
130
+				menuTransformOpened = '';
131
+				contentsTransformClosed = '';
132
+				menuAngle = config.angle;
133
+				contentsAngle = config.angle / -2;
134
+
135
+				switch( config.position ) {
136
+					case POSITION_T:
137
+						// Primary transform:
138
+						menuTransformOrigin = '50% 0%';
139
+						menuTransformClosed = 'rotateX( ' + menuAngle + 'deg ) translateY( -100% ) translateY( '+ config.overlap +'px )';
140
+						contentsTransformOrigin = '50% 0';
141
+						contentsTransformOpened = 'translateY( '+ config.height +'px ) rotateX( ' + contentsAngle + 'deg )';
142
+
143
+						// Position fallback:
144
+						menuStyleClosed = { top: '-' + (config.height-config.overlap) + 'px' };
145
+						menuStyleOpened = { top: '0px' };
146
+						contentsStyleClosed = { top: '0px' };
147
+						contentsStyleOpened = { top: config.height + 'px' };
148
+						break;
149
+
150
+					case POSITION_R:
151
+						// Primary transform:
152
+						menuTransformOrigin = '100% 50%';
153
+						menuTransformClosed = 'rotateY( ' + menuAngle + 'deg ) translateX( 100% ) translateX( -2px ) scale( 1.01 )';
154
+						contentsTransformOrigin = '100% 50%';
155
+						contentsTransformOpened = 'translateX( -'+ config.width +'px ) rotateY( ' + contentsAngle + 'deg )';
156
+
157
+						// Position fallback:
158
+						menuStyleClosed = { right: '-' + (config.width-config.overlap) + 'px' };
159
+						menuStyleOpened = { right: '0px' };
160
+						contentsStyleClosed = { left: '0px' };
161
+						contentsStyleOpened = { left: '-' + config.width + 'px' };
162
+						break;
163
+
164
+					case POSITION_B:
165
+						// Primary transform:
166
+						menuTransformOrigin = '50% 100%';
167
+						menuTransformClosed = 'rotateX( ' + -menuAngle + 'deg ) translateY( 100% ) translateY( -'+ config.overlap +'px )';
168
+						contentsTransformOrigin = '50% 100%';
169
+						contentsTransformOpened = 'translateY( -'+ config.height +'px ) rotateX( ' + -contentsAngle + 'deg )';
170
+
171
+						// Position fallback:
172
+						menuStyleClosed = { bottom: '-' + (config.height-config.overlap) + 'px' };
173
+						menuStyleOpened = { bottom: '0px' };
174
+						contentsStyleClosed = { top: '0px' };
175
+						contentsStyleOpened = { top: '-' + config.height + 'px' };
176
+						break;
177
+
178
+					default:
179
+						// Primary transform:
180
+						menuTransformOrigin = '100% 50%';
181
+						menuTransformClosed = 'translateX( -100% ) translateX( '+ config.overlap +'px ) scale( 1.01 ) rotateY( ' + -menuAngle + 'deg )';
182
+						contentsTransformOrigin = '0 50%';
183
+						contentsTransformOpened = 'translateX( '+ config.width +'px ) rotateY( ' + -contentsAngle + 'deg )';
184
+
185
+						// Position fallback:
186
+						menuStyleClosed = { left: '-' + (config.width-config.overlap) + 'px' };
187
+						menuStyleOpened = { left: '0px' };
188
+						contentsStyleClosed = { left: '0px' };
189
+						contentsStyleOpened = { left: config.width + 'px' };
190
+						break;
191
+				}
192
+			}
193
+
194
+			/**
195
+			 * The wrapper element holds the menu and contents.
196
+			 */
197
+			function setupWrapper() {
198
+				// Add a class to allow for custom styles based on
199
+				// position
200
+				Meny.addClass( dom.wrapper, 'meny-' + config.position );
201
+
202
+				originalStyles.wrapper = dom.wrapper.style.cssText;
203
+
204
+				dom.wrapper.style[ Meny.prefix( 'perspective' ) ] = '800px';
205
+				dom.wrapper.style[ Meny.prefix( 'perspectiveOrigin' ) ] = contentsTransformOrigin;
206
+			}
207
+
208
+			/**
209
+			 * The cover is used to obfuscate the contents while
210
+			 * Meny is open.
211
+			 */
212
+			function setupCover() {
213
+				if( dom.cover ) {
214
+					dom.cover.parentNode.removeChild( dom.cover );
215
+				}
216
+
217
+				dom.cover = document.createElement( 'div' );
218
+
219
+				// Disabled until a falback fade in animation is added
220
+				dom.cover.style.position = 'absolute';
221
+				dom.cover.style.display = 'block';
222
+				dom.cover.style.width = '100%';
223
+				dom.cover.style.height = '100%';
224
+				dom.cover.style.left = 0;
225
+				dom.cover.style.top = 0;
226
+				dom.cover.style.zIndex = 1000;
227
+				dom.cover.style.visibility = 'hidden';
228
+				dom.cover.style.opacity = 0;
229
+
230
+				// Silence unimportant errors in IE8
231
+				try {
232
+					dom.cover.style.background = 'rgba( 0, 0, 0, 0.4 )';
233
+					dom.cover.style.background = '-ms-linear-gradient('+ config.position +','+ config.gradient;
234
+					dom.cover.style.background = '-moz-linear-gradient('+ config.position +','+ config.gradient;
235
+					dom.cover.style.background = '-webkit-linear-gradient('+ config.position +','+ config.gradient;
236
+				}
237
+				catch( e ) {}
238
+
239
+				if( supports3DTransforms ) {
240
+					dom.cover.style[ Meny.prefix( 'transition' ) ] = 'all ' + config.transitionDuration +' '+ config.transitionEasing;
241
+				}
242
+
243
+				dom.contents.appendChild( dom.cover );
244
+			}
245
+
246
+			/**
247
+			 * The meny element that folds out upon activation.
248
+			 */
249
+			function setupMenu() {
250
+				// Shorthand
251
+				var style = dom.menu.style;
252
+
253
+				switch( config.position ) {
254
+					case POSITION_T:
255
+						style.width = '100%';
256
+						style.height = config.height + 'px';
257
+						break;
258
+
259
+					case POSITION_R:
260
+						style.right = '0';
261
+						style.width = config.width + 'px';
262
+						style.height = '100%';
263
+						break;
264
+
265
+					case POSITION_B:
266
+						style.bottom = '0';
267
+						style.width = '100%';
268
+						style.height = config.height + 'px';
269
+						break;
270
+
271
+					case POSITION_L:
272
+						style.width = config.width + 'px';
273
+						style.height = '100%';
274
+						break;
275
+				}
276
+
277
+				originalStyles.menu = style.cssText;
278
+
279
+				style.position = 'fixed';
280
+				style.display = 'block';
281
+				style.zIndex = 1;
282
+
283
+				if( supports3DTransforms ) {
284
+					style[ Meny.prefix( 'transform' ) ] = menuTransformClosed;
285
+					style[ Meny.prefix( 'transformOrigin' ) ] = menuTransformOrigin;
286
+					style[ Meny.prefix( 'transition' ) ] = 'all ' + config.transitionDuration +' '+ config.transitionEasing;
287
+				}
288
+				else {
289
+					Meny.extend( style, menuStyleClosed );
290
+				}
291
+			}
292
+
293
+			/**
294
+			 * The contents element which gets pushed aside while
295
+			 * Meny is open.
296
+			 */
297
+			function setupContents() {
298
+				// Shorthand
299
+				var style = dom.contents.style;
300
+
301
+				originalStyles.contents = style.cssText;
302
+
303
+				if( supports3DTransforms ) {
304
+					style[ Meny.prefix( 'transform' ) ] = contentsTransformClosed;
305
+					style[ Meny.prefix( 'transformOrigin' ) ] = contentsTransformOrigin;
306
+					style[ Meny.prefix( 'transition' ) ] = 'all ' + config.transitionDuration +' '+ config.transitionEasing;
307
+				}
308
+				else {
309
+					style.position = style.position.match( /relative|absolute|fixed/gi ) ? style.position : 'relative';
310
+					Meny.extend( style, contentsStyleClosed );
311
+				}
312
+			}
313
+
314
+			/**
315
+			 * Attaches all input event listeners.
316
+			 */
317
+			function bindEvents() {
318
+
319
+				if( 'ontouchstart' in window ) {
320
+					if( config.touch ) {
321
+						Meny.bindEvent( document, 'touchstart', onTouchStart );
322
+						Meny.bindEvent( document, 'touchend', onTouchEnd );
323
+					}
324
+					else {
325
+						Meny.unbindEvent( document, 'touchstart', onTouchStart );
326
+						Meny.unbindEvent( document, 'touchend', onTouchEnd );
327
+					}
328
+				}
329
+
330
+				if( config.mouse ) {
331
+					Meny.bindEvent( document, 'mousedown', onMouseDown );
332
+					Meny.bindEvent( document, 'mouseup', onMouseUp );
333
+					Meny.bindEvent( document, 'mousemove', onMouseMove );
334
+				}
335
+				else {
336
+					Meny.unbindEvent( document, 'mousedown', onMouseDown );
337
+					Meny.unbindEvent( document, 'mouseup', onMouseUp );
338
+					Meny.unbindEvent( document, 'mousemove', onMouseMove );
339
+				}
340
+			}
341
+
342
+			/**
343
+			 * Expands the menu.
344
+			 */
345
+			function open() {
346
+				if( !isOpen ) {
347
+					isOpen = true;
348
+
349
+					Meny.addClass( dom.wrapper, 'meny-active' );
350
+
351
+					dom.cover.style.height = dom.contents.scrollHeight + 'px';
352
+					dom.cover.style.visibility = 'visible';
353
+
354
+					// Use transforms and transitions if available...
355
+					if( supports3DTransforms ) {
356
+						// 'webkitAnimationEnd oanimationend msAnimationEnd animationend transitionend'
357
+						Meny.bindEventOnce( dom.wrapper, 'transitionend', function() {
358
+							Meny.dispatchEvent( dom.menu, 'opened' );
359
+						} );
360
+
361
+						dom.cover.style.opacity = 1;
362
+
363
+						dom.contents.style[ Meny.prefix( 'transform' ) ] = contentsTransformOpened;
364
+						dom.menu.style[ Meny.prefix( 'transform' ) ] = menuTransformOpened;
365
+					}
366
+					// ...fall back on JS animation
367
+					else {
368
+						menuAnimation && menuAnimation.stop();
369
+						menuAnimation = Meny.animate( dom.menu, menuStyleOpened, 500 );
370
+						contentsAnimation && contentsAnimation.stop();
371
+						contentsAnimation = Meny.animate( dom.contents, contentsStyleOpened, 500 );
372
+						coverAnimation && coverAnimation.stop();
373
+						coverAnimation = Meny.animate( dom.cover, { opacity: 1 }, 500 );
374
+					}
375
+
376
+					Meny.dispatchEvent( dom.menu, 'open' );
377
+				}
378
+			}
379
+
380
+			/**
381
+			 * Collapses the menu.
382
+			 */
383
+			function close() {
384
+				if( isOpen ) {
385
+					isOpen = false;
386
+
387
+					Meny.removeClass( dom.wrapper, 'meny-active' );
388
+
389
+					// Use transforms and transitions if available...
390
+					if( supports3DTransforms ) {
391
+						// 'webkitAnimationEnd oanimationend msAnimationEnd animationend transitionend'
392
+						Meny.bindEventOnce( dom.wrapper, 'transitionend', function() {
393
+							Meny.dispatchEvent( dom.menu, 'closed' );
394
+						} );
395
+
396
+						dom.cover.style.visibility = 'hidden';
397
+						dom.cover.style.opacity = 0;
398
+
399
+						dom.contents.style[ Meny.prefix( 'transform' ) ] = contentsTransformClosed;
400
+						dom.menu.style[ Meny.prefix( 'transform' ) ] = menuTransformClosed;
401
+					}
402
+					// ...fall back on JS animation
403
+					else {
404
+						menuAnimation && menuAnimation.stop();
405
+						menuAnimation = Meny.animate( dom.menu, menuStyleClosed, 500 );
406
+						contentsAnimation && contentsAnimation.stop();
407
+						contentsAnimation = Meny.animate( dom.contents, contentsStyleClosed, 500 );
408
+						coverAnimation && coverAnimation.stop();
409
+						coverAnimation = Meny.animate( dom.cover, { opacity: 0 }, 500, function() {
410
+							dom.cover.style.visibility = 'hidden';
411
+							Meny.dispatchEvent( dom.menu, 'closed' );
412
+						} );
413
+					}
414
+					Meny.dispatchEvent( dom.menu, 'close' );
415
+				}
416
+			}
417
+
418
+			/**
419
+			 * Unbinds Meny and resets the DOM to the state it
420
+			 * was at before Meny was initialized.
421
+			 */
422
+			function destroy() {
423
+				dom.wrapper.style.cssText = originalStyles.wrapper
424
+				dom.menu.style.cssText = originalStyles.menu;
425
+				dom.contents.style.cssText = originalStyles.contents;
426
+
427
+				if( dom.cover && dom.cover.parentNode ) {
428
+					dom.cover.parentNode.removeChild( dom.cover );
429
+				}
430
+
431
+				Meny.unbindEvent( document, 'touchstart', onTouchStart );
432
+				Meny.unbindEvent( document, 'touchend', onTouchEnd );
433
+				Meny.unbindEvent( document, 'mousedown', onMouseDown );
434
+				Meny.unbindEvent( document, 'mouseup', onMouseUp );
435
+				Meny.unbindEvent( document, 'mousemove', onMouseMove );
436
+
437
+				for( var i in addedEventListeners ) {
438
+					this.removeEventListener( addedEventListeners[i][0], addedEventListeners[i][1] );
439
+				}
440
+
441
+				addedEventListeners = [];
442
+			}
443
+
444
+
445
+			/// INPUT: /////////////////////////////////
446
+
447
+			function onMouseDown( event ) {
448
+				isMouseDown = true;
449
+			}
450
+
451
+			function onMouseMove( event ) {
452
+				// Prevent opening/closing when mouse is down since
453
+				// the user may be selecting text
454
+				if( !isMouseDown ) {
455
+					var x = event.clientX - indentX,
456
+						y = event.clientY - indentY;
457
+
458
+					switch( config.position ) {
459
+						case POSITION_T:
460
+							if( y > config.height ) {
461
+								close();
462
+							}
463
+							else if( y < config.threshold ) {
464
+								open();
465
+							}
466
+							break;
467
+
468
+						case POSITION_R:
469
+							var w = dom.wrapper.offsetWidth;
470
+							if( x < w - config.width ) {
471
+								close();
472
+							}
473
+							else if( x > w - config.threshold ) {
474
+								open();
475
+							}
476
+							break;
477
+
478
+						case POSITION_B:
479
+							var h = dom.wrapper.offsetHeight;
480
+							if( y < h - config.height ) {
481
+								close();
482
+							}
483
+							else if( y > h - config.threshold ) {
484
+								open();
485
+							}
486
+							break;
487
+
488
+						case POSITION_L:
489
+							if( x > config.width ) {
490
+								close();
491
+							}
492
+							else if( x < config.threshold ) {
493
+								open();
494
+							}
495
+							break;
496
+					}
497
+				}
498
+			}
499
+
500
+			function onMouseUp( event ) {
501
+				isMouseDown = false;
502
+			}
503
+
504
+			function onTouchStart( event ) {
505
+				touchStartX = event.touches[0].clientX - indentX;
506
+				touchStartY = event.touches[0].clientY - indentY;
507
+				touchMoveX = null;
508
+				touchMoveY = null;
509
+
510
+				Meny.bindEvent( document, 'touchmove', onTouchMove );
511
+			}
512
+
513
+			function onTouchMove( event ) {
514
+				touchMoveX = event.touches[0].clientX - indentX;
515
+				touchMoveY = event.touches[0].clientY - indentY;
516
+
517
+				var swipeMethod = null;
518
+
519
+				// Check for swipe gestures in any direction
520
+
521
+				if( Math.abs( touchMoveX - touchStartX ) > Math.abs( touchMoveY - touchStartY ) ) {
522
+					if( touchMoveX < touchStartX - config.threshold ) {
523
+						swipeMethod = onSwipeRight;
524
+					}
525
+					else if( touchMoveX > touchStartX + config.threshold ) {
526
+						swipeMethod = onSwipeLeft;
527
+					}
528
+				}
529
+				else {
530
+					if( touchMoveY < touchStartY - config.threshold ) {
531
+						swipeMethod = onSwipeDown;
532
+					}
533
+					else if( touchMoveY > touchStartY + config.threshold ) {
534
+						swipeMethod = onSwipeUp;
535
+					}
536
+				}
537
+
538
+				if( swipeMethod && swipeMethod() ) {
539
+					event.preventDefault();
540
+				}
541
+			}
542
+
543
+			function onTouchEnd( event ) {
544
+				Meny.unbindEvent( document, 'touchmove', onTouchMove );
545
+
546
+				// If there was no movement this was a tap
547
+				if( touchMoveX === null && touchMoveY === null ) {
548
+					onTap();
549
+				}
550
+			}
551
+
552
+			function onTap() {
553
+				var isOverContent = ( config.position === POSITION_T && touchStartY > config.height ) ||
554
+									( config.position === POSITION_R && touchStartX < dom.wrapper.offsetWidth - config.width ) ||
555
+									( config.position === POSITION_B && touchStartY < dom.wrapper.offsetHeight - config.height ) ||
556
+									( config.position === POSITION_L && touchStartX > config.width );
557
+
558
+				if( isOverContent ) {
559
+					close();
560
+				}
561
+			}
562
+
563
+			function onSwipeLeft() {
564
+				if( config.position === POSITION_R && isOpen ) {
565
+					close();
566
+					return true;
567
+				}
568
+				else if( config.position === POSITION_L && !isOpen ) {
569
+					open();
570
+					return true;
571
+				}
572
+			}
573
+
574
+			function onSwipeRight() {
575
+				if( config.position === POSITION_R && !isOpen ) {
576
+					open();
577
+					return true;
578
+				}
579
+				else if( config.position === POSITION_L && isOpen ) {
580
+					close();
581
+					return true;
582
+				}
583
+			}
584
+
585
+			function onSwipeUp() {
586
+				if( config.position === POSITION_B && isOpen ) {
587
+					close();
588
+					return true;
589
+				}
590
+				else if( config.position === POSITION_T && !isOpen ) {
591
+					open();
592
+					return true;
593
+				}
594
+			}
595
+
596
+			function onSwipeDown() {
597
+				if( config.position === POSITION_B && !isOpen ) {
598
+					open();
599
+					return true;
600
+				}
601
+				else if( config.position === POSITION_T && isOpen ) {
602
+					close();
603
+					return true;
604
+				}
605
+			}
606
+
607
+
608
+			/// API: ///////////////////////////////////
609
+
610
+			return {
611
+				configure: configure,
612
+
613
+				open: open,
614
+				close: close,
615
+				destroy: destroy,
616
+
617
+				isOpen: function() {
618
+					return isOpen;
619
+				},
620
+
621
+				/**
622
+				 * Forward event binding to the menu DOM element.
623
+				 */
624
+				addEventListener: function( type, listener ) {
625
+					addedEventListeners.push( [type, listener] );
626
+					dom.menu && Meny.bindEvent( dom.menu, type, listener );
627
+				},
628
+				removeEventListener: function( type, listener ) {
629
+					dom.menu && Meny.unbindEvent( dom.menu, type, listener );
630
+				}
631
+			};
632
+
633
+		})();
634
+	},
635
+
636
+	/**
637
+	 * Helper method, changes an element style over time.
638
+	 */
639
+	animate: function( element, properties, duration, callback ) {
640
+		return (function() {
641
+			// Will hold start/end values for all properties
642
+			var interpolations = {};
643
+
644
+			// Format properties
645
+			for( var p in properties ) {
646
+				interpolations[p] = {
647
+					start: parseFloat( element.style[p] ) || 0,
648
+					end: parseFloat( properties[p] ),
649
+					unit: ( typeof properties[p] === 'string' && properties[p].match( /px|em|%/gi ) ) ? properties[p].match( /px|em|%/gi )[0] : ''
650
+				};
651
+			}
652
+
653
+			var animationStartTime = Date.now(),
654
+				animationTimeout;
655
+
656
+			// Takes one step forward in the animation
657
+			function step() {
658
+				// Ease out
659
+				var progress = 1 - Math.pow( 1 - ( ( Date.now() - animationStartTime ) / duration ), 5 );
660
+
661
+				// Set style to interpolated value
662
+				for( var p in interpolations ) {
663
+					var property = interpolations[p];
664
+					element.style[p] = property.start + ( ( property.end - property.start ) * progress ) + property.unit;
665
+				}
666
+
667
+				// Continue as long as we're not done
668
+				if( progress < 1 ) {
669
+					animationTimeout = setTimeout( step, 1000 / 60 );
670
+				}
671
+				else {
672
+					callback && callback();
673
+					stop();
674
+				}
675
+			}
676
+
677
+			// Cancels the animation
678
+			function stop() {
679
+				clearTimeout( animationTimeout );
680
+			}
681
+
682
+			// Starts the animation
683
+			step();
684
+
685
+
686
+			/// API: ///////////////////////////////////
687
+
688
+			return {
689
+				stop: stop
690
+			};
691
+		})();
692
+	},
693
+
694
+	/**
695
+	 * Extend object a with the properties of object b.
696
+	 * If there's a conflict, object b takes precedence.
697
+	 */
698
+	extend: function( a, b ) {
699
+		for( var i in b ) {
700
+			a[ i ] = b[ i ];
701
+		}
702
+	},
703
+
704
+	/**
705
+	 * Prefixes a style property with the correct vendor.
706
+	 */
707
+	prefix: function( property, el ) {
708
+		var propertyUC = property.slice( 0, 1 ).toUpperCase() + property.slice( 1 ),
709
+			vendors = [ 'Webkit', 'Moz', 'O', 'ms' ];
710
+
711
+		for( var i = 0, len = vendors.length; i < len; i++ ) {
712
+			var vendor = vendors[i];
713
+
714
+			if( typeof ( el || document.body ).style[ vendor + propertyUC ] !== 'undefined' ) {
715
+				return vendor + propertyUC;
716
+			}
717
+		}
718
+
719
+		return property;
720
+	},
721
+
722
+	/**
723
+	 * Adds a class to the target element.
724
+	 */
725
+	addClass: function( element, name ) {
726
+		element.className = element.className.replace( /\s+$/gi, '' ) + ' ' + name;
727
+	},
728
+
729
+	/**
730
+	 * Removes a class from the target element.
731
+	 */
732
+	removeClass: function( element, name ) {
733
+		element.className = element.className.replace( name, '' );
734
+	},
735
+
736
+	/**
737
+	 * Adds an event listener in a browser safe way.
738
+	 */
739
+	bindEvent: function( element, ev, fn ) {
740
+		if( element.addEventListener ) {
741
+			element.addEventListener( ev, fn, false );
742
+		}
743
+		else {
744
+			element.attachEvent( 'on' + ev, fn );
745
+		}
746
+	},
747
+
748
+	/**
749
+	 * Removes an event listener in a browser safe way.
750
+	 */
751
+	unbindEvent: function( element, ev, fn ) {
752
+		if( element.removeEventListener ) {
753
+			element.removeEventListener( ev, fn, false );
754
+		}
755
+		else {
756
+			element.detachEvent( 'on' + ev, fn );
757
+		}
758
+	},
759
+
760
+	bindEventOnce: function ( element, ev, fn ) {
761
+		var me = this;
762
+		var listener = function() {
763
+			me.unbindEvent( element, ev, listener );
764
+			fn.apply( this, arguments );
765
+		};
766
+		this.bindEvent( element, ev, listener );
767
+	},
768
+
769
+	/**
770
+	 * Dispatches an event of the specified type from the
771
+	 * menu DOM element.
772
+	 */
773
+	dispatchEvent: function( element, type, properties ) {
774
+		if( element ) {
775
+			var event = document.createEvent( "HTMLEvents", 1, 2 );
776
+			event.initEvent( type, true, true );
777
+			Meny.extend( event, properties );
778
+			element.dispatchEvent( event );
779
+		}
780
+	},
781
+
782
+	/**
783
+	 * Retrieves query string as a key/value hash.
784
+	 */
785
+	getQuery: function() {
786
+		var query = {};
787
+
788
+		location.search.replace( /[A-Z0-9]+?=([\w|:|\/\.]*)/gi, function(a) {
789
+			query[ a.split( '=' ).shift() ] = a.split( '=' ).pop();
790
+		} );
791
+
792
+		return query;
793
+	}
794
+
795
+};
796
+
797
+return Meny;
798
+
799
+}));