2015-10-01 16:00:26 +02:00
; ( function ( $ , window , document , undefined ) {
'use strict' ;
Foundation . libs [ 'magellan-expedition' ] = {
name : 'magellan-expedition' ,
2018-02-15 18:42:07 +01:00
version : '{{VERSION}}' ,
2015-10-01 16:00:26 +02:00
settings : {
active _class : 'active' ,
threshold : 0 , // pixels from the top of the expedition for it to become fixes
destination _threshold : 20 , // pixels from the top of destination for it to be considered active
throttle _delay : 30 , // calculation throttling to increase framerate
fixed _top : 0 , // top distance in pixels assigend to the fixed element on scroll
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.
duration : 700 , // animation duration time
easing : 'swing' // animation easing
} ,
init : function ( scope , method , options ) {
Foundation . inherit ( this , 'throttle' ) ;
this . bindings ( method , options ) ;
} ,
events : function ( ) {
var self = this ,
S = self . S ,
settings = self . settings ;
// initialize expedition offset
self . set _expedition _position ( ) ;
S ( self . scope )
. off ( '.magellan' )
2018-02-15 18:42:07 +01:00
. on ( 'click.fndtn.magellan' , '[' + self . add _namespace ( 'data-magellan-arrival' ) + '] a[href^="#"]' , function ( e ) {
2015-10-01 16:00:26 +02:00
var sameHost = ( ( this . hostname === location . hostname ) || ! this . hostname ) ,
samePath = self . filterPathname ( location . pathname ) === self . filterPathname ( this . pathname ) ,
testHash = this . hash . replace ( /(:|\.|\/)/g , '\\$1' ) ,
anchor = this ;
if ( sameHost && samePath && testHash ) {
e . preventDefault ( ) ;
var expedition = $ ( this ) . closest ( '[' + self . attr _name ( ) + ']' ) ,
settings = expedition . data ( 'magellan-expedition-init' ) ,
hash = this . hash . split ( '#' ) . join ( '' ) ,
target = $ ( 'a[name="' + hash + '"]' ) ;
if ( target . length === 0 ) {
target = $ ( '#' + hash ) ;
}
// Account for expedition height if fixed position
var scroll _top = target . offset ( ) . top - settings . destination _threshold + 1 ;
if ( settings . offset _by _height ) {
scroll _top = scroll _top - expedition . outerHeight ( ) ;
}
$ ( 'html, body' ) . stop ( ) . animate ( {
'scrollTop' : scroll _top
} , settings . duration , settings . easing , function ( ) {
if ( history . pushState ) {
2018-02-09 03:02:47 +01:00
history . pushState ( null , null , anchor . pathname + anchor . search + '#' + hash ) ;
} else {
location . hash = anchor . pathname + anchor . search + '#' + hash ;
2015-10-01 16:00:26 +02:00
}
} ) ;
}
} )
. on ( 'scroll.fndtn.magellan' , self . throttle ( this . check _for _arrivals . bind ( this ) , settings . throttle _delay ) ) ;
} ,
check _for _arrivals : function ( ) {
var self = this ;
self . update _arrivals ( ) ;
self . update _expedition _positions ( ) ;
} ,
set _expedition _position : function ( ) {
var self = this ;
$ ( '[' + this . attr _name ( ) + '=fixed]' , self . scope ) . each ( function ( idx , el ) {
var expedition = $ ( this ) ,
settings = expedition . data ( 'magellan-expedition-init' ) ,
2018-02-15 18:42:07 +01:00
styles = expedition . attr ( 'style' ) , // save styles
2015-10-01 16:00:26 +02:00
top _offset , fixed _top ;
expedition . attr ( 'style' , '' ) ;
top _offset = expedition . offset ( ) . top + settings . threshold ;
//set fixed-top by attribute
fixed _top = parseInt ( expedition . data ( 'magellan-fixed-top' ) ) ;
if ( ! isNaN ( fixed _top ) ) {
self . settings . fixed _top = fixed _top ;
}
expedition . data ( self . data _attr ( 'magellan-top-offset' ) , top _offset ) ;
expedition . attr ( 'style' , styles ) ;
} ) ;
} ,
update _expedition _positions : function ( ) {
var self = this ,
window _top _offset = $ ( window ) . scrollTop ( ) ;
$ ( '[' + this . attr _name ( ) + '=fixed]' , self . scope ) . each ( function ( ) {
var expedition = $ ( this ) ,
settings = expedition . data ( 'magellan-expedition-init' ) ,
styles = expedition . attr ( 'style' ) , // save styles
top _offset = expedition . data ( 'magellan-top-offset' ) ;
//scroll to the top distance
if ( window _top _offset + self . settings . fixed _top >= top _offset ) {
// Placeholder allows height calculations to be consistent even when
// appearing to switch between fixed/non-fixed placement
var placeholder = expedition . prev ( '[' + self . add _namespace ( 'data-magellan-expedition-clone' ) + ']' ) ;
if ( placeholder . length === 0 ) {
placeholder = expedition . clone ( ) ;
placeholder . removeAttr ( self . attr _name ( ) ) ;
placeholder . attr ( self . add _namespace ( 'data-magellan-expedition-clone' ) , '' ) ;
expedition . before ( placeholder ) ;
}
expedition . css ( { position : 'fixed' , top : settings . fixed _top } ) . addClass ( 'fixed' ) ;
} else {
expedition . prev ( '[' + self . add _namespace ( 'data-magellan-expedition-clone' ) + ']' ) . remove ( ) ;
expedition . attr ( 'style' , styles ) . css ( 'position' , '' ) . css ( 'top' , '' ) . removeClass ( 'fixed' ) ;
}
} ) ;
} ,
update _arrivals : function ( ) {
var self = this ,
window _top _offset = $ ( window ) . scrollTop ( ) ;
$ ( '[' + this . attr _name ( ) + ']' , self . scope ) . each ( function ( ) {
var expedition = $ ( this ) ,
settings = expedition . data ( self . attr _name ( true ) + '-init' ) ,
offsets = self . offsets ( expedition , window _top _offset ) ,
arrivals = expedition . find ( '[' + self . add _namespace ( 'data-magellan-arrival' ) + ']' ) ,
active _item = false ;
offsets . each ( function ( idx , item ) {
if ( item . viewport _offset >= item . top _offset ) {
var arrivals = expedition . find ( '[' + self . add _namespace ( 'data-magellan-arrival' ) + ']' ) ;
arrivals . not ( item . arrival ) . removeClass ( settings . active _class ) ;
item . arrival . addClass ( settings . active _class ) ;
active _item = true ;
return true ;
}
} ) ;
if ( ! active _item ) {
arrivals . removeClass ( settings . active _class ) ;
}
} ) ;
} ,
offsets : function ( expedition , window _offset ) {
var self = this ,
settings = expedition . data ( self . attr _name ( true ) + '-init' ) ,
viewport _offset = window _offset ;
return expedition . find ( '[' + self . add _namespace ( 'data-magellan-arrival' ) + ']' ) . map ( function ( idx , el ) {
var name = $ ( this ) . data ( self . data _attr ( 'magellan-arrival' ) ) ,
dest = $ ( '[' + self . add _namespace ( 'data-magellan-destination' ) + '=' + name + ']' ) ;
if ( dest . length > 0 ) {
var top _offset = dest . offset ( ) . top - settings . destination _threshold ;
if ( settings . offset _by _height ) {
top _offset = top _offset - expedition . outerHeight ( ) ;
}
top _offset = Math . floor ( top _offset ) ;
return {
destination : dest ,
arrival : $ ( this ) ,
top _offset : top _offset ,
viewport _offset : viewport _offset
}
}
} ) . sort ( function ( a , b ) {
if ( a . top _offset < b . top _offset ) {
return - 1 ;
}
if ( a . top _offset > b . top _offset ) {
return 1 ;
}
return 0 ;
} ) ;
} ,
data _attr : function ( str ) {
if ( this . namespace . length > 0 ) {
return this . namespace + '-' + str ;
}
return str ;
} ,
off : function ( ) {
this . S ( this . scope ) . off ( '.magellan' ) ;
this . S ( window ) . off ( '.magellan' ) ;
} ,
filterPathname : function ( pathname ) {
pathname = pathname || '' ;
return pathname
. replace ( /^\// , '' )
. replace ( /(?:index|default).[a-zA-Z]{3,4}$/ , '' )
. replace ( /\/$/ , '' ) ;
} ,
reflow : function ( ) {
var self = this ;
// remove placeholder expeditions used for height calculation purposes
$ ( '[' + self . add _namespace ( 'data-magellan-expedition-clone' ) + ']' , self . scope ) . remove ( ) ;
}
} ;
} ( jQuery , window , window . document ) ) ;