From c5c60729062cc3d89be7447b5d330367417aa6f7 Mon Sep 17 00:00:00 2001 From: Matt Rude Date: Sat, 3 Feb 2018 21:08:46 -0600 Subject: Update --- assets/node_modules/bootstrap/js/src/scrollspy.js | 329 ++++++++++++++++++++++ 1 file changed, 329 insertions(+) create mode 100644 assets/node_modules/bootstrap/js/src/scrollspy.js (limited to 'assets/node_modules/bootstrap/js/src/scrollspy.js') diff --git a/assets/node_modules/bootstrap/js/src/scrollspy.js b/assets/node_modules/bootstrap/js/src/scrollspy.js new file mode 100644 index 0000000..6c9c6d1 --- /dev/null +++ b/assets/node_modules/bootstrap/js/src/scrollspy.js @@ -0,0 +1,329 @@ +import $ from 'jquery' +import Util from './util' + +/** + * -------------------------------------------------------------------------- + * Bootstrap (v4.0.0): scrollspy.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * -------------------------------------------------------------------------- + */ + +const ScrollSpy = (($) => { + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + const NAME = 'scrollspy' + const VERSION = '4.0.0' + const DATA_KEY = 'bs.scrollspy' + const EVENT_KEY = `.${DATA_KEY}` + const DATA_API_KEY = '.data-api' + const JQUERY_NO_CONFLICT = $.fn[NAME] + + const Default = { + offset : 10, + method : 'auto', + target : '' + } + + const DefaultType = { + offset : 'number', + method : 'string', + target : '(string|element)' + } + + const Event = { + ACTIVATE : `activate${EVENT_KEY}`, + SCROLL : `scroll${EVENT_KEY}`, + LOAD_DATA_API : `load${EVENT_KEY}${DATA_API_KEY}` + } + + const ClassName = { + DROPDOWN_ITEM : 'dropdown-item', + DROPDOWN_MENU : 'dropdown-menu', + ACTIVE : 'active' + } + + const Selector = { + DATA_SPY : '[data-spy="scroll"]', + ACTIVE : '.active', + NAV_LIST_GROUP : '.nav, .list-group', + NAV_LINKS : '.nav-link', + NAV_ITEMS : '.nav-item', + LIST_ITEMS : '.list-group-item', + DROPDOWN : '.dropdown', + DROPDOWN_ITEMS : '.dropdown-item', + DROPDOWN_TOGGLE : '.dropdown-toggle' + } + + const OffsetMethod = { + OFFSET : 'offset', + POSITION : 'position' + } + + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + class ScrollSpy { + constructor(element, config) { + this._element = element + this._scrollElement = element.tagName === 'BODY' ? window : element + this._config = this._getConfig(config) + this._selector = `${this._config.target} ${Selector.NAV_LINKS},` + + `${this._config.target} ${Selector.LIST_ITEMS},` + + `${this._config.target} ${Selector.DROPDOWN_ITEMS}` + this._offsets = [] + this._targets = [] + this._activeTarget = null + this._scrollHeight = 0 + + $(this._scrollElement).on(Event.SCROLL, (event) => this._process(event)) + + this.refresh() + this._process() + } + + // Getters + + static get VERSION() { + return VERSION + } + + static get Default() { + return Default + } + + // Public + + refresh() { + const autoMethod = this._scrollElement === this._scrollElement.window + ? OffsetMethod.OFFSET : OffsetMethod.POSITION + + const offsetMethod = this._config.method === 'auto' + ? autoMethod : this._config.method + + const offsetBase = offsetMethod === OffsetMethod.POSITION + ? this._getScrollTop() : 0 + + this._offsets = [] + this._targets = [] + + this._scrollHeight = this._getScrollHeight() + + const targets = $.makeArray($(this._selector)) + + targets + .map((element) => { + let target + const targetSelector = Util.getSelectorFromElement(element) + + if (targetSelector) { + target = $(targetSelector)[0] + } + + if (target) { + const targetBCR = target.getBoundingClientRect() + if (targetBCR.width || targetBCR.height) { + // TODO (fat): remove sketch reliance on jQuery position/offset + return [ + $(target)[offsetMethod]().top + offsetBase, + targetSelector + ] + } + } + return null + }) + .filter((item) => item) + .sort((a, b) => a[0] - b[0]) + .forEach((item) => { + this._offsets.push(item[0]) + this._targets.push(item[1]) + }) + } + + 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 + } + + // Private + + _getConfig(config) { + config = { + ...Default, + ...config + } + + if (typeof config.target !== 'string') { + let id = $(config.target).attr('id') + if (!id) { + id = Util.getUID(NAME) + $(config.target).attr('id', id) + } + config.target = `#${id}` + } + + Util.typeCheckConfig(NAME, config, DefaultType) + + return config + } + + _getScrollTop() { + return this._scrollElement === window + ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop + } + + _getScrollHeight() { + return this._scrollElement.scrollHeight || Math.max( + document.body.scrollHeight, + document.documentElement.scrollHeight + ) + } + + _getOffsetHeight() { + return this._scrollElement === window + ? window.innerHeight : this._scrollElement.getBoundingClientRect().height + } + + _process() { + const scrollTop = this._getScrollTop() + this._config.offset + const scrollHeight = this._getScrollHeight() + const maxScroll = this._config.offset + + scrollHeight - + this._getOffsetHeight() + + if (this._scrollHeight !== scrollHeight) { + this.refresh() + } + + if (scrollTop >= maxScroll) { + const target = this._targets[this._targets.length - 1] + + if (this._activeTarget !== target) { + this._activate(target) + } + return + } + + if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) { + this._activeTarget = null + this._clear() + return + } + + for (let i = this._offsets.length; i--;) { + const isActiveTarget = this._activeTarget !== this._targets[i] && + scrollTop >= this._offsets[i] && + (typeof this._offsets[i + 1] === 'undefined' || + scrollTop < this._offsets[i + 1]) + + if (isActiveTarget) { + this._activate(this._targets[i]) + } + } + } + + _activate(target) { + this._activeTarget = target + + this._clear() + + let queries = this._selector.split(',') + // eslint-disable-next-line arrow-body-style + queries = queries.map((selector) => { + return `${selector}[data-target="${target}"],` + + `${selector}[href="${target}"]` + }) + + const $link = $(queries.join(',')) + + if ($link.hasClass(ClassName.DROPDOWN_ITEM)) { + $link.closest(Selector.DROPDOWN).find(Selector.DROPDOWN_TOGGLE).addClass(ClassName.ACTIVE) + $link.addClass(ClassName.ACTIVE) + } else { + // Set triggered link as active + $link.addClass(ClassName.ACTIVE) + // Set triggered links parents as active + // With both