2 (function ($, window
, document
, undefined) {
5 Foundation
.libs
['magellan-expedition'] = {
6 name
: 'magellan-expedition',
11 active_class
: 'active',
12 threshold
: 0, // pixels from the top of the expedition for it to become fixes
13 destination_threshold
: 20, // pixels from the top of destination for it to be considered active
14 throttle_delay
: 30, // calculation throttling to increase framerate
15 fixed_top
: 0, // top distance in pixels assigend to the fixed element on scroll
16 offset_by_height
: true, // whether to offset the destination by the expedition height. Usually you want this to be true, unless your expedition is on the side.
17 duration
: 700, // animation duration time
18 easing
: 'swing' // animation easing
21 init: function (scope
, method
, options
) {
22 Foundation
.inherit(this, 'throttle');
23 this.bindings(method
, options
);
29 settings
= self
.settings
;
31 // initialize expedition offset
32 self
.set_expedition_position();
36 .on('click.fndtn.magellan', '[' + self
.add_namespace('data-magellan-arrival') + '] a[href^="#"]', function (e
) {
38 var expedition
= $(this).closest('[' + self
.attr_name() + ']'),
39 settings
= expedition
.data('magellan-expedition-init'),
40 hash
= this.hash
.split('#').join(''),
41 target
= $('a[name="' + hash
+ '"]');
43 if (target
.length
=== 0) {
44 target
= $('#' + hash
);
49 // Account for expedition height if fixed position
50 var scroll_top
= target
.offset().top
- settings
.destination_threshold
+ 1;
51 if (settings
.offset_by_height
) {
52 scroll_top
= scroll_top
- expedition
.outerHeight();
55 $('html, body').stop().animate({
56 'scrollTop': scroll_top
57 }, settings
.duration
, settings
.easing
, function () {
58 if (history
.pushState
) {
59 history
.pushState(null, null, '#' + hash
);
62 location
.hash
= '#' + hash
;
66 .on('scroll.fndtn.magellan', self
.throttle(this.check_for_arrivals
.bind(this), settings
.throttle_delay
));
69 .on('resize.fndtn.magellan', self
.throttle(this.set_expedition_position
.bind(this), settings
.throttle_delay
));
72 check_for_arrivals: function () {
74 self
.update_arrivals();
75 self
.update_expedition_positions();
78 set_expedition_position: function () {
80 $('[' + this.attr_name() + '=fixed]', self
.scope
).each(function (idx
, el
) {
81 var expedition
= $(this),
82 settings
= expedition
.data('magellan-expedition-init'),
83 styles
= expedition
.attr('styles'), // save styles
84 top_offset
, fixed_top
;
86 expedition
.attr('style', '');
87 top_offset
= expedition
.offset().top
+ settings
.threshold
;
89 //set fixed-top by attribute
90 fixed_top
= parseInt(expedition
.data('magellan-fixed-top'));
91 if (!isNaN(fixed_top
))
92 self
.settings
.fixed_top
= fixed_top
;
94 expedition
.data(self
.data_attr('magellan-top-offset'), top_offset
);
95 expedition
.attr('style', styles
);
99 update_expedition_positions: function () {
101 window_top_offset
= $(window
).scrollTop();
103 $('[' + this.attr_name() + '=fixed]', self
.scope
).each(function () {
104 var expedition
= $(this),
105 settings
= expedition
.data('magellan-expedition-init'),
106 styles
= expedition
.attr('style'), // save styles
107 top_offset
= expedition
.data('magellan-top-offset');
109 //scroll to the top distance
110 if (window_top_offset
+ self
.settings
.fixed_top
>= top_offset
) {
111 // Placeholder allows height calculations to be consistent even when
112 // appearing to switch between fixed/non-fixed placement
113 var placeholder
= expedition
.prev('[' + self
.add_namespace('data-magellan-expedition-clone') + ']');
114 if (placeholder
.length
=== 0) {
115 placeholder
= expedition
.clone();
116 placeholder
.removeAttr(self
.attr_name());
117 placeholder
.attr(self
.add_namespace('data-magellan-expedition-clone'), '');
118 expedition
.before(placeholder
);
120 expedition
.css({position
: 'fixed', top
: settings
.fixed_top
}).addClass('fixed');
122 expedition
.prev('[' + self
.add_namespace('data-magellan-expedition-clone') + ']').remove();
123 expedition
.attr('style', styles
).css('position', '').css('top', '').removeClass('fixed');
128 update_arrivals: function () {
130 window_top_offset
= $(window
).scrollTop();
132 $('[' + this.attr_name() + ']', self
.scope
).each(function () {
133 var expedition
= $(this),
134 settings
= expedition
.data(self
.attr_name(true) + '-init'),
135 offsets
= self
.offsets(expedition
, window_top_offset
),
136 arrivals
= expedition
.find('[' + self
.add_namespace('data-magellan-arrival') + ']'),
138 offsets
.each(function (idx
, item
) {
139 if (item
.viewport_offset
>= item
.top_offset
) {
140 var arrivals
= expedition
.find('[' + self
.add_namespace('data-magellan-arrival') + ']');
141 arrivals
.not(item
.arrival
).removeClass(settings
.active_class
);
142 item
.arrival
.addClass(settings
.active_class
);
148 if (!active_item
) arrivals
.removeClass(settings
.active_class
);
152 offsets: function (expedition
, window_offset
) {
154 settings
= expedition
.data(self
.attr_name(true) + '-init'),
155 viewport_offset
= window_offset
;
157 return expedition
.find('[' + self
.add_namespace('data-magellan-arrival') + ']').map(function (idx
, el
) {
158 var name
= $(this).data(self
.data_attr('magellan-arrival')),
159 dest
= $('[' + self
.add_namespace('data-magellan-destination') + '=' + name
+ ']');
160 if (dest
.length
> 0) {
161 var top_offset
= dest
.offset().top
- settings
.destination_threshold
;
162 if (settings
.offset_by_height
) {
163 top_offset
= top_offset
- expedition
.outerHeight();
165 top_offset
= Math
.floor(top_offset
);
169 top_offset
: top_offset
,
170 viewport_offset
: viewport_offset
173 }).sort(function (a
, b
) {
174 if (a
.top_offset
< b
.top_offset
) return -1;
175 if (a
.top_offset
> b
.top_offset
) return 1;
180 data_attr: function (str
) {
181 if (this.namespace.length
> 0) {
182 return this.namespace + '-' + str
;
189 this.S(this.scope
).off('.magellan');
190 this.S(window
).off('.magellan');
193 reflow: function () {
195 // remove placeholder expeditions used for height calculation purposes
196 $('[' + self
.add_namespace('data-magellan-expedition-clone') + ']', self
.scope
).remove();
199 }(jQuery
, window
, window
.document
));