Vous êtes connecté en tant que anonymous Se Deconnecter
public/js/meny.js
8d6a2feb
 /*!
  * meny 1.4
  * http://lab.hakim.se/meny
  * MIT licensed
  *
  * Created by Hakim El Hattab (http://hakim.se, @hakimel)
  */
 
 (function( root, factory ) {
     if( typeof define === 'function' && define.amd ) {
         // AMD module
         define( factory );
     } else {
         // Browser global
         root.Meny = factory();
     }
 }(this, function () {
 
 // Date.now polyfill
 if( typeof Date.now !== 'function' ) Date.now = function() { return new Date().getTime(); };
 
 var Meny = {
 
 	// Creates a new instance of Meny
 	create: function( options ) {
 		return (function(){
 
 			// Make sure the required arguments are defined
 			if( !options || !options.menuElement || !options.contentsElement ) {
 				throw 'You need to specify which menu and contents elements to use.';
 			}
 
 			// Make sure the menu and contents have the same parent
 			if( options.menuElement.parentNode !== options.contentsElement.parentNode ) {
 				throw 'The menu and contents elements must have the same parent.';
 			}
 
 			// Constants
 			var POSITION_T = 'top',
 				POSITION_R = 'right',
 				POSITION_B = 'bottom',
 				POSITION_L = 'left';
 
 			// Feature detection for 3D transforms
 			var supports3DTransforms =  'WebkitPerspective' in document.body.style ||
 										'MozPerspective' in document.body.style ||
 										'msPerspective' in document.body.style ||
 										'OPerspective' in document.body.style ||
 										'perspective' in document.body.style;
 
 			// Default options, gets extended by passed in arguments
 			var config = {
 				width: 300,
 				height: 300,
 				position: POSITION_L,
 				threshold: 40,
 				angle: 30,
 				overlap: 6,
 				transitionDuration: '0.5s',
 				transitionEasing: 'ease',
 				gradient: 'rgba(0,0,0,0.20) 0%, rgba(0,0,0,0.65) 100%)',
 				mouse: true,
 				touch: true
 			};
 
 			// Cache references to DOM elements
 			var dom = {
 				menu: options.menuElement,
 				contents: options.contentsElement,
 				wrapper: options.menuElement.parentNode,
 				cover: null
 			};
 
 			// State and input
 			var indentX = dom.wrapper.offsetLeft,
 				indentY = dom.wrapper.offsetTop,
 				touchStartX = null,
 				touchStartY = null,
 				touchMoveX = null,
 				touchMoveY = null,
 				isOpen = false,
 				isMouseDown = false;
 
 			// Precalculated transform and style states
 			var menuTransformOrigin,
 				menuTransformClosed,
 				menuTransformOpened,
 				menuStyleClosed,
 				menuStyleOpened,
 
 				contentsTransformOrigin,
 				contentsTransformClosed,
 				contentsTransformOpened,
 				contentsStyleClosed,
 				contentsStyleOpened;
 
 			var originalStyles = {},
 				addedEventListeners = [];
 
 			// Ongoing animations (for fallback mode)
 			var menuAnimation,
 				contentsAnimation,
 				coverAnimation;
 
 			configure( options );
 
 			/**
 			 * Initializes Meny with the specified user options,
 			 * may be called multiple times as configuration changes.
 			 */
 			function configure( o ) {
 				// Extend the default config object with the passed in
 				// options
 				Meny.extend( config, o );
 
 				setupPositions();
 				setupWrapper();
 				setupCover();
 				setupMenu();
 				setupContents();
 
 				bindEvents();
 			}
 
 			/**
 			 * Prepares the transforms for the current positioning
 			 * settings.
 			 */
 			function setupPositions() {
 				menuTransformOpened = '';
 				contentsTransformClosed = '';
 				menuAngle = config.angle;
 				contentsAngle = config.angle / -2;
 
 				switch( config.position ) {
 					case POSITION_T:
 						// Primary transform:
 						menuTransformOrigin = '50% 0%';
 						menuTransformClosed = 'rotateX( ' + menuAngle + 'deg ) translateY( -100% ) translateY( '+ config.overlap +'px )';
 						contentsTransformOrigin = '50% 0';
 						contentsTransformOpened = 'translateY( '+ config.height +'px ) rotateX( ' + contentsAngle + 'deg )';
 
 						// Position fallback:
 						menuStyleClosed = { top: '-' + (config.height-config.overlap) + 'px' };
 						menuStyleOpened = { top: '0px' };
 						contentsStyleClosed = { top: '0px' };
 						contentsStyleOpened = { top: config.height + 'px' };
 						break;
 
 					case POSITION_R:
 						// Primary transform:
 						menuTransformOrigin = '100% 50%';
 						menuTransformClosed = 'rotateY( ' + menuAngle + 'deg ) translateX( 100% ) translateX( -2px ) scale( 1.01 )';
 						contentsTransformOrigin = '100% 50%';
 						contentsTransformOpened = 'translateX( -'+ config.width +'px ) rotateY( ' + contentsAngle + 'deg )';
 
 						// Position fallback:
 						menuStyleClosed = { right: '-' + (config.width-config.overlap) + 'px' };
 						menuStyleOpened = { right: '0px' };
 						contentsStyleClosed = { left: '0px' };
 						contentsStyleOpened = { left: '-' + config.width + 'px' };
 						break;
 
 					case POSITION_B:
 						// Primary transform:
 						menuTransformOrigin = '50% 100%';
 						menuTransformClosed = 'rotateX( ' + -menuAngle + 'deg ) translateY( 100% ) translateY( -'+ config.overlap +'px )';
 						contentsTransformOrigin = '50% 100%';
 						contentsTransformOpened = 'translateY( -'+ config.height +'px ) rotateX( ' + -contentsAngle + 'deg )';
 
 						// Position fallback:
 						menuStyleClosed = { bottom: '-' + (config.height-config.overlap) + 'px' };
 						menuStyleOpened = { bottom: '0px' };
 						contentsStyleClosed = { top: '0px' };
 						contentsStyleOpened = { top: '-' + config.height + 'px' };
 						break;
 
 					default:
 						// Primary transform:
 						menuTransformOrigin = '100% 50%';
 						menuTransformClosed = 'translateX( -100% ) translateX( '+ config.overlap +'px ) scale( 1.01 ) rotateY( ' + -menuAngle + 'deg )';
 						contentsTransformOrigin = '0 50%';
 						contentsTransformOpened = 'translateX( '+ config.width +'px ) rotateY( ' + -contentsAngle + 'deg )';
 
 						// Position fallback:
 						menuStyleClosed = { left: '-' + (config.width-config.overlap) + 'px' };
 						menuStyleOpened = { left: '0px' };
 						contentsStyleClosed = { left: '0px' };
 						contentsStyleOpened = { left: config.width + 'px' };
 						break;
 				}
 			}
 
 			/**
 			 * The wrapper element holds the menu and contents.
 			 */
 			function setupWrapper() {
 				// Add a class to allow for custom styles based on
 				// position
 				Meny.addClass( dom.wrapper, 'meny-' + config.position );
 
 				originalStyles.wrapper = dom.wrapper.style.cssText;
 
 				dom.wrapper.style[ Meny.prefix( 'perspective' ) ] = '800px';
 				dom.wrapper.style[ Meny.prefix( 'perspectiveOrigin' ) ] = contentsTransformOrigin;
 			}
 
 			/**
 			 * The cover is used to obfuscate the contents while
 			 * Meny is open.
 			 */
 			function setupCover() {
 				if( dom.cover ) {
 					dom.cover.parentNode.removeChild( dom.cover );
 				}
 
 				dom.cover = document.createElement( 'div' );
 
 				// Disabled until a falback fade in animation is added
 				dom.cover.style.position = 'absolute';
 				dom.cover.style.display = 'block';
 				dom.cover.style.width = '100%';
 				dom.cover.style.height = '100%';
 				dom.cover.style.left = 0;
 				dom.cover.style.top = 0;
 				dom.cover.style.zIndex = 1000;
 				dom.cover.style.visibility = 'hidden';
 				dom.cover.style.opacity = 0;
 
 				// Silence unimportant errors in IE8
 				try {
 					dom.cover.style.background = 'rgba( 0, 0, 0, 0.4 )';
 					dom.cover.style.background = '-ms-linear-gradient('+ config.position +','+ config.gradient;
 					dom.cover.style.background = '-moz-linear-gradient('+ config.position +','+ config.gradient;
 					dom.cover.style.background = '-webkit-linear-gradient('+ config.position +','+ config.gradient;
 				}
 				catch( e ) {}
 
 				if( supports3DTransforms ) {
 					dom.cover.style[ Meny.prefix( 'transition' ) ] = 'all ' + config.transitionDuration +' '+ config.transitionEasing;
 				}
 
 				dom.contents.appendChild( dom.cover );
 			}
 
 			/**
 			 * The meny element that folds out upon activation.
 			 */
 			function setupMenu() {
 				// Shorthand
 				var style = dom.menu.style;
 
 				switch( config.position ) {
 					case POSITION_T:
 						style.width = '100%';
 						style.height = config.height + 'px';
 						break;
 
 					case POSITION_R:
 						style.right = '0';
 						style.width = config.width + 'px';
 						style.height = '100%';
 						break;
 
 					case POSITION_B:
 						style.bottom = '0';
 						style.width = '100%';
 						style.height = config.height + 'px';
 						break;
 
 					case POSITION_L:
 						style.width = config.width + 'px';
 						style.height = '100%';
 						break;
 				}
 
 				originalStyles.menu = style.cssText;
 
 				style.position = 'fixed';
 				style.display = 'block';
 				style.zIndex = 1;
 
 				if( supports3DTransforms ) {
 					style[ Meny.prefix( 'transform' ) ] = menuTransformClosed;
 					style[ Meny.prefix( 'transformOrigin' ) ] = menuTransformOrigin;
 					style[ Meny.prefix( 'transition' ) ] = 'all ' + config.transitionDuration +' '+ config.transitionEasing;
 				}
 				else {
 					Meny.extend( style, menuStyleClosed );
 				}
 			}
 
 			/**
 			 * The contents element which gets pushed aside while
 			 * Meny is open.
 			 */
 			function setupContents() {
 				// Shorthand
 				var style = dom.contents.style;
 
 				originalStyles.contents = style.cssText;
 
 				if( supports3DTransforms ) {
 					style[ Meny.prefix( 'transform' ) ] = contentsTransformClosed;
 					style[ Meny.prefix( 'transformOrigin' ) ] = contentsTransformOrigin;
 					style[ Meny.prefix( 'transition' ) ] = 'all ' + config.transitionDuration +' '+ config.transitionEasing;
 				}
 				else {
 					style.position = style.position.match( /relative|absolute|fixed/gi ) ? style.position : 'relative';
 					Meny.extend( style, contentsStyleClosed );
 				}
 			}
 
 			/**
 			 * Attaches all input event listeners.
 			 */
 			function bindEvents() {
 
 				if( 'ontouchstart' in window ) {
 					if( config.touch ) {
 						Meny.bindEvent( document, 'touchstart', onTouchStart );
 						Meny.bindEvent( document, 'touchend', onTouchEnd );
 					}
 					else {
 						Meny.unbindEvent( document, 'touchstart', onTouchStart );
 						Meny.unbindEvent( document, 'touchend', onTouchEnd );
 					}
 				}
 
 				if( config.mouse ) {
 					Meny.bindEvent( document, 'mousedown', onMouseDown );
 					Meny.bindEvent( document, 'mouseup', onMouseUp );
 					Meny.bindEvent( document, 'mousemove', onMouseMove );
 				}
 				else {
 					Meny.unbindEvent( document, 'mousedown', onMouseDown );
 					Meny.unbindEvent( document, 'mouseup', onMouseUp );
 					Meny.unbindEvent( document, 'mousemove', onMouseMove );
 				}
 			}
 
 			/**
 			 * Expands the menu.
 			 */
 			function open() {
 				if( !isOpen ) {
 					isOpen = true;
 
 					Meny.addClass( dom.wrapper, 'meny-active' );
 
 					dom.cover.style.height = dom.contents.scrollHeight + 'px';
 					dom.cover.style.visibility = 'visible';
 
 					// Use transforms and transitions if available...
 					if( supports3DTransforms ) {
 						// 'webkitAnimationEnd oanimationend msAnimationEnd animationend transitionend'
 						Meny.bindEventOnce( dom.wrapper, 'transitionend', function() {
 							Meny.dispatchEvent( dom.menu, 'opened' );
 						} );
 
 						dom.cover.style.opacity = 1;
 
 						dom.contents.style[ Meny.prefix( 'transform' ) ] = contentsTransformOpened;
 						dom.menu.style[ Meny.prefix( 'transform' ) ] = menuTransformOpened;
 					}
 					// ...fall back on JS animation
 					else {
 						menuAnimation && menuAnimation.stop();
 						menuAnimation = Meny.animate( dom.menu, menuStyleOpened, 500 );
 						contentsAnimation && contentsAnimation.stop();
 						contentsAnimation = Meny.animate( dom.contents, contentsStyleOpened, 500 );
 						coverAnimation && coverAnimation.stop();
 						coverAnimation = Meny.animate( dom.cover, { opacity: 1 }, 500 );
 					}
 
 					Meny.dispatchEvent( dom.menu, 'open' );
 				}
 			}
 
 			/**
 			 * Collapses the menu.
 			 */
 			function close() {
 				if( isOpen ) {
 					isOpen = false;
 
 					Meny.removeClass( dom.wrapper, 'meny-active' );
 
 					// Use transforms and transitions if available...
 					if( supports3DTransforms ) {
 						// 'webkitAnimationEnd oanimationend msAnimationEnd animationend transitionend'
 						Meny.bindEventOnce( dom.wrapper, 'transitionend', function() {
 							Meny.dispatchEvent( dom.menu, 'closed' );
 						} );
 
 						dom.cover.style.visibility = 'hidden';
 						dom.cover.style.opacity = 0;
 
 						dom.contents.style[ Meny.prefix( 'transform' ) ] = contentsTransformClosed;
 						dom.menu.style[ Meny.prefix( 'transform' ) ] = menuTransformClosed;
 					}
 					// ...fall back on JS animation
 					else {
 						menuAnimation && menuAnimation.stop();
 						menuAnimation = Meny.animate( dom.menu, menuStyleClosed, 500 );
 						contentsAnimation && contentsAnimation.stop();
 						contentsAnimation = Meny.animate( dom.contents, contentsStyleClosed, 500 );
 						coverAnimation && coverAnimation.stop();
 						coverAnimation = Meny.animate( dom.cover, { opacity: 0 }, 500, function() {
 							dom.cover.style.visibility = 'hidden';
 							Meny.dispatchEvent( dom.menu, 'closed' );
 						} );
 					}
 					Meny.dispatchEvent( dom.menu, 'close' );
 				}
 			}
 
 			/**
 			 * Unbinds Meny and resets the DOM to the state it
 			 * was at before Meny was initialized.
 			 */
 			function destroy() {
 				dom.wrapper.style.cssText = originalStyles.wrapper
 				dom.menu.style.cssText = originalStyles.menu;
 				dom.contents.style.cssText = originalStyles.contents;
 
 				if( dom.cover && dom.cover.parentNode ) {
 					dom.cover.parentNode.removeChild( dom.cover );
 				}
 
 				Meny.unbindEvent( document, 'touchstart', onTouchStart );
 				Meny.unbindEvent( document, 'touchend', onTouchEnd );
 				Meny.unbindEvent( document, 'mousedown', onMouseDown );
 				Meny.unbindEvent( document, 'mouseup', onMouseUp );
 				Meny.unbindEvent( document, 'mousemove', onMouseMove );
 
 				for( var i in addedEventListeners ) {
 					this.removeEventListener( addedEventListeners[i][0], addedEventListeners[i][1] );
 				}
 
 				addedEventListeners = [];
 			}
 
 
 			/// INPUT: /////////////////////////////////
 
 			function onMouseDown( event ) {
 				isMouseDown = true;
 			}
 
 			function onMouseMove( event ) {
 				// Prevent opening/closing when mouse is down since
 				// the user may be selecting text
 				if( !isMouseDown ) {
 					var x = event.clientX - indentX,
 						y = event.clientY - indentY;
 
 					switch( config.position ) {
 						case POSITION_T:
 							if( y > config.height ) {
 								close();
 							}
 							else if( y < config.threshold ) {
 								open();
 							}
 							break;
 
 						case POSITION_R:
 							var w = dom.wrapper.offsetWidth;
 							if( x < w - config.width ) {
 								close();
 							}
 							else if( x > w - config.threshold ) {
 								open();
 							}
 							break;
 
 						case POSITION_B:
 							var h = dom.wrapper.offsetHeight;
 							if( y < h - config.height ) {
 								close();
 							}
 							else if( y > h - config.threshold ) {
 								open();
 							}
 							break;
 
 						case POSITION_L:
 							if( x > config.width ) {
 								close();
 							}
 							else if( x < config.threshold ) {
 								open();
 							}
 							break;
 					}
 				}
 			}
 
 			function onMouseUp( event ) {
 				isMouseDown = false;
 			}
 
 			function onTouchStart( event ) {
 				touchStartX = event.touches[0].clientX - indentX;
 				touchStartY = event.touches[0].clientY - indentY;
 				touchMoveX = null;
 				touchMoveY = null;
 
 				Meny.bindEvent( document, 'touchmove', onTouchMove );
 			}
 
 			function onTouchMove( event ) {
 				touchMoveX = event.touches[0].clientX - indentX;
 				touchMoveY = event.touches[0].clientY - indentY;
 
 				var swipeMethod = null;
 
 				// Check for swipe gestures in any direction
 
 				if( Math.abs( touchMoveX - touchStartX ) > Math.abs( touchMoveY - touchStartY ) ) {
 					if( touchMoveX < touchStartX - config.threshold ) {
 						swipeMethod = onSwipeRight;
 					}
 					else if( touchMoveX > touchStartX + config.threshold ) {
 						swipeMethod = onSwipeLeft;
 					}
 				}
 				else {
 					if( touchMoveY < touchStartY - config.threshold ) {
 						swipeMethod = onSwipeDown;
 					}
 					else if( touchMoveY > touchStartY + config.threshold ) {
 						swipeMethod = onSwipeUp;
 					}
 				}
 
 				if( swipeMethod && swipeMethod() ) {
 					event.preventDefault();
 				}
 			}
 
 			function onTouchEnd( event ) {
 				Meny.unbindEvent( document, 'touchmove', onTouchMove );
 
 				// If there was no movement this was a tap
 				if( touchMoveX === null && touchMoveY === null ) {
 					onTap();
 				}
 			}
 
 			function onTap() {
 				var isOverContent = ( config.position === POSITION_T && touchStartY > config.height ) ||
 									( config.position === POSITION_R && touchStartX < dom.wrapper.offsetWidth - config.width ) ||
 									( config.position === POSITION_B && touchStartY < dom.wrapper.offsetHeight - config.height ) ||
 									( config.position === POSITION_L && touchStartX > config.width );
 
 				if( isOverContent ) {
 					close();
 				}
 			}
 
 			function onSwipeLeft() {
 				if( config.position === POSITION_R && isOpen ) {
 					close();
 					return true;
 				}
 				else if( config.position === POSITION_L && !isOpen ) {
 					open();
 					return true;
 				}
 			}
 
 			function onSwipeRight() {
 				if( config.position === POSITION_R && !isOpen ) {
 					open();
 					return true;
 				}
 				else if( config.position === POSITION_L && isOpen ) {
 					close();
 					return true;
 				}
 			}
 
 			function onSwipeUp() {
 				if( config.position === POSITION_B && isOpen ) {
 					close();
 					return true;
 				}
 				else if( config.position === POSITION_T && !isOpen ) {
 					open();
 					return true;
 				}
 			}
 
 			function onSwipeDown() {
 				if( config.position === POSITION_B && !isOpen ) {
 					open();
 					return true;
 				}
 				else if( config.position === POSITION_T && isOpen ) {
 					close();
 					return true;
 				}
 			}
 
 
 			/// API: ///////////////////////////////////
 
 			return {
 				configure: configure,
 
 				open: open,
 				close: close,
 				destroy: destroy,
 
 				isOpen: function() {
 					return isOpen;
 				},
 
 				/**
 				 * Forward event binding to the menu DOM element.
 				 */
 				addEventListener: function( type, listener ) {
 					addedEventListeners.push( [type, listener] );
 					dom.menu && Meny.bindEvent( dom.menu, type, listener );
 				},
 				removeEventListener: function( type, listener ) {
 					dom.menu && Meny.unbindEvent( dom.menu, type, listener );
 				}
 			};
 
 		})();
 	},
 
 	/**
 	 * Helper method, changes an element style over time.
 	 */
 	animate: function( element, properties, duration, callback ) {
 		return (function() {
 			// Will hold start/end values for all properties
 			var interpolations = {};
 
 			// Format properties
 			for( var p in properties ) {
 				interpolations[p] = {
 					start: parseFloat( element.style[p] ) || 0,
 					end: parseFloat( properties[p] ),
 					unit: ( typeof properties[p] === 'string' && properties[p].match( /px|em|%/gi ) ) ? properties[p].match( /px|em|%/gi )[0] : ''
 				};
 			}
 
 			var animationStartTime = Date.now(),
 				animationTimeout;
 
 			// Takes one step forward in the animation
 			function step() {
 				// Ease out
 				var progress = 1 - Math.pow( 1 - ( ( Date.now() - animationStartTime ) / duration ), 5 );
 
 				// Set style to interpolated value
 				for( var p in interpolations ) {
 					var property = interpolations[p];
 					element.style[p] = property.start + ( ( property.end - property.start ) * progress ) + property.unit;
 				}
 
 				// Continue as long as we're not done
 				if( progress < 1 ) {
 					animationTimeout = setTimeout( step, 1000 / 60 );
 				}
 				else {
 					callback && callback();
 					stop();
 				}
 			}
 
 			// Cancels the animation
 			function stop() {
 				clearTimeout( animationTimeout );
 			}
 
 			// Starts the animation
 			step();
 
 
 			/// API: ///////////////////////////////////
 
 			return {
 				stop: stop
 			};
 		})();
 	},
 
 	/**
 	 * Extend object a with the properties of object b.
 	 * If there's a conflict, object b takes precedence.
 	 */
 	extend: function( a, b ) {
 		for( var i in b ) {
 			a[ i ] = b[ i ];
 		}
 	},
 
 	/**
 	 * Prefixes a style property with the correct vendor.
 	 */
 	prefix: function( property, el ) {
 		var propertyUC = property.slice( 0, 1 ).toUpperCase() + property.slice( 1 ),
 			vendors = [ 'Webkit', 'Moz', 'O', 'ms' ];
 
 		for( var i = 0, len = vendors.length; i < len; i++ ) {
 			var vendor = vendors[i];
 
 			if( typeof ( el || document.body ).style[ vendor + propertyUC ] !== 'undefined' ) {
 				return vendor + propertyUC;
 			}
 		}
 
 		return property;
 	},
 
 	/**
 	 * Adds a class to the target element.
 	 */
 	addClass: function( element, name ) {
 		element.className = element.className.replace( /\s+$/gi, '' ) + ' ' + name;
 	},
 
 	/**
 	 * Removes a class from the target element.
 	 */
 	removeClass: function( element, name ) {
 		element.className = element.className.replace( name, '' );
 	},
 
 	/**
 	 * Adds an event listener in a browser safe way.
 	 */
 	bindEvent: function( element, ev, fn ) {
 		if( element.addEventListener ) {
 			element.addEventListener( ev, fn, false );
 		}
 		else {
 			element.attachEvent( 'on' + ev, fn );
 		}
 	},
 
 	/**
 	 * Removes an event listener in a browser safe way.
 	 */
 	unbindEvent: function( element, ev, fn ) {
 		if( element.removeEventListener ) {
 			element.removeEventListener( ev, fn, false );
 		}
 		else {
 			element.detachEvent( 'on' + ev, fn );
 		}
 	},
 
 	bindEventOnce: function ( element, ev, fn ) {
 		var me = this;
 		var listener = function() {
 			me.unbindEvent( element, ev, listener );
 			fn.apply( this, arguments );
 		};
 		this.bindEvent( element, ev, listener );
 	},
 
 	/**
 	 * Dispatches an event of the specified type from the
 	 * menu DOM element.
 	 */
 	dispatchEvent: function( element, type, properties ) {
 		if( element ) {
 			var event = document.createEvent( "HTMLEvents", 1, 2 );
 			event.initEvent( type, true, true );
 			Meny.extend( event, properties );
 			element.dispatchEvent( event );
 		}
 	},
 
 	/**
 	 * Retrieves query string as a key/value hash.
 	 */
 	getQuery: function() {
 		var query = {};
 
 		location.search.replace( /[A-Z0-9]+?=([\w|:|\/\.]*)/gi, function(a) {
 			query[ a.split( '=' ).shift() ] = a.split( '=' ).pop();
 		} );
 
 		return query;
 	}
 
 };
 
 return Meny;
 
 }));