Download raw (18.0 KB)
// Utility for creating objects in older browsers if ( typeof Object.create !== 'function' ) { Object.create = function( obj ) { function F() {} F.prototype = obj; return new F(); }; } /*! * jQuery panelSnap * Version 0.10.0 * * Requires: * - jQuery 1.7.1 or higher (no jQuery.migrate needed) * * https://github.com/guidobouman/jquery-panelsnap * * Copyright 2013, Guido Bouman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * Date: Wed Feb 13 16:05:00 2013 +0100 */ (function($, window, document, undefined) { var pluginName = 'panelSnap'; var storageName = 'plugin_' + pluginName; var pluginObject = { isMouseDown: false, isSnapping: false, enabled: true, scrollInterval: 0, scrollOffset: 0, init: function(options, container) { var self = this; self.$window = $(window); self.$document = $(document); self.container = container; self.$container = $(container); self.$eventContainer = self.$container; self.$snapContainer = self.$container; if(self.$container.is('body')) { self.$eventContainer = self.$document; var ua = navigator.userAgent; if(!~ua.indexOf("WebKit")) { self.$snapContainer = $('html'); } } self.scrollInterval = self.$container.height(); self.options = $.extend(true, {}, $.fn.panelSnap.options, options); self.bind(); if(self.options.$menu !== false && $('.active', self.options.$menu).length > 0) { $('.active', self.options.$menu).click(); } else { var $target = self.getPanel(':first'); self.activatePanel($target); } return self; }, bind: function() { var self = this; self.bindProxied(self.$eventContainer, 'scrollstop', self.scrollStop); self.bindProxied(self.$eventContainer, 'mousewheel', self.mouseWheel); self.bindProxied(self.$eventContainer, 'mousedown', self.mouseDown); self.bindProxied(self.$eventContainer, 'mouseup', self.mouseUp); self.bindProxied(self.$window, 'resizestop', self.resize); if(self.options.$menu !== false) { self.bindProxied($(self.options.$menu), 'click', self.captureMenuClick, self.options.menuSelector); } }, bindProxied: function($element, event, method, selector) { var self = this; selector = typeof selector === 'string' ? selector : null; $element.on(event + self.options.namespace, selector, $.proxy(function(e) { return method.call(self, e); }, self)); }, destroy: function() { var self = this; // Gotta love namespaced events! self.$eventContainer.off(self.options.namespace); self.$window.off(self.options.namespace); if(self.options.$menu !== false) { $(self.options.menuSelector, self.options.$menu).off(self.options.namespace); } self.$container.removeData(storageName); }, scrollStop: function(e) { var self = this; e.stopPropagation(); if(!self.enabled) { return; } if(self.isMouseDown) { self.$eventContainer.one('mouseup' + self.options.namespace, self.processScroll); return; } if(self.isSnapping) { return; } var offset = self.$eventContainer.scrollTop(); var scrollDifference = offset - self.scrollOffset; var maxOffset = self.$container[0].scrollHeight - self.scrollInterval; var panelCount = self.getPanel().length; var childNumber; if( scrollDifference < -self.options.directionThreshold && scrollDifference > -self.scrollInterval ) { childNumber = Math.floor(offset / self.scrollInterval); } else if( scrollDifference > self.options.directionThreshold && scrollDifference < self.scrollInterval ) { childNumber = Math.ceil(offset / self.scrollInterval); } else { childNumber = Math.round(offset / self.scrollInterval); } childNumber = Math.max(0, Math.min(childNumber, panelCount)); var $target = self.getPanel(':eq(' + childNumber + ')'); if(scrollDifference === 0) { // Do nothing } else if (offset < 0 || offset > maxOffset) { // Only activate, prevent stuttering self.activatePanel($target); // Set scrollOffset to a sane number for next scroll self.scrollOffset = offset < 0 ? 0 : maxOffset; } else { self.snapToPanel($target); } }, mouseWheel: function(e) { var self = this; // This event only fires when the user actually scrolls with their input device. // Be it a trackpad, legacy mouse or anything else. self.$container.stop(true); self.isSnapping = false; }, mouseDown: function(e) { var self = this; self.isMouseDown = true; }, mouseUp: function(e) { var self = this; self.isMouseDown = false; }, resize: function(e) { var self = this; self.scrollInterval = self.$container.height(); if(!self.enabled) { return; } var $target = self.getPanel('.active'); self.snapToPanel($target); }, captureMenuClick: function(e) { var self = this; var panel = $(e.currentTarget).data('panel'); var $target = self.getPanel('[data-panel=' + panel + ']'); self.snapToPanel($target); return false; }, snapToPanel: function($target) { var self = this; self.isSnapping = true; self.options.onSnapStart.call(self, $target); self.$container.trigger('panelsnap:start', [$target]); var scrollTarget = 0; if(self.$container.is('body')) { scrollTarget = $target.offset().top; } else { scrollTarget = self.$eventContainer.scrollTop() + $target.position().top; } self.$snapContainer.stop(true).animate({ scrollTop: scrollTarget }, self.options.slideSpeed, function() { self.scrollOffset = scrollTarget; self.isSnapping = false; // Call callback self.options.onSnapFinish.call(self, $target); self.$container.trigger('panelsnap:finish', [$target]); }); self.activatePanel($target); }, activatePanel: function($target) { var self = this; self.getPanel('.active').removeClass('active'); $target.addClass('active'); if(self.options.$menu !== false) { var activeItemSelector = '> ' + self.options.menuSelector + '.active'; $(activeItemSelector, self.options.$menu).removeClass('active'); var attribute = '[data-panel=' + $target.data('panel') + ']'; var itemSelector = '> ' + self.options.menuSelector + attribute; var $itemToActivate = $(itemSelector, self.options.$menu); $itemToActivate.addClass('active'); } self.options.onActivate.call(self, $target); self.$container.trigger('panelsnap:activate', [$target]); }, getPanel: function(selector) { var self = this; if(typeof selector === 'undefined') { selector = ''; } var panelSelector = '> ' + self.options.panelSelector + selector; return $(panelSelector, self.$container); }, snapTo: function(target, wrap) { var self = this; if(typeof wrap !== 'boolean') { wrap = true; } var $target; switch(target) { case 'prev': $target = self.getPanel('.active').prev(self.options.panelSelector); if($target.length < 1 && wrap) { $target = self.getPanel(':last'); } break; case 'next': $target = self.getPanel('.active').next(self.options.panelSelector); if($target.length < 1 && wrap) { $target = self.getPanel(':first'); } break; case 'first': $target = self.getPanel(':first'); break; case 'last': $target = self.getPanel(':last'); break; } if($target.length > 0) { self.snapToPanel($target); } }, enable: function() { var self = this; // Gather scrollOffset for next scroll self.scrollOffset = self.$container[0].scrollHeight; self.enabled = true; }, disable: function() { var self = this; self.enabled = false; }, toggle: function() { var self = this; if(self.enabled) { self.disable(); } else { self.enable(); } } }; $.fn[pluginName] = function(options) { var args = Array.prototype.slice.call(arguments); return this.each(function() { var pluginInstance = $.data(this, storageName); if(typeof options === 'object' || options === 'init' || ! options) { if(!pluginInstance) { if(options === 'init') { options = args[1] || {}; } pluginInstance = Object.create(pluginObject).init(options, this); $.data(this, storageName, pluginInstance); } else { $.error('Plugin is already initialized for this object.'); return; } } else if(!pluginInstance) { $.error('Plugin is not initialized for this object yet.'); return; } else if(pluginInstance[options]) { var method = options; options = args.slice(1); pluginInstance[method].apply(pluginInstance, options); } else { $.error('Method ' + options + ' does not exist on jQuery.panelSnap.'); return; } }); }; $.fn[pluginName].options = { $menu: false, menuSelector: 'a', panelSelector: 'section', namespace: '.panelSnap', onSnapStart: function(){}, onSnapFinish: function(){}, onActivate: function(){}, directionThreshold: 50, slideSpeed: 200 }; })(jQuery, window, document); /*! * Special flavoured jQuery Mobile scrollstart & scrollstop events. * Version 0.1.3 * * Requires: * - jQuery 1.7.1 or higher (no jQuery.migrate needed) * * Copyright 2013, Guido Bouman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * Date: Wed Feb 13 16:05:00 2013 +0100 */ (function($) { // Also handles the scrollstop event $.event.special.scrollstart = { enabled: true, setup: function() { var thisObject = this; var $this = $(thisObject); var scrolling; var timer; $this.data('scrollwatch', true); function trigger(event, scrolling) { event.type = scrolling ? "scrollstart" : "scrollstop"; $this.trigger(event); } $this.on("touchmove scroll", function(event) { if(!$.event.special.scrollstart.enabled) { return; } if(!$.event.special.scrollstart.scrolling) { $.event.special.scrollstart.scrolling = true; trigger(event, true); } clearTimeout(timer); timer = setTimeout(function() { $.event.special.scrollstart.scrolling = false; trigger(event, false); }, 50); }); } }; // Proxies scrollstart when needed $.event.special.scrollstop = { setup: function() { var thisObject = this; var $this = $(thisObject); if(!$this.data('scrollwatch')) { $(this).on('scrollstart', function(){}); } } }; })(jQuery); /*! * Resizestart and resizestop events. * Version 0.0.1 * * Requires: * - jQuery 1.7.1 or higher (no jQuery.migrate needed) * * Copyright 2013, Guido Bouman * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * Date: Fri Oct 25 15:05:00 2013 +0100 */ (function($) { // Also handles the resizestop event $.event.special.resizestart = { enabled: true, setup: function() { var thisObject = this; var $this = $(thisObject); var resizing; var timer; $this.data('resizewatch', true); function trigger(event, resizing) { event.type = resizing ? "resizestart" : "resizestop"; $this.trigger(event); } $this.on("resize", function(event) { if(!$.event.special.resizestart.enabled) { return; } if(!$.event.special.resizestart.resizing) { $.event.special.resizestart.resizing = true; trigger(event, true); } clearTimeout(timer); timer = setTimeout(function() { $.event.special.resizestart.resizing = false; trigger(event, false); }, 200); }); } }; // Proxies resizestart when needed $.event.special.resizestop = { setup: function() { var thisObject = this; var $this = $(thisObject); if(!$this.data('resizewatch')) { $(this).on('resizestart', function(){}); } } }; })(jQuery); /*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net) * Licensed under the MIT License (LICENSE.txt). * * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers. * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix. * Thanks to: Seamus Leahy for adding deltaX and deltaY * * Version: 3.0.6 * * Requires: 1.2.2+ */ (function($) { var types = ['DOMMouseScroll', 'mousewheel']; if ($.event.fixHooks) { for ( var i=types.length; i; ) { $.event.fixHooks[ types[--i] ] = $.event.mouseHooks; } } $.event.special.mousewheel = { setup: function() { if ( this.addEventListener ) { for ( var i=types.length; i; ) { this.addEventListener( types[--i], handler, false ); } } else { this.onmousewheel = handler; } }, teardown: function() { if ( this.removeEventListener ) { for ( var i=types.length; i; ) { this.removeEventListener( types[--i], handler, false ); } } else { this.onmousewheel = null; } } }; $.fn.extend({ mousewheel: function(fn) { return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel"); }, unmousewheel: function(fn) { return this.unbind("mousewheel", fn); } }); function handler(event) { var orgEvent = event || window.event, args = [].slice.call( arguments, 1 ), delta = 0, returnValue = true, deltaX = 0, deltaY = 0; event = $.event.fix(orgEvent); event.type = "mousewheel"; // Old school scrollwheel delta if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta/120; } if ( orgEvent.detail ) { delta = -orgEvent.detail/3; } // New school multidimensional scroll (touchpads) deltas deltaY = delta; // Gecko if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) { deltaY = 0; deltaX = -1*delta; } // Webkit if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY/120; } if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = -1*orgEvent.wheelDeltaX/120; } // Add event and delta to the front of the arguments args.unshift(event, delta, deltaX, deltaY); return ($.event.dispatch || $.event.handle).apply(this, args); } })(jQuery);