scrollspy.js 9.88 KB
Newer Older
Mark Otto's avatar
grunt    
Mark Otto committed
1
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
fat's avatar
fat committed
2

Mark Otto's avatar
grunt    
Mark Otto committed
3
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; }; }();
fat's avatar
fat committed
4

Mark Otto's avatar
grunt    
Mark Otto committed
5
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
fat's avatar
fat committed
6
7
8

/**
 * --------------------------------------------------------------------------
Mark Otto's avatar
Mark Otto committed
9
 * Bootstrap (v4.0.0-alpha.6): scrollspy.js
fat's avatar
fat committed
10
11
12
13
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * --------------------------------------------------------------------------
 */

Mark Otto's avatar
grunt    
Mark Otto committed
14
var ScrollSpy = function ($) {
fat's avatar
fat committed
15
16
17
18
19
20
21
22

  /**
   * ------------------------------------------------------------------------
   * Constants
   * ------------------------------------------------------------------------
   */

  var NAME = 'scrollspy';
Mark Otto's avatar
Mark Otto committed
23
  var VERSION = '4.0.0-alpha.6';
fat's avatar
fat committed
24
  var DATA_KEY = 'bs.scrollspy';
fat's avatar
fat committed
25
26
  var EVENT_KEY = '.' + DATA_KEY;
  var DATA_API_KEY = '.data-api';
fat's avatar
fat committed
27
28
  var JQUERY_NO_CONFLICT = $.fn[NAME];

29
  var Default = {
30
    offset: 10,
fat's avatar
fat committed
31
32
    method: 'auto',
    target: ''
fat's avatar
fat committed
33
34
  };

fat's avatar
fat committed
35
36
37
38
39
40
  var DefaultType = {
    offset: 'number',
    method: 'string',
    target: '(string|element)'
  };

fat's avatar
fat committed
41
  var Event = {
fat's avatar
fat committed
42
43
    ACTIVATE: 'activate' + EVENT_KEY,
    SCROLL: 'scroll' + EVENT_KEY,
Jacob Thornton's avatar
Jacob Thornton committed
44
    LOAD_DATA_API: 'load' + EVENT_KEY + DATA_API_KEY
fat's avatar
fat committed
45
46
47
  };

  var ClassName = {
Jacob Thornton's avatar
Jacob Thornton committed
48
    DROPDOWN_ITEM: 'dropdown-item',
fat's avatar
fat committed
49
    DROPDOWN_MENU: 'dropdown-menu',
50
51
    NAV_LINK: 'nav-link',
    NAV: 'nav',
fat's avatar
fat committed
52
53
54
55
56
57
    ACTIVE: 'active'
  };

  var Selector = {
    DATA_SPY: '[data-spy="scroll"]',
    ACTIVE: '.active',
58
    LIST_ITEM: '.list-item',
fat's avatar
fat committed
59
    LI: 'li',
fat's avatar
fat committed
60
    LI_DROPDOWN: 'li.dropdown',
Jacob Thornton's avatar
Jacob Thornton committed
61
    NAV_LINKS: '.nav-link',
62
63
64
    DROPDOWN: '.dropdown',
    DROPDOWN_ITEMS: '.dropdown-item',
    DROPDOWN_TOGGLE: '.dropdown-toggle'
fat's avatar
fat committed
65
66
  };

67
68
69
70
71
  var OffsetMethod = {
    OFFSET: 'offset',
    POSITION: 'position'
  };

fat's avatar
fat committed
72
73
74
75
76
77
  /**
   * ------------------------------------------------------------------------
   * Class Definition
   * ------------------------------------------------------------------------
   */

Mark Otto's avatar
grunt    
Mark Otto committed
78
  var ScrollSpy = function () {
fat's avatar
fat committed
79
    function ScrollSpy(element, config) {
Mark Otto's avatar
grunt    
Mark Otto committed
80
81
      var _this = this;

fat's avatar
fat committed
82
83
      _classCallCheck(this, ScrollSpy);

fat's avatar
fat committed
84
      this._element = element;
fat's avatar
fat committed
85
      this._scrollElement = element.tagName === 'BODY' ? window : element;
fat's avatar
fat committed
86
      this._config = this._getConfig(config);
Jacob Thornton's avatar
Jacob Thornton committed
87
      this._selector = this._config.target + ' ' + Selector.NAV_LINKS + ',' + (this._config.target + ' ' + Selector.DROPDOWN_ITEMS);
fat's avatar
fat committed
88
89
90
91
92
      this._offsets = [];
      this._targets = [];
      this._activeTarget = null;
      this._scrollHeight = 0;

Mark Otto's avatar
grunt    
Mark Otto committed
93
94
95
      $(this._scrollElement).on(Event.SCROLL, function (event) {
        return _this._process(event);
      });
fat's avatar
fat committed
96
97
98
99
100

      this.refresh();
      this._process();
    }

Jacob Thornton's avatar
Jacob Thornton committed
101
102
    // getters

Mark Otto's avatar
grunt    
Mark Otto committed
103
    // public
fat's avatar
fat committed
104

Mark Otto's avatar
grunt    
Mark Otto committed
105
    ScrollSpy.prototype.refresh = function refresh() {
Mark Otto's avatar
grunt    
Mark Otto committed
106
      var _this2 = this;
fat's avatar
fat committed
107

Mark Otto's avatar
grunt    
Mark Otto committed
108
      var autoMethod = this._scrollElement !== this._scrollElement.window ? OffsetMethod.POSITION : OffsetMethod.OFFSET;
fat's avatar
fat committed
109

Mark Otto's avatar
grunt    
Mark Otto committed
110
      var offsetMethod = this._config.method === 'auto' ? autoMethod : this._config.method;
111

Mark Otto's avatar
grunt    
Mark Otto committed
112
      var offsetBase = offsetMethod === OffsetMethod.POSITION ? this._getScrollTop() : 0;
fat's avatar
fat committed
113

Mark Otto's avatar
grunt    
Mark Otto committed
114
115
      this._offsets = [];
      this._targets = [];
fat's avatar
fat committed
116

Mark Otto's avatar
grunt    
Mark Otto committed
117
      this._scrollHeight = this._getScrollHeight();
fat's avatar
fat committed
118

Mark Otto's avatar
grunt    
Mark Otto committed
119
      var targets = $.makeArray($(this._selector));
fat's avatar
fat committed
120

Mark Otto's avatar
grunt    
Mark Otto committed
121
122
123
      targets.map(function (element) {
        var target = void 0;
        var targetSelector = Util.getSelectorFromElement(element);
fat's avatar
fat committed
124

Mark Otto's avatar
grunt    
Mark Otto committed
125
126
127
        if (targetSelector) {
          target = $(targetSelector)[0];
        }
fat's avatar
fat committed
128

Mark Otto's avatar
grunt    
Mark Otto committed
129
130
131
132
133
134
        if (target) {
          var targetBCR = target.getBoundingClientRect();
          if (targetBCR.width || targetBCR.height) {
            // todo (fat): remove sketch reliance on jQuery position/offset
            return [$(target)[offsetMethod]().top + offsetBase, targetSelector];
          }
Mark Otto's avatar
grunt    
Mark Otto committed
135
136
137
138
139
140
141
        }
        return null;
      }).filter(function (item) {
        return item;
      }).sort(function (a, b) {
        return a[0] - b[0];
      }).forEach(function (item) {
Mark Otto's avatar
grunt    
Mark Otto committed
142
143
        _this2._offsets.push(item[0]);
        _this2._targets.push(item[1]);
Mark Otto's avatar
grunt    
Mark Otto committed
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
      });
    };

    ScrollSpy.prototype.dispose = function dispose() {
      $.removeData(this._element, DATA_KEY);
      $(this._scrollElement).off(EVENT_KEY);

      this._element = null;
      this._scrollElement = null;
      this._config = null;
      this._selector = null;
      this._offsets = null;
      this._targets = null;
      this._activeTarget = null;
      this._scrollHeight = null;
    };
fat's avatar
fat committed
160

Mark Otto's avatar
grunt    
Mark Otto committed
161
    // private
fat's avatar
fat committed
162

Mark Otto's avatar
grunt    
Mark Otto committed
163
164
    ScrollSpy.prototype._getConfig = function _getConfig(config) {
      config = $.extend({}, Default, config);
fat's avatar
fat committed
165

Mark Otto's avatar
grunt    
Mark Otto committed
166
167
168
169
170
      if (typeof config.target !== 'string') {
        var id = $(config.target).attr('id');
        if (!id) {
          id = Util.getUID(NAME);
          $(config.target).attr('id', id);
fat's avatar
fat committed
171
        }
Mark Otto's avatar
grunt    
Mark Otto committed
172
173
        config.target = '#' + id;
      }
fat's avatar
fat committed
174

Mark Otto's avatar
grunt    
Mark Otto committed
175
      Util.typeCheckConfig(NAME, config, DefaultType);
fat's avatar
fat committed
176

Mark Otto's avatar
grunt    
Mark Otto committed
177
178
179
180
      return config;
    };

    ScrollSpy.prototype._getScrollTop = function _getScrollTop() {
Mark Otto's avatar
grunt    
Mark Otto committed
181
      return this._scrollElement === window ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop;
Mark Otto's avatar
grunt    
Mark Otto committed
182
183
184
185
186
187
    };

    ScrollSpy.prototype._getScrollHeight = function _getScrollHeight() {
      return this._scrollElement.scrollHeight || Math.max(document.body.scrollHeight, document.documentElement.scrollHeight);
    };

matus's avatar
matus committed
188
    ScrollSpy.prototype._getOffsetHeight = function _getOffsetHeight() {
Mark Otto's avatar
grunt    
Mark Otto committed
189
      return this._scrollElement === window ? window.innerHeight : this._scrollElement.getBoundingClientRect().height;
matus's avatar
matus committed
190
191
    };

Mark Otto's avatar
grunt    
Mark Otto committed
192
193
194
    ScrollSpy.prototype._process = function _process() {
      var scrollTop = this._getScrollTop() + this._config.offset;
      var scrollHeight = this._getScrollHeight();
matus's avatar
matus committed
195
      var maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight();
Mark Otto's avatar
grunt    
Mark Otto committed
196
197
198

      if (this._scrollHeight !== scrollHeight) {
        this.refresh();
fat's avatar
fat committed
199
200
      }

Mark Otto's avatar
grunt    
Mark Otto committed
201
202
      if (scrollTop >= maxScroll) {
        var target = this._targets[this._targets.length - 1];
fat's avatar
fat committed
203

Mark Otto's avatar
grunt    
Mark Otto committed
204
205
        if (this._activeTarget !== target) {
          this._activate(target);
fat's avatar
fat committed
206
        }
matus's avatar
matus committed
207
        return;
Mark Otto's avatar
grunt    
Mark Otto committed
208
      }
fat's avatar
fat committed
209

Mark Otto's avatar
grunt    
Mark Otto committed
210
      if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) {
Mark Otto's avatar
grunt    
Mark Otto committed
211
212
213
214
        this._activeTarget = null;
        this._clear();
        return;
      }
fat's avatar
fat committed
215

Mark Otto's avatar
grunt    
Mark Otto committed
216
217
      for (var i = this._offsets.length; i--;) {
        var isActiveTarget = this._activeTarget !== this._targets[i] && scrollTop >= this._offsets[i] && (this._offsets[i + 1] === undefined || scrollTop < this._offsets[i + 1]);
fat's avatar
fat committed
218

Mark Otto's avatar
grunt    
Mark Otto committed
219
220
        if (isActiveTarget) {
          this._activate(this._targets[i]);
fat's avatar
fat committed
221
222
        }
      }
Mark Otto's avatar
grunt    
Mark Otto committed
223
    };
fat's avatar
fat committed
224

Mark Otto's avatar
grunt    
Mark Otto committed
225
226
    ScrollSpy.prototype._activate = function _activate(target) {
      this._activeTarget = target;
fat's avatar
fat committed
227

Mark Otto's avatar
grunt    
Mark Otto committed
228
      this._clear();
fat's avatar
fat committed
229

Mark Otto's avatar
grunt    
Mark Otto committed
230
231
232
233
      var queries = this._selector.split(',');
      queries = queries.map(function (selector) {
        return selector + '[data-target="' + target + '"],' + (selector + '[href="' + target + '"]');
      });
fat's avatar
fat committed
234

Mark Otto's avatar
grunt    
Mark Otto committed
235
      var $link = $(queries.join(','));
fat's avatar
fat committed
236

Mark Otto's avatar
grunt    
Mark Otto committed
237
238
239
240
241
242
      if ($link.hasClass(ClassName.DROPDOWN_ITEM)) {
        $link.closest(Selector.DROPDOWN).find(Selector.DROPDOWN_TOGGLE).addClass(ClassName.ACTIVE);
        $link.addClass(ClassName.ACTIVE);
      } else {
        // todo (fat) this is kinda sus...
        // recursively add actives to tested nav-links
Mark Otto's avatar
grunt    
Mark Otto committed
243
        $link.parents(Selector.LI).find('> ' + Selector.NAV_LINKS).addClass(ClassName.ACTIVE);
fat's avatar
fat committed
244
245
      }

Mark Otto's avatar
grunt    
Mark Otto committed
246
247
248
249
      $(this._scrollElement).trigger(Event.ACTIVATE, {
        relatedTarget: target
      });
    };
fat's avatar
fat committed
250

Mark Otto's avatar
grunt    
Mark Otto committed
251
252
253
    ScrollSpy.prototype._clear = function _clear() {
      $(this._selector).filter(Selector.ACTIVE).removeClass(ClassName.ACTIVE);
    };
fat's avatar
fat committed
254

Mark Otto's avatar
grunt    
Mark Otto committed
255
    // static
fat's avatar
fat committed
256

Mark Otto's avatar
grunt    
Mark Otto committed
257
258
259
    ScrollSpy._jQueryInterface = function _jQueryInterface(config) {
      return this.each(function () {
        var data = $(this).data(DATA_KEY);
Mark Otto's avatar
grunt    
Mark Otto committed
260
        var _config = (typeof config === 'undefined' ? 'undefined' : _typeof(config)) === 'object' && config;
Mark Otto's avatar
grunt    
Mark Otto committed
261
262
263
264
265
266
267
268
269

        if (!data) {
          data = new ScrollSpy(this, _config);
          $(this).data(DATA_KEY, data);
        }

        if (typeof config === 'string') {
          if (data[config] === undefined) {
            throw new Error('No method named "' + config + '"');
fat's avatar
fat committed
270
          }
Mark Otto's avatar
grunt    
Mark Otto committed
271
272
273
274
275
276
          data[config]();
        }
      });
    };

    _createClass(ScrollSpy, null, [{
Jacob Thornton's avatar
Jacob Thornton committed
277
278
279
280
281
282
283
284
285
      key: 'VERSION',
      get: function get() {
        return VERSION;
      }
    }, {
      key: 'Default',
      get: function get() {
        return Default;
      }
fat's avatar
fat committed
286
287
288
    }]);

    return ScrollSpy;
Mark Otto's avatar
grunt    
Mark Otto committed
289
290
291
292
293
294
295
  }();

  /**
   * ------------------------------------------------------------------------
   * Data Api implementation
   * ------------------------------------------------------------------------
   */
fat's avatar
fat committed
296

fat's avatar
fat committed
297
  $(window).on(Event.LOAD_DATA_API, function () {
fat's avatar
fat committed
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
    var scrollSpys = $.makeArray($(Selector.DATA_SPY));

    for (var i = scrollSpys.length; i--;) {
      var $spy = $(scrollSpys[i]);
      ScrollSpy._jQueryInterface.call($spy, $spy.data());
    }
  });

  /**
   * ------------------------------------------------------------------------
   * jQuery
   * ------------------------------------------------------------------------
   */

  $.fn[NAME] = ScrollSpy._jQueryInterface;
  $.fn[NAME].Constructor = ScrollSpy;
  $.fn[NAME].noConflict = function () {
    $.fn[NAME] = JQUERY_NO_CONFLICT;
    return ScrollSpy._jQueryInterface;
  };

  return ScrollSpy;
Mark Otto's avatar
grunt    
Mark Otto committed
320
}(jQuery);
Jacob Thornton's avatar
Jacob Thornton committed
321
//# sourceMappingURL=scrollspy.js.map