forked from imakewebthings/waypoints
-
Notifications
You must be signed in to change notification settings - Fork 1
/
waypoints.coffee
692 lines (558 loc) · 26.3 KB
/
waypoints.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
###
jQuery Waypoints - v2.0.3
Copyright (c) 2011-2013 Caleb Troughton
Dual licensed under the MIT license and GPL license.
https://github.com/imakewebthings/jquery-waypoints/blob/master/licenses.txt
###
((root, factory) ->
if typeof define is 'function' and define.amd
define 'waypoints', ['jquery'], ($) ->
factory $, root
else
factory root.jQuery, root
) this, ($, window) ->
$w = $ window
# Touch support feature test
isTouch = 'ontouchstart' in window
# Internal plugin-wide variables:
# - allWaypoints: A hash containing two hashes, one for vertical waypoints
# and one for horizontal waypoints. In each hash they value is a Waypoint
# instance and the key is that waypoint's unique ID.
# - contextCounter: A counter that is incremented with each instantiation
# of the Context class, used in its unique ID.
# - contexts: A hash of all contexts. The value of each entry is a Context
# instance and the key is that context's unique ID.
# - contextKey: The DOM element for each context keeps a reference to the
# context's unique ID in the jQuery .data() object. This is the key for
# that data entry.
# - resizeEvent: The namespaced resize event used by contexts.
# - scrollEvent: The namespaced scroll event used by contexts.
# - waypointCounter: A counter that is incremented with each instantiation
# of the Waypoint class, used in its unique ID.
# - waypointKey: The DOM element for each waypoint keeps a reference to an
# array of the unique IDs of all waypoints attached to that element. This
# array is kept in the jQuery .data() object, and this is the key for
# that entry.
# - wp: A variable shortcut for the waypoint method name on the $.fn object.
# Using this variable just helps with minification.
# - wps: A variable shortcut for the waypoints method name on the $ object.
# Using this variable just helps with minification.
allWaypoints =
horizontal: {}
vertical: {}
contextCounter = 1
contexts = {}
contextKey = 'waypoints-context-id'
resizeEvent = 'resize.waypoints'
scrollEvent = 'scroll.waypoints'
waypointCounter = 1
waypointKey = 'waypoints-waypoint-ids'
wp = 'waypoint'
wps = 'waypoints'
# Context: Represents a single scrolling element in which waypoints live.
# For most users there will only be one Context, the window, but users can
# use other scrollable elements as a context using the "context" option
# when creating waypoints.
# Properties:
# - $element: jQuery object containing the context element.
# - element: The raw HTMLNode of the context element.
# - didResize: A flag used in throttling the resize event.
# - didScroll: A flag used in throttling the scroll event.
# - id: A unique identifier for the context.
# - oldScroll: A hash containing...
# - x: The context's last known horizontal scroll value.
# - y: The context's last known vertical scroll value.
# - waypoints: A hash containing two hashes with all waypoints in the context.
# Entries are in the same style as the allWaypoints hashes:
# (key = waypoint.id, value = waypoint)
# - horizontal: A hash of all horizontal waypoints.
# - vertical: A hash of all vertical waypoints.
class Context
constructor: ($element) ->
@$element = $element
@element = $element[0]
@didResize = no
@didScroll = no
@id = 'context' + contextCounter++
@oldScroll =
x: $element.scrollLeft()
y: $element.scrollTop()
@waypoints =
horizontal: {}
vertical: {}
# We need to keep a reference to this Context instance on the DOM node
# so we can look it up later based on the node.
$element.data contextKey, @id
# To do that look up, we need to have this instance in the global hash.
contexts[@id] = this
# Run scroll checks on scroll, but throttle it for performance reasons.
$element.bind scrollEvent, =>
unless @didScroll or isTouch
@didScroll = yes
scrollHandler = =>
@doScroll()
@didScroll = no
window.setTimeout scrollHandler, $[wps].settings.scrollThrottle
# Run a refresh on resize, but throttle it for performance reasons.
$element.bind resizeEvent, =>
unless @didResize
@didResize = yes
resizeHandler = =>
$[wps] 'refresh'
@didResize = no
window.setTimeout resizeHandler, $[wps].settings.resizeThrottle
# doScroll()
# Looks at the new scroll values for the context, compares them to the old
# scroll values, and checks to see if any waypoints should be triggered
# by that change.
doScroll: ->
# We use some hashes with common values for each axis so that we can
# just iterate over it rather than write the whole thing twice for
# each axis.
axes =
horizontal:
newScroll: @$element.scrollLeft()
oldScroll: @oldScroll.x
forward: 'right'
backward: 'left'
vertical:
newScroll: @$element.scrollTop()
oldScroll: @oldScroll.y
forward: 'down'
backward: 'up'
# This is a small "hack" for iOS, needed because scrolls in mobile
# Safari that start or end with the URL bar showing will cause window
# height changes without firing a resize event.
if isTouch and (!axes.vertical.oldScroll or !axes.vertical.newScroll)
$[wps] 'refresh'
# For each axis, check to see if any waypoints have been crossed.
# Also determine the direction it's being crossed and sort/reverse all
# crossed waypoints accordingly. And, of course, trigger the waypoints.
$.each axes, (aKey, axis) =>
triggered = []
isForward = axis.newScroll > axis.oldScroll
direction = if isForward then axis.forward else axis.backward
$.each @waypoints[aKey], (wKey, waypoint) ->
if axis.oldScroll < waypoint.offset <= axis.newScroll
triggered.push waypoint
else if axis.newScroll < waypoint.offset <= axis.oldScroll
triggered.push waypoint
triggered.sort (a, b) -> a.offset - b.offset
triggered.reverse() unless isForward
$.each triggered, (i, waypoint) ->
if waypoint.options.continuous or i is triggered.length - 1
waypoint.trigger [direction]
# Now that we're done with the check, the new scroll values become
# the old scroll values for the next check.
@oldScroll =
x: axes.horizontal.newScroll
y: axes.vertical.newScroll
# refresh()
# Runs through all of the waypoints in the context and recalculates
# their offsets (the scroll value at which the waypoint is triggered.)
# If a change in offset also happens to cross the context's current
# scroll value, the waypoint will be triggered in the appropriate direction
# unless prevented by the "onlyOnScroll" waypoint option.
refresh: () ->
isWin = $.isWindow @element
cOffset = @$element.offset()
# Make sure we have the most up-to-date scroll values for our context.
@doScroll()
# Each axis recalculation needs to know some things:
# - contextOffset: The distance between the edge of the document and
# the context element.
# - contextScroll: The scroll value of the context. However, if the
# context is the window this needs to be 0 because this value only
# comes into play when used in adjustment calculations for non-window
# context waypoints.
# - contextDimension: Width or height of the context.
# - oldScroll: The scroll value of the context. Unlike "contextScroll",
# this is the same no matter the type of context, and is used when
# determining whether a newly added waypoint should immediately fire
# on its first offset calculation.
# - forward: Direction string passed to forward waypoint triggers.
# - backward: Direction string passed to backward waypoint triggers.
# - offsetProp: Key of the .offset() object for this axis.
axes =
horizontal:
contextOffset: if isWin then 0 else cOffset.left
contextScroll: if isWin then 0 else @oldScroll.x
contextDimension: @$element.width()
oldScroll: @oldScroll.x
forward: 'right'
backward: 'left'
offsetProp: 'left'
vertical:
contextOffset: if isWin then 0 else cOffset.top
contextScroll: if isWin then 0 else @oldScroll.y
contextDimension: if isWin then $[wps]('viewportHeight') else \
@$element.height()
oldScroll: @oldScroll.y
forward: 'down'
backward: 'up'
offsetProp: 'top'
# For each axis, run through the waypoints. Store the old offset.
# Recalculate the new offset. Check the difference against the context's
# current scroll value and trigger any crossed waypoints accordingly.
$.each axes, (aKey, axis) =>
$.each @waypoints[aKey], (i, waypoint) ->
adjustment = waypoint.options.offset
oldOffset = waypoint.offset
elementOffset = if $.isWindow waypoint.element then 0 else \
waypoint.$element.offset()[axis.offsetProp]
# The "offset" waypoint option (which we call "adjustment" here) can
# be a number, percentage string, keyword string (bottom-in-view),
# or a function. So we deal with all of these types here.
if $.isFunction adjustment
adjustment = adjustment.apply waypoint.element
else if typeof adjustment is 'string'
adjustment = parseFloat adjustment
if waypoint.options.offset.indexOf('%') > -1
adjustment = Math.ceil(axis.contextDimension * adjustment / 100)
# We've finally calculated all the crazy little adjustments that
# can come from using non-window contexts and the "offset" option.
# Store the damn thing.
waypoint.offset = elementOffset \
- axis.contextOffset \
+ axis.contextScroll \
- adjustment
# "onlyOnScroll" tells us to not even consider triggering waypoints
# during refresh, so we can eject early.
return if (waypoint.options.onlyOnScroll and oldOffset?) or \
!waypoint.enabled
# Case where the refresh causes a backward trigger.
if oldOffset isnt null and \
oldOffset < axis.oldScroll <= waypoint.offset
waypoint.trigger [axis.backward]
# Now the forward case.
else if oldOffset isnt null and \
oldOffset > axis.oldScroll >= waypoint.offset
waypoint.trigger [axis.forward]
# "oldOffset" values of null mean this is the first calculation of
# the waypoint's offset. It's a special time in a waypoint's life.
else if oldOffset is null and axis.oldScroll >= waypoint.offset
waypoint.trigger [axis.forward]
# checkEmpty()
# Looks at the waypoints hashes. If they are empty, the context removes
# itself from the global contexts hash.
checkEmpty: ->
if $.isEmptyObject(@waypoints.horizontal) and \
$.isEmptyObject(@waypoints.vertical)
@$element.unbind [resizeEvent, scrollEvent].join(' ')
delete contexts[@id]
# Waypoint: Represents a single callback function tied to an element. An
# element can have multiple waypoints with multiple offsets.
# Properties:
# - $element: jQuery object containing the waypoint element.
# - element: The raw HTMLNode of the waypoint element.
# - axis: 'horizontal' || 'vertical' - The axis on which this waypoint lives.
# - callback: The function that is fired when the waypoint is triggered.
# - context: A reference to the context this waypoint belongs to.
# - enabled: Boolean indicating whether this waypoint is enabled or not.
# Disabled waypoints are still returned in functions that aggregate
# waypoints, but do not fire their callbacks.
# - id: A unique identifier for the waypoint.
# - offset: The scroll offset at which the waypoint should trigger.
# - options: A hash containing the various waypoint options.
# See $.fn.waypoint.defaults for more information on those options.
class Waypoint
constructor: ($element, context, options) ->
options = $.extend {}, $.fn[wp].defaults, options
if options.offset is 'bottom-in-view'
options.offset = ->
contextHeight = $[wps] 'viewportHeight'
unless $.isWindow context.element
contextHeight = context.$element.height()
contextHeight - $(this).outerHeight()
@$element = $element
@element = $element[0]
@axis = if options.horizontal then 'horizontal' else 'vertical'
@callback = options.handler
@context = context
@enabled = options.enabled
@id = 'waypoints' + waypointCounter++
@offset = null
@options = options
# Add our new waypoint to its context.
context.waypoints[@axis][@id] = this
# Add it to the global hash.
allWaypoints[@axis][@id] = this
# Add the waypoint's id to the element's waypoint id list.
idList = $element.data(waypointKey) ? []
idList.push @id
$element.data waypointKey, idList
# trigger(array)
# Calls the waypoint's callback function, passing to it the arguments
# supplied in the "args" array.
trigger: (args) ->
return unless @enabled
if @callback?
@callback.apply @element, args
if @options.triggerOnce
@destroy()
# disable()
# Temporarily disables a waypoint from firing its callback.
disable: ->
@enabled = false
# enable()
# Breathe life back into the waypoint.
enable: ->
@context.refresh()
@enabled = true
# destroy()
# Kills the waypoint for good.
destroy: ->
delete allWaypoints[@axis][@id]
delete @context.waypoints[@axis][@id]
@context.checkEmpty()
# Waypoint.getWaypointsByElement(HTMLNode)
# Returns an array of all Waypoint instances attached to the "element"
# HTMLNode. Returns an empty array if there are no attached waypoints.
@getWaypointsByElement: (element) ->
ids = $(element).data waypointKey
return [] unless ids
all = $.extend {}, allWaypoints.horizontal, allWaypoints.vertical
$.map ids, (id) ->
all[id]
# These methods are available on the $.fn object by using the method
# name as the first argument to .waypoint. Ex: $('div').waypoint('destroy')
methods =
# init(function, object)
# Creates a new waypoint (and if needed, a new context) using the supplied
# callback function and options.
# The "f" function and the "options" object are both optional, but at least
# one must be supplied. So acceptable signatures are:
# - .waypoint(f)
# - .waypoint(options)
# - .waypoint(f, options)
# This "init" method should never need to be called explicity by the user.
# It is the default method that is delegated to when .waypoint is called
# with one of the above signatures.
# Ex: $('div').waypoint(function(direction) {
# // Do things
# }, { offset: '100%' });
init: (f, options) ->
options ?= {}
options.handler ?= f
@each ->
$this = $ this
contextElement = options.context ? $.fn[wp].defaults.context
unless $.isWindow contextElement
contextElement = $this.closest contextElement
contextElement = $ contextElement
context = contexts[contextElement.data contextKey]
context = new Context contextElement unless context
new Waypoint $this, context, options
$[wps] 'refresh'
this
# Disable, enable, and destroy all just delegate to the instance methods
# of the waypoints attached to the subject elements.
disable: -> methods._invoke this, 'disable'
enable: -> methods._invoke this, 'enable'
destroy: -> methods._invoke this, 'destroy'
# .waypoint('prev', string, string|HTMLNode|jQuery)
# Returns a jQuery object containing previous waypoint elements. This
# creates a new entry in the jQuery object stack just like jQuery's prev
# function. "axis" indicates the axis on which to traverse
# ('horizontal' | 'vertical') and "selector" indicates which context
# element to use. The defaults are 'vertical' and window respectively.
prev: (axis, selector) ->
methods._traverse.call this, axis, selector, (stack, index, waypoints) ->
stack.push waypoints[index-1] if index > 0
# .waypoint('next', string, string|HTMLNode|jQuery)
# Returns a jQuery object containing next waypoint elements. This
# creates a new entry in the jQuery object stack just like jQuery's next
# function. "axis" indicates the axis on which to traverse
# ('horizontal' | 'vertical') and "selector" indicates which context
# element to use. The defaults are 'vertical' and window respectively.
next: (axis, selector) ->
methods._traverse.call this, axis, selector, (stack, index, waypoints) ->
stack.push waypoints[index+1] if index < waypoints.length-1
# Internal: Aggregates waypoints on a given axis of a context, and applies
# a "push" callback for each element in the subject jQuery object. This
# callback builds the element array to push to the jQuery stack.
_traverse: (axis = 'vertical', selector = window, push) ->
waypoints = jQMethods.aggregate selector
stack = []
@each ->
index = $.inArray this, waypoints[axis]
push stack, index, waypoints[axis]
@pushStack stack
# Internal: Finds all waypoints on a given set of "$elements" and invokes
# "method" on each instance.
_invoke: ($elements, method) ->
$elements.each ->
waypoints = Waypoint.getWaypointsByElement this
$.each waypoints, (i, waypoint) ->
waypoint[method]()
true
this
# $.fn.waypoint. Let's just hook this guy up to our methods hash and
# add some trivial error reporting for bogus calls.
$.fn[wp] = (method, args...) ->
if methods[method]
methods[method].apply this, args
else if $.isFunction(method)
methods.init.apply this, arguments
else if $.isPlainObject(method)
methods.init.apply this, [null, method]
else if !method
$.error "jQuery Waypoints needs a callback function or handler option."
else
$.error "The #{method} method does not exist in jQuery Waypoints."
# The default options object for a waypoint.
# - context: string|HTMLNode|jQuery - The scrollable element that the
# waypoint acts within. The waypoint will look for the closest ancestor
# element that matches this selector or node.
# - continuous: Multiple waypoints may be triggered by a single scroll check.
# If you would like a waypoint to only trigger if it is the last waypoint
# in a scroll check, set this to false.
# - enabled: Should this waypoint start enabled (true) or disabled (false)?
# - handler: This option is not defined by default, but can be used as an
# alternate way to pass the waypoint callback function, rather than as
# the first argument to .waypoint.
# Ex: $('div').waypoint({
# handler: function(direction) { ... }
# });
# - horizontal: Set this to true if the waypoint is, well, horizontal.
# - offset: number|string|function - Determines how far from the top (or left
# if the waypoint is horizontal) of the context's viewport to trigger the
# waypoint. The default of 0 means that the waypoint is triggered when the
# top of the waypoint element hits the top of the window/context-element.
# An offset of 50 would mean the waypoint triggers when the top of the
# element is 50 pixels from the top of the window.
# A % string is translated into a percentage of the width/height of
# the context.
# If a function is passed, that function should return a number. The "this"
# keyword within this function will be set to the raw HTMLNode of the
# waypoint element.
# - triggerOnce: If true, the waypoint will destroy itself after
# first trigger.
$.fn[wp].defaults =
context: window
continuous: true
enabled: true
horizontal: false
offset: 0
triggerOnce: false
# These methods are available on the $ object by using the method name as
# the first argument to .waypoint. Ex: $.waypoints('refresh')
jQMethods =
# $.waypoints('refresh')
# Forces a refresh on all contexts, recalculating all waypoint offsets.
# This is done automatically on waypoint addition and during resize events,
# but if a user does something to change the DOM, CSS, or in some way
# change the layout of a page and its elements, they might need to call
# this method manually.
refresh: ->
$.each contexts, (i, context) -> context.refresh()
# $.waypoints('viewportHeight')
# A utility method that returns the window height, but takes into account
# inconsistencies that come with just using jQuery's .height() on iOS.
viewportHeight: ->
window.innerHeight ? $w.height()
# $.waypoints(['aggregate'], [contextSelector])
# Returns an object containing two HTMLNode arrays, one for each axis:
# {
# horizontal: [ HTMLNode... ]
# vertical: [ HTMLNode... ]
# }
# This is the default method used when calling $.waypoints(). If
# "contextSelector" is not supplied, it returns all waypoints. If
# "contextSelector" is supplied it only returns waypoints for that context.
# The array of waypoint elements is returned sorted by calculated offset,
# the order in which they would be triggered on the page.
aggregate: (contextSelector) ->
collection = allWaypoints
if contextSelector
collection = contexts[$(contextSelector).data contextKey]?.waypoints
return [] unless collection
waypoints =
horizontal: []
vertical: []
$.each waypoints, (axis, arr) ->
$.each collection[axis], (key, waypoint) ->
arr.push waypoint
arr.sort (a, b) -> a.offset - b.offset
waypoints[axis] = $.map arr, (waypoint) -> waypoint.element
waypoints[axis] = $.unique waypoints[axis]
waypoints
# $.waypoints('above', [string|HTMLNode|jQuery])
# Returns all vertical waypoints that lie above the current scroll position
# of the context specified by "contextSelector". If no "contextSelector"
# is supplied, it defaults to the window.
above: (contextSelector = window) ->
jQMethods._filter contextSelector, 'vertical', (context, waypoint) ->
waypoint.offset <= context.oldScroll.y
# $.waypoints('below', [string|HTMLNode|jQuery])
# Returns all vertical waypoints that lie below the current scroll position
# of the context specified by "contextSelector". If no "contextSelector"
# is supplied, it defaults to the window.
below: (contextSelector = window) ->
jQMethods._filter contextSelector, 'vertical', (context, waypoint) ->
waypoint.offset > context.oldScroll.y
# $.waypoints('left', [string|HTMLNode|jQuery])
# Returns all horizontal waypoints left of the current scroll position
# of the context specified by "contextSelector". If no "contextSelector"
# is supplied, it defaults to the window.
left: (contextSelector = window) ->
jQMethods._filter contextSelector, 'horizontal', (context, waypoint) ->
waypoint.offset <= context.oldScroll.x
# $.waypoints('right', [string|HTMLNode|jQuery])
# Returns all horizontal waypoints right of the current scroll position
# of the context specified by "contextSelector". If no "contextSelector"
# is supplied, it defaults to the window.
right: (contextSelector = window) ->
jQMethods._filter contextSelector, 'horizontal', (context, waypoint) ->
waypoint.offset > context.oldScroll.x
# $.waypoints('enable/disable/destroy')
# These methods delegate to the enable/disable/destroy instance methods
# for all waypoints.
enable: -> jQMethods._invoke 'enable'
disable: -> jQMethods._invoke 'disable'
destroy: -> jQMethods._invoke 'destroy'
# $.waypoints('extendFn', string, function)
# Extends the $.fn.waypoint method object with a new method, "f". This
# just lets other modules piggyback on the .waypoint namespace.
extendFn: (methodName, f) ->
methods[methodName] = f
# Internal: Invokes "method" on all waypoints.
_invoke: (method) ->
waypoints = $.extend {}, allWaypoints.vertical, allWaypoints.horizontal
$.each waypoints, (key, waypoint) ->
waypoint[method]()
true
# Internal: Returns an array of all HTMLNodes for each waypoint that passes
# the "test" function. Only waypoints within the "selector" context on the
# "axis" axis are tested. As with .aggregate, the array is sorted by
# calculated offset (trigger order).
_filter: (selector, axis, test) ->
context = contexts[$(selector).data contextKey]
return [] unless context
waypoints = []
$.each context.waypoints[axis], (i, waypoint) ->
waypoints.push waypoint if test context, waypoint
waypoints.sort (a, b) -> a.offset - b.offset
$.map waypoints, (waypoint) -> waypoint.element
# Hook up jQMethods to the $.waypoints namespace.
$[wps] = (method, args...) ->
if jQMethods[method]
jQMethods[method].apply null, args
else
jQMethods.aggregate.call null, method
# Plugin-wide settings:
# - resizeThrottle: For performance reasons, the refresh performed during
# resizes is throttled. This value is the rate-limit in milliseconds
# between resize refreshes. For more information on throttling, check out
# Ben Alman’s throttle / debounce plugin.
# http://benalman.com/projects/jquery-throttle-debounce-plugin/
# - scrollThrottle: For performance reasons, checking for any crossed
# waypoints during a scroll event is throttled. This value is the
# rate-limit in milliseconds between scroll checks. For more information
# on throttling, check out Ben Alman’s throttle / debounce plugin.
# http://benalman.com/projects/jquery-throttle-debounce-plugin/
$[wps].settings =
resizeThrottle: 100
scrollThrottle: 30
# Ensure a refresh on page load. Newly loaded images often shift layout.
$w.load -> $[wps] 'refresh'