├── .eslintrc
├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── README.md
├── bower.json
├── gulpfile.js
├── lib
├── jquery.waypoints.js
├── jquery.waypoints.min.js
├── noframework.waypoints.js
├── noframework.waypoints.min.js
├── shortcuts
│ ├── infinite.js
│ ├── infinite.min.js
│ ├── inview.js
│ ├── inview.min.js
│ ├── sticky.js
│ └── sticky.min.js
├── waypoints.debug.js
├── zepto.waypoints.js
└── zepto.waypoints.min.js
├── licenses.txt
├── package.json
├── src
├── adapters
│ ├── jquery-zepto-fn-extension.js
│ ├── jquery.js
│ ├── noframework.js
│ └── zepto.js
├── context.js
├── debug.js
├── group.js
├── shortcuts
│ ├── infinite.js
│ ├── inview.js
│ └── sticky.js
└── waypoint.js
├── test
├── adapter-fn-spec.js
├── context-spec.js
├── debug-spec.js
├── fixtures
│ ├── infinite.html
│ ├── standard.html
│ └── sticky.html
├── group-spec.js
├── infinite-spec.js
├── inview-spec.js
├── lib
│ ├── coffee-script.js
│ ├── jasmine-html.js
│ ├── jasmine-jquery.js
│ ├── jasmine.css
│ ├── jasmine.js
│ ├── require.js
│ └── testloader.js
├── settings.js
├── sticky-spec.js
└── waypoint-spec.js
└── testem.json
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "node": true
5 | },
6 |
7 | "rules": {
8 | "brace-style": [1, "stroustrup"],
9 | "consistent-this": [1, "self"],
10 | "eqeqeq": [1, "smart"],
11 | "func-style": [1, "declaration"],
12 | "no-else-return": 1,
13 | "no-extra-parens": 1,
14 | "no-floating-decimal": 1,
15 | "no-nested-ternary": 1,
16 | "no-lonely-if": 1,
17 | "quotes": [1, "single", "avoid-escape"],
18 | "radix": 1,
19 | "semi": [1, "never"],
20 | "space-after-keywords": [1, "always"],
21 | "space-in-brackets": [1, "never"],
22 | "space-unary-word-ops": 1,
23 | "wrap-iife": 1
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | _site
2 | .sass-cache
3 | .DS_Store
4 | /style.scss
5 | *.gz
6 | node_modules
7 | bower_components
8 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | sudo: false
3 | node_js:
4 | - "0.10"
5 | before_script:
6 | - npm install -g bower
7 | - bower install
8 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## v4.0.1
4 |
5 | - Improve performance of `enableAll`. (Issue #454)
6 | - Handle edge case bug where Waypoint initialization during a specific part of iOS scroll bounce would cause an immediate trigger of it. (Issue #499)
7 | - Maintain `window` Context/resize-handler even when there are only non-window-context waypoints. (Issue #442)
8 |
9 | ## v4.0.0
10 |
11 | - Allow Sticky option `wrapper` to accept false, which will not create a wrapper and instead use the preexisting parent element. (Pull #416)
12 | - Waypoints that are immediately triggered on creation because they've already passed their trigger point now run their handlers on the next animation frame. This contains Zalgo. (Issue #384)
13 | - Pass the jQuery object of items added during an Infinite page load to the `onAfterPageLoad` callback. (Pull #398)
14 | - Add `enabled` option, `enable` and `disable` methods to the Inview shortcut (Pull #406)
15 | - Make the Inview instance `this` within the callbacks, rather than the invdividual underlying waypoints. (Issue #412)
16 | - Account for changes to jQuery 3 around calling `offset` on the window. (Pull #430)
17 | - Add `context` option to Inview. (Issue #433)
18 |
19 | ## v3.1.1
20 |
21 | - Fix bad `isWindow` checks causing errors in IE8-. (Issue #372)
22 |
23 | ## v3.1.0
24 |
25 | - Add `Waypoint.disableAll` and `Waypoint.enableAll` methods.
26 | - Fix Illegal Invocation errors stemming from non-window context use of `requestAnimationFrame`. (Pull #366)
27 | - Keep disabled waypoints from triggering debug script errors. (Pull #365)
28 | - Allow Infinite Scroll items to be root elements in the AJAX response. (Pull #361)
29 | - In debug script, detect display none and fixed positioning defined in CSS.
30 |
31 | ## v3.0.1
32 |
33 | - Add semicolons to the end of built files to aid in clean concatenation. (Issue #353)
34 |
35 | ## v3.0.0
36 |
37 | - Remove hard jQuery dependency. Create builds for jQuery, Zepto, and no DOM framework. (Issue #282)
38 | - Expose `Waypoint` and `Context` classes. (Issue #281)
39 | - Add `Group` class and `group` option for grouping waypoints. Make `continuous` option work within these groups. (Issue #264)
40 | - Add Inview shortcut. (Issue #131)
41 | - Extend `continuous` option to cover refreshes. (Issue #166)
42 | - Throttle resize and scroll handlers using `requestAnimationFrame` instead of a set millisecond timeout. Fallback to the old 60 FPS `setTimeout` throttle for unsupported browsers. (Issue #242)
43 | - Add debugging script for diagnosing common problems.
44 | - Remove `triggerOnce` option.
45 | - Add `viewportWidth` utility method.
46 | - Remove all traces of CoffeeScript.
47 |
48 | ## v2.0.5
49 |
50 | - Allow sticky users to define which direction the stuck class shold be applied. (Issue #192)
51 | - Fix bug where short content on a large screen could cause the infinite shortcut to stall after the first page load. (Issue #207)
52 | - Make `unsticky` safe to use on any element. Previously it would unwrap the parent even if the element had never had `sticky` called on it or already had `unsticky` called previously. (Issue #225)
53 | - Fix bug that would cause handlers to be overwritten when trying to reuse an options object. (Issue #253)
54 | - Remove "More" link when infinite shortcut reaches last page. (Issue #260)
55 | - Fix use of `this` instead of `window`, causing Browserify to fail. (Issue #262)
56 | - Stop using deprecated jQuery `load` method. (Issue #283)
57 |
58 | ## v2.0.4
59 |
60 | - Fix enable, disable, and destroys calls not chaining the jQuery object. (Issue #244) (Thanks [@robharper](https://github.com/robharper))
61 | - Fix destroy not unregistering internal waypoint references if underlying node has been removed from the document, causing memory leaks. (Issue #243)
62 |
63 | ## v2.0.3
64 |
65 | - Add "unsticky" function for sticky shortcut. (Issue #130)
66 | - Exit early from Infinite shortcut if no "more" link exists. (Issue #140)
67 | - Delay height evaluation of sticky shortcut wrapper. (Issue #151)
68 | - Fix errors with Infinite shortcut's parsing of HTML with jQuery 1.9+. (Issue #163)
69 |
70 |
71 | ## v2.0.2
72 |
73 | - Add AMD support. (Issue #116)
74 | - Work around iOS issue with cancelled `setTimeout` timers by not using scroll throttling on touch devices. (Issue #120)
75 | - If defined, execute `handler` option passed to sticky shortcut at the end of the stuck/unstuck change. (Issue #123)
76 |
77 | ## v2.0.1
78 |
79 | - Lower default throttle values for `scrollThrottle` and `resizeThrottle`.
80 | - Fix Issue #104: Pixel offsets written as strings are interpreted as %s.
81 | - Fix Issue #100: Work around IE not firing scroll event on document shortening by forcing a scroll check on `refresh` calls.
82 |
83 | ## v2.0.0
84 |
85 | - Rewrite Waypoints in CoffeeScript.
86 | - Add Sticky and Infinite shortcut scripts.
87 | - Allow multiple Waypoints on each element. (Issue #40)
88 | - Allow horizontal scrolling Waypoints. (Issue #14)
89 | - API additions: (#69, 83, 88)
90 | - prev, next, above, below, left, right, extendFn, enable, disable
91 | - API subtractions:
92 | - remove
93 | - Remove custom 'waypoint.reached' jQuery Event from powering the trigger.
94 | - $.waypoints now returns object with vertical+horizontal properties and HTMLElement arrays instead of jQuery object (to preserve trigger order instead of jQuery's forced source order).
95 | - Add enabled option.
96 |
97 | ## v1.1.7
98 |
99 | - Actually fix the post-load bug in Issue #28 from v1.1.3.
100 |
101 | ## v1.1.6
102 |
103 | - Fix potential memory leak by unbinding events on empty context elements.
104 |
105 | ## v1.1.5
106 |
107 | - Make plugin compatible with Browserify/RequireJS. (Thanks [@cjroebuck](https://github.com/cjroebuck))
108 |
109 | ## v1.1.4
110 |
111 | - Add handler option to give alternate binding method.
112 |
113 | ## v1.1.3
114 |
115 | - Fix cases where waypoints are added post-load and should be triggered immediately.
116 |
117 | ## v1.1.2
118 |
119 | - Fixed error thrown by waypoints with triggerOnce option that were triggered via resize refresh.
120 |
121 | ## v1.1.1
122 |
123 | - Fixed bug in initialization where all offsets were being calculated as if set to 0 initially, causing unwarranted triggers during the subsequent refresh.
124 | - Added `onlyOnScroll`, an option for individual waypoints that disables triggers due to an offset refresh that crosses the current scroll point. (All credit to [@knuton](https://github.com/knuton) on this one.)
125 |
126 | ## v1.1
127 |
128 | - Moved the continuous option out of global settings and into the options
129 | object for individual waypoints.
130 | - Added the context option, which allows for using waypoints within any
131 | scrollable element, not just the window.
132 |
133 | ## v1.0.2
134 |
135 | - Moved scroll and resize handler bindings out of load. Should play nicer with async loaders like Head JS and LABjs.
136 | - Fixed a 1px off error when using certain % offsets.
137 | - Added unit tests.
138 |
139 | ## v1.0.1
140 |
141 | - Added $.waypoints('viewportHeight').
142 | - Fixed iOS bug (using the new viewportHeight method).
143 | - Added offset function alias: 'bottom-in-view'.
144 |
145 | ## v1.0
146 |
147 | - Initial release.
148 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Opening an Issue
2 |
3 | The GitHub issue tracker is exclusively for opening demonstrable bugs with the library or for discussing/implementing enhancements. If you need general help with Waypoints try searching through existing closed tickets, searching through the [#jquery-waypoints](http://stackoverflow.com/questions/tagged/jquery-waypoints) tag on StackOverflow, or asking your question there using that tag. If you do ask a question on StackOverflow, please follow the guidelines for [asking a good question](http://stackoverflow.com/help/how-to-ask).
4 |
5 | If you're opening a ticket for a bug:
6 |
7 | - Give a clear explanation of the bug.
8 | - Try to provide a link to a [JSFiddle](http://jsfiddle.net/) or [CodePen](http://codepen.io/) or similar reduced test case.
9 | - If you cannot provide a reduced test case, please provide a link to a live site demonstrating your bug and include in the ticket the relevant Waypoints code.
10 |
11 | If you're interested in discussing a possible new feature:
12 |
13 | - Search closed tickets for discussions that may have already occurred.
14 | - Open a ticket and let's talk!
15 |
16 | # Pull Requests
17 |
18 | - Please send the pull request against the master branch.
19 | - Note any tickets that the pull request addresses.
20 | - Add any necessary tests (see below).
21 | - Follow the coding style of the current codebase.
22 |
23 | # Tests
24 |
25 | Tests are written in [Jasmine](http://jasmine.github.io/) and run through the [testem](https://github.com/airportyh/testem) test runner. To run them locally you'll need to:
26 |
27 | - Install, if you haven't already: [PhantomJS](http://phantomjs.org/), node, and [Bower](bower.io).
28 | - `npm install`
29 | - `bower install`
30 |
31 | You can then run the tests one time by running `npm test`, or enter TDD mode by running `npm run tdd`.
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Waypoints
2 |
3 | Waypoints is a library that makes it easy to execute a function whenever you scroll to an element. 
4 |
5 | ```js
6 | var waypoint = new Waypoint({
7 | element: document.getElementById('thing'),
8 | handler: function(direction) {
9 | alert('You have scrolled to a thing')
10 | }
11 | })
12 | ```
13 |
14 | If you're new to Waypoints, check out the [Getting Started](http://imakewebthings.com/waypoints/guides/getting-started) guide.
15 |
16 | [Read the full documentation](http://imakewebthings.com/waypoints/api/waypoint) for more details on usage and customization.
17 |
18 | ## Shortcuts
19 |
20 | In addition to the normal Waypoints script, extensions exist to make common UI patterns just a little easier to implement:
21 |
22 | - [Infinite Scrolling](http://imakewebthings.com/waypoints/shortcuts/infinite-scroll)
23 | - [Sticky Elements](http://imakewebthings.com/waypoints/shortcuts/sticky-elements)
24 | - [Inview Detection](http://imakewebthings.com/waypoints/shortcuts/inview)
25 |
26 |
27 | ## Contributing
28 |
29 | If you want to report a Waypoints bug or contribute code to the library, please read the [Contributing Guidelines](https://github.com/imakewebthings/waypoints/blob/master/CONTRIBUTING.md). If you need help *using* Waypoints, please do not open an issue. Instead, ask the question on [Stack Overflow](http://stackoverflow.com) and tag it with #jquery-waypoints
. Be sure to follow the guidelines for [asking a good question](http://stackoverflow.com/help/how-to-ask).
30 |
31 | ## License
32 |
33 | Copyright (c) 2011-2014 Caleb Troughton. Licensed under the [MIT license](https://github.com/imakewebthings/waypoints/blob/master/licenses.txt).
34 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "waypoints",
3 | "main": "lib/noframework.waypoints.js",
4 | "description": "Easily execute a function when you scroll to an element.",
5 | "ignore": [
6 | "gulpfile.js",
7 | "package.json",
8 | "src",
9 | "test",
10 | "testem.json"
11 | ],
12 | "devDependencies": {
13 | "jquery": "~1.11.1",
14 | "lodash": "~2.4.1",
15 | "jasmine-jquery": "~1.7.0",
16 | "zepto": "~1.1.3"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp')
2 | var eslint = require('gulp-eslint')
3 | var concat = require('gulp-concat')
4 | var uglify = require('gulp-uglify')
5 | var rename = require('gulp-rename')
6 | var header = require('gulp-header')
7 | var footer = require('gulp-footer')
8 | var tap = require('gulp-tap')
9 | var merge = require('merge-stream')
10 | var pkg = require('./package.json')
11 | var path = require('path')
12 |
13 | var jsFiles = ['src/**/*.js', 'test/**/*.js', '!test/lib/**/*.js']
14 | var shortcutTitles = {
15 | 'infinite': 'Waypoints Infinite Scroll Shortcut',
16 | 'inview': 'Waypoints Inview Shortcut',
17 | 'sticky': 'Waypoints Sticky Element Shortcut'
18 | }
19 |
20 | function fileHeader(title) {
21 | return [
22 | '/*!',
23 | title + ' - ' + pkg.version,
24 | 'Copyright © 2011-' + new Date().getFullYear() + ' Caleb Troughton',
25 | 'Licensed under the MIT license.',
26 | 'https://github.com/imakewebthings/waypoints/blob/master/licenses.txt',
27 | '*/\n'
28 | ].join('\n')
29 | }
30 |
31 | gulp.task('lint', function() {
32 | return gulp.src(jsFiles).pipe(eslint('.eslintrc')).pipe(eslint.format())
33 | })
34 |
35 | gulp.task('build-core', function() {
36 | var streams = ['noframework', 'jquery', 'zepto'].map(function(adapter) {
37 | var sources = [
38 | 'src/waypoint.js',
39 | 'src/context.js',
40 | 'src/group.js',
41 | 'src/adapters/' + adapter + '.js'
42 | ]
43 | if (['jquery', 'zepto'].indexOf(adapter) > -1) {
44 | sources.push('src/adapters/jquery-zepto-fn-extension.js')
45 | }
46 | return gulp.src(sources)
47 | .pipe(concat(adapter + '.waypoints.js', { newLine: ';' }))
48 | .pipe(header(fileHeader('Waypoints')))
49 | .pipe(footer(';'))
50 | .pipe(gulp.dest('lib/'))
51 | .pipe(rename(adapter + '.waypoints.min.js'))
52 | .pipe(uglify({
53 | preserveComments: 'some'
54 | }))
55 | .pipe(gulp.dest('lib/'))
56 | })
57 | return merge.apply(null, streams)
58 | })
59 |
60 | gulp.task('build-shortcuts', function() {
61 | return gulp.src([
62 | 'src/shortcuts/*.js'
63 | ])
64 | .pipe(tap(function(file) {
65 | var title = path.basename(file.path, '.js')
66 | file.contents = Buffer.concat([
67 | new Buffer(fileHeader(shortcutTitles[title])),
68 | file.contents
69 | ])
70 | }))
71 | .pipe(footer(';'))
72 | .pipe(gulp.dest('lib/shortcuts/'))
73 | .pipe(rename(function(path) {
74 | path.basename += '.min'
75 | }))
76 | .pipe(uglify({
77 | preserveComments: 'some'
78 | }))
79 | .pipe(gulp.dest('lib/shortcuts/'))
80 | })
81 |
82 | gulp.task('build-debug', function() {
83 | return gulp.src([
84 | 'src/debug.js'
85 | ])
86 | .pipe(rename('waypoints.debug.js'))
87 | .pipe(header(fileHeader('Waypoints Debug')))
88 | .pipe(footer(';'))
89 | .pipe(gulp.dest('lib/'))
90 | })
91 |
92 | gulp.task('build', ['build-core', 'build-shortcuts', 'build-debug'])
93 |
94 | gulp.task('watch', function() {
95 | gulp.watch(jsFiles, ['lint', 'build'])
96 | })
97 |
98 | gulp.task('default', ['lint', 'build', 'watch'])
99 |
--------------------------------------------------------------------------------
/lib/jquery.waypoints.js:
--------------------------------------------------------------------------------
1 | /*!
2 | Waypoints - 4.0.1
3 | Copyright © 2011-2016 Caleb Troughton
4 | Licensed under the MIT license.
5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
6 | */
7 | (function() {
8 | 'use strict'
9 |
10 | var keyCounter = 0
11 | var allWaypoints = {}
12 |
13 | /* http://imakewebthings.com/waypoints/api/waypoint */
14 | function Waypoint(options) {
15 | if (!options) {
16 | throw new Error('No options passed to Waypoint constructor')
17 | }
18 | if (!options.element) {
19 | throw new Error('No element option passed to Waypoint constructor')
20 | }
21 | if (!options.handler) {
22 | throw new Error('No handler option passed to Waypoint constructor')
23 | }
24 |
25 | this.key = 'waypoint-' + keyCounter
26 | this.options = Waypoint.Adapter.extend({}, Waypoint.defaults, options)
27 | this.element = this.options.element
28 | this.adapter = new Waypoint.Adapter(this.element)
29 | this.callback = options.handler
30 | this.axis = this.options.horizontal ? 'horizontal' : 'vertical'
31 | this.enabled = this.options.enabled
32 | this.triggerPoint = null
33 | this.group = Waypoint.Group.findOrCreate({
34 | name: this.options.group,
35 | axis: this.axis
36 | })
37 | this.context = Waypoint.Context.findOrCreateByElement(this.options.context)
38 |
39 | if (Waypoint.offsetAliases[this.options.offset]) {
40 | this.options.offset = Waypoint.offsetAliases[this.options.offset]
41 | }
42 | this.group.add(this)
43 | this.context.add(this)
44 | allWaypoints[this.key] = this
45 | keyCounter += 1
46 | }
47 |
48 | /* Private */
49 | Waypoint.prototype.queueTrigger = function(direction) {
50 | this.group.queueTrigger(this, direction)
51 | }
52 |
53 | /* Private */
54 | Waypoint.prototype.trigger = function(args) {
55 | if (!this.enabled) {
56 | return
57 | }
58 | if (this.callback) {
59 | this.callback.apply(this, args)
60 | }
61 | }
62 |
63 | /* Public */
64 | /* http://imakewebthings.com/waypoints/api/destroy */
65 | Waypoint.prototype.destroy = function() {
66 | this.context.remove(this)
67 | this.group.remove(this)
68 | delete allWaypoints[this.key]
69 | }
70 |
71 | /* Public */
72 | /* http://imakewebthings.com/waypoints/api/disable */
73 | Waypoint.prototype.disable = function() {
74 | this.enabled = false
75 | return this
76 | }
77 |
78 | /* Public */
79 | /* http://imakewebthings.com/waypoints/api/enable */
80 | Waypoint.prototype.enable = function() {
81 | this.context.refresh()
82 | this.enabled = true
83 | return this
84 | }
85 |
86 | /* Public */
87 | /* http://imakewebthings.com/waypoints/api/next */
88 | Waypoint.prototype.next = function() {
89 | return this.group.next(this)
90 | }
91 |
92 | /* Public */
93 | /* http://imakewebthings.com/waypoints/api/previous */
94 | Waypoint.prototype.previous = function() {
95 | return this.group.previous(this)
96 | }
97 |
98 | /* Private */
99 | Waypoint.invokeAll = function(method) {
100 | var allWaypointsArray = []
101 | for (var waypointKey in allWaypoints) {
102 | allWaypointsArray.push(allWaypoints[waypointKey])
103 | }
104 | for (var i = 0, end = allWaypointsArray.length; i < end; i++) {
105 | allWaypointsArray[i][method]()
106 | }
107 | }
108 |
109 | /* Public */
110 | /* http://imakewebthings.com/waypoints/api/destroy-all */
111 | Waypoint.destroyAll = function() {
112 | Waypoint.invokeAll('destroy')
113 | }
114 |
115 | /* Public */
116 | /* http://imakewebthings.com/waypoints/api/disable-all */
117 | Waypoint.disableAll = function() {
118 | Waypoint.invokeAll('disable')
119 | }
120 |
121 | /* Public */
122 | /* http://imakewebthings.com/waypoints/api/enable-all */
123 | Waypoint.enableAll = function() {
124 | Waypoint.Context.refreshAll()
125 | for (var waypointKey in allWaypoints) {
126 | allWaypoints[waypointKey].enabled = true
127 | }
128 | return this
129 | }
130 |
131 | /* Public */
132 | /* http://imakewebthings.com/waypoints/api/refresh-all */
133 | Waypoint.refreshAll = function() {
134 | Waypoint.Context.refreshAll()
135 | }
136 |
137 | /* Public */
138 | /* http://imakewebthings.com/waypoints/api/viewport-height */
139 | Waypoint.viewportHeight = function() {
140 | return window.innerHeight || document.documentElement.clientHeight
141 | }
142 |
143 | /* Public */
144 | /* http://imakewebthings.com/waypoints/api/viewport-width */
145 | Waypoint.viewportWidth = function() {
146 | return document.documentElement.clientWidth
147 | }
148 |
149 | Waypoint.adapters = []
150 |
151 | Waypoint.defaults = {
152 | context: window,
153 | continuous: true,
154 | enabled: true,
155 | group: 'default',
156 | horizontal: false,
157 | offset: 0
158 | }
159 |
160 | Waypoint.offsetAliases = {
161 | 'bottom-in-view': function() {
162 | return this.context.innerHeight() - this.adapter.outerHeight()
163 | },
164 | 'right-in-view': function() {
165 | return this.context.innerWidth() - this.adapter.outerWidth()
166 | }
167 | }
168 |
169 | window.Waypoint = Waypoint
170 | }())
171 | ;(function() {
172 | 'use strict'
173 |
174 | function requestAnimationFrameShim(callback) {
175 | window.setTimeout(callback, 1000 / 60)
176 | }
177 |
178 | var keyCounter = 0
179 | var contexts = {}
180 | var Waypoint = window.Waypoint
181 | var oldWindowLoad = window.onload
182 |
183 | /* http://imakewebthings.com/waypoints/api/context */
184 | function Context(element) {
185 | this.element = element
186 | this.Adapter = Waypoint.Adapter
187 | this.adapter = new this.Adapter(element)
188 | this.key = 'waypoint-context-' + keyCounter
189 | this.didScroll = false
190 | this.didResize = false
191 | this.oldScroll = {
192 | x: this.adapter.scrollLeft(),
193 | y: this.adapter.scrollTop()
194 | }
195 | this.waypoints = {
196 | vertical: {},
197 | horizontal: {}
198 | }
199 |
200 | element.waypointContextKey = this.key
201 | contexts[element.waypointContextKey] = this
202 | keyCounter += 1
203 | if (!Waypoint.windowContext) {
204 | Waypoint.windowContext = true
205 | Waypoint.windowContext = new Context(window)
206 | }
207 |
208 | this.createThrottledScrollHandler()
209 | this.createThrottledResizeHandler()
210 | }
211 |
212 | /* Private */
213 | Context.prototype.add = function(waypoint) {
214 | var axis = waypoint.options.horizontal ? 'horizontal' : 'vertical'
215 | this.waypoints[axis][waypoint.key] = waypoint
216 | this.refresh()
217 | }
218 |
219 | /* Private */
220 | Context.prototype.checkEmpty = function() {
221 | var horizontalEmpty = this.Adapter.isEmptyObject(this.waypoints.horizontal)
222 | var verticalEmpty = this.Adapter.isEmptyObject(this.waypoints.vertical)
223 | var isWindow = this.element == this.element.window
224 | if (horizontalEmpty && verticalEmpty && !isWindow) {
225 | this.adapter.off('.waypoints')
226 | delete contexts[this.key]
227 | }
228 | }
229 |
230 | /* Private */
231 | Context.prototype.createThrottledResizeHandler = function() {
232 | var self = this
233 |
234 | function resizeHandler() {
235 | self.handleResize()
236 | self.didResize = false
237 | }
238 |
239 | this.adapter.on('resize.waypoints', function() {
240 | if (!self.didResize) {
241 | self.didResize = true
242 | Waypoint.requestAnimationFrame(resizeHandler)
243 | }
244 | })
245 | }
246 |
247 | /* Private */
248 | Context.prototype.createThrottledScrollHandler = function() {
249 | var self = this
250 | function scrollHandler() {
251 | self.handleScroll()
252 | self.didScroll = false
253 | }
254 |
255 | this.adapter.on('scroll.waypoints', function() {
256 | if (!self.didScroll || Waypoint.isTouch) {
257 | self.didScroll = true
258 | Waypoint.requestAnimationFrame(scrollHandler)
259 | }
260 | })
261 | }
262 |
263 | /* Private */
264 | Context.prototype.handleResize = function() {
265 | Waypoint.Context.refreshAll()
266 | }
267 |
268 | /* Private */
269 | Context.prototype.handleScroll = function() {
270 | var triggeredGroups = {}
271 | var axes = {
272 | horizontal: {
273 | newScroll: this.adapter.scrollLeft(),
274 | oldScroll: this.oldScroll.x,
275 | forward: 'right',
276 | backward: 'left'
277 | },
278 | vertical: {
279 | newScroll: this.adapter.scrollTop(),
280 | oldScroll: this.oldScroll.y,
281 | forward: 'down',
282 | backward: 'up'
283 | }
284 | }
285 |
286 | for (var axisKey in axes) {
287 | var axis = axes[axisKey]
288 | var isForward = axis.newScroll > axis.oldScroll
289 | var direction = isForward ? axis.forward : axis.backward
290 |
291 | for (var waypointKey in this.waypoints[axisKey]) {
292 | var waypoint = this.waypoints[axisKey][waypointKey]
293 | if (waypoint.triggerPoint === null) {
294 | continue
295 | }
296 | var wasBeforeTriggerPoint = axis.oldScroll < waypoint.triggerPoint
297 | var nowAfterTriggerPoint = axis.newScroll >= waypoint.triggerPoint
298 | var crossedForward = wasBeforeTriggerPoint && nowAfterTriggerPoint
299 | var crossedBackward = !wasBeforeTriggerPoint && !nowAfterTriggerPoint
300 | if (crossedForward || crossedBackward) {
301 | waypoint.queueTrigger(direction)
302 | triggeredGroups[waypoint.group.id] = waypoint.group
303 | }
304 | }
305 | }
306 |
307 | for (var groupKey in triggeredGroups) {
308 | triggeredGroups[groupKey].flushTriggers()
309 | }
310 |
311 | this.oldScroll = {
312 | x: axes.horizontal.newScroll,
313 | y: axes.vertical.newScroll
314 | }
315 | }
316 |
317 | /* Private */
318 | Context.prototype.innerHeight = function() {
319 | /*eslint-disable eqeqeq */
320 | if (this.element == this.element.window) {
321 | return Waypoint.viewportHeight()
322 | }
323 | /*eslint-enable eqeqeq */
324 | return this.adapter.innerHeight()
325 | }
326 |
327 | /* Private */
328 | Context.prototype.remove = function(waypoint) {
329 | delete this.waypoints[waypoint.axis][waypoint.key]
330 | this.checkEmpty()
331 | }
332 |
333 | /* Private */
334 | Context.prototype.innerWidth = function() {
335 | /*eslint-disable eqeqeq */
336 | if (this.element == this.element.window) {
337 | return Waypoint.viewportWidth()
338 | }
339 | /*eslint-enable eqeqeq */
340 | return this.adapter.innerWidth()
341 | }
342 |
343 | /* Public */
344 | /* http://imakewebthings.com/waypoints/api/context-destroy */
345 | Context.prototype.destroy = function() {
346 | var allWaypoints = []
347 | for (var axis in this.waypoints) {
348 | for (var waypointKey in this.waypoints[axis]) {
349 | allWaypoints.push(this.waypoints[axis][waypointKey])
350 | }
351 | }
352 | for (var i = 0, end = allWaypoints.length; i < end; i++) {
353 | allWaypoints[i].destroy()
354 | }
355 | }
356 |
357 | /* Public */
358 | /* http://imakewebthings.com/waypoints/api/context-refresh */
359 | Context.prototype.refresh = function() {
360 | /*eslint-disable eqeqeq */
361 | var isWindow = this.element == this.element.window
362 | /*eslint-enable eqeqeq */
363 | var contextOffset = isWindow ? undefined : this.adapter.offset()
364 | var triggeredGroups = {}
365 | var axes
366 |
367 | this.handleScroll()
368 | axes = {
369 | horizontal: {
370 | contextOffset: isWindow ? 0 : contextOffset.left,
371 | contextScroll: isWindow ? 0 : this.oldScroll.x,
372 | contextDimension: this.innerWidth(),
373 | oldScroll: this.oldScroll.x,
374 | forward: 'right',
375 | backward: 'left',
376 | offsetProp: 'left'
377 | },
378 | vertical: {
379 | contextOffset: isWindow ? 0 : contextOffset.top,
380 | contextScroll: isWindow ? 0 : this.oldScroll.y,
381 | contextDimension: this.innerHeight(),
382 | oldScroll: this.oldScroll.y,
383 | forward: 'down',
384 | backward: 'up',
385 | offsetProp: 'top'
386 | }
387 | }
388 |
389 | for (var axisKey in axes) {
390 | var axis = axes[axisKey]
391 | for (var waypointKey in this.waypoints[axisKey]) {
392 | var waypoint = this.waypoints[axisKey][waypointKey]
393 | var adjustment = waypoint.options.offset
394 | var oldTriggerPoint = waypoint.triggerPoint
395 | var elementOffset = 0
396 | var freshWaypoint = oldTriggerPoint == null
397 | var contextModifier, wasBeforeScroll, nowAfterScroll
398 | var triggeredBackward, triggeredForward
399 |
400 | if (waypoint.element !== waypoint.element.window) {
401 | elementOffset = waypoint.adapter.offset()[axis.offsetProp]
402 | }
403 |
404 | if (typeof adjustment === 'function') {
405 | adjustment = adjustment.apply(waypoint)
406 | }
407 | else if (typeof adjustment === 'string') {
408 | adjustment = parseFloat(adjustment)
409 | if (waypoint.options.offset.indexOf('%') > - 1) {
410 | adjustment = Math.ceil(axis.contextDimension * adjustment / 100)
411 | }
412 | }
413 |
414 | contextModifier = axis.contextScroll - axis.contextOffset
415 | waypoint.triggerPoint = Math.floor(elementOffset + contextModifier - adjustment)
416 | wasBeforeScroll = oldTriggerPoint < axis.oldScroll
417 | nowAfterScroll = waypoint.triggerPoint >= axis.oldScroll
418 | triggeredBackward = wasBeforeScroll && nowAfterScroll
419 | triggeredForward = !wasBeforeScroll && !nowAfterScroll
420 |
421 | if (!freshWaypoint && triggeredBackward) {
422 | waypoint.queueTrigger(axis.backward)
423 | triggeredGroups[waypoint.group.id] = waypoint.group
424 | }
425 | else if (!freshWaypoint && triggeredForward) {
426 | waypoint.queueTrigger(axis.forward)
427 | triggeredGroups[waypoint.group.id] = waypoint.group
428 | }
429 | else if (freshWaypoint && axis.oldScroll >= waypoint.triggerPoint) {
430 | waypoint.queueTrigger(axis.forward)
431 | triggeredGroups[waypoint.group.id] = waypoint.group
432 | }
433 | }
434 | }
435 |
436 | Waypoint.requestAnimationFrame(function() {
437 | for (var groupKey in triggeredGroups) {
438 | triggeredGroups[groupKey].flushTriggers()
439 | }
440 | })
441 |
442 | return this
443 | }
444 |
445 | /* Private */
446 | Context.findOrCreateByElement = function(element) {
447 | return Context.findByElement(element) || new Context(element)
448 | }
449 |
450 | /* Private */
451 | Context.refreshAll = function() {
452 | for (var contextId in contexts) {
453 | contexts[contextId].refresh()
454 | }
455 | }
456 |
457 | /* Public */
458 | /* http://imakewebthings.com/waypoints/api/context-find-by-element */
459 | Context.findByElement = function(element) {
460 | return contexts[element.waypointContextKey]
461 | }
462 |
463 | window.onload = function() {
464 | if (oldWindowLoad) {
465 | oldWindowLoad()
466 | }
467 | Context.refreshAll()
468 | }
469 |
470 |
471 | Waypoint.requestAnimationFrame = function(callback) {
472 | var requestFn = window.requestAnimationFrame ||
473 | window.mozRequestAnimationFrame ||
474 | window.webkitRequestAnimationFrame ||
475 | requestAnimationFrameShim
476 | requestFn.call(window, callback)
477 | }
478 | Waypoint.Context = Context
479 | }())
480 | ;(function() {
481 | 'use strict'
482 |
483 | function byTriggerPoint(a, b) {
484 | return a.triggerPoint - b.triggerPoint
485 | }
486 |
487 | function byReverseTriggerPoint(a, b) {
488 | return b.triggerPoint - a.triggerPoint
489 | }
490 |
491 | var groups = {
492 | vertical: {},
493 | horizontal: {}
494 | }
495 | var Waypoint = window.Waypoint
496 |
497 | /* http://imakewebthings.com/waypoints/api/group */
498 | function Group(options) {
499 | this.name = options.name
500 | this.axis = options.axis
501 | this.id = this.name + '-' + this.axis
502 | this.waypoints = []
503 | this.clearTriggerQueues()
504 | groups[this.axis][this.name] = this
505 | }
506 |
507 | /* Private */
508 | Group.prototype.add = function(waypoint) {
509 | this.waypoints.push(waypoint)
510 | }
511 |
512 | /* Private */
513 | Group.prototype.clearTriggerQueues = function() {
514 | this.triggerQueues = {
515 | up: [],
516 | down: [],
517 | left: [],
518 | right: []
519 | }
520 | }
521 |
522 | /* Private */
523 | Group.prototype.flushTriggers = function() {
524 | for (var direction in this.triggerQueues) {
525 | var waypoints = this.triggerQueues[direction]
526 | var reverse = direction === 'up' || direction === 'left'
527 | waypoints.sort(reverse ? byReverseTriggerPoint : byTriggerPoint)
528 | for (var i = 0, end = waypoints.length; i < end; i += 1) {
529 | var waypoint = waypoints[i]
530 | if (waypoint.options.continuous || i === waypoints.length - 1) {
531 | waypoint.trigger([direction])
532 | }
533 | }
534 | }
535 | this.clearTriggerQueues()
536 | }
537 |
538 | /* Private */
539 | Group.prototype.next = function(waypoint) {
540 | this.waypoints.sort(byTriggerPoint)
541 | var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
542 | var isLast = index === this.waypoints.length - 1
543 | return isLast ? null : this.waypoints[index + 1]
544 | }
545 |
546 | /* Private */
547 | Group.prototype.previous = function(waypoint) {
548 | this.waypoints.sort(byTriggerPoint)
549 | var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
550 | return index ? this.waypoints[index - 1] : null
551 | }
552 |
553 | /* Private */
554 | Group.prototype.queueTrigger = function(waypoint, direction) {
555 | this.triggerQueues[direction].push(waypoint)
556 | }
557 |
558 | /* Private */
559 | Group.prototype.remove = function(waypoint) {
560 | var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
561 | if (index > -1) {
562 | this.waypoints.splice(index, 1)
563 | }
564 | }
565 |
566 | /* Public */
567 | /* http://imakewebthings.com/waypoints/api/first */
568 | Group.prototype.first = function() {
569 | return this.waypoints[0]
570 | }
571 |
572 | /* Public */
573 | /* http://imakewebthings.com/waypoints/api/last */
574 | Group.prototype.last = function() {
575 | return this.waypoints[this.waypoints.length - 1]
576 | }
577 |
578 | /* Private */
579 | Group.findOrCreate = function(options) {
580 | return groups[options.axis][options.name] || new Group(options)
581 | }
582 |
583 | Waypoint.Group = Group
584 | }())
585 | ;(function() {
586 | 'use strict'
587 |
588 | var $ = window.jQuery
589 | var Waypoint = window.Waypoint
590 |
591 | function JQueryAdapter(element) {
592 | this.$element = $(element)
593 | }
594 |
595 | $.each([
596 | 'innerHeight',
597 | 'innerWidth',
598 | 'off',
599 | 'offset',
600 | 'on',
601 | 'outerHeight',
602 | 'outerWidth',
603 | 'scrollLeft',
604 | 'scrollTop'
605 | ], function(i, method) {
606 | JQueryAdapter.prototype[method] = function() {
607 | var args = Array.prototype.slice.call(arguments)
608 | return this.$element[method].apply(this.$element, args)
609 | }
610 | })
611 |
612 | $.each([
613 | 'extend',
614 | 'inArray',
615 | 'isEmptyObject'
616 | ], function(i, method) {
617 | JQueryAdapter[method] = $[method]
618 | })
619 |
620 | Waypoint.adapters.push({
621 | name: 'jquery',
622 | Adapter: JQueryAdapter
623 | })
624 | Waypoint.Adapter = JQueryAdapter
625 | }())
626 | ;(function() {
627 | 'use strict'
628 |
629 | var Waypoint = window.Waypoint
630 |
631 | function createExtension(framework) {
632 | return function() {
633 | var waypoints = []
634 | var overrides = arguments[0]
635 |
636 | if (framework.isFunction(arguments[0])) {
637 | overrides = framework.extend({}, arguments[1])
638 | overrides.handler = arguments[0]
639 | }
640 |
641 | this.each(function() {
642 | var options = framework.extend({}, overrides, {
643 | element: this
644 | })
645 | if (typeof options.context === 'string') {
646 | options.context = framework(this).closest(options.context)[0]
647 | }
648 | waypoints.push(new Waypoint(options))
649 | })
650 |
651 | return waypoints
652 | }
653 | }
654 |
655 | if (window.jQuery) {
656 | window.jQuery.fn.waypoint = createExtension(window.jQuery)
657 | }
658 | if (window.Zepto) {
659 | window.Zepto.fn.waypoint = createExtension(window.Zepto)
660 | }
661 | }())
662 | ;
--------------------------------------------------------------------------------
/lib/jquery.waypoints.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | Waypoints - 4.0.1
3 | Copyright © 2011-2016 Caleb Troughton
4 | Licensed under the MIT license.
5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
6 | */
7 | !function(){"use strict";function t(o){if(!o)throw new Error("No options passed to Waypoint constructor");if(!o.element)throw new Error("No element option passed to Waypoint constructor");if(!o.handler)throw new Error("No handler option passed to Waypoint constructor");this.key="waypoint-"+e,this.options=t.Adapter.extend({},t.defaults,o),this.element=this.options.element,this.adapter=new t.Adapter(this.element),this.callback=o.handler,this.axis=this.options.horizontal?"horizontal":"vertical",this.enabled=this.options.enabled,this.triggerPoint=null,this.group=t.Group.findOrCreate({name:this.options.group,axis:this.axis}),this.context=t.Context.findOrCreateByElement(this.options.context),t.offsetAliases[this.options.offset]&&(this.options.offset=t.offsetAliases[this.options.offset]),this.group.add(this),this.context.add(this),i[this.key]=this,e+=1}var e=0,i={};t.prototype.queueTrigger=function(t){this.group.queueTrigger(this,t)},t.prototype.trigger=function(t){this.enabled&&this.callback&&this.callback.apply(this,t)},t.prototype.destroy=function(){this.context.remove(this),this.group.remove(this),delete i[this.key]},t.prototype.disable=function(){return this.enabled=!1,this},t.prototype.enable=function(){return this.context.refresh(),this.enabled=!0,this},t.prototype.next=function(){return this.group.next(this)},t.prototype.previous=function(){return this.group.previous(this)},t.invokeAll=function(t){var e=[];for(var o in i)e.push(i[o]);for(var n=0,r=e.length;r>n;n++)e[n][t]()},t.destroyAll=function(){t.invokeAll("destroy")},t.disableAll=function(){t.invokeAll("disable")},t.enableAll=function(){t.Context.refreshAll();for(var e in i)i[e].enabled=!0;return this},t.refreshAll=function(){t.Context.refreshAll()},t.viewportHeight=function(){return window.innerHeight||document.documentElement.clientHeight},t.viewportWidth=function(){return document.documentElement.clientWidth},t.adapters=[],t.defaults={context:window,continuous:!0,enabled:!0,group:"default",horizontal:!1,offset:0},t.offsetAliases={"bottom-in-view":function(){return this.context.innerHeight()-this.adapter.outerHeight()},"right-in-view":function(){return this.context.innerWidth()-this.adapter.outerWidth()}},window.Waypoint=t}(),function(){"use strict";function t(t){window.setTimeout(t,1e3/60)}function e(t){this.element=t,this.Adapter=n.Adapter,this.adapter=new this.Adapter(t),this.key="waypoint-context-"+i,this.didScroll=!1,this.didResize=!1,this.oldScroll={x:this.adapter.scrollLeft(),y:this.adapter.scrollTop()},this.waypoints={vertical:{},horizontal:{}},t.waypointContextKey=this.key,o[t.waypointContextKey]=this,i+=1,n.windowContext||(n.windowContext=!0,n.windowContext=new e(window)),this.createThrottledScrollHandler(),this.createThrottledResizeHandler()}var i=0,o={},n=window.Waypoint,r=window.onload;e.prototype.add=function(t){var e=t.options.horizontal?"horizontal":"vertical";this.waypoints[e][t.key]=t,this.refresh()},e.prototype.checkEmpty=function(){var t=this.Adapter.isEmptyObject(this.waypoints.horizontal),e=this.Adapter.isEmptyObject(this.waypoints.vertical),i=this.element==this.element.window;t&&e&&!i&&(this.adapter.off(".waypoints"),delete o[this.key])},e.prototype.createThrottledResizeHandler=function(){function t(){e.handleResize(),e.didResize=!1}var e=this;this.adapter.on("resize.waypoints",function(){e.didResize||(e.didResize=!0,n.requestAnimationFrame(t))})},e.prototype.createThrottledScrollHandler=function(){function t(){e.handleScroll(),e.didScroll=!1}var e=this;this.adapter.on("scroll.waypoints",function(){(!e.didScroll||n.isTouch)&&(e.didScroll=!0,n.requestAnimationFrame(t))})},e.prototype.handleResize=function(){n.Context.refreshAll()},e.prototype.handleScroll=function(){var t={},e={horizontal:{newScroll:this.adapter.scrollLeft(),oldScroll:this.oldScroll.x,forward:"right",backward:"left"},vertical:{newScroll:this.adapter.scrollTop(),oldScroll:this.oldScroll.y,forward:"down",backward:"up"}};for(var i in e){var o=e[i],n=o.newScroll>o.oldScroll,r=n?o.forward:o.backward;for(var s in this.waypoints[i]){var a=this.waypoints[i][s];if(null!==a.triggerPoint){var l=o.oldScroll=a.triggerPoint,p=l&&h,u=!l&&!h;(p||u)&&(a.queueTrigger(r),t[a.group.id]=a.group)}}}for(var c in t)t[c].flushTriggers();this.oldScroll={x:e.horizontal.newScroll,y:e.vertical.newScroll}},e.prototype.innerHeight=function(){return this.element==this.element.window?n.viewportHeight():this.adapter.innerHeight()},e.prototype.remove=function(t){delete this.waypoints[t.axis][t.key],this.checkEmpty()},e.prototype.innerWidth=function(){return this.element==this.element.window?n.viewportWidth():this.adapter.innerWidth()},e.prototype.destroy=function(){var t=[];for(var e in this.waypoints)for(var i in this.waypoints[e])t.push(this.waypoints[e][i]);for(var o=0,n=t.length;n>o;o++)t[o].destroy()},e.prototype.refresh=function(){var t,e=this.element==this.element.window,i=e?void 0:this.adapter.offset(),o={};this.handleScroll(),t={horizontal:{contextOffset:e?0:i.left,contextScroll:e?0:this.oldScroll.x,contextDimension:this.innerWidth(),oldScroll:this.oldScroll.x,forward:"right",backward:"left",offsetProp:"left"},vertical:{contextOffset:e?0:i.top,contextScroll:e?0:this.oldScroll.y,contextDimension:this.innerHeight(),oldScroll:this.oldScroll.y,forward:"down",backward:"up",offsetProp:"top"}};for(var r in t){var s=t[r];for(var a in this.waypoints[r]){var l,h,p,u,c,d=this.waypoints[r][a],f=d.options.offset,w=d.triggerPoint,y=0,g=null==w;d.element!==d.element.window&&(y=d.adapter.offset()[s.offsetProp]),"function"==typeof f?f=f.apply(d):"string"==typeof f&&(f=parseFloat(f),d.options.offset.indexOf("%")>-1&&(f=Math.ceil(s.contextDimension*f/100))),l=s.contextScroll-s.contextOffset,d.triggerPoint=Math.floor(y+l-f),h=w=s.oldScroll,u=h&&p,c=!h&&!p,!g&&u?(d.queueTrigger(s.backward),o[d.group.id]=d.group):!g&&c?(d.queueTrigger(s.forward),o[d.group.id]=d.group):g&&s.oldScroll>=d.triggerPoint&&(d.queueTrigger(s.forward),o[d.group.id]=d.group)}}return n.requestAnimationFrame(function(){for(var t in o)o[t].flushTriggers()}),this},e.findOrCreateByElement=function(t){return e.findByElement(t)||new e(t)},e.refreshAll=function(){for(var t in o)o[t].refresh()},e.findByElement=function(t){return o[t.waypointContextKey]},window.onload=function(){r&&r(),e.refreshAll()},n.requestAnimationFrame=function(e){var i=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||t;i.call(window,e)},n.Context=e}(),function(){"use strict";function t(t,e){return t.triggerPoint-e.triggerPoint}function e(t,e){return e.triggerPoint-t.triggerPoint}function i(t){this.name=t.name,this.axis=t.axis,this.id=this.name+"-"+this.axis,this.waypoints=[],this.clearTriggerQueues(),o[this.axis][this.name]=this}var o={vertical:{},horizontal:{}},n=window.Waypoint;i.prototype.add=function(t){this.waypoints.push(t)},i.prototype.clearTriggerQueues=function(){this.triggerQueues={up:[],down:[],left:[],right:[]}},i.prototype.flushTriggers=function(){for(var i in this.triggerQueues){var o=this.triggerQueues[i],n="up"===i||"left"===i;o.sort(n?e:t);for(var r=0,s=o.length;s>r;r+=1){var a=o[r];(a.options.continuous||r===o.length-1)&&a.trigger([i])}}this.clearTriggerQueues()},i.prototype.next=function(e){this.waypoints.sort(t);var i=n.Adapter.inArray(e,this.waypoints),o=i===this.waypoints.length-1;return o?null:this.waypoints[i+1]},i.prototype.previous=function(e){this.waypoints.sort(t);var i=n.Adapter.inArray(e,this.waypoints);return i?this.waypoints[i-1]:null},i.prototype.queueTrigger=function(t,e){this.triggerQueues[e].push(t)},i.prototype.remove=function(t){var e=n.Adapter.inArray(t,this.waypoints);e>-1&&this.waypoints.splice(e,1)},i.prototype.first=function(){return this.waypoints[0]},i.prototype.last=function(){return this.waypoints[this.waypoints.length-1]},i.findOrCreate=function(t){return o[t.axis][t.name]||new i(t)},n.Group=i}(),function(){"use strict";function t(t){this.$element=e(t)}var e=window.jQuery,i=window.Waypoint;e.each(["innerHeight","innerWidth","off","offset","on","outerHeight","outerWidth","scrollLeft","scrollTop"],function(e,i){t.prototype[i]=function(){var t=Array.prototype.slice.call(arguments);return this.$element[i].apply(this.$element,t)}}),e.each(["extend","inArray","isEmptyObject"],function(i,o){t[o]=e[o]}),i.adapters.push({name:"jquery",Adapter:t}),i.Adapter=t}(),function(){"use strict";function t(t){return function(){var i=[],o=arguments[0];return t.isFunction(arguments[0])&&(o=t.extend({},arguments[1]),o.handler=arguments[0]),this.each(function(){var n=t.extend({},o,{element:this});"string"==typeof n.context&&(n.context=t(this).closest(n.context)[0]),i.push(new e(n))}),i}}var e=window.Waypoint;window.jQuery&&(window.jQuery.fn.waypoint=t(window.jQuery)),window.Zepto&&(window.Zepto.fn.waypoint=t(window.Zepto))}();
--------------------------------------------------------------------------------
/lib/noframework.waypoints.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | Waypoints - 4.0.1
3 | Copyright © 2011-2016 Caleb Troughton
4 | Licensed under the MIT license.
5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
6 | */
7 | !function(){"use strict";function t(n){if(!n)throw new Error("No options passed to Waypoint constructor");if(!n.element)throw new Error("No element option passed to Waypoint constructor");if(!n.handler)throw new Error("No handler option passed to Waypoint constructor");this.key="waypoint-"+e,this.options=t.Adapter.extend({},t.defaults,n),this.element=this.options.element,this.adapter=new t.Adapter(this.element),this.callback=n.handler,this.axis=this.options.horizontal?"horizontal":"vertical",this.enabled=this.options.enabled,this.triggerPoint=null,this.group=t.Group.findOrCreate({name:this.options.group,axis:this.axis}),this.context=t.Context.findOrCreateByElement(this.options.context),t.offsetAliases[this.options.offset]&&(this.options.offset=t.offsetAliases[this.options.offset]),this.group.add(this),this.context.add(this),i[this.key]=this,e+=1}var e=0,i={};t.prototype.queueTrigger=function(t){this.group.queueTrigger(this,t)},t.prototype.trigger=function(t){this.enabled&&this.callback&&this.callback.apply(this,t)},t.prototype.destroy=function(){this.context.remove(this),this.group.remove(this),delete i[this.key]},t.prototype.disable=function(){return this.enabled=!1,this},t.prototype.enable=function(){return this.context.refresh(),this.enabled=!0,this},t.prototype.next=function(){return this.group.next(this)},t.prototype.previous=function(){return this.group.previous(this)},t.invokeAll=function(t){var e=[];for(var n in i)e.push(i[n]);for(var o=0,r=e.length;r>o;o++)e[o][t]()},t.destroyAll=function(){t.invokeAll("destroy")},t.disableAll=function(){t.invokeAll("disable")},t.enableAll=function(){t.Context.refreshAll();for(var e in i)i[e].enabled=!0;return this},t.refreshAll=function(){t.Context.refreshAll()},t.viewportHeight=function(){return window.innerHeight||document.documentElement.clientHeight},t.viewportWidth=function(){return document.documentElement.clientWidth},t.adapters=[],t.defaults={context:window,continuous:!0,enabled:!0,group:"default",horizontal:!1,offset:0},t.offsetAliases={"bottom-in-view":function(){return this.context.innerHeight()-this.adapter.outerHeight()},"right-in-view":function(){return this.context.innerWidth()-this.adapter.outerWidth()}},window.Waypoint=t}(),function(){"use strict";function t(t){window.setTimeout(t,1e3/60)}function e(t){this.element=t,this.Adapter=o.Adapter,this.adapter=new this.Adapter(t),this.key="waypoint-context-"+i,this.didScroll=!1,this.didResize=!1,this.oldScroll={x:this.adapter.scrollLeft(),y:this.adapter.scrollTop()},this.waypoints={vertical:{},horizontal:{}},t.waypointContextKey=this.key,n[t.waypointContextKey]=this,i+=1,o.windowContext||(o.windowContext=!0,o.windowContext=new e(window)),this.createThrottledScrollHandler(),this.createThrottledResizeHandler()}var i=0,n={},o=window.Waypoint,r=window.onload;e.prototype.add=function(t){var e=t.options.horizontal?"horizontal":"vertical";this.waypoints[e][t.key]=t,this.refresh()},e.prototype.checkEmpty=function(){var t=this.Adapter.isEmptyObject(this.waypoints.horizontal),e=this.Adapter.isEmptyObject(this.waypoints.vertical),i=this.element==this.element.window;t&&e&&!i&&(this.adapter.off(".waypoints"),delete n[this.key])},e.prototype.createThrottledResizeHandler=function(){function t(){e.handleResize(),e.didResize=!1}var e=this;this.adapter.on("resize.waypoints",function(){e.didResize||(e.didResize=!0,o.requestAnimationFrame(t))})},e.prototype.createThrottledScrollHandler=function(){function t(){e.handleScroll(),e.didScroll=!1}var e=this;this.adapter.on("scroll.waypoints",function(){(!e.didScroll||o.isTouch)&&(e.didScroll=!0,o.requestAnimationFrame(t))})},e.prototype.handleResize=function(){o.Context.refreshAll()},e.prototype.handleScroll=function(){var t={},e={horizontal:{newScroll:this.adapter.scrollLeft(),oldScroll:this.oldScroll.x,forward:"right",backward:"left"},vertical:{newScroll:this.adapter.scrollTop(),oldScroll:this.oldScroll.y,forward:"down",backward:"up"}};for(var i in e){var n=e[i],o=n.newScroll>n.oldScroll,r=o?n.forward:n.backward;for(var s in this.waypoints[i]){var l=this.waypoints[i][s];if(null!==l.triggerPoint){var a=n.oldScroll=l.triggerPoint,p=a&&h,u=!a&&!h;(p||u)&&(l.queueTrigger(r),t[l.group.id]=l.group)}}}for(var d in t)t[d].flushTriggers();this.oldScroll={x:e.horizontal.newScroll,y:e.vertical.newScroll}},e.prototype.innerHeight=function(){return this.element==this.element.window?o.viewportHeight():this.adapter.innerHeight()},e.prototype.remove=function(t){delete this.waypoints[t.axis][t.key],this.checkEmpty()},e.prototype.innerWidth=function(){return this.element==this.element.window?o.viewportWidth():this.adapter.innerWidth()},e.prototype.destroy=function(){var t=[];for(var e in this.waypoints)for(var i in this.waypoints[e])t.push(this.waypoints[e][i]);for(var n=0,o=t.length;o>n;n++)t[n].destroy()},e.prototype.refresh=function(){var t,e=this.element==this.element.window,i=e?void 0:this.adapter.offset(),n={};this.handleScroll(),t={horizontal:{contextOffset:e?0:i.left,contextScroll:e?0:this.oldScroll.x,contextDimension:this.innerWidth(),oldScroll:this.oldScroll.x,forward:"right",backward:"left",offsetProp:"left"},vertical:{contextOffset:e?0:i.top,contextScroll:e?0:this.oldScroll.y,contextDimension:this.innerHeight(),oldScroll:this.oldScroll.y,forward:"down",backward:"up",offsetProp:"top"}};for(var r in t){var s=t[r];for(var l in this.waypoints[r]){var a,h,p,u,d,f=this.waypoints[r][l],c=f.options.offset,w=f.triggerPoint,y=0,g=null==w;f.element!==f.element.window&&(y=f.adapter.offset()[s.offsetProp]),"function"==typeof c?c=c.apply(f):"string"==typeof c&&(c=parseFloat(c),f.options.offset.indexOf("%")>-1&&(c=Math.ceil(s.contextDimension*c/100))),a=s.contextScroll-s.contextOffset,f.triggerPoint=Math.floor(y+a-c),h=w=s.oldScroll,u=h&&p,d=!h&&!p,!g&&u?(f.queueTrigger(s.backward),n[f.group.id]=f.group):!g&&d?(f.queueTrigger(s.forward),n[f.group.id]=f.group):g&&s.oldScroll>=f.triggerPoint&&(f.queueTrigger(s.forward),n[f.group.id]=f.group)}}return o.requestAnimationFrame(function(){for(var t in n)n[t].flushTriggers()}),this},e.findOrCreateByElement=function(t){return e.findByElement(t)||new e(t)},e.refreshAll=function(){for(var t in n)n[t].refresh()},e.findByElement=function(t){return n[t.waypointContextKey]},window.onload=function(){r&&r(),e.refreshAll()},o.requestAnimationFrame=function(e){var i=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||t;i.call(window,e)},o.Context=e}(),function(){"use strict";function t(t,e){return t.triggerPoint-e.triggerPoint}function e(t,e){return e.triggerPoint-t.triggerPoint}function i(t){this.name=t.name,this.axis=t.axis,this.id=this.name+"-"+this.axis,this.waypoints=[],this.clearTriggerQueues(),n[this.axis][this.name]=this}var n={vertical:{},horizontal:{}},o=window.Waypoint;i.prototype.add=function(t){this.waypoints.push(t)},i.prototype.clearTriggerQueues=function(){this.triggerQueues={up:[],down:[],left:[],right:[]}},i.prototype.flushTriggers=function(){for(var i in this.triggerQueues){var n=this.triggerQueues[i],o="up"===i||"left"===i;n.sort(o?e:t);for(var r=0,s=n.length;s>r;r+=1){var l=n[r];(l.options.continuous||r===n.length-1)&&l.trigger([i])}}this.clearTriggerQueues()},i.prototype.next=function(e){this.waypoints.sort(t);var i=o.Adapter.inArray(e,this.waypoints),n=i===this.waypoints.length-1;return n?null:this.waypoints[i+1]},i.prototype.previous=function(e){this.waypoints.sort(t);var i=o.Adapter.inArray(e,this.waypoints);return i?this.waypoints[i-1]:null},i.prototype.queueTrigger=function(t,e){this.triggerQueues[e].push(t)},i.prototype.remove=function(t){var e=o.Adapter.inArray(t,this.waypoints);e>-1&&this.waypoints.splice(e,1)},i.prototype.first=function(){return this.waypoints[0]},i.prototype.last=function(){return this.waypoints[this.waypoints.length-1]},i.findOrCreate=function(t){return n[t.axis][t.name]||new i(t)},o.Group=i}(),function(){"use strict";function t(t){return t===t.window}function e(e){return t(e)?e:e.defaultView}function i(t){this.element=t,this.handlers={}}var n=window.Waypoint;i.prototype.innerHeight=function(){var e=t(this.element);return e?this.element.innerHeight:this.element.clientHeight},i.prototype.innerWidth=function(){var e=t(this.element);return e?this.element.innerWidth:this.element.clientWidth},i.prototype.off=function(t,e){function i(t,e,i){for(var n=0,o=e.length-1;o>n;n++){var r=e[n];i&&i!==r||t.removeEventListener(r)}}var n=t.split("."),o=n[0],r=n[1],s=this.element;if(r&&this.handlers[r]&&o)i(s,this.handlers[r][o],e),this.handlers[r][o]=[];else if(o)for(var l in this.handlers)i(s,this.handlers[l][o]||[],e),this.handlers[l][o]=[];else if(r&&this.handlers[r]){for(var a in this.handlers[r])i(s,this.handlers[r][a],e);this.handlers[r]={}}},i.prototype.offset=function(){if(!this.element.ownerDocument)return null;var t=this.element.ownerDocument.documentElement,i=e(this.element.ownerDocument),n={top:0,left:0};return this.element.getBoundingClientRect&&(n=this.element.getBoundingClientRect()),{top:n.top+i.pageYOffset-t.clientTop,left:n.left+i.pageXOffset-t.clientLeft}},i.prototype.on=function(t,e){var i=t.split("."),n=i[0],o=i[1]||"__default",r=this.handlers[o]=this.handlers[o]||{},s=r[n]=r[n]||[];s.push(e),this.element.addEventListener(n,e)},i.prototype.outerHeight=function(e){var i,n=this.innerHeight();return e&&!t(this.element)&&(i=window.getComputedStyle(this.element),n+=parseInt(i.marginTop,10),n+=parseInt(i.marginBottom,10)),n},i.prototype.outerWidth=function(e){var i,n=this.innerWidth();return e&&!t(this.element)&&(i=window.getComputedStyle(this.element),n+=parseInt(i.marginLeft,10),n+=parseInt(i.marginRight,10)),n},i.prototype.scrollLeft=function(){var t=e(this.element);return t?t.pageXOffset:this.element.scrollLeft},i.prototype.scrollTop=function(){var t=e(this.element);return t?t.pageYOffset:this.element.scrollTop},i.extend=function(){function t(t,e){if("object"==typeof t&&"object"==typeof e)for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}for(var e=Array.prototype.slice.call(arguments),i=1,n=e.length;n>i;i++)t(e[0],e[i]);return e[0]},i.inArray=function(t,e,i){return null==e?-1:e.indexOf(t,i)},i.isEmptyObject=function(t){for(var e in t)return!1;return!0},n.adapters.push({name:"noframework",Adapter:i}),n.Adapter=i}();
--------------------------------------------------------------------------------
/lib/shortcuts/infinite.js:
--------------------------------------------------------------------------------
1 | /*!
2 | Waypoints Infinite Scroll Shortcut - 4.0.1
3 | Copyright © 2011-2016 Caleb Troughton
4 | Licensed under the MIT license.
5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
6 | */
7 | (function() {
8 | 'use strict'
9 |
10 | var $ = window.jQuery
11 | var Waypoint = window.Waypoint
12 |
13 | /* http://imakewebthings.com/waypoints/shortcuts/infinite-scroll */
14 | function Infinite(options) {
15 | this.options = $.extend({}, Infinite.defaults, options)
16 | this.container = this.options.element
17 | if (this.options.container !== 'auto') {
18 | this.container = this.options.container
19 | }
20 | this.$container = $(this.container)
21 | this.$more = $(this.options.more)
22 |
23 | if (this.$more.length) {
24 | this.setupHandler()
25 | this.waypoint = new Waypoint(this.options)
26 | }
27 | }
28 |
29 | /* Private */
30 | Infinite.prototype.setupHandler = function() {
31 | this.options.handler = $.proxy(function() {
32 | this.options.onBeforePageLoad()
33 | this.destroy()
34 | this.$container.addClass(this.options.loadingClass)
35 |
36 | $.get($(this.options.more).attr('href'), $.proxy(function(data) {
37 | var $data = $($.parseHTML(data))
38 | var $newMore = $data.find(this.options.more)
39 |
40 | var $items = $data.find(this.options.items)
41 | if (!$items.length) {
42 | $items = $data.filter(this.options.items)
43 | }
44 |
45 | this.$container.append($items)
46 | this.$container.removeClass(this.options.loadingClass)
47 |
48 | if (!$newMore.length) {
49 | $newMore = $data.filter(this.options.more)
50 | }
51 | if ($newMore.length) {
52 | this.$more.replaceWith($newMore)
53 | this.$more = $newMore
54 | this.waypoint = new Waypoint(this.options)
55 | }
56 | else {
57 | this.$more.remove()
58 | }
59 |
60 | this.options.onAfterPageLoad($items)
61 | }, this))
62 | }, this)
63 | }
64 |
65 | /* Public */
66 | Infinite.prototype.destroy = function() {
67 | if (this.waypoint) {
68 | this.waypoint.destroy()
69 | }
70 | }
71 |
72 | Infinite.defaults = {
73 | container: 'auto',
74 | items: '.infinite-item',
75 | more: '.infinite-more-link',
76 | offset: 'bottom-in-view',
77 | loadingClass: 'infinite-loading',
78 | onBeforePageLoad: $.noop,
79 | onAfterPageLoad: $.noop
80 | }
81 |
82 | Waypoint.Infinite = Infinite
83 | }())
84 | ;
--------------------------------------------------------------------------------
/lib/shortcuts/infinite.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | Waypoints Infinite Scroll Shortcut - 4.0.1
3 | Copyright © 2011-2016 Caleb Troughton
4 | Licensed under the MIT license.
5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
6 | */
7 | !function(){"use strict";function t(n){this.options=i.extend({},t.defaults,n),this.container=this.options.element,"auto"!==this.options.container&&(this.container=this.options.container),this.$container=i(this.container),this.$more=i(this.options.more),this.$more.length&&(this.setupHandler(),this.waypoint=new o(this.options))}var i=window.jQuery,o=window.Waypoint;t.prototype.setupHandler=function(){this.options.handler=i.proxy(function(){this.options.onBeforePageLoad(),this.destroy(),this.$container.addClass(this.options.loadingClass),i.get(i(this.options.more).attr("href"),i.proxy(function(t){var n=i(i.parseHTML(t)),e=n.find(this.options.more),s=n.find(this.options.items);s.length||(s=n.filter(this.options.items)),this.$container.append(s),this.$container.removeClass(this.options.loadingClass),e.length||(e=n.filter(this.options.more)),e.length?(this.$more.replaceWith(e),this.$more=e,this.waypoint=new o(this.options)):this.$more.remove(),this.options.onAfterPageLoad(s)},this))},this)},t.prototype.destroy=function(){this.waypoint&&this.waypoint.destroy()},t.defaults={container:"auto",items:".infinite-item",more:".infinite-more-link",offset:"bottom-in-view",loadingClass:"infinite-loading",onBeforePageLoad:i.noop,onAfterPageLoad:i.noop},o.Infinite=t}();
--------------------------------------------------------------------------------
/lib/shortcuts/inview.js:
--------------------------------------------------------------------------------
1 | /*!
2 | Waypoints Inview Shortcut - 4.0.1
3 | Copyright © 2011-2016 Caleb Troughton
4 | Licensed under the MIT license.
5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
6 | */
7 | (function() {
8 | 'use strict'
9 |
10 | function noop() {}
11 |
12 | var Waypoint = window.Waypoint
13 |
14 | /* http://imakewebthings.com/waypoints/shortcuts/inview */
15 | function Inview(options) {
16 | this.options = Waypoint.Adapter.extend({}, Inview.defaults, options)
17 | this.axis = this.options.horizontal ? 'horizontal' : 'vertical'
18 | this.waypoints = []
19 | this.element = this.options.element
20 | this.createWaypoints()
21 | }
22 |
23 | /* Private */
24 | Inview.prototype.createWaypoints = function() {
25 | var configs = {
26 | vertical: [{
27 | down: 'enter',
28 | up: 'exited',
29 | offset: '100%'
30 | }, {
31 | down: 'entered',
32 | up: 'exit',
33 | offset: 'bottom-in-view'
34 | }, {
35 | down: 'exit',
36 | up: 'entered',
37 | offset: 0
38 | }, {
39 | down: 'exited',
40 | up: 'enter',
41 | offset: function() {
42 | return -this.adapter.outerHeight()
43 | }
44 | }],
45 | horizontal: [{
46 | right: 'enter',
47 | left: 'exited',
48 | offset: '100%'
49 | }, {
50 | right: 'entered',
51 | left: 'exit',
52 | offset: 'right-in-view'
53 | }, {
54 | right: 'exit',
55 | left: 'entered',
56 | offset: 0
57 | }, {
58 | right: 'exited',
59 | left: 'enter',
60 | offset: function() {
61 | return -this.adapter.outerWidth()
62 | }
63 | }]
64 | }
65 |
66 | for (var i = 0, end = configs[this.axis].length; i < end; i++) {
67 | var config = configs[this.axis][i]
68 | this.createWaypoint(config)
69 | }
70 | }
71 |
72 | /* Private */
73 | Inview.prototype.createWaypoint = function(config) {
74 | var self = this
75 | this.waypoints.push(new Waypoint({
76 | context: this.options.context,
77 | element: this.options.element,
78 | enabled: this.options.enabled,
79 | handler: (function(config) {
80 | return function(direction) {
81 | self.options[config[direction]].call(self, direction)
82 | }
83 | }(config)),
84 | offset: config.offset,
85 | horizontal: this.options.horizontal
86 | }))
87 | }
88 |
89 | /* Public */
90 | Inview.prototype.destroy = function() {
91 | for (var i = 0, end = this.waypoints.length; i < end; i++) {
92 | this.waypoints[i].destroy()
93 | }
94 | this.waypoints = []
95 | }
96 |
97 | Inview.prototype.disable = function() {
98 | for (var i = 0, end = this.waypoints.length; i < end; i++) {
99 | this.waypoints[i].disable()
100 | }
101 | }
102 |
103 | Inview.prototype.enable = function() {
104 | for (var i = 0, end = this.waypoints.length; i < end; i++) {
105 | this.waypoints[i].enable()
106 | }
107 | }
108 |
109 | Inview.defaults = {
110 | context: window,
111 | enabled: true,
112 | enter: noop,
113 | entered: noop,
114 | exit: noop,
115 | exited: noop
116 | }
117 |
118 | Waypoint.Inview = Inview
119 | }())
120 | ;
--------------------------------------------------------------------------------
/lib/shortcuts/inview.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | Waypoints Inview Shortcut - 4.0.1
3 | Copyright © 2011-2016 Caleb Troughton
4 | Licensed under the MIT license.
5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
6 | */
7 | !function(){"use strict";function t(){}function e(t){this.options=i.Adapter.extend({},e.defaults,t),this.axis=this.options.horizontal?"horizontal":"vertical",this.waypoints=[],this.element=this.options.element,this.createWaypoints()}var i=window.Waypoint;e.prototype.createWaypoints=function(){for(var t={vertical:[{down:"enter",up:"exited",offset:"100%"},{down:"entered",up:"exit",offset:"bottom-in-view"},{down:"exit",up:"entered",offset:0},{down:"exited",up:"enter",offset:function(){return-this.adapter.outerHeight()}}],horizontal:[{right:"enter",left:"exited",offset:"100%"},{right:"entered",left:"exit",offset:"right-in-view"},{right:"exit",left:"entered",offset:0},{right:"exited",left:"enter",offset:function(){return-this.adapter.outerWidth()}}]},e=0,i=t[this.axis].length;i>e;e++){var n=t[this.axis][e];this.createWaypoint(n)}},e.prototype.createWaypoint=function(t){var e=this;this.waypoints.push(new i({context:this.options.context,element:this.options.element,enabled:this.options.enabled,handler:function(t){return function(i){e.options[t[i]].call(e,i)}}(t),offset:t.offset,horizontal:this.options.horizontal}))},e.prototype.destroy=function(){for(var t=0,e=this.waypoints.length;e>t;t++)this.waypoints[t].destroy();this.waypoints=[]},e.prototype.disable=function(){for(var t=0,e=this.waypoints.length;e>t;t++)this.waypoints[t].disable()},e.prototype.enable=function(){for(var t=0,e=this.waypoints.length;e>t;t++)this.waypoints[t].enable()},e.defaults={context:window,enabled:!0,enter:t,entered:t,exit:t,exited:t},i.Inview=e}();
--------------------------------------------------------------------------------
/lib/shortcuts/sticky.js:
--------------------------------------------------------------------------------
1 | /*!
2 | Waypoints Sticky Element Shortcut - 4.0.1
3 | Copyright © 2011-2016 Caleb Troughton
4 | Licensed under the MIT license.
5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
6 | */
7 | (function() {
8 | 'use strict'
9 |
10 | var $ = window.jQuery
11 | var Waypoint = window.Waypoint
12 |
13 | /* http://imakewebthings.com/waypoints/shortcuts/sticky-elements */
14 | function Sticky(options) {
15 | this.options = $.extend({}, Waypoint.defaults, Sticky.defaults, options)
16 | this.element = this.options.element
17 | this.$element = $(this.element)
18 | this.createWrapper()
19 | this.createWaypoint()
20 | }
21 |
22 | /* Private */
23 | Sticky.prototype.createWaypoint = function() {
24 | var originalHandler = this.options.handler
25 |
26 | this.waypoint = new Waypoint($.extend({}, this.options, {
27 | element: this.wrapper,
28 | handler: $.proxy(function(direction) {
29 | var shouldBeStuck = this.options.direction.indexOf(direction) > -1
30 | var wrapperHeight = shouldBeStuck ? this.$element.outerHeight(true) : ''
31 |
32 | this.$wrapper.height(wrapperHeight)
33 | this.$element.toggleClass(this.options.stuckClass, shouldBeStuck)
34 |
35 | if (originalHandler) {
36 | originalHandler.call(this, direction)
37 | }
38 | }, this)
39 | }))
40 | }
41 |
42 | /* Private */
43 | Sticky.prototype.createWrapper = function() {
44 | if (this.options.wrapper) {
45 | this.$element.wrap(this.options.wrapper)
46 | }
47 | this.$wrapper = this.$element.parent()
48 | this.wrapper = this.$wrapper[0]
49 | }
50 |
51 | /* Public */
52 | Sticky.prototype.destroy = function() {
53 | if (this.$element.parent()[0] === this.wrapper) {
54 | this.waypoint.destroy()
55 | this.$element.removeClass(this.options.stuckClass)
56 | if (this.options.wrapper) {
57 | this.$element.unwrap()
58 | }
59 | }
60 | }
61 |
62 | Sticky.defaults = {
63 | wrapper: '',
64 | stuckClass: 'stuck',
65 | direction: 'down right'
66 | }
67 |
68 | Waypoint.Sticky = Sticky
69 | }())
70 | ;
--------------------------------------------------------------------------------
/lib/shortcuts/sticky.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | Waypoints Sticky Element Shortcut - 4.0.1
3 | Copyright © 2011-2016 Caleb Troughton
4 | Licensed under the MIT license.
5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
6 | */
7 | !function(){"use strict";function t(s){this.options=e.extend({},i.defaults,t.defaults,s),this.element=this.options.element,this.$element=e(this.element),this.createWrapper(),this.createWaypoint()}var e=window.jQuery,i=window.Waypoint;t.prototype.createWaypoint=function(){var t=this.options.handler;this.waypoint=new i(e.extend({},this.options,{element:this.wrapper,handler:e.proxy(function(e){var i=this.options.direction.indexOf(e)>-1,s=i?this.$element.outerHeight(!0):"";this.$wrapper.height(s),this.$element.toggleClass(this.options.stuckClass,i),t&&t.call(this,e)},this)}))},t.prototype.createWrapper=function(){this.options.wrapper&&this.$element.wrap(this.options.wrapper),this.$wrapper=this.$element.parent(),this.wrapper=this.$wrapper[0]},t.prototype.destroy=function(){this.$element.parent()[0]===this.wrapper&&(this.waypoint.destroy(),this.$element.removeClass(this.options.stuckClass),this.options.wrapper&&this.$element.unwrap())},t.defaults={wrapper:'',stuckClass:"stuck",direction:"down right"},i.Sticky=t}();
--------------------------------------------------------------------------------
/lib/waypoints.debug.js:
--------------------------------------------------------------------------------
1 | /*!
2 | Waypoints Debug - 4.0.1
3 | Copyright © 2011-2016 Caleb Troughton
4 | Licensed under the MIT license.
5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
6 | */
7 | (function() {
8 | 'use strict'
9 |
10 | var displayNoneMessage = [
11 | 'You have a Waypoint element with display none. For more information on ',
12 | 'why this is a bad idea read ',
13 | 'http://imakewebthings.com/waypoints/guides/debugging/#display-none'
14 | ].join('')
15 | var fixedMessage = [
16 | 'You have a Waypoint element with fixed positioning. For more ',
17 | 'information on why this is a bad idea read ',
18 | 'http://imakewebthings.com/waypoints/guides/debugging/#fixed-position'
19 | ].join('')
20 |
21 | function checkWaypointStyles() {
22 | var originalRefresh = window.Waypoint.Context.prototype.refresh
23 |
24 | window.Waypoint.Context.prototype.refresh = function() {
25 | for (var axis in this.waypoints) {
26 | for (var key in this.waypoints[axis]) {
27 | var waypoint = this.waypoints[axis][key]
28 | var style = window.getComputedStyle(waypoint.element)
29 | if (!waypoint.enabled) {
30 | continue
31 | }
32 | if (style && style.display === 'none') {
33 | console.error(displayNoneMessage)
34 | }
35 | if (style && style.position === 'fixed') {
36 | console.error(fixedMessage)
37 | }
38 | }
39 | }
40 | return originalRefresh.call(this)
41 | }
42 | }
43 |
44 | checkWaypointStyles()
45 | }())
46 | ;
--------------------------------------------------------------------------------
/lib/zepto.waypoints.js:
--------------------------------------------------------------------------------
1 | /*!
2 | Waypoints - 4.0.1
3 | Copyright © 2011-2016 Caleb Troughton
4 | Licensed under the MIT license.
5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
6 | */
7 | (function() {
8 | 'use strict'
9 |
10 | var keyCounter = 0
11 | var allWaypoints = {}
12 |
13 | /* http://imakewebthings.com/waypoints/api/waypoint */
14 | function Waypoint(options) {
15 | if (!options) {
16 | throw new Error('No options passed to Waypoint constructor')
17 | }
18 | if (!options.element) {
19 | throw new Error('No element option passed to Waypoint constructor')
20 | }
21 | if (!options.handler) {
22 | throw new Error('No handler option passed to Waypoint constructor')
23 | }
24 |
25 | this.key = 'waypoint-' + keyCounter
26 | this.options = Waypoint.Adapter.extend({}, Waypoint.defaults, options)
27 | this.element = this.options.element
28 | this.adapter = new Waypoint.Adapter(this.element)
29 | this.callback = options.handler
30 | this.axis = this.options.horizontal ? 'horizontal' : 'vertical'
31 | this.enabled = this.options.enabled
32 | this.triggerPoint = null
33 | this.group = Waypoint.Group.findOrCreate({
34 | name: this.options.group,
35 | axis: this.axis
36 | })
37 | this.context = Waypoint.Context.findOrCreateByElement(this.options.context)
38 |
39 | if (Waypoint.offsetAliases[this.options.offset]) {
40 | this.options.offset = Waypoint.offsetAliases[this.options.offset]
41 | }
42 | this.group.add(this)
43 | this.context.add(this)
44 | allWaypoints[this.key] = this
45 | keyCounter += 1
46 | }
47 |
48 | /* Private */
49 | Waypoint.prototype.queueTrigger = function(direction) {
50 | this.group.queueTrigger(this, direction)
51 | }
52 |
53 | /* Private */
54 | Waypoint.prototype.trigger = function(args) {
55 | if (!this.enabled) {
56 | return
57 | }
58 | if (this.callback) {
59 | this.callback.apply(this, args)
60 | }
61 | }
62 |
63 | /* Public */
64 | /* http://imakewebthings.com/waypoints/api/destroy */
65 | Waypoint.prototype.destroy = function() {
66 | this.context.remove(this)
67 | this.group.remove(this)
68 | delete allWaypoints[this.key]
69 | }
70 |
71 | /* Public */
72 | /* http://imakewebthings.com/waypoints/api/disable */
73 | Waypoint.prototype.disable = function() {
74 | this.enabled = false
75 | return this
76 | }
77 |
78 | /* Public */
79 | /* http://imakewebthings.com/waypoints/api/enable */
80 | Waypoint.prototype.enable = function() {
81 | this.context.refresh()
82 | this.enabled = true
83 | return this
84 | }
85 |
86 | /* Public */
87 | /* http://imakewebthings.com/waypoints/api/next */
88 | Waypoint.prototype.next = function() {
89 | return this.group.next(this)
90 | }
91 |
92 | /* Public */
93 | /* http://imakewebthings.com/waypoints/api/previous */
94 | Waypoint.prototype.previous = function() {
95 | return this.group.previous(this)
96 | }
97 |
98 | /* Private */
99 | Waypoint.invokeAll = function(method) {
100 | var allWaypointsArray = []
101 | for (var waypointKey in allWaypoints) {
102 | allWaypointsArray.push(allWaypoints[waypointKey])
103 | }
104 | for (var i = 0, end = allWaypointsArray.length; i < end; i++) {
105 | allWaypointsArray[i][method]()
106 | }
107 | }
108 |
109 | /* Public */
110 | /* http://imakewebthings.com/waypoints/api/destroy-all */
111 | Waypoint.destroyAll = function() {
112 | Waypoint.invokeAll('destroy')
113 | }
114 |
115 | /* Public */
116 | /* http://imakewebthings.com/waypoints/api/disable-all */
117 | Waypoint.disableAll = function() {
118 | Waypoint.invokeAll('disable')
119 | }
120 |
121 | /* Public */
122 | /* http://imakewebthings.com/waypoints/api/enable-all */
123 | Waypoint.enableAll = function() {
124 | Waypoint.Context.refreshAll()
125 | for (var waypointKey in allWaypoints) {
126 | allWaypoints[waypointKey].enabled = true
127 | }
128 | return this
129 | }
130 |
131 | /* Public */
132 | /* http://imakewebthings.com/waypoints/api/refresh-all */
133 | Waypoint.refreshAll = function() {
134 | Waypoint.Context.refreshAll()
135 | }
136 |
137 | /* Public */
138 | /* http://imakewebthings.com/waypoints/api/viewport-height */
139 | Waypoint.viewportHeight = function() {
140 | return window.innerHeight || document.documentElement.clientHeight
141 | }
142 |
143 | /* Public */
144 | /* http://imakewebthings.com/waypoints/api/viewport-width */
145 | Waypoint.viewportWidth = function() {
146 | return document.documentElement.clientWidth
147 | }
148 |
149 | Waypoint.adapters = []
150 |
151 | Waypoint.defaults = {
152 | context: window,
153 | continuous: true,
154 | enabled: true,
155 | group: 'default',
156 | horizontal: false,
157 | offset: 0
158 | }
159 |
160 | Waypoint.offsetAliases = {
161 | 'bottom-in-view': function() {
162 | return this.context.innerHeight() - this.adapter.outerHeight()
163 | },
164 | 'right-in-view': function() {
165 | return this.context.innerWidth() - this.adapter.outerWidth()
166 | }
167 | }
168 |
169 | window.Waypoint = Waypoint
170 | }())
171 | ;(function() {
172 | 'use strict'
173 |
174 | function requestAnimationFrameShim(callback) {
175 | window.setTimeout(callback, 1000 / 60)
176 | }
177 |
178 | var keyCounter = 0
179 | var contexts = {}
180 | var Waypoint = window.Waypoint
181 | var oldWindowLoad = window.onload
182 |
183 | /* http://imakewebthings.com/waypoints/api/context */
184 | function Context(element) {
185 | this.element = element
186 | this.Adapter = Waypoint.Adapter
187 | this.adapter = new this.Adapter(element)
188 | this.key = 'waypoint-context-' + keyCounter
189 | this.didScroll = false
190 | this.didResize = false
191 | this.oldScroll = {
192 | x: this.adapter.scrollLeft(),
193 | y: this.adapter.scrollTop()
194 | }
195 | this.waypoints = {
196 | vertical: {},
197 | horizontal: {}
198 | }
199 |
200 | element.waypointContextKey = this.key
201 | contexts[element.waypointContextKey] = this
202 | keyCounter += 1
203 | if (!Waypoint.windowContext) {
204 | Waypoint.windowContext = true
205 | Waypoint.windowContext = new Context(window)
206 | }
207 |
208 | this.createThrottledScrollHandler()
209 | this.createThrottledResizeHandler()
210 | }
211 |
212 | /* Private */
213 | Context.prototype.add = function(waypoint) {
214 | var axis = waypoint.options.horizontal ? 'horizontal' : 'vertical'
215 | this.waypoints[axis][waypoint.key] = waypoint
216 | this.refresh()
217 | }
218 |
219 | /* Private */
220 | Context.prototype.checkEmpty = function() {
221 | var horizontalEmpty = this.Adapter.isEmptyObject(this.waypoints.horizontal)
222 | var verticalEmpty = this.Adapter.isEmptyObject(this.waypoints.vertical)
223 | var isWindow = this.element == this.element.window
224 | if (horizontalEmpty && verticalEmpty && !isWindow) {
225 | this.adapter.off('.waypoints')
226 | delete contexts[this.key]
227 | }
228 | }
229 |
230 | /* Private */
231 | Context.prototype.createThrottledResizeHandler = function() {
232 | var self = this
233 |
234 | function resizeHandler() {
235 | self.handleResize()
236 | self.didResize = false
237 | }
238 |
239 | this.adapter.on('resize.waypoints', function() {
240 | if (!self.didResize) {
241 | self.didResize = true
242 | Waypoint.requestAnimationFrame(resizeHandler)
243 | }
244 | })
245 | }
246 |
247 | /* Private */
248 | Context.prototype.createThrottledScrollHandler = function() {
249 | var self = this
250 | function scrollHandler() {
251 | self.handleScroll()
252 | self.didScroll = false
253 | }
254 |
255 | this.adapter.on('scroll.waypoints', function() {
256 | if (!self.didScroll || Waypoint.isTouch) {
257 | self.didScroll = true
258 | Waypoint.requestAnimationFrame(scrollHandler)
259 | }
260 | })
261 | }
262 |
263 | /* Private */
264 | Context.prototype.handleResize = function() {
265 | Waypoint.Context.refreshAll()
266 | }
267 |
268 | /* Private */
269 | Context.prototype.handleScroll = function() {
270 | var triggeredGroups = {}
271 | var axes = {
272 | horizontal: {
273 | newScroll: this.adapter.scrollLeft(),
274 | oldScroll: this.oldScroll.x,
275 | forward: 'right',
276 | backward: 'left'
277 | },
278 | vertical: {
279 | newScroll: this.adapter.scrollTop(),
280 | oldScroll: this.oldScroll.y,
281 | forward: 'down',
282 | backward: 'up'
283 | }
284 | }
285 |
286 | for (var axisKey in axes) {
287 | var axis = axes[axisKey]
288 | var isForward = axis.newScroll > axis.oldScroll
289 | var direction = isForward ? axis.forward : axis.backward
290 |
291 | for (var waypointKey in this.waypoints[axisKey]) {
292 | var waypoint = this.waypoints[axisKey][waypointKey]
293 | if (waypoint.triggerPoint === null) {
294 | continue
295 | }
296 | var wasBeforeTriggerPoint = axis.oldScroll < waypoint.triggerPoint
297 | var nowAfterTriggerPoint = axis.newScroll >= waypoint.triggerPoint
298 | var crossedForward = wasBeforeTriggerPoint && nowAfterTriggerPoint
299 | var crossedBackward = !wasBeforeTriggerPoint && !nowAfterTriggerPoint
300 | if (crossedForward || crossedBackward) {
301 | waypoint.queueTrigger(direction)
302 | triggeredGroups[waypoint.group.id] = waypoint.group
303 | }
304 | }
305 | }
306 |
307 | for (var groupKey in triggeredGroups) {
308 | triggeredGroups[groupKey].flushTriggers()
309 | }
310 |
311 | this.oldScroll = {
312 | x: axes.horizontal.newScroll,
313 | y: axes.vertical.newScroll
314 | }
315 | }
316 |
317 | /* Private */
318 | Context.prototype.innerHeight = function() {
319 | /*eslint-disable eqeqeq */
320 | if (this.element == this.element.window) {
321 | return Waypoint.viewportHeight()
322 | }
323 | /*eslint-enable eqeqeq */
324 | return this.adapter.innerHeight()
325 | }
326 |
327 | /* Private */
328 | Context.prototype.remove = function(waypoint) {
329 | delete this.waypoints[waypoint.axis][waypoint.key]
330 | this.checkEmpty()
331 | }
332 |
333 | /* Private */
334 | Context.prototype.innerWidth = function() {
335 | /*eslint-disable eqeqeq */
336 | if (this.element == this.element.window) {
337 | return Waypoint.viewportWidth()
338 | }
339 | /*eslint-enable eqeqeq */
340 | return this.adapter.innerWidth()
341 | }
342 |
343 | /* Public */
344 | /* http://imakewebthings.com/waypoints/api/context-destroy */
345 | Context.prototype.destroy = function() {
346 | var allWaypoints = []
347 | for (var axis in this.waypoints) {
348 | for (var waypointKey in this.waypoints[axis]) {
349 | allWaypoints.push(this.waypoints[axis][waypointKey])
350 | }
351 | }
352 | for (var i = 0, end = allWaypoints.length; i < end; i++) {
353 | allWaypoints[i].destroy()
354 | }
355 | }
356 |
357 | /* Public */
358 | /* http://imakewebthings.com/waypoints/api/context-refresh */
359 | Context.prototype.refresh = function() {
360 | /*eslint-disable eqeqeq */
361 | var isWindow = this.element == this.element.window
362 | /*eslint-enable eqeqeq */
363 | var contextOffset = isWindow ? undefined : this.adapter.offset()
364 | var triggeredGroups = {}
365 | var axes
366 |
367 | this.handleScroll()
368 | axes = {
369 | horizontal: {
370 | contextOffset: isWindow ? 0 : contextOffset.left,
371 | contextScroll: isWindow ? 0 : this.oldScroll.x,
372 | contextDimension: this.innerWidth(),
373 | oldScroll: this.oldScroll.x,
374 | forward: 'right',
375 | backward: 'left',
376 | offsetProp: 'left'
377 | },
378 | vertical: {
379 | contextOffset: isWindow ? 0 : contextOffset.top,
380 | contextScroll: isWindow ? 0 : this.oldScroll.y,
381 | contextDimension: this.innerHeight(),
382 | oldScroll: this.oldScroll.y,
383 | forward: 'down',
384 | backward: 'up',
385 | offsetProp: 'top'
386 | }
387 | }
388 |
389 | for (var axisKey in axes) {
390 | var axis = axes[axisKey]
391 | for (var waypointKey in this.waypoints[axisKey]) {
392 | var waypoint = this.waypoints[axisKey][waypointKey]
393 | var adjustment = waypoint.options.offset
394 | var oldTriggerPoint = waypoint.triggerPoint
395 | var elementOffset = 0
396 | var freshWaypoint = oldTriggerPoint == null
397 | var contextModifier, wasBeforeScroll, nowAfterScroll
398 | var triggeredBackward, triggeredForward
399 |
400 | if (waypoint.element !== waypoint.element.window) {
401 | elementOffset = waypoint.adapter.offset()[axis.offsetProp]
402 | }
403 |
404 | if (typeof adjustment === 'function') {
405 | adjustment = adjustment.apply(waypoint)
406 | }
407 | else if (typeof adjustment === 'string') {
408 | adjustment = parseFloat(adjustment)
409 | if (waypoint.options.offset.indexOf('%') > - 1) {
410 | adjustment = Math.ceil(axis.contextDimension * adjustment / 100)
411 | }
412 | }
413 |
414 | contextModifier = axis.contextScroll - axis.contextOffset
415 | waypoint.triggerPoint = Math.floor(elementOffset + contextModifier - adjustment)
416 | wasBeforeScroll = oldTriggerPoint < axis.oldScroll
417 | nowAfterScroll = waypoint.triggerPoint >= axis.oldScroll
418 | triggeredBackward = wasBeforeScroll && nowAfterScroll
419 | triggeredForward = !wasBeforeScroll && !nowAfterScroll
420 |
421 | if (!freshWaypoint && triggeredBackward) {
422 | waypoint.queueTrigger(axis.backward)
423 | triggeredGroups[waypoint.group.id] = waypoint.group
424 | }
425 | else if (!freshWaypoint && triggeredForward) {
426 | waypoint.queueTrigger(axis.forward)
427 | triggeredGroups[waypoint.group.id] = waypoint.group
428 | }
429 | else if (freshWaypoint && axis.oldScroll >= waypoint.triggerPoint) {
430 | waypoint.queueTrigger(axis.forward)
431 | triggeredGroups[waypoint.group.id] = waypoint.group
432 | }
433 | }
434 | }
435 |
436 | Waypoint.requestAnimationFrame(function() {
437 | for (var groupKey in triggeredGroups) {
438 | triggeredGroups[groupKey].flushTriggers()
439 | }
440 | })
441 |
442 | return this
443 | }
444 |
445 | /* Private */
446 | Context.findOrCreateByElement = function(element) {
447 | return Context.findByElement(element) || new Context(element)
448 | }
449 |
450 | /* Private */
451 | Context.refreshAll = function() {
452 | for (var contextId in contexts) {
453 | contexts[contextId].refresh()
454 | }
455 | }
456 |
457 | /* Public */
458 | /* http://imakewebthings.com/waypoints/api/context-find-by-element */
459 | Context.findByElement = function(element) {
460 | return contexts[element.waypointContextKey]
461 | }
462 |
463 | window.onload = function() {
464 | if (oldWindowLoad) {
465 | oldWindowLoad()
466 | }
467 | Context.refreshAll()
468 | }
469 |
470 |
471 | Waypoint.requestAnimationFrame = function(callback) {
472 | var requestFn = window.requestAnimationFrame ||
473 | window.mozRequestAnimationFrame ||
474 | window.webkitRequestAnimationFrame ||
475 | requestAnimationFrameShim
476 | requestFn.call(window, callback)
477 | }
478 | Waypoint.Context = Context
479 | }())
480 | ;(function() {
481 | 'use strict'
482 |
483 | function byTriggerPoint(a, b) {
484 | return a.triggerPoint - b.triggerPoint
485 | }
486 |
487 | function byReverseTriggerPoint(a, b) {
488 | return b.triggerPoint - a.triggerPoint
489 | }
490 |
491 | var groups = {
492 | vertical: {},
493 | horizontal: {}
494 | }
495 | var Waypoint = window.Waypoint
496 |
497 | /* http://imakewebthings.com/waypoints/api/group */
498 | function Group(options) {
499 | this.name = options.name
500 | this.axis = options.axis
501 | this.id = this.name + '-' + this.axis
502 | this.waypoints = []
503 | this.clearTriggerQueues()
504 | groups[this.axis][this.name] = this
505 | }
506 |
507 | /* Private */
508 | Group.prototype.add = function(waypoint) {
509 | this.waypoints.push(waypoint)
510 | }
511 |
512 | /* Private */
513 | Group.prototype.clearTriggerQueues = function() {
514 | this.triggerQueues = {
515 | up: [],
516 | down: [],
517 | left: [],
518 | right: []
519 | }
520 | }
521 |
522 | /* Private */
523 | Group.prototype.flushTriggers = function() {
524 | for (var direction in this.triggerQueues) {
525 | var waypoints = this.triggerQueues[direction]
526 | var reverse = direction === 'up' || direction === 'left'
527 | waypoints.sort(reverse ? byReverseTriggerPoint : byTriggerPoint)
528 | for (var i = 0, end = waypoints.length; i < end; i += 1) {
529 | var waypoint = waypoints[i]
530 | if (waypoint.options.continuous || i === waypoints.length - 1) {
531 | waypoint.trigger([direction])
532 | }
533 | }
534 | }
535 | this.clearTriggerQueues()
536 | }
537 |
538 | /* Private */
539 | Group.prototype.next = function(waypoint) {
540 | this.waypoints.sort(byTriggerPoint)
541 | var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
542 | var isLast = index === this.waypoints.length - 1
543 | return isLast ? null : this.waypoints[index + 1]
544 | }
545 |
546 | /* Private */
547 | Group.prototype.previous = function(waypoint) {
548 | this.waypoints.sort(byTriggerPoint)
549 | var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
550 | return index ? this.waypoints[index - 1] : null
551 | }
552 |
553 | /* Private */
554 | Group.prototype.queueTrigger = function(waypoint, direction) {
555 | this.triggerQueues[direction].push(waypoint)
556 | }
557 |
558 | /* Private */
559 | Group.prototype.remove = function(waypoint) {
560 | var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
561 | if (index > -1) {
562 | this.waypoints.splice(index, 1)
563 | }
564 | }
565 |
566 | /* Public */
567 | /* http://imakewebthings.com/waypoints/api/first */
568 | Group.prototype.first = function() {
569 | return this.waypoints[0]
570 | }
571 |
572 | /* Public */
573 | /* http://imakewebthings.com/waypoints/api/last */
574 | Group.prototype.last = function() {
575 | return this.waypoints[this.waypoints.length - 1]
576 | }
577 |
578 | /* Private */
579 | Group.findOrCreate = function(options) {
580 | return groups[options.axis][options.name] || new Group(options)
581 | }
582 |
583 | Waypoint.Group = Group
584 | }())
585 | ;(function() {
586 | 'use strict'
587 |
588 | var $ = window.Zepto
589 | var Waypoint = window.Waypoint
590 |
591 | function ZeptoAdapter(element) {
592 | this.element = element
593 | this.$element = $(element)
594 | }
595 |
596 | $.each([
597 | 'off',
598 | 'on',
599 | 'scrollLeft',
600 | 'scrollTop'
601 | ], function(i, method) {
602 | ZeptoAdapter.prototype[method] = function() {
603 | var args = Array.prototype.slice.call(arguments)
604 | return this.$element[method].apply(this.$element, args)
605 | }
606 | })
607 |
608 | ZeptoAdapter.prototype.offset = function() {
609 | if (this.element !== this.element.window) {
610 | return this.$element.offset()
611 | }
612 | }
613 |
614 | // Adapted from https://gist.github.com/wheresrhys/5823198
615 | $.each([
616 | 'width',
617 | 'height'
618 | ], function(i, dimension) {
619 | function createDimensionMethod($element, includeBorder) {
620 | return function(includeMargin) {
621 | var $element = this.$element
622 | var size = $element[dimension]()
623 | var sides = {
624 | width: ['left', 'right'],
625 | height: ['top', 'bottom']
626 | }
627 |
628 | $.each(sides[dimension], function(i, side) {
629 | size += parseInt($element.css('padding-' + side), 10)
630 | if (includeBorder) {
631 | size += parseInt($element.css('border-' + side + '-width'), 10)
632 | }
633 | if (includeMargin) {
634 | size += parseInt($element.css('margin-' + side), 10)
635 | }
636 | })
637 | return size
638 | }
639 | }
640 |
641 | var innerMethod = $.camelCase('inner-' + dimension)
642 | var outerMethod = $.camelCase('outer-' + dimension)
643 |
644 | ZeptoAdapter.prototype[innerMethod] = createDimensionMethod(false)
645 | ZeptoAdapter.prototype[outerMethod] = createDimensionMethod(true)
646 | })
647 |
648 | $.each([
649 | 'extend',
650 | 'inArray'
651 | ], function(i, method) {
652 | ZeptoAdapter[method] = $[method]
653 | })
654 |
655 | ZeptoAdapter.isEmptyObject = function(obj) {
656 | /* eslint no-unused-vars: 0 */
657 | for (var name in obj) {
658 | return false
659 | }
660 | return true
661 | }
662 |
663 | Waypoint.adapters.push({
664 | name: 'zepto',
665 | Adapter: ZeptoAdapter
666 | })
667 | Waypoint.Adapter = ZeptoAdapter
668 | }())
669 | ;(function() {
670 | 'use strict'
671 |
672 | var Waypoint = window.Waypoint
673 |
674 | function createExtension(framework) {
675 | return function() {
676 | var waypoints = []
677 | var overrides = arguments[0]
678 |
679 | if (framework.isFunction(arguments[0])) {
680 | overrides = framework.extend({}, arguments[1])
681 | overrides.handler = arguments[0]
682 | }
683 |
684 | this.each(function() {
685 | var options = framework.extend({}, overrides, {
686 | element: this
687 | })
688 | if (typeof options.context === 'string') {
689 | options.context = framework(this).closest(options.context)[0]
690 | }
691 | waypoints.push(new Waypoint(options))
692 | })
693 |
694 | return waypoints
695 | }
696 | }
697 |
698 | if (window.jQuery) {
699 | window.jQuery.fn.waypoint = createExtension(window.jQuery)
700 | }
701 | if (window.Zepto) {
702 | window.Zepto.fn.waypoint = createExtension(window.Zepto)
703 | }
704 | }())
705 | ;
--------------------------------------------------------------------------------
/lib/zepto.waypoints.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | Waypoints - 4.0.1
3 | Copyright © 2011-2016 Caleb Troughton
4 | Licensed under the MIT license.
5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
6 | */
7 | !function(){"use strict";function t(o){if(!o)throw new Error("No options passed to Waypoint constructor");if(!o.element)throw new Error("No element option passed to Waypoint constructor");if(!o.handler)throw new Error("No handler option passed to Waypoint constructor");this.key="waypoint-"+e,this.options=t.Adapter.extend({},t.defaults,o),this.element=this.options.element,this.adapter=new t.Adapter(this.element),this.callback=o.handler,this.axis=this.options.horizontal?"horizontal":"vertical",this.enabled=this.options.enabled,this.triggerPoint=null,this.group=t.Group.findOrCreate({name:this.options.group,axis:this.axis}),this.context=t.Context.findOrCreateByElement(this.options.context),t.offsetAliases[this.options.offset]&&(this.options.offset=t.offsetAliases[this.options.offset]),this.group.add(this),this.context.add(this),i[this.key]=this,e+=1}var e=0,i={};t.prototype.queueTrigger=function(t){this.group.queueTrigger(this,t)},t.prototype.trigger=function(t){this.enabled&&this.callback&&this.callback.apply(this,t)},t.prototype.destroy=function(){this.context.remove(this),this.group.remove(this),delete i[this.key]},t.prototype.disable=function(){return this.enabled=!1,this},t.prototype.enable=function(){return this.context.refresh(),this.enabled=!0,this},t.prototype.next=function(){return this.group.next(this)},t.prototype.previous=function(){return this.group.previous(this)},t.invokeAll=function(t){var e=[];for(var o in i)e.push(i[o]);for(var n=0,r=e.length;r>n;n++)e[n][t]()},t.destroyAll=function(){t.invokeAll("destroy")},t.disableAll=function(){t.invokeAll("disable")},t.enableAll=function(){t.Context.refreshAll();for(var e in i)i[e].enabled=!0;return this},t.refreshAll=function(){t.Context.refreshAll()},t.viewportHeight=function(){return window.innerHeight||document.documentElement.clientHeight},t.viewportWidth=function(){return document.documentElement.clientWidth},t.adapters=[],t.defaults={context:window,continuous:!0,enabled:!0,group:"default",horizontal:!1,offset:0},t.offsetAliases={"bottom-in-view":function(){return this.context.innerHeight()-this.adapter.outerHeight()},"right-in-view":function(){return this.context.innerWidth()-this.adapter.outerWidth()}},window.Waypoint=t}(),function(){"use strict";function t(t){window.setTimeout(t,1e3/60)}function e(t){this.element=t,this.Adapter=n.Adapter,this.adapter=new this.Adapter(t),this.key="waypoint-context-"+i,this.didScroll=!1,this.didResize=!1,this.oldScroll={x:this.adapter.scrollLeft(),y:this.adapter.scrollTop()},this.waypoints={vertical:{},horizontal:{}},t.waypointContextKey=this.key,o[t.waypointContextKey]=this,i+=1,n.windowContext||(n.windowContext=!0,n.windowContext=new e(window)),this.createThrottledScrollHandler(),this.createThrottledResizeHandler()}var i=0,o={},n=window.Waypoint,r=window.onload;e.prototype.add=function(t){var e=t.options.horizontal?"horizontal":"vertical";this.waypoints[e][t.key]=t,this.refresh()},e.prototype.checkEmpty=function(){var t=this.Adapter.isEmptyObject(this.waypoints.horizontal),e=this.Adapter.isEmptyObject(this.waypoints.vertical),i=this.element==this.element.window;t&&e&&!i&&(this.adapter.off(".waypoints"),delete o[this.key])},e.prototype.createThrottledResizeHandler=function(){function t(){e.handleResize(),e.didResize=!1}var e=this;this.adapter.on("resize.waypoints",function(){e.didResize||(e.didResize=!0,n.requestAnimationFrame(t))})},e.prototype.createThrottledScrollHandler=function(){function t(){e.handleScroll(),e.didScroll=!1}var e=this;this.adapter.on("scroll.waypoints",function(){(!e.didScroll||n.isTouch)&&(e.didScroll=!0,n.requestAnimationFrame(t))})},e.prototype.handleResize=function(){n.Context.refreshAll()},e.prototype.handleScroll=function(){var t={},e={horizontal:{newScroll:this.adapter.scrollLeft(),oldScroll:this.oldScroll.x,forward:"right",backward:"left"},vertical:{newScroll:this.adapter.scrollTop(),oldScroll:this.oldScroll.y,forward:"down",backward:"up"}};for(var i in e){var o=e[i],n=o.newScroll>o.oldScroll,r=n?o.forward:o.backward;for(var s in this.waypoints[i]){var a=this.waypoints[i][s];if(null!==a.triggerPoint){var l=o.oldScroll=a.triggerPoint,p=l&&h,u=!l&&!h;(p||u)&&(a.queueTrigger(r),t[a.group.id]=a.group)}}}for(var c in t)t[c].flushTriggers();this.oldScroll={x:e.horizontal.newScroll,y:e.vertical.newScroll}},e.prototype.innerHeight=function(){return this.element==this.element.window?n.viewportHeight():this.adapter.innerHeight()},e.prototype.remove=function(t){delete this.waypoints[t.axis][t.key],this.checkEmpty()},e.prototype.innerWidth=function(){return this.element==this.element.window?n.viewportWidth():this.adapter.innerWidth()},e.prototype.destroy=function(){var t=[];for(var e in this.waypoints)for(var i in this.waypoints[e])t.push(this.waypoints[e][i]);for(var o=0,n=t.length;n>o;o++)t[o].destroy()},e.prototype.refresh=function(){var t,e=this.element==this.element.window,i=e?void 0:this.adapter.offset(),o={};this.handleScroll(),t={horizontal:{contextOffset:e?0:i.left,contextScroll:e?0:this.oldScroll.x,contextDimension:this.innerWidth(),oldScroll:this.oldScroll.x,forward:"right",backward:"left",offsetProp:"left"},vertical:{contextOffset:e?0:i.top,contextScroll:e?0:this.oldScroll.y,contextDimension:this.innerHeight(),oldScroll:this.oldScroll.y,forward:"down",backward:"up",offsetProp:"top"}};for(var r in t){var s=t[r];for(var a in this.waypoints[r]){var l,h,p,u,c,d=this.waypoints[r][a],f=d.options.offset,w=d.triggerPoint,y=0,g=null==w;d.element!==d.element.window&&(y=d.adapter.offset()[s.offsetProp]),"function"==typeof f?f=f.apply(d):"string"==typeof f&&(f=parseFloat(f),d.options.offset.indexOf("%")>-1&&(f=Math.ceil(s.contextDimension*f/100))),l=s.contextScroll-s.contextOffset,d.triggerPoint=Math.floor(y+l-f),h=w=s.oldScroll,u=h&&p,c=!h&&!p,!g&&u?(d.queueTrigger(s.backward),o[d.group.id]=d.group):!g&&c?(d.queueTrigger(s.forward),o[d.group.id]=d.group):g&&s.oldScroll>=d.triggerPoint&&(d.queueTrigger(s.forward),o[d.group.id]=d.group)}}return n.requestAnimationFrame(function(){for(var t in o)o[t].flushTriggers()}),this},e.findOrCreateByElement=function(t){return e.findByElement(t)||new e(t)},e.refreshAll=function(){for(var t in o)o[t].refresh()},e.findByElement=function(t){return o[t.waypointContextKey]},window.onload=function(){r&&r(),e.refreshAll()},n.requestAnimationFrame=function(e){var i=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||t;i.call(window,e)},n.Context=e}(),function(){"use strict";function t(t,e){return t.triggerPoint-e.triggerPoint}function e(t,e){return e.triggerPoint-t.triggerPoint}function i(t){this.name=t.name,this.axis=t.axis,this.id=this.name+"-"+this.axis,this.waypoints=[],this.clearTriggerQueues(),o[this.axis][this.name]=this}var o={vertical:{},horizontal:{}},n=window.Waypoint;i.prototype.add=function(t){this.waypoints.push(t)},i.prototype.clearTriggerQueues=function(){this.triggerQueues={up:[],down:[],left:[],right:[]}},i.prototype.flushTriggers=function(){for(var i in this.triggerQueues){var o=this.triggerQueues[i],n="up"===i||"left"===i;o.sort(n?e:t);for(var r=0,s=o.length;s>r;r+=1){var a=o[r];(a.options.continuous||r===o.length-1)&&a.trigger([i])}}this.clearTriggerQueues()},i.prototype.next=function(e){this.waypoints.sort(t);var i=n.Adapter.inArray(e,this.waypoints),o=i===this.waypoints.length-1;return o?null:this.waypoints[i+1]},i.prototype.previous=function(e){this.waypoints.sort(t);var i=n.Adapter.inArray(e,this.waypoints);return i?this.waypoints[i-1]:null},i.prototype.queueTrigger=function(t,e){this.triggerQueues[e].push(t)},i.prototype.remove=function(t){var e=n.Adapter.inArray(t,this.waypoints);e>-1&&this.waypoints.splice(e,1)},i.prototype.first=function(){return this.waypoints[0]},i.prototype.last=function(){return this.waypoints[this.waypoints.length-1]},i.findOrCreate=function(t){return o[t.axis][t.name]||new i(t)},n.Group=i}(),function(){"use strict";function t(t){this.element=t,this.$element=e(t)}var e=window.Zepto,i=window.Waypoint;e.each(["off","on","scrollLeft","scrollTop"],function(e,i){t.prototype[i]=function(){var t=Array.prototype.slice.call(arguments);return this.$element[i].apply(this.$element,t)}}),t.prototype.offset=function(){return this.element!==this.element.window?this.$element.offset():void 0},e.each(["width","height"],function(i,o){function n(t,i){return function(t){var n=this.$element,r=n[o](),s={width:["left","right"],height:["top","bottom"]};return e.each(s[o],function(e,o){r+=parseInt(n.css("padding-"+o),10),i&&(r+=parseInt(n.css("border-"+o+"-width"),10)),t&&(r+=parseInt(n.css("margin-"+o),10))}),r}}var r=e.camelCase("inner-"+o),s=e.camelCase("outer-"+o);t.prototype[r]=n(!1),t.prototype[s]=n(!0)}),e.each(["extend","inArray"],function(i,o){t[o]=e[o]}),t.isEmptyObject=function(t){for(var e in t)return!1;return!0},i.adapters.push({name:"zepto",Adapter:t}),i.Adapter=t}(),function(){"use strict";function t(t){return function(){var i=[],o=arguments[0];return t.isFunction(arguments[0])&&(o=t.extend({},arguments[1]),o.handler=arguments[0]),this.each(function(){var n=t.extend({},o,{element:this});"string"==typeof n.context&&(n.context=t(this).closest(n.context)[0]),i.push(new e(n))}),i}}var e=window.Waypoint;window.jQuery&&(window.jQuery.fn.waypoint=t(window.jQuery)),window.Zepto&&(window.Zepto.fn.waypoint=t(window.Zepto))}();
--------------------------------------------------------------------------------
/licenses.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2011-2012 Caleb Troughton
2 |
3 | -----------------------------------------------------------------------
4 |
5 | The MIT License
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in
15 | all copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | THE SOFTWARE.
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "waypoints",
3 | "version": "4.0.1",
4 | "author": "Caleb Troughton (http://imakewebthings.com)",
5 | "description": "Easily execute a function when you scroll to an element",
6 | "scripts": {
7 | "build": "gulp build",
8 | "start": "gulp",
9 | "test": "testem ci",
10 | "tdd": "testem",
11 | "watch": "gulp watch"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "https://github.com/imakewebthings/waypoints.git"
16 | },
17 | "keywords": [
18 | "scroll"
19 | ],
20 | "devDependencies": {
21 | "eslint": "^0.6.2",
22 | "gulp": "^3.6.2",
23 | "gulp-concat": "^2.2.0",
24 | "gulp-eslint": "^0.1.7",
25 | "gulp-footer": "^1.0.5",
26 | "gulp-header": "^1.0.2",
27 | "gulp-rename": "^1.2.0",
28 | "gulp-tap": "^0.1.1",
29 | "gulp-uglify": "^0.3.1",
30 | "merge-stream": "^0.1.1",
31 | "testem": "0.6.24"
32 | },
33 | "license": "MIT"
34 | }
35 |
--------------------------------------------------------------------------------
/src/adapters/jquery-zepto-fn-extension.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict'
3 |
4 | var Waypoint = window.Waypoint
5 |
6 | function createExtension(framework) {
7 | return function() {
8 | var waypoints = []
9 | var overrides = arguments[0]
10 |
11 | if (framework.isFunction(arguments[0])) {
12 | overrides = framework.extend({}, arguments[1])
13 | overrides.handler = arguments[0]
14 | }
15 |
16 | this.each(function() {
17 | var options = framework.extend({}, overrides, {
18 | element: this
19 | })
20 | if (typeof options.context === 'string') {
21 | options.context = framework(this).closest(options.context)[0]
22 | }
23 | waypoints.push(new Waypoint(options))
24 | })
25 |
26 | return waypoints
27 | }
28 | }
29 |
30 | if (window.jQuery) {
31 | window.jQuery.fn.waypoint = createExtension(window.jQuery)
32 | }
33 | if (window.Zepto) {
34 | window.Zepto.fn.waypoint = createExtension(window.Zepto)
35 | }
36 | }())
37 |
--------------------------------------------------------------------------------
/src/adapters/jquery.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict'
3 |
4 | var $ = window.jQuery
5 | var Waypoint = window.Waypoint
6 |
7 | function JQueryAdapter(element) {
8 | this.$element = $(element)
9 | }
10 |
11 | $.each([
12 | 'innerHeight',
13 | 'innerWidth',
14 | 'off',
15 | 'offset',
16 | 'on',
17 | 'outerHeight',
18 | 'outerWidth',
19 | 'scrollLeft',
20 | 'scrollTop'
21 | ], function(i, method) {
22 | JQueryAdapter.prototype[method] = function() {
23 | var args = Array.prototype.slice.call(arguments)
24 | return this.$element[method].apply(this.$element, args)
25 | }
26 | })
27 |
28 | $.each([
29 | 'extend',
30 | 'inArray',
31 | 'isEmptyObject'
32 | ], function(i, method) {
33 | JQueryAdapter[method] = $[method]
34 | })
35 |
36 | Waypoint.adapters.push({
37 | name: 'jquery',
38 | Adapter: JQueryAdapter
39 | })
40 | Waypoint.Adapter = JQueryAdapter
41 | }())
42 |
--------------------------------------------------------------------------------
/src/adapters/noframework.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict'
3 |
4 | var Waypoint = window.Waypoint
5 |
6 | function isWindow(element) {
7 | return element === element.window
8 | }
9 |
10 | function getWindow(element) {
11 | if (isWindow(element)) {
12 | return element
13 | }
14 | return element.defaultView
15 | }
16 |
17 | function NoFrameworkAdapter(element) {
18 | this.element = element
19 | this.handlers = {}
20 | }
21 |
22 | NoFrameworkAdapter.prototype.innerHeight = function() {
23 | var isWin = isWindow(this.element)
24 | return isWin ? this.element.innerHeight : this.element.clientHeight
25 | }
26 |
27 | NoFrameworkAdapter.prototype.innerWidth = function() {
28 | var isWin = isWindow(this.element)
29 | return isWin ? this.element.innerWidth : this.element.clientWidth
30 | }
31 |
32 | NoFrameworkAdapter.prototype.off = function(event, handler) {
33 | function removeListeners(element, listeners, handler) {
34 | for (var i = 0, end = listeners.length - 1; i < end; i++) {
35 | var listener = listeners[i]
36 | if (!handler || handler === listener) {
37 | element.removeEventListener(listener)
38 | }
39 | }
40 | }
41 |
42 | var eventParts = event.split('.')
43 | var eventType = eventParts[0]
44 | var namespace = eventParts[1]
45 | var element = this.element
46 |
47 | if (namespace && this.handlers[namespace] && eventType) {
48 | removeListeners(element, this.handlers[namespace][eventType], handler)
49 | this.handlers[namespace][eventType] = []
50 | }
51 | else if (eventType) {
52 | for (var ns in this.handlers) {
53 | removeListeners(element, this.handlers[ns][eventType] || [], handler)
54 | this.handlers[ns][eventType] = []
55 | }
56 | }
57 | else if (namespace && this.handlers[namespace]) {
58 | for (var type in this.handlers[namespace]) {
59 | removeListeners(element, this.handlers[namespace][type], handler)
60 | }
61 | this.handlers[namespace] = {}
62 | }
63 | }
64 |
65 | /* Adapted from jQuery 1.x offset() */
66 | NoFrameworkAdapter.prototype.offset = function() {
67 | if (!this.element.ownerDocument) {
68 | return null
69 | }
70 |
71 | var documentElement = this.element.ownerDocument.documentElement
72 | var win = getWindow(this.element.ownerDocument)
73 | var rect = {
74 | top: 0,
75 | left: 0
76 | }
77 |
78 | if (this.element.getBoundingClientRect) {
79 | rect = this.element.getBoundingClientRect()
80 | }
81 |
82 | return {
83 | top: rect.top + win.pageYOffset - documentElement.clientTop,
84 | left: rect.left + win.pageXOffset - documentElement.clientLeft
85 | }
86 | }
87 |
88 | NoFrameworkAdapter.prototype.on = function(event, handler) {
89 | var eventParts = event.split('.')
90 | var eventType = eventParts[0]
91 | var namespace = eventParts[1] || '__default'
92 | var nsHandlers = this.handlers[namespace] = this.handlers[namespace] || {}
93 | var nsTypeList = nsHandlers[eventType] = nsHandlers[eventType] || []
94 |
95 | nsTypeList.push(handler)
96 | this.element.addEventListener(eventType, handler)
97 | }
98 |
99 | NoFrameworkAdapter.prototype.outerHeight = function(includeMargin) {
100 | var height = this.innerHeight()
101 | var computedStyle
102 |
103 | if (includeMargin && !isWindow(this.element)) {
104 | computedStyle = window.getComputedStyle(this.element)
105 | height += parseInt(computedStyle.marginTop, 10)
106 | height += parseInt(computedStyle.marginBottom, 10)
107 | }
108 |
109 | return height
110 | }
111 |
112 | NoFrameworkAdapter.prototype.outerWidth = function(includeMargin) {
113 | var width = this.innerWidth()
114 | var computedStyle
115 |
116 | if (includeMargin && !isWindow(this.element)) {
117 | computedStyle = window.getComputedStyle(this.element)
118 | width += parseInt(computedStyle.marginLeft, 10)
119 | width += parseInt(computedStyle.marginRight, 10)
120 | }
121 |
122 | return width
123 | }
124 |
125 | NoFrameworkAdapter.prototype.scrollLeft = function() {
126 | var win = getWindow(this.element)
127 | return win ? win.pageXOffset : this.element.scrollLeft
128 | }
129 |
130 | NoFrameworkAdapter.prototype.scrollTop = function() {
131 | var win = getWindow(this.element)
132 | return win ? win.pageYOffset : this.element.scrollTop
133 | }
134 |
135 | NoFrameworkAdapter.extend = function() {
136 | var args = Array.prototype.slice.call(arguments)
137 |
138 | function merge(target, obj) {
139 | if (typeof target === 'object' && typeof obj === 'object') {
140 | for (var key in obj) {
141 | if (obj.hasOwnProperty(key)) {
142 | target[key] = obj[key]
143 | }
144 | }
145 | }
146 |
147 | return target
148 | }
149 |
150 | for (var i = 1, end = args.length; i < end; i++) {
151 | merge(args[0], args[i])
152 | }
153 | return args[0]
154 | }
155 |
156 | NoFrameworkAdapter.inArray = function(element, array, i) {
157 | return array == null ? -1 : array.indexOf(element, i)
158 | }
159 |
160 | NoFrameworkAdapter.isEmptyObject = function(obj) {
161 | /* eslint no-unused-vars: 0 */
162 | for (var name in obj) {
163 | return false
164 | }
165 | return true
166 | }
167 |
168 | Waypoint.adapters.push({
169 | name: 'noframework',
170 | Adapter: NoFrameworkAdapter
171 | })
172 | Waypoint.Adapter = NoFrameworkAdapter
173 | }())
174 |
--------------------------------------------------------------------------------
/src/adapters/zepto.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict'
3 |
4 | var $ = window.Zepto
5 | var Waypoint = window.Waypoint
6 |
7 | function ZeptoAdapter(element) {
8 | this.element = element
9 | this.$element = $(element)
10 | }
11 |
12 | $.each([
13 | 'off',
14 | 'on',
15 | 'scrollLeft',
16 | 'scrollTop'
17 | ], function(i, method) {
18 | ZeptoAdapter.prototype[method] = function() {
19 | var args = Array.prototype.slice.call(arguments)
20 | return this.$element[method].apply(this.$element, args)
21 | }
22 | })
23 |
24 | ZeptoAdapter.prototype.offset = function() {
25 | if (this.element !== this.element.window) {
26 | return this.$element.offset()
27 | }
28 | }
29 |
30 | // Adapted from https://gist.github.com/wheresrhys/5823198
31 | $.each([
32 | 'width',
33 | 'height'
34 | ], function(i, dimension) {
35 | function createDimensionMethod($element, includeBorder) {
36 | return function(includeMargin) {
37 | var $element = this.$element
38 | var size = $element[dimension]()
39 | var sides = {
40 | width: ['left', 'right'],
41 | height: ['top', 'bottom']
42 | }
43 |
44 | $.each(sides[dimension], function(i, side) {
45 | size += parseInt($element.css('padding-' + side), 10)
46 | if (includeBorder) {
47 | size += parseInt($element.css('border-' + side + '-width'), 10)
48 | }
49 | if (includeMargin) {
50 | size += parseInt($element.css('margin-' + side), 10)
51 | }
52 | })
53 | return size
54 | }
55 | }
56 |
57 | var innerMethod = $.camelCase('inner-' + dimension)
58 | var outerMethod = $.camelCase('outer-' + dimension)
59 |
60 | ZeptoAdapter.prototype[innerMethod] = createDimensionMethod(false)
61 | ZeptoAdapter.prototype[outerMethod] = createDimensionMethod(true)
62 | })
63 |
64 | $.each([
65 | 'extend',
66 | 'inArray'
67 | ], function(i, method) {
68 | ZeptoAdapter[method] = $[method]
69 | })
70 |
71 | ZeptoAdapter.isEmptyObject = function(obj) {
72 | /* eslint no-unused-vars: 0 */
73 | for (var name in obj) {
74 | return false
75 | }
76 | return true
77 | }
78 |
79 | Waypoint.adapters.push({
80 | name: 'zepto',
81 | Adapter: ZeptoAdapter
82 | })
83 | Waypoint.Adapter = ZeptoAdapter
84 | }())
85 |
--------------------------------------------------------------------------------
/src/context.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict'
3 |
4 | function requestAnimationFrameShim(callback) {
5 | window.setTimeout(callback, 1000 / 60)
6 | }
7 |
8 | var keyCounter = 0
9 | var contexts = {}
10 | var Waypoint = window.Waypoint
11 | var oldWindowLoad = window.onload
12 |
13 | /* http://imakewebthings.com/waypoints/api/context */
14 | function Context(element) {
15 | this.element = element
16 | this.Adapter = Waypoint.Adapter
17 | this.adapter = new this.Adapter(element)
18 | this.key = 'waypoint-context-' + keyCounter
19 | this.didScroll = false
20 | this.didResize = false
21 | this.oldScroll = {
22 | x: this.adapter.scrollLeft(),
23 | y: this.adapter.scrollTop()
24 | }
25 | this.waypoints = {
26 | vertical: {},
27 | horizontal: {}
28 | }
29 |
30 | element.waypointContextKey = this.key
31 | contexts[element.waypointContextKey] = this
32 | keyCounter += 1
33 | if (!Waypoint.windowContext) {
34 | Waypoint.windowContext = true
35 | Waypoint.windowContext = new Context(window)
36 | }
37 |
38 | this.createThrottledScrollHandler()
39 | this.createThrottledResizeHandler()
40 | }
41 |
42 | /* Private */
43 | Context.prototype.add = function(waypoint) {
44 | var axis = waypoint.options.horizontal ? 'horizontal' : 'vertical'
45 | this.waypoints[axis][waypoint.key] = waypoint
46 | this.refresh()
47 | }
48 |
49 | /* Private */
50 | Context.prototype.checkEmpty = function() {
51 | var horizontalEmpty = this.Adapter.isEmptyObject(this.waypoints.horizontal)
52 | var verticalEmpty = this.Adapter.isEmptyObject(this.waypoints.vertical)
53 | var isWindow = this.element == this.element.window
54 | if (horizontalEmpty && verticalEmpty && !isWindow) {
55 | this.adapter.off('.waypoints')
56 | delete contexts[this.key]
57 | }
58 | }
59 |
60 | /* Private */
61 | Context.prototype.createThrottledResizeHandler = function() {
62 | var self = this
63 |
64 | function resizeHandler() {
65 | self.handleResize()
66 | self.didResize = false
67 | }
68 |
69 | this.adapter.on('resize.waypoints', function() {
70 | if (!self.didResize) {
71 | self.didResize = true
72 | Waypoint.requestAnimationFrame(resizeHandler)
73 | }
74 | })
75 | }
76 |
77 | /* Private */
78 | Context.prototype.createThrottledScrollHandler = function() {
79 | var self = this
80 | function scrollHandler() {
81 | self.handleScroll()
82 | self.didScroll = false
83 | }
84 |
85 | this.adapter.on('scroll.waypoints', function() {
86 | if (!self.didScroll || Waypoint.isTouch) {
87 | self.didScroll = true
88 | Waypoint.requestAnimationFrame(scrollHandler)
89 | }
90 | })
91 | }
92 |
93 | /* Private */
94 | Context.prototype.handleResize = function() {
95 | Waypoint.Context.refreshAll()
96 | }
97 |
98 | /* Private */
99 | Context.prototype.handleScroll = function() {
100 | var triggeredGroups = {}
101 | var axes = {
102 | horizontal: {
103 | newScroll: this.adapter.scrollLeft(),
104 | oldScroll: this.oldScroll.x,
105 | forward: 'right',
106 | backward: 'left'
107 | },
108 | vertical: {
109 | newScroll: this.adapter.scrollTop(),
110 | oldScroll: this.oldScroll.y,
111 | forward: 'down',
112 | backward: 'up'
113 | }
114 | }
115 |
116 | for (var axisKey in axes) {
117 | var axis = axes[axisKey]
118 | var isForward = axis.newScroll > axis.oldScroll
119 | var direction = isForward ? axis.forward : axis.backward
120 |
121 | for (var waypointKey in this.waypoints[axisKey]) {
122 | var waypoint = this.waypoints[axisKey][waypointKey]
123 | if (waypoint.triggerPoint === null) {
124 | continue
125 | }
126 | var wasBeforeTriggerPoint = axis.oldScroll < waypoint.triggerPoint
127 | var nowAfterTriggerPoint = axis.newScroll >= waypoint.triggerPoint
128 | var crossedForward = wasBeforeTriggerPoint && nowAfterTriggerPoint
129 | var crossedBackward = !wasBeforeTriggerPoint && !nowAfterTriggerPoint
130 | if (crossedForward || crossedBackward) {
131 | waypoint.queueTrigger(direction)
132 | triggeredGroups[waypoint.group.id] = waypoint.group
133 | }
134 | }
135 | }
136 |
137 | for (var groupKey in triggeredGroups) {
138 | triggeredGroups[groupKey].flushTriggers()
139 | }
140 |
141 | this.oldScroll = {
142 | x: axes.horizontal.newScroll,
143 | y: axes.vertical.newScroll
144 | }
145 | }
146 |
147 | /* Private */
148 | Context.prototype.innerHeight = function() {
149 | /*eslint-disable eqeqeq */
150 | if (this.element == this.element.window) {
151 | return Waypoint.viewportHeight()
152 | }
153 | /*eslint-enable eqeqeq */
154 | return this.adapter.innerHeight()
155 | }
156 |
157 | /* Private */
158 | Context.prototype.remove = function(waypoint) {
159 | delete this.waypoints[waypoint.axis][waypoint.key]
160 | this.checkEmpty()
161 | }
162 |
163 | /* Private */
164 | Context.prototype.innerWidth = function() {
165 | /*eslint-disable eqeqeq */
166 | if (this.element == this.element.window) {
167 | return Waypoint.viewportWidth()
168 | }
169 | /*eslint-enable eqeqeq */
170 | return this.adapter.innerWidth()
171 | }
172 |
173 | /* Public */
174 | /* http://imakewebthings.com/waypoints/api/context-destroy */
175 | Context.prototype.destroy = function() {
176 | var allWaypoints = []
177 | for (var axis in this.waypoints) {
178 | for (var waypointKey in this.waypoints[axis]) {
179 | allWaypoints.push(this.waypoints[axis][waypointKey])
180 | }
181 | }
182 | for (var i = 0, end = allWaypoints.length; i < end; i++) {
183 | allWaypoints[i].destroy()
184 | }
185 | }
186 |
187 | /* Public */
188 | /* http://imakewebthings.com/waypoints/api/context-refresh */
189 | Context.prototype.refresh = function() {
190 | /*eslint-disable eqeqeq */
191 | var isWindow = this.element == this.element.window
192 | /*eslint-enable eqeqeq */
193 | var contextOffset = isWindow ? undefined : this.adapter.offset()
194 | var triggeredGroups = {}
195 | var axes
196 |
197 | this.handleScroll()
198 | axes = {
199 | horizontal: {
200 | contextOffset: isWindow ? 0 : contextOffset.left,
201 | contextScroll: isWindow ? 0 : this.oldScroll.x,
202 | contextDimension: this.innerWidth(),
203 | oldScroll: this.oldScroll.x,
204 | forward: 'right',
205 | backward: 'left',
206 | offsetProp: 'left'
207 | },
208 | vertical: {
209 | contextOffset: isWindow ? 0 : contextOffset.top,
210 | contextScroll: isWindow ? 0 : this.oldScroll.y,
211 | contextDimension: this.innerHeight(),
212 | oldScroll: this.oldScroll.y,
213 | forward: 'down',
214 | backward: 'up',
215 | offsetProp: 'top'
216 | }
217 | }
218 |
219 | for (var axisKey in axes) {
220 | var axis = axes[axisKey]
221 | for (var waypointKey in this.waypoints[axisKey]) {
222 | var waypoint = this.waypoints[axisKey][waypointKey]
223 | var adjustment = waypoint.options.offset
224 | var oldTriggerPoint = waypoint.triggerPoint
225 | var elementOffset = 0
226 | var freshWaypoint = oldTriggerPoint == null
227 | var contextModifier, wasBeforeScroll, nowAfterScroll
228 | var triggeredBackward, triggeredForward
229 |
230 | if (waypoint.element !== waypoint.element.window) {
231 | elementOffset = waypoint.adapter.offset()[axis.offsetProp]
232 | }
233 |
234 | if (typeof adjustment === 'function') {
235 | adjustment = adjustment.apply(waypoint)
236 | }
237 | else if (typeof adjustment === 'string') {
238 | adjustment = parseFloat(adjustment)
239 | if (waypoint.options.offset.indexOf('%') > - 1) {
240 | adjustment = Math.ceil(axis.contextDimension * adjustment / 100)
241 | }
242 | }
243 |
244 | contextModifier = axis.contextScroll - axis.contextOffset
245 | waypoint.triggerPoint = Math.floor(elementOffset + contextModifier - adjustment)
246 | wasBeforeScroll = oldTriggerPoint < axis.oldScroll
247 | nowAfterScroll = waypoint.triggerPoint >= axis.oldScroll
248 | triggeredBackward = wasBeforeScroll && nowAfterScroll
249 | triggeredForward = !wasBeforeScroll && !nowAfterScroll
250 |
251 | if (!freshWaypoint && triggeredBackward) {
252 | waypoint.queueTrigger(axis.backward)
253 | triggeredGroups[waypoint.group.id] = waypoint.group
254 | }
255 | else if (!freshWaypoint && triggeredForward) {
256 | waypoint.queueTrigger(axis.forward)
257 | triggeredGroups[waypoint.group.id] = waypoint.group
258 | }
259 | else if (freshWaypoint && axis.oldScroll >= waypoint.triggerPoint) {
260 | waypoint.queueTrigger(axis.forward)
261 | triggeredGroups[waypoint.group.id] = waypoint.group
262 | }
263 | }
264 | }
265 |
266 | Waypoint.requestAnimationFrame(function() {
267 | for (var groupKey in triggeredGroups) {
268 | triggeredGroups[groupKey].flushTriggers()
269 | }
270 | })
271 |
272 | return this
273 | }
274 |
275 | /* Private */
276 | Context.findOrCreateByElement = function(element) {
277 | return Context.findByElement(element) || new Context(element)
278 | }
279 |
280 | /* Private */
281 | Context.refreshAll = function() {
282 | for (var contextId in contexts) {
283 | contexts[contextId].refresh()
284 | }
285 | }
286 |
287 | /* Public */
288 | /* http://imakewebthings.com/waypoints/api/context-find-by-element */
289 | Context.findByElement = function(element) {
290 | return contexts[element.waypointContextKey]
291 | }
292 |
293 | window.onload = function() {
294 | if (oldWindowLoad) {
295 | oldWindowLoad()
296 | }
297 | Context.refreshAll()
298 | }
299 |
300 |
301 | Waypoint.requestAnimationFrame = function(callback) {
302 | var requestFn = window.requestAnimationFrame ||
303 | window.mozRequestAnimationFrame ||
304 | window.webkitRequestAnimationFrame ||
305 | requestAnimationFrameShim
306 | requestFn.call(window, callback)
307 | }
308 | Waypoint.Context = Context
309 | }())
310 |
--------------------------------------------------------------------------------
/src/debug.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict'
3 |
4 | var displayNoneMessage = [
5 | 'You have a Waypoint element with display none. For more information on ',
6 | 'why this is a bad idea read ',
7 | 'http://imakewebthings.com/waypoints/guides/debugging/#display-none'
8 | ].join('')
9 | var fixedMessage = [
10 | 'You have a Waypoint element with fixed positioning. For more ',
11 | 'information on why this is a bad idea read ',
12 | 'http://imakewebthings.com/waypoints/guides/debugging/#fixed-position'
13 | ].join('')
14 |
15 | function checkWaypointStyles() {
16 | var originalRefresh = window.Waypoint.Context.prototype.refresh
17 |
18 | window.Waypoint.Context.prototype.refresh = function() {
19 | for (var axis in this.waypoints) {
20 | for (var key in this.waypoints[axis]) {
21 | var waypoint = this.waypoints[axis][key]
22 | var style = window.getComputedStyle(waypoint.element)
23 | if (!waypoint.enabled) {
24 | continue
25 | }
26 | if (style && style.display === 'none') {
27 | console.error(displayNoneMessage)
28 | }
29 | if (style && style.position === 'fixed') {
30 | console.error(fixedMessage)
31 | }
32 | }
33 | }
34 | return originalRefresh.call(this)
35 | }
36 | }
37 |
38 | checkWaypointStyles()
39 | }())
40 |
--------------------------------------------------------------------------------
/src/group.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict'
3 |
4 | function byTriggerPoint(a, b) {
5 | return a.triggerPoint - b.triggerPoint
6 | }
7 |
8 | function byReverseTriggerPoint(a, b) {
9 | return b.triggerPoint - a.triggerPoint
10 | }
11 |
12 | var groups = {
13 | vertical: {},
14 | horizontal: {}
15 | }
16 | var Waypoint = window.Waypoint
17 |
18 | /* http://imakewebthings.com/waypoints/api/group */
19 | function Group(options) {
20 | this.name = options.name
21 | this.axis = options.axis
22 | this.id = this.name + '-' + this.axis
23 | this.waypoints = []
24 | this.clearTriggerQueues()
25 | groups[this.axis][this.name] = this
26 | }
27 |
28 | /* Private */
29 | Group.prototype.add = function(waypoint) {
30 | this.waypoints.push(waypoint)
31 | }
32 |
33 | /* Private */
34 | Group.prototype.clearTriggerQueues = function() {
35 | this.triggerQueues = {
36 | up: [],
37 | down: [],
38 | left: [],
39 | right: []
40 | }
41 | }
42 |
43 | /* Private */
44 | Group.prototype.flushTriggers = function() {
45 | for (var direction in this.triggerQueues) {
46 | var waypoints = this.triggerQueues[direction]
47 | var reverse = direction === 'up' || direction === 'left'
48 | waypoints.sort(reverse ? byReverseTriggerPoint : byTriggerPoint)
49 | for (var i = 0, end = waypoints.length; i < end; i += 1) {
50 | var waypoint = waypoints[i]
51 | if (waypoint.options.continuous || i === waypoints.length - 1) {
52 | waypoint.trigger([direction])
53 | }
54 | }
55 | }
56 | this.clearTriggerQueues()
57 | }
58 |
59 | /* Private */
60 | Group.prototype.next = function(waypoint) {
61 | this.waypoints.sort(byTriggerPoint)
62 | var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
63 | var isLast = index === this.waypoints.length - 1
64 | return isLast ? null : this.waypoints[index + 1]
65 | }
66 |
67 | /* Private */
68 | Group.prototype.previous = function(waypoint) {
69 | this.waypoints.sort(byTriggerPoint)
70 | var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
71 | return index ? this.waypoints[index - 1] : null
72 | }
73 |
74 | /* Private */
75 | Group.prototype.queueTrigger = function(waypoint, direction) {
76 | this.triggerQueues[direction].push(waypoint)
77 | }
78 |
79 | /* Private */
80 | Group.prototype.remove = function(waypoint) {
81 | var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
82 | if (index > -1) {
83 | this.waypoints.splice(index, 1)
84 | }
85 | }
86 |
87 | /* Public */
88 | /* http://imakewebthings.com/waypoints/api/first */
89 | Group.prototype.first = function() {
90 | return this.waypoints[0]
91 | }
92 |
93 | /* Public */
94 | /* http://imakewebthings.com/waypoints/api/last */
95 | Group.prototype.last = function() {
96 | return this.waypoints[this.waypoints.length - 1]
97 | }
98 |
99 | /* Private */
100 | Group.findOrCreate = function(options) {
101 | return groups[options.axis][options.name] || new Group(options)
102 | }
103 |
104 | Waypoint.Group = Group
105 | }())
106 |
--------------------------------------------------------------------------------
/src/shortcuts/infinite.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict'
3 |
4 | var $ = window.jQuery
5 | var Waypoint = window.Waypoint
6 |
7 | /* http://imakewebthings.com/waypoints/shortcuts/infinite-scroll */
8 | function Infinite(options) {
9 | this.options = $.extend({}, Infinite.defaults, options)
10 | this.container = this.options.element
11 | if (this.options.container !== 'auto') {
12 | this.container = this.options.container
13 | }
14 | this.$container = $(this.container)
15 | this.$more = $(this.options.more)
16 |
17 | if (this.$more.length) {
18 | this.setupHandler()
19 | this.waypoint = new Waypoint(this.options)
20 | }
21 | }
22 |
23 | /* Private */
24 | Infinite.prototype.setupHandler = function() {
25 | this.options.handler = $.proxy(function() {
26 | this.options.onBeforePageLoad()
27 | this.destroy()
28 | this.$container.addClass(this.options.loadingClass)
29 |
30 | $.get($(this.options.more).attr('href'), $.proxy(function(data) {
31 | var $data = $($.parseHTML(data))
32 | var $newMore = $data.find(this.options.more)
33 |
34 | var $items = $data.find(this.options.items)
35 | if (!$items.length) {
36 | $items = $data.filter(this.options.items)
37 | }
38 |
39 | this.$container.append($items)
40 | this.$container.removeClass(this.options.loadingClass)
41 |
42 | if (!$newMore.length) {
43 | $newMore = $data.filter(this.options.more)
44 | }
45 | if ($newMore.length) {
46 | this.$more.replaceWith($newMore)
47 | this.$more = $newMore
48 | this.waypoint = new Waypoint(this.options)
49 | }
50 | else {
51 | this.$more.remove()
52 | }
53 |
54 | this.options.onAfterPageLoad($items)
55 | }, this))
56 | }, this)
57 | }
58 |
59 | /* Public */
60 | Infinite.prototype.destroy = function() {
61 | if (this.waypoint) {
62 | this.waypoint.destroy()
63 | }
64 | }
65 |
66 | Infinite.defaults = {
67 | container: 'auto',
68 | items: '.infinite-item',
69 | more: '.infinite-more-link',
70 | offset: 'bottom-in-view',
71 | loadingClass: 'infinite-loading',
72 | onBeforePageLoad: $.noop,
73 | onAfterPageLoad: $.noop
74 | }
75 |
76 | Waypoint.Infinite = Infinite
77 | }())
78 |
--------------------------------------------------------------------------------
/src/shortcuts/inview.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict'
3 |
4 | function noop() {}
5 |
6 | var Waypoint = window.Waypoint
7 |
8 | /* http://imakewebthings.com/waypoints/shortcuts/inview */
9 | function Inview(options) {
10 | this.options = Waypoint.Adapter.extend({}, Inview.defaults, options)
11 | this.axis = this.options.horizontal ? 'horizontal' : 'vertical'
12 | this.waypoints = []
13 | this.element = this.options.element
14 | this.createWaypoints()
15 | }
16 |
17 | /* Private */
18 | Inview.prototype.createWaypoints = function() {
19 | var configs = {
20 | vertical: [{
21 | down: 'enter',
22 | up: 'exited',
23 | offset: '100%'
24 | }, {
25 | down: 'entered',
26 | up: 'exit',
27 | offset: 'bottom-in-view'
28 | }, {
29 | down: 'exit',
30 | up: 'entered',
31 | offset: 0
32 | }, {
33 | down: 'exited',
34 | up: 'enter',
35 | offset: function() {
36 | return -this.adapter.outerHeight()
37 | }
38 | }],
39 | horizontal: [{
40 | right: 'enter',
41 | left: 'exited',
42 | offset: '100%'
43 | }, {
44 | right: 'entered',
45 | left: 'exit',
46 | offset: 'right-in-view'
47 | }, {
48 | right: 'exit',
49 | left: 'entered',
50 | offset: 0
51 | }, {
52 | right: 'exited',
53 | left: 'enter',
54 | offset: function() {
55 | return -this.adapter.outerWidth()
56 | }
57 | }]
58 | }
59 |
60 | for (var i = 0, end = configs[this.axis].length; i < end; i++) {
61 | var config = configs[this.axis][i]
62 | this.createWaypoint(config)
63 | }
64 | }
65 |
66 | /* Private */
67 | Inview.prototype.createWaypoint = function(config) {
68 | var self = this
69 | this.waypoints.push(new Waypoint({
70 | context: this.options.context,
71 | element: this.options.element,
72 | enabled: this.options.enabled,
73 | handler: (function(config) {
74 | return function(direction) {
75 | self.options[config[direction]].call(self, direction)
76 | }
77 | }(config)),
78 | offset: config.offset,
79 | horizontal: this.options.horizontal
80 | }))
81 | }
82 |
83 | /* Public */
84 | Inview.prototype.destroy = function() {
85 | for (var i = 0, end = this.waypoints.length; i < end; i++) {
86 | this.waypoints[i].destroy()
87 | }
88 | this.waypoints = []
89 | }
90 |
91 | Inview.prototype.disable = function() {
92 | for (var i = 0, end = this.waypoints.length; i < end; i++) {
93 | this.waypoints[i].disable()
94 | }
95 | }
96 |
97 | Inview.prototype.enable = function() {
98 | for (var i = 0, end = this.waypoints.length; i < end; i++) {
99 | this.waypoints[i].enable()
100 | }
101 | }
102 |
103 | Inview.defaults = {
104 | context: window,
105 | enabled: true,
106 | enter: noop,
107 | entered: noop,
108 | exit: noop,
109 | exited: noop
110 | }
111 |
112 | Waypoint.Inview = Inview
113 | }())
114 |
--------------------------------------------------------------------------------
/src/shortcuts/sticky.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict'
3 |
4 | var $ = window.jQuery
5 | var Waypoint = window.Waypoint
6 |
7 | /* http://imakewebthings.com/waypoints/shortcuts/sticky-elements */
8 | function Sticky(options) {
9 | this.options = $.extend({}, Waypoint.defaults, Sticky.defaults, options)
10 | this.element = this.options.element
11 | this.$element = $(this.element)
12 | this.createWrapper()
13 | this.createWaypoint()
14 | }
15 |
16 | /* Private */
17 | Sticky.prototype.createWaypoint = function() {
18 | var originalHandler = this.options.handler
19 |
20 | this.waypoint = new Waypoint($.extend({}, this.options, {
21 | element: this.wrapper,
22 | handler: $.proxy(function(direction) {
23 | var shouldBeStuck = this.options.direction.indexOf(direction) > -1
24 | var wrapperHeight = shouldBeStuck ? this.$element.outerHeight(true) : ''
25 |
26 | this.$wrapper.height(wrapperHeight)
27 | this.$element.toggleClass(this.options.stuckClass, shouldBeStuck)
28 |
29 | if (originalHandler) {
30 | originalHandler.call(this, direction)
31 | }
32 | }, this)
33 | }))
34 | }
35 |
36 | /* Private */
37 | Sticky.prototype.createWrapper = function() {
38 | if (this.options.wrapper) {
39 | this.$element.wrap(this.options.wrapper)
40 | }
41 | this.$wrapper = this.$element.parent()
42 | this.wrapper = this.$wrapper[0]
43 | }
44 |
45 | /* Public */
46 | Sticky.prototype.destroy = function() {
47 | if (this.$element.parent()[0] === this.wrapper) {
48 | this.waypoint.destroy()
49 | this.$element.removeClass(this.options.stuckClass)
50 | if (this.options.wrapper) {
51 | this.$element.unwrap()
52 | }
53 | }
54 | }
55 |
56 | Sticky.defaults = {
57 | wrapper: '',
58 | stuckClass: 'stuck',
59 | direction: 'down right'
60 | }
61 |
62 | Waypoint.Sticky = Sticky
63 | }())
64 |
--------------------------------------------------------------------------------
/src/waypoint.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict'
3 |
4 | var keyCounter = 0
5 | var allWaypoints = {}
6 |
7 | /* http://imakewebthings.com/waypoints/api/waypoint */
8 | function Waypoint(options) {
9 | if (!options) {
10 | throw new Error('No options passed to Waypoint constructor')
11 | }
12 | if (!options.element) {
13 | throw new Error('No element option passed to Waypoint constructor')
14 | }
15 | if (!options.handler) {
16 | throw new Error('No handler option passed to Waypoint constructor')
17 | }
18 |
19 | this.key = 'waypoint-' + keyCounter
20 | this.options = Waypoint.Adapter.extend({}, Waypoint.defaults, options)
21 | this.element = this.options.element
22 | this.adapter = new Waypoint.Adapter(this.element)
23 | this.callback = options.handler
24 | this.axis = this.options.horizontal ? 'horizontal' : 'vertical'
25 | this.enabled = this.options.enabled
26 | this.triggerPoint = null
27 | this.group = Waypoint.Group.findOrCreate({
28 | name: this.options.group,
29 | axis: this.axis
30 | })
31 | this.context = Waypoint.Context.findOrCreateByElement(this.options.context)
32 |
33 | if (Waypoint.offsetAliases[this.options.offset]) {
34 | this.options.offset = Waypoint.offsetAliases[this.options.offset]
35 | }
36 | this.group.add(this)
37 | this.context.add(this)
38 | allWaypoints[this.key] = this
39 | keyCounter += 1
40 | }
41 |
42 | /* Private */
43 | Waypoint.prototype.queueTrigger = function(direction) {
44 | this.group.queueTrigger(this, direction)
45 | }
46 |
47 | /* Private */
48 | Waypoint.prototype.trigger = function(args) {
49 | if (!this.enabled) {
50 | return
51 | }
52 | if (this.callback) {
53 | this.callback.apply(this, args)
54 | }
55 | }
56 |
57 | /* Public */
58 | /* http://imakewebthings.com/waypoints/api/destroy */
59 | Waypoint.prototype.destroy = function() {
60 | this.context.remove(this)
61 | this.group.remove(this)
62 | delete allWaypoints[this.key]
63 | }
64 |
65 | /* Public */
66 | /* http://imakewebthings.com/waypoints/api/disable */
67 | Waypoint.prototype.disable = function() {
68 | this.enabled = false
69 | return this
70 | }
71 |
72 | /* Public */
73 | /* http://imakewebthings.com/waypoints/api/enable */
74 | Waypoint.prototype.enable = function() {
75 | this.context.refresh()
76 | this.enabled = true
77 | return this
78 | }
79 |
80 | /* Public */
81 | /* http://imakewebthings.com/waypoints/api/next */
82 | Waypoint.prototype.next = function() {
83 | return this.group.next(this)
84 | }
85 |
86 | /* Public */
87 | /* http://imakewebthings.com/waypoints/api/previous */
88 | Waypoint.prototype.previous = function() {
89 | return this.group.previous(this)
90 | }
91 |
92 | /* Private */
93 | Waypoint.invokeAll = function(method) {
94 | var allWaypointsArray = []
95 | for (var waypointKey in allWaypoints) {
96 | allWaypointsArray.push(allWaypoints[waypointKey])
97 | }
98 | for (var i = 0, end = allWaypointsArray.length; i < end; i++) {
99 | allWaypointsArray[i][method]()
100 | }
101 | }
102 |
103 | /* Public */
104 | /* http://imakewebthings.com/waypoints/api/destroy-all */
105 | Waypoint.destroyAll = function() {
106 | Waypoint.invokeAll('destroy')
107 | }
108 |
109 | /* Public */
110 | /* http://imakewebthings.com/waypoints/api/disable-all */
111 | Waypoint.disableAll = function() {
112 | Waypoint.invokeAll('disable')
113 | }
114 |
115 | /* Public */
116 | /* http://imakewebthings.com/waypoints/api/enable-all */
117 | Waypoint.enableAll = function() {
118 | Waypoint.Context.refreshAll()
119 | for (var waypointKey in allWaypoints) {
120 | allWaypoints[waypointKey].enabled = true
121 | }
122 | return this
123 | }
124 |
125 | /* Public */
126 | /* http://imakewebthings.com/waypoints/api/refresh-all */
127 | Waypoint.refreshAll = function() {
128 | Waypoint.Context.refreshAll()
129 | }
130 |
131 | /* Public */
132 | /* http://imakewebthings.com/waypoints/api/viewport-height */
133 | Waypoint.viewportHeight = function() {
134 | return window.innerHeight || document.documentElement.clientHeight
135 | }
136 |
137 | /* Public */
138 | /* http://imakewebthings.com/waypoints/api/viewport-width */
139 | Waypoint.viewportWidth = function() {
140 | return document.documentElement.clientWidth
141 | }
142 |
143 | Waypoint.adapters = []
144 |
145 | Waypoint.defaults = {
146 | context: window,
147 | continuous: true,
148 | enabled: true,
149 | group: 'default',
150 | horizontal: false,
151 | offset: 0
152 | }
153 |
154 | Waypoint.offsetAliases = {
155 | 'bottom-in-view': function() {
156 | return this.context.innerHeight() - this.adapter.outerHeight()
157 | },
158 | 'right-in-view': function() {
159 | return this.context.innerWidth() - this.adapter.outerWidth()
160 | }
161 | }
162 |
163 | window.Waypoint = Waypoint
164 | }())
165 |
--------------------------------------------------------------------------------
/test/adapter-fn-spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | /* global
3 | * describe, it, beforeEach, afterEach, expect, spyOn, waits, runs,
4 | * waitsFor, loadFixtures, Waypoint
5 | */
6 |
7 | window.jQuery.each(window.jQuery.grep(Waypoint.adapters, function(adapter) {
8 | return 'jquery zepto'.indexOf(adapter.name) > -1
9 | }), function(i, adapter) {
10 | describe('$.fn extension for ' + adapter.name + ':', function() {
11 | var $, waypoints
12 |
13 | beforeEach(function() {
14 | $ = adapter.name === 'jquery' ? window.jQuery : window.Zepto
15 | Waypoint.Adapter = adapter.Adapter
16 | loadFixtures('standard.html')
17 | })
18 |
19 | afterEach(function() {
20 | $.each(waypoints, function(i, waypoint) {
21 | waypoint.destroy()
22 | })
23 | })
24 |
25 | describe('waypoint initialization', function() {
26 | it('uses the subject elements as the element option', function() {
27 | waypoints = $('.nearsame').waypoint(function() {})
28 | expect(waypoints[0].element.id).toEqual('near1')
29 | expect(waypoints[1].element.id).toEqual('near2')
30 | })
31 |
32 | it('returns an array of Waypoint instances', function() {
33 | waypoints = $('.nearsame').waypoint(function() {})
34 | expect($.isArray(waypoints)).toBeTruthy()
35 | expect(waypoints.length).toEqual(2)
36 | })
37 |
38 | it('can take the handler as the first parameter', function() {
39 | function handler() {}
40 | waypoints = $('#near1').waypoint(handler)
41 | expect(waypoints[0].callback).toBe(handler)
42 | })
43 | })
44 |
45 | describe('context option', function() {
46 | it('can be given a string selector', function() {
47 | waypoints = $('#inner3').waypoint({
48 | context: '#bottom',
49 | handler: function() {}
50 | })
51 | expect(waypoints[0].context.element).toBe($('#bottom')[0])
52 | })
53 | })
54 | })
55 | })
56 |
--------------------------------------------------------------------------------
/test/context-spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | /* global
3 | * describe, it, beforeEach, afterEach, expect, spyOn, runs,
4 | * loadFixtures, Waypoint
5 | */
6 |
7 | window.jQuery.each(Waypoint.adapters, function(i, adapter) {
8 | describe(adapter.name + ' adapter:', function() {
9 | describe('Waypoint.Context', function() {
10 | var $ = window.jQuery
11 | var currentDirection, $scroller, waypoint, $target, context, skipDestroy
12 |
13 | function setDirection(direction) {
14 | currentDirection = direction
15 | }
16 |
17 | beforeEach(function() {
18 | Waypoint.Adapter = adapter.Adapter
19 | loadFixtures('standard.html')
20 | $scroller = $(window)
21 | currentDirection = null
22 | skipDestroy = false
23 | $target = $('#same1')
24 | waypoint = new Waypoint({
25 | element: $target[0],
26 | handler: setDirection
27 | })
28 | context = waypoint.context
29 | })
30 |
31 | afterEach(function() {
32 | if (!skipDestroy) {
33 | waypoint.destroy()
34 | }
35 | $scroller.scrollTop(0).scrollLeft(0)
36 | })
37 |
38 | describe('#refresh', function() {
39 | it('updates trigger point of waypoints', function() {
40 | var top = $target.offset().top
41 | $target.css({
42 | top: top + 1
43 | })
44 | context.refresh()
45 | expect(waypoint.triggerPoint).toEqual(top + 1)
46 | })
47 |
48 | it('triggers down direction if waypoint crosses upwards', function() {
49 | $target.css('top', '-1px')
50 | context.refresh()
51 | expect(currentDirection).toEqual('down')
52 | })
53 |
54 | it('triggers up direction if waypoint crosses downwards', function() {
55 | $target.css('top', '-1px')
56 | context.refresh()
57 | $target.css('top', '0px')
58 | context.refresh()
59 | expect(currentDirection).toEqual('up')
60 | })
61 |
62 | it('returns the same context instance for chaining', function() {
63 | expect(context.refresh()).toEqual(context)
64 | })
65 | })
66 |
67 | describe('#destroy', function() {
68 | it('prevents further waypoint triggers', function() {
69 | skipDestroy = true
70 | context.destroy()
71 | $scroller.scrollTop($target.offset().top)
72 | expect(currentDirection).toBeNull()
73 | })
74 | })
75 |
76 | describe('Waypoint.Context.refreshAll()', function() {
77 | it('calls refresh on all contexts', function() {
78 | var secondWaypoint = new Waypoint({
79 | element: $('#inner3')[0],
80 | context: $('#bottom')[0],
81 | handler: function() {}
82 | })
83 | var secondContext = secondWaypoint.context
84 | spyOn(context, 'refresh')
85 | spyOn(secondContext, 'refresh')
86 | Waypoint.Context.refreshAll()
87 | expect(context.refresh).toHaveBeenCalled()
88 | expect(secondContext.refresh).toHaveBeenCalled()
89 | secondWaypoint.destroy()
90 | })
91 | })
92 | })
93 | })
94 | })
95 |
--------------------------------------------------------------------------------
/test/debug-spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | /* global
4 | * describe, it, beforeEach, afterEach, expect, spyOn,
5 | * loadFixtures, Waypoint
6 | */
7 |
8 | describe('Waypoints debug script', function() {
9 | var waypoint, element
10 |
11 | beforeEach(function() {
12 | loadFixtures('standard.html')
13 | })
14 |
15 | afterEach(function() {
16 | waypoint.destroy()
17 | })
18 |
19 | describe('display none detection', function() {
20 | beforeEach(function() {
21 | element = document.getElementById('same1')
22 | waypoint = new Waypoint({
23 | element: element,
24 | handler: function() {}
25 | })
26 | element.style.display = 'none'
27 | })
28 |
29 | it('logs a console error', function() {
30 | spyOn(console, 'error')
31 | waypoint.context.refresh()
32 | expect(console.error).toHaveBeenCalled()
33 | })
34 | })
35 |
36 | describe('display fixed positioning detection', function() {
37 | beforeEach(function() {
38 | element = document.getElementById('same1')
39 | waypoint = new Waypoint({
40 | element: element,
41 | handler: function() {}
42 | })
43 | element.style.position = 'fixed'
44 | })
45 |
46 | it('logs a console error', function() {
47 | spyOn(console, 'error')
48 | waypoint.context.refresh()
49 | expect(console.error).toHaveBeenCalled()
50 | })
51 | })
52 |
53 |
54 | describe('fixed position detection', function() {
55 |
56 | })
57 |
58 | describe('respect waypoint disabling', function() {
59 | beforeEach(function() {
60 | element = document.getElementById('same1')
61 | waypoint = new Waypoint({
62 | element: element,
63 | handler: function() {}
64 | })
65 | element.style.display = 'none'
66 | waypoint.disable()
67 | })
68 |
69 | it('does not log a console error', function() {
70 | spyOn(console, 'error')
71 | waypoint.context.refresh()
72 | expect(console.error.calls.length).toEqual(0)
73 | })
74 | })
75 | })
76 |
--------------------------------------------------------------------------------
/test/fixtures/infinite.html:
--------------------------------------------------------------------------------
1 |
11 |
12 |
25 |
--------------------------------------------------------------------------------
/test/fixtures/standard.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
14 |
15 |
16 |
17 |
81 |
--------------------------------------------------------------------------------
/test/fixtures/sticky.html:
--------------------------------------------------------------------------------
1 |
5 |
6 |
--------------------------------------------------------------------------------
/test/group-spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | /* global
3 | * describe, it, beforeEach, afterEach, expect, spyOn,
4 | * loadFixtures, Waypoint
5 | */
6 |
7 | window.jQuery.each(Waypoint.adapters, function(i, adapter) {
8 | describe(adapter.name + ' adapter:', function() {
9 | describe('Waypoint.Group', function() {
10 | var $ = window.jQuery
11 | var firstWaypoint, secondWaypoint, customGroupWaypoint, defaultGroup
12 |
13 | beforeEach(function() {
14 | Waypoint.Adapter = adapter.Adapter
15 | loadFixtures('standard.html')
16 | firstWaypoint = new Waypoint({
17 | element: $('#same1')[0],
18 | handler: function() {}
19 | })
20 | secondWaypoint = new Waypoint({
21 | element: $('#near1')[0],
22 | handler: function() {}
23 | })
24 | customGroupWaypoint = new Waypoint({
25 | element: $('#same2')[0],
26 | group: 'custom',
27 | handler: function() {}
28 | })
29 | defaultGroup = firstWaypoint.group
30 | })
31 |
32 | afterEach(function() {
33 | firstWaypoint.destroy()
34 | secondWaypoint.destroy()
35 | customGroupWaypoint.destroy()
36 | })
37 |
38 | describe('#previous(waypoint)', function() {
39 | it('returns previous waypoint based on trigger point', function() {
40 | expect(defaultGroup.previous(secondWaypoint)).toEqual(firstWaypoint)
41 | })
42 |
43 | it('returns null if on the first waypoint in the group', function() {
44 | expect(defaultGroup.previous(firstWaypoint)).toBeNull()
45 | })
46 | })
47 |
48 | describe('#next(waypoint)', function() {
49 | it('returns next waypoint based on trigger point', function() {
50 | expect(defaultGroup.next(firstWaypoint)).toEqual(secondWaypoint)
51 | })
52 |
53 | it('returns null if on the last waypoint in the group', function() {
54 | expect(defaultGroup.next(secondWaypoint)).toBeNull()
55 | })
56 | })
57 |
58 | describe('#first()', function() {
59 | it('returns the first waypoint based on trigger point', function() {
60 | expect(defaultGroup.first()).toEqual(firstWaypoint)
61 | })
62 | })
63 |
64 | describe('#last()', function() {
65 | it('returns the first waypoint based on trigger point', function() {
66 | expect(defaultGroup.last()).toEqual(secondWaypoint)
67 | })
68 | })
69 | })
70 | })
71 | })
72 |
--------------------------------------------------------------------------------
/test/infinite-spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | /* global
3 | * describe, it, beforeEach, afterEach, expect, spyOn, runs,
4 | * waitsFor, loadFixtures, Waypoint, jasmine
5 | */
6 |
7 | describe('Waypoint Sticky Shortcut', function() {
8 | var $ = window.jQuery
9 | var $scroller = $(window)
10 | var $container, $items, $more, waypoint, beforeSpy, afterSpy
11 |
12 | beforeEach(function() {
13 | loadFixtures('infinite.html')
14 | $items = $('.infinite-item')
15 | $container = $('.infinite-container')
16 | $more = $('.infinite-more-link')
17 | beforeSpy = jasmine.createSpy('on before callback')
18 | afterSpy = jasmine.createSpy('on after callback')
19 | })
20 |
21 | afterEach(function() {
22 | waypoint.destroy()
23 | $scroller.scrollTop(0)
24 | })
25 |
26 | it('returns an instance of the Waypoint.Infinite class', function() {
27 | waypoint = new Waypoint.Infinite({
28 | element: $container[0]
29 | })
30 | expect(waypoint instanceof Waypoint.Infinite).toBeTruthy()
31 | })
32 |
33 | describe('loading new pages', function() {
34 | beforeEach(function() {
35 | runs(function() {
36 | waypoint = new Waypoint.Infinite({
37 | element: $container[0],
38 | onBeforePageLoad: beforeSpy,
39 | onAfterPageLoad: afterSpy
40 | })
41 | $scroller.scrollTop(Waypoint.viewportHeight() - $container.height())
42 | })
43 | waitsFor(function() {
44 | return $('.infinite-container > .infinite-item').length > $items.length
45 | }, 'new items to load')
46 | })
47 |
48 | it('replaces the more link with the new more link', function() {
49 | expect($more[0]).not.toEqual($('.infinite-more-link')[0])
50 | })
51 |
52 | it('fires the before callback', function() {
53 | expect(beforeSpy.callCount).toBeTruthy()
54 | })
55 |
56 | it('fires the after callback', function() {
57 | expect(afterSpy.callCount).toBeTruthy()
58 | expect(afterSpy).toHaveBeenCalledWith(jasmine.any(Object))
59 | })
60 | })
61 |
62 | describe('when there is no more link on initialization', function() {
63 | beforeEach(function() {
64 | $more.remove()
65 | waypoint = new Waypoint.Infinite({
66 | element: $container[0]
67 | })
68 | })
69 |
70 | it('does not create the waypoint', function() {
71 | expect(waypoint.waypoint).toBeFalsy()
72 | })
73 | })
74 | })
75 |
--------------------------------------------------------------------------------
/test/inview-spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | /* global
3 | * describe, it, beforeEach, afterEach, expect, spyOn, waits, runs,
4 | * waitsFor, loadFixtures, Waypoint
5 | */
6 |
7 | window.jQuery.each(Waypoint.adapters, function(i, adapter) {
8 | describe(adapter.name + ' adapter:', function() {
9 | describe('Waypoints Inview Shortcut', function() {
10 | var $ = window.jQuery
11 | var standard = 50
12 | var $scroller = $(window)
13 | var $target, waypoint, hits, callbackContext
14 |
15 | function setsTrue(key) {
16 | return function() {
17 | callbackContext = this
18 | hits[key] = true
19 | }
20 | }
21 |
22 | function toBeTrue(key) {
23 | return function() {
24 | return hits[key]
25 | }
26 | }
27 |
28 | beforeEach(function() {
29 | Waypoint.Adapter = adapter.Adapter
30 | loadFixtures('standard.html')
31 | $target = $('#near2')
32 | hits = {}
33 | })
34 |
35 | afterEach(function() {
36 | waypoint.destroy()
37 | $scroller.scrollTop(0).scrollLeft(0)
38 | })
39 |
40 | describe('vertical', function() {
41 | beforeEach(function() {
42 | waypoint = new Waypoint.Inview({
43 | element: $target[0],
44 | enter: setsTrue('enter'),
45 | entered: setsTrue('entered'),
46 | exit: setsTrue('exit'),
47 | exited: setsTrue('exited')
48 | })
49 | })
50 |
51 | describe('enter callback', function() {
52 | it('triggers when element starts entering from below', function() {
53 | runs(function() {
54 | var top = $target.offset().top
55 | $scroller.scrollTop(top - Waypoint.viewportHeight())
56 | })
57 | waitsFor(toBeTrue('enter'), 'enter to trigger')
58 | runs(function() {
59 | expect(callbackContext).toEqual(waypoint)
60 | })
61 | })
62 |
63 | it('triggers when element starts entering from above', function() {
64 | runs(function() {
65 | $scroller.scrollTop($target.offset().top + $target.outerHeight())
66 | })
67 | waits(standard)
68 | runs(function() {
69 | hits.enter = false
70 | $scroller.scrollTop($scroller.scrollTop() - 1)
71 | })
72 | waitsFor(toBeTrue('enter'), 'enter to trigger')
73 | })
74 | })
75 |
76 | describe('entered callback', function() {
77 | it('triggers when element finishes entering from below', function() {
78 | runs(function() {
79 | var top = $target.offset().top
80 | var viewportHeight = Waypoint.viewportHeight()
81 | var elementHeight = $target.outerHeight()
82 | $scroller.scrollTop(top - viewportHeight + elementHeight)
83 | })
84 | waitsFor(toBeTrue('entered'), 'entered to trigger')
85 | runs(function() {
86 | expect(callbackContext).toEqual(waypoint)
87 | })
88 | })
89 |
90 | it('triggers when element finishes entering from above', function() {
91 | runs(function() {
92 | $scroller.scrollTop($target.offset().top)
93 | })
94 | waits(standard)
95 | runs(function() {
96 | hits.entered = false
97 | $scroller.scrollTop($scroller.scrollTop() - 1)
98 | })
99 | waitsFor(toBeTrue('entered'), 'entered to trigger')
100 | })
101 | })
102 |
103 | describe('exit callback', function() {
104 | it('triggers when element starts leaving below', function() {
105 | runs(function() {
106 | var top = $target.offset().top
107 | var viewportHeight = Waypoint.viewportHeight()
108 | var elementHeight = $target.outerHeight()
109 | $scroller.scrollTop(top - viewportHeight + elementHeight)
110 | })
111 | waits(standard)
112 | runs(function() {
113 | expect(hits.exit).toBeFalsy()
114 | $scroller.scrollTop($scroller.scrollTop() - 1)
115 | })
116 | waitsFor(toBeTrue('exit'), 'exit to trigger')
117 | })
118 |
119 | it('triggers when element starts leaving above', function() {
120 | runs(function() {
121 | $scroller.scrollTop($target.offset().top)
122 | })
123 | waitsFor(toBeTrue('exit'), 'exit to trigger')
124 | runs(function() {
125 | expect(callbackContext).toEqual(waypoint)
126 | })
127 | })
128 | })
129 |
130 | describe('exited callback', function() {
131 | it('triggers when element finishes exiting below', function() {
132 | runs(function() {
133 | var top = $target.offset().top
134 | $scroller.scrollTop(top - Waypoint.viewportHeight())
135 | })
136 | waits(standard)
137 | runs(function() {
138 | $scroller.scrollTop($scroller.scrollTop() - 1)
139 | })
140 | waitsFor(toBeTrue('exited'), 'exited to trigger')
141 | })
142 |
143 | it('triggers when element finishes exiting above', function() {
144 | runs(function() {
145 | $scroller.scrollTop($target.offset().top + $target.outerHeight())
146 | })
147 | waitsFor(toBeTrue('exited'), 'exited to trigger')
148 | runs(function() {
149 | expect(callbackContext).toEqual(waypoint)
150 | })
151 | })
152 | })
153 | })
154 |
155 | describe('horizontal', function() {
156 | beforeEach(function() {
157 | waypoint = new Waypoint.Inview({
158 | horizontal: true,
159 | element: $target[0],
160 | enter: setsTrue('enter'),
161 | entered: setsTrue('entered'),
162 | exit: setsTrue('exit'),
163 | exited: setsTrue('exited')
164 | })
165 | })
166 |
167 | describe('enter callback', function() {
168 | it('triggers when element starts entering from right', function() {
169 | runs(function() {
170 | $scroller.scrollLeft($target.offset().left - $scroller.width())
171 | })
172 | waitsFor(toBeTrue('enter'), 'enter to trigger')
173 | })
174 |
175 | it('triggers when element starts entering from left', function() {
176 | runs(function() {
177 | var left = $target.offset().left
178 | $scroller.scrollLeft(left + $target.outerWidth())
179 | })
180 | waits(standard)
181 | runs(function() {
182 | hits.enter = false
183 | $scroller.scrollLeft($scroller.scrollLeft() - 1)
184 | })
185 | waitsFor(toBeTrue('enter'), 'enter to trigger')
186 | })
187 | })
188 |
189 | describe('entered callback', function() {
190 | it('triggers when element finishes entering from right', function() {
191 | runs(function() {
192 | var left = $target.offset().left
193 | var viewportWidth = $scroller.width()
194 | var elementWidth = $target.outerWidth()
195 | $scroller.scrollLeft(left - viewportWidth + elementWidth)
196 | })
197 | waitsFor(toBeTrue('entered'), 'entered to trigger')
198 | })
199 |
200 | it('triggers when element finishes entering from left', function() {
201 | runs(function() {
202 | $scroller.scrollLeft($target.offset().left)
203 | })
204 | waits(standard)
205 | runs(function() {
206 | hits.entered = false
207 | $scroller.scrollLeft($scroller.scrollLeft() - 1)
208 | })
209 | waitsFor(toBeTrue('entered'), 'entered to trigger')
210 | })
211 | })
212 |
213 | describe('exit callback', function() {
214 | it('triggers when element starts leaving on the right', function() {
215 | runs(function() {
216 | var left = $target.offset().left
217 | var viewportWidth = $scroller.width()
218 | var elementWidth = $target.outerWidth()
219 | $scroller.scrollLeft(left - viewportWidth + elementWidth)
220 | })
221 | waits(standard)
222 | runs(function() {
223 | expect(hits.exit).toBeFalsy()
224 | $scroller.scrollLeft($scroller.scrollLeft() - 1)
225 | })
226 | waitsFor(toBeTrue('exit'), 'exit to trigger')
227 | })
228 |
229 | it('triggers when element starts leaving on the left', function() {
230 | runs(function() {
231 | $scroller.scrollLeft($target.offset().left)
232 | })
233 | waitsFor(toBeTrue('exit'), 'exit to trigger')
234 | })
235 | })
236 |
237 | describe('exited callback', function() {
238 | it('triggers when element finishes exiting to the right', function() {
239 | runs(function() {
240 | var left = $target.offset().left
241 | $scroller.scrollLeft(left - $scroller.width())
242 | })
243 | waitsFor(toBeTrue('enter'), 'enter to trigger')
244 | runs(function() {
245 | $scroller.scrollLeft($scroller.scrollLeft() - 1)
246 | })
247 | waitsFor(toBeTrue('exited'), 'exited to trigger')
248 | })
249 |
250 | it('triggers when element finishes exiting to the left', function() {
251 | runs(function() {
252 | var left = $target.offset().left
253 | $scroller.scrollLeft(left + $target.outerWidth())
254 | })
255 | waitsFor(toBeTrue('exited'), 'exited to trigger')
256 | })
257 | })
258 | })
259 |
260 | describe('disabled', function() {
261 | beforeEach(function() {
262 | waypoint = new Waypoint.Inview({
263 | element: $target[0],
264 | enabled: false,
265 | enter: setsTrue('enter'),
266 | entered: setsTrue('entered'),
267 | exit: setsTrue('exit'),
268 | exited: setsTrue('exited')
269 | })
270 | })
271 |
272 | it('starts disabled', function() {
273 | $.each(waypoint.waypoints, function(i, wp) {
274 | expect(wp.enabled).toEqual(false)
275 | })
276 | })
277 |
278 | describe('#enable', function() {
279 | it('enables all waypoints', function() {
280 | waypoint.enable()
281 | $.each(waypoint.waypoints, function(i, wp) {
282 | expect(wp.enabled).toEqual(true)
283 | })
284 | })
285 | })
286 |
287 | describe('#disable', function() {
288 | it('disables all waypoints', function() {
289 | waypoint.enable()
290 | waypoint.disable()
291 | $.each(waypoint.waypoints, function(i, wp) {
292 | expect(wp.enabled).toEqual(false)
293 | })
294 | })
295 | })
296 | })
297 | })
298 | })
299 | })
300 |
--------------------------------------------------------------------------------
/test/lib/jasmine-html.js:
--------------------------------------------------------------------------------
1 | jasmine.HtmlReporterHelpers = {};
2 |
3 | jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) {
4 | var el = document.createElement(type);
5 |
6 | for (var i = 2; i < arguments.length; i++) {
7 | var child = arguments[i];
8 |
9 | if (typeof child === 'string') {
10 | el.appendChild(document.createTextNode(child));
11 | } else {
12 | if (child) {
13 | el.appendChild(child);
14 | }
15 | }
16 | }
17 |
18 | for (var attr in attrs) {
19 | if (attr == "className") {
20 | el[attr] = attrs[attr];
21 | } else {
22 | el.setAttribute(attr, attrs[attr]);
23 | }
24 | }
25 |
26 | return el;
27 | };
28 |
29 | jasmine.HtmlReporterHelpers.getSpecStatus = function(child) {
30 | var results = child.results();
31 | var status = results.passed() ? 'passed' : 'failed';
32 | if (results.skipped) {
33 | status = 'skipped';
34 | }
35 |
36 | return status;
37 | };
38 |
39 | jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) {
40 | var parentDiv = this.dom.summary;
41 | var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
42 | var parent = child[parentSuite];
43 |
44 | if (parent) {
45 | if (typeof this.views.suites[parent.id] == 'undefined') {
46 | this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views);
47 | }
48 | parentDiv = this.views.suites[parent.id].element;
49 | }
50 |
51 | parentDiv.appendChild(childElement);
52 | };
53 |
54 |
55 | jasmine.HtmlReporterHelpers.addHelpers = function(ctor) {
56 | for(var fn in jasmine.HtmlReporterHelpers) {
57 | ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
58 | }
59 | };
60 |
61 | jasmine.HtmlReporter = function(_doc) {
62 | var self = this;
63 | var doc = _doc || window.document;
64 |
65 | var reporterView;
66 |
67 | var dom = {};
68 |
69 | // Jasmine Reporter Public Interface
70 | self.logRunningSpecs = false;
71 |
72 | self.reportRunnerStarting = function(runner) {
73 | var specs = runner.specs() || [];
74 |
75 | if (specs.length == 0) {
76 | return;
77 | }
78 |
79 | createReporterDom(runner.env.versionString());
80 | doc.body.appendChild(dom.reporter);
81 | setExceptionHandling();
82 |
83 | reporterView = new jasmine.HtmlReporter.ReporterView(dom);
84 | reporterView.addSpecs(specs, self.specFilter);
85 | };
86 |
87 | self.reportRunnerResults = function(runner) {
88 | reporterView && reporterView.complete();
89 | };
90 |
91 | self.reportSuiteResults = function(suite) {
92 | reporterView.suiteComplete(suite);
93 | };
94 |
95 | self.reportSpecStarting = function(spec) {
96 | if (self.logRunningSpecs) {
97 | self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
98 | }
99 | };
100 |
101 | self.reportSpecResults = function(spec) {
102 | reporterView.specComplete(spec);
103 | };
104 |
105 | self.log = function() {
106 | var console = jasmine.getGlobal().console;
107 | if (console && console.log) {
108 | if (console.log.apply) {
109 | console.log.apply(console, arguments);
110 | } else {
111 | console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
112 | }
113 | }
114 | };
115 |
116 | self.specFilter = function(spec) {
117 | if (!focusedSpecName()) {
118 | return true;
119 | }
120 |
121 | return spec.getFullName().indexOf(focusedSpecName()) === 0;
122 | };
123 |
124 | return self;
125 |
126 | function focusedSpecName() {
127 | var specName;
128 |
129 | (function memoizeFocusedSpec() {
130 | if (specName) {
131 | return;
132 | }
133 |
134 | var paramMap = [];
135 | var params = jasmine.HtmlReporter.parameters(doc);
136 |
137 | for (var i = 0; i < params.length; i++) {
138 | var p = params[i].split('=');
139 | paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
140 | }
141 |
142 | specName = paramMap.spec;
143 | })();
144 |
145 | return specName;
146 | }
147 |
148 | function createReporterDom(version) {
149 | dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' },
150 | dom.banner = self.createDom('div', { className: 'banner' },
151 | self.createDom('span', { className: 'title' }, "Jasmine "),
152 | self.createDom('span', { className: 'version' }, version)),
153 |
154 | dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}),
155 | dom.alert = self.createDom('div', {className: 'alert'},
156 | self.createDom('span', { className: 'exceptions' },
157 | self.createDom('label', { className: 'label', 'for': 'no_try_catch' }, 'No try/catch'),
158 | self.createDom('input', { id: 'no_try_catch', type: 'checkbox' }))),
159 | dom.results = self.createDom('div', {className: 'results'},
160 | dom.summary = self.createDom('div', { className: 'summary' }),
161 | dom.details = self.createDom('div', { id: 'details' }))
162 | );
163 | }
164 |
165 | function noTryCatch() {
166 | return window.location.search.match(/catch=false/);
167 | }
168 |
169 | function searchWithCatch() {
170 | var params = jasmine.HtmlReporter.parameters(window.document);
171 | var removed = false;
172 | var i = 0;
173 |
174 | while (!removed && i < params.length) {
175 | if (params[i].match(/catch=/)) {
176 | params.splice(i, 1);
177 | removed = true;
178 | }
179 | i++;
180 | }
181 | if (jasmine.CATCH_EXCEPTIONS) {
182 | params.push("catch=false");
183 | }
184 |
185 | return params.join("&");
186 | }
187 |
188 | function setExceptionHandling() {
189 | var chxCatch = document.getElementById('no_try_catch');
190 |
191 | if (noTryCatch()) {
192 | chxCatch.setAttribute('checked', true);
193 | jasmine.CATCH_EXCEPTIONS = false;
194 | }
195 | chxCatch.onclick = function() {
196 | window.location.search = searchWithCatch();
197 | };
198 | }
199 | };
200 | jasmine.HtmlReporter.parameters = function(doc) {
201 | var paramStr = doc.location.search.substring(1);
202 | var params = [];
203 |
204 | if (paramStr.length > 0) {
205 | params = paramStr.split('&');
206 | }
207 | return params;
208 | }
209 | jasmine.HtmlReporter.sectionLink = function(sectionName) {
210 | var link = '?';
211 | var params = [];
212 |
213 | if (sectionName) {
214 | params.push('spec=' + encodeURIComponent(sectionName));
215 | }
216 | if (!jasmine.CATCH_EXCEPTIONS) {
217 | params.push("catch=false");
218 | }
219 | if (params.length > 0) {
220 | link += params.join("&");
221 | }
222 |
223 | return link;
224 | };
225 | jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);
226 | jasmine.HtmlReporter.ReporterView = function(dom) {
227 | this.startedAt = new Date();
228 | this.runningSpecCount = 0;
229 | this.completeSpecCount = 0;
230 | this.passedCount = 0;
231 | this.failedCount = 0;
232 | this.skippedCount = 0;
233 |
234 | this.createResultsMenu = function() {
235 | this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'},
236 | this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'),
237 | ' | ',
238 | this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing'));
239 |
240 | this.summaryMenuItem.onclick = function() {
241 | dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, '');
242 | };
243 |
244 | this.detailsMenuItem.onclick = function() {
245 | showDetails();
246 | };
247 | };
248 |
249 | this.addSpecs = function(specs, specFilter) {
250 | this.totalSpecCount = specs.length;
251 |
252 | this.views = {
253 | specs: {},
254 | suites: {}
255 | };
256 |
257 | for (var i = 0; i < specs.length; i++) {
258 | var spec = specs[i];
259 | this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views);
260 | if (specFilter(spec)) {
261 | this.runningSpecCount++;
262 | }
263 | }
264 | };
265 |
266 | this.specComplete = function(spec) {
267 | this.completeSpecCount++;
268 |
269 | if (isUndefined(this.views.specs[spec.id])) {
270 | this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom);
271 | }
272 |
273 | var specView = this.views.specs[spec.id];
274 |
275 | switch (specView.status()) {
276 | case 'passed':
277 | this.passedCount++;
278 | break;
279 |
280 | case 'failed':
281 | this.failedCount++;
282 | break;
283 |
284 | case 'skipped':
285 | this.skippedCount++;
286 | break;
287 | }
288 |
289 | specView.refresh();
290 | this.refresh();
291 | };
292 |
293 | this.suiteComplete = function(suite) {
294 | var suiteView = this.views.suites[suite.id];
295 | if (isUndefined(suiteView)) {
296 | return;
297 | }
298 | suiteView.refresh();
299 | };
300 |
301 | this.refresh = function() {
302 |
303 | if (isUndefined(this.resultsMenu)) {
304 | this.createResultsMenu();
305 | }
306 |
307 | // currently running UI
308 | if (isUndefined(this.runningAlert)) {
309 | this.runningAlert = this.createDom('a', { href: jasmine.HtmlReporter.sectionLink(), className: "runningAlert bar" });
310 | dom.alert.appendChild(this.runningAlert);
311 | }
312 | this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount);
313 |
314 | // skipped specs UI
315 | if (isUndefined(this.skippedAlert)) {
316 | this.skippedAlert = this.createDom('a', { href: jasmine.HtmlReporter.sectionLink(), className: "skippedAlert bar" });
317 | }
318 |
319 | this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
320 |
321 | if (this.skippedCount === 1 && isDefined(dom.alert)) {
322 | dom.alert.appendChild(this.skippedAlert);
323 | }
324 |
325 | // passing specs UI
326 | if (isUndefined(this.passedAlert)) {
327 | this.passedAlert = this.createDom('span', { href: jasmine.HtmlReporter.sectionLink(), className: "passingAlert bar" });
328 | }
329 | this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount);
330 |
331 | // failing specs UI
332 | if (isUndefined(this.failedAlert)) {
333 | this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"});
334 | }
335 | this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount);
336 |
337 | if (this.failedCount === 1 && isDefined(dom.alert)) {
338 | dom.alert.appendChild(this.failedAlert);
339 | dom.alert.appendChild(this.resultsMenu);
340 | }
341 |
342 | // summary info
343 | this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount);
344 | this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing";
345 | };
346 |
347 | this.complete = function() {
348 | dom.alert.removeChild(this.runningAlert);
349 |
350 | this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
351 |
352 | if (this.failedCount === 0) {
353 | dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount)));
354 | } else {
355 | showDetails();
356 | }
357 |
358 | dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"));
359 | };
360 |
361 | return this;
362 |
363 | function showDetails() {
364 | if (dom.reporter.className.search(/showDetails/) === -1) {
365 | dom.reporter.className += " showDetails";
366 | }
367 | }
368 |
369 | function isUndefined(obj) {
370 | return typeof obj === 'undefined';
371 | }
372 |
373 | function isDefined(obj) {
374 | return !isUndefined(obj);
375 | }
376 |
377 | function specPluralizedFor(count) {
378 | var str = count + " spec";
379 | if (count > 1) {
380 | str += "s"
381 | }
382 | return str;
383 | }
384 |
385 | };
386 |
387 | jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView);
388 |
389 |
390 | jasmine.HtmlReporter.SpecView = function(spec, dom, views) {
391 | this.spec = spec;
392 | this.dom = dom;
393 | this.views = views;
394 |
395 | this.symbol = this.createDom('li', { className: 'pending' });
396 | this.dom.symbolSummary.appendChild(this.symbol);
397 |
398 | this.summary = this.createDom('div', { className: 'specSummary' },
399 | this.createDom('a', {
400 | className: 'description',
401 | href: jasmine.HtmlReporter.sectionLink(this.spec.getFullName()),
402 | title: this.spec.getFullName()
403 | }, this.spec.description)
404 | );
405 |
406 | this.detail = this.createDom('div', { className: 'specDetail' },
407 | this.createDom('a', {
408 | className: 'description',
409 | href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
410 | title: this.spec.getFullName()
411 | }, this.spec.getFullName())
412 | );
413 | };
414 |
415 | jasmine.HtmlReporter.SpecView.prototype.status = function() {
416 | return this.getSpecStatus(this.spec);
417 | };
418 |
419 | jasmine.HtmlReporter.SpecView.prototype.refresh = function() {
420 | this.symbol.className = this.status();
421 |
422 | switch (this.status()) {
423 | case 'skipped':
424 | break;
425 |
426 | case 'passed':
427 | this.appendSummaryToSuiteDiv();
428 | break;
429 |
430 | case 'failed':
431 | this.appendSummaryToSuiteDiv();
432 | this.appendFailureDetail();
433 | break;
434 | }
435 | };
436 |
437 | jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() {
438 | this.summary.className += ' ' + this.status();
439 | this.appendToSummary(this.spec, this.summary);
440 | };
441 |
442 | jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() {
443 | this.detail.className += ' ' + this.status();
444 |
445 | var resultItems = this.spec.results().getItems();
446 | var messagesDiv = this.createDom('div', { className: 'messages' });
447 |
448 | for (var i = 0; i < resultItems.length; i++) {
449 | var result = resultItems[i];
450 |
451 | if (result.type == 'log') {
452 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
453 | } else if (result.type == 'expect' && result.passed && !result.passed()) {
454 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
455 |
456 | if (result.trace.stack) {
457 | messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
458 | }
459 | }
460 | }
461 |
462 | if (messagesDiv.childNodes.length > 0) {
463 | this.detail.appendChild(messagesDiv);
464 | this.dom.details.appendChild(this.detail);
465 | }
466 | };
467 |
468 | jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) {
469 | this.suite = suite;
470 | this.dom = dom;
471 | this.views = views;
472 |
473 | this.element = this.createDom('div', { className: 'suite' },
474 | this.createDom('a', { className: 'description', href: jasmine.HtmlReporter.sectionLink(this.suite.getFullName()) }, this.suite.description)
475 | );
476 |
477 | this.appendToSummary(this.suite, this.element);
478 | };
479 |
480 | jasmine.HtmlReporter.SuiteView.prototype.status = function() {
481 | return this.getSpecStatus(this.suite);
482 | };
483 |
484 | jasmine.HtmlReporter.SuiteView.prototype.refresh = function() {
485 | this.element.className += " " + this.status();
486 | };
487 |
488 | jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView);
489 |
490 | /* @deprecated Use jasmine.HtmlReporter instead
491 | */
492 | jasmine.TrivialReporter = function(doc) {
493 | this.document = doc || document;
494 | this.suiteDivs = {};
495 | this.logRunningSpecs = false;
496 | };
497 |
498 | jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
499 | var el = document.createElement(type);
500 |
501 | for (var i = 2; i < arguments.length; i++) {
502 | var child = arguments[i];
503 |
504 | if (typeof child === 'string') {
505 | el.appendChild(document.createTextNode(child));
506 | } else {
507 | if (child) { el.appendChild(child); }
508 | }
509 | }
510 |
511 | for (var attr in attrs) {
512 | if (attr == "className") {
513 | el[attr] = attrs[attr];
514 | } else {
515 | el.setAttribute(attr, attrs[attr]);
516 | }
517 | }
518 |
519 | return el;
520 | };
521 |
522 | jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
523 | var showPassed, showSkipped;
524 |
525 | this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' },
526 | this.createDom('div', { className: 'banner' },
527 | this.createDom('div', { className: 'logo' },
528 | this.createDom('span', { className: 'title' }, "Jasmine"),
529 | this.createDom('span', { className: 'version' }, runner.env.versionString())),
530 | this.createDom('div', { className: 'options' },
531 | "Show ",
532 | showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
533 | this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
534 | showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
535 | this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
536 | )
537 | ),
538 |
539 | this.runnerDiv = this.createDom('div', { className: 'runner running' },
540 | this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
541 | this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
542 | this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
543 | );
544 |
545 | this.document.body.appendChild(this.outerDiv);
546 |
547 | var suites = runner.suites();
548 | for (var i = 0; i < suites.length; i++) {
549 | var suite = suites[i];
550 | var suiteDiv = this.createDom('div', { className: 'suite' },
551 | this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
552 | this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
553 | this.suiteDivs[suite.id] = suiteDiv;
554 | var parentDiv = this.outerDiv;
555 | if (suite.parentSuite) {
556 | parentDiv = this.suiteDivs[suite.parentSuite.id];
557 | }
558 | parentDiv.appendChild(suiteDiv);
559 | }
560 |
561 | this.startedAt = new Date();
562 |
563 | var self = this;
564 | showPassed.onclick = function(evt) {
565 | if (showPassed.checked) {
566 | self.outerDiv.className += ' show-passed';
567 | } else {
568 | self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
569 | }
570 | };
571 |
572 | showSkipped.onclick = function(evt) {
573 | if (showSkipped.checked) {
574 | self.outerDiv.className += ' show-skipped';
575 | } else {
576 | self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
577 | }
578 | };
579 | };
580 |
581 | jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
582 | var results = runner.results();
583 | var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
584 | this.runnerDiv.setAttribute("class", className);
585 | //do it twice for IE
586 | this.runnerDiv.setAttribute("className", className);
587 | var specs = runner.specs();
588 | var specCount = 0;
589 | for (var i = 0; i < specs.length; i++) {
590 | if (this.specFilter(specs[i])) {
591 | specCount++;
592 | }
593 | }
594 | var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
595 | message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
596 | this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
597 |
598 | this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
599 | };
600 |
601 | jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
602 | var results = suite.results();
603 | var status = results.passed() ? 'passed' : 'failed';
604 | if (results.totalCount === 0) { // todo: change this to check results.skipped
605 | status = 'skipped';
606 | }
607 | this.suiteDivs[suite.id].className += " " + status;
608 | };
609 |
610 | jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
611 | if (this.logRunningSpecs) {
612 | this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
613 | }
614 | };
615 |
616 | jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
617 | var results = spec.results();
618 | var status = results.passed() ? 'passed' : 'failed';
619 | if (results.skipped) {
620 | status = 'skipped';
621 | }
622 | var specDiv = this.createDom('div', { className: 'spec ' + status },
623 | this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
624 | this.createDom('a', {
625 | className: 'description',
626 | href: '?spec=' + encodeURIComponent(spec.getFullName()),
627 | title: spec.getFullName()
628 | }, spec.description));
629 |
630 |
631 | var resultItems = results.getItems();
632 | var messagesDiv = this.createDom('div', { className: 'messages' });
633 | for (var i = 0; i < resultItems.length; i++) {
634 | var result = resultItems[i];
635 |
636 | if (result.type == 'log') {
637 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
638 | } else if (result.type == 'expect' && result.passed && !result.passed()) {
639 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
640 |
641 | if (result.trace.stack) {
642 | messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
643 | }
644 | }
645 | }
646 |
647 | if (messagesDiv.childNodes.length > 0) {
648 | specDiv.appendChild(messagesDiv);
649 | }
650 |
651 | this.suiteDivs[spec.suite.id].appendChild(specDiv);
652 | };
653 |
654 | jasmine.TrivialReporter.prototype.log = function() {
655 | var console = jasmine.getGlobal().console;
656 | if (console && console.log) {
657 | if (console.log.apply) {
658 | console.log.apply(console, arguments);
659 | } else {
660 | console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
661 | }
662 | }
663 | };
664 |
665 | jasmine.TrivialReporter.prototype.getLocation = function() {
666 | return this.document.location;
667 | };
668 |
669 | jasmine.TrivialReporter.prototype.specFilter = function(spec) {
670 | var paramMap = {};
671 | var params = this.getLocation().search.substring(1).split('&');
672 | for (var i = 0; i < params.length; i++) {
673 | var p = params[i].split('=');
674 | paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
675 | }
676 |
677 | if (!paramMap.spec) {
678 | return true;
679 | }
680 | return spec.getFullName().indexOf(paramMap.spec) === 0;
681 | };
682 |
--------------------------------------------------------------------------------
/test/lib/jasmine.css:
--------------------------------------------------------------------------------
1 | body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
2 |
3 | #HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
4 | #HTMLReporter a { text-decoration: none; }
5 | #HTMLReporter a:hover { text-decoration: underline; }
6 | #HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
7 | #HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
8 | #HTMLReporter #jasmine_content { position: fixed; right: 100%; }
9 | #HTMLReporter .version { color: #aaaaaa; }
10 | #HTMLReporter .banner { margin-top: 14px; }
11 | #HTMLReporter .duration { color: #aaaaaa; float: right; }
12 | #HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
13 | #HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
14 | #HTMLReporter .symbolSummary li.passed { font-size: 14px; }
15 | #HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
16 | #HTMLReporter .symbolSummary li.failed { line-height: 9px; }
17 | #HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
18 | #HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
19 | #HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
20 | #HTMLReporter .symbolSummary li.pending { line-height: 11px; }
21 | #HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
22 | #HTMLReporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; }
23 | #HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
24 | #HTMLReporter .runningAlert { background-color: #666666; }
25 | #HTMLReporter .skippedAlert { background-color: #aaaaaa; }
26 | #HTMLReporter .skippedAlert:first-child { background-color: #333333; }
27 | #HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
28 | #HTMLReporter .passingAlert { background-color: #a6b779; }
29 | #HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
30 | #HTMLReporter .failingAlert { background-color: #cf867e; }
31 | #HTMLReporter .failingAlert:first-child { background-color: #b03911; }
32 | #HTMLReporter .results { margin-top: 14px; }
33 | #HTMLReporter #details { display: none; }
34 | #HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
35 | #HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
36 | #HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
37 | #HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
38 | #HTMLReporter.showDetails .summary { display: none; }
39 | #HTMLReporter.showDetails #details { display: block; }
40 | #HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
41 | #HTMLReporter .summary { margin-top: 14px; }
42 | #HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
43 | #HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
44 | #HTMLReporter .summary .specSummary.failed a { color: #b03911; }
45 | #HTMLReporter .description + .suite { margin-top: 0; }
46 | #HTMLReporter .suite { margin-top: 14px; }
47 | #HTMLReporter .suite a { color: #333333; }
48 | #HTMLReporter #details .specDetail { margin-bottom: 28px; }
49 | #HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
50 | #HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
51 | #HTMLReporter .resultMessage span.result { display: block; }
52 | #HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
53 |
54 | #TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
55 | #TrivialReporter a:visited, #TrivialReporter a { color: #303; }
56 | #TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
57 | #TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
58 | #TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
59 | #TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
60 | #TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
61 | #TrivialReporter .runner.running { background-color: yellow; }
62 | #TrivialReporter .options { text-align: right; font-size: .8em; }
63 | #TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
64 | #TrivialReporter .suite .suite { margin: 5px; }
65 | #TrivialReporter .suite.passed { background-color: #dfd; }
66 | #TrivialReporter .suite.failed { background-color: #fdd; }
67 | #TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
68 | #TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
69 | #TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
70 | #TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
71 | #TrivialReporter .spec.skipped { background-color: #bbb; }
72 | #TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
73 | #TrivialReporter .passed { background-color: #cfc; display: none; }
74 | #TrivialReporter .failed { background-color: #fbb; }
75 | #TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
76 | #TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
77 | #TrivialReporter .resultMessage .mismatch { color: black; }
78 | #TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
79 | #TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
80 | #TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
81 | #TrivialReporter #jasmine_content { position: fixed; right: 100%; }
82 | #TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }
83 |
--------------------------------------------------------------------------------
/test/lib/testloader.js:
--------------------------------------------------------------------------------
1 | function testLoader(){
2 | var jasmineEnv = jasmine.getEnv();
3 | jasmineEnv.updateInterval = 1000;
4 |
5 | var htmlReporter = new jasmine.HtmlReporter();
6 |
7 | jasmineEnv.addReporter(htmlReporter);
8 |
9 | jasmineEnv.specFilter = function(spec) {
10 | return htmlReporter.specFilter(spec);
11 | };
12 |
13 | var currentWindowOnload = window.onload;
14 |
15 | window.onload = function() {
16 | var count = 0;
17 | var loadCoffee = function(files) {
18 | for (var i = 0, len = files.length; i < len; i++) {
19 | count++;
20 | CoffeeScript.load(files[i], function() {
21 | count--;
22 | if (!count) {
23 | jasmine.getFixtures().fixturesPath = 'fixtures';
24 | execJasmine();
25 | }
26 | });
27 | }
28 | };
29 |
30 | if (currentWindowOnload) {
31 | currentWindowOnload();
32 | }
33 | loadCoffee([
34 | 'waypoints.coffee',
35 | 'infinite.coffee',
36 | 'sticky.coffee'
37 | ]);
38 | };
39 |
40 | function execJasmine() {
41 | jasmineEnv.execute();
42 | }
43 |
44 | if (document.readyState === 'complete'){
45 | window.onload();
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/test/settings.js:
--------------------------------------------------------------------------------
1 | /* global jasmine, Waypoint */
2 |
3 | 'use strict'
4 |
5 | jasmine.getFixtures().fixturesPath = 'test/fixtures'
6 | jasmine.getEnv().defaultTimeoutInterval = 1000
7 | Waypoint.requestAnimationFrame = function(callback) {
8 | callback()
9 | }
10 |
--------------------------------------------------------------------------------
/test/sticky-spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | /* global
3 | * describe, it, beforeEach, afterEach, expect, spyOn, waits, runs,
4 | * waitsFor, loadFixtures, Waypoint, jasmine
5 | */
6 |
7 | describe('Waypoint Sticky Shortcut', function() {
8 | var $ = window.jQuery
9 | var $scroller = $(window)
10 | var $sticky, waypoint, handlerSpy
11 |
12 | beforeEach(function() {
13 | loadFixtures('sticky.html')
14 | $sticky = $('.sticky')
15 | })
16 |
17 | describe('with default options', function() {
18 | beforeEach(function() {
19 | handlerSpy = jasmine.createSpy('on handler')
20 | waypoint = new Waypoint.Sticky({
21 | element: $sticky[0],
22 | handler: handlerSpy
23 | })
24 | })
25 |
26 | afterEach(function() {
27 | if (waypoint) {
28 | waypoint.destroy()
29 | }
30 | $scroller.scrollTop(0)
31 | })
32 |
33 | describe('on init', function() {
34 | afterEach(function() {
35 | waypoint.destroy()
36 | })
37 |
38 | it('returns an instance of the Waypoint.Sticky class', function() {
39 | expect(waypoint instanceof Waypoint.Sticky).toBeTruthy()
40 | })
41 |
42 | it('wraps the sticky element on init', function() {
43 | expect($sticky.parent()).toHaveClass('sticky-wrapper')
44 | })
45 |
46 | describe('when sticky element is scrolled to', function() {
47 | beforeEach(function() {
48 | runs(function() {
49 | $scroller.scrollTop($sticky.offset().top)
50 | })
51 | waitsFor(function() {
52 | return $sticky.hasClass('stuck')
53 | }, 'stuck class to apply')
54 | })
55 |
56 | it('adds/removes stuck class', function() {
57 | runs(function() {
58 | $scroller.scrollTop($scroller.scrollTop() - 1)
59 | })
60 | waitsFor(function() {
61 | return !$sticky.hasClass('stuck')
62 | })
63 | })
64 |
65 | it('gives the wrapper the same height as the sticky element', function() {
66 | expect($sticky.parent().height()).toEqual($sticky.outerHeight())
67 | })
68 |
69 | it('executes handler option after stuck class applied', function() {
70 | expect(handlerSpy).toHaveBeenCalled()
71 | })
72 | })
73 | })
74 |
75 | describe('#destroy', function() {
76 | beforeEach(function() {
77 | runs(function() {
78 | $scroller.scrollTop($sticky.offset().top)
79 | })
80 | waitsFor(function() {
81 | return handlerSpy.callCount
82 | })
83 | runs(function() {
84 | waypoint.destroy()
85 | })
86 | })
87 |
88 | it('unwraps the sticky element', function() {
89 | expect($sticky.parent()).not.toHaveClass('sticky-wrapper')
90 | })
91 |
92 | it('removes the stuck class', function() {
93 | expect($sticky).not.toHaveClass('stuck')
94 | })
95 | })
96 | })
97 |
98 | describe('with wrapper false', function() {
99 | beforeEach(function() {
100 | waypoint = new Waypoint.Sticky({
101 | element: $sticky[0],
102 | handler: handlerSpy,
103 | wrapper: false
104 | })
105 | })
106 |
107 | it('does not wrap the sticky element', function() {
108 | expect($sticky.parent()).not.toHaveClass('sticky-wrapper')
109 | })
110 |
111 | it('does not unwrap on destroy', function() {
112 | var parent = waypoint.wrapper
113 | waypoint.destroy()
114 | expect(parent).toBe(waypoint.wrapper)
115 | })
116 | })
117 | })
118 |
--------------------------------------------------------------------------------
/test/waypoint-spec.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | /* global
3 | * describe, it, beforeEach, afterEach, expect, spyOn, waits, runs,
4 | * waitsFor, loadFixtures, Waypoint
5 | */
6 |
7 | window.jQuery.each(Waypoint.adapters, function(i, adapter) {
8 | describe(adapter.name + ' adapter: ', function() {
9 | describe('Waypoint', function() {
10 | var $ = window.jQuery
11 | var standard = 50
12 | var hit, $scroller, waypoint, $target, returnValue
13 |
14 | function setHitTrue() {
15 | hit = true
16 | }
17 |
18 | function hitToBeTrue() {
19 | return hit
20 | }
21 |
22 | beforeEach(function() {
23 | Waypoint.Adapter = adapter.Adapter
24 | loadFixtures('standard.html')
25 | $scroller = $(window)
26 | hit = false
27 | waypoint = null
28 | })
29 |
30 | afterEach(function() {
31 | Waypoint.destroyAll()
32 | $scroller.scrollTop(0).scrollLeft(0)
33 | })
34 |
35 | describe('new Waypoint()', function() {
36 | it('errors out', function() {
37 | expect(function() {
38 | waypoint = new Waypoint()
39 | }).toThrow()
40 | })
41 | })
42 |
43 | describe('new Waypoint(options)', function() {
44 | it('returns an instance of the Waypoint class', function() {
45 | waypoint = new Waypoint({
46 | element: document.getElementById('same1'),
47 | handler: function() {}
48 | })
49 | expect(waypoint instanceof Waypoint).toBeTruthy()
50 | })
51 |
52 | it('requires the element option', function() {
53 | expect(function() {
54 | waypoint = new Waypoint({
55 | handler: function() {}
56 | })
57 | }).toThrow()
58 | })
59 |
60 | it('requires the handler option', function() {
61 | expect(function() {
62 | waypoint = new Waypoint({
63 | element: document.getElementById('same1')
64 | })
65 | }).toThrow()
66 | })
67 |
68 | it('triggers down on new already-reached waypoints', function() {
69 | runs(function() {
70 | $target = $('#same2')
71 | $scroller.scrollTop($target.offset().top + 1)
72 | waypoint = new Waypoint({
73 | element: $target[0],
74 | handler: function(direction) {
75 | hit = direction === 'down'
76 | }
77 | })
78 | })
79 | waitsFor(hitToBeTrue, 'callback to trigger')
80 | })
81 | })
82 |
83 | describe('handler option', function() {
84 | var currentDirection
85 |
86 | beforeEach(function() {
87 | $target = $('#same1')
88 | currentDirection = null
89 | waypoint = new Waypoint({
90 | element: $target[0],
91 | handler: function(direction) {
92 | currentDirection = direction
93 | }
94 | })
95 | })
96 |
97 | it('triggers with direction parameter', function() {
98 | runs(function() {
99 | $scroller.scrollTop($target.offset().top)
100 | })
101 | waitsFor(function() {
102 | return currentDirection === 'down'
103 | }, 'down to trigger')
104 | runs(function() {
105 | $scroller.scrollTop($target.offset().top - 1)
106 | })
107 | waitsFor(function() {
108 | return currentDirection === 'up'
109 | }, 'up to trigger')
110 | })
111 | })
112 |
113 | describe('offset option', function() {
114 | beforeEach(function() {
115 | $target = $('#same1')
116 | })
117 |
118 | it('takes a px offset', function(){
119 | runs(function() {
120 | waypoint = new Waypoint({
121 | element: $target[0],
122 | handler: setHitTrue,
123 | offset: 50
124 | })
125 | $scroller.scrollTop($target.offset().top - 51)
126 | expect(hit).toBeFalsy()
127 | $scroller.scrollTop($target.offset().top - 50)
128 | })
129 | waitsFor(hitToBeTrue, 'callback to trigger')
130 | })
131 |
132 | it('takes a % offset', function() {
133 | var trigger = $target.offset().top - Waypoint.viewportHeight() * 0.37
134 | runs(function() {
135 | waypoint = new Waypoint({
136 | element: $target[0],
137 | handler: setHitTrue,
138 | offset: '37%'
139 | })
140 | $scroller.scrollTop(trigger - 1)
141 | expect(hit).toBeFalsy()
142 | $scroller.scrollTop(trigger)
143 | })
144 | waitsFor(hitToBeTrue, 'callback to trigger')
145 | })
146 |
147 | it('takes a function offset', function() {
148 | runs(function() {
149 | waypoint = new Waypoint({
150 | element: $target[0],
151 | handler: setHitTrue,
152 | offset: function() {
153 | return -$(this.element).height()
154 | }
155 | })
156 | $scroller.scrollTop($target.offset().top + $target.height() - 1)
157 | expect(hit).toBeFalsy()
158 | $scroller.scrollTop($target.offset().top + $target.height())
159 | })
160 | waitsFor(hitToBeTrue, 'callback to trigger')
161 | })
162 |
163 | it('takes a bottom-in-view function alias', function() {
164 | var top = $target.offset().top
165 | var height = $target.outerHeight()
166 | var windowHeight = Waypoint.viewportHeight()
167 | var inview = top + height - windowHeight
168 | runs(function() {
169 | waypoint = new Waypoint({
170 | element: $target[0],
171 | handler: setHitTrue,
172 | offset: 'bottom-in-view'
173 | })
174 | $scroller.scrollTop(inview - 1)
175 | expect(hit).toBeFalsy()
176 | $scroller.scrollTop(inview)
177 | })
178 | waitsFor(hitToBeTrue, 'callback to trigger')
179 | })
180 | })
181 |
182 | describe('context option', function() {
183 | beforeEach(function() {
184 | $scroller = $('#bottom')
185 | $target = $('#inner3')
186 | })
187 |
188 | it('works with px offset', function() {
189 | waypoint = new Waypoint({
190 | element: $target[0],
191 | handler: setHitTrue,
192 | context: $scroller[0],
193 | offset: 10
194 | })
195 | runs(function() {
196 | $scroller.scrollTop(189)
197 | expect(hit).toBeFalsy()
198 | $scroller.scrollTop(190)
199 | })
200 | waitsFor(hitToBeTrue, 'callback to trigger')
201 | })
202 |
203 | it('works with % offset', function() {
204 | waypoint = new Waypoint({
205 | element: $target[0],
206 | handler: setHitTrue,
207 | context: $scroller[0],
208 | offset: '100%'
209 | })
210 | runs(function() {
211 | $scroller.scrollTop(149)
212 | expect(hit).toBeFalsy()
213 | $scroller.scrollTop(150)
214 | })
215 | waitsFor(hitToBeTrue, 'callback to trigger')
216 | })
217 |
218 | it('works with function offset', function() {
219 | waypoint = new Waypoint({
220 | element: $target[0],
221 | handler: setHitTrue,
222 | context: $scroller[0],
223 | offset: function() {
224 | return $(this.element).height() / 2
225 | }
226 | })
227 | runs(function() {
228 | $scroller.scrollTop(149)
229 | expect(hit).toBeFalsy()
230 | $scroller.scrollTop(150)
231 | })
232 | waitsFor(hitToBeTrue, 'callback to trigger')
233 | })
234 |
235 | it('works with bottom-in-view offset alias', function() {
236 | waypoint = new Waypoint({
237 | element: $target[0],
238 | handler: setHitTrue,
239 | context: $scroller[0],
240 | offset: 'bottom-in-view'
241 | })
242 | runs(function() {
243 | $scroller.scrollTop(249)
244 | expect(hit).toBeFalsy()
245 | $scroller.scrollTop(250)
246 | })
247 | waitsFor(hitToBeTrue, 'callback to trigger')
248 | })
249 | })
250 |
251 | describe('horizontal option', function() {
252 | var currentDirection
253 |
254 | beforeEach(function() {
255 | currentDirection = null
256 | $target = $('#same1')
257 | waypoint = new Waypoint({
258 | element: $target[0],
259 | horizontal: true,
260 | handler: function(direction) {
261 | currentDirection = direction
262 | }
263 | })
264 | })
265 |
266 | it('triggers right/left directions', function() {
267 | runs(function() {
268 | $scroller.scrollLeft($target.offset().left)
269 | })
270 | waitsFor(function() {
271 | return currentDirection === 'right'
272 | }, 'right direction to trigger')
273 | runs(function() {
274 | $scroller.scrollLeft($target.offset().left - 1)
275 | })
276 | waitsFor(function() {
277 | return currentDirection === 'left'
278 | })
279 | })
280 | })
281 |
282 | describe('continuous option', function() {
283 | var $later, laterWaypoint, hitCount, hitWaypoint
284 |
285 | function incrementHitCount() {
286 | hitCount += 1
287 | hitWaypoint = this
288 | }
289 |
290 | beforeEach(function() {
291 | $target = $('#same1')
292 | $later = $('#near1')
293 | hitCount = 0
294 | waypoint = new Waypoint({
295 | element: $target[0],
296 | continuous: false,
297 | handler: incrementHitCount
298 | })
299 | laterWaypoint = new Waypoint({
300 | element: $later[0],
301 | continuous: false,
302 | handler: incrementHitCount
303 | })
304 | })
305 |
306 | it('does not trigger the earlier waypoint', function() {
307 | runs(function() {
308 | $scroller.scrollTop($later.offset().top)
309 | })
310 | waitsFor(function() {
311 | return hitCount
312 | }, 'later callback to trigger')
313 | runs(function() {
314 | expect(hitCount).toEqual(1)
315 | expect(hitWaypoint).toEqual(laterWaypoint)
316 | })
317 | })
318 |
319 | it('prevents earlier trigger on refresh', function() {
320 | runs(function() {
321 | $target.css('top', '-1px')
322 | $later.css('top', '-2px')
323 | Waypoint.refreshAll()
324 | })
325 | waitsFor(function() {
326 | return hitCount
327 | }, 'later callback to trigger')
328 | runs(function() {
329 | expect(hitCount).toEqual(1)
330 | expect(hitWaypoint).toEqual(waypoint)
331 | })
332 | })
333 | })
334 |
335 | describe('with window as the waypoint element', function() {
336 | beforeEach(function() {
337 | $target = $(window)
338 | waypoint = new Waypoint({
339 | element: $target[0],
340 | offset: -$target.height(),
341 | handler: setHitTrue
342 | })
343 | })
344 |
345 | it('triggers waypoint', function() {
346 | runs(function() {
347 | $target.scrollTop($target.height() + 1)
348 | })
349 | waitsFor(hitToBeTrue, 'callback to trigger')
350 | })
351 | })
352 |
353 | describe('#disable()', function() {
354 | beforeEach(function() {
355 | $target = $('#same1')
356 | waypoint = new Waypoint({
357 | element: $target[0],
358 | handler: setHitTrue
359 | })
360 | returnValue = waypoint.disable()
361 | })
362 |
363 | it('returns the same waypoint object for chaining', function() {
364 | expect(returnValue).toEqual(waypoint)
365 | })
366 |
367 | it('disables callback triggers', function() {
368 | runs(function() {
369 | $scroller.scrollTop($target.offset().top)
370 | })
371 | waits(standard)
372 | runs(function() {
373 | expect(hit).toBeFalsy()
374 | })
375 | })
376 | })
377 |
378 | describe('#enable()', function() {
379 | beforeEach(function() {
380 | $target = $('#same1')
381 | waypoint = new Waypoint({
382 | element: $target[0],
383 | handler: setHitTrue
384 | })
385 | waypoint.disable()
386 | returnValue = waypoint.enable()
387 | })
388 |
389 | it('returns the same waypoint instance for chaining', function() {
390 | expect(returnValue).toEqual(waypoint)
391 | })
392 |
393 | it('enables callback triggers', function() {
394 | runs(function() {
395 | $scroller.scrollTop($target.offset().top)
396 | })
397 | waitsFor(hitToBeTrue, 'callback to trigger')
398 | })
399 | })
400 |
401 | describe('#destroy()', function() {
402 | beforeEach(function() {
403 | $target = $('#same1')
404 | waypoint = new Waypoint({
405 | element: $target[0],
406 | handler: setHitTrue
407 | })
408 | returnValue = waypoint.destroy()
409 | })
410 |
411 | it('returns undefined', function() {
412 | expect(returnValue).toBeUndefined()
413 | })
414 |
415 | it('no longer triggers callbacks', function() {
416 | runs(function() {
417 | $scroller.scrollTop($target.offset().top)
418 | })
419 | waits(standard)
420 | runs(function() {
421 | expect(hit).toBeFalsy()
422 | })
423 | })
424 | })
425 |
426 | describe('#previous', function() {
427 | beforeEach(function() {
428 | $target = $('#same1')
429 | waypoint = new Waypoint({
430 | element: $target[0],
431 | handler: setHitTrue
432 | })
433 | })
434 |
435 | it('calls previous on the waypoint group', function() {
436 | spyOn(waypoint.group, 'previous')
437 | waypoint.previous()
438 | expect(waypoint.group.previous).toHaveBeenCalledWith(waypoint)
439 | })
440 |
441 | it('returns the group call results', function() {
442 | expect(waypoint.previous()).toBeNull()
443 | })
444 | })
445 |
446 | describe('#next', function() {
447 | beforeEach(function() {
448 | $target = $('#same1')
449 | waypoint = new Waypoint({
450 | element: $target[0],
451 | handler: setHitTrue
452 | })
453 | })
454 |
455 | it('calls next on the waypoint group', function() {
456 | spyOn(waypoint.group, 'next')
457 | waypoint.next()
458 | expect(waypoint.group.next).toHaveBeenCalledWith(waypoint)
459 | })
460 |
461 | it('returns the group call results', function() {
462 | expect(waypoint.next()).toBeNull()
463 | })
464 | })
465 |
466 | describe('Waypoint.viewportHeight()', function() {
467 | it('returns window innerHeight if it exists', function() {
468 | var height = Waypoint.viewportHeight()
469 | if (window.innerHeight) {
470 | expect(height).toEqual(window.innerHeight)
471 | }
472 | else {
473 | expect(height).toEqual(document.documentElement.clientHeight)
474 | }
475 | })
476 | })
477 |
478 | describe('Waypoint.viewportWidth()', function() {
479 | it('returns client width', function() {
480 | var clientWidth = document.documentElement.clientWidth
481 | expect(Waypoint.viewportWidth()).toEqual(clientWidth)
482 | })
483 | })
484 |
485 | describe('Waypoint.refreshAll()', function() {
486 | it('is an alias for Waypoint.Context.refreshAll', function() {
487 | spyOn(Waypoint.Context, 'refreshAll')
488 | Waypoint.refreshAll()
489 | expect(Waypoint.Context.refreshAll).toHaveBeenCalled()
490 | })
491 | })
492 |
493 | describe('Waypoint.destroyAll()', function() {
494 | it('calls destroy on all waypoints', function() {
495 | var secondWaypoint = new Waypoint({
496 | element: $('#same1')[0],
497 | handler: function() {}
498 | })
499 | waypoint = new Waypoint({
500 | element: $('#same1')[0],
501 | handler: function() {}
502 | })
503 | spyOn(secondWaypoint, 'destroy').andCallThrough()
504 | spyOn(waypoint, 'destroy').andCallThrough()
505 | Waypoint.destroyAll()
506 | expect(secondWaypoint.destroy).toHaveBeenCalled()
507 | expect(waypoint.destroy).toHaveBeenCalled()
508 | })
509 | })
510 |
511 | describe('Waypoint.disableAll()', function() {
512 | it('calls disable on all waypoints', function() {
513 | var secondWaypoint = new Waypoint({
514 | element: $('#same1')[0],
515 | handler: function() {}
516 | })
517 | waypoint = new Waypoint({
518 | element: $('#same1')[0],
519 | handler: function() {}
520 | })
521 | spyOn(secondWaypoint, 'disable').andCallThrough()
522 | spyOn(waypoint, 'disable').andCallThrough()
523 | Waypoint.disableAll()
524 | expect(secondWaypoint.disable).toHaveBeenCalled()
525 | expect(waypoint.disable).toHaveBeenCalled()
526 | })
527 | })
528 |
529 | describe('Waypoint.enableAll()', function() {
530 | var secondWaypoint
531 |
532 | beforeEach(function() {
533 | secondWaypoint = new Waypoint({
534 | element: $('#same1')[0],
535 | handler: function() {}
536 | })
537 | waypoint = new Waypoint({
538 | element: $('#same1')[0],
539 | handler: function() {}
540 | })
541 | Waypoint.disableAll()
542 | spyOn(Waypoint.Context, 'refreshAll').andCallThrough()
543 | Waypoint.enableAll()
544 | })
545 |
546 | it('sets enabled on all waypoints', function() {
547 | expect(secondWaypoint.enabled).toBeTruthy()
548 | expect(waypoint.enabled).toBeTruthy()
549 | })
550 |
551 | it('refreshes all contexts', function() {
552 | expect(Waypoint.Context.refreshAll).toHaveBeenCalled()
553 | })
554 | })
555 | })
556 | })
557 | })
558 |
--------------------------------------------------------------------------------
/testem.json:
--------------------------------------------------------------------------------
1 | {
2 | "framework": "jasmine",
3 | "launch_in_dev": [
4 | "PhantomJS"
5 | ],
6 | "launch_in_ci": [
7 | "PhantomJS"
8 | ],
9 | "src_files": [
10 | "bower_components/jquery/dist/jquery.js",
11 | "bower_components/jasmine-jquery/lib/jasmine-jquery.js",
12 | "bower_components/zepto/zepto.js",
13 |
14 | "src/waypoint.js",
15 | "src/context.js",
16 | "src/group.js",
17 | "src/debug.js",
18 | "src/adapters/*.js",
19 | "src/shortcuts/*.js",
20 |
21 | "test/settings.js",
22 | "test/*-spec.js"
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------