mirror of
https://github.com/mdbootstrap/mdb-ui-kit.git
synced 2025-03-27 05:14:23 +03:00
578 lines
17 KiB
JavaScript
578 lines
17 KiB
JavaScript
/*!
|
|
* Bootstrap scrollspy.js v5.0.0-beta1 (https://getbootstrap.com/)
|
|
* Copyright 2011-2020 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
|
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|
*/
|
|
(function (global, factory) {
|
|
typeof exports === 'object' && typeof module !== 'undefined'
|
|
? (module.exports = factory(
|
|
require('./dom/data.js'),
|
|
require('./dom/event-handler.js'),
|
|
require('./dom/manipulator.js'),
|
|
require('./dom/selector-engine.js')
|
|
))
|
|
: typeof define === 'function' && define.amd
|
|
? define([
|
|
'./dom/data',
|
|
'./dom/event-handler',
|
|
'./dom/manipulator',
|
|
'./dom/selector-engine',
|
|
], factory)
|
|
: ((global = typeof globalThis !== 'undefined' ? globalThis : global || self),
|
|
(global.ScrollSpy = factory(
|
|
global.Data,
|
|
global.EventHandler,
|
|
global.Manipulator,
|
|
global.SelectorEngine
|
|
)));
|
|
})(this, function (Data, EventHandler, Manipulator, SelectorEngine) {
|
|
'use strict';
|
|
|
|
function _interopDefaultLegacy(e) {
|
|
return e && typeof e === 'object' && 'default' in e ? e : { default: e };
|
|
}
|
|
|
|
var Data__default = /*#__PURE__*/ _interopDefaultLegacy(Data);
|
|
var EventHandler__default = /*#__PURE__*/ _interopDefaultLegacy(EventHandler);
|
|
var Manipulator__default = /*#__PURE__*/ _interopDefaultLegacy(Manipulator);
|
|
var SelectorEngine__default = /*#__PURE__*/ _interopDefaultLegacy(SelectorEngine);
|
|
|
|
/**
|
|
* --------------------------------------------------------------------------
|
|
* Bootstrap (v5.0.0-beta1): util/index.js
|
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|
* --------------------------------------------------------------------------
|
|
*/
|
|
var MAX_UID = 1000000;
|
|
|
|
var toType = function toType(obj) {
|
|
if (obj === null || obj === undefined) {
|
|
return '' + obj;
|
|
}
|
|
|
|
return {}.toString
|
|
.call(obj)
|
|
.match(/\s([a-z]+)/i)[1]
|
|
.toLowerCase();
|
|
};
|
|
/**
|
|
* --------------------------------------------------------------------------
|
|
* Public Util Api
|
|
* --------------------------------------------------------------------------
|
|
*/
|
|
|
|
var getUID = function getUID(prefix) {
|
|
do {
|
|
prefix += Math.floor(Math.random() * MAX_UID);
|
|
} while (document.getElementById(prefix));
|
|
|
|
return prefix;
|
|
};
|
|
|
|
var getSelector = function getSelector(element) {
|
|
var selector = element.getAttribute('data-bs-target');
|
|
|
|
if (!selector || selector === '#') {
|
|
var hrefAttr = element.getAttribute('href');
|
|
selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null;
|
|
}
|
|
|
|
return selector;
|
|
};
|
|
|
|
var getSelectorFromElement = function getSelectorFromElement(element) {
|
|
var selector = getSelector(element);
|
|
|
|
if (selector) {
|
|
return document.querySelector(selector) ? selector : null;
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
var isElement = function isElement(obj) {
|
|
return (obj[0] || obj).nodeType;
|
|
};
|
|
|
|
var typeCheckConfig = function typeCheckConfig(componentName, config, configTypes) {
|
|
Object.keys(configTypes).forEach(function (property) {
|
|
var expectedTypes = configTypes[property];
|
|
var value = config[property];
|
|
var valueType = value && isElement(value) ? 'element' : toType(value);
|
|
|
|
if (!new RegExp(expectedTypes).test(valueType)) {
|
|
throw new Error(
|
|
componentName.toUpperCase() +
|
|
': ' +
|
|
('Option "' + property + '" provided type "' + valueType + '" ') +
|
|
('but expected type "' + expectedTypes + '".')
|
|
);
|
|
}
|
|
});
|
|
};
|
|
|
|
var getjQuery = function getjQuery() {
|
|
var _window = window,
|
|
jQuery = _window.jQuery;
|
|
|
|
if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
|
|
return jQuery;
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
var onDOMContentLoaded = function onDOMContentLoaded(callback) {
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', callback);
|
|
} else {
|
|
callback();
|
|
}
|
|
};
|
|
|
|
var isRTL = document.documentElement.dir === 'rtl';
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
function _createClass(Constructor, protoProps, staticProps) {
|
|
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
|
|
if (staticProps) _defineProperties(Constructor, staticProps);
|
|
return Constructor;
|
|
}
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Constants
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
var VERSION = '5.0.0-beta1';
|
|
|
|
var BaseComponent = /*#__PURE__*/ (function () {
|
|
function BaseComponent(element) {
|
|
if (!element) {
|
|
return;
|
|
}
|
|
|
|
this._element = element;
|
|
Data__default['default'].setData(element, this.constructor.DATA_KEY, this);
|
|
}
|
|
|
|
var _proto = BaseComponent.prototype;
|
|
|
|
_proto.dispose = function dispose() {
|
|
Data__default['default'].removeData(this._element, this.constructor.DATA_KEY);
|
|
this._element = null;
|
|
};
|
|
/** Static */
|
|
|
|
BaseComponent.getInstance = function getInstance(element) {
|
|
return Data__default['default'].getData(element, this.DATA_KEY);
|
|
};
|
|
|
|
_createClass(BaseComponent, null, [
|
|
{
|
|
key: 'VERSION',
|
|
get: function get() {
|
|
return VERSION;
|
|
},
|
|
},
|
|
]);
|
|
|
|
return BaseComponent;
|
|
})();
|
|
|
|
function _extends() {
|
|
_extends =
|
|
Object.assign ||
|
|
function (target) {
|
|
for (var i = 1; i < arguments.length; i++) {
|
|
var source = arguments[i];
|
|
for (var key in source) {
|
|
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
target[key] = source[key];
|
|
}
|
|
}
|
|
}
|
|
return target;
|
|
};
|
|
return _extends.apply(this, arguments);
|
|
}
|
|
|
|
function _defineProperties$1(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);
|
|
}
|
|
}
|
|
|
|
function _createClass$1(Constructor, protoProps, staticProps) {
|
|
if (protoProps) _defineProperties$1(Constructor.prototype, protoProps);
|
|
if (staticProps) _defineProperties$1(Constructor, staticProps);
|
|
return Constructor;
|
|
}
|
|
|
|
function _inheritsLoose(subClass, superClass) {
|
|
subClass.prototype = Object.create(superClass.prototype);
|
|
subClass.prototype.constructor = subClass;
|
|
subClass.__proto__ = superClass;
|
|
}
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Constants
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
var NAME = 'scrollspy';
|
|
var DATA_KEY = 'bs.scrollspy';
|
|
var EVENT_KEY = '.' + DATA_KEY;
|
|
var DATA_API_KEY = '.data-api';
|
|
var Default = {
|
|
offset: 10,
|
|
method: 'auto',
|
|
target: '',
|
|
};
|
|
var DefaultType = {
|
|
offset: 'number',
|
|
method: 'string',
|
|
target: '(string|element)',
|
|
};
|
|
var EVENT_ACTIVATE = 'activate' + EVENT_KEY;
|
|
var EVENT_SCROLL = 'scroll' + EVENT_KEY;
|
|
var EVENT_LOAD_DATA_API = 'load' + EVENT_KEY + DATA_API_KEY;
|
|
var CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item';
|
|
var CLASS_NAME_ACTIVE = 'active';
|
|
var SELECTOR_DATA_SPY = '[data-bs-spy="scroll"]';
|
|
var SELECTOR_NAV_LIST_GROUP = '.nav, .list-group';
|
|
var SELECTOR_NAV_LINKS = '.nav-link';
|
|
var SELECTOR_NAV_ITEMS = '.nav-item';
|
|
var SELECTOR_LIST_ITEMS = '.list-group-item';
|
|
var SELECTOR_DROPDOWN = '.dropdown';
|
|
var SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle';
|
|
var METHOD_OFFSET = 'offset';
|
|
var METHOD_POSITION = 'position';
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Class Definition
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
var ScrollSpy = /*#__PURE__*/ (function (_BaseComponent) {
|
|
_inheritsLoose(ScrollSpy, _BaseComponent);
|
|
|
|
function ScrollSpy(element, config) {
|
|
var _this;
|
|
|
|
_this = _BaseComponent.call(this, element) || this;
|
|
_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 +
|
|
' .' +
|
|
CLASS_NAME_DROPDOWN_ITEM;
|
|
_this._offsets = [];
|
|
_this._targets = [];
|
|
_this._activeTarget = null;
|
|
_this._scrollHeight = 0;
|
|
EventHandler__default['default'].on(_this._scrollElement, EVENT_SCROLL, function (event) {
|
|
return _this._process(event);
|
|
});
|
|
|
|
_this.refresh();
|
|
|
|
_this._process();
|
|
|
|
return _this;
|
|
} // Getters
|
|
|
|
var _proto = ScrollSpy.prototype;
|
|
|
|
// Public
|
|
_proto.refresh = function refresh() {
|
|
var _this2 = this;
|
|
|
|
var autoMethod =
|
|
this._scrollElement === this._scrollElement.window ? METHOD_OFFSET : METHOD_POSITION;
|
|
var offsetMethod = this._config.method === 'auto' ? autoMethod : this._config.method;
|
|
var offsetBase = offsetMethod === METHOD_POSITION ? this._getScrollTop() : 0;
|
|
this._offsets = [];
|
|
this._targets = [];
|
|
this._scrollHeight = this._getScrollHeight();
|
|
var targets = SelectorEngine__default['default'].find(this._selector);
|
|
targets
|
|
.map(function (element) {
|
|
var targetSelector = getSelectorFromElement(element);
|
|
var target = targetSelector
|
|
? SelectorEngine__default['default'].findOne(targetSelector)
|
|
: null;
|
|
|
|
if (target) {
|
|
var targetBCR = target.getBoundingClientRect();
|
|
|
|
if (targetBCR.width || targetBCR.height) {
|
|
return [
|
|
Manipulator__default['default'][offsetMethod](target).top + offsetBase,
|
|
targetSelector,
|
|
];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
})
|
|
.filter(function (item) {
|
|
return item;
|
|
})
|
|
.sort(function (a, b) {
|
|
return a[0] - b[0];
|
|
})
|
|
.forEach(function (item) {
|
|
_this2._offsets.push(item[0]);
|
|
|
|
_this2._targets.push(item[1]);
|
|
});
|
|
};
|
|
|
|
_proto.dispose = function dispose() {
|
|
_BaseComponent.prototype.dispose.call(this);
|
|
|
|
EventHandler__default['default'].off(this._scrollElement, EVENT_KEY);
|
|
this._scrollElement = null;
|
|
this._config = null;
|
|
this._selector = null;
|
|
this._offsets = null;
|
|
this._targets = null;
|
|
this._activeTarget = null;
|
|
this._scrollHeight = null;
|
|
}; // Private
|
|
|
|
_proto._getConfig = function _getConfig(config) {
|
|
config = _extends({}, Default, typeof config === 'object' && config ? config : {});
|
|
|
|
if (typeof config.target !== 'string' && isElement(config.target)) {
|
|
var id = config.target.id;
|
|
|
|
if (!id) {
|
|
id = getUID(NAME);
|
|
config.target.id = id;
|
|
}
|
|
|
|
config.target = '#' + id;
|
|
}
|
|
|
|
typeCheckConfig(NAME, config, DefaultType);
|
|
return config;
|
|
};
|
|
|
|
_proto._getScrollTop = function _getScrollTop() {
|
|
return this._scrollElement === window
|
|
? this._scrollElement.pageYOffset
|
|
: this._scrollElement.scrollTop;
|
|
};
|
|
|
|
_proto._getScrollHeight = function _getScrollHeight() {
|
|
return (
|
|
this._scrollElement.scrollHeight ||
|
|
Math.max(document.body.scrollHeight, document.documentElement.scrollHeight)
|
|
);
|
|
};
|
|
|
|
_proto._getOffsetHeight = function _getOffsetHeight() {
|
|
return this._scrollElement === window
|
|
? window.innerHeight
|
|
: this._scrollElement.getBoundingClientRect().height;
|
|
};
|
|
|
|
_proto._process = function _process() {
|
|
var scrollTop = this._getScrollTop() + this._config.offset;
|
|
|
|
var scrollHeight = this._getScrollHeight();
|
|
|
|
var maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight();
|
|
|
|
if (this._scrollHeight !== scrollHeight) {
|
|
this.refresh();
|
|
}
|
|
|
|
if (scrollTop >= maxScroll) {
|
|
var 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 (var i = this._offsets.length; i--; ) {
|
|
var 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]);
|
|
}
|
|
}
|
|
};
|
|
|
|
_proto._activate = function _activate(target) {
|
|
this._activeTarget = target;
|
|
|
|
this._clear();
|
|
|
|
var queries = this._selector.split(',').map(function (selector) {
|
|
return (
|
|
selector + '[data-bs-target="' + target + '"],' + selector + '[href="' + target + '"]'
|
|
);
|
|
});
|
|
|
|
var link = SelectorEngine__default['default'].findOne(queries.join(','));
|
|
|
|
if (link.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {
|
|
SelectorEngine__default['default']
|
|
.findOne(SELECTOR_DROPDOWN_TOGGLE, link.closest(SELECTOR_DROPDOWN))
|
|
.classList.add(CLASS_NAME_ACTIVE);
|
|
link.classList.add(CLASS_NAME_ACTIVE);
|
|
} else {
|
|
// Set triggered link as active
|
|
link.classList.add(CLASS_NAME_ACTIVE);
|
|
SelectorEngine__default['default']
|
|
.parents(link, SELECTOR_NAV_LIST_GROUP)
|
|
.forEach(function (listGroup) {
|
|
// Set triggered links parents as active
|
|
// With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor
|
|
SelectorEngine__default['default']
|
|
.prev(listGroup, SELECTOR_NAV_LINKS + ', ' + SELECTOR_LIST_ITEMS)
|
|
.forEach(function (item) {
|
|
return item.classList.add(CLASS_NAME_ACTIVE);
|
|
}); // Handle special case when .nav-link is inside .nav-item
|
|
|
|
SelectorEngine__default['default']
|
|
.prev(listGroup, SELECTOR_NAV_ITEMS)
|
|
.forEach(function (navItem) {
|
|
SelectorEngine__default['default']
|
|
.children(navItem, SELECTOR_NAV_LINKS)
|
|
.forEach(function (item) {
|
|
return item.classList.add(CLASS_NAME_ACTIVE);
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
EventHandler__default['default'].trigger(this._scrollElement, EVENT_ACTIVATE, {
|
|
relatedTarget: target,
|
|
});
|
|
};
|
|
|
|
_proto._clear = function _clear() {
|
|
SelectorEngine__default['default']
|
|
.find(this._selector)
|
|
.filter(function (node) {
|
|
return node.classList.contains(CLASS_NAME_ACTIVE);
|
|
})
|
|
.forEach(function (node) {
|
|
return node.classList.remove(CLASS_NAME_ACTIVE);
|
|
});
|
|
}; // Static
|
|
|
|
ScrollSpy.jQueryInterface = function jQueryInterface(config) {
|
|
return this.each(function () {
|
|
var data = Data__default['default'].getData(this, DATA_KEY);
|
|
|
|
var _config = typeof config === 'object' && config;
|
|
|
|
if (!data) {
|
|
data = new ScrollSpy(this, _config);
|
|
}
|
|
|
|
if (typeof config === 'string') {
|
|
if (typeof data[config] === 'undefined') {
|
|
throw new TypeError('No method named "' + config + '"');
|
|
}
|
|
|
|
data[config]();
|
|
}
|
|
});
|
|
};
|
|
|
|
_createClass$1(ScrollSpy, null, [
|
|
{
|
|
key: 'Default',
|
|
get: function get() {
|
|
return Default;
|
|
},
|
|
},
|
|
{
|
|
key: 'DATA_KEY',
|
|
get: function get() {
|
|
return DATA_KEY;
|
|
},
|
|
},
|
|
]);
|
|
|
|
return ScrollSpy;
|
|
})(BaseComponent);
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* Data Api implementation
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
EventHandler__default['default'].on(window, EVENT_LOAD_DATA_API, function () {
|
|
SelectorEngine__default['default'].find(SELECTOR_DATA_SPY).forEach(function (spy) {
|
|
return new ScrollSpy(spy, Manipulator__default['default'].getDataAttributes(spy));
|
|
});
|
|
});
|
|
/**
|
|
* ------------------------------------------------------------------------
|
|
* jQuery
|
|
* ------------------------------------------------------------------------
|
|
* add .ScrollSpy to jQuery only if jQuery is present
|
|
*/
|
|
|
|
onDOMContentLoaded(function () {
|
|
var $ = getjQuery();
|
|
/* istanbul ignore if */
|
|
|
|
if ($) {
|
|
var JQUERY_NO_CONFLICT = $.fn[NAME];
|
|
$.fn[NAME] = ScrollSpy.jQueryInterface;
|
|
$.fn[NAME].Constructor = ScrollSpy;
|
|
|
|
$.fn[NAME].noConflict = function () {
|
|
$.fn[NAME] = JQUERY_NO_CONFLICT;
|
|
return ScrollSpy.jQueryInterface;
|
|
};
|
|
}
|
|
});
|
|
|
|
return ScrollSpy;
|
|
});
|
|
//# sourceMappingURL=scrollspy.js.map
|