/** * Gumby SkipLink */ !function($) { 'use strict'; function SkipLink($el) { Gumby.debug('Initializing Skiplink', $el); this.$el = $el; this.targetPos = 0; this.duration = 0; this.offset = false; this.easing = ''; this.update = false; // set up module based on attributes this.setup(); var scope = this; // skip to target element on click or trigger of gumby.skipTo event this.$el.on(Gumby.click+' gumby.skip', function(e) { e.preventDefault(); if(e.namespace === 'skip') { Gumby.debug('Skip event triggered', scope.$el); } // calculate target on each click if update var set to true if(scope.update) { scope.calculateTarget(scope.skipTo); // skip straight to target } else { scope.skipTo(); } }).on('gumby.initialize', function() { Gumby.debug('Re-initializing Skiplink', scope.$el); scope.setup(); }); } // set up module based on attributes SkipLink.prototype.setup = function() { this.duration = Number(Gumby.selectAttr.apply(this.$el, ['duration'])) || 200; this.offset = Gumby.selectAttr.apply(this.$el, ['offset']) || false; this.easing = Gumby.selectAttr.apply(this.$el, ['easing']) || 'swing'; this.update = Gumby.selectAttr.apply(this.$el, ['update']) ? true : false; this.calculateTarget(); }; // calculate target px point to skip to SkipLink.prototype.calculateTarget = function(cb) { var scope = this, target = Gumby.selectAttr.apply(this.$el, ['goto']), $target; // 'top' specified so target is 0px if(target == 'top') { this.targetPos = 0; // px point specified } else if($.isNumeric(target)) { this.targetPos = Number(target); } else { // check for element with target as selector $target = $(target); // target does not exist, we need a target if(!$target.length) { Gumby.error('Cannot find skiplink target: '+target); return false; } this.targetPos = $target.offset().top; } if(cb) { cb.apply(this); } }; // animate body, html scrollTop value to target px point SkipLink.prototype.skipTo = function() { Gumby.debug('Skipping to target', this.$el); var scope = this; // slide to position of target $('html,body').animate({ 'scrollTop' : this.calculateOffset() }, this.duration, this.easing).promise().done(function() { Gumby.debug('Triggering onComplete event', scope.$el); scope.$el.trigger('gumby.onComplete'); }); }; // calculate offset with current target point SkipLink.prototype.calculateOffset = function() { // no offset so return target here if(!this.offset) { return this.targetPos; } // negative / positive var op = this.offset.substr(0, 1), off = Number(this.offset.substr(1, this.offset.length)); // subtract offset from target position if(op === '-') { return this.targetPos - off; // add offset to target position } else if(op === '+') { return this.targetPos + off; } }; // add initialisation Gumby.addInitalisation('skiplink', function(all) { $('.skiplink > a, .skip').each(function() { var $this = $(this); // this element has already been initialized // and we're only initializing new modules if($this.data('isSkipLink') && !all) { return true; // this element has already been initialized // and we need to reinitialize it } else if($this.data('isSkipLink') && all) { $this.trigger('gumby.initialize'); return true; } // mark element as initialized $this.data('isSkipLink', true); new SkipLink($this); }); }); // register UI module Gumby.UIModule({ module: 'skiplink', events: ['initialize', 'onComplete', 'skip'], init: function() { Gumby.initialize('skiplink'); } }); }(jQuery);