1 | 'use strict';
|
2 |
|
3 |
|
4 | import $ from 'jquery';
|
5 | import { GetYoDigits } from './foundation.util.core';
|
6 | import { Plugin } from './foundation.plugin';
|
7 | import { SmoothScroll } from './foundation.smoothScroll';
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 | class Magellan extends Plugin {
|
16 | |
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 | _setup(element, options) {
|
25 | this.$element = element;
|
26 | this.options = $.extend({}, Magellan.defaults, this.$element.data(), options);
|
27 | this.className = 'Magellan';
|
28 |
|
29 | this._init();
|
30 | this.calcPoints();
|
31 | }
|
32 |
|
33 | |
34 |
|
35 |
|
36 |
|
37 | _init() {
|
38 | var id = this.$element[0].id || GetYoDigits(6, 'magellan');
|
39 | var _this = this;
|
40 | this.$targets = $('[data-magellan-target]');
|
41 | this.$links = this.$element.find('a');
|
42 | this.$element.attr({
|
43 | 'data-resize': id,
|
44 | 'data-scroll': id,
|
45 | 'id': id
|
46 | });
|
47 | this.$active = $();
|
48 | this.scrollPos = parseInt(window.pageYOffset, 10);
|
49 |
|
50 | this._events();
|
51 | }
|
52 |
|
53 | |
54 |
|
55 |
|
56 |
|
57 |
|
58 | calcPoints() {
|
59 | var _this = this,
|
60 | body = document.body,
|
61 | html = document.documentElement;
|
62 |
|
63 | this.points = [];
|
64 | this.winHeight = Math.round(Math.max(window.innerHeight, html.clientHeight));
|
65 | this.docHeight = Math.round(Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight));
|
66 |
|
67 | this.$targets.each(function(){
|
68 | var $tar = $(this),
|
69 | pt = Math.round($tar.offset().top - _this.options.threshold);
|
70 | $tar.targetPoint = pt;
|
71 | _this.points.push(pt);
|
72 | });
|
73 | }
|
74 |
|
75 | |
76 |
|
77 |
|
78 |
|
79 | _events() {
|
80 | var _this = this,
|
81 | $body = $('html, body'),
|
82 | opts = {
|
83 | duration: _this.options.animationDuration,
|
84 | easing: _this.options.animationEasing
|
85 | };
|
86 | $(window).one('load', function(){
|
87 | if(_this.options.deepLinking){
|
88 | if(location.hash){
|
89 | _this.scrollToLoc(location.hash);
|
90 | }
|
91 | }
|
92 | _this.calcPoints();
|
93 | _this._updateActive();
|
94 | });
|
95 |
|
96 | this.$element.on({
|
97 | 'resizeme.zf.trigger': this.reflow.bind(this),
|
98 | 'scrollme.zf.trigger': this._updateActive.bind(this)
|
99 | }).on('click.zf.magellan', 'a[href^="#"]', function(e) {
|
100 | e.preventDefault();
|
101 | var arrival = this.getAttribute('href');
|
102 | _this.scrollToLoc(arrival);
|
103 | });
|
104 |
|
105 | this._deepLinkScroll = function(e) {
|
106 | if(_this.options.deepLinking) {
|
107 | _this.scrollToLoc(window.location.hash);
|
108 | }
|
109 | };
|
110 |
|
111 | $(window).on('popstate', this._deepLinkScroll);
|
112 | }
|
113 |
|
114 | |
115 |
|
116 |
|
117 |
|
118 |
|
119 | scrollToLoc(loc) {
|
120 | this._inTransition = true;
|
121 | var _this = this;
|
122 |
|
123 | var options = {
|
124 | animationEasing: this.options.animationEasing,
|
125 | animationDuration: this.options.animationDuration,
|
126 | threshold: this.options.threshold,
|
127 | offset: this.options.offset
|
128 | };
|
129 |
|
130 | SmoothScroll.scrollToLoc(loc, options, function() {
|
131 | _this._inTransition = false;
|
132 | _this._updateActive();
|
133 | })
|
134 | }
|
135 |
|
136 | |
137 |
|
138 |
|
139 |
|
140 | reflow() {
|
141 | this.calcPoints();
|
142 | this._updateActive();
|
143 | }
|
144 |
|
145 | |
146 |
|
147 |
|
148 |
|
149 |
|
150 |
|
151 | _updateActive() {
|
152 | if(this._inTransition) {return;}
|
153 | var winPos = parseInt(window.pageYOffset, 10),
|
154 | curIdx;
|
155 |
|
156 | if(winPos + this.winHeight === this.docHeight){ curIdx = this.points.length - 1; }
|
157 | else if(winPos < this.points[0]){ curIdx = undefined; }
|
158 | else{
|
159 | var isDown = this.scrollPos < winPos,
|
160 | _this = this,
|
161 | curVisible = this.points.filter(function(p, i){
|
162 | return isDown ? p - _this.options.offset <= winPos : p - _this.options.offset - _this.options.threshold <= winPos;
|
163 | });
|
164 | curIdx = curVisible.length ? curVisible.length - 1 : 0;
|
165 | }
|
166 |
|
167 | this.$active.removeClass(this.options.activeClass);
|
168 | this.$active = this.$links.filter('[href="#' + this.$targets.eq(curIdx).data('magellan-target') + '"]').addClass(this.options.activeClass);
|
169 |
|
170 | if(this.options.deepLinking){
|
171 | var hash = "";
|
172 | if(curIdx != undefined){
|
173 | hash = this.$active[0].getAttribute('href');
|
174 | }
|
175 | if(hash !== window.location.hash) {
|
176 | if(window.history.pushState){
|
177 | window.history.pushState(null, null, hash);
|
178 | }else{
|
179 | window.location.hash = hash;
|
180 | }
|
181 | }
|
182 | }
|
183 |
|
184 | this.scrollPos = winPos;
|
185 | |
186 |
|
187 |
|
188 |
|
189 | this.$element.trigger('update.zf.magellan', [this.$active]);
|
190 | }
|
191 |
|
192 | |
193 |
|
194 |
|
195 |
|
196 | _destroy() {
|
197 | this.$element.off('.zf.trigger .zf.magellan')
|
198 | .find(`.${this.options.activeClass}`).removeClass(this.options.activeClass);
|
199 |
|
200 | if(this.options.deepLinking){
|
201 | var hash = this.$active[0].getAttribute('href');
|
202 | window.location.hash.replace(hash, '');
|
203 | }
|
204 | $(window).off('popstate', this._deepLinkScroll);
|
205 | }
|
206 | }
|
207 |
|
208 |
|
209 |
|
210 |
|
211 | Magellan.defaults = {
|
212 | |
213 |
|
214 |
|
215 |
|
216 |
|
217 |
|
218 | animationDuration: 500,
|
219 | |
220 |
|
221 |
|
222 |
|
223 |
|
224 |
|
225 |
|
226 | animationEasing: 'linear',
|
227 | |
228 |
|
229 |
|
230 |
|
231 |
|
232 |
|
233 | threshold: 50,
|
234 | |
235 |
|
236 |
|
237 |
|
238 |
|
239 |
|
240 | activeClass: 'is-active',
|
241 | |
242 |
|
243 |
|
244 |
|
245 |
|
246 |
|
247 | deepLinking: false,
|
248 | |
249 |
|
250 |
|
251 |
|
252 |
|
253 |
|
254 | offset: 0
|
255 | }
|
256 |
|
257 | export {Magellan};
|