scrollspy.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
  2. function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
  3. 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); } }
  4. function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
  5. /**
  6. * --------------------------------------------------------------------------
  7. * Bootstrap (v4.1.1): scrollspy.js
  8. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
  9. * --------------------------------------------------------------------------
  10. */
  11. var ScrollSpy = function ($) {
  12. /**
  13. * ------------------------------------------------------------------------
  14. * Constants
  15. * ------------------------------------------------------------------------
  16. */
  17. var NAME = 'scrollspy';
  18. var VERSION = '4.1.1';
  19. var DATA_KEY = 'bs.scrollspy';
  20. var EVENT_KEY = "." + DATA_KEY;
  21. var DATA_API_KEY = '.data-api';
  22. var JQUERY_NO_CONFLICT = $.fn[NAME];
  23. var Default = {
  24. offset: 10,
  25. method: 'auto',
  26. target: ''
  27. };
  28. var DefaultType = {
  29. offset: 'number',
  30. method: 'string',
  31. target: '(string|element)'
  32. };
  33. var Event = {
  34. ACTIVATE: "activate" + EVENT_KEY,
  35. SCROLL: "scroll" + EVENT_KEY,
  36. LOAD_DATA_API: "load" + EVENT_KEY + DATA_API_KEY
  37. };
  38. var ClassName = {
  39. DROPDOWN_ITEM: 'dropdown-item',
  40. DROPDOWN_MENU: 'dropdown-menu',
  41. ACTIVE: 'active'
  42. };
  43. var Selector = {
  44. DATA_SPY: '[data-spy="scroll"]',
  45. ACTIVE: '.active',
  46. NAV_LIST_GROUP: '.nav, .list-group',
  47. NAV_LINKS: '.nav-link',
  48. NAV_ITEMS: '.nav-item',
  49. LIST_ITEMS: '.list-group-item',
  50. DROPDOWN: '.dropdown',
  51. DROPDOWN_ITEMS: '.dropdown-item',
  52. DROPDOWN_TOGGLE: '.dropdown-toggle'
  53. };
  54. var OffsetMethod = {
  55. OFFSET: 'offset',
  56. POSITION: 'position'
  57. /**
  58. * ------------------------------------------------------------------------
  59. * Class Definition
  60. * ------------------------------------------------------------------------
  61. */
  62. };
  63. var ScrollSpy =
  64. /*#__PURE__*/
  65. function () {
  66. function ScrollSpy(element, config) {
  67. var _this = this;
  68. this._element = element;
  69. this._scrollElement = element.tagName === 'BODY' ? window : element;
  70. this._config = this._getConfig(config);
  71. this._selector = this._config.target + " " + Selector.NAV_LINKS + "," + (this._config.target + " " + Selector.LIST_ITEMS + ",") + (this._config.target + " " + Selector.DROPDOWN_ITEMS);
  72. this._offsets = [];
  73. this._targets = [];
  74. this._activeTarget = null;
  75. this._scrollHeight = 0;
  76. $(this._scrollElement).on(Event.SCROLL, function (event) {
  77. return _this._process(event);
  78. });
  79. this.refresh();
  80. this._process();
  81. } // Getters
  82. var _proto = ScrollSpy.prototype;
  83. // Public
  84. _proto.refresh = function refresh() {
  85. var _this2 = this;
  86. var autoMethod = this._scrollElement === this._scrollElement.window ? OffsetMethod.OFFSET : OffsetMethod.POSITION;
  87. var offsetMethod = this._config.method === 'auto' ? autoMethod : this._config.method;
  88. var offsetBase = offsetMethod === OffsetMethod.POSITION ? this._getScrollTop() : 0;
  89. this._offsets = [];
  90. this._targets = [];
  91. this._scrollHeight = this._getScrollHeight();
  92. var targets = $.makeArray($(this._selector));
  93. targets.map(function (element) {
  94. var target;
  95. var targetSelector = Util.getSelectorFromElement(element);
  96. if (targetSelector) {
  97. target = $(targetSelector)[0];
  98. }
  99. if (target) {
  100. var targetBCR = target.getBoundingClientRect();
  101. if (targetBCR.width || targetBCR.height) {
  102. // TODO (fat): remove sketch reliance on jQuery position/offset
  103. return [$(target)[offsetMethod]().top + offsetBase, targetSelector];
  104. }
  105. }
  106. return null;
  107. }).filter(function (item) {
  108. return item;
  109. }).sort(function (a, b) {
  110. return a[0] - b[0];
  111. }).forEach(function (item) {
  112. _this2._offsets.push(item[0]);
  113. _this2._targets.push(item[1]);
  114. });
  115. };
  116. _proto.dispose = function dispose() {
  117. $.removeData(this._element, DATA_KEY);
  118. $(this._scrollElement).off(EVENT_KEY);
  119. this._element = null;
  120. this._scrollElement = null;
  121. this._config = null;
  122. this._selector = null;
  123. this._offsets = null;
  124. this._targets = null;
  125. this._activeTarget = null;
  126. this._scrollHeight = null;
  127. }; // Private
  128. _proto._getConfig = function _getConfig(config) {
  129. config = _objectSpread({}, Default, typeof config === 'object' && config ? config : {});
  130. if (typeof config.target !== 'string') {
  131. var id = $(config.target).attr('id');
  132. if (!id) {
  133. id = Util.getUID(NAME);
  134. $(config.target).attr('id', id);
  135. }
  136. config.target = "#" + id;
  137. }
  138. Util.typeCheckConfig(NAME, config, DefaultType);
  139. return config;
  140. };
  141. _proto._getScrollTop = function _getScrollTop() {
  142. return this._scrollElement === window ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop;
  143. };
  144. _proto._getScrollHeight = function _getScrollHeight() {
  145. return this._scrollElement.scrollHeight || Math.max(document.body.scrollHeight, document.documentElement.scrollHeight);
  146. };
  147. _proto._getOffsetHeight = function _getOffsetHeight() {
  148. return this._scrollElement === window ? window.innerHeight : this._scrollElement.getBoundingClientRect().height;
  149. };
  150. _proto._process = function _process() {
  151. var scrollTop = this._getScrollTop() + this._config.offset;
  152. var scrollHeight = this._getScrollHeight();
  153. var maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight();
  154. if (this._scrollHeight !== scrollHeight) {
  155. this.refresh();
  156. }
  157. if (scrollTop >= maxScroll) {
  158. var target = this._targets[this._targets.length - 1];
  159. if (this._activeTarget !== target) {
  160. this._activate(target);
  161. }
  162. return;
  163. }
  164. if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) {
  165. this._activeTarget = null;
  166. this._clear();
  167. return;
  168. }
  169. for (var i = this._offsets.length; i--;) {
  170. var isActiveTarget = this._activeTarget !== this._targets[i] && scrollTop >= this._offsets[i] && (typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1]);
  171. if (isActiveTarget) {
  172. this._activate(this._targets[i]);
  173. }
  174. }
  175. };
  176. _proto._activate = function _activate(target) {
  177. this._activeTarget = target;
  178. this._clear();
  179. var queries = this._selector.split(','); // eslint-disable-next-line arrow-body-style
  180. queries = queries.map(function (selector) {
  181. return selector + "[data-target=\"" + target + "\"]," + (selector + "[href=\"" + target + "\"]");
  182. });
  183. var $link = $(queries.join(','));
  184. if ($link.hasClass(ClassName.DROPDOWN_ITEM)) {
  185. $link.closest(Selector.DROPDOWN).find(Selector.DROPDOWN_TOGGLE).addClass(ClassName.ACTIVE);
  186. $link.addClass(ClassName.ACTIVE);
  187. } else {
  188. // Set triggered link as active
  189. $link.addClass(ClassName.ACTIVE); // Set triggered links parents as active
  190. // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor
  191. $link.parents(Selector.NAV_LIST_GROUP).prev(Selector.NAV_LINKS + ", " + Selector.LIST_ITEMS).addClass(ClassName.ACTIVE); // Handle special case when .nav-link is inside .nav-item
  192. $link.parents(Selector.NAV_LIST_GROUP).prev(Selector.NAV_ITEMS).children(Selector.NAV_LINKS).addClass(ClassName.ACTIVE);
  193. }
  194. $(this._scrollElement).trigger(Event.ACTIVATE, {
  195. relatedTarget: target
  196. });
  197. };
  198. _proto._clear = function _clear() {
  199. $(this._selector).filter(Selector.ACTIVE).removeClass(ClassName.ACTIVE);
  200. }; // Static
  201. ScrollSpy._jQueryInterface = function _jQueryInterface(config) {
  202. return this.each(function () {
  203. var data = $(this).data(DATA_KEY);
  204. var _config = typeof config === 'object' && config;
  205. if (!data) {
  206. data = new ScrollSpy(this, _config);
  207. $(this).data(DATA_KEY, data);
  208. }
  209. if (typeof config === 'string') {
  210. if (typeof data[config] === 'undefined') {
  211. throw new TypeError("No method named \"" + config + "\"");
  212. }
  213. data[config]();
  214. }
  215. });
  216. };
  217. _createClass(ScrollSpy, null, [{
  218. key: "VERSION",
  219. get: function get() {
  220. return VERSION;
  221. }
  222. }, {
  223. key: "Default",
  224. get: function get() {
  225. return Default;
  226. }
  227. }]);
  228. return ScrollSpy;
  229. }();
  230. /**
  231. * ------------------------------------------------------------------------
  232. * Data Api implementation
  233. * ------------------------------------------------------------------------
  234. */
  235. $(window).on(Event.LOAD_DATA_API, function () {
  236. var scrollSpys = $.makeArray($(Selector.DATA_SPY));
  237. for (var i = scrollSpys.length; i--;) {
  238. var $spy = $(scrollSpys[i]);
  239. ScrollSpy._jQueryInterface.call($spy, $spy.data());
  240. }
  241. });
  242. /**
  243. * ------------------------------------------------------------------------
  244. * jQuery
  245. * ------------------------------------------------------------------------
  246. */
  247. $.fn[NAME] = ScrollSpy._jQueryInterface;
  248. $.fn[NAME].Constructor = ScrollSpy;
  249. $.fn[NAME].noConflict = function () {
  250. $.fn[NAME] = JQUERY_NO_CONFLICT;
  251. return ScrollSpy._jQueryInterface;
  252. };
  253. return ScrollSpy;
  254. }($);
  255. //# sourceMappingURL=scrollspy.js.map