Files
odoo_source/addons/web/static/lib/bootstrap/js/scrollspy.js
T
Xavier Morel 8e17223c26 [FIX] web: remove bootstrap sourceMappingURL
We're not shipping the sourcemap files, and while the assets minifier
strips out the mappings they're getting hit in debug=assets which is
bot useless and problematic when running odoo-bin without a proxy for
static folders: if sourcemaps are enabled (which is apparently the
default in all browsers if devtools are opened at this point) the
browser tries to fetch the sourcemap, which does through the
SharedDataMiddleware which doesn't find them and passes the query on
to the regular Application which goes through the entire dispatch &
NotFound process.

If website is installed, that process ends up rendering website.404,
which can be pretty costly until everything is properly cached:

    # initial request
    "GET /web/static/lib/bootstrap/js/index.js.map HTTP/1.1" 404 - 319 0.198 0.954
    # a few requests later
    "GET /web/static/lib/bootstrap/js/index.js.map HTTP/1.1" 404 - 27 0.022 0.060

And the way sourcemaps are fetched (might be headers, might be the
stampede as browsers will try to fetch a dozen sourcemaps as fast as
possible) seems to make this problem much, much worse: instead of 300+
the requests take 800+ queries each, multiple seconds, and requests
get worse as time goes on (didn't investigate the exact reason for
that) *and* they apparently don't ever get cached (at least they don't
after half a dozen reloads of the client).
2018-09-17 10:44:58 +02:00

379 lines
12 KiB
JavaScript

(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery'), require('./util.js')) :
typeof define === 'function' && define.amd ? define(['jquery', './util.js'], factory) :
(global.ScrollSpy = factory(global.jQuery,global.Util));
}(this, (function ($,Util) { 'use strict';
$ = $ && $.hasOwnProperty('default') ? $['default'] : $;
Util = Util && Util.hasOwnProperty('default') ? Util['default'] : Util;
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;
}
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;
}
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;
}
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.1.3): scrollspy.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
var ScrollSpy = function ($$$1) {
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
var NAME = 'scrollspy';
var VERSION = '4.1.3';
var DATA_KEY = 'bs.scrollspy';
var EVENT_KEY = "." + DATA_KEY;
var DATA_API_KEY = '.data-api';
var JQUERY_NO_CONFLICT = $$$1.fn[NAME];
var Default = {
offset: 10,
method: 'auto',
target: ''
};
var DefaultType = {
offset: 'number',
method: 'string',
target: '(string|element)'
};
var Event = {
ACTIVATE: "activate" + EVENT_KEY,
SCROLL: "scroll" + EVENT_KEY,
LOAD_DATA_API: "load" + EVENT_KEY + DATA_API_KEY
};
var ClassName = {
DROPDOWN_ITEM: 'dropdown-item',
DROPDOWN_MENU: 'dropdown-menu',
ACTIVE: 'active'
};
var 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'
};
var OffsetMethod = {
OFFSET: 'offset',
POSITION: 'position'
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
};
var ScrollSpy =
/*#__PURE__*/
function () {
function ScrollSpy(element, config) {
var _this = this;
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;
$$$1(this._scrollElement).on(Event.SCROLL, function (event) {
return _this._process(event);
});
this.refresh();
this._process();
} // Getters
var _proto = ScrollSpy.prototype;
// Public
_proto.refresh = function refresh() {
var _this2 = this;
var autoMethod = this._scrollElement === this._scrollElement.window ? OffsetMethod.OFFSET : OffsetMethod.POSITION;
var offsetMethod = this._config.method === 'auto' ? autoMethod : this._config.method;
var offsetBase = offsetMethod === OffsetMethod.POSITION ? this._getScrollTop() : 0;
this._offsets = [];
this._targets = [];
this._scrollHeight = this._getScrollHeight();
var targets = [].slice.call(document.querySelectorAll(this._selector));
targets.map(function (element) {
var target;
var targetSelector = Util.getSelectorFromElement(element);
if (targetSelector) {
target = document.querySelector(targetSelector);
}
if (target) {
var targetBCR = target.getBoundingClientRect();
if (targetBCR.width || targetBCR.height) {
// TODO (fat): remove sketch reliance on jQuery position/offset
return [$$$1(target)[offsetMethod]().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() {
$$$1.removeData(this._element, DATA_KEY);
$$$1(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
_proto._getConfig = function _getConfig(config) {
config = _objectSpread({}, Default, typeof config === 'object' && config ? config : {});
if (typeof config.target !== 'string') {
var id = $$$1(config.target).attr('id');
if (!id) {
id = Util.getUID(NAME);
$$$1(config.target).attr('id', id);
}
config.target = "#" + id;
}
Util.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;
}
var offsetLength = this._offsets.length;
for (var i = offsetLength; 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(','); // eslint-disable-next-line arrow-body-style
queries = queries.map(function (selector) {
return selector + "[data-target=\"" + target + "\"]," + (selector + "[href=\"" + target + "\"]");
});
var $link = $$$1([].slice.call(document.querySelectorAll(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 <ul> and <nav> markup a parent is the previous sibling of any nav ancestor
$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
$link.parents(Selector.NAV_LIST_GROUP).prev(Selector.NAV_ITEMS).children(Selector.NAV_LINKS).addClass(ClassName.ACTIVE);
}
$$$1(this._scrollElement).trigger(Event.ACTIVATE, {
relatedTarget: target
});
};
_proto._clear = function _clear() {
var nodes = [].slice.call(document.querySelectorAll(this._selector));
$$$1(nodes).filter(Selector.ACTIVE).removeClass(ClassName.ACTIVE);
}; // Static
ScrollSpy._jQueryInterface = function _jQueryInterface(config) {
return this.each(function () {
var data = $$$1(this).data(DATA_KEY);
var _config = typeof config === 'object' && config;
if (!data) {
data = new ScrollSpy(this, _config);
$$$1(this).data(DATA_KEY, data);
}
if (typeof config === 'string') {
if (typeof data[config] === 'undefined') {
throw new TypeError("No method named \"" + config + "\"");
}
data[config]();
}
});
};
_createClass(ScrollSpy, null, [{
key: "VERSION",
get: function get() {
return VERSION;
}
}, {
key: "Default",
get: function get() {
return Default;
}
}]);
return ScrollSpy;
}();
/**
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
*/
$$$1(window).on(Event.LOAD_DATA_API, function () {
var scrollSpys = [].slice.call(document.querySelectorAll(Selector.DATA_SPY));
var scrollSpysLength = scrollSpys.length;
for (var i = scrollSpysLength; i--;) {
var $spy = $$$1(scrollSpys[i]);
ScrollSpy._jQueryInterface.call($spy, $spy.data());
}
});
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
$$$1.fn[NAME] = ScrollSpy._jQueryInterface;
$$$1.fn[NAME].Constructor = ScrollSpy;
$$$1.fn[NAME].noConflict = function () {
$$$1.fn[NAME] = JQUERY_NO_CONFLICT;
return ScrollSpy._jQueryInterface;
};
return ScrollSpy;
}($);
return ScrollSpy;
})));