All Downloads are FREE. Search and download functionalities are using the official Maven repository.

package.js.dist.scrollspy.js.map Maven / Gradle / Ivy

Go to download

Orange Boosted with Bootstrap is a Bootstrap based, Orange branded accessible and ergonomic components library.

The newest version!
{"version":3,"file":"scrollspy.js","sources":["../src/scrollspy.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap scrollspy.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n  defineJQueryPlugin, getElement, isDisabled, isVisible\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'scrollspy'\nconst DATA_KEY = 'bs.scrollspy'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_ACTIVATE = `activate${EVENT_KEY}`\nconst EVENT_CLICK = `click${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'\nconst CLASS_NAME_ACTIVE = 'active'\n\nconst SELECTOR_DATA_SPY = '[data-bs-spy=\"scroll\"]'\nconst SELECTOR_TARGET_LINKS = '[href]'\nconst SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'\nconst SELECTOR_NAV_LINKS = '.nav-link'\nconst SELECTOR_NAV_ITEMS = '.nav-item'\nconst SELECTOR_LIST_ITEMS = '.list-group-item'\nconst SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`\nconst SELECTOR_DROPDOWN = '.dropdown'\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\n\nconst Default = {\n  offset: null, // TODO: v6 @deprecated, keep it for backwards compatibility reasons\n  rootMargin: '0px 0px -25%',\n  smoothScroll: false,\n  target: null,\n  threshold: [0.1, 0.5, 1]\n}\n\nconst DefaultType = {\n  offset: '(number|null)', // TODO v6 @deprecated, keep it for backwards compatibility reasons\n  rootMargin: 'string',\n  smoothScroll: 'boolean',\n  target: 'element',\n  threshold: 'array'\n}\n\n/**\n * Class definition\n */\n\nclass ScrollSpy extends BaseComponent {\n  constructor(element, config) {\n    super(element, config)\n\n    // this._element is the observablesContainer and config.target the menu links wrapper\n    this._targetLinks = new Map()\n    this._observableSections = new Map()\n    this._rootElement = getComputedStyle(this._element).overflowY === 'visible' ? null : this._element\n    this._activeTarget = null\n    this._observer = null\n    this._previousScrollData = {\n      visibleEntryTop: 0,\n      parentScrollTop: 0\n    }\n    this.refresh() // initialize\n  }\n\n  // Getters\n  static get Default() {\n    return Default\n  }\n\n  static get DefaultType() {\n    return DefaultType\n  }\n\n  static get NAME() {\n    return NAME\n  }\n\n  // Public\n  refresh() {\n    this._initializeTargetsAndObservables()\n    this._maybeEnableSmoothScroll()\n\n    if (this._observer) {\n      this._observer.disconnect()\n    } else {\n      this._observer = this._getNewObserver()\n    }\n\n    for (const section of this._observableSections.values()) {\n      this._observer.observe(section)\n    }\n  }\n\n  dispose() {\n    this._observer.disconnect()\n    super.dispose()\n  }\n\n  // Private\n  _configAfterMerge(config) {\n    // TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case\n    config.target = getElement(config.target) || document.body\n\n    // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only\n    config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin\n\n    if (typeof config.threshold === 'string') {\n      config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value))\n    }\n\n    return config\n  }\n\n  _maybeEnableSmoothScroll() {\n    if (!this._config.smoothScroll) {\n      return\n    }\n\n    // unregister any previous listeners\n    EventHandler.off(this._config.target, EVENT_CLICK)\n\n    EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, event => {\n      const observableSection = this._observableSections.get(event.target.hash)\n      if (observableSection) {\n        event.preventDefault()\n        const root = this._rootElement || window\n        const height = observableSection.offsetTop - this._element.offsetTop\n        if (root.scrollTo) {\n          root.scrollTo({ top: height, behavior: 'smooth' })\n          return\n        }\n\n        // Chrome 60 doesn't support `scrollTo`\n        root.scrollTop = height\n      }\n    })\n  }\n\n  _getNewObserver() {\n    const options = {\n      root: this._rootElement,\n      threshold: this._config.threshold,\n      rootMargin: this._config.rootMargin\n    }\n\n    return new IntersectionObserver(entries => this._observerCallback(entries), options)\n  }\n\n  // The logic of selection\n  _observerCallback(entries) {\n    const targetElement = entry => this._targetLinks.get(`#${entry.target.id}`)\n    const activate = entry => {\n      this._previousScrollData.visibleEntryTop = entry.target.offsetTop\n      this._process(targetElement(entry))\n    }\n\n    const parentScrollTop = (this._rootElement || document.documentElement).scrollTop\n    const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop\n    this._previousScrollData.parentScrollTop = parentScrollTop\n\n    for (const entry of entries) {\n      if (!entry.isIntersecting) {\n        this._activeTarget = null\n        this._clearActiveClass(targetElement(entry))\n\n        continue\n      }\n\n      const entryIsLowerThanPrevious = entry.target.offsetTop >= this._previousScrollData.visibleEntryTop\n      // if we are scrolling down, pick the bigger offsetTop\n      if (userScrollsDown && entryIsLowerThanPrevious) {\n        activate(entry)\n        // if parent isn't scrolled, let's keep the first visible item, breaking the iteration\n        if (!parentScrollTop) {\n          return\n        }\n\n        continue\n      }\n\n      // if we are scrolling up, pick the smallest offsetTop\n      if (!userScrollsDown && !entryIsLowerThanPrevious) {\n        activate(entry)\n      }\n    }\n  }\n\n  _initializeTargetsAndObservables() {\n    this._targetLinks = new Map()\n    this._observableSections = new Map()\n\n    const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target)\n\n    for (const anchor of targetLinks) {\n      // ensure that the anchor has an id and is not disabled\n      if (!anchor.hash || isDisabled(anchor)) {\n        continue\n      }\n\n      const observableSection = SelectorEngine.findOne(decodeURI(anchor.hash), this._element)\n\n      // ensure that the observableSection exists & is visible\n      if (isVisible(observableSection)) {\n        this._targetLinks.set(decodeURI(anchor.hash), anchor)\n        this._observableSections.set(anchor.hash, observableSection)\n      }\n    }\n  }\n\n  _process(target) {\n    if (this._activeTarget === target) {\n      return\n    }\n\n    this._clearActiveClass(this._config.target)\n    this._activeTarget = target\n    target.classList.add(CLASS_NAME_ACTIVE)\n    this._activateParents(target)\n\n    EventHandler.trigger(this._element, EVENT_ACTIVATE, { relatedTarget: target })\n  }\n\n  _activateParents(target) {\n    // Activate dropdown parents\n    if (target.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {\n      SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE, target.closest(SELECTOR_DROPDOWN))\n        .classList.add(CLASS_NAME_ACTIVE)\n      return\n    }\n\n    for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) {\n      // Set triggered links parents as active\n      // With both 
    and




© 2015 - 2024 Weber Informatics LLC | Privacy Policy