1/** 2* Gumby SkipLink 3*/ 4!function($) { 5 6 'use strict'; 7 8 function SkipLink($el) { 9 10 Gumby.debug('Initializing Skiplink', $el); 11 12 this.$el = $el; 13 this.targetPos = 0; 14 this.duration = 0; 15 this.offset = false; 16 this.easing = ''; 17 this.update = false; 18 19 // set up module based on attributes 20 this.setup(); 21 22 var scope = this; 23 24 // skip to target element on click or trigger of gumby.skipTo event 25 this.$el.on(Gumby.click+' gumby.skip', function(e) { 26 e.preventDefault(); 27 28 if(e.namespace === 'skip') { 29 Gumby.debug('Skip event triggered', scope.$el); 30 } 31 32 // calculate target on each click if update var set to true 33 if(scope.update) { 34 scope.calculateTarget(scope.skipTo); 35 36 // skip straight to target 37 } else { 38 scope.skipTo(); 39 } 40 }).on('gumby.initialize', function() { 41 Gumby.debug('Re-initializing Skiplink', scope.$el); 42 scope.setup(); 43 }); 44 } 45 46 // set up module based on attributes 47 SkipLink.prototype.setup = function() { 48 this.duration = Number(Gumby.selectAttr.apply(this.$el, ['duration'])) || 200; 49 this.offset = Gumby.selectAttr.apply(this.$el, ['offset']) || false; 50 this.easing = Gumby.selectAttr.apply(this.$el, ['easing']) || 'swing'; 51 this.update = Gumby.selectAttr.apply(this.$el, ['update']) ? true : false; 52 53 this.calculateTarget(); 54 }; 55 56 // calculate target px point to skip to 57 SkipLink.prototype.calculateTarget = function(cb) { 58 59 var scope = this, 60 target = Gumby.selectAttr.apply(this.$el, ['goto']), 61 $target; 62 63 // 'top' specified so target is 0px 64 if(target == 'top') { 65 this.targetPos = 0; 66 67 // px point specified 68 } else if($.isNumeric(target)) { 69 this.targetPos = Number(target); 70 } else { 71 72 // check for element with target as selector 73 $target = $(target); 74 75 // target does not exist, we need a target 76 if(!$target.length) { 77 Gumby.error('Cannot find skiplink target: '+target); 78 return false; 79 } 80 81 this.targetPos = $target.offset().top; 82 } 83 84 if(cb) { 85 cb.apply(this); 86 } 87 }; 88 89 // animate body, html scrollTop value to target px point 90 SkipLink.prototype.skipTo = function() { 91 92 Gumby.debug('Skipping to target', this.$el); 93 94 var scope = this; 95 96 // slide to position of target 97 $('html,body').animate({ 98 'scrollTop' : this.calculateOffset() 99 }, this.duration, this.easing).promise().done(function() { 100 101 Gumby.debug('Triggering onComplete event', scope.$el); 102 scope.$el.trigger('gumby.onComplete'); 103 }); 104 }; 105 106 // calculate offset with current target point 107 SkipLink.prototype.calculateOffset = function() { 108 // no offset so return target here 109 if(!this.offset) { 110 return this.targetPos; 111 } 112 113 // negative / positive 114 var op = this.offset.substr(0, 1), 115 off = Number(this.offset.substr(1, this.offset.length)); 116 117 // subtract offset from target position 118 if(op === '-') { 119 return this.targetPos - off; 120 // add offset to target position 121 } else if(op === '+') { 122 return this.targetPos + off; 123 } 124 }; 125 126 // add initialisation 127 Gumby.addInitalisation('skiplink', function(all) { 128 $('.skiplink > a, .skip').each(function() { 129 var $this = $(this); 130 131 // this element has already been initialized 132 // and we're only initializing new modules 133 if($this.data('isSkipLink') && !all) { 134 return true; 135 136 // this element has already been initialized 137 // and we need to reinitialize it 138 } else if($this.data('isSkipLink') && all) { 139 $this.trigger('gumby.initialize'); 140 return true; 141 } 142 143 // mark element as initialized 144 $this.data('isSkipLink', true); 145 new SkipLink($this); 146 }); 147 }); 148 149 // register UI module 150 Gumby.UIModule({ 151 module: 'skiplink', 152 events: ['initialize', 'onComplete', 'skip'], 153 init: function() { 154 Gumby.initialize('skiplink'); 155 } 156 }); 157}(jQuery); 158