scrollspy.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. /*!
  2. * Bootstrap scrollspy.js v4.6.2 (https://getbootstrap.com/)
  3. * Copyright 2011-2022 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
  4. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  5. */
  6. (function (global, factory) {
  7. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery'), require('./util.js')) :
  8. typeof define === 'function' && define.amd ? define(['jquery', './util'], factory) :
  9. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.ScrollSpy = factory(global.jQuery, global.Util));
  10. })(this, (function ($, Util) { 'use strict';
  11. function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
  12. var $__default = /*#__PURE__*/_interopDefaultLegacy($);
  13. var Util__default = /*#__PURE__*/_interopDefaultLegacy(Util);
  14. function _defineProperties(target, props) {
  15. for (var i = 0; i < props.length; i++) {
  16. var descriptor = props[i];
  17. descriptor.enumerable = descriptor.enumerable || false;
  18. descriptor.configurable = true;
  19. if ("value" in descriptor) descriptor.writable = true;
  20. Object.defineProperty(target, descriptor.key, descriptor);
  21. }
  22. }
  23. function _createClass(Constructor, protoProps, staticProps) {
  24. if (protoProps) _defineProperties(Constructor.prototype, protoProps);
  25. if (staticProps) _defineProperties(Constructor, staticProps);
  26. Object.defineProperty(Constructor, "prototype", {
  27. writable: false
  28. });
  29. return Constructor;
  30. }
  31. function _extends() {
  32. _extends = Object.assign ? Object.assign.bind() : function (target) {
  33. for (var i = 1; i < arguments.length; i++) {
  34. var source = arguments[i];
  35. for (var key in source) {
  36. if (Object.prototype.hasOwnProperty.call(source, key)) {
  37. target[key] = source[key];
  38. }
  39. }
  40. }
  41. return target;
  42. };
  43. return _extends.apply(this, arguments);
  44. }
  45. /**
  46. * Constants
  47. */
  48. var NAME = 'scrollspy';
  49. var VERSION = '4.6.2';
  50. var DATA_KEY = 'bs.scrollspy';
  51. var EVENT_KEY = "." + DATA_KEY;
  52. var DATA_API_KEY = '.data-api';
  53. var JQUERY_NO_CONFLICT = $__default["default"].fn[NAME];
  54. var CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item';
  55. var CLASS_NAME_ACTIVE = 'active';
  56. var EVENT_ACTIVATE = "activate" + EVENT_KEY;
  57. var EVENT_SCROLL = "scroll" + EVENT_KEY;
  58. var EVENT_LOAD_DATA_API = "load" + EVENT_KEY + DATA_API_KEY;
  59. var METHOD_OFFSET = 'offset';
  60. var METHOD_POSITION = 'position';
  61. var SELECTOR_DATA_SPY = '[data-spy="scroll"]';
  62. var SELECTOR_NAV_LIST_GROUP = '.nav, .list-group';
  63. var SELECTOR_NAV_LINKS = '.nav-link';
  64. var SELECTOR_NAV_ITEMS = '.nav-item';
  65. var SELECTOR_LIST_ITEMS = '.list-group-item';
  66. var SELECTOR_DROPDOWN = '.dropdown';
  67. var SELECTOR_DROPDOWN_ITEMS = '.dropdown-item';
  68. var SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle';
  69. var Default = {
  70. offset: 10,
  71. method: 'auto',
  72. target: ''
  73. };
  74. var DefaultType = {
  75. offset: 'number',
  76. method: 'string',
  77. target: '(string|element)'
  78. };
  79. /**
  80. * Class definition
  81. */
  82. var ScrollSpy = /*#__PURE__*/function () {
  83. function ScrollSpy(element, config) {
  84. var _this = this;
  85. this._element = element;
  86. this._scrollElement = element.tagName === 'BODY' ? window : element;
  87. this._config = this._getConfig(config);
  88. this._selector = this._config.target + " " + SELECTOR_NAV_LINKS + "," + (this._config.target + " " + SELECTOR_LIST_ITEMS + ",") + (this._config.target + " " + SELECTOR_DROPDOWN_ITEMS);
  89. this._offsets = [];
  90. this._targets = [];
  91. this._activeTarget = null;
  92. this._scrollHeight = 0;
  93. $__default["default"](this._scrollElement).on(EVENT_SCROLL, function (event) {
  94. return _this._process(event);
  95. });
  96. this.refresh();
  97. this._process();
  98. } // Getters
  99. var _proto = ScrollSpy.prototype;
  100. // Public
  101. _proto.refresh = function refresh() {
  102. var _this2 = this;
  103. var autoMethod = this._scrollElement === this._scrollElement.window ? METHOD_OFFSET : METHOD_POSITION;
  104. var offsetMethod = this._config.method === 'auto' ? autoMethod : this._config.method;
  105. var offsetBase = offsetMethod === METHOD_POSITION ? this._getScrollTop() : 0;
  106. this._offsets = [];
  107. this._targets = [];
  108. this._scrollHeight = this._getScrollHeight();
  109. var targets = [].slice.call(document.querySelectorAll(this._selector));
  110. targets.map(function (element) {
  111. var target;
  112. var targetSelector = Util__default["default"].getSelectorFromElement(element);
  113. if (targetSelector) {
  114. target = document.querySelector(targetSelector);
  115. }
  116. if (target) {
  117. var targetBCR = target.getBoundingClientRect();
  118. if (targetBCR.width || targetBCR.height) {
  119. // TODO (fat): remove sketch reliance on jQuery position/offset
  120. return [$__default["default"](target)[offsetMethod]().top + offsetBase, targetSelector];
  121. }
  122. }
  123. return null;
  124. }).filter(Boolean).sort(function (a, b) {
  125. return a[0] - b[0];
  126. }).forEach(function (item) {
  127. _this2._offsets.push(item[0]);
  128. _this2._targets.push(item[1]);
  129. });
  130. };
  131. _proto.dispose = function dispose() {
  132. $__default["default"].removeData(this._element, DATA_KEY);
  133. $__default["default"](this._scrollElement).off(EVENT_KEY);
  134. this._element = null;
  135. this._scrollElement = null;
  136. this._config = null;
  137. this._selector = null;
  138. this._offsets = null;
  139. this._targets = null;
  140. this._activeTarget = null;
  141. this._scrollHeight = null;
  142. } // Private
  143. ;
  144. _proto._getConfig = function _getConfig(config) {
  145. config = _extends({}, Default, typeof config === 'object' && config ? config : {});
  146. if (typeof config.target !== 'string' && Util__default["default"].isElement(config.target)) {
  147. var id = $__default["default"](config.target).attr('id');
  148. if (!id) {
  149. id = Util__default["default"].getUID(NAME);
  150. $__default["default"](config.target).attr('id', id);
  151. }
  152. config.target = "#" + id;
  153. }
  154. Util__default["default"].typeCheckConfig(NAME, config, DefaultType);
  155. return config;
  156. };
  157. _proto._getScrollTop = function _getScrollTop() {
  158. return this._scrollElement === window ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop;
  159. };
  160. _proto._getScrollHeight = function _getScrollHeight() {
  161. return this._scrollElement.scrollHeight || Math.max(document.body.scrollHeight, document.documentElement.scrollHeight);
  162. };
  163. _proto._getOffsetHeight = function _getOffsetHeight() {
  164. return this._scrollElement === window ? window.innerHeight : this._scrollElement.getBoundingClientRect().height;
  165. };
  166. _proto._process = function _process() {
  167. var scrollTop = this._getScrollTop() + this._config.offset;
  168. var scrollHeight = this._getScrollHeight();
  169. var maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight();
  170. if (this._scrollHeight !== scrollHeight) {
  171. this.refresh();
  172. }
  173. if (scrollTop >= maxScroll) {
  174. var target = this._targets[this._targets.length - 1];
  175. if (this._activeTarget !== target) {
  176. this._activate(target);
  177. }
  178. return;
  179. }
  180. if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) {
  181. this._activeTarget = null;
  182. this._clear();
  183. return;
  184. }
  185. for (var i = this._offsets.length; i--;) {
  186. var isActiveTarget = this._activeTarget !== this._targets[i] && scrollTop >= this._offsets[i] && (typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1]);
  187. if (isActiveTarget) {
  188. this._activate(this._targets[i]);
  189. }
  190. }
  191. };
  192. _proto._activate = function _activate(target) {
  193. this._activeTarget = target;
  194. this._clear();
  195. var queries = this._selector.split(',').map(function (selector) {
  196. return selector + "[data-target=\"" + target + "\"]," + selector + "[href=\"" + target + "\"]";
  197. });
  198. var $link = $__default["default"]([].slice.call(document.querySelectorAll(queries.join(','))));
  199. if ($link.hasClass(CLASS_NAME_DROPDOWN_ITEM)) {
  200. $link.closest(SELECTOR_DROPDOWN).find(SELECTOR_DROPDOWN_TOGGLE).addClass(CLASS_NAME_ACTIVE);
  201. $link.addClass(CLASS_NAME_ACTIVE);
  202. } else {
  203. // Set triggered link as active
  204. $link.addClass(CLASS_NAME_ACTIVE); // Set triggered links parents as active
  205. // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor
  206. $link.parents(SELECTOR_NAV_LIST_GROUP).prev(SELECTOR_NAV_LINKS + ", " + SELECTOR_LIST_ITEMS).addClass(CLASS_NAME_ACTIVE); // Handle special case when .nav-link is inside .nav-item
  207. $link.parents(SELECTOR_NAV_LIST_GROUP).prev(SELECTOR_NAV_ITEMS).children(SELECTOR_NAV_LINKS).addClass(CLASS_NAME_ACTIVE);
  208. }
  209. $__default["default"](this._scrollElement).trigger(EVENT_ACTIVATE, {
  210. relatedTarget: target
  211. });
  212. };
  213. _proto._clear = function _clear() {
  214. [].slice.call(document.querySelectorAll(this._selector)).filter(function (node) {
  215. return node.classList.contains(CLASS_NAME_ACTIVE);
  216. }).forEach(function (node) {
  217. return node.classList.remove(CLASS_NAME_ACTIVE);
  218. });
  219. } // Static
  220. ;
  221. ScrollSpy._jQueryInterface = function _jQueryInterface(config) {
  222. return this.each(function () {
  223. var data = $__default["default"](this).data(DATA_KEY);
  224. var _config = typeof config === 'object' && config;
  225. if (!data) {
  226. data = new ScrollSpy(this, _config);
  227. $__default["default"](this).data(DATA_KEY, data);
  228. }
  229. if (typeof config === 'string') {
  230. if (typeof data[config] === 'undefined') {
  231. throw new TypeError("No method named \"" + config + "\"");
  232. }
  233. data[config]();
  234. }
  235. });
  236. };
  237. _createClass(ScrollSpy, null, [{
  238. key: "VERSION",
  239. get: function get() {
  240. return VERSION;
  241. }
  242. }, {
  243. key: "Default",
  244. get: function get() {
  245. return Default;
  246. }
  247. }]);
  248. return ScrollSpy;
  249. }();
  250. /**
  251. * Data API implementation
  252. */
  253. $__default["default"](window).on(EVENT_LOAD_DATA_API, function () {
  254. var scrollSpys = [].slice.call(document.querySelectorAll(SELECTOR_DATA_SPY));
  255. var scrollSpysLength = scrollSpys.length;
  256. for (var i = scrollSpysLength; i--;) {
  257. var $spy = $__default["default"](scrollSpys[i]);
  258. ScrollSpy._jQueryInterface.call($spy, $spy.data());
  259. }
  260. });
  261. /**
  262. * jQuery
  263. */
  264. $__default["default"].fn[NAME] = ScrollSpy._jQueryInterface;
  265. $__default["default"].fn[NAME].Constructor = ScrollSpy;
  266. $__default["default"].fn[NAME].noConflict = function () {
  267. $__default["default"].fn[NAME] = JQUERY_NO_CONFLICT;
  268. return ScrollSpy._jQueryInterface;
  269. };
  270. return ScrollSpy;
  271. }));
  272. //# sourceMappingURL=scrollspy.js.map