'use strict';
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
!function ($) {
/**
* Magellan module.
* @module foundation.magellan
*/
var Magellan = function () {
/**
* Creates a new instance of Magellan.
* @class
* @fires Magellan#init
* @param {Object} element - jQuery object to add the trigger to.
* @param {Object} options - Overrides to the default plugin settings.
*/
function Magellan(element, options) {
_classCallCheck(this, Magellan);
this.$element = element;
this.options = $.extend({}, Magellan.defaults, this.$element.data(), options);
this._init();
this.calcPoints();
Foundation.registerPlugin(this, 'Magellan');
}
/**
* Initializes the Magellan plugin and calls functions to get equalizer functioning on load.
* @private
*/
_createClass(Magellan, [{
key: '_init',
value: function _init() {
var id = this.$element[0].id || Foundation.GetYoDigits(6, 'magellan');
var _this = this;
this.$targets = $('[data-magellan-target]');
this.$links = this.$element.find('a');
this.$element.attr({
'data-resize': id,
'data-scroll': id,
'id': id
});
this.$active = $();
this.scrollPos = parseInt(window.pageYOffset, 10);
this._events();
}
/**
* Calculates an array of pixel values that are the demarcation lines between locations on the page.
* Can be invoked if new elements are added or the size of a location changes.
* @function
*/
}, {
key: 'calcPoints',
value: function calcPoints() {
var _this = this,
body = document.body,
html = document.documentElement;
this.points = [];
this.winHeight = Math.round(Math.max(window.innerHeight, html.clientHeight));
this.docHeight = Math.round(Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight));
this.$targets.each(function () {
var $tar = $(this),
pt = Math.round($tar.offset().top - _this.options.threshold);
$tar.targetPoint = pt;
_this.points.push(pt);
});
}
/**
* Initializes events for Magellan.
* @private
*/
}, {
key: '_events',
value: function _events() {
var _this = this,
$body = $('html, body'),
opts = {
duration: _this.options.animationDuration,
easing: _this.options.animationEasing
};
$(window).one('load', function () {
if (_this.options.deepLinking) {
if (location.hash) {
_this.scrollToLoc(location.hash);
}
}
_this.calcPoints();
_this._updateActive();
});
this.$element.on({
'resizeme.zf.trigger': this.reflow.bind(this),
'scrollme.zf.trigger': this._updateActive.bind(this)
}).on('click.zf.magellan', 'a[href^="#"]', function (e) {
e.preventDefault();
var arrival = this.getAttribute('href');
_this.scrollToLoc(arrival);
});
$(window).on('popstate', function (e) {
if (_this.options.deepLinking) {
_this.scrollToLoc(window.location.hash);
}
});
}
/**
* Function to scroll to a given location on the page.
* @param {String} loc - a properly formatted jQuery id selector. Example: '#foo'
* @function
*/
}, {
key: 'scrollToLoc',
value: function scrollToLoc(loc) {
// Do nothing if target does not exist to prevent errors
if (!$(loc).length) {
return false;
}
this._inTransition = true;
var _this = this,
scrollPos = Math.round($(loc).offset().top - this.options.threshold / 2 - this.options.barOffset);
$('html, body').stop(true).animate({ scrollTop: scrollPos }, this.options.animationDuration, this.options.animationEasing, function () {
_this._inTransition = false;_this._updateActive();
});
}
/**
* Calls necessary functions to update Magellan upon DOM change
* @function
*/
}, {
key: 'reflow',
value: function reflow() {
this.calcPoints();
this._updateActive();
}
/**
* Updates the visibility of an active location link, and updates the url hash for the page, if deepLinking enabled.
* @private
* @function
* @fires Magellan#update
*/
}, {
key: '_updateActive',
value: function _updateActive() /*evt, elem, scrollPos*/{
if (this._inTransition) {
return;
}
var winPos = /*scrollPos ||*/parseInt(window.pageYOffset, 10),
curIdx;
if (winPos + this.winHeight === this.docHeight) {
curIdx = this.points.length - 1;
} else if (winPos < this.points[0]) {
curIdx = undefined;
} else {
var isDown = this.scrollPos < winPos,
_this = this,
curVisible = this.points.filter(function (p, i) {
return isDown ? p - _this.options.barOffset <= winPos : p - _this.options.barOffset - _this.options.threshold <= winPos;
});
curIdx = curVisible.length ? curVisible.length - 1 : 0;
}
this.$active.removeClass(this.options.activeClass);
this.$active = this.$links.filter('[href="#' + this.$targets.eq(curIdx).data('magellan-target') + '"]').addClass(this.options.activeClass);
if (this.options.deepLinking) {
var hash = "";
if (curIdx != undefined) {
hash = this.$active[0].getAttribute('href');
}
if (hash !== window.location.hash) {
if (window.history.pushState) {
window.history.pushState(null, null, hash);
} else {
window.location.hash = hash;
}
}
}
this.scrollPos = winPos;
/**
* Fires when magellan is finished updating to the new active element.
* @event Magellan#update
*/
this.$element.trigger('update.zf.magellan', [this.$active]);
}
/**
* Destroys an instance of Magellan and resets the url of the window.
* @function
*/
}, {
key: 'destroy',
value: function destroy() {
this.$element.off('.zf.trigger .zf.magellan').find('.' + this.options.activeClass).removeClass(this.options.activeClass);
if (this.options.deepLinking) {
var hash = this.$active[0].getAttribute('href');
window.location.hash.replace(hash, '');
}
Foundation.unregisterPlugin(this);
}
}]);
return Magellan;
}();
/**
* Default settings for plugin
*/
Magellan.defaults = {
/**
* Amount of time, in ms, the animated scrolling should take between locations.
* @option
* @example 500
*/
animationDuration: 500,
/**
* Animation style to use when scrolling between locations.
* @option
* @example 'ease-in-out'
*/
animationEasing: 'linear',
/**
* Number of pixels to use as a marker for location changes.
* @option
* @example 50
*/
threshold: 50,
/**
* Class applied to the active locations link on the magellan container.
* @option
* @example 'active'
*/
activeClass: 'active',
/**
* Allows the script to manipulate the url of the current page, and if supported, alter the history.
* @option
* @example true
*/
deepLinking: false,
/**
* Number of pixels to offset the scroll of the page on item click if using a sticky nav bar.
* @option
* @example 25
*/
barOffset: 0
};
// Window exports
Foundation.plugin(Magellan, 'Magellan');
}(jQuery);
|