(function($, wp, wps, window, undefined) { '$:nomunge'; var $w = $(window), waypoints = [], oldScroll = -99999, didScroll = false, didResize = false, eventName = 'waypoint.reached', methods = { init: function(f, options) { this.each(function() { var $this = $(this), ndx = waypointIndex($this), base = ndx < 0 ? $.fn[wp].defaults: waypoints[ndx].options, opts = $.extend({}, base, options); opts.offset = opts.offset === "bottom-in-view" ? function() { return $[wps]('viewportHeight') - $(this).outerHeight(); }: opts.offset; if (ndx < 0) { waypoints.push({ element: $this, offset: $this.offset().top, options: opts }); } else { waypoints[ndx].options = opts; } f && $this.bind(eventName, f); }); $[wps]('refresh'); return this; }, remove: function() { return this.each(function() { var ndx = waypointIndex($(this)); if (ndx >= 0) { waypoints.splice(ndx, 1); } }); }, destroy: function() { return this.unbind(eventName)[wp]('remove'); } }; function waypointIndex(el) { var i = waypoints.length - 1; while (i >= 0 && waypoints[i].element[0] !== el[0]) { i -= 1; } return i; } function triggerWaypoint(way, dir) { way.element.trigger(eventName, dir) if (way.options.triggerOnce) { way.element[wp]('destroy'); } } function doScroll() { var newScroll = $w.scrollTop(), isDown = newScroll > oldScroll, pointsHit = $.grep(waypoints, function(el, i) { return isDown ? (el.offset > oldScroll && el.offset <= newScroll) : (el.offset <= oldScroll && el.offset > newScroll); }); if (!oldScroll || !newScroll) { $[wps]('refresh'); } oldScroll = newScroll; if (!pointsHit.length) return; if ($[wps].settings.continuous) { $.each(isDown ? pointsHit: pointsHit.reverse(), function(i, point) { triggerWaypoint(point, [isDown ? 'down': 'up']); }); } else { triggerWaypoint(pointsHit[isDown ? pointsHit.length - 1: 0], [isDown ? 'down': 'up']); } } $.fn[wp] = function(method) { if (methods[method]) { return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); } else if (typeof method === "function" || !method) { return methods.init.apply(this, arguments); } else if (typeof method === "object") { return methods.init.apply(this, [null, method]); } else { $.error('Method ' + method + ' does not exist on jQuery' + wp); } }; $.fn[wp].defaults = { offset: 0, triggerOnce: false }; var jQMethods = { refresh: function() { $.each(waypoints, function(i, o) { var adjustment = 0, oldOffset = o.offset; if (typeof o.options.offset === "function") { adjustment = o.options.offset.apply(o.element); } else if (typeof o.options.offset === "string") { var amount = parseFloat(o.options.offset), adjustment = o.options.offset.indexOf("%") ? Math.ceil($[wps]('viewportHeight') * (amount / 100)) : amount; } else { adjustment = o.options.offset; } o.offset = o.element.offset().top - adjustment; if (oldScroll > oldOffset && oldScroll <= o.offset) { triggerWaypoint(o, ['up']); } else if (oldScroll < oldOffset && oldScroll >= o.offset) { triggerWaypoint(o, ['down']); } }); waypoints.sort(function(a, b) { return a.offset - b.offset; }); }, viewportHeight: function() { return (window.innerHeight ? window.innerHeight: $w.height()); }, aggregate: function() { var points = $(); $.each(waypoints, function(i, e) { points = points.add(e.element); }); return points; } }; $[wps] = function(method) { if (jQMethods[method]) { return jQMethods[method].apply(this); } else { return jQMethods["aggregate"](); } }; $[wps].settings = { continuous: true, resizeThrottle: 200, scrollThrottle: 100 }; $w.scroll(function() { if (!didScroll) { didScroll = true; window.setTimeout(function() { doScroll(); didScroll = false; }, $[wps].settings.scrollThrottle); } }).resize(function() { if (!didResize) { didResize = true; window.setTimeout(function() { $[wps]('refresh'); didResize = false; }, $[wps].settings.resizeThrottle); } }).load(function() { $[wps]('refresh'); doScroll(); }); })(jQuery, 'waypoint', 'waypoints', this);