mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-26 23:49:57 +01:00
* Fix logos when rootPath is used * Fix close buttons used in JS Co-authored-by: Dennis Reimann <mail@dennisreimann.de>
16701 lines
496 KiB
JavaScript
16701 lines
496 KiB
JavaScript
(function (global, factory) {
|
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
typeof define === 'function' && define.amd ? define(factory) :
|
|
(global.bootstrapVue = factory());
|
|
}(this, (function () { 'use strict';
|
|
|
|
var __assign = Object.assign || function (e) {
|
|
for (var a, s = 1, t = arguments.length; s < t; s++) {
|
|
for (var r in a = arguments[s]) {
|
|
Object.prototype.hasOwnProperty.call(a, r) && (e[r] = a[r]);
|
|
}
|
|
}return e;
|
|
};function mergeData() {
|
|
for (var e, a, s = {}, t = arguments.length; t--;) {
|
|
for (var r = 0, c = Object.keys(arguments[t]); r < c.length; r++) {
|
|
switch (e = c[r]) {case "class":case "style":case "directives":
|
|
Array.isArray(s[e]) || (s[e] = []), s[e] = s[e].concat(arguments[t][e]);break;case "staticClass":
|
|
if (!arguments[t][e]) break;void 0 === s[e] && (s[e] = ""), s[e] && (s[e] += " "), s[e] += arguments[t][e].trim();break;case "on":case "nativeOn":
|
|
s[e] || (s[e] = {});for (var o = 0, n = Object.keys(arguments[t][e] || {}); o < n.length; o++) {
|
|
a = n[o], s[e][a] ? s[e][a] = [].concat(s[e][a], arguments[t][e][a]) : s[e][a] = arguments[t][e][a];
|
|
}break;case "attrs":case "props":case "domProps":case "scopedSlots":case "staticStyle":case "hook":case "transition":
|
|
s[e] || (s[e] = {}), s[e] = __assign({}, arguments[t][e], s[e]);break;case "slot":case "key":case "ref":case "tag":case "show":case "keepAlive":default:
|
|
s[e] || (s[e] = arguments[t][e]);}
|
|
}
|
|
}return s;
|
|
}
|
|
|
|
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
|
|
return typeof obj;
|
|
} : function (obj) {
|
|
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
|
|
};
|
|
|
|
var classCallCheck = function (instance, Constructor) {
|
|
if (!(instance instanceof Constructor)) {
|
|
throw new TypeError("Cannot call a class as a function");
|
|
}
|
|
};
|
|
|
|
var createClass = function () {
|
|
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);
|
|
}
|
|
}
|
|
|
|
return function (Constructor, protoProps, staticProps) {
|
|
if (protoProps) defineProperties(Constructor.prototype, protoProps);
|
|
if (staticProps) defineProperties(Constructor, staticProps);
|
|
return Constructor;
|
|
};
|
|
}();
|
|
|
|
var defineProperty = function (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;
|
|
};
|
|
|
|
var inherits = function (subClass, superClass) {
|
|
if (typeof superClass !== "function" && superClass !== null) {
|
|
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
|
|
}
|
|
|
|
subClass.prototype = Object.create(superClass && superClass.prototype, {
|
|
constructor: {
|
|
value: subClass,
|
|
enumerable: false,
|
|
writable: true,
|
|
configurable: true
|
|
}
|
|
});
|
|
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
|
|
};
|
|
|
|
var possibleConstructorReturn = function (self, call) {
|
|
if (!self) {
|
|
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
|
|
}
|
|
|
|
return call && (typeof call === "object" || typeof call === "function") ? call : self;
|
|
};
|
|
|
|
var toConsumableArray = function (arr) {
|
|
if (Array.isArray(arr)) {
|
|
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
|
|
|
|
return arr2;
|
|
} else {
|
|
return Array.from(arr);
|
|
}
|
|
};
|
|
|
|
var props = {
|
|
disabled: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
ariaLabel: {
|
|
type: String,
|
|
default: 'Close'
|
|
},
|
|
textVariant: {
|
|
type: String,
|
|
default: null
|
|
}
|
|
};
|
|
|
|
var bBtnClose = {
|
|
functional: true,
|
|
props: props,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
listeners = _ref.listeners,
|
|
slots = _ref.slots;
|
|
|
|
var componentData = {
|
|
staticClass: 'btn-close',
|
|
class: defineProperty({}, 'text-' + props.textVariant, props.textVariant),
|
|
attrs: {
|
|
type: 'button',
|
|
disabled: props.disabled,
|
|
'aria-label': props.ariaLabel ? String(props.ariaLabel) : null
|
|
},
|
|
on: {
|
|
click: function click(e) {
|
|
// Ensure click on button HTML content is also disabled
|
|
if (props.disabled && e instanceof Event) {
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
}
|
|
}
|
|
}
|
|
// Careful not to override the slot with innerHTML
|
|
};if (!slots().default) {
|
|
componentData.domProps = { innerHTML: '<svg role="img" class="icon icon-close" viewBox="0 0 16 16"><path d="M9.38526 8.08753L15.5498 1.85558C15.9653 1.43545 15.9653 0.805252 15.5498 0.385121C15.1342 -0.0350102 14.5108 -0.0350102 14.0952 0.385121L7.93072 6.61707L1.76623 0.315098C1.35065 -0.105033 0.727273 -0.105033 0.311688 0.315098C-0.103896 0.73523 -0.103896 1.36543 0.311688 1.78556L6.47618 8.0175L0.311688 14.2495C-0.103896 14.6696 -0.103896 15.2998 0.311688 15.7199C0.519481 15.93 0.796499 16 1.07355 16C1.35061 16 1.62769 15.93 1.83548 15.7199L7.99997 9.48797L14.1645 15.7199C14.3722 15.93 14.6493 16 14.9264 16C15.2034 16 15.4805 15.93 15.6883 15.7199C16.1039 15.2998 16.1039 14.6696 15.6883 14.2495L9.38526 8.08753Z" fill="currentColor"/></svg>' };
|
|
}
|
|
return h('button', mergeData(data, componentData), slots().default);
|
|
}
|
|
};
|
|
|
|
var bAlert = {
|
|
components: { bButtonClose: bBtnClose },
|
|
render: function render(h) {
|
|
if (!this.localShow) {
|
|
// If not showing, render placeholder
|
|
return h(false);
|
|
}
|
|
var dismissBtn = h(false);
|
|
if (this.dismissible) {
|
|
// Add dismiss button
|
|
dismissBtn = h('b-button-close', { attrs: { 'aria-label': this.dismissLabel }, on: { click: this.dismiss } }, [this.$slots.dismiss]);
|
|
}
|
|
var alert = h('div', { class: this.classObject, attrs: { role: 'alert', 'aria-live': 'polite', 'aria-atomic': true } }, [dismissBtn, this.$slots.default]);
|
|
return !this.fade ? alert : h('transition', { props: { name: 'fade', appear: true } }, [alert]);
|
|
},
|
|
|
|
model: {
|
|
prop: 'show',
|
|
event: 'input'
|
|
},
|
|
data: function data() {
|
|
return {
|
|
countDownTimerId: null,
|
|
dismissed: false
|
|
};
|
|
},
|
|
|
|
computed: {
|
|
classObject: function classObject() {
|
|
return ['alert', this.alertVariant, this.dismissible ? 'alert-dismissible' : ''];
|
|
},
|
|
alertVariant: function alertVariant() {
|
|
var variant = this.variant;
|
|
return 'alert-' + variant;
|
|
},
|
|
localShow: function localShow() {
|
|
return !this.dismissed && (this.countDownTimerId || this.show);
|
|
}
|
|
},
|
|
props: {
|
|
variant: {
|
|
type: String,
|
|
default: 'info'
|
|
},
|
|
dismissible: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
dismissLabel: {
|
|
type: String,
|
|
default: 'Close'
|
|
},
|
|
show: {
|
|
type: [Boolean, Number],
|
|
default: false
|
|
},
|
|
fade: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
},
|
|
watch: {
|
|
show: function show() {
|
|
this.showChanged();
|
|
}
|
|
},
|
|
mounted: function mounted() {
|
|
this.showChanged();
|
|
},
|
|
destroyed /* istanbul ignore next */: function destroyed() {
|
|
this.clearCounter();
|
|
},
|
|
|
|
methods: {
|
|
dismiss: function dismiss() {
|
|
this.clearCounter();
|
|
this.dismissed = true;
|
|
this.$emit('dismissed');
|
|
this.$emit('input', false);
|
|
if (typeof this.show === 'number') {
|
|
this.$emit('dismiss-count-down', 0);
|
|
this.$emit('input', 0);
|
|
} else {
|
|
this.$emit('input', false);
|
|
}
|
|
},
|
|
clearCounter: function clearCounter() {
|
|
if (this.countDownTimerId) {
|
|
clearInterval(this.countDownTimerId);
|
|
this.countDownTimerId = null;
|
|
}
|
|
},
|
|
showChanged: function showChanged() {
|
|
var _this = this;
|
|
|
|
// Reset counter status
|
|
this.clearCounter();
|
|
// Reset dismiss status
|
|
this.dismissed = false;
|
|
// No timer for boolean values
|
|
if (this.show === true || this.show === false || this.show === null || this.show === 0) {
|
|
return;
|
|
}
|
|
// Start counter
|
|
var dismissCountDown = this.show;
|
|
this.countDownTimerId = setInterval(function () {
|
|
if (dismissCountDown < 1) {
|
|
_this.dismiss();
|
|
return;
|
|
}
|
|
dismissCountDown--;
|
|
_this.$emit('dismiss-count-down', dismissCountDown);
|
|
_this.$emit('input', dismissCountDown);
|
|
}, 1000);
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Register a component plugin as being loaded. returns true if compoent plugin already registered
|
|
* @param {object} Vue
|
|
* @param {string} Component name
|
|
* @param {object} Component definition
|
|
*/
|
|
function registerComponent(Vue, name, def) {
|
|
Vue._bootstrap_vue_components_ = Vue._bootstrap_vue_components_ || {};
|
|
var loaded = Vue._bootstrap_vue_components_[name];
|
|
if (!loaded && def && name) {
|
|
Vue._bootstrap_vue_components_[name] = true;
|
|
Vue.component(name, def);
|
|
}
|
|
return loaded;
|
|
}
|
|
|
|
/**
|
|
* Register a group of components as being loaded.
|
|
* @param {object} Vue
|
|
* @param {object} Object of component definitions
|
|
*/
|
|
function registerComponents(Vue, components) {
|
|
for (var component in components) {
|
|
registerComponent(Vue, component, components[component]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Register a directive as being loaded. returns true if directive plugin already registered
|
|
* @param {object} Vue
|
|
* @param {string} Directive name
|
|
* @param {object} Directive definition
|
|
*/
|
|
function registerDirective(Vue, name, def) {
|
|
Vue._bootstrap_vue_directives_ = Vue._bootstrap_vue_directives_ || {};
|
|
var loaded = Vue._bootstrap_vue_directives_[name];
|
|
if (!loaded && def && name) {
|
|
Vue._bootstrap_vue_directives_[name] = true;
|
|
Vue.directive(name, def);
|
|
}
|
|
return loaded;
|
|
}
|
|
|
|
/**
|
|
* Register a group of directives as being loaded.
|
|
* @param {object} Vue
|
|
* @param {object} Object of directive definitions
|
|
*/
|
|
function registerDirectives(Vue, directives) {
|
|
for (var directive in directives) {
|
|
registerDirective(Vue, directive, directives[directive]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Install plugin if window.Vue available
|
|
* @param {object} Plugin definition
|
|
*/
|
|
function vueUse(VuePlugin) {
|
|
if (typeof window !== 'undefined' && window.Vue) {
|
|
window.Vue.use(VuePlugin);
|
|
}
|
|
}
|
|
|
|
var components = {
|
|
bAlert: bAlert
|
|
};
|
|
|
|
var VuePlugin = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin);
|
|
|
|
/**
|
|
* Aliasing Object[method] allows the minifier to shorten methods to a single character variable,
|
|
* as well as giving BV a chance to inject polyfills.
|
|
* As long as we avoid
|
|
* - import * as Object from "utils/object"
|
|
* all unused exports should be removed by tree-shaking.
|
|
*/
|
|
|
|
// @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
|
|
if (typeof Object.assign !== 'function') {
|
|
Object.assign = function (target, varArgs) {
|
|
// .length of function is 2
|
|
|
|
if (target == null) {
|
|
// TypeError if undefined or null
|
|
throw new TypeError('Cannot convert undefined or null to object');
|
|
}
|
|
|
|
var to = Object(target);
|
|
|
|
for (var index = 1; index < arguments.length; index++) {
|
|
var nextSource = arguments[index];
|
|
|
|
if (nextSource != null) {
|
|
// Skip over if undefined or null
|
|
for (var nextKey in nextSource) {
|
|
// Avoid bugs when hasOwnProperty is shadowed
|
|
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
|
|
to[nextKey] = nextSource[nextKey];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return to;
|
|
};
|
|
}
|
|
|
|
// @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is#Polyfill
|
|
if (!Object.is) {
|
|
Object.is = function (x, y) {
|
|
// SameValue algorithm
|
|
if (x === y) {
|
|
// Steps 1-5, 7-10
|
|
// Steps 6.b-6.e: +0 != -0
|
|
return x !== 0 || 1 / x === 1 / y;
|
|
} else {
|
|
// Step 6.a: NaN == NaN
|
|
// eslint-disable-next-line no-self-compare
|
|
return x !== x && y !== y;
|
|
}
|
|
};
|
|
}
|
|
|
|
var assign = Object.assign;
|
|
var keys = Object.keys;
|
|
var defineProperties = Object.defineProperties;
|
|
var defineProperty$1 = Object.defineProperty;
|
|
var create = Object.create;
|
|
|
|
function readonlyDescriptor() {
|
|
return { enumerable: true, configurable: false, writable: false };
|
|
}
|
|
|
|
// Production steps of ECMA-262, Edition 6, 22.1.2.1
|
|
// es6-ified by @alexsasharegan
|
|
if (!Array.from) {
|
|
Array.from = function () {
|
|
var toStr = Object.prototype.toString;
|
|
var isCallable = function isCallable(fn) {
|
|
return typeof fn === 'function' || toStr.call(fn) === '[object Function]';
|
|
};
|
|
var toInteger = function toInteger(value) {
|
|
var number = Number(value);
|
|
if (isNaN(number)) {
|
|
return 0;
|
|
}
|
|
if (number === 0 || !isFinite(number)) {
|
|
return number;
|
|
}
|
|
return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
|
|
};
|
|
var maxSafeInteger = Math.pow(2, 53) - 1;
|
|
var toLength = function toLength(value) {
|
|
return Math.min(Math.max(toInteger(value), 0), maxSafeInteger);
|
|
};
|
|
|
|
// The length property of the from method is 1.
|
|
return function from(arrayLike /*, mapFn, thisArg */) {
|
|
// 1. Let C be the this value.
|
|
var C = this;
|
|
|
|
// 2. Let items be ToObject(arrayLike).
|
|
var items = Object(arrayLike);
|
|
|
|
// 3. ReturnIfAbrupt(items).
|
|
if (arrayLike == null) {
|
|
throw new TypeError('Array.from requires an array-like object - not null or undefined');
|
|
}
|
|
|
|
// 4. If mapfn is undefined, then let mapping be false.
|
|
var mapFn = arguments.length > 1 ? arguments[1] : void undefined;
|
|
var T = void 0;
|
|
|
|
if (typeof mapFn !== 'undefined') {
|
|
// 5. else
|
|
// 5. a If IsCallable(mapfn) is false, throw a TypeError exception.
|
|
if (!isCallable(mapFn)) {
|
|
throw new TypeError('Array.from: when provided, the second argument must be a function');
|
|
}
|
|
|
|
// 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined.
|
|
if (arguments.length > 2) {
|
|
T = arguments[2];
|
|
}
|
|
}
|
|
|
|
// 10. Let lenValue be Get(items, "length").
|
|
// 11. Let len be ToLength(lenValue).
|
|
var len = toLength(items.length);
|
|
|
|
// 13. If IsConstructor(C) is true, then
|
|
// 13. a. Let A be the result of calling the [[Construct]] internal method
|
|
// of C with an argument list containing the single item len.
|
|
// 14. a. Else, Let A be ArrayCreate(len).
|
|
var A = isCallable(C) ? Object(new C(len)) : new Array(len);
|
|
|
|
// 16. Let k be 0.
|
|
var k = 0;
|
|
// 17. Repeat, while k < len… (also steps a - h)
|
|
var kValue = void 0;
|
|
while (k < len) {
|
|
kValue = items[k];
|
|
if (mapFn) {
|
|
A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k);
|
|
} else {
|
|
A[k] = kValue;
|
|
}
|
|
k += 1;
|
|
}
|
|
// 18. Let putStatus be Put(A, "length", len, true).
|
|
A.length = len;
|
|
// 20. Return A.
|
|
return A;
|
|
};
|
|
}();
|
|
}
|
|
|
|
// https://tc39.github.io/ecma262/#sec-array.prototype.find
|
|
// Needed for IE support
|
|
if (!Array.prototype.find) {
|
|
// eslint-disable-next-line no-extend-native
|
|
Object.defineProperty(Array.prototype, 'find', {
|
|
value: function value(predicate) {
|
|
// 1. Let O be ? ToObject(this value).
|
|
if (this == null) {
|
|
throw new TypeError('"this" is null or not defined');
|
|
}
|
|
|
|
var o = Object(this);
|
|
|
|
// 2. Let len be ? ToLength(? Get(O, "length")).
|
|
var len = o.length >>> 0;
|
|
|
|
// 3. If IsCallable(predicate) is false, throw a TypeError exception.
|
|
if (typeof predicate !== 'function') {
|
|
throw new TypeError('predicate must be a function');
|
|
}
|
|
|
|
// 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
|
|
var thisArg = arguments[1];
|
|
|
|
// 5. Let k be 0.
|
|
var k = 0;
|
|
|
|
// 6. Repeat, while k < len
|
|
while (k < len) {
|
|
// a. Let Pk be ! ToString(k).
|
|
// b. Let kValue be ? Get(O, Pk).
|
|
// c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
|
|
// d. If testResult is true, return kValue.
|
|
var kValue = o[k];
|
|
if (predicate.call(thisArg, kValue, k, o)) {
|
|
return kValue;
|
|
}
|
|
// e. Increase k by 1.
|
|
k++;
|
|
}
|
|
|
|
// 7. Return undefined.
|
|
return undefined;
|
|
}
|
|
});
|
|
}
|
|
|
|
if (!Array.isArray) {
|
|
Array.isArray = function (arg) {
|
|
return Object.prototype.toString.call(arg) === '[object Array]';
|
|
};
|
|
}
|
|
|
|
// Static
|
|
var from = Array.from;
|
|
var isArray = Array.isArray;
|
|
|
|
// Instance
|
|
var arrayIncludes = function arrayIncludes(array, value) {
|
|
return array.indexOf(value) !== -1;
|
|
};
|
|
function concat() {
|
|
return Array.prototype.concat.apply([], arguments);
|
|
}
|
|
|
|
function identity(x) {
|
|
return x;
|
|
}
|
|
|
|
/**
|
|
* Given an array of properties or an object of property keys,
|
|
* plucks all the values off the target object.
|
|
* @param {{}|string[]} keysToPluck
|
|
* @param {{}} objToPluck
|
|
* @param {Function} transformFn
|
|
* @return {{}}
|
|
*/
|
|
function pluckProps(keysToPluck, objToPluck) {
|
|
var transformFn = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : identity;
|
|
|
|
return (isArray(keysToPluck) ? keysToPluck.slice() : keys(keysToPluck)).reduce(function (memo, prop) {
|
|
// eslint-disable-next-line no-sequences
|
|
return memo[transformFn(prop)] = objToPluck[prop], memo;
|
|
}, {});
|
|
}
|
|
|
|
/**
|
|
* The Link component is used in many other BV components.
|
|
* As such, sharing its props makes supporting all its features easier.
|
|
* However, some components need to modify the defaults for their own purpose.
|
|
* Prefer sharing a fresh copy of the props to ensure mutations
|
|
* do not affect other component references to the props.
|
|
*
|
|
* https://github.com/vuejs/vue-router/blob/dev/src/components/link.js
|
|
* @return {{}}
|
|
*/
|
|
function propsFactory() {
|
|
return {
|
|
href: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
rel: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
target: {
|
|
type: String,
|
|
default: '_self'
|
|
},
|
|
active: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
activeClass: {
|
|
type: String,
|
|
default: 'active'
|
|
},
|
|
append: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
disabled: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
event: {
|
|
type: [String, Array],
|
|
default: 'click'
|
|
},
|
|
exact: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
exactActiveClass: {
|
|
type: String,
|
|
default: 'active'
|
|
},
|
|
replace: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
routerTag: {
|
|
type: String,
|
|
default: 'a'
|
|
},
|
|
to: {
|
|
type: [String, Object],
|
|
default: null
|
|
}
|
|
};
|
|
}
|
|
|
|
function pickLinkProps(propsToPick) {
|
|
var freshLinkProps = propsFactory();
|
|
// Normalize everything to array.
|
|
propsToPick = concat(propsToPick);
|
|
|
|
return keys(freshLinkProps).reduce(function (memo, prop) {
|
|
if (arrayIncludes(propsToPick, prop)) {
|
|
memo[prop] = freshLinkProps[prop];
|
|
}
|
|
|
|
return memo;
|
|
}, {});
|
|
}
|
|
|
|
function computeTag(props, parent) {
|
|
return Boolean(parent.$router) && props.to && !props.disabled ? 'router-link' : 'a';
|
|
}
|
|
|
|
function computeHref(_ref, tag) {
|
|
var disabled = _ref.disabled,
|
|
href = _ref.href,
|
|
to = _ref.to;
|
|
|
|
// We've already checked the parent.$router in computeTag,
|
|
// so router-link means live router.
|
|
// When deferring to Vue Router's router-link,
|
|
// don't use the href attr at all.
|
|
// Must return undefined for router-link to populate href.
|
|
if (tag === 'router-link') return void 0;
|
|
// If href explicitly provided
|
|
if (href) return href;
|
|
// Reconstruct href when `to` used, but no router
|
|
if (to) {
|
|
// Fallback to `to` prop (if `to` is a string)
|
|
if (typeof to === 'string') return to;
|
|
// Fallback to `to.path` prop (if `to` is an object)
|
|
if ((typeof to === 'undefined' ? 'undefined' : _typeof(to)) === 'object' && typeof to.path === 'string') return to.path;
|
|
}
|
|
// If nothing is provided use '#'
|
|
return '#';
|
|
}
|
|
|
|
function computeRel(_ref2) {
|
|
var target = _ref2.target,
|
|
rel = _ref2.rel;
|
|
|
|
if (target === '_blank' && rel === null) {
|
|
return 'noopener';
|
|
}
|
|
return rel || null;
|
|
}
|
|
|
|
function clickHandlerFactory(_ref3) {
|
|
var disabled = _ref3.disabled,
|
|
tag = _ref3.tag,
|
|
href = _ref3.href,
|
|
suppliedHandler = _ref3.suppliedHandler,
|
|
parent = _ref3.parent;
|
|
|
|
var isRouterLink = tag === 'router-link';
|
|
|
|
return function onClick(e) {
|
|
if (disabled && e instanceof Event) {
|
|
// Stop event from bubbling up.
|
|
e.stopPropagation();
|
|
// Kill the event loop attached to this specific EventTarget.
|
|
e.stopImmediatePropagation();
|
|
} else {
|
|
parent.$root.$emit('clicked::link', e);
|
|
|
|
if (isRouterLink && e.target.__vue__) {
|
|
e.target.__vue__.$emit('click', e);
|
|
}
|
|
if (typeof suppliedHandler === 'function') {
|
|
suppliedHandler.apply(undefined, arguments);
|
|
}
|
|
}
|
|
|
|
if (!isRouterLink && href === '#' || disabled) {
|
|
// Stop scroll-to-top behavior or navigation.
|
|
e.preventDefault();
|
|
}
|
|
};
|
|
}
|
|
|
|
var bLink = {
|
|
functional: true,
|
|
props: propsFactory(),
|
|
render: function render(h, _ref4) {
|
|
var props = _ref4.props,
|
|
data = _ref4.data,
|
|
parent = _ref4.parent,
|
|
children = _ref4.children;
|
|
|
|
var tag = computeTag(props, parent);
|
|
var rel = computeRel(props);
|
|
var href = computeHref(props, tag);
|
|
var eventType = tag === 'router-link' ? 'nativeOn' : 'on';
|
|
var suppliedHandler = (data[eventType] || {}).click;
|
|
var handlers = { click: clickHandlerFactory({ tag: tag, href: href, disabled: props.disabled, suppliedHandler: suppliedHandler, parent: parent }) };
|
|
|
|
var componentData = mergeData(data, {
|
|
class: [props.active ? props.exact ? props.exactActiveClass : props.activeClass : null, { disabled: props.disabled }],
|
|
attrs: {
|
|
rel: rel,
|
|
href: href,
|
|
target: props.target,
|
|
tabindex: props.disabled ? '-1' : data.attrs ? data.attrs.tabindex : null,
|
|
'aria-disabled': tag === 'a' && props.disabled ? 'true' : null
|
|
},
|
|
props: assign(props, { tag: props.routerTag })
|
|
});
|
|
|
|
// If href prop exists on router-link (even undefined or null) it fails working on SSR
|
|
if (!componentData.attrs.href) {
|
|
delete componentData.attrs.href;
|
|
}
|
|
|
|
// We want to overwrite any click handler since our callback
|
|
// will invoke the supplied handler if !props.disabled
|
|
componentData[eventType] = assign(componentData[eventType] || {}, handlers);
|
|
|
|
return h(tag, componentData, children);
|
|
}
|
|
};
|
|
|
|
var linkProps = propsFactory();
|
|
delete linkProps.href.default;
|
|
delete linkProps.to.default;
|
|
|
|
var props$2 = assign(linkProps, {
|
|
tag: {
|
|
type: String,
|
|
default: 'span'
|
|
},
|
|
variant: {
|
|
type: String,
|
|
default: 'secondary'
|
|
},
|
|
pill: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
});
|
|
|
|
var bBadge = {
|
|
functional: true,
|
|
props: props$2,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
var tag = !props.href && !props.to ? props.tag : bLink;
|
|
|
|
var componentData = {
|
|
staticClass: 'badge',
|
|
class: [!props.variant ? 'bg-secondary' : 'bg-' + props.variant, {
|
|
'rounded-pill': Boolean(props.pill),
|
|
active: props.active,
|
|
disabled: props.disabled
|
|
}],
|
|
props: pluckProps(linkProps, props)
|
|
};
|
|
|
|
return h(tag, mergeData(data, componentData), children);
|
|
}
|
|
};
|
|
|
|
var components$1 = {
|
|
bBadge: bBadge
|
|
};
|
|
|
|
var VuePlugin$1 = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$1);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$1);
|
|
|
|
var props$3 = assign(propsFactory(), {
|
|
text: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
active: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
href: {
|
|
type: String,
|
|
default: '#'
|
|
},
|
|
ariaCurrent: {
|
|
type: String,
|
|
default: 'location'
|
|
}
|
|
});
|
|
|
|
var BreadcrumbLink = {
|
|
functional: true,
|
|
props: props$3,
|
|
render: function render(h, _ref) {
|
|
var suppliedProps = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
var tag = suppliedProps.active ? 'span' : bLink;
|
|
|
|
var componentData = { props: pluckProps(props$3, suppliedProps) };
|
|
if (suppliedProps.active) {
|
|
componentData.attrs = { 'aria-current': suppliedProps.ariaCurrent };
|
|
} else {
|
|
componentData.attrs = { href: suppliedProps.href };
|
|
}
|
|
|
|
return h(tag, mergeData(data, componentData), children || suppliedProps.text);
|
|
}
|
|
};
|
|
|
|
var props$4 = assign({}, props$3, {
|
|
text: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
href: {
|
|
type: String,
|
|
default: null
|
|
}
|
|
});
|
|
|
|
var BreadcrumbItem = {
|
|
functional: true,
|
|
props: props$4,
|
|
render: function render(h, _ref) {
|
|
var props$$1 = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
return h('li', mergeData(data, {
|
|
staticClass: 'breadcrumb-item',
|
|
class: { active: props$$1.active },
|
|
attrs: { role: 'presentation' }
|
|
}), [h(BreadcrumbLink, { props: props$$1 }, children)]);
|
|
}
|
|
};
|
|
|
|
var props$5 = {
|
|
items: {
|
|
type: Array,
|
|
default: null
|
|
}
|
|
};
|
|
|
|
var bBreadcrumb = {
|
|
functional: true,
|
|
props: props$5,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
var childNodes = children;
|
|
// Build child nodes from items if given.
|
|
if (isArray(props.items)) {
|
|
var activeDefined = false;
|
|
childNodes = props.items.map(function (item, idx) {
|
|
if ((typeof item === 'undefined' ? 'undefined' : _typeof(item)) !== 'object') {
|
|
item = { text: item };
|
|
}
|
|
// Copy the value here so we can normalize it.
|
|
var active = item.active;
|
|
if (active) {
|
|
activeDefined = true;
|
|
}
|
|
if (!active && !activeDefined) {
|
|
// Auto-detect active by position in list.
|
|
active = idx + 1 === props.items.length;
|
|
}
|
|
|
|
return h(BreadcrumbItem, { props: assign({}, item, { active: active }) });
|
|
});
|
|
}
|
|
|
|
return h('ol', mergeData(data, { staticClass: 'breadcrumb' }), childNodes);
|
|
}
|
|
};
|
|
|
|
var components$2 = {
|
|
bBreadcrumb: bBreadcrumb,
|
|
bBreadcrumbItem: BreadcrumbItem,
|
|
bBreadcrumbLink: BreadcrumbLink
|
|
};
|
|
|
|
var VuePlugin$2 = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$2);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$2);
|
|
|
|
// Determine if an element is an HTML Element
|
|
var isElement = function isElement(el) {
|
|
return el && el.nodeType === Node.ELEMENT_NODE;
|
|
};
|
|
|
|
// Determine if an HTML element is visible - Faster than CSS check
|
|
var isVisible = function isVisible(el) {
|
|
return isElement(el) && document.body.contains(el) && el.getBoundingClientRect().height > 0 && el.getBoundingClientRect().width > 0;
|
|
};
|
|
|
|
// Determine if an element is disabled
|
|
var isDisabled = function isDisabled(el) {
|
|
return !isElement(el) || el.disabled || el.classList.contains('disabled') || Boolean(el.getAttribute('disabled'));
|
|
};
|
|
|
|
// Cause/wait-for an element to reflow it's content (adjusting it's height/width)
|
|
var reflow = function reflow(el) {
|
|
// requsting an elements offsetHight will trigger a reflow of the element content
|
|
return isElement(el) && el.offsetHeight;
|
|
};
|
|
|
|
// Select all elements matching selector. Returns [] if none found
|
|
var selectAll = function selectAll(selector, root) {
|
|
if (!isElement(root)) {
|
|
root = document;
|
|
}
|
|
return from(root.querySelectorAll(selector));
|
|
};
|
|
|
|
// Select a single element, returns null if not found
|
|
var select = function select(selector, root) {
|
|
if (!isElement(root)) {
|
|
root = document;
|
|
}
|
|
return root.querySelector(selector) || null;
|
|
};
|
|
|
|
// Determine if an element matches a selector
|
|
var matches = function matches(el, selector) {
|
|
if (!isElement(el)) {
|
|
return false;
|
|
}
|
|
|
|
// https://developer.mozilla.org/en-US/docs/Web/API/Element/matches#Polyfill
|
|
// Prefer native implementations over polyfill function
|
|
var proto = Element.prototype;
|
|
var Matches = proto.matches || proto.matchesSelector || proto.mozMatchesSelector || proto.msMatchesSelector || proto.oMatchesSelector || proto.webkitMatchesSelector ||
|
|
/* istanbul ignore next */
|
|
function (sel) {
|
|
var element = this;
|
|
var m = selectAll(sel, element.document || element.ownerDocument);
|
|
var i = m.length;
|
|
// eslint-disable-next-line no-empty
|
|
while (--i >= 0 && m.item(i) !== element) {}
|
|
return i > -1;
|
|
};
|
|
|
|
return Matches.call(el, selector);
|
|
};
|
|
|
|
// Finds closest element matching selector. Returns null if not found
|
|
var closest = function closest(selector, root) {
|
|
if (!isElement(root)) {
|
|
return null;
|
|
}
|
|
|
|
// https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
|
|
// Since we dont support IE < 10, we can use the "Matches" version of the polyfill for speed
|
|
// Prefer native implementation over polyfill function
|
|
var Closest = Element.prototype.closest ||
|
|
/* istanbul ignore next */
|
|
function (sel) {
|
|
var element = this;
|
|
if (!document.documentElement.contains(element)) {
|
|
return null;
|
|
}
|
|
do {
|
|
// Use our "patched" matches function
|
|
if (matches(element, sel)) {
|
|
return element;
|
|
}
|
|
element = element.parentElement;
|
|
} while (element !== null);
|
|
return null;
|
|
};
|
|
|
|
var el = Closest.call(root, selector);
|
|
// Emulate jQuery closest and return null if match is the passed in element (root)
|
|
return el === root ? null : el;
|
|
};
|
|
|
|
// Get an element given an ID
|
|
var getById = function getById(id) {
|
|
return document.getElementById(/^#/.test(id) ? id.slice(1) : id) || null;
|
|
};
|
|
|
|
// Add a class to an element
|
|
var addClass = function addClass(el, className) {
|
|
if (className && isElement(el)) {
|
|
el.classList.add(className);
|
|
}
|
|
};
|
|
|
|
// Remove a class from an element
|
|
var removeClass = function removeClass(el, className) {
|
|
if (className && isElement(el)) {
|
|
el.classList.remove(className);
|
|
}
|
|
};
|
|
|
|
// Test if an element has a class
|
|
var hasClass = function hasClass(el, className) {
|
|
if (className && isElement(el)) {
|
|
return el.classList.contains(className);
|
|
}
|
|
return false;
|
|
};
|
|
|
|
// Set an attribute on an element
|
|
var setAttr = function setAttr(el, attr, value) {
|
|
if (attr && isElement(el)) {
|
|
el.setAttribute(attr, value);
|
|
}
|
|
};
|
|
|
|
// Remove an attribute from an element
|
|
var removeAttr = function removeAttr(el, attr) {
|
|
if (attr && isElement(el)) {
|
|
el.removeAttribute(attr);
|
|
}
|
|
};
|
|
|
|
// Get an attribute value from an element (returns null if not found)
|
|
var getAttr = function getAttr(el, attr) {
|
|
if (attr && isElement(el)) {
|
|
return el.getAttribute(attr);
|
|
}
|
|
return null;
|
|
};
|
|
|
|
// Determine if an attribute exists on an element (returns true or false, or null if element not found)
|
|
var hasAttr = function hasAttr(el, attr) {
|
|
if (attr && isElement(el)) {
|
|
return el.hasAttribute(attr);
|
|
}
|
|
return null;
|
|
};
|
|
|
|
// Return the Bounding Client Rec of an element. Retruns null if not an element
|
|
var getBCR = function getBCR(el) {
|
|
return isElement(el) ? el.getBoundingClientRect() : null;
|
|
};
|
|
|
|
// Get computed style object for an element
|
|
var getCS = function getCS(el) {
|
|
return isElement(el) ? window.getComputedStyle(el) : {};
|
|
};
|
|
|
|
// Return an element's offset wrt document element
|
|
// https://j11y.io/jquery/#v=git&fn=jQuery.fn.offset
|
|
var offset = function offset(el) {
|
|
if (isElement(el)) {
|
|
if (!el.getClientRects().length) {
|
|
return { top: 0, left: 0 };
|
|
}
|
|
var bcr = getBCR(el);
|
|
var win = el.ownerDocument.defaultView;
|
|
return {
|
|
top: bcr.top + win.pageYOffset,
|
|
left: bcr.left + win.pageXOffset
|
|
};
|
|
}
|
|
};
|
|
|
|
// Return an element's offset wrt to it's offsetParent
|
|
// https://j11y.io/jquery/#v=git&fn=jQuery.fn.position
|
|
var position = function position(el) {
|
|
if (!isElement(el)) {
|
|
return;
|
|
}
|
|
var parentOffset = { top: 0, left: 0 };
|
|
var offsetSelf = void 0;
|
|
var offsetParent = void 0;
|
|
if (getCS(el).position === 'fixed') {
|
|
offsetSelf = getBCR(el);
|
|
} else {
|
|
offsetSelf = offset(el);
|
|
var doc = el.ownerDocument;
|
|
offsetParent = el.offsetParent || doc.documentElement;
|
|
while (offsetParent && (offsetParent === doc.body || offsetParent === doc.documentElement) && getCS(offsetParent).position === 'static') {
|
|
offsetParent = offsetParent.parentNode;
|
|
}
|
|
if (offsetParent && offsetParent !== el && offsetParent.nodeType === Node.ELEMENT_NODE) {
|
|
parentOffset = offset(offsetParent);
|
|
parentOffset.top += parseFloat(getCS(offsetParent).borderTopWidth);
|
|
parentOffset.left += parseFloat(getCS(offsetParent).borderLeftWidth);
|
|
}
|
|
}
|
|
return {
|
|
top: offsetSelf.top - parentOffset.top - parseFloat(getCS(el).marginTop),
|
|
left: offsetSelf.left - parentOffset.left - parseFloat(getCS(el).marginLeft)
|
|
};
|
|
};
|
|
|
|
// Attach an event listener to an element
|
|
var eventOn = function eventOn(el, evtName, handler) {
|
|
if (el && el.addEventListener) {
|
|
el.addEventListener(evtName, handler);
|
|
}
|
|
};
|
|
|
|
// Remove an event listener from an element
|
|
var eventOff = function eventOff(el, evtName, handler) {
|
|
if (el && el.removeEventListener) {
|
|
el.removeEventListener(evtName, handler);
|
|
}
|
|
};
|
|
|
|
var btnProps = {
|
|
block: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
disabled: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
size: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
variant: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
type: {
|
|
type: String,
|
|
default: 'button'
|
|
},
|
|
pressed: {
|
|
// tri-state prop: true, false or null
|
|
// => on, off, not a toggle
|
|
type: Boolean,
|
|
default: null
|
|
}
|
|
};
|
|
|
|
var linkProps$1 = propsFactory();
|
|
delete linkProps$1.href.default;
|
|
delete linkProps$1.to.default;
|
|
var linkPropKeys = keys(linkProps$1);
|
|
|
|
var props$6 = assign(linkProps$1, btnProps);
|
|
|
|
function handleFocus(evt) {
|
|
if (evt.type === 'focusin') {
|
|
addClass(evt.target, 'focus');
|
|
} else if (evt.type === 'focusout') {
|
|
removeClass(evt.target, 'focus');
|
|
}
|
|
}
|
|
|
|
var bBtn = {
|
|
functional: true,
|
|
props: props$6,
|
|
render: function render(h, _ref) {
|
|
var _ref2;
|
|
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
listeners = _ref.listeners,
|
|
children = _ref.children;
|
|
|
|
var isLink = Boolean(props.href || props.to);
|
|
var isToggle = typeof props.pressed === 'boolean';
|
|
var on = {
|
|
click: function click(e) {
|
|
if (props.disabled && e instanceof Event) {
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
} else if (isToggle) {
|
|
// Concat will normalize the value to an array
|
|
// without double wrapping an array value in an array.
|
|
concat(listeners['update:pressed']).forEach(function (fn) {
|
|
if (typeof fn === 'function') {
|
|
fn(!props.pressed);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
if (isToggle) {
|
|
on.focusin = handleFocus;
|
|
on.focusout = handleFocus;
|
|
}
|
|
|
|
var componentData = {
|
|
staticClass: 'btn',
|
|
class: [props.variant ? 'btn-' + props.variant : 'btn-secondary', (_ref2 = {}, defineProperty(_ref2, 'btn-' + props.size, Boolean(props.size)), defineProperty(_ref2, 'btn-block', props.block), defineProperty(_ref2, 'disabled', props.disabled), defineProperty(_ref2, 'active', props.pressed), _ref2)],
|
|
props: isLink ? pluckProps(linkPropKeys, props) : null,
|
|
attrs: {
|
|
type: isLink ? null : props.type,
|
|
disabled: isLink ? null : props.disabled,
|
|
// Data attribute not used for js logic,
|
|
// but only for BS4 style selectors.
|
|
'data-toggle': isToggle ? 'button' : null,
|
|
'aria-pressed': isToggle ? String(props.pressed) : null,
|
|
// Tab index is used when the component becomes a link.
|
|
// Links are tabable, but don't allow disabled,
|
|
// so we mimic that functionality by disabling tabbing.
|
|
tabindex: props.disabled && isLink ? '-1' : data.attrs ? data.attrs['tabindex'] : null
|
|
},
|
|
on: on
|
|
};
|
|
|
|
return h(isLink ? bLink : 'button', mergeData(data, componentData), children);
|
|
}
|
|
};
|
|
|
|
var components$3 = {
|
|
bButton: bBtn,
|
|
bBtn: bBtn,
|
|
bButtonClose: bBtnClose,
|
|
bBtnClose: bBtnClose
|
|
};
|
|
|
|
var VuePlugin$3 = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$3);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$3);
|
|
|
|
var props$7 = {
|
|
vertical: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
size: {
|
|
type: String,
|
|
default: null,
|
|
validator: function validator(size) {
|
|
return arrayIncludes(['sm', '', 'lg'], size);
|
|
}
|
|
},
|
|
tag: {
|
|
type: String,
|
|
default: 'div'
|
|
},
|
|
ariaRole: {
|
|
type: String,
|
|
default: 'group'
|
|
}
|
|
};
|
|
|
|
var bButtonGroup = {
|
|
functional: true,
|
|
props: props$7,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
return h(props.tag, mergeData(data, {
|
|
class: defineProperty({
|
|
'btn-group': !props.vertical,
|
|
'btn-group-vertical': props.vertical
|
|
}, 'btn-group-' + props.size, Boolean(props.size)),
|
|
attrs: { 'role': props.ariaRole }
|
|
}), children);
|
|
}
|
|
};
|
|
|
|
var components$4 = {
|
|
bButtonGroup: bButtonGroup,
|
|
bBtnGroup: bButtonGroup
|
|
};
|
|
|
|
var VuePlugin$4 = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$4);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$4);
|
|
|
|
/*
|
|
* Key Codes (events)
|
|
*/
|
|
|
|
var KeyCodes = {
|
|
SPACE: 32,
|
|
ENTER: 13,
|
|
ESC: 27,
|
|
LEFT: 37,
|
|
UP: 38,
|
|
RIGHT: 39,
|
|
DOWN: 40,
|
|
PAGEUP: 33,
|
|
PAGEDOWN: 34,
|
|
HOME: 36,
|
|
END: 35
|
|
};
|
|
|
|
var ITEM_SELECTOR = ['.btn:not(.disabled):not([disabled]):not(.dropdown-item)', '.form-control:not(.disabled):not([disabled])', 'select:not(.disabled):not([disabled])', 'input[type="checkbox"]:not(.disabled)', 'input[type="radio"]:not(.disabled)'].join(',');
|
|
|
|
var bButtonToolbar = {
|
|
render: function render(h) {
|
|
return h('div', {
|
|
class: this.classObject,
|
|
attrs: {
|
|
role: 'toolbar',
|
|
tabindex: this.keyNav ? '0' : null
|
|
},
|
|
on: {
|
|
focusin: this.onFocusin,
|
|
keydown: this.onKeydown
|
|
}
|
|
}, [this.$slots.default]);
|
|
},
|
|
|
|
computed: {
|
|
classObject: function classObject() {
|
|
return ['btn-toolbar', this.justify && !this.vertical ? 'justify-content-between' : ''];
|
|
}
|
|
},
|
|
props: {
|
|
justify: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
keyNav: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
},
|
|
methods: {
|
|
onFocusin: function onFocusin(evt) {
|
|
if (evt.target === this.$el) {
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
this.focusFirst(evt);
|
|
}
|
|
},
|
|
onKeydown: function onKeydown(evt) {
|
|
if (!this.keyNav) {
|
|
return;
|
|
}
|
|
var key = evt.keyCode;
|
|
var shift = evt.shiftKey;
|
|
if (key === KeyCodes.UP || key === KeyCodes.LEFT) {
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
if (shift) {
|
|
this.focusFirst(evt);
|
|
} else {
|
|
this.focusNext(evt, true);
|
|
}
|
|
} else if (key === KeyCodes.DOWN || key === KeyCodes.RIGHT) {
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
if (shift) {
|
|
this.focusLast(evt);
|
|
} else {
|
|
this.focusNext(evt, false);
|
|
}
|
|
}
|
|
},
|
|
setItemFocus: function setItemFocus(item) {
|
|
this.$nextTick(function () {
|
|
item.focus();
|
|
});
|
|
},
|
|
focusNext: function focusNext(evt, prev) {
|
|
var items = this.getItems();
|
|
if (items.length < 1) {
|
|
return;
|
|
}
|
|
var index = items.indexOf(evt.target);
|
|
if (prev && index > 0) {
|
|
index--;
|
|
} else if (!prev && index < items.length - 1) {
|
|
index++;
|
|
}
|
|
if (index < 0) {
|
|
index = 0;
|
|
}
|
|
this.setItemFocus(items[index]);
|
|
},
|
|
focusFirst: function focusFirst(evt) {
|
|
var items = this.getItems();
|
|
if (items.length > 0) {
|
|
this.setItemFocus(items[0]);
|
|
}
|
|
},
|
|
focusLast: function focusLast(evt) {
|
|
var items = this.getItems();
|
|
if (items.length > 0) {
|
|
this.setItemFocus([items.length - 1]);
|
|
}
|
|
},
|
|
getItems: function getItems() {
|
|
var items = selectAll(ITEM_SELECTOR, this.$el);
|
|
items.forEach(function (item) {
|
|
// Ensure tabfocus is -1 on any new elements
|
|
item.tabIndex = -1;
|
|
});
|
|
return items.filter(function (el) {
|
|
return isVisible(el);
|
|
});
|
|
}
|
|
},
|
|
mounted: function mounted() {
|
|
if (this.keyNav) {
|
|
// Pre-set the tabindexes if the markup does not include tabindex="-1" on the toolbar items
|
|
this.getItems();
|
|
}
|
|
}
|
|
};
|
|
|
|
var components$5 = {
|
|
bButtonToolbar: bButtonToolbar,
|
|
bBtnToolbar: bButtonToolbar
|
|
};
|
|
|
|
var VuePlugin$5 = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$5);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$5);
|
|
|
|
var props$8 = {
|
|
tag: {
|
|
type: String,
|
|
default: 'div'
|
|
}
|
|
};
|
|
|
|
var InputGroupText = {
|
|
props: props$8,
|
|
functional: true,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
return h(props.tag, mergeData(data, {
|
|
staticClass: 'input-group-text'
|
|
}), children);
|
|
}
|
|
};
|
|
|
|
var propsFactory$1 = function propsFactory(append) {
|
|
return {
|
|
id: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
tag: {
|
|
type: String,
|
|
default: 'div'
|
|
},
|
|
append: {
|
|
type: Boolean,
|
|
default: append
|
|
},
|
|
isText: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
};
|
|
};
|
|
|
|
var InputGroupAddon = {
|
|
functional: true,
|
|
props: propsFactory$1(false),
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
return h(props.tag, mergeData(data, {
|
|
staticClass: 'input-group-' + (props.append ? 'append' : 'prepend'),
|
|
attrs: {
|
|
id: props.id
|
|
}
|
|
}), props.isText ? [h(InputGroupText, children)] : children);
|
|
}
|
|
};
|
|
|
|
var InputGroupPrepend = {
|
|
functional: true,
|
|
props: propsFactory$1(false),
|
|
render: InputGroupAddon.render
|
|
};
|
|
|
|
var InputGroupAppend = {
|
|
functional: true,
|
|
props: propsFactory$1(true),
|
|
render: InputGroupAddon.render
|
|
};
|
|
|
|
var props$9 = {
|
|
id: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
size: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
prepend: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
append: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
tag: {
|
|
type: String,
|
|
default: 'div'
|
|
}
|
|
};
|
|
|
|
var bInputGroup = {
|
|
functional: true,
|
|
props: props$9,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
slots = _ref.slots;
|
|
|
|
var $slots = slots();
|
|
|
|
var childNodes = [];
|
|
|
|
// Prepend prop
|
|
if (props.prepend) {
|
|
childNodes.push(h(InputGroupPrepend, [h(InputGroupText, { domProps: { innerHTML: props.prepend } })]));
|
|
}
|
|
|
|
// Prepend slot
|
|
if ($slots.prepend) {
|
|
childNodes.push(h(InputGroupPrepend, $slots.prepend));
|
|
}
|
|
|
|
// Default slot
|
|
childNodes.push($slots.default);
|
|
|
|
// Append prop
|
|
if (props.append) {
|
|
childNodes.push(h(InputGroupAppend, [h(InputGroupText, { domProps: { innerHTML: props.append } })]));
|
|
}
|
|
|
|
// Append slot
|
|
if ($slots.append) {
|
|
childNodes.push(h(InputGroupAppend, $slots.append));
|
|
}
|
|
|
|
return h(props.tag, mergeData(data, {
|
|
staticClass: 'input-group',
|
|
class: defineProperty({}, 'input-group-' + props.size, Boolean(props.size)),
|
|
attrs: {
|
|
id: props.id || null,
|
|
role: 'group'
|
|
}
|
|
}), childNodes);
|
|
}
|
|
};
|
|
|
|
var components$6 = {
|
|
bInputGroup: bInputGroup,
|
|
bInputGroupAddon: InputGroupAddon,
|
|
bInputGroupPrepend: InputGroupPrepend,
|
|
bInputGroupAppend: InputGroupAppend,
|
|
bInputGroupText: InputGroupText
|
|
};
|
|
|
|
var VuePlugin$6 = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$6);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$6);
|
|
|
|
/**
|
|
* @param {string} str
|
|
*/
|
|
function upperFirst(str) {
|
|
if (typeof str !== 'string') {
|
|
str = String(str);
|
|
}
|
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
}
|
|
|
|
/**
|
|
* @param {string} prefix
|
|
* @param {string} value
|
|
*/
|
|
function prefixPropName(prefix, value) {
|
|
return prefix + upperFirst(value);
|
|
}
|
|
|
|
/**
|
|
* @param {string} str
|
|
*/
|
|
function lowerFirst(str) {
|
|
if (typeof str !== 'string') {
|
|
str = String(str);
|
|
}
|
|
return str.charAt(0).toLowerCase() + str.slice(1);
|
|
}
|
|
|
|
/**
|
|
* @param {string} prefix
|
|
* @param {string} value
|
|
*/
|
|
function unPrefixPropName(prefix, value) {
|
|
return lowerFirst(value.replace(prefix, ''));
|
|
}
|
|
|
|
/**
|
|
* @param {[]|{}} props
|
|
* @param {Function} transformFn
|
|
*/
|
|
function copyProps(props) {
|
|
var transformFn = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : identity;
|
|
|
|
if (isArray(props)) {
|
|
return props.map(transformFn);
|
|
}
|
|
// Props as an object.
|
|
var copied = {};
|
|
|
|
for (var prop in props) {
|
|
if (props.hasOwnProperty(prop)) {
|
|
if ((typeof prop === 'undefined' ? 'undefined' : _typeof(prop)) === 'object') {
|
|
copied[transformFn(prop)] = assign({}, props[prop]);
|
|
} else {
|
|
copied[transformFn(prop)] = props[prop];
|
|
}
|
|
}
|
|
}
|
|
|
|
return copied;
|
|
}
|
|
|
|
var cardMixin = {
|
|
props: {
|
|
tag: {
|
|
type: String,
|
|
default: 'div'
|
|
},
|
|
bgVariant: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
borderVariant: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
textVariant: {
|
|
type: String,
|
|
default: null
|
|
}
|
|
}
|
|
};
|
|
|
|
var props$a = assign({}, copyProps(cardMixin.props, prefixPropName.bind(null, 'body')), {
|
|
bodyClass: {
|
|
type: [String, Object, Array],
|
|
default: null
|
|
},
|
|
title: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
titleTag: {
|
|
type: String,
|
|
default: 'h4'
|
|
},
|
|
subTitle: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
subTitleTag: {
|
|
type: String,
|
|
default: 'h6'
|
|
},
|
|
overlay: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
});
|
|
|
|
var CardBody = {
|
|
functional: true,
|
|
props: props$a,
|
|
render: function render(h, _ref) {
|
|
var _ref2;
|
|
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
slots = _ref.slots;
|
|
|
|
var cardBodyChildren = [];
|
|
if (props.title) {
|
|
cardBodyChildren.push(h(props.titleTag, {
|
|
staticClass: 'card-title',
|
|
domProps: { innerHTML: props.title }
|
|
}));
|
|
}
|
|
if (props.subTitle) {
|
|
cardBodyChildren.push(h(props.subTitleTag, {
|
|
staticClass: 'card-subtitle mb-2 text-muted',
|
|
domProps: { innerHTML: props.subTitle }
|
|
}));
|
|
}
|
|
cardBodyChildren.push(slots().default);
|
|
|
|
return h(props.bodyTag, mergeData(data, {
|
|
staticClass: 'card-body',
|
|
class: [(_ref2 = {
|
|
'card-img-overlay': props.overlay
|
|
}, defineProperty(_ref2, 'bg-' + props.bodyBgVariant, Boolean(props.bodyBgVariant)), defineProperty(_ref2, 'border-' + props.bodyBorderVariant, Boolean(props.bodyBorderVariant)), defineProperty(_ref2, 'text-' + props.bodyTextVariant, Boolean(props.bodyTextVariant)), _ref2), props.bodyClass || {}]
|
|
}), cardBodyChildren);
|
|
}
|
|
};
|
|
|
|
var props$b = assign({}, copyProps(cardMixin.props, prefixPropName.bind(null, 'header')), {
|
|
header: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
headerClass: {
|
|
type: [String, Object, Array],
|
|
default: null
|
|
}
|
|
});
|
|
|
|
var CardHeader = {
|
|
functional: true,
|
|
props: props$b,
|
|
render: function render(h, _ref) {
|
|
var _ref2;
|
|
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
slots = _ref.slots,
|
|
children = _ref.children;
|
|
|
|
return h(props.headerTag, mergeData(data, {
|
|
staticClass: 'card-header',
|
|
class: [props.headerClass, (_ref2 = {}, defineProperty(_ref2, 'bg-' + props.headerBgVariant, Boolean(props.headerBgVariant)), defineProperty(_ref2, 'border-' + props.headerBorderVariant, Boolean(props.headerBorderVariant)), defineProperty(_ref2, 'text-' + props.headerTextVariant, Boolean(props.headerTextVariant)), _ref2)]
|
|
}), children || [h('div', { domProps: { innerHTML: props.header } })]);
|
|
}
|
|
};
|
|
|
|
var props$c = assign({}, copyProps(cardMixin.props, prefixPropName.bind(null, 'footer')), {
|
|
footer: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
footerClass: {
|
|
type: [String, Object, Array],
|
|
default: null
|
|
}
|
|
});
|
|
|
|
var CardFooter = {
|
|
functional: true,
|
|
props: props$c,
|
|
render: function render(h, _ref) {
|
|
var _ref2;
|
|
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
slots = _ref.slots,
|
|
children = _ref.children;
|
|
|
|
return h(props.footerTag, mergeData(data, {
|
|
staticClass: 'card-footer',
|
|
class: [props.footerClass, (_ref2 = {}, defineProperty(_ref2, 'bg-' + props.footerBgVariant, Boolean(props.footerBgVariant)), defineProperty(_ref2, 'border-' + props.footerBorderVariant, Boolean(props.footerBorderVariant)), defineProperty(_ref2, 'text-' + props.footerTextVariant, Boolean(props.footerTextVariant)), _ref2)]
|
|
}), children || [h('div', { domProps: { innerHTML: props.footer } })]);
|
|
}
|
|
};
|
|
|
|
var props$d = {
|
|
src: {
|
|
type: String,
|
|
default: null,
|
|
required: true
|
|
},
|
|
alt: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
top: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
bottom: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
fluid: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
};
|
|
|
|
var CardImg = {
|
|
functional: true,
|
|
props: props$d,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
slots = _ref.slots;
|
|
|
|
var staticClass = 'card-img';
|
|
if (props.top) {
|
|
staticClass += '-top';
|
|
} else if (props.bottom) {
|
|
staticClass += '-bottom';
|
|
}
|
|
|
|
return h('img', mergeData(data, {
|
|
staticClass: staticClass,
|
|
class: { 'img-fluid': props.fluid },
|
|
attrs: { src: props.src, alt: props.alt }
|
|
}));
|
|
}
|
|
};
|
|
|
|
var cardImgProps = copyProps(props$d, prefixPropName.bind(null, 'img'));
|
|
cardImgProps.imgSrc.required = false;
|
|
|
|
var props$e = assign({}, props$a, props$b, props$c, cardImgProps, copyProps(cardMixin.props), {
|
|
align: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
noBody: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
});
|
|
|
|
var bCard = {
|
|
functional: true,
|
|
props: props$e,
|
|
render: function render(h, _ref) {
|
|
var _class;
|
|
|
|
var props$$1 = _ref.props,
|
|
data = _ref.data,
|
|
slots = _ref.slots,
|
|
children = _ref.children;
|
|
|
|
// The order of the conditionals matter.
|
|
// We are building the component markup in order.
|
|
var childNodes = [];
|
|
var $slots = slots();
|
|
var img = props$$1.imgSrc ? h(CardImg, {
|
|
props: pluckProps(cardImgProps, props$$1, unPrefixPropName.bind(null, 'img'))
|
|
}) : null;
|
|
|
|
if (img) {
|
|
// Above the header placement.
|
|
if (props$$1.imgTop || !props$$1.imgBottom) {
|
|
childNodes.push(img);
|
|
}
|
|
}
|
|
if (props$$1.header || $slots.header) {
|
|
childNodes.push(h(CardHeader, { props: pluckProps(props$b, props$$1) }, $slots.header));
|
|
}
|
|
if (props$$1.noBody) {
|
|
childNodes.push($slots.default);
|
|
} else {
|
|
childNodes.push(h(CardBody, { props: pluckProps(props$a, props$$1) }, $slots.default));
|
|
}
|
|
if (props$$1.footer || $slots.footer) {
|
|
childNodes.push(h(CardFooter, { props: pluckProps(props$c, props$$1) }, $slots.footer));
|
|
}
|
|
if (img && props$$1.imgBottom) {
|
|
// Below the footer placement.
|
|
childNodes.push(img);
|
|
}
|
|
|
|
return h(props$$1.tag, mergeData(data, {
|
|
staticClass: 'card',
|
|
class: (_class = {}, defineProperty(_class, 'text-' + props$$1.align, Boolean(props$$1.align)), defineProperty(_class, 'bg-' + props$$1.bgVariant, Boolean(props$$1.bgVariant)), defineProperty(_class, 'border-' + props$$1.borderVariant, Boolean(props$$1.borderVariant)), defineProperty(_class, 'text-' + props$$1.textVariant, Boolean(props$$1.textVariant)), _class)
|
|
}), childNodes);
|
|
}
|
|
};
|
|
|
|
var props$f = {
|
|
tag: {
|
|
type: String,
|
|
default: 'div'
|
|
},
|
|
deck: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
columns: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
};
|
|
|
|
var bCardGroup = {
|
|
functional: true,
|
|
props: props$f,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
var staticClass = 'card-group';
|
|
if (props.columns) {
|
|
staticClass = 'card-columns';
|
|
}
|
|
if (props.deck) {
|
|
staticClass = 'card-deck';
|
|
}
|
|
|
|
return h(props.tag, mergeData(data, { staticClass: staticClass }), children);
|
|
}
|
|
};
|
|
|
|
var components$7 = {
|
|
bCard: bCard,
|
|
bCardHeader: CardHeader,
|
|
bCardBody: CardBody,
|
|
bCardFooter: CardFooter,
|
|
bCardImg: CardImg,
|
|
bCardGroup: bCardGroup
|
|
};
|
|
|
|
var VuePlugin$7 = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$7);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$7);
|
|
|
|
/**
|
|
* Observe a DOM element changes, falls back to eventListener mode
|
|
* @param {Element} el The DOM element to observe
|
|
* @param {Function} callback callback to be called on change
|
|
* @param {object} [opts={childList: true, subtree: true}] observe options
|
|
* @see http://stackoverflow.com/questions/3219758
|
|
*/
|
|
function observeDOM(el, callback, opts) {
|
|
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
|
|
var eventListenerSupported = window.addEventListener;
|
|
|
|
// Handle case where we might be passed a vue instance
|
|
el = el ? el.$el || el : null;
|
|
/* istanbul ignore next: dificult to test in JSDOM */
|
|
if (!isElement(el)) {
|
|
// We can't observe somthing that isn't an element
|
|
return null;
|
|
}
|
|
|
|
var obs = null;
|
|
|
|
/* istanbul ignore next: dificult to test in JSDOM */
|
|
if (MutationObserver) {
|
|
// Define a new observer
|
|
obs = new MutationObserver(function (mutations) {
|
|
var changed = false;
|
|
// A Mutation can contain several change records, so we loop through them to see what has changed.
|
|
// We break out of the loop early if any "significant" change has been detected
|
|
for (var i = 0; i < mutations.length && !changed; i++) {
|
|
// The muttion record
|
|
var mutation = mutations[i];
|
|
// Mutation Type
|
|
var type = mutation.type;
|
|
// DOM Node (could be any DOM Node type - HTMLElement, Text, comment, etc)
|
|
var target = mutation.target;
|
|
if (type === 'characterData' && target.nodeType === Node.TEXT_NODE) {
|
|
// We ignore nodes that are not TEXt (i.e. comments, etc) as they don't change layout
|
|
changed = true;
|
|
} else if (type === 'attributes') {
|
|
changed = true;
|
|
} else if (type === 'childList' && (mutation.addedNodes.length > 0 || mutation.removedNodes.length > 0)) {
|
|
// This includes HTMLElement and Text Nodes being added/removed/re-arranged
|
|
changed = true;
|
|
}
|
|
}
|
|
if (changed) {
|
|
// We only call the callback if a change that could affect layout/size truely happened.
|
|
callback();
|
|
}
|
|
});
|
|
|
|
// Have the observer observe foo for changes in children, etc
|
|
obs.observe(el, assign({ childList: true, subtree: true }, opts));
|
|
} else if (eventListenerSupported) {
|
|
// Legacy interface. most likely not used in modern browsers
|
|
el.addEventListener('DOMNodeInserted', callback, false);
|
|
el.addEventListener('DOMNodeRemoved', callback, false);
|
|
}
|
|
|
|
// We return a reference to the observer so that obs.disconnect() can be called if necessary
|
|
// To reduce overhead when the root element is hiiden
|
|
return obs;
|
|
}
|
|
|
|
/*
|
|
* SSR Safe Client Side ID attribute generation
|
|
*
|
|
*/
|
|
|
|
var idMixin = {
|
|
props: {
|
|
id: {
|
|
type: String,
|
|
default: null
|
|
}
|
|
},
|
|
methods: {
|
|
safeId: function safeId() {
|
|
var suffix = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
|
|
|
var id = this.id || this.localId_ || null;
|
|
if (!id) {
|
|
return null;
|
|
}
|
|
suffix = String(suffix).replace(/\s+/g, '_');
|
|
return suffix ? id + '_' + suffix : id;
|
|
}
|
|
},
|
|
computed: {
|
|
localId_: function localId_() {
|
|
if (!this.$isServer && !this.id && typeof this._uid !== 'undefined') {
|
|
return '__BVID__' + this._uid;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// Slide directional classes
|
|
var DIRECTION = {
|
|
next: {
|
|
dirClass: 'carousel-item-left',
|
|
overlayClass: 'carousel-item-next'
|
|
},
|
|
prev: {
|
|
dirClass: 'carousel-item-right',
|
|
overlayClass: 'carousel-item-prev'
|
|
}
|
|
|
|
// Fallback Transition duration (with a little buffer) in ms
|
|
};var TRANS_DURATION = 600 + 50;
|
|
|
|
// Transition Event names
|
|
var TransitionEndEvents = {
|
|
WebkitTransition: 'webkitTransitionEnd',
|
|
MozTransition: 'transitionend',
|
|
OTransition: 'otransitionend oTransitionEnd',
|
|
transition: 'transitionend'
|
|
|
|
// Return the browser specific transitionEnd event name
|
|
};function getTransisionEndEvent(el) {
|
|
for (var name in TransitionEndEvents) {
|
|
if (el.style[name] !== undefined) {
|
|
return TransitionEndEvents[name];
|
|
}
|
|
}
|
|
// fallback
|
|
return null;
|
|
}
|
|
|
|
var bCarousel = {
|
|
mixins: [idMixin],
|
|
render: function render(h) {
|
|
var _this = this;
|
|
|
|
// Wrapper for slides
|
|
var inner = h('div', {
|
|
ref: 'inner',
|
|
class: ['carousel-inner'],
|
|
attrs: {
|
|
id: this.safeId('__BV_inner_'),
|
|
role: 'list'
|
|
}
|
|
}, [this.$slots.default]);
|
|
|
|
// Prev and Next Controls
|
|
var controls = h(false);
|
|
if (this.controls) {
|
|
controls = [h('a', {
|
|
class: ['carousel-control-prev'],
|
|
attrs: { href: '#', role: 'button', 'aria-controls': this.safeId('__BV_inner_') },
|
|
on: {
|
|
click: function click(evt) {
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
_this.prev();
|
|
},
|
|
keydown: function keydown(evt) {
|
|
var keyCode = evt.keyCode;
|
|
if (keyCode === KeyCodes.SPACE || keyCode === KeyCodes.ENTER) {
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
_this.prev();
|
|
}
|
|
}
|
|
}
|
|
}, [h('span', { class: ['carousel-control-prev-icon'], attrs: { 'aria-hidden': 'true' } }), h('span', { class: ['sr-only'] }, [this.labelPrev])]), h('a', {
|
|
class: ['carousel-control-next'],
|
|
attrs: { href: '#', role: 'button', 'aria-controls': this.safeId('__BV_inner_') },
|
|
on: {
|
|
click: function click(evt) {
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
_this.next();
|
|
},
|
|
keydown: function keydown(evt) {
|
|
var keyCode = evt.keyCode;
|
|
if (keyCode === KeyCodes.SPACE || keyCode === KeyCodes.ENTER) {
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
_this.next();
|
|
}
|
|
}
|
|
}
|
|
}, [h('span', { class: ['carousel-control-next-icon'], attrs: { 'aria-hidden': 'true' } }), h('span', { class: ['sr-only'] }, [this.labelNext])])];
|
|
}
|
|
|
|
// Indicators
|
|
var indicators = h('ol', {
|
|
class: ['carousel-indicators'],
|
|
directives: [{ name: 'show', rawName: 'v-show', value: this.indicators, expression: 'indicators' }],
|
|
attrs: {
|
|
id: this.safeId('__BV_indicators_'),
|
|
'aria-hidden': this.indicators ? 'false' : 'true',
|
|
'aria-label': this.labelIndicators,
|
|
'aria-owns': this.safeId('__BV_inner_')
|
|
}
|
|
}, this.slides.map(function (slide, n) {
|
|
return h('li', {
|
|
key: 'slide_' + n,
|
|
class: { active: n === _this.index },
|
|
attrs: {
|
|
role: 'button',
|
|
id: _this.safeId('__BV_indicator_' + (n + 1) + '_'),
|
|
tabindex: _this.indicators ? '0' : '-1',
|
|
'aria-current': n === _this.index ? 'true' : 'false',
|
|
'aria-label': _this.labelGotoSlide + ' ' + (n + 1),
|
|
'aria-describedby': _this.slides[n].id || null,
|
|
'aria-controls': _this.safeId('__BV_inner_')
|
|
},
|
|
on: {
|
|
click: function click(evt) {
|
|
_this.setSlide(n);
|
|
},
|
|
keydown: function keydown(evt) {
|
|
var keyCode = evt.keyCode;
|
|
if (keyCode === KeyCodes.SPACE || keyCode === KeyCodes.ENTER) {
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
_this.setSlide(n);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}));
|
|
|
|
// Return the carousel
|
|
return h('div', {
|
|
class: ['carousel', 'slide'],
|
|
style: { background: this.background },
|
|
attrs: {
|
|
role: 'region',
|
|
id: this.safeId(),
|
|
'aria-busy': this.isSliding ? 'true' : 'false'
|
|
},
|
|
on: {
|
|
mouseenter: this.pause,
|
|
mouseleave: this.restart,
|
|
focusin: this.pause,
|
|
focusout: this.restart,
|
|
keydown: function keydown(evt) {
|
|
var keyCode = evt.keyCode;
|
|
if (keyCode === KeyCodes.LEFT || keyCode === KeyCodes.RIGHT) {
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
_this[keyCode === KeyCodes.LEFT ? 'prev' : 'next']();
|
|
}
|
|
}
|
|
}
|
|
}, [inner, controls, indicators]);
|
|
},
|
|
data: function data() {
|
|
return {
|
|
index: this.value || 0,
|
|
isSliding: false,
|
|
intervalId: null,
|
|
transitionEndEvent: null,
|
|
slides: [],
|
|
direction: null
|
|
};
|
|
},
|
|
|
|
props: {
|
|
labelPrev: {
|
|
type: String,
|
|
default: 'Previous Slide'
|
|
},
|
|
labelNext: {
|
|
type: String,
|
|
default: 'Next Slide'
|
|
},
|
|
labelGotoSlide: {
|
|
type: String,
|
|
default: 'Goto Slide'
|
|
},
|
|
labelIndicators: {
|
|
type: String,
|
|
default: 'Select a slide to display'
|
|
},
|
|
interval: {
|
|
type: Number,
|
|
default: 5000
|
|
},
|
|
indicators: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
controls: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
imgWidth: {
|
|
// Sniffed by carousel-slide
|
|
type: [Number, String]
|
|
},
|
|
imgHeight: {
|
|
// Sniffed by carousel-slide
|
|
type: [Number, String]
|
|
},
|
|
background: {
|
|
type: String
|
|
},
|
|
value: {
|
|
type: Number,
|
|
default: 0
|
|
}
|
|
},
|
|
computed: {
|
|
isCycling: function isCycling() {
|
|
return Boolean(this.intervalId);
|
|
}
|
|
},
|
|
methods: {
|
|
// Set slide
|
|
setSlide: function setSlide(slide) {
|
|
var _this2 = this;
|
|
|
|
// Don't animate when page is not visible
|
|
if (typeof document !== 'undefined' && document.visibilityState && document.hidden) {
|
|
return;
|
|
}
|
|
var len = this.slides.length;
|
|
// Don't do anything if nothing to slide to
|
|
if (len === 0) {
|
|
return;
|
|
}
|
|
// Don't change slide while transitioning, wait until transition is done
|
|
if (this.isSliding) {
|
|
// Schedule slide after sliding complete
|
|
this.$once('sliding-end', function () {
|
|
return _this2.setSlide(slide);
|
|
});
|
|
return;
|
|
}
|
|
// Make sure we have an integer (you never know!)
|
|
slide = Math.floor(slide);
|
|
// Set new slide index. Wrap around if necessary
|
|
this.index = slide >= len ? 0 : slide >= 0 ? slide : len - 1;
|
|
},
|
|
|
|
// Previous slide
|
|
prev: function prev() {
|
|
this.direction = 'prev';
|
|
this.setSlide(this.index - 1);
|
|
},
|
|
|
|
// Next slide
|
|
next: function next() {
|
|
this.direction = 'next';
|
|
this.setSlide(this.index + 1);
|
|
},
|
|
|
|
// Pause auto rotation
|
|
pause: function pause() {
|
|
if (this.isCycling) {
|
|
clearInterval(this.intervalId);
|
|
this.intervalId = null;
|
|
if (this.slides[this.index]) {
|
|
// Make current slide focusable for screen readers
|
|
this.slides[this.index].tabIndex = 0;
|
|
}
|
|
}
|
|
},
|
|
|
|
// Start auto rotate slides
|
|
start: function start() {
|
|
var _this3 = this;
|
|
|
|
// Don't start if no interval, or if we are already running
|
|
if (!this.interval || this.isCycling) {
|
|
return;
|
|
}
|
|
this.slides.forEach(function (slide) {
|
|
slide.tabIndex = -1;
|
|
});
|
|
this.intervalId = setInterval(function () {
|
|
_this3.next();
|
|
}, Math.max(1000, this.interval));
|
|
},
|
|
|
|
// Re-Start auto rotate slides when focus/hover leaves the carousel
|
|
restart: function restart(evt) {
|
|
if (!this.$el.contains(document.activeElement)) {
|
|
this.start();
|
|
}
|
|
},
|
|
|
|
// Update slide list
|
|
updateSlides: function updateSlides() {
|
|
this.pause();
|
|
// Get all slides as DOM elements
|
|
this.slides = selectAll('.carousel-item', this.$refs.inner);
|
|
var numSlides = this.slides.length;
|
|
// Keep slide number in range
|
|
var index = Math.max(0, Math.min(Math.floor(this.index), numSlides - 1));
|
|
this.slides.forEach(function (slide, idx) {
|
|
var n = idx + 1;
|
|
if (idx === index) {
|
|
addClass(slide, 'active');
|
|
} else {
|
|
removeClass(slide, 'active');
|
|
}
|
|
setAttr(slide, 'aria-current', idx === index ? 'true' : 'false');
|
|
setAttr(slide, 'aria-posinset', String(n));
|
|
setAttr(slide, 'aria-setsize', String(numSlides));
|
|
slide.tabIndex = -1;
|
|
});
|
|
// Set slide as active
|
|
this.setSlide(index);
|
|
this.start();
|
|
},
|
|
calcDirection: function calcDirection() {
|
|
var direction = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
|
|
var curIndex = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
var nextIndex = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
|
|
|
|
if (!direction) {
|
|
return nextIndex > curIndex ? DIRECTION.next : DIRECTION.prev;
|
|
}
|
|
return DIRECTION[direction];
|
|
}
|
|
},
|
|
watch: {
|
|
value: function value(newVal, oldVal) {
|
|
if (newVal !== oldVal) {
|
|
this.setSlide(newVal);
|
|
}
|
|
},
|
|
interval: function interval(newVal, oldVal) {
|
|
if (newVal === oldVal) {
|
|
return;
|
|
}
|
|
if (!newVal) {
|
|
// Pausing slide show
|
|
this.pause();
|
|
} else {
|
|
// Restarting or Changing interval
|
|
this.pause();
|
|
this.start();
|
|
}
|
|
},
|
|
index: function index(val, oldVal) {
|
|
var _this4 = this;
|
|
|
|
if (val === oldVal || this.isSliding) {
|
|
return;
|
|
}
|
|
// Determine sliding direction
|
|
var direction = this.calcDirection(this.direction, oldVal, val);
|
|
// Determine current and next slides
|
|
var currentSlide = this.slides[oldVal];
|
|
var nextSlide = this.slides[val];
|
|
// Don't do anything if there aren't any slides to slide to
|
|
if (!currentSlide || !nextSlide) {
|
|
return;
|
|
}
|
|
// Start animating
|
|
this.isSliding = true;
|
|
this.$emit('sliding-start', val);
|
|
// Update v-model
|
|
this.$emit('input', this.index);
|
|
nextSlide.classList.add(direction.overlayClass);
|
|
// Trigger a reflow of next slide
|
|
reflow(nextSlide);
|
|
addClass(currentSlide, direction.dirClass);
|
|
addClass(nextSlide, direction.dirClass);
|
|
// Transition End handler
|
|
var called = false;
|
|
/* istanbul ignore next: dificult to test */
|
|
var onceTransEnd = function onceTransEnd(evt) {
|
|
if (called) {
|
|
return;
|
|
}
|
|
called = true;
|
|
if (_this4.transitionEndEvent) {
|
|
var events = _this4.transitionEndEvent.split(/\s+/);
|
|
events.forEach(function (event) {
|
|
eventOff(currentSlide, event, onceTransEnd);
|
|
});
|
|
}
|
|
_this4._animationTimeout = null;
|
|
removeClass(nextSlide, direction.dirClass);
|
|
removeClass(nextSlide, direction.overlayClass);
|
|
addClass(nextSlide, 'active');
|
|
removeClass(currentSlide, 'active');
|
|
removeClass(currentSlide, direction.dirClass);
|
|
removeClass(currentSlide, direction.overlayClass);
|
|
setAttr(currentSlide, 'aria-current', 'false');
|
|
setAttr(nextSlide, 'aria-current', 'true');
|
|
setAttr(currentSlide, 'aria-hidden', 'true');
|
|
setAttr(nextSlide, 'aria-hidden', 'false');
|
|
currentSlide.tabIndex = -1;
|
|
nextSlide.tabIndex = -1;
|
|
if (!_this4.isCycling) {
|
|
// Focus the next slide for screen readers if not in play mode
|
|
nextSlide.tabIndex = 0;
|
|
_this4.$nextTick(function () {
|
|
nextSlide.focus();
|
|
});
|
|
}
|
|
_this4.isSliding = false;
|
|
_this4.direction = null;
|
|
// Notify ourselves that we're done sliding (slid)
|
|
_this4.$nextTick(function () {
|
|
return _this4.$emit('sliding-end', val);
|
|
});
|
|
};
|
|
// Clear transition classes after transition ends
|
|
if (this.transitionEndEvent) {
|
|
var events = this.transitionEndEvent.split(/\s+/);
|
|
events.forEach(function (event) {
|
|
eventOn(currentSlide, event, onceTransEnd);
|
|
});
|
|
}
|
|
// Fallback to setTimeout
|
|
this._animationTimeout = setTimeout(onceTransEnd, TRANS_DURATION);
|
|
}
|
|
},
|
|
created: function created() {
|
|
// Create private non-reactive props
|
|
this._animationTimeout = null;
|
|
},
|
|
mounted: function mounted() {
|
|
// Cache current browser transitionend event name
|
|
this.transitionEndEvent = getTransisionEndEvent(this.$el) || null;
|
|
// Get all slides
|
|
this.updateSlides();
|
|
// Observe child changes so we can update slide list
|
|
observeDOM(this.$refs.inner, this.updateSlides.bind(this), {
|
|
subtree: false,
|
|
childList: true,
|
|
attributes: true,
|
|
attributeFilter: ['id']
|
|
});
|
|
},
|
|
|
|
/* istanbul ignore next: dificult to test */
|
|
beforeDestroy: function beforeDestroy() {
|
|
clearInterval(this.intervalId);
|
|
clearTimeout(this._animationTimeout);
|
|
this.intervalId = null;
|
|
this._animationTimeout = null;
|
|
}
|
|
};
|
|
|
|
// Blank image with fill template
|
|
var BLANK_TEMPLATE = '<svg width="%{w}" height="%{h}" ' + 'xmlns="http://www.w3.org/2000/svg" ' + 'viewBox="0 0 %{w} %{h}" preserveAspectRatio="none">' + '<rect width="100%" height="100%" style="fill:%{f};"></rect>' + '</svg>';
|
|
|
|
function makeBlankImgSrc(width, height, color) {
|
|
var src = encodeURIComponent(BLANK_TEMPLATE.replace('%{w}', String(width)).replace('%{h}', String(height)).replace('%{f}', color));
|
|
return 'data:image/svg+xml;charset=UTF-8,' + src;
|
|
}
|
|
|
|
var props$g = {
|
|
src: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
alt: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
width: {
|
|
type: [Number, String],
|
|
default: null
|
|
},
|
|
height: {
|
|
type: [Number, String],
|
|
default: null
|
|
},
|
|
block: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
fluid: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
fluidGrow: {
|
|
// Gives fluid images class `w-100` to make them grow to fit container
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
rounded: {
|
|
// rounded can be:
|
|
// false: no rounding of corners
|
|
// true: slightly rounded corners
|
|
// 'top': top corners rounded
|
|
// 'right': right corners rounded
|
|
// 'bottom': bottom corners rounded
|
|
// 'left': left corners rounded
|
|
// 'circle': circle/oval
|
|
// '0': force rounding off
|
|
type: [Boolean, String],
|
|
default: false
|
|
},
|
|
thumbnail: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
left: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
right: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
center: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
blank: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
blankColor: {
|
|
type: String,
|
|
default: 'transparent'
|
|
}
|
|
};
|
|
|
|
var bImg = {
|
|
functional: true,
|
|
props: props$g,
|
|
render: function render(h, _ref) {
|
|
var _class;
|
|
|
|
var props = _ref.props,
|
|
data = _ref.data;
|
|
|
|
var src = props.src;
|
|
var width = parseInt(props.width, 10) ? parseInt(props.width, 10) : null;
|
|
var height = parseInt(props.height, 10) ? parseInt(props.height, 10) : null;
|
|
var align = null;
|
|
var block = props.block;
|
|
if (props.blank) {
|
|
if (!height && Boolean(width)) {
|
|
height = width;
|
|
} else if (!width && Boolean(height)) {
|
|
width = height;
|
|
}
|
|
if (!width && !height) {
|
|
width = 1;
|
|
height = 1;
|
|
}
|
|
// Make a blank SVG image
|
|
src = makeBlankImgSrc(width, height, props.blankColor || 'transparent');
|
|
}
|
|
if (props.left) {
|
|
align = 'float-start';
|
|
} else if (props.right) {
|
|
align = 'float-end';
|
|
} else if (props.center) {
|
|
align = 'mx-auto';
|
|
block = true;
|
|
}
|
|
return h('img', mergeData(data, {
|
|
attrs: {
|
|
'src': src,
|
|
'alt': props.alt,
|
|
'width': width ? String(width) : null,
|
|
'height': height ? String(height) : null
|
|
},
|
|
class: (_class = {
|
|
'img-thumbnail': props.thumbnail,
|
|
'img-fluid': props.fluid || props.fluidGrow,
|
|
'w-100': props.fluidGrow,
|
|
'rounded': props.rounded === '' || props.rounded === true
|
|
}, defineProperty(_class, 'rounded-' + props.rounded, typeof props.rounded === 'string' && props.rounded !== ''), defineProperty(_class, align, Boolean(align)), defineProperty(_class, 'd-block', block), _class)
|
|
}));
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Log a warning message to the console with bootstrap-vue formatting sugar.
|
|
* @param {string} message
|
|
*/
|
|
/* istanbul ignore next */
|
|
function warn(message) {
|
|
console.warn("[Bootstrap-Vue warn]: " + message);
|
|
}
|
|
|
|
var bCarouselSlide = {
|
|
components: { bImg: bImg },
|
|
mixins: [idMixin],
|
|
render: function render(h) {
|
|
var $slots = this.$slots;
|
|
|
|
var img = $slots.img;
|
|
if (!img && (this.imgSrc || this.imgBlank)) {
|
|
img = h('b-img', {
|
|
props: {
|
|
fluidGrow: true,
|
|
block: true,
|
|
src: this.imgSrc,
|
|
blank: this.imgBlank,
|
|
blankColor: this.imgBlankColor,
|
|
width: this.computedWidth,
|
|
height: this.computedHeight,
|
|
alt: this.imgAlt
|
|
}
|
|
});
|
|
}
|
|
|
|
var content = h(this.contentTag, { class: this.contentClasses }, [this.caption ? h(this.captionTag, { domProps: { innerHTML: this.caption } }) : h(false), this.text ? h(this.textTag, { domProps: { innerHTML: this.text } }) : h(false), $slots.default]);
|
|
|
|
return h('div', {
|
|
class: ['carousel-item'],
|
|
style: { background: this.background },
|
|
attrs: { id: this.safeId(), role: 'listitem' }
|
|
}, [img, content]);
|
|
},
|
|
|
|
props: {
|
|
imgSrc: {
|
|
type: String,
|
|
default: function _default() {
|
|
if (this && this.src) {
|
|
// Deprecate src
|
|
warn("b-carousel-slide: prop 'src' has been deprecated. Use 'img-src' instead");
|
|
return this.src;
|
|
}
|
|
return null;
|
|
}
|
|
},
|
|
src: {
|
|
// Deprecated: use img-src instead
|
|
type: String
|
|
},
|
|
imgAlt: {
|
|
type: String
|
|
},
|
|
imgWidth: {
|
|
type: [Number, String]
|
|
},
|
|
imgHeight: {
|
|
type: [Number, String]
|
|
},
|
|
imgBlank: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
imgBlankColor: {
|
|
type: String,
|
|
default: 'transparent'
|
|
},
|
|
contentVisibleUp: {
|
|
type: String
|
|
},
|
|
contentTag: {
|
|
type: String,
|
|
default: 'div'
|
|
},
|
|
caption: {
|
|
type: String
|
|
},
|
|
captionTag: {
|
|
type: String,
|
|
default: 'h3'
|
|
},
|
|
text: {
|
|
type: String
|
|
},
|
|
textTag: {
|
|
type: String,
|
|
default: 'p'
|
|
},
|
|
background: {
|
|
type: String
|
|
}
|
|
},
|
|
computed: {
|
|
contentClasses: function contentClasses() {
|
|
return ['carousel-caption', this.contentVisibleUp ? 'd-none' : '', this.contentVisibleUp ? 'd-' + this.contentVisibleUp + '-block' : ''];
|
|
},
|
|
computedWidth: function computedWidth() {
|
|
// Use local width, or try parent width
|
|
return this.imgWidth || this.$parent.imgWidth;
|
|
},
|
|
computedHeight: function computedHeight() {
|
|
// Use local height, or try parent height
|
|
return this.imgHeight || this.$parent.imgHeight;
|
|
}
|
|
}
|
|
};
|
|
|
|
var components$8 = {
|
|
bCarousel: bCarousel,
|
|
bCarouselSlide: bCarouselSlide
|
|
};
|
|
|
|
var VuePlugin$8 = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$8);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$8);
|
|
|
|
var props$h = {
|
|
tag: {
|
|
type: String,
|
|
default: 'div'
|
|
},
|
|
fluid: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
};
|
|
|
|
var Container = {
|
|
functional: true,
|
|
props: props$h,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
return h(props.tag, mergeData(data, {
|
|
class: {
|
|
'container': !props.fluid,
|
|
'container-fluid': props.fluid
|
|
}
|
|
}), children);
|
|
}
|
|
};
|
|
|
|
var COMMON_ALIGNMENT = ['start', 'end', 'center'];
|
|
|
|
var props$i = {
|
|
tag: {
|
|
type: String,
|
|
default: 'div'
|
|
},
|
|
noGutters: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
alignV: {
|
|
type: String,
|
|
default: null,
|
|
validator: function validator(str) {
|
|
return arrayIncludes(COMMON_ALIGNMENT.concat(['baseline', 'stretch']), str);
|
|
}
|
|
},
|
|
alignH: {
|
|
type: String,
|
|
default: null,
|
|
validator: function validator(str) {
|
|
return arrayIncludes(COMMON_ALIGNMENT.concat(['between', 'around']), str);
|
|
}
|
|
},
|
|
alignContent: {
|
|
type: String,
|
|
default: null,
|
|
validator: function validator(str) {
|
|
return arrayIncludes(COMMON_ALIGNMENT.concat(['between', 'around', 'stretch']), str);
|
|
}
|
|
}
|
|
};
|
|
|
|
var bRow = {
|
|
functional: true,
|
|
props: props$i,
|
|
render: function render(h, _ref) {
|
|
var _class;
|
|
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
return h(props.tag, mergeData(data, {
|
|
staticClass: 'row',
|
|
class: (_class = {
|
|
'no-gutters': props.noGutters
|
|
}, defineProperty(_class, 'align-items-' + props.alignV, props.alignV), defineProperty(_class, 'justify-content-' + props.alignH, props.alignH), defineProperty(_class, 'align-content-' + props.alignContent, props.alignContent), _class)
|
|
}), children);
|
|
}
|
|
};
|
|
|
|
function memoize(fn) {
|
|
var cache = create(null);
|
|
|
|
return function memoizedFn() {
|
|
var args = JSON.stringify(arguments);
|
|
return cache[args] = cache[args] || fn.apply(null, arguments);
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Suffix can be a falsey value so nothing is appended to string.
|
|
* (helps when looping over props & some shouldn't change)
|
|
* Use data last parameters to allow for currying.
|
|
* @param {string} suffix
|
|
* @param {string} str
|
|
*/
|
|
function suffixPropName(suffix, str) {
|
|
return str + (suffix ? upperFirst(suffix) : '');
|
|
}
|
|
|
|
/**
|
|
* Generates a prop object with a type of
|
|
* [Boolean, String, Number]
|
|
*/
|
|
function boolStrNum() {
|
|
return {
|
|
type: [Boolean, String, Number],
|
|
default: false
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generates a prop object with a type of
|
|
* [String, Number]
|
|
*/
|
|
function strNum() {
|
|
return {
|
|
type: [String, Number],
|
|
default: null
|
|
};
|
|
}
|
|
|
|
var computeBkPtClass = memoize(function computeBkPt(type, breakpoint, val) {
|
|
var className = type;
|
|
if (val === false || val === null || val === undefined) {
|
|
return undefined;
|
|
}
|
|
if (breakpoint) {
|
|
className += '-' + breakpoint;
|
|
}
|
|
// Handling the boolean style prop when accepting [Boolean, String, Number]
|
|
// means Vue will not convert <b-col sm /> to sm: true for us.
|
|
// Since the default is false, an empty string indicates the prop's presence.
|
|
if (type === 'col' && (val === '' || val === true)) {
|
|
// .col-md
|
|
return className.toLowerCase();
|
|
}
|
|
// .order-md-6
|
|
className += '-' + val;
|
|
return className.toLowerCase();
|
|
});
|
|
|
|
var BREAKPOINTS = ['sm', 'md', 'lg', 'xl'];
|
|
// Supports classes like: .col-sm, .col-md-6, .col-lg-auto
|
|
var breakpointCol = BREAKPOINTS.reduce(
|
|
// eslint-disable-next-line no-sequences
|
|
function (propMap, breakpoint) {
|
|
return propMap[breakpoint] = boolStrNum(), propMap;
|
|
}, create(null));
|
|
// Supports classes like: .offset-md-1, .offset-lg-12
|
|
var breakpointOffset = BREAKPOINTS.reduce(
|
|
// eslint-disable-next-line no-sequences
|
|
function (propMap, breakpoint) {
|
|
return propMap[suffixPropName(breakpoint, 'offset')] = strNum(), propMap;
|
|
}, create(null));
|
|
// Supports classes like: .order-md-1, .order-lg-12
|
|
var breakpointOrder = BREAKPOINTS.reduce(
|
|
// eslint-disable-next-line no-sequences
|
|
function (propMap, breakpoint) {
|
|
return propMap[suffixPropName(breakpoint, 'order')] = strNum(), propMap;
|
|
}, create(null));
|
|
|
|
// For loop doesn't need to check hasOwnProperty
|
|
// when using an object created from null
|
|
var breakpointPropMap = assign(create(null), {
|
|
col: keys(breakpointCol),
|
|
offset: keys(breakpointOffset),
|
|
order: keys(breakpointOrder)
|
|
});
|
|
|
|
var props$j = assign({}, breakpointCol, breakpointOffset, breakpointOrder, {
|
|
tag: {
|
|
type: String,
|
|
default: 'div'
|
|
},
|
|
// Generic flexbox .col
|
|
col: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
// .col-[1-12]|auto
|
|
cols: strNum(),
|
|
// .offset-[1-12]
|
|
offset: strNum(),
|
|
// Flex ordering utility .order-[1-12]
|
|
order: strNum(),
|
|
alignSelf: {
|
|
type: String,
|
|
default: null,
|
|
validator: function validator(str) {
|
|
return arrayIncludes(['auto', 'start', 'end', 'center', 'baseline', 'stretch'], str);
|
|
}
|
|
}
|
|
});
|
|
|
|
/**
|
|
* We need ".col" to default in when no other props are passed,
|
|
* but always render when col=true.
|
|
*/
|
|
var bCol = {
|
|
functional: true,
|
|
props: props$j,
|
|
render: function render(h, _ref) {
|
|
var _classList$push;
|
|
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
var classList = [];
|
|
// Loop through `col`, `offset`, `order` breakpoint props
|
|
for (var type in breakpointPropMap) {
|
|
// Returns colSm, offset, offsetSm, orderMd, etc.
|
|
var _keys = breakpointPropMap[type];
|
|
for (var i = 0; i < _keys.length; i++) {
|
|
// computeBkPt(col, colSm => Sm, value=[String, Number, Boolean])
|
|
var c = computeBkPtClass(type, _keys[i].replace(type, ''), props[_keys[i]]);
|
|
// If a class is returned, push it onto the array.
|
|
if (c) {
|
|
classList.push(c);
|
|
}
|
|
}
|
|
}
|
|
|
|
classList.push((_classList$push = {
|
|
// Default to .col if no other classes generated nor `cols` specified.
|
|
col: props.col || classList.length === 0 && !props.cols
|
|
}, defineProperty(_classList$push, 'col-' + props.cols, props.cols), defineProperty(_classList$push, 'offset-' + props.offset, props.offset), defineProperty(_classList$push, 'order-' + props.order, props.order), defineProperty(_classList$push, 'align-self-' + props.alignSelf, props.alignSelf), _classList$push));
|
|
|
|
return h(props.tag, mergeData(data, { class: classList }), children);
|
|
}
|
|
};
|
|
|
|
var props$k = {
|
|
tag: {
|
|
type: String,
|
|
default: 'div'
|
|
}
|
|
};
|
|
|
|
var bFormRow = {
|
|
functional: true,
|
|
props: props$k,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
return h(props.tag, mergeData(data, {
|
|
staticClass: 'row'
|
|
}), children);
|
|
}
|
|
};
|
|
|
|
var components$9 = {
|
|
bContainer: Container,
|
|
bRow: bRow,
|
|
bCol: bCol,
|
|
bFormRow: bFormRow
|
|
};
|
|
|
|
var VuePlugin$9 = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$9);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$9);
|
|
|
|
/**
|
|
* Issue #569: collapse::toggle::state triggered too many times
|
|
* @link https://github.com/bootstrap-vue/bootstrap-vue/issues/569
|
|
*/
|
|
|
|
var BVRL = '__BV_root_listeners__';
|
|
|
|
var listenOnRootMixin = {
|
|
methods: {
|
|
/**
|
|
* Safely register event listeners on the root Vue node.
|
|
* While Vue automatically removes listeners for individual components,
|
|
* when a component registers a listener on root and is destroyed,
|
|
* this orphans a callback because the node is gone,
|
|
* but the root does not clear the callback.
|
|
*
|
|
* This adds a non-reactive prop to a vm on the fly
|
|
* in order to avoid object observation and its performance costs
|
|
* to something that needs no reactivity.
|
|
* It should be highly unlikely there are any naming collisions.
|
|
* @param {string} event
|
|
* @param {function} callback
|
|
* @chainable
|
|
*/
|
|
listenOnRoot: function listenOnRoot(event, callback) {
|
|
if (!this[BVRL] || !isArray(this[BVRL])) {
|
|
this[BVRL] = [];
|
|
}
|
|
this[BVRL].push({ event: event, callback: callback });
|
|
this.$root.$on(event, callback);
|
|
return this;
|
|
},
|
|
|
|
|
|
/**
|
|
* Convenience method for calling vm.$emit on vm.$root.
|
|
* @param {string} event
|
|
* @param {*} args
|
|
* @chainable
|
|
*/
|
|
emitOnRoot: function emitOnRoot(event) {
|
|
var _$root;
|
|
|
|
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
args[_key - 1] = arguments[_key];
|
|
}
|
|
|
|
(_$root = this.$root).$emit.apply(_$root, [event].concat(toConsumableArray(args)));
|
|
return this;
|
|
}
|
|
},
|
|
|
|
beforeDestroy: function beforeDestroy() {
|
|
if (this[BVRL] && isArray(this[BVRL])) {
|
|
while (this[BVRL].length > 0) {
|
|
// shift to process in order
|
|
var _BVRL$shift = this[BVRL].shift(),
|
|
event = _BVRL$shift.event,
|
|
callback = _BVRL$shift.callback;
|
|
|
|
this.$root.$off(event, callback);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// Events we emit on $root
|
|
var EVENT_STATE = 'bv::collapse::state';
|
|
var EVENT_ACCORDION = 'bv::collapse::accordion';
|
|
// Events we listen to on $root
|
|
var EVENT_TOGGLE = 'bv::toggle::collapse';
|
|
|
|
var bCollapse = {
|
|
mixins: [listenOnRootMixin],
|
|
render: function render(h) {
|
|
var content = h(this.tag, {
|
|
class: this.classObject,
|
|
directives: [{ name: 'show', value: this.show }],
|
|
attrs: { id: this.id || null },
|
|
on: { click: this.clickHandler }
|
|
}, [this.$slots.default]);
|
|
return h('transition', {
|
|
props: {
|
|
enterClass: '',
|
|
enterActiveClass: 'collapsing',
|
|
enterToClass: '',
|
|
leaveClass: '',
|
|
leaveActiveClass: 'collapsing',
|
|
leaveToClass: ''
|
|
},
|
|
on: {
|
|
enter: this.onEnter,
|
|
afterEnter: this.onAfterEnter,
|
|
leave: this.onLeave,
|
|
afterLeave: this.onAfterLeave
|
|
}
|
|
}, [content]);
|
|
},
|
|
data: function data() {
|
|
return {
|
|
show: this.visible,
|
|
transitioning: false
|
|
};
|
|
},
|
|
|
|
model: {
|
|
prop: 'visible',
|
|
event: 'input'
|
|
},
|
|
props: {
|
|
id: {
|
|
type: String,
|
|
required: true
|
|
},
|
|
isNav: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
accordion: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
visible: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
tag: {
|
|
type: String,
|
|
default: 'div'
|
|
}
|
|
},
|
|
watch: {
|
|
visible: function visible(newVal) {
|
|
if (newVal !== this.show) {
|
|
this.show = newVal;
|
|
}
|
|
},
|
|
show: function show(newVal, oldVal) {
|
|
if (newVal !== oldVal) {
|
|
this.emitState();
|
|
}
|
|
}
|
|
},
|
|
computed: {
|
|
classObject: function classObject() {
|
|
return {
|
|
'navbar-collapse': this.isNav,
|
|
'collapse': !this.transitioning,
|
|
'show': this.show && !this.transitioning
|
|
};
|
|
}
|
|
},
|
|
methods: {
|
|
toggle: function toggle() {
|
|
this.show = !this.show;
|
|
},
|
|
onEnter: function onEnter(el) {
|
|
el.style.height = 0;
|
|
reflow(el);
|
|
el.style.height = el.scrollHeight + 'px';
|
|
this.transitioning = true;
|
|
// This should be moved out so we can add cancellable events
|
|
this.$emit('show');
|
|
},
|
|
onAfterEnter: function onAfterEnter(el) {
|
|
el.style.height = null;
|
|
this.transitioning = false;
|
|
this.$emit('shown');
|
|
},
|
|
onLeave: function onLeave(el) {
|
|
el.style.height = 'auto';
|
|
el.style.display = 'block';
|
|
el.style.height = el.getBoundingClientRect().height + 'px';
|
|
reflow(el);
|
|
this.transitioning = true;
|
|
el.style.height = 0;
|
|
// This should be moved out so we can add cancellable events
|
|
this.$emit('hide');
|
|
},
|
|
onAfterLeave: function onAfterLeave(el) {
|
|
el.style.height = null;
|
|
this.transitioning = false;
|
|
this.$emit('hidden');
|
|
},
|
|
emitState: function emitState() {
|
|
this.$emit('input', this.show);
|
|
// Let v-b-toggle know the state of this collapse
|
|
this.$root.$emit(EVENT_STATE, this.id, this.show);
|
|
if (this.accordion && this.show) {
|
|
// Tell the other collapses in this accordion to close
|
|
this.$root.$emit(EVENT_ACCORDION, this.id, this.accordion);
|
|
}
|
|
},
|
|
clickHandler: function clickHandler(evt) {
|
|
// If we are in a nav/navbar, close the collapse when non-disabled link clicked
|
|
var el = evt.target;
|
|
if (!this.isNav || !el || getComputedStyle(this.$el).display !== 'block') {
|
|
return;
|
|
}
|
|
if (hasClass(el, 'nav-link') || hasClass(el, 'dropdown-item')) {
|
|
this.show = false;
|
|
}
|
|
},
|
|
handleToggleEvt: function handleToggleEvt(target) {
|
|
if (target !== this.id) {
|
|
return;
|
|
}
|
|
this.toggle();
|
|
},
|
|
handleAccordionEvt: function handleAccordionEvt(openedId, accordion) {
|
|
if (!this.accordion || accordion !== this.accordion) {
|
|
return;
|
|
}
|
|
if (openedId === this.id) {
|
|
// Open this collapse if not shown
|
|
if (!this.show) {
|
|
this.toggle();
|
|
}
|
|
} else {
|
|
// Close this collapse if shown
|
|
if (this.show) {
|
|
this.toggle();
|
|
}
|
|
}
|
|
},
|
|
handleResize: function handleResize() {
|
|
// Handler for orientation/resize to set collapsed state in nav/navbar
|
|
this.show = getComputedStyle(this.$el).display === 'block';
|
|
}
|
|
},
|
|
created: function created() {
|
|
// Listen for toggle events to open/close us
|
|
this.listenOnRoot(EVENT_TOGGLE, this.handleToggleEvt);
|
|
// Listen to otehr collapses for accordion events
|
|
this.listenOnRoot(EVENT_ACCORDION, this.handleAccordionEvt);
|
|
},
|
|
mounted: function mounted() {
|
|
if (this.isNav && typeof document !== 'undefined') {
|
|
// Set up handlers
|
|
window.addEventListener('resize', this.handleResize, false);
|
|
window.addEventListener('orientationchange', this.handleResize, false);
|
|
this.handleResize();
|
|
}
|
|
this.emitState();
|
|
},
|
|
beforeDestroy: function beforeDestroy() {
|
|
if (this.isNav && typeof document !== 'undefined') {
|
|
window.removeEventListener('resize', this.handleResize, false);
|
|
window.removeEventListener('orientationchange', this.handleResize, false);
|
|
}
|
|
}
|
|
};
|
|
|
|
var allListenTypes = { hover: true, click: true, focus: true };
|
|
|
|
var BVBoundListeners = '__BV_boundEventListeners__';
|
|
|
|
var bindTargets = function bindTargets(vnode, binding, listenTypes, fn) {
|
|
var targets = keys(binding.modifiers || {}).filter(function (t) {
|
|
return !allListenTypes[t];
|
|
});
|
|
|
|
if (binding.value) {
|
|
targets.push(binding.value);
|
|
}
|
|
|
|
var listener = function listener() {
|
|
fn({ targets: targets, vnode: vnode });
|
|
};
|
|
|
|
keys(allListenTypes).forEach(function (type) {
|
|
if (listenTypes[type] || binding.modifiers[type]) {
|
|
vnode.elm.addEventListener(type, listener);
|
|
var boundListeners = vnode.elm[BVBoundListeners] || {};
|
|
boundListeners[type] = boundListeners[type] || [];
|
|
boundListeners[type].push(listener);
|
|
vnode.elm[BVBoundListeners] = boundListeners;
|
|
}
|
|
});
|
|
|
|
// Return the list of targets
|
|
return targets;
|
|
};
|
|
|
|
var unbindTargets = function unbindTargets(vnode, binding, listenTypes) {
|
|
keys(allListenTypes).forEach(function (type) {
|
|
if (listenTypes[type] || binding.modifiers[type]) {
|
|
var boundListeners = vnode.elm[BVBoundListeners] && vnode.elm[BVBoundListeners][type];
|
|
if (boundListeners) {
|
|
boundListeners.forEach(function (listener) {
|
|
return vnode.elm.removeEventListener(type, listener);
|
|
});
|
|
delete vnode.elm[BVBoundListeners][type];
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
// Are we client side?
|
|
var inBrowser = typeof window !== 'undefined';
|
|
|
|
// target listen types
|
|
var listenTypes = { click: true
|
|
|
|
// Property key for handler storage
|
|
};var BVT = '__BV_toggle__';
|
|
|
|
// Emitted Control Event for collapse (emitted to collapse)
|
|
var EVENT_TOGGLE$1 = 'bv::toggle::collapse';
|
|
|
|
// Listen to Event for toggle state update (Emited by collapse)
|
|
var EVENT_STATE$1 = 'bv::collapse::state';
|
|
|
|
var bToggle = {
|
|
bind: function bind(el, binding, vnode) {
|
|
var targets = bindTargets(vnode, binding, listenTypes, function (_ref) {
|
|
var targets = _ref.targets,
|
|
vnode = _ref.vnode;
|
|
|
|
targets.forEach(function (target) {
|
|
vnode.context.$root.$emit(EVENT_TOGGLE$1, target);
|
|
});
|
|
});
|
|
|
|
if (inBrowser && vnode.context && targets.length > 0) {
|
|
// Add aria attributes to element
|
|
setAttr(el, 'aria-controls', targets.join(' '));
|
|
setAttr(el, 'aria-expanded', 'false');
|
|
if (el.tagName !== 'BUTTON') {
|
|
// If element is not a button, we add `role="button"` for accessibility
|
|
setAttr(el, 'role', 'button');
|
|
}
|
|
|
|
// Toggle state hadnler, stored on element
|
|
el[BVT] = function toggleDirectiveHandler(id, state) {
|
|
if (targets.indexOf(id) !== -1) {
|
|
// Set aria-expanded state
|
|
setAttr(el, 'aria-expanded', state ? 'true' : 'false');
|
|
// Set/Clear 'collapsed' class state
|
|
if (state) {
|
|
removeClass(el, 'collapsed');
|
|
} else {
|
|
addClass(el, 'collapsed');
|
|
}
|
|
}
|
|
};
|
|
|
|
// Listen for toggle state changes
|
|
vnode.context.$root.$on(EVENT_STATE$1, el[BVT]);
|
|
}
|
|
},
|
|
unbind: function unbind(el, binding, vnode) {
|
|
if (el[BVT]) {
|
|
// Remove our $root listener
|
|
vnode.context.$root.$off(EVENT_STATE$1, el[BVT]);
|
|
el[BVT] = null;
|
|
}
|
|
}
|
|
};
|
|
|
|
var directives = {
|
|
bToggle: bToggle
|
|
};
|
|
|
|
var VuePlugin$a = {
|
|
install: function install(Vue) {
|
|
registerDirectives(Vue, directives);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$a);
|
|
|
|
var components$a = {
|
|
bCollapse: bCollapse
|
|
};
|
|
|
|
var VuePlugin$b = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$a);
|
|
Vue.use(VuePlugin$a);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$b);
|
|
|
|
/**!
|
|
* @fileOverview Kickass library to create and place poppers near their reference elements.
|
|
* @version 1.14.3
|
|
* @license
|
|
* Copyright (c) 2016 Federico Zivolo and contributors
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
var isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
|
|
var longerTimeoutBrowsers = ['Edge', 'Trident', 'Firefox'];
|
|
var timeoutDuration = 0;
|
|
for (var i = 0; i < longerTimeoutBrowsers.length; i += 1) {
|
|
if (isBrowser && navigator.userAgent.indexOf(longerTimeoutBrowsers[i]) >= 0) {
|
|
timeoutDuration = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
function microtaskDebounce(fn) {
|
|
var called = false;
|
|
return function () {
|
|
if (called) {
|
|
return;
|
|
}
|
|
called = true;
|
|
window.Promise.resolve().then(function () {
|
|
called = false;
|
|
fn();
|
|
});
|
|
};
|
|
}
|
|
|
|
function taskDebounce(fn) {
|
|
var scheduled = false;
|
|
return function () {
|
|
if (!scheduled) {
|
|
scheduled = true;
|
|
setTimeout(function () {
|
|
scheduled = false;
|
|
fn();
|
|
}, timeoutDuration);
|
|
}
|
|
};
|
|
}
|
|
|
|
var supportsMicroTasks = isBrowser && window.Promise;
|
|
|
|
/**
|
|
* Create a debounced version of a method, that's asynchronously deferred
|
|
* but called in the minimum time possible.
|
|
*
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @argument {Function} fn
|
|
* @returns {Function}
|
|
*/
|
|
var debounce = supportsMicroTasks ? microtaskDebounce : taskDebounce;
|
|
|
|
/**
|
|
* Check if the given variable is a function
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @argument {Any} functionToCheck - variable to check
|
|
* @returns {Boolean} answer to: is a function?
|
|
*/
|
|
function isFunction(functionToCheck) {
|
|
var getType = {};
|
|
return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
|
|
}
|
|
|
|
/**
|
|
* Get CSS computed property of the given element
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @argument {Eement} element
|
|
* @argument {String} property
|
|
*/
|
|
function getStyleComputedProperty(element, property) {
|
|
if (element.nodeType !== 1) {
|
|
return [];
|
|
}
|
|
// NOTE: 1 DOM access here
|
|
var css = getComputedStyle(element, null);
|
|
return property ? css[property] : css;
|
|
}
|
|
|
|
/**
|
|
* Returns the parentNode or the host of the element
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @argument {Element} element
|
|
* @returns {Element} parent
|
|
*/
|
|
function getParentNode(element) {
|
|
if (element.nodeName === 'HTML') {
|
|
return element;
|
|
}
|
|
return element.parentNode || element.host;
|
|
}
|
|
|
|
/**
|
|
* Returns the scrolling parent of the given element
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @argument {Element} element
|
|
* @returns {Element} scroll parent
|
|
*/
|
|
function getScrollParent(element) {
|
|
// Return body, `getScroll` will take care to get the correct `scrollTop` from it
|
|
if (!element) {
|
|
return document.body;
|
|
}
|
|
|
|
switch (element.nodeName) {
|
|
case 'HTML':
|
|
case 'BODY':
|
|
return element.ownerDocument.body;
|
|
case '#document':
|
|
return element.body;
|
|
}
|
|
|
|
// Firefox want us to check `-x` and `-y` variations as well
|
|
|
|
var _getStyleComputedProp = getStyleComputedProperty(element),
|
|
overflow = _getStyleComputedProp.overflow,
|
|
overflowX = _getStyleComputedProp.overflowX,
|
|
overflowY = _getStyleComputedProp.overflowY;
|
|
|
|
if (/(auto|scroll|overlay)/.test(overflow + overflowY + overflowX)) {
|
|
return element;
|
|
}
|
|
|
|
return getScrollParent(getParentNode(element));
|
|
}
|
|
|
|
var isIE11 = isBrowser && !!(window.MSInputMethodContext && document.documentMode);
|
|
var isIE10 = isBrowser && /MSIE 10/.test(navigator.userAgent);
|
|
|
|
/**
|
|
* Determines if the browser is Internet Explorer
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @param {Number} version to check
|
|
* @returns {Boolean} isIE
|
|
*/
|
|
function isIE(version) {
|
|
if (version === 11) {
|
|
return isIE11;
|
|
}
|
|
if (version === 10) {
|
|
return isIE10;
|
|
}
|
|
return isIE11 || isIE10;
|
|
}
|
|
|
|
/**
|
|
* Returns the offset parent of the given element
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @argument {Element} element
|
|
* @returns {Element} offset parent
|
|
*/
|
|
function getOffsetParent(element) {
|
|
if (!element) {
|
|
return document.documentElement;
|
|
}
|
|
|
|
var noOffsetParent = isIE(10) ? document.body : null;
|
|
|
|
// NOTE: 1 DOM access here
|
|
var offsetParent = element.offsetParent;
|
|
// Skip hidden elements which don't have an offsetParent
|
|
while (offsetParent === noOffsetParent && element.nextElementSibling) {
|
|
offsetParent = (element = element.nextElementSibling).offsetParent;
|
|
}
|
|
|
|
var nodeName = offsetParent && offsetParent.nodeName;
|
|
|
|
if (!nodeName || nodeName === 'BODY' || nodeName === 'HTML') {
|
|
return element ? element.ownerDocument.documentElement : document.documentElement;
|
|
}
|
|
|
|
// .offsetParent will return the closest TD or TABLE in case
|
|
// no offsetParent is present, I hate this job...
|
|
if (['TD', 'TABLE'].indexOf(offsetParent.nodeName) !== -1 && getStyleComputedProperty(offsetParent, 'position') === 'static') {
|
|
return getOffsetParent(offsetParent);
|
|
}
|
|
|
|
return offsetParent;
|
|
}
|
|
|
|
function isOffsetContainer(element) {
|
|
var nodeName = element.nodeName;
|
|
|
|
if (nodeName === 'BODY') {
|
|
return false;
|
|
}
|
|
return nodeName === 'HTML' || getOffsetParent(element.firstElementChild) === element;
|
|
}
|
|
|
|
/**
|
|
* Finds the root node (document, shadowDOM root) of the given element
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @argument {Element} node
|
|
* @returns {Element} root node
|
|
*/
|
|
function getRoot(node) {
|
|
if (node.parentNode !== null) {
|
|
return getRoot(node.parentNode);
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/**
|
|
* Finds the offset parent common to the two provided nodes
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @argument {Element} element1
|
|
* @argument {Element} element2
|
|
* @returns {Element} common offset parent
|
|
*/
|
|
function findCommonOffsetParent(element1, element2) {
|
|
// This check is needed to avoid errors in case one of the elements isn't defined for any reason
|
|
if (!element1 || !element1.nodeType || !element2 || !element2.nodeType) {
|
|
return document.documentElement;
|
|
}
|
|
|
|
// Here we make sure to give as "start" the element that comes first in the DOM
|
|
var order = element1.compareDocumentPosition(element2) & Node.DOCUMENT_POSITION_FOLLOWING;
|
|
var start = order ? element1 : element2;
|
|
var end = order ? element2 : element1;
|
|
|
|
// Get common ancestor container
|
|
var range = document.createRange();
|
|
range.setStart(start, 0);
|
|
range.setEnd(end, 0);
|
|
var commonAncestorContainer = range.commonAncestorContainer;
|
|
|
|
// Both nodes are inside #document
|
|
|
|
if (element1 !== commonAncestorContainer && element2 !== commonAncestorContainer || start.contains(end)) {
|
|
if (isOffsetContainer(commonAncestorContainer)) {
|
|
return commonAncestorContainer;
|
|
}
|
|
|
|
return getOffsetParent(commonAncestorContainer);
|
|
}
|
|
|
|
// one of the nodes is inside shadowDOM, find which one
|
|
var element1root = getRoot(element1);
|
|
if (element1root.host) {
|
|
return findCommonOffsetParent(element1root.host, element2);
|
|
} else {
|
|
return findCommonOffsetParent(element1, getRoot(element2).host);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the scroll value of the given element in the given side (top and left)
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @argument {Element} element
|
|
* @argument {String} side `top` or `left`
|
|
* @returns {number} amount of scrolled pixels
|
|
*/
|
|
function getScroll(element) {
|
|
var side = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'top';
|
|
|
|
var upperSide = side === 'top' ? 'scrollTop' : 'scrollLeft';
|
|
var nodeName = element.nodeName;
|
|
|
|
if (nodeName === 'BODY' || nodeName === 'HTML') {
|
|
var html = element.ownerDocument.documentElement;
|
|
var scrollingElement = element.ownerDocument.scrollingElement || html;
|
|
return scrollingElement[upperSide];
|
|
}
|
|
|
|
return element[upperSide];
|
|
}
|
|
|
|
/*
|
|
* Sum or subtract the element scroll values (left and top) from a given rect object
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @param {Object} rect - Rect object you want to change
|
|
* @param {HTMLElement} element - The element from the function reads the scroll values
|
|
* @param {Boolean} subtract - set to true if you want to subtract the scroll values
|
|
* @return {Object} rect - The modifier rect object
|
|
*/
|
|
function includeScroll(rect, element) {
|
|
var subtract = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
|
|
var scrollTop = getScroll(element, 'top');
|
|
var scrollLeft = getScroll(element, 'left');
|
|
var modifier = subtract ? -1 : 1;
|
|
rect.top += scrollTop * modifier;
|
|
rect.bottom += scrollTop * modifier;
|
|
rect.left += scrollLeft * modifier;
|
|
rect.right += scrollLeft * modifier;
|
|
return rect;
|
|
}
|
|
|
|
/*
|
|
* Helper to detect borders of a given element
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @param {CSSStyleDeclaration} styles
|
|
* Result of `getStyleComputedProperty` on the given element
|
|
* @param {String} axis - `x` or `y`
|
|
* @return {number} borders - The borders size of the given axis
|
|
*/
|
|
|
|
function getBordersSize(styles, axis) {
|
|
var sideA = axis === 'x' ? 'Left' : 'Top';
|
|
var sideB = sideA === 'Left' ? 'Right' : 'Bottom';
|
|
|
|
return parseFloat(styles['border' + sideA + 'Width'], 10) + parseFloat(styles['border' + sideB + 'Width'], 10);
|
|
}
|
|
|
|
function getSize(axis, body, html, computedStyle) {
|
|
return Math.max(body['offset' + axis], body['scroll' + axis], html['client' + axis], html['offset' + axis], html['scroll' + axis], isIE(10) ? html['offset' + axis] + computedStyle['margin' + (axis === 'Height' ? 'Top' : 'Left')] + computedStyle['margin' + (axis === 'Height' ? 'Bottom' : 'Right')] : 0);
|
|
}
|
|
|
|
function getWindowSizes() {
|
|
var body = document.body;
|
|
var html = document.documentElement;
|
|
var computedStyle = isIE(10) && getComputedStyle(html);
|
|
|
|
return {
|
|
height: getSize('Height', body, html, computedStyle),
|
|
width: getSize('Width', body, html, computedStyle)
|
|
};
|
|
}
|
|
|
|
var classCallCheck$1 = function classCallCheck(instance, Constructor) {
|
|
if (!(instance instanceof Constructor)) {
|
|
throw new TypeError("Cannot call a class as a function");
|
|
}
|
|
};
|
|
|
|
var createClass$1 = function () {
|
|
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);
|
|
}
|
|
}
|
|
|
|
return function (Constructor, protoProps, staticProps) {
|
|
if (protoProps) defineProperties(Constructor.prototype, protoProps);
|
|
if (staticProps) defineProperties(Constructor, staticProps);
|
|
return Constructor;
|
|
};
|
|
}();
|
|
|
|
var defineProperty$2 = 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;
|
|
};
|
|
|
|
var _extends$1 = 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;
|
|
};
|
|
|
|
/**
|
|
* Given element offsets, generate an output similar to getBoundingClientRect
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @argument {Object} offsets
|
|
* @returns {Object} ClientRect like output
|
|
*/
|
|
function getClientRect(offsets) {
|
|
return _extends$1({}, offsets, {
|
|
right: offsets.left + offsets.width,
|
|
bottom: offsets.top + offsets.height
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get bounding client rect of given element
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @param {HTMLElement} element
|
|
* @return {Object} client rect
|
|
*/
|
|
function getBoundingClientRect(element) {
|
|
var rect = {};
|
|
|
|
// IE10 10 FIX: Please, don't ask, the element isn't
|
|
// considered in DOM in some circumstances...
|
|
// This isn't reproducible in IE10 compatibility mode of IE11
|
|
try {
|
|
if (isIE(10)) {
|
|
rect = element.getBoundingClientRect();
|
|
var scrollTop = getScroll(element, 'top');
|
|
var scrollLeft = getScroll(element, 'left');
|
|
rect.top += scrollTop;
|
|
rect.left += scrollLeft;
|
|
rect.bottom += scrollTop;
|
|
rect.right += scrollLeft;
|
|
} else {
|
|
rect = element.getBoundingClientRect();
|
|
}
|
|
} catch (e) {}
|
|
|
|
var result = {
|
|
left: rect.left,
|
|
top: rect.top,
|
|
width: rect.right - rect.left,
|
|
height: rect.bottom - rect.top
|
|
};
|
|
|
|
// subtract scrollbar size from sizes
|
|
var sizes = element.nodeName === 'HTML' ? getWindowSizes() : {};
|
|
var width = sizes.width || element.clientWidth || result.right - result.left;
|
|
var height = sizes.height || element.clientHeight || result.bottom - result.top;
|
|
|
|
var horizScrollbar = element.offsetWidth - width;
|
|
var vertScrollbar = element.offsetHeight - height;
|
|
|
|
// if an hypothetical scrollbar is detected, we must be sure it's not a `border`
|
|
// we make this check conditional for performance reasons
|
|
if (horizScrollbar || vertScrollbar) {
|
|
var styles = getStyleComputedProperty(element);
|
|
horizScrollbar -= getBordersSize(styles, 'x');
|
|
vertScrollbar -= getBordersSize(styles, 'y');
|
|
|
|
result.width -= horizScrollbar;
|
|
result.height -= vertScrollbar;
|
|
}
|
|
|
|
return getClientRect(result);
|
|
}
|
|
|
|
function getOffsetRectRelativeToArbitraryNode(children, parent) {
|
|
var fixedPosition = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
|
|
var isIE10 = isIE(10);
|
|
var isHTML = parent.nodeName === 'HTML';
|
|
var childrenRect = getBoundingClientRect(children);
|
|
var parentRect = getBoundingClientRect(parent);
|
|
var scrollParent = getScrollParent(children);
|
|
|
|
var styles = getStyleComputedProperty(parent);
|
|
var borderTopWidth = parseFloat(styles.borderTopWidth, 10);
|
|
var borderLeftWidth = parseFloat(styles.borderLeftWidth, 10);
|
|
|
|
// In cases where the parent is fixed, we must ignore negative scroll in offset calc
|
|
if (fixedPosition && parent.nodeName === 'HTML') {
|
|
parentRect.top = Math.max(parentRect.top, 0);
|
|
parentRect.left = Math.max(parentRect.left, 0);
|
|
}
|
|
var offsets = getClientRect({
|
|
top: childrenRect.top - parentRect.top - borderTopWidth,
|
|
left: childrenRect.left - parentRect.left - borderLeftWidth,
|
|
width: childrenRect.width,
|
|
height: childrenRect.height
|
|
});
|
|
offsets.marginTop = 0;
|
|
offsets.marginLeft = 0;
|
|
|
|
// Subtract margins of documentElement in case it's being used as parent
|
|
// we do this only on HTML because it's the only element that behaves
|
|
// differently when margins are applied to it. The margins are included in
|
|
// the box of the documentElement, in the other cases not.
|
|
if (!isIE10 && isHTML) {
|
|
var marginTop = parseFloat(styles.marginTop, 10);
|
|
var marginLeft = parseFloat(styles.marginLeft, 10);
|
|
|
|
offsets.top -= borderTopWidth - marginTop;
|
|
offsets.bottom -= borderTopWidth - marginTop;
|
|
offsets.left -= borderLeftWidth - marginLeft;
|
|
offsets.right -= borderLeftWidth - marginLeft;
|
|
|
|
// Attach marginTop and marginLeft because in some circumstances we may need them
|
|
offsets.marginTop = marginTop;
|
|
offsets.marginLeft = marginLeft;
|
|
}
|
|
|
|
if (isIE10 && !fixedPosition ? parent.contains(scrollParent) : parent === scrollParent && scrollParent.nodeName !== 'BODY') {
|
|
offsets = includeScroll(offsets, parent);
|
|
}
|
|
|
|
return offsets;
|
|
}
|
|
|
|
function getViewportOffsetRectRelativeToArtbitraryNode(element) {
|
|
var excludeScroll = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
|
|
var html = element.ownerDocument.documentElement;
|
|
var relativeOffset = getOffsetRectRelativeToArbitraryNode(element, html);
|
|
var width = Math.max(html.clientWidth, window.innerWidth || 0);
|
|
var height = Math.max(html.clientHeight, window.innerHeight || 0);
|
|
|
|
var scrollTop = !excludeScroll ? getScroll(html) : 0;
|
|
var scrollLeft = !excludeScroll ? getScroll(html, 'left') : 0;
|
|
|
|
var offset = {
|
|
top: scrollTop - relativeOffset.top + relativeOffset.marginTop,
|
|
left: scrollLeft - relativeOffset.left + relativeOffset.marginLeft,
|
|
width: width,
|
|
height: height
|
|
};
|
|
|
|
return getClientRect(offset);
|
|
}
|
|
|
|
/**
|
|
* Check if the given element is fixed or is inside a fixed parent
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @argument {Element} element
|
|
* @argument {Element} customContainer
|
|
* @returns {Boolean} answer to "isFixed?"
|
|
*/
|
|
function isFixed(element) {
|
|
var nodeName = element.nodeName;
|
|
if (nodeName === 'BODY' || nodeName === 'HTML') {
|
|
return false;
|
|
}
|
|
if (getStyleComputedProperty(element, 'position') === 'fixed') {
|
|
return true;
|
|
}
|
|
return isFixed(getParentNode(element));
|
|
}
|
|
|
|
/**
|
|
* Finds the first parent of an element that has a transformed property defined
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @argument {Element} element
|
|
* @returns {Element} first transformed parent or documentElement
|
|
*/
|
|
|
|
function getFixedPositionOffsetParent(element) {
|
|
// This check is needed to avoid errors in case one of the elements isn't defined for any reason
|
|
if (!element || !element.parentElement || isIE()) {
|
|
return document.documentElement;
|
|
}
|
|
var el = element.parentElement;
|
|
while (el && getStyleComputedProperty(el, 'transform') === 'none') {
|
|
el = el.parentElement;
|
|
}
|
|
return el || document.documentElement;
|
|
}
|
|
|
|
/**
|
|
* Computed the boundaries limits and return them
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @param {HTMLElement} popper
|
|
* @param {HTMLElement} reference
|
|
* @param {number} padding
|
|
* @param {HTMLElement} boundariesElement - Element used to define the boundaries
|
|
* @param {Boolean} fixedPosition - Is in fixed position mode
|
|
* @returns {Object} Coordinates of the boundaries
|
|
*/
|
|
function getBoundaries(popper, reference, padding, boundariesElement) {
|
|
var fixedPosition = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
|
|
|
|
// NOTE: 1 DOM access here
|
|
|
|
var boundaries = { top: 0, left: 0 };
|
|
var offsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, reference);
|
|
|
|
// Handle viewport case
|
|
if (boundariesElement === 'viewport') {
|
|
boundaries = getViewportOffsetRectRelativeToArtbitraryNode(offsetParent, fixedPosition);
|
|
} else {
|
|
// Handle other cases based on DOM element used as boundaries
|
|
var boundariesNode = void 0;
|
|
if (boundariesElement === 'scrollParent') {
|
|
boundariesNode = getScrollParent(getParentNode(reference));
|
|
if (boundariesNode.nodeName === 'BODY') {
|
|
boundariesNode = popper.ownerDocument.documentElement;
|
|
}
|
|
} else if (boundariesElement === 'window') {
|
|
boundariesNode = popper.ownerDocument.documentElement;
|
|
} else {
|
|
boundariesNode = boundariesElement;
|
|
}
|
|
|
|
var offsets = getOffsetRectRelativeToArbitraryNode(boundariesNode, offsetParent, fixedPosition);
|
|
|
|
// In case of HTML, we need a different computation
|
|
if (boundariesNode.nodeName === 'HTML' && !isFixed(offsetParent)) {
|
|
var _getWindowSizes = getWindowSizes(),
|
|
height = _getWindowSizes.height,
|
|
width = _getWindowSizes.width;
|
|
|
|
boundaries.top += offsets.top - offsets.marginTop;
|
|
boundaries.bottom = height + offsets.top;
|
|
boundaries.left += offsets.left - offsets.marginLeft;
|
|
boundaries.right = width + offsets.left;
|
|
} else {
|
|
// for all the other DOM elements, this one is good
|
|
boundaries = offsets;
|
|
}
|
|
}
|
|
|
|
// Add paddings
|
|
boundaries.left += padding;
|
|
boundaries.top += padding;
|
|
boundaries.right -= padding;
|
|
boundaries.bottom -= padding;
|
|
|
|
return boundaries;
|
|
}
|
|
|
|
function getArea(_ref) {
|
|
var width = _ref.width,
|
|
height = _ref.height;
|
|
|
|
return width * height;
|
|
}
|
|
|
|
/**
|
|
* Utility used to transform the `auto` placement to the placement with more
|
|
* available space.
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @argument {Object} data - The data object generated by update method
|
|
* @argument {Object} options - Modifiers configuration and options
|
|
* @returns {Object} The data object, properly modified
|
|
*/
|
|
function computeAutoPlacement(placement, refRect, popper, reference, boundariesElement) {
|
|
var padding = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;
|
|
|
|
if (placement.indexOf('auto') === -1) {
|
|
return placement;
|
|
}
|
|
|
|
var boundaries = getBoundaries(popper, reference, padding, boundariesElement);
|
|
|
|
var rects = {
|
|
top: {
|
|
width: boundaries.width,
|
|
height: refRect.top - boundaries.top
|
|
},
|
|
right: {
|
|
width: boundaries.right - refRect.right,
|
|
height: boundaries.height
|
|
},
|
|
bottom: {
|
|
width: boundaries.width,
|
|
height: boundaries.bottom - refRect.bottom
|
|
},
|
|
left: {
|
|
width: refRect.left - boundaries.left,
|
|
height: boundaries.height
|
|
}
|
|
};
|
|
|
|
var sortedAreas = Object.keys(rects).map(function (key) {
|
|
return _extends$1({
|
|
key: key
|
|
}, rects[key], {
|
|
area: getArea(rects[key])
|
|
});
|
|
}).sort(function (a, b) {
|
|
return b.area - a.area;
|
|
});
|
|
|
|
var filteredAreas = sortedAreas.filter(function (_ref2) {
|
|
var width = _ref2.width,
|
|
height = _ref2.height;
|
|
return width >= popper.clientWidth && height >= popper.clientHeight;
|
|
});
|
|
|
|
var computedPlacement = filteredAreas.length > 0 ? filteredAreas[0].key : sortedAreas[0].key;
|
|
|
|
var variation = placement.split('-')[1];
|
|
|
|
return computedPlacement + (variation ? '-' + variation : '');
|
|
}
|
|
|
|
/**
|
|
* Get offsets to the reference element
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @param {Object} state
|
|
* @param {Element} popper - the popper element
|
|
* @param {Element} reference - the reference element (the popper will be relative to this)
|
|
* @param {Element} fixedPosition - is in fixed position mode
|
|
* @returns {Object} An object containing the offsets which will be applied to the popper
|
|
*/
|
|
function getReferenceOffsets(state, popper, reference) {
|
|
var fixedPosition = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
|
|
|
|
var commonOffsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, reference);
|
|
return getOffsetRectRelativeToArbitraryNode(reference, commonOffsetParent, fixedPosition);
|
|
}
|
|
|
|
/**
|
|
* Get the outer sizes of the given element (offset size + margins)
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @argument {Element} element
|
|
* @returns {Object} object containing width and height properties
|
|
*/
|
|
function getOuterSizes(element) {
|
|
var styles = getComputedStyle(element);
|
|
var x = parseFloat(styles.marginTop) + parseFloat(styles.marginBottom);
|
|
var y = parseFloat(styles.marginLeft) + parseFloat(styles.marginRight);
|
|
var result = {
|
|
width: element.offsetWidth + y,
|
|
height: element.offsetHeight + x
|
|
};
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Get the opposite placement of the given one
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @argument {String} placement
|
|
* @returns {String} flipped placement
|
|
*/
|
|
function getOppositePlacement(placement) {
|
|
var hash = { left: 'right', right: 'left', bottom: 'top', top: 'bottom' };
|
|
return placement.replace(/left|right|bottom|top/g, function (matched) {
|
|
return hash[matched];
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get offsets to the popper
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @param {Object} position - CSS position the Popper will get applied
|
|
* @param {HTMLElement} popper - the popper element
|
|
* @param {Object} referenceOffsets - the reference offsets (the popper will be relative to this)
|
|
* @param {String} placement - one of the valid placement options
|
|
* @returns {Object} popperOffsets - An object containing the offsets which will be applied to the popper
|
|
*/
|
|
function getPopperOffsets(popper, referenceOffsets, placement) {
|
|
placement = placement.split('-')[0];
|
|
|
|
// Get popper node sizes
|
|
var popperRect = getOuterSizes(popper);
|
|
|
|
// Add position, width and height to our offsets object
|
|
var popperOffsets = {
|
|
width: popperRect.width,
|
|
height: popperRect.height
|
|
};
|
|
|
|
// depending by the popper placement we have to compute its offsets slightly differently
|
|
var isHoriz = ['right', 'left'].indexOf(placement) !== -1;
|
|
var mainSide = isHoriz ? 'top' : 'left';
|
|
var secondarySide = isHoriz ? 'left' : 'top';
|
|
var measurement = isHoriz ? 'height' : 'width';
|
|
var secondaryMeasurement = !isHoriz ? 'height' : 'width';
|
|
|
|
popperOffsets[mainSide] = referenceOffsets[mainSide] + referenceOffsets[measurement] / 2 - popperRect[measurement] / 2;
|
|
if (placement === secondarySide) {
|
|
popperOffsets[secondarySide] = referenceOffsets[secondarySide] - popperRect[secondaryMeasurement];
|
|
} else {
|
|
popperOffsets[secondarySide] = referenceOffsets[getOppositePlacement(secondarySide)];
|
|
}
|
|
|
|
return popperOffsets;
|
|
}
|
|
|
|
/**
|
|
* Mimics the `find` method of Array
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @argument {Array} arr
|
|
* @argument prop
|
|
* @argument value
|
|
* @returns index or -1
|
|
*/
|
|
function find(arr, check) {
|
|
// use native find if supported
|
|
if (Array.prototype.find) {
|
|
return arr.find(check);
|
|
}
|
|
|
|
// use `filter` to obtain the same behavior of `find`
|
|
return arr.filter(check)[0];
|
|
}
|
|
|
|
/**
|
|
* Return the index of the matching object
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @argument {Array} arr
|
|
* @argument prop
|
|
* @argument value
|
|
* @returns index or -1
|
|
*/
|
|
function findIndex(arr, prop, value) {
|
|
// use native findIndex if supported
|
|
if (Array.prototype.findIndex) {
|
|
return arr.findIndex(function (cur) {
|
|
return cur[prop] === value;
|
|
});
|
|
}
|
|
|
|
// use `find` + `indexOf` if `findIndex` isn't supported
|
|
var match = find(arr, function (obj) {
|
|
return obj[prop] === value;
|
|
});
|
|
return arr.indexOf(match);
|
|
}
|
|
|
|
/**
|
|
* Loop trough the list of modifiers and run them in order,
|
|
* each of them will then edit the data object.
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @param {dataObject} data
|
|
* @param {Array} modifiers
|
|
* @param {String} ends - Optional modifier name used as stopper
|
|
* @returns {dataObject}
|
|
*/
|
|
function runModifiers(modifiers, data, ends) {
|
|
var modifiersToRun = ends === undefined ? modifiers : modifiers.slice(0, findIndex(modifiers, 'name', ends));
|
|
|
|
modifiersToRun.forEach(function (modifier) {
|
|
if (modifier['function']) {
|
|
// eslint-disable-line dot-notation
|
|
console.warn('`modifier.function` is deprecated, use `modifier.fn`!');
|
|
}
|
|
var fn = modifier['function'] || modifier.fn; // eslint-disable-line dot-notation
|
|
if (modifier.enabled && isFunction(fn)) {
|
|
// Add properties to offsets to make them a complete clientRect object
|
|
// we do this before each modifier to make sure the previous one doesn't
|
|
// mess with these values
|
|
data.offsets.popper = getClientRect(data.offsets.popper);
|
|
data.offsets.reference = getClientRect(data.offsets.reference);
|
|
|
|
data = fn(data, modifier);
|
|
}
|
|
});
|
|
|
|
return data;
|
|
}
|
|
|
|
/**
|
|
* Updates the position of the popper, computing the new offsets and applying
|
|
* the new style.<br />
|
|
* Prefer `scheduleUpdate` over `update` because of performance reasons.
|
|
* @method
|
|
* @memberof Popper
|
|
*/
|
|
function update() {
|
|
// if popper is destroyed, don't perform any further update
|
|
if (this.state.isDestroyed) {
|
|
return;
|
|
}
|
|
|
|
var data = {
|
|
instance: this,
|
|
styles: {},
|
|
arrowStyles: {},
|
|
attributes: {},
|
|
flipped: false,
|
|
offsets: {}
|
|
};
|
|
|
|
// compute reference element offsets
|
|
data.offsets.reference = getReferenceOffsets(this.state, this.popper, this.reference, this.options.positionFixed);
|
|
|
|
// compute auto placement, store placement inside the data object,
|
|
// modifiers will be able to edit `placement` if needed
|
|
// and refer to originalPlacement to know the original value
|
|
data.placement = computeAutoPlacement(this.options.placement, data.offsets.reference, this.popper, this.reference, this.options.modifiers.flip.boundariesElement, this.options.modifiers.flip.padding);
|
|
|
|
// store the computed placement inside `originalPlacement`
|
|
data.originalPlacement = data.placement;
|
|
|
|
data.positionFixed = this.options.positionFixed;
|
|
|
|
// compute the popper offsets
|
|
data.offsets.popper = getPopperOffsets(this.popper, data.offsets.reference, data.placement);
|
|
|
|
data.offsets.popper.position = this.options.positionFixed ? 'fixed' : 'absolute';
|
|
|
|
// run the modifiers
|
|
data = runModifiers(this.modifiers, data);
|
|
|
|
// the first `update` will call `onCreate` callback
|
|
// the other ones will call `onUpdate` callback
|
|
if (!this.state.isCreated) {
|
|
this.state.isCreated = true;
|
|
this.options.onCreate(data);
|
|
} else {
|
|
this.options.onUpdate(data);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper used to know if the given modifier is enabled.
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @returns {Boolean}
|
|
*/
|
|
function isModifierEnabled(modifiers, modifierName) {
|
|
return modifiers.some(function (_ref) {
|
|
var name = _ref.name,
|
|
enabled = _ref.enabled;
|
|
return enabled && name === modifierName;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get the prefixed supported property name
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @argument {String} property (camelCase)
|
|
* @returns {String} prefixed property (camelCase or PascalCase, depending on the vendor prefix)
|
|
*/
|
|
function getSupportedPropertyName(property) {
|
|
var prefixes = [false, 'ms', 'Webkit', 'Moz', 'O'];
|
|
var upperProp = property.charAt(0).toUpperCase() + property.slice(1);
|
|
|
|
for (var i = 0; i < prefixes.length; i++) {
|
|
var prefix = prefixes[i];
|
|
var toCheck = prefix ? '' + prefix + upperProp : property;
|
|
if (typeof document.body.style[toCheck] !== 'undefined') {
|
|
return toCheck;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Destroy the popper
|
|
* @method
|
|
* @memberof Popper
|
|
*/
|
|
function destroy() {
|
|
this.state.isDestroyed = true;
|
|
|
|
// touch DOM only if `applyStyle` modifier is enabled
|
|
if (isModifierEnabled(this.modifiers, 'applyStyle')) {
|
|
this.popper.removeAttribute('x-placement');
|
|
this.popper.style.position = '';
|
|
this.popper.style.top = '';
|
|
this.popper.style.left = '';
|
|
this.popper.style.right = '';
|
|
this.popper.style.bottom = '';
|
|
this.popper.style.willChange = '';
|
|
this.popper.style[getSupportedPropertyName('transform')] = '';
|
|
}
|
|
|
|
this.disableEventListeners();
|
|
|
|
// remove the popper if user explicity asked for the deletion on destroy
|
|
// do not use `remove` because IE11 doesn't support it
|
|
if (this.options.removeOnDestroy) {
|
|
this.popper.parentNode.removeChild(this.popper);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Get the window associated with the element
|
|
* @argument {Element} element
|
|
* @returns {Window}
|
|
*/
|
|
function getWindow(element) {
|
|
var ownerDocument = element.ownerDocument;
|
|
return ownerDocument ? ownerDocument.defaultView : window;
|
|
}
|
|
|
|
function attachToScrollParents(scrollParent, event, callback, scrollParents) {
|
|
var isBody = scrollParent.nodeName === 'BODY';
|
|
var target = isBody ? scrollParent.ownerDocument.defaultView : scrollParent;
|
|
target.addEventListener(event, callback, { passive: true });
|
|
|
|
if (!isBody) {
|
|
attachToScrollParents(getScrollParent(target.parentNode), event, callback, scrollParents);
|
|
}
|
|
scrollParents.push(target);
|
|
}
|
|
|
|
/**
|
|
* Setup needed event listeners used to update the popper position
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @private
|
|
*/
|
|
function setupEventListeners(reference, options, state, updateBound) {
|
|
// Resize event listener on window
|
|
state.updateBound = updateBound;
|
|
getWindow(reference).addEventListener('resize', state.updateBound, { passive: true });
|
|
|
|
// Scroll event listener on scroll parents
|
|
var scrollElement = getScrollParent(reference);
|
|
attachToScrollParents(scrollElement, 'scroll', state.updateBound, state.scrollParents);
|
|
state.scrollElement = scrollElement;
|
|
state.eventsEnabled = true;
|
|
|
|
return state;
|
|
}
|
|
|
|
/**
|
|
* It will add resize/scroll events and start recalculating
|
|
* position of the popper element when they are triggered.
|
|
* @method
|
|
* @memberof Popper
|
|
*/
|
|
function enableEventListeners() {
|
|
if (!this.state.eventsEnabled) {
|
|
this.state = setupEventListeners(this.reference, this.options, this.state, this.scheduleUpdate);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove event listeners used to update the popper position
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @private
|
|
*/
|
|
function removeEventListeners(reference, state) {
|
|
// Remove resize event listener on window
|
|
getWindow(reference).removeEventListener('resize', state.updateBound);
|
|
|
|
// Remove scroll event listener on scroll parents
|
|
state.scrollParents.forEach(function (target) {
|
|
target.removeEventListener('scroll', state.updateBound);
|
|
});
|
|
|
|
// Reset state
|
|
state.updateBound = null;
|
|
state.scrollParents = [];
|
|
state.scrollElement = null;
|
|
state.eventsEnabled = false;
|
|
return state;
|
|
}
|
|
|
|
/**
|
|
* It will remove resize/scroll events and won't recalculate popper position
|
|
* when they are triggered. It also won't trigger onUpdate callback anymore,
|
|
* unless you call `update` method manually.
|
|
* @method
|
|
* @memberof Popper
|
|
*/
|
|
function disableEventListeners() {
|
|
if (this.state.eventsEnabled) {
|
|
cancelAnimationFrame(this.scheduleUpdate);
|
|
this.state = removeEventListeners(this.reference, this.state);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Tells if a given input is a number
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @param {*} input to check
|
|
* @return {Boolean}
|
|
*/
|
|
function isNumeric(n) {
|
|
return n !== '' && !isNaN(parseFloat(n)) && isFinite(n);
|
|
}
|
|
|
|
/**
|
|
* Set the style to the given popper
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @argument {Element} element - Element to apply the style to
|
|
* @argument {Object} styles
|
|
* Object with a list of properties and values which will be applied to the element
|
|
*/
|
|
function setStyles(element, styles) {
|
|
Object.keys(styles).forEach(function (prop) {
|
|
var unit = '';
|
|
// add unit if the value is numeric and is one of the following
|
|
if (['width', 'height', 'top', 'right', 'bottom', 'left'].indexOf(prop) !== -1 && isNumeric(styles[prop])) {
|
|
unit = 'px';
|
|
}
|
|
element.style[prop] = styles[prop] + unit;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Set the attributes to the given popper
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @argument {Element} element - Element to apply the attributes to
|
|
* @argument {Object} styles
|
|
* Object with a list of properties and values which will be applied to the element
|
|
*/
|
|
function setAttributes(element, attributes) {
|
|
Object.keys(attributes).forEach(function (prop) {
|
|
var value = attributes[prop];
|
|
if (value !== false) {
|
|
element.setAttribute(prop, attributes[prop]);
|
|
} else {
|
|
element.removeAttribute(prop);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @function
|
|
* @memberof Modifiers
|
|
* @argument {Object} data - The data object generated by `update` method
|
|
* @argument {Object} data.styles - List of style properties - values to apply to popper element
|
|
* @argument {Object} data.attributes - List of attribute properties - values to apply to popper element
|
|
* @argument {Object} options - Modifiers configuration and options
|
|
* @returns {Object} The same data object
|
|
*/
|
|
function applyStyle(data) {
|
|
// any property present in `data.styles` will be applied to the popper,
|
|
// in this way we can make the 3rd party modifiers add custom styles to it
|
|
// Be aware, modifiers could override the properties defined in the previous
|
|
// lines of this modifier!
|
|
setStyles(data.instance.popper, data.styles);
|
|
|
|
// any property present in `data.attributes` will be applied to the popper,
|
|
// they will be set as HTML attributes of the element
|
|
setAttributes(data.instance.popper, data.attributes);
|
|
|
|
// if arrowElement is defined and arrowStyles has some properties
|
|
if (data.arrowElement && Object.keys(data.arrowStyles).length) {
|
|
setStyles(data.arrowElement, data.arrowStyles);
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
/**
|
|
* Set the x-placement attribute before everything else because it could be used
|
|
* to add margins to the popper margins needs to be calculated to get the
|
|
* correct popper offsets.
|
|
* @method
|
|
* @memberof Popper.modifiers
|
|
* @param {HTMLElement} reference - The reference element used to position the popper
|
|
* @param {HTMLElement} popper - The HTML element used as popper
|
|
* @param {Object} options - Popper.js options
|
|
*/
|
|
function applyStyleOnLoad(reference, popper, options, modifierOptions, state) {
|
|
// compute reference element offsets
|
|
var referenceOffsets = getReferenceOffsets(state, popper, reference, options.positionFixed);
|
|
|
|
// compute auto placement, store placement inside the data object,
|
|
// modifiers will be able to edit `placement` if needed
|
|
// and refer to originalPlacement to know the original value
|
|
var placement = computeAutoPlacement(options.placement, referenceOffsets, popper, reference, options.modifiers.flip.boundariesElement, options.modifiers.flip.padding);
|
|
|
|
popper.setAttribute('x-placement', placement);
|
|
|
|
// Apply `position` to popper before anything else because
|
|
// without the position applied we can't guarantee correct computations
|
|
setStyles(popper, { position: options.positionFixed ? 'fixed' : 'absolute' });
|
|
|
|
return options;
|
|
}
|
|
|
|
/**
|
|
* @function
|
|
* @memberof Modifiers
|
|
* @argument {Object} data - The data object generated by `update` method
|
|
* @argument {Object} options - Modifiers configuration and options
|
|
* @returns {Object} The data object, properly modified
|
|
*/
|
|
function computeStyle(data, options) {
|
|
var x = options.x,
|
|
y = options.y;
|
|
var popper = data.offsets.popper;
|
|
|
|
// Remove this legacy support in Popper.js v2
|
|
|
|
var legacyGpuAccelerationOption = find(data.instance.modifiers, function (modifier) {
|
|
return modifier.name === 'applyStyle';
|
|
}).gpuAcceleration;
|
|
if (legacyGpuAccelerationOption !== undefined) {
|
|
console.warn('WARNING: `gpuAcceleration` option moved to `computeStyle` modifier and will not be supported in future versions of Popper.js!');
|
|
}
|
|
var gpuAcceleration = legacyGpuAccelerationOption !== undefined ? legacyGpuAccelerationOption : options.gpuAcceleration;
|
|
|
|
var offsetParent = getOffsetParent(data.instance.popper);
|
|
var offsetParentRect = getBoundingClientRect(offsetParent);
|
|
|
|
// Styles
|
|
var styles = {
|
|
position: popper.position
|
|
};
|
|
|
|
// Avoid blurry text by using full pixel integers.
|
|
// For pixel-perfect positioning, top/bottom prefers rounded
|
|
// values, while left/right prefers floored values.
|
|
var offsets = {
|
|
left: Math.floor(popper.left),
|
|
top: Math.round(popper.top),
|
|
bottom: Math.round(popper.bottom),
|
|
right: Math.floor(popper.right)
|
|
};
|
|
|
|
var sideA = x === 'bottom' ? 'top' : 'bottom';
|
|
var sideB = y === 'right' ? 'left' : 'right';
|
|
|
|
// if gpuAcceleration is set to `true` and transform is supported,
|
|
// we use `translate3d` to apply the position to the popper we
|
|
// automatically use the supported prefixed version if needed
|
|
var prefixedProperty = getSupportedPropertyName('transform');
|
|
|
|
// now, let's make a step back and look at this code closely (wtf?)
|
|
// If the content of the popper grows once it's been positioned, it
|
|
// may happen that the popper gets misplaced because of the new content
|
|
// overflowing its reference element
|
|
// To avoid this problem, we provide two options (x and y), which allow
|
|
// the consumer to define the offset origin.
|
|
// If we position a popper on top of a reference element, we can set
|
|
// `x` to `top` to make the popper grow towards its top instead of
|
|
// its bottom.
|
|
var left = void 0,
|
|
top = void 0;
|
|
if (sideA === 'bottom') {
|
|
top = -offsetParentRect.height + offsets.bottom;
|
|
} else {
|
|
top = offsets.top;
|
|
}
|
|
if (sideB === 'right') {
|
|
left = -offsetParentRect.width + offsets.right;
|
|
} else {
|
|
left = offsets.left;
|
|
}
|
|
if (gpuAcceleration && prefixedProperty) {
|
|
styles[prefixedProperty] = 'translate3d(' + left + 'px, ' + top + 'px, 0)';
|
|
styles[sideA] = 0;
|
|
styles[sideB] = 0;
|
|
styles.willChange = 'transform';
|
|
} else {
|
|
// othwerise, we use the standard `top`, `left`, `bottom` and `right` properties
|
|
var invertTop = sideA === 'bottom' ? -1 : 1;
|
|
var invertLeft = sideB === 'right' ? -1 : 1;
|
|
styles[sideA] = top * invertTop;
|
|
styles[sideB] = left * invertLeft;
|
|
styles.willChange = sideA + ', ' + sideB;
|
|
}
|
|
|
|
// Attributes
|
|
var attributes = {
|
|
'x-placement': data.placement
|
|
};
|
|
|
|
// Update `data` attributes, styles and arrowStyles
|
|
data.attributes = _extends$1({}, attributes, data.attributes);
|
|
data.styles = _extends$1({}, styles, data.styles);
|
|
data.arrowStyles = _extends$1({}, data.offsets.arrow, data.arrowStyles);
|
|
|
|
return data;
|
|
}
|
|
|
|
/**
|
|
* Helper used to know if the given modifier depends from another one.<br />
|
|
* It checks if the needed modifier is listed and enabled.
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @param {Array} modifiers - list of modifiers
|
|
* @param {String} requestingName - name of requesting modifier
|
|
* @param {String} requestedName - name of requested modifier
|
|
* @returns {Boolean}
|
|
*/
|
|
function isModifierRequired(modifiers, requestingName, requestedName) {
|
|
var requesting = find(modifiers, function (_ref) {
|
|
var name = _ref.name;
|
|
return name === requestingName;
|
|
});
|
|
|
|
var isRequired = !!requesting && modifiers.some(function (modifier) {
|
|
return modifier.name === requestedName && modifier.enabled && modifier.order < requesting.order;
|
|
});
|
|
|
|
if (!isRequired) {
|
|
var _requesting = '`' + requestingName + '`';
|
|
var requested = '`' + requestedName + '`';
|
|
console.warn(requested + ' modifier is required by ' + _requesting + ' modifier in order to work, be sure to include it before ' + _requesting + '!');
|
|
}
|
|
return isRequired;
|
|
}
|
|
|
|
/**
|
|
* @function
|
|
* @memberof Modifiers
|
|
* @argument {Object} data - The data object generated by update method
|
|
* @argument {Object} options - Modifiers configuration and options
|
|
* @returns {Object} The data object, properly modified
|
|
*/
|
|
function arrow(data, options) {
|
|
var _data$offsets$arrow;
|
|
|
|
// arrow depends on keepTogether in order to work
|
|
if (!isModifierRequired(data.instance.modifiers, 'arrow', 'keepTogether')) {
|
|
return data;
|
|
}
|
|
|
|
var arrowElement = options.element;
|
|
|
|
// if arrowElement is a string, suppose it's a CSS selector
|
|
if (typeof arrowElement === 'string') {
|
|
arrowElement = data.instance.popper.querySelector(arrowElement);
|
|
|
|
// if arrowElement is not found, don't run the modifier
|
|
if (!arrowElement) {
|
|
return data;
|
|
}
|
|
} else {
|
|
// if the arrowElement isn't a query selector we must check that the
|
|
// provided DOM node is child of its popper node
|
|
if (!data.instance.popper.contains(arrowElement)) {
|
|
console.warn('WARNING: `arrow.element` must be child of its popper element!');
|
|
return data;
|
|
}
|
|
}
|
|
|
|
var placement = data.placement.split('-')[0];
|
|
var _data$offsets = data.offsets,
|
|
popper = _data$offsets.popper,
|
|
reference = _data$offsets.reference;
|
|
|
|
var isVertical = ['left', 'right'].indexOf(placement) !== -1;
|
|
|
|
var len = isVertical ? 'height' : 'width';
|
|
var sideCapitalized = isVertical ? 'Top' : 'Left';
|
|
var side = sideCapitalized.toLowerCase();
|
|
var altSide = isVertical ? 'left' : 'top';
|
|
var opSide = isVertical ? 'bottom' : 'right';
|
|
var arrowElementSize = getOuterSizes(arrowElement)[len];
|
|
|
|
//
|
|
// extends keepTogether behavior making sure the popper and its
|
|
// reference have enough pixels in conjuction
|
|
//
|
|
|
|
// top/left side
|
|
if (reference[opSide] - arrowElementSize < popper[side]) {
|
|
data.offsets.popper[side] -= popper[side] - (reference[opSide] - arrowElementSize);
|
|
}
|
|
// bottom/right side
|
|
if (reference[side] + arrowElementSize > popper[opSide]) {
|
|
data.offsets.popper[side] += reference[side] + arrowElementSize - popper[opSide];
|
|
}
|
|
data.offsets.popper = getClientRect(data.offsets.popper);
|
|
|
|
// compute center of the popper
|
|
var center = reference[side] + reference[len] / 2 - arrowElementSize / 2;
|
|
|
|
// Compute the sideValue using the updated popper offsets
|
|
// take popper margin in account because we don't have this info available
|
|
var css = getStyleComputedProperty(data.instance.popper);
|
|
var popperMarginSide = parseFloat(css['margin' + sideCapitalized], 10);
|
|
var popperBorderSide = parseFloat(css['border' + sideCapitalized + 'Width'], 10);
|
|
var sideValue = center - data.offsets.popper[side] - popperMarginSide - popperBorderSide;
|
|
|
|
// prevent arrowElement from being placed not contiguously to its popper
|
|
sideValue = Math.max(Math.min(popper[len] - arrowElementSize, sideValue), 0);
|
|
|
|
data.arrowElement = arrowElement;
|
|
data.offsets.arrow = (_data$offsets$arrow = {}, defineProperty$2(_data$offsets$arrow, side, Math.round(sideValue)), defineProperty$2(_data$offsets$arrow, altSide, ''), _data$offsets$arrow);
|
|
|
|
return data;
|
|
}
|
|
|
|
/**
|
|
* Get the opposite placement variation of the given one
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @argument {String} placement variation
|
|
* @returns {String} flipped placement variation
|
|
*/
|
|
function getOppositeVariation(variation) {
|
|
if (variation === 'end') {
|
|
return 'start';
|
|
} else if (variation === 'start') {
|
|
return 'end';
|
|
}
|
|
return variation;
|
|
}
|
|
|
|
/**
|
|
* List of accepted placements to use as values of the `placement` option.<br />
|
|
* Valid placements are:
|
|
* - `auto`
|
|
* - `top`
|
|
* - `right`
|
|
* - `bottom`
|
|
* - `left`
|
|
*
|
|
* Each placement can have a variation from this list:
|
|
* - `-start`
|
|
* - `-end`
|
|
*
|
|
* Variations are interpreted easily if you think of them as the left to right
|
|
* written languages. Horizontally (`top` and `bottom`), `start` is left and `end`
|
|
* is right.<br />
|
|
* Vertically (`left` and `right`), `start` is top and `end` is bottom.
|
|
*
|
|
* Some valid examples are:
|
|
* - `top-end` (on top of reference, right aligned)
|
|
* - `right-start` (on right of reference, top aligned)
|
|
* - `bottom` (on bottom, centered)
|
|
* - `auto-right` (on the side with more space available, alignment depends by placement)
|
|
*
|
|
* @static
|
|
* @type {Array}
|
|
* @enum {String}
|
|
* @readonly
|
|
* @method placements
|
|
* @memberof Popper
|
|
*/
|
|
var placements = ['auto-start', 'auto', 'auto-end', 'top-start', 'top', 'top-end', 'right-start', 'right', 'right-end', 'bottom-end', 'bottom', 'bottom-start', 'left-end', 'left', 'left-start'];
|
|
|
|
// Get rid of `auto` `auto-start` and `auto-end`
|
|
var validPlacements = placements.slice(3);
|
|
|
|
/**
|
|
* Given an initial placement, returns all the subsequent placements
|
|
* clockwise (or counter-clockwise).
|
|
*
|
|
* @method
|
|
* @memberof Popper.Utils
|
|
* @argument {String} placement - A valid placement (it accepts variations)
|
|
* @argument {Boolean} counter - Set to true to walk the placements counterclockwise
|
|
* @returns {Array} placements including their variations
|
|
*/
|
|
function clockwise(placement) {
|
|
var counter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
|
|
var index = validPlacements.indexOf(placement);
|
|
var arr = validPlacements.slice(index + 1).concat(validPlacements.slice(0, index));
|
|
return counter ? arr.reverse() : arr;
|
|
}
|
|
|
|
var BEHAVIORS = {
|
|
FLIP: 'flip',
|
|
CLOCKWISE: 'clockwise',
|
|
COUNTERCLOCKWISE: 'counterclockwise'
|
|
};
|
|
|
|
/**
|
|
* @function
|
|
* @memberof Modifiers
|
|
* @argument {Object} data - The data object generated by update method
|
|
* @argument {Object} options - Modifiers configuration and options
|
|
* @returns {Object} The data object, properly modified
|
|
*/
|
|
function flip(data, options) {
|
|
// if `inner` modifier is enabled, we can't use the `flip` modifier
|
|
if (isModifierEnabled(data.instance.modifiers, 'inner')) {
|
|
return data;
|
|
}
|
|
|
|
if (data.flipped && data.placement === data.originalPlacement) {
|
|
// seems like flip is trying to loop, probably there's not enough space on any of the flippable sides
|
|
return data;
|
|
}
|
|
|
|
var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, options.boundariesElement, data.positionFixed);
|
|
|
|
var placement = data.placement.split('-')[0];
|
|
var placementOpposite = getOppositePlacement(placement);
|
|
var variation = data.placement.split('-')[1] || '';
|
|
|
|
var flipOrder = [];
|
|
|
|
switch (options.behavior) {
|
|
case BEHAVIORS.FLIP:
|
|
flipOrder = [placement, placementOpposite];
|
|
break;
|
|
case BEHAVIORS.CLOCKWISE:
|
|
flipOrder = clockwise(placement);
|
|
break;
|
|
case BEHAVIORS.COUNTERCLOCKWISE:
|
|
flipOrder = clockwise(placement, true);
|
|
break;
|
|
default:
|
|
flipOrder = options.behavior;
|
|
}
|
|
|
|
flipOrder.forEach(function (step, index) {
|
|
if (placement !== step || flipOrder.length === index + 1) {
|
|
return data;
|
|
}
|
|
|
|
placement = data.placement.split('-')[0];
|
|
placementOpposite = getOppositePlacement(placement);
|
|
|
|
var popperOffsets = data.offsets.popper;
|
|
var refOffsets = data.offsets.reference;
|
|
|
|
// using floor because the reference offsets may contain decimals we are not going to consider here
|
|
var floor = Math.floor;
|
|
var overlapsRef = placement === 'left' && floor(popperOffsets.right) > floor(refOffsets.left) || placement === 'right' && floor(popperOffsets.left) < floor(refOffsets.right) || placement === 'top' && floor(popperOffsets.bottom) > floor(refOffsets.top) || placement === 'bottom' && floor(popperOffsets.top) < floor(refOffsets.bottom);
|
|
|
|
var overflowsLeft = floor(popperOffsets.left) < floor(boundaries.left);
|
|
var overflowsRight = floor(popperOffsets.right) > floor(boundaries.right);
|
|
var overflowsTop = floor(popperOffsets.top) < floor(boundaries.top);
|
|
var overflowsBottom = floor(popperOffsets.bottom) > floor(boundaries.bottom);
|
|
|
|
var overflowsBoundaries = placement === 'left' && overflowsLeft || placement === 'right' && overflowsRight || placement === 'top' && overflowsTop || placement === 'bottom' && overflowsBottom;
|
|
|
|
// flip the variation if required
|
|
var isVertical = ['top', 'bottom'].indexOf(placement) !== -1;
|
|
var flippedVariation = !!options.flipVariations && (isVertical && variation === 'start' && overflowsLeft || isVertical && variation === 'end' && overflowsRight || !isVertical && variation === 'start' && overflowsTop || !isVertical && variation === 'end' && overflowsBottom);
|
|
|
|
if (overlapsRef || overflowsBoundaries || flippedVariation) {
|
|
// this boolean to detect any flip loop
|
|
data.flipped = true;
|
|
|
|
if (overlapsRef || overflowsBoundaries) {
|
|
placement = flipOrder[index + 1];
|
|
}
|
|
|
|
if (flippedVariation) {
|
|
variation = getOppositeVariation(variation);
|
|
}
|
|
|
|
data.placement = placement + (variation ? '-' + variation : '');
|
|
|
|
// this object contains `position`, we want to preserve it along with
|
|
// any additional property we may add in the future
|
|
data.offsets.popper = _extends$1({}, data.offsets.popper, getPopperOffsets(data.instance.popper, data.offsets.reference, data.placement));
|
|
|
|
data = runModifiers(data.instance.modifiers, data, 'flip');
|
|
}
|
|
});
|
|
return data;
|
|
}
|
|
|
|
/**
|
|
* @function
|
|
* @memberof Modifiers
|
|
* @argument {Object} data - The data object generated by update method
|
|
* @argument {Object} options - Modifiers configuration and options
|
|
* @returns {Object} The data object, properly modified
|
|
*/
|
|
function keepTogether(data) {
|
|
var _data$offsets = data.offsets,
|
|
popper = _data$offsets.popper,
|
|
reference = _data$offsets.reference;
|
|
|
|
var placement = data.placement.split('-')[0];
|
|
var floor = Math.floor;
|
|
var isVertical = ['top', 'bottom'].indexOf(placement) !== -1;
|
|
var side = isVertical ? 'right' : 'bottom';
|
|
var opSide = isVertical ? 'left' : 'top';
|
|
var measurement = isVertical ? 'width' : 'height';
|
|
|
|
if (popper[side] < floor(reference[opSide])) {
|
|
data.offsets.popper[opSide] = floor(reference[opSide]) - popper[measurement];
|
|
}
|
|
if (popper[opSide] > floor(reference[side])) {
|
|
data.offsets.popper[opSide] = floor(reference[side]);
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
/**
|
|
* Converts a string containing value + unit into a px value number
|
|
* @function
|
|
* @memberof {modifiers~offset}
|
|
* @private
|
|
* @argument {String} str - Value + unit string
|
|
* @argument {String} measurement - `height` or `width`
|
|
* @argument {Object} popperOffsets
|
|
* @argument {Object} referenceOffsets
|
|
* @returns {Number|String}
|
|
* Value in pixels, or original string if no values were extracted
|
|
*/
|
|
function toValue(str, measurement, popperOffsets, referenceOffsets) {
|
|
// separate value from unit
|
|
var split = str.match(/((?:\-|\+)?\d*\.?\d*)(.*)/);
|
|
var value = +split[1];
|
|
var unit = split[2];
|
|
|
|
// If it's not a number it's an operator, I guess
|
|
if (!value) {
|
|
return str;
|
|
}
|
|
|
|
if (unit.indexOf('%') === 0) {
|
|
var element = void 0;
|
|
switch (unit) {
|
|
case '%p':
|
|
element = popperOffsets;
|
|
break;
|
|
case '%':
|
|
case '%r':
|
|
default:
|
|
element = referenceOffsets;
|
|
}
|
|
|
|
var rect = getClientRect(element);
|
|
return rect[measurement] / 100 * value;
|
|
} else if (unit === 'vh' || unit === 'vw') {
|
|
// if is a vh or vw, we calculate the size based on the viewport
|
|
var size = void 0;
|
|
if (unit === 'vh') {
|
|
size = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
|
|
} else {
|
|
size = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
|
|
}
|
|
return size / 100 * value;
|
|
} else {
|
|
// if is an explicit pixel unit, we get rid of the unit and keep the value
|
|
// if is an implicit unit, it's px, and we return just the value
|
|
return value;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parse an `offset` string to extrapolate `x` and `y` numeric offsets.
|
|
* @function
|
|
* @memberof {modifiers~offset}
|
|
* @private
|
|
* @argument {String} offset
|
|
* @argument {Object} popperOffsets
|
|
* @argument {Object} referenceOffsets
|
|
* @argument {String} basePlacement
|
|
* @returns {Array} a two cells array with x and y offsets in numbers
|
|
*/
|
|
function parseOffset(offset, popperOffsets, referenceOffsets, basePlacement) {
|
|
var offsets = [0, 0];
|
|
|
|
// Use height if placement is left or right and index is 0 otherwise use width
|
|
// in this way the first offset will use an axis and the second one
|
|
// will use the other one
|
|
var useHeight = ['right', 'left'].indexOf(basePlacement) !== -1;
|
|
|
|
// Split the offset string to obtain a list of values and operands
|
|
// The regex addresses values with the plus or minus sign in front (+10, -20, etc)
|
|
var fragments = offset.split(/(\+|\-)/).map(function (frag) {
|
|
return frag.trim();
|
|
});
|
|
|
|
// Detect if the offset string contains a pair of values or a single one
|
|
// they could be separated by comma or space
|
|
var divider = fragments.indexOf(find(fragments, function (frag) {
|
|
return frag.search(/,|\s/) !== -1;
|
|
}));
|
|
|
|
if (fragments[divider] && fragments[divider].indexOf(',') === -1) {
|
|
console.warn('Offsets separated by white space(s) are deprecated, use a comma (,) instead.');
|
|
}
|
|
|
|
// If divider is found, we divide the list of values and operands to divide
|
|
// them by ofset X and Y.
|
|
var splitRegex = /\s*,\s*|\s+/;
|
|
var ops = divider !== -1 ? [fragments.slice(0, divider).concat([fragments[divider].split(splitRegex)[0]]), [fragments[divider].split(splitRegex)[1]].concat(fragments.slice(divider + 1))] : [fragments];
|
|
|
|
// Convert the values with units to absolute pixels to allow our computations
|
|
ops = ops.map(function (op, index) {
|
|
// Most of the units rely on the orientation of the popper
|
|
var measurement = (index === 1 ? !useHeight : useHeight) ? 'height' : 'width';
|
|
var mergeWithPrevious = false;
|
|
return op
|
|
// This aggregates any `+` or `-` sign that aren't considered operators
|
|
// e.g.: 10 + +5 => [10, +, +5]
|
|
.reduce(function (a, b) {
|
|
if (a[a.length - 1] === '' && ['+', '-'].indexOf(b) !== -1) {
|
|
a[a.length - 1] = b;
|
|
mergeWithPrevious = true;
|
|
return a;
|
|
} else if (mergeWithPrevious) {
|
|
a[a.length - 1] += b;
|
|
mergeWithPrevious = false;
|
|
return a;
|
|
} else {
|
|
return a.concat(b);
|
|
}
|
|
}, [])
|
|
// Here we convert the string values into number values (in px)
|
|
.map(function (str) {
|
|
return toValue(str, measurement, popperOffsets, referenceOffsets);
|
|
});
|
|
});
|
|
|
|
// Loop trough the offsets arrays and execute the operations
|
|
ops.forEach(function (op, index) {
|
|
op.forEach(function (frag, index2) {
|
|
if (isNumeric(frag)) {
|
|
offsets[index] += frag * (op[index2 - 1] === '-' ? -1 : 1);
|
|
}
|
|
});
|
|
});
|
|
return offsets;
|
|
}
|
|
|
|
/**
|
|
* @function
|
|
* @memberof Modifiers
|
|
* @argument {Object} data - The data object generated by update method
|
|
* @argument {Object} options - Modifiers configuration and options
|
|
* @argument {Number|String} options.offset=0
|
|
* The offset value as described in the modifier description
|
|
* @returns {Object} The data object, properly modified
|
|
*/
|
|
function offset$1(data, _ref) {
|
|
var offset = _ref.offset;
|
|
var placement = data.placement,
|
|
_data$offsets = data.offsets,
|
|
popper = _data$offsets.popper,
|
|
reference = _data$offsets.reference;
|
|
|
|
var basePlacement = placement.split('-')[0];
|
|
|
|
var offsets = void 0;
|
|
if (isNumeric(+offset)) {
|
|
offsets = [+offset, 0];
|
|
} else {
|
|
offsets = parseOffset(offset, popper, reference, basePlacement);
|
|
}
|
|
|
|
if (basePlacement === 'left') {
|
|
popper.top += offsets[0];
|
|
popper.left -= offsets[1];
|
|
} else if (basePlacement === 'right') {
|
|
popper.top += offsets[0];
|
|
popper.left += offsets[1];
|
|
} else if (basePlacement === 'top') {
|
|
popper.left += offsets[0];
|
|
popper.top -= offsets[1];
|
|
} else if (basePlacement === 'bottom') {
|
|
popper.left += offsets[0];
|
|
popper.top += offsets[1];
|
|
}
|
|
|
|
data.popper = popper;
|
|
return data;
|
|
}
|
|
|
|
/**
|
|
* @function
|
|
* @memberof Modifiers
|
|
* @argument {Object} data - The data object generated by `update` method
|
|
* @argument {Object} options - Modifiers configuration and options
|
|
* @returns {Object} The data object, properly modified
|
|
*/
|
|
function preventOverflow(data, options) {
|
|
var boundariesElement = options.boundariesElement || getOffsetParent(data.instance.popper);
|
|
|
|
// If offsetParent is the reference element, we really want to
|
|
// go one step up and use the next offsetParent as reference to
|
|
// avoid to make this modifier completely useless and look like broken
|
|
if (data.instance.reference === boundariesElement) {
|
|
boundariesElement = getOffsetParent(boundariesElement);
|
|
}
|
|
|
|
// NOTE: DOM access here
|
|
// resets the popper's position so that the document size can be calculated excluding
|
|
// the size of the popper element itself
|
|
var transformProp = getSupportedPropertyName('transform');
|
|
var popperStyles = data.instance.popper.style; // assignment to help minification
|
|
var top = popperStyles.top,
|
|
left = popperStyles.left,
|
|
transform = popperStyles[transformProp];
|
|
|
|
popperStyles.top = '';
|
|
popperStyles.left = '';
|
|
popperStyles[transformProp] = '';
|
|
|
|
var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, boundariesElement, data.positionFixed);
|
|
|
|
// NOTE: DOM access here
|
|
// restores the original style properties after the offsets have been computed
|
|
popperStyles.top = top;
|
|
popperStyles.left = left;
|
|
popperStyles[transformProp] = transform;
|
|
|
|
options.boundaries = boundaries;
|
|
|
|
var order = options.priority;
|
|
var popper = data.offsets.popper;
|
|
|
|
var check = {
|
|
primary: function primary(placement) {
|
|
var value = popper[placement];
|
|
if (popper[placement] < boundaries[placement] && !options.escapeWithReference) {
|
|
value = Math.max(popper[placement], boundaries[placement]);
|
|
}
|
|
return defineProperty$2({}, placement, value);
|
|
},
|
|
secondary: function secondary(placement) {
|
|
var mainSide = placement === 'right' ? 'left' : 'top';
|
|
var value = popper[mainSide];
|
|
if (popper[placement] > boundaries[placement] && !options.escapeWithReference) {
|
|
value = Math.min(popper[mainSide], boundaries[placement] - (placement === 'right' ? popper.width : popper.height));
|
|
}
|
|
return defineProperty$2({}, mainSide, value);
|
|
}
|
|
};
|
|
|
|
order.forEach(function (placement) {
|
|
var side = ['left', 'top'].indexOf(placement) !== -1 ? 'primary' : 'secondary';
|
|
popper = _extends$1({}, popper, check[side](placement));
|
|
});
|
|
|
|
data.offsets.popper = popper;
|
|
|
|
return data;
|
|
}
|
|
|
|
/**
|
|
* @function
|
|
* @memberof Modifiers
|
|
* @argument {Object} data - The data object generated by `update` method
|
|
* @argument {Object} options - Modifiers configuration and options
|
|
* @returns {Object} The data object, properly modified
|
|
*/
|
|
function shift(data) {
|
|
var placement = data.placement;
|
|
var basePlacement = placement.split('-')[0];
|
|
var shiftvariation = placement.split('-')[1];
|
|
|
|
// if shift shiftvariation is specified, run the modifier
|
|
if (shiftvariation) {
|
|
var _data$offsets = data.offsets,
|
|
reference = _data$offsets.reference,
|
|
popper = _data$offsets.popper;
|
|
|
|
var isVertical = ['bottom', 'top'].indexOf(basePlacement) !== -1;
|
|
var side = isVertical ? 'left' : 'top';
|
|
var measurement = isVertical ? 'width' : 'height';
|
|
|
|
var shiftOffsets = {
|
|
start: defineProperty$2({}, side, reference[side]),
|
|
end: defineProperty$2({}, side, reference[side] + reference[measurement] - popper[measurement])
|
|
};
|
|
|
|
data.offsets.popper = _extends$1({}, popper, shiftOffsets[shiftvariation]);
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
/**
|
|
* @function
|
|
* @memberof Modifiers
|
|
* @argument {Object} data - The data object generated by update method
|
|
* @argument {Object} options - Modifiers configuration and options
|
|
* @returns {Object} The data object, properly modified
|
|
*/
|
|
function hide(data) {
|
|
if (!isModifierRequired(data.instance.modifiers, 'hide', 'preventOverflow')) {
|
|
return data;
|
|
}
|
|
|
|
var refRect = data.offsets.reference;
|
|
var bound = find(data.instance.modifiers, function (modifier) {
|
|
return modifier.name === 'preventOverflow';
|
|
}).boundaries;
|
|
|
|
if (refRect.bottom < bound.top || refRect.left > bound.right || refRect.top > bound.bottom || refRect.right < bound.left) {
|
|
// Avoid unnecessary DOM access if visibility hasn't changed
|
|
if (data.hide === true) {
|
|
return data;
|
|
}
|
|
|
|
data.hide = true;
|
|
data.attributes['x-out-of-boundaries'] = '';
|
|
} else {
|
|
// Avoid unnecessary DOM access if visibility hasn't changed
|
|
if (data.hide === false) {
|
|
return data;
|
|
}
|
|
|
|
data.hide = false;
|
|
data.attributes['x-out-of-boundaries'] = false;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
/**
|
|
* @function
|
|
* @memberof Modifiers
|
|
* @argument {Object} data - The data object generated by `update` method
|
|
* @argument {Object} options - Modifiers configuration and options
|
|
* @returns {Object} The data object, properly modified
|
|
*/
|
|
function inner(data) {
|
|
var placement = data.placement;
|
|
var basePlacement = placement.split('-')[0];
|
|
var _data$offsets = data.offsets,
|
|
popper = _data$offsets.popper,
|
|
reference = _data$offsets.reference;
|
|
|
|
var isHoriz = ['left', 'right'].indexOf(basePlacement) !== -1;
|
|
|
|
var subtractLength = ['top', 'left'].indexOf(basePlacement) === -1;
|
|
|
|
popper[isHoriz ? 'left' : 'top'] = reference[basePlacement] - (subtractLength ? popper[isHoriz ? 'width' : 'height'] : 0);
|
|
|
|
data.placement = getOppositePlacement(placement);
|
|
data.offsets.popper = getClientRect(popper);
|
|
|
|
return data;
|
|
}
|
|
|
|
/**
|
|
* Modifier function, each modifier can have a function of this type assigned
|
|
* to its `fn` property.<br />
|
|
* These functions will be called on each update, this means that you must
|
|
* make sure they are performant enough to avoid performance bottlenecks.
|
|
*
|
|
* @function ModifierFn
|
|
* @argument {dataObject} data - The data object generated by `update` method
|
|
* @argument {Object} options - Modifiers configuration and options
|
|
* @returns {dataObject} The data object, properly modified
|
|
*/
|
|
|
|
/**
|
|
* Modifiers are plugins used to alter the behavior of your poppers.<br />
|
|
* Popper.js uses a set of 9 modifiers to provide all the basic functionalities
|
|
* needed by the library.
|
|
*
|
|
* Usually you don't want to override the `order`, `fn` and `onLoad` props.
|
|
* All the other properties are configurations that could be tweaked.
|
|
* @namespace modifiers
|
|
*/
|
|
var modifiers = {
|
|
/**
|
|
* Modifier used to shift the popper on the start or end of its reference
|
|
* element.<br />
|
|
* It will read the variation of the `placement` property.<br />
|
|
* It can be one either `-end` or `-start`.
|
|
* @memberof modifiers
|
|
* @inner
|
|
*/
|
|
shift: {
|
|
/** @prop {number} order=100 - Index used to define the order of execution */
|
|
order: 100,
|
|
/** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
|
|
enabled: true,
|
|
/** @prop {ModifierFn} */
|
|
fn: shift
|
|
},
|
|
|
|
/**
|
|
* The `offset` modifier can shift your popper on both its axis.
|
|
*
|
|
* It accepts the following units:
|
|
* - `px` or unitless, interpreted as pixels
|
|
* - `%` or `%r`, percentage relative to the length of the reference element
|
|
* - `%p`, percentage relative to the length of the popper element
|
|
* - `vw`, CSS viewport width unit
|
|
* - `vh`, CSS viewport height unit
|
|
*
|
|
* For length is intended the main axis relative to the placement of the popper.<br />
|
|
* This means that if the placement is `top` or `bottom`, the length will be the
|
|
* `width`. In case of `left` or `right`, it will be the height.
|
|
*
|
|
* You can provide a single value (as `Number` or `String`), or a pair of values
|
|
* as `String` divided by a comma or one (or more) white spaces.<br />
|
|
* The latter is a deprecated method because it leads to confusion and will be
|
|
* removed in v2.<br />
|
|
* Additionally, it accepts additions and subtractions between different units.
|
|
* Note that multiplications and divisions aren't supported.
|
|
*
|
|
* Valid examples are:
|
|
* ```
|
|
* 10
|
|
* '10%'
|
|
* '10, 10'
|
|
* '10%, 10'
|
|
* '10 + 10%'
|
|
* '10 - 5vh + 3%'
|
|
* '-10px + 5vh, 5px - 6%'
|
|
* ```
|
|
* > **NB**: If you desire to apply offsets to your poppers in a way that may make them overlap
|
|
* > with their reference element, unfortunately, you will have to disable the `flip` modifier.
|
|
* > More on this [reading this issue](https://github.com/FezVrasta/popper.js/issues/373)
|
|
*
|
|
* @memberof modifiers
|
|
* @inner
|
|
*/
|
|
offset: {
|
|
/** @prop {number} order=200 - Index used to define the order of execution */
|
|
order: 200,
|
|
/** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
|
|
enabled: true,
|
|
/** @prop {ModifierFn} */
|
|
fn: offset$1,
|
|
/** @prop {Number|String} offset=0
|
|
* The offset value as described in the modifier description
|
|
*/
|
|
offset: 0
|
|
},
|
|
|
|
/**
|
|
* Modifier used to prevent the popper from being positioned outside the boundary.
|
|
*
|
|
* An scenario exists where the reference itself is not within the boundaries.<br />
|
|
* We can say it has "escaped the boundaries" — or just "escaped".<br />
|
|
* In this case we need to decide whether the popper should either:
|
|
*
|
|
* - detach from the reference and remain "trapped" in the boundaries, or
|
|
* - if it should ignore the boundary and "escape with its reference"
|
|
*
|
|
* When `escapeWithReference` is set to`true` and reference is completely
|
|
* outside its boundaries, the popper will overflow (or completely leave)
|
|
* the boundaries in order to remain attached to the edge of the reference.
|
|
*
|
|
* @memberof modifiers
|
|
* @inner
|
|
*/
|
|
preventOverflow: {
|
|
/** @prop {number} order=300 - Index used to define the order of execution */
|
|
order: 300,
|
|
/** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
|
|
enabled: true,
|
|
/** @prop {ModifierFn} */
|
|
fn: preventOverflow,
|
|
/**
|
|
* @prop {Array} [priority=['left','right','top','bottom']]
|
|
* Popper will try to prevent overflow following these priorities by default,
|
|
* then, it could overflow on the left and on top of the `boundariesElement`
|
|
*/
|
|
priority: ['left', 'right', 'top', 'bottom'],
|
|
/**
|
|
* @prop {number} padding=5
|
|
* Amount of pixel used to define a minimum distance between the boundaries
|
|
* and the popper this makes sure the popper has always a little padding
|
|
* between the edges of its container
|
|
*/
|
|
padding: 5,
|
|
/**
|
|
* @prop {String|HTMLElement} boundariesElement='scrollParent'
|
|
* Boundaries used by the modifier, can be `scrollParent`, `window`,
|
|
* `viewport` or any DOM element.
|
|
*/
|
|
boundariesElement: 'scrollParent'
|
|
},
|
|
|
|
/**
|
|
* Modifier used to make sure the reference and its popper stay near eachothers
|
|
* without leaving any gap between the two. Expecially useful when the arrow is
|
|
* enabled and you want to assure it to point to its reference element.
|
|
* It cares only about the first axis, you can still have poppers with margin
|
|
* between the popper and its reference element.
|
|
* @memberof modifiers
|
|
* @inner
|
|
*/
|
|
keepTogether: {
|
|
/** @prop {number} order=400 - Index used to define the order of execution */
|
|
order: 400,
|
|
/** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
|
|
enabled: true,
|
|
/** @prop {ModifierFn} */
|
|
fn: keepTogether
|
|
},
|
|
|
|
/**
|
|
* This modifier is used to move the `arrowElement` of the popper to make
|
|
* sure it is positioned between the reference element and its popper element.
|
|
* It will read the outer size of the `arrowElement` node to detect how many
|
|
* pixels of conjuction are needed.
|
|
*
|
|
* It has no effect if no `arrowElement` is provided.
|
|
* @memberof modifiers
|
|
* @inner
|
|
*/
|
|
arrow: {
|
|
/** @prop {number} order=500 - Index used to define the order of execution */
|
|
order: 500,
|
|
/** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
|
|
enabled: true,
|
|
/** @prop {ModifierFn} */
|
|
fn: arrow,
|
|
/** @prop {String|HTMLElement} element='[x-arrow]' - Selector or node used as arrow */
|
|
element: '[x-arrow]'
|
|
},
|
|
|
|
/**
|
|
* Modifier used to flip the popper's placement when it starts to overlap its
|
|
* reference element.
|
|
*
|
|
* Requires the `preventOverflow` modifier before it in order to work.
|
|
*
|
|
* **NOTE:** this modifier will interrupt the current update cycle and will
|
|
* restart it if it detects the need to flip the placement.
|
|
* @memberof modifiers
|
|
* @inner
|
|
*/
|
|
flip: {
|
|
/** @prop {number} order=600 - Index used to define the order of execution */
|
|
order: 600,
|
|
/** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
|
|
enabled: true,
|
|
/** @prop {ModifierFn} */
|
|
fn: flip,
|
|
/**
|
|
* @prop {String|Array} behavior='flip'
|
|
* The behavior used to change the popper's placement. It can be one of
|
|
* `flip`, `clockwise`, `counterclockwise` or an array with a list of valid
|
|
* placements (with optional variations).
|
|
*/
|
|
behavior: 'flip',
|
|
/**
|
|
* @prop {number} padding=5
|
|
* The popper will flip if it hits the edges of the `boundariesElement`
|
|
*/
|
|
padding: 5,
|
|
/**
|
|
* @prop {String|HTMLElement} boundariesElement='viewport'
|
|
* The element which will define the boundaries of the popper position,
|
|
* the popper will never be placed outside of the defined boundaries
|
|
* (except if keepTogether is enabled)
|
|
*/
|
|
boundariesElement: 'viewport'
|
|
},
|
|
|
|
/**
|
|
* Modifier used to make the popper flow toward the inner of the reference element.
|
|
* By default, when this modifier is disabled, the popper will be placed outside
|
|
* the reference element.
|
|
* @memberof modifiers
|
|
* @inner
|
|
*/
|
|
inner: {
|
|
/** @prop {number} order=700 - Index used to define the order of execution */
|
|
order: 700,
|
|
/** @prop {Boolean} enabled=false - Whether the modifier is enabled or not */
|
|
enabled: false,
|
|
/** @prop {ModifierFn} */
|
|
fn: inner
|
|
},
|
|
|
|
/**
|
|
* Modifier used to hide the popper when its reference element is outside of the
|
|
* popper boundaries. It will set a `x-out-of-boundaries` attribute which can
|
|
* be used to hide with a CSS selector the popper when its reference is
|
|
* out of boundaries.
|
|
*
|
|
* Requires the `preventOverflow` modifier before it in order to work.
|
|
* @memberof modifiers
|
|
* @inner
|
|
*/
|
|
hide: {
|
|
/** @prop {number} order=800 - Index used to define the order of execution */
|
|
order: 800,
|
|
/** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
|
|
enabled: true,
|
|
/** @prop {ModifierFn} */
|
|
fn: hide
|
|
},
|
|
|
|
/**
|
|
* Computes the style that will be applied to the popper element to gets
|
|
* properly positioned.
|
|
*
|
|
* Note that this modifier will not touch the DOM, it just prepares the styles
|
|
* so that `applyStyle` modifier can apply it. This separation is useful
|
|
* in case you need to replace `applyStyle` with a custom implementation.
|
|
*
|
|
* This modifier has `850` as `order` value to maintain backward compatibility
|
|
* with previous versions of Popper.js. Expect the modifiers ordering method
|
|
* to change in future major versions of the library.
|
|
*
|
|
* @memberof modifiers
|
|
* @inner
|
|
*/
|
|
computeStyle: {
|
|
/** @prop {number} order=850 - Index used to define the order of execution */
|
|
order: 850,
|
|
/** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
|
|
enabled: true,
|
|
/** @prop {ModifierFn} */
|
|
fn: computeStyle,
|
|
/**
|
|
* @prop {Boolean} gpuAcceleration=true
|
|
* If true, it uses the CSS 3d transformation to position the popper.
|
|
* Otherwise, it will use the `top` and `left` properties.
|
|
*/
|
|
gpuAcceleration: true,
|
|
/**
|
|
* @prop {string} [x='bottom']
|
|
* Where to anchor the X axis (`bottom` or `top`). AKA X offset origin.
|
|
* Change this if your popper should grow in a direction different from `bottom`
|
|
*/
|
|
x: 'bottom',
|
|
/**
|
|
* @prop {string} [x='left']
|
|
* Where to anchor the Y axis (`left` or `right`). AKA Y offset origin.
|
|
* Change this if your popper should grow in a direction different from `right`
|
|
*/
|
|
y: 'right'
|
|
},
|
|
|
|
/**
|
|
* Applies the computed styles to the popper element.
|
|
*
|
|
* All the DOM manipulations are limited to this modifier. This is useful in case
|
|
* you want to integrate Popper.js inside a framework or view library and you
|
|
* want to delegate all the DOM manipulations to it.
|
|
*
|
|
* Note that if you disable this modifier, you must make sure the popper element
|
|
* has its position set to `absolute` before Popper.js can do its work!
|
|
*
|
|
* Just disable this modifier and define you own to achieve the desired effect.
|
|
*
|
|
* @memberof modifiers
|
|
* @inner
|
|
*/
|
|
applyStyle: {
|
|
/** @prop {number} order=900 - Index used to define the order of execution */
|
|
order: 900,
|
|
/** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
|
|
enabled: true,
|
|
/** @prop {ModifierFn} */
|
|
fn: applyStyle,
|
|
/** @prop {Function} */
|
|
onLoad: applyStyleOnLoad,
|
|
/**
|
|
* @deprecated since version 1.10.0, the property moved to `computeStyle` modifier
|
|
* @prop {Boolean} gpuAcceleration=true
|
|
* If true, it uses the CSS 3d transformation to position the popper.
|
|
* Otherwise, it will use the `top` and `left` properties.
|
|
*/
|
|
gpuAcceleration: undefined
|
|
}
|
|
};
|
|
|
|
/**
|
|
* The `dataObject` is an object containing all the informations used by Popper.js
|
|
* this object get passed to modifiers and to the `onCreate` and `onUpdate` callbacks.
|
|
* @name dataObject
|
|
* @property {Object} data.instance The Popper.js instance
|
|
* @property {String} data.placement Placement applied to popper
|
|
* @property {String} data.originalPlacement Placement originally defined on init
|
|
* @property {Boolean} data.flipped True if popper has been flipped by flip modifier
|
|
* @property {Boolean} data.hide True if the reference element is out of boundaries, useful to know when to hide the popper.
|
|
* @property {HTMLElement} data.arrowElement Node used as arrow by arrow modifier
|
|
* @property {Object} data.styles Any CSS property defined here will be applied to the popper, it expects the JavaScript nomenclature (eg. `marginBottom`)
|
|
* @property {Object} data.arrowStyles Any CSS property defined here will be applied to the popper arrow, it expects the JavaScript nomenclature (eg. `marginBottom`)
|
|
* @property {Object} data.boundaries Offsets of the popper boundaries
|
|
* @property {Object} data.offsets The measurements of popper, reference and arrow elements.
|
|
* @property {Object} data.offsets.popper `top`, `left`, `width`, `height` values
|
|
* @property {Object} data.offsets.reference `top`, `left`, `width`, `height` values
|
|
* @property {Object} data.offsets.arrow] `top` and `left` offsets, only one of them will be different from 0
|
|
*/
|
|
|
|
/**
|
|
* Default options provided to Popper.js constructor.<br />
|
|
* These can be overriden using the `options` argument of Popper.js.<br />
|
|
* To override an option, simply pass as 3rd argument an object with the same
|
|
* structure of this object, example:
|
|
* ```
|
|
* new Popper(ref, pop, {
|
|
* modifiers: {
|
|
* preventOverflow: { enabled: false }
|
|
* }
|
|
* })
|
|
* ```
|
|
* @type {Object}
|
|
* @static
|
|
* @memberof Popper
|
|
*/
|
|
var Defaults = {
|
|
/**
|
|
* Popper's placement
|
|
* @prop {Popper.placements} placement='bottom'
|
|
*/
|
|
placement: 'bottom',
|
|
|
|
/**
|
|
* Set this to true if you want popper to position it self in 'fixed' mode
|
|
* @prop {Boolean} positionFixed=false
|
|
*/
|
|
positionFixed: false,
|
|
|
|
/**
|
|
* Whether events (resize, scroll) are initially enabled
|
|
* @prop {Boolean} eventsEnabled=true
|
|
*/
|
|
eventsEnabled: true,
|
|
|
|
/**
|
|
* Set to true if you want to automatically remove the popper when
|
|
* you call the `destroy` method.
|
|
* @prop {Boolean} removeOnDestroy=false
|
|
*/
|
|
removeOnDestroy: false,
|
|
|
|
/**
|
|
* Callback called when the popper is created.<br />
|
|
* By default, is set to no-op.<br />
|
|
* Access Popper.js instance with `data.instance`.
|
|
* @prop {onCreate}
|
|
*/
|
|
onCreate: function onCreate() {},
|
|
|
|
/**
|
|
* Callback called when the popper is updated, this callback is not called
|
|
* on the initialization/creation of the popper, but only on subsequent
|
|
* updates.<br />
|
|
* By default, is set to no-op.<br />
|
|
* Access Popper.js instance with `data.instance`.
|
|
* @prop {onUpdate}
|
|
*/
|
|
onUpdate: function onUpdate() {},
|
|
|
|
/**
|
|
* List of modifiers used to modify the offsets before they are applied to the popper.
|
|
* They provide most of the functionalities of Popper.js
|
|
* @prop {modifiers}
|
|
*/
|
|
modifiers: modifiers
|
|
};
|
|
|
|
/**
|
|
* @callback onCreate
|
|
* @param {dataObject} data
|
|
*/
|
|
|
|
/**
|
|
* @callback onUpdate
|
|
* @param {dataObject} data
|
|
*/
|
|
|
|
// Utils
|
|
// Methods
|
|
var Popper = function () {
|
|
/**
|
|
* Create a new Popper.js instance
|
|
* @class Popper
|
|
* @param {HTMLElement|referenceObject} reference - The reference element used to position the popper
|
|
* @param {HTMLElement} popper - The HTML element used as popper.
|
|
* @param {Object} options - Your custom options to override the ones defined in [Defaults](#defaults)
|
|
* @return {Object} instance - The generated Popper.js instance
|
|
*/
|
|
function Popper(reference, popper) {
|
|
var _this = this;
|
|
|
|
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
classCallCheck$1(this, Popper);
|
|
|
|
this.scheduleUpdate = function () {
|
|
return requestAnimationFrame(_this.update);
|
|
};
|
|
|
|
// make update() debounced, so that it only runs at most once-per-tick
|
|
this.update = debounce(this.update.bind(this));
|
|
|
|
// with {} we create a new object with the options inside it
|
|
this.options = _extends$1({}, Popper.Defaults, options);
|
|
|
|
// init state
|
|
this.state = {
|
|
isDestroyed: false,
|
|
isCreated: false,
|
|
scrollParents: []
|
|
};
|
|
|
|
// get reference and popper elements (allow jQuery wrappers)
|
|
this.reference = reference && reference.jquery ? reference[0] : reference;
|
|
this.popper = popper && popper.jquery ? popper[0] : popper;
|
|
|
|
// Deep merge modifiers options
|
|
this.options.modifiers = {};
|
|
Object.keys(_extends$1({}, Popper.Defaults.modifiers, options.modifiers)).forEach(function (name) {
|
|
_this.options.modifiers[name] = _extends$1({}, Popper.Defaults.modifiers[name] || {}, options.modifiers ? options.modifiers[name] : {});
|
|
});
|
|
|
|
// Refactoring modifiers' list (Object => Array)
|
|
this.modifiers = Object.keys(this.options.modifiers).map(function (name) {
|
|
return _extends$1({
|
|
name: name
|
|
}, _this.options.modifiers[name]);
|
|
})
|
|
// sort the modifiers by order
|
|
.sort(function (a, b) {
|
|
return a.order - b.order;
|
|
});
|
|
|
|
// modifiers have the ability to execute arbitrary code when Popper.js get inited
|
|
// such code is executed in the same order of its modifier
|
|
// they could add new properties to their options configuration
|
|
// BE AWARE: don't add options to `options.modifiers.name` but to `modifierOptions`!
|
|
this.modifiers.forEach(function (modifierOptions) {
|
|
if (modifierOptions.enabled && isFunction(modifierOptions.onLoad)) {
|
|
modifierOptions.onLoad(_this.reference, _this.popper, _this.options, modifierOptions, _this.state);
|
|
}
|
|
});
|
|
|
|
// fire the first update to position the popper in the right place
|
|
this.update();
|
|
|
|
var eventsEnabled = this.options.eventsEnabled;
|
|
if (eventsEnabled) {
|
|
// setup event listeners, they will take care of update the position in specific situations
|
|
this.enableEventListeners();
|
|
}
|
|
|
|
this.state.eventsEnabled = eventsEnabled;
|
|
}
|
|
|
|
// We can't use class properties because they don't get listed in the
|
|
// class prototype and break stuff like Sinon stubs
|
|
|
|
|
|
createClass$1(Popper, [{
|
|
key: 'update',
|
|
value: function update$$1() {
|
|
return update.call(this);
|
|
}
|
|
}, {
|
|
key: 'destroy',
|
|
value: function destroy$$1() {
|
|
return destroy.call(this);
|
|
}
|
|
}, {
|
|
key: 'enableEventListeners',
|
|
value: function enableEventListeners$$1() {
|
|
return enableEventListeners.call(this);
|
|
}
|
|
}, {
|
|
key: 'disableEventListeners',
|
|
value: function disableEventListeners$$1() {
|
|
return disableEventListeners.call(this);
|
|
}
|
|
|
|
/**
|
|
* Schedule an update, it will run on the next UI update available
|
|
* @method scheduleUpdate
|
|
* @memberof Popper
|
|
*/
|
|
|
|
/**
|
|
* Collection of utilities useful when writing custom modifiers.
|
|
* Starting from version 1.7, this method is available only if you
|
|
* include `popper-utils.js` before `popper.js`.
|
|
*
|
|
* **DEPRECATION**: This way to access PopperUtils is deprecated
|
|
* and will be removed in v2! Use the PopperUtils module directly instead.
|
|
* Due to the high instability of the methods contained in Utils, we can't
|
|
* guarantee them to follow semver. Use them at your own risk!
|
|
* @static
|
|
* @private
|
|
* @type {Object}
|
|
* @deprecated since version 1.8
|
|
* @member Utils
|
|
* @memberof Popper
|
|
*/
|
|
|
|
}]);
|
|
return Popper;
|
|
}();
|
|
|
|
/**
|
|
* The `referenceObject` is an object that provides an interface compatible with Popper.js
|
|
* and lets you use it as replacement of a real DOM node.<br />
|
|
* You can use this method to position a popper relatively to a set of coordinates
|
|
* in case you don't have a DOM node to use as reference.
|
|
*
|
|
* ```
|
|
* new Popper(referenceObject, popperNode);
|
|
* ```
|
|
*
|
|
* NB: This feature isn't supported in Internet Explorer 10
|
|
* @name referenceObject
|
|
* @property {Function} data.getBoundingClientRect
|
|
* A function that returns a set of coordinates compatible with the native `getBoundingClientRect` method.
|
|
* @property {number} data.clientWidth
|
|
* An ES6 getter that will return the width of the virtual reference element.
|
|
* @property {number} data.clientHeight
|
|
* An ES6 getter that will return the height of the virtual reference element.
|
|
*/
|
|
|
|
Popper.Utils = (typeof window !== 'undefined' ? window : global).PopperUtils;
|
|
Popper.placements = placements;
|
|
Popper.Defaults = Defaults;
|
|
|
|
var clickoutMixin = {
|
|
mounted: function mounted() {
|
|
if (typeof document !== 'undefined') {
|
|
document.documentElement.addEventListener('click', this._clickOutListener);
|
|
}
|
|
},
|
|
beforeDestroy: function beforeDestroy() {
|
|
if (typeof document !== 'undefined') {
|
|
document.documentElement.removeEventListener('click', this._clickOutListener);
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
_clickOutListener: function _clickOutListener(e) {
|
|
if (!this.$el.contains(e.target)) {
|
|
if (this.clickOutListener) {
|
|
this.clickOutListener();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
var BvEvent = function () {
|
|
function BvEvent(type) {
|
|
var eventInit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
classCallCheck(this, BvEvent);
|
|
|
|
// Start by emulating native Event constructor.
|
|
if (!type) {
|
|
throw new TypeError('Failed to construct \'' + this.constructor.name + '\'. 1 argument required, ' + arguments.length + ' given.');
|
|
}
|
|
// Assign defaults first, the eventInit,
|
|
// and the type last so it can't be overwritten.
|
|
assign(this, BvEvent.defaults(), eventInit, { type: type });
|
|
// Freeze some props as readonly, but leave them enumerable.
|
|
defineProperties(this, {
|
|
type: readonlyDescriptor(),
|
|
cancelable: readonlyDescriptor(),
|
|
nativeEvent: readonlyDescriptor(),
|
|
target: readonlyDescriptor(),
|
|
relatedTarget: readonlyDescriptor(),
|
|
vueTarget: readonlyDescriptor()
|
|
});
|
|
// Create a private variable using closure scoping.
|
|
var defaultPrevented = false;
|
|
// Recreate preventDefault method. One way setter.
|
|
this.preventDefault = function preventDefault() {
|
|
if (this.cancelable) {
|
|
defaultPrevented = true;
|
|
}
|
|
};
|
|
// Create 'defaultPrevented' publicly accessible prop
|
|
// that can only be altered by the preventDefault method.
|
|
defineProperty$1(this, 'defaultPrevented', {
|
|
enumerable: true,
|
|
get: function get$$1() {
|
|
return defaultPrevented;
|
|
}
|
|
});
|
|
}
|
|
|
|
createClass(BvEvent, null, [{
|
|
key: 'defaults',
|
|
value: function defaults$$1() {
|
|
return {
|
|
type: '',
|
|
cancelable: true,
|
|
nativeEvent: null,
|
|
target: null,
|
|
relatedTarget: null,
|
|
vueTarget: null
|
|
};
|
|
}
|
|
}]);
|
|
return BvEvent;
|
|
}();
|
|
|
|
// Return an Array of visible items
|
|
function filterVisible(els) {
|
|
return (els || []).filter(isVisible);
|
|
}
|
|
|
|
// Dropdown item CSS selectors
|
|
// TODO: .dropdown-form handling
|
|
var ITEM_SELECTOR$1 = '.dropdown-item:not(.disabled):not([disabled])';
|
|
|
|
// Popper attachment positions
|
|
var AttachmentMap = {
|
|
// DropUp Left Align
|
|
TOP: 'top-start',
|
|
// DropUp Right Align
|
|
TOPEND: 'top-end',
|
|
// Dropdown left Align
|
|
BOTTOM: 'bottom-start',
|
|
// Dropdown Right Align
|
|
BOTTOMEND: 'bottom-end'
|
|
};
|
|
|
|
var dropdownMixin = {
|
|
mixins: [clickoutMixin, listenOnRootMixin],
|
|
props: {
|
|
disabled: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
text: {
|
|
// Button label
|
|
type: String,
|
|
default: ''
|
|
},
|
|
dropup: {
|
|
// place on top if possible
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
right: {
|
|
// Right align menu (default is left align)
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
offset: {
|
|
// Number of pixels to offset menu, or a CSS unit value (i.e. 1px, 1rem, etc)
|
|
type: [Number, String],
|
|
default: 0
|
|
},
|
|
noFlip: {
|
|
// Disable auto-flipping of menu from bottom<=>top
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
popperOpts: {
|
|
type: Object,
|
|
default: function _default() {}
|
|
}
|
|
},
|
|
data: function data() {
|
|
return {
|
|
visible: false,
|
|
inNavbar: null,
|
|
visibleChangePrevented: false
|
|
};
|
|
},
|
|
created: function created() {
|
|
// Create non-reactive property
|
|
this._popper = null;
|
|
},
|
|
mounted: function mounted() {
|
|
// To keep one dropdown opened on page
|
|
this.listenOnRoot('bv::dropdown::shown', this.rootCloseListener);
|
|
// Hide when clicked on links
|
|
this.listenOnRoot('clicked::link', this.rootCloseListener);
|
|
// Use new namespaced events
|
|
this.listenOnRoot('bv::link::clicked', this.rootCloseListener);
|
|
},
|
|
|
|
/* istanbul ignore next: not easy to test */
|
|
deactivated: function deactivated() {
|
|
// In case we are inside a `<keep-alive>`
|
|
this.visible = false;
|
|
this.setTouchStart(false);
|
|
this.removePopper();
|
|
},
|
|
|
|
/* istanbul ignore next: not easy to test */
|
|
beforeDestroy: function beforeDestroy() {
|
|
this.visible = false;
|
|
this.setTouchStart(false);
|
|
this.removePopper();
|
|
},
|
|
|
|
watch: {
|
|
visible: function visible(newValue, oldValue) {
|
|
if (this.visibleChangePrevented) {
|
|
this.visibleChangePrevented = false;
|
|
return;
|
|
}
|
|
|
|
if (newValue !== oldValue) {
|
|
var evtName = newValue ? 'show' : 'hide';
|
|
var bvEvt = new BvEvent(evtName, {
|
|
cancelable: true,
|
|
vueTarget: this,
|
|
target: this.$refs.menu,
|
|
relatedTarget: null
|
|
});
|
|
this.emitEvent(bvEvt);
|
|
if (bvEvt.defaultPrevented) {
|
|
// Reset value and exit if canceled
|
|
this.visibleChangePrevented = true;
|
|
this.visible = oldValue;
|
|
return;
|
|
}
|
|
if (evtName === 'show') {
|
|
this.showMenu();
|
|
} else {
|
|
this.hideMenu();
|
|
}
|
|
}
|
|
},
|
|
disabled: function disabled(newValue, oldValue) {
|
|
if (newValue !== oldValue && newValue && this.visible) {
|
|
// Hide dropdown if disabled changes to true
|
|
this.visible = false;
|
|
}
|
|
}
|
|
},
|
|
computed: {
|
|
toggler: function toggler() {
|
|
return this.$refs.toggle.$el || this.$refs.toggle;
|
|
}
|
|
},
|
|
methods: {
|
|
// Event emitter
|
|
emitEvent: function emitEvent(bvEvt) {
|
|
var type = bvEvt.type;
|
|
this.$emit(type, bvEvt);
|
|
this.emitOnRoot('bv::dropdown::' + type, bvEvt);
|
|
},
|
|
showMenu: function showMenu() {
|
|
if (this.disabled) {
|
|
return;
|
|
}
|
|
// Ensure other menus are closed
|
|
this.emitOnRoot('bv::dropdown::shown', this);
|
|
|
|
// Are we in a navbar ?
|
|
if (this.inNavbar === null && this.isNav) {
|
|
this.inNavbar = Boolean(closest('.navbar', this.$el));
|
|
}
|
|
|
|
// Disable totally Popper.js for Dropdown in Navbar
|
|
/* istnbul ignore next: can't test popper in JSDOM */
|
|
if (!this.inNavbar) {
|
|
if (typeof Popper === 'undefined') {
|
|
warn('b-dropdown: Popper.js not found. Falling back to CSS positioning.');
|
|
} else {
|
|
// for dropup with alignment we use the parent element as popper container
|
|
var element = this.dropup && this.right || this.split ? this.$el : this.$refs.toggle;
|
|
// Make sure we have a reference to an element, not a component!
|
|
element = element.$el || element;
|
|
// Instantiate popper.js
|
|
this.createPopper(element);
|
|
}
|
|
}
|
|
|
|
this.setTouchStart(true);
|
|
this.$emit('shown');
|
|
|
|
// Focus on the first item on show
|
|
this.$nextTick(this.focusFirstItem);
|
|
},
|
|
hideMenu: function hideMenu() {
|
|
this.setTouchStart(false);
|
|
this.emitOnRoot('bv::dropdown::hidden', this);
|
|
this.$emit('hidden');
|
|
this.removePopper();
|
|
},
|
|
createPopper: function createPopper(element) {
|
|
this.removePopper();
|
|
this._popper = new Popper(element, this.$refs.menu, this.getPopperConfig());
|
|
},
|
|
removePopper: function removePopper() {
|
|
if (this._popper) {
|
|
// Ensure popper event listeners are removed cleanly
|
|
this._popper.destroy();
|
|
}
|
|
this._popper = null;
|
|
},
|
|
getPopperConfig /* istanbul ignore next: can't test popper in JSDOM */: function getPopperConfig() {
|
|
var placement = AttachmentMap.BOTTOM;
|
|
if (this.dropup && this.right) {
|
|
// dropup + right
|
|
placement = AttachmentMap.TOPEND;
|
|
} else if (this.dropup) {
|
|
// dropup + left
|
|
placement = AttachmentMap.TOP;
|
|
} else if (this.right) {
|
|
// dropdown + right
|
|
placement = AttachmentMap.BOTTOMEND;
|
|
}
|
|
var popperConfig = {
|
|
placement: placement,
|
|
modifiers: {
|
|
offset: {
|
|
offset: this.offset || 0
|
|
},
|
|
flip: {
|
|
enabled: !this.noFlip
|
|
}
|
|
}
|
|
};
|
|
if (this.boundary) {
|
|
popperConfig.modifiers.preventOverflow = {
|
|
boundariesElement: this.boundary
|
|
};
|
|
}
|
|
return assign(popperConfig, this.popperOpts || {});
|
|
},
|
|
setTouchStart: function setTouchStart(on) {
|
|
var _this = this;
|
|
|
|
/*
|
|
* If this is a touch-enabled device we add extra
|
|
* empty mouseover listeners to the body's immediate children;
|
|
* only needed because of broken event delegation on iOS
|
|
* https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
|
|
*/
|
|
if ('ontouchstart' in document.documentElement) {
|
|
var children = from(document.body.children);
|
|
children.forEach(function (el) {
|
|
if (on) {
|
|
eventOn('mouseover', _this._noop);
|
|
} else {
|
|
eventOff('mouseover', _this._noop);
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
/* istanbul ignore next: not easy to test */
|
|
_noop: function _noop() {
|
|
// Do nothing event handler (used in touchstart event handler)
|
|
},
|
|
rootCloseListener: function rootCloseListener(vm) {
|
|
if (vm !== this) {
|
|
this.visible = false;
|
|
}
|
|
},
|
|
clickOutListener: function clickOutListener() {
|
|
this.visible = false;
|
|
},
|
|
show: function show() {
|
|
// Public method to show dropdown
|
|
if (this.disabled) {
|
|
return;
|
|
}
|
|
this.visible = true;
|
|
},
|
|
hide: function hide() {
|
|
// Public method to hide dropdown
|
|
if (this.disabled) {
|
|
return;
|
|
}
|
|
this.visible = false;
|
|
},
|
|
toggle: function toggle(evt) {
|
|
// Called only by a button that toggles the menu
|
|
evt = evt || {};
|
|
var type = evt.type;
|
|
var key = evt.keyCode;
|
|
if (type !== 'click' && !(type === 'keydown' && (key === KeyCodes.ENTER || key === KeyCodes.SPACE || key === KeyCodes.DOWN))) {
|
|
// We only toggle on Click, Enter, Space, and Arrow Down
|
|
return;
|
|
}
|
|
if (this.disabled) {
|
|
this.visible = false;
|
|
return;
|
|
}
|
|
this.$emit('toggle', evt);
|
|
if (evt.defaultPrevented) {
|
|
// Exit if canceled
|
|
return;
|
|
}
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
// Toggle visibility
|
|
this.visible = !this.visible;
|
|
},
|
|
click: function click(evt) {
|
|
// Calle only in split button mode, for the split button
|
|
if (this.disabled) {
|
|
this.visible = false;
|
|
return;
|
|
}
|
|
this.$emit('click', evt);
|
|
},
|
|
|
|
/* istanbul ignore next: not easy to test */
|
|
onKeydown: function onKeydown(evt) {
|
|
// Called from dropdown menu context
|
|
var key = evt.keyCode;
|
|
if (key === KeyCodes.ESC) {
|
|
// Close on ESC
|
|
this.onEsc(evt);
|
|
} else if (key === KeyCodes.TAB) {
|
|
// Close on tab out
|
|
this.onTab(evt);
|
|
} else if (key === KeyCodes.DOWN) {
|
|
// Down Arrow
|
|
this.focusNext(evt, false);
|
|
} else if (key === KeyCodes.UP) {
|
|
// Up Arrow
|
|
this.focusNext(evt, true);
|
|
}
|
|
},
|
|
|
|
/* istanbul ignore next: not easy to test */
|
|
onEsc: function onEsc(evt) {
|
|
if (this.visible) {
|
|
this.visible = false;
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
// Return focus to original trigger button
|
|
this.$nextTick(this.focusToggler);
|
|
}
|
|
},
|
|
|
|
/* istanbul ignore next: not easy to test */
|
|
onTab: function onTab(evt) {
|
|
if (this.visible) {
|
|
// TODO: Need special handler for dealing with form inputs
|
|
// Tab, if in a text-like input, we should just focus next item in the dropdown
|
|
// Note: Inputs are in a special .dropdown-form container
|
|
this.visible = false;
|
|
}
|
|
},
|
|
onFocusOut: function onFocusOut(evt) {
|
|
if (this.$refs.menu.contains(evt.relatedTarget)) {
|
|
return;
|
|
}
|
|
this.visible = false;
|
|
},
|
|
|
|
/* istanbul ignore next: not easy to test */
|
|
onMouseOver: function onMouseOver(evt) {
|
|
// Focus the item on hover
|
|
// TODO: Special handling for inputs? Inputs are in a special .dropdown-form container
|
|
var item = evt.target;
|
|
if (item.classList.contains('dropdown-item') && !item.disabled && !item.classList.contains('disabled') && item.focus) {
|
|
item.focus();
|
|
}
|
|
},
|
|
focusNext: function focusNext(evt, up) {
|
|
var _this2 = this;
|
|
|
|
if (!this.visible) {
|
|
return;
|
|
}
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
this.$nextTick(function () {
|
|
var items = _this2.getItems();
|
|
if (items.length < 1) {
|
|
return;
|
|
}
|
|
var index = items.indexOf(evt.target);
|
|
if (up && index > 0) {
|
|
index--;
|
|
} else if (!up && index < items.length - 1) {
|
|
index++;
|
|
}
|
|
if (index < 0) {
|
|
index = 0;
|
|
}
|
|
_this2.focusItem(index, items);
|
|
});
|
|
},
|
|
focusItem: function focusItem(idx, items) {
|
|
var el = items.find(function (el, i) {
|
|
return i === idx;
|
|
});
|
|
if (el && getAttr(el, 'tabindex') !== '-1') {
|
|
el.focus();
|
|
}
|
|
},
|
|
getItems: function getItems() {
|
|
// Get all items
|
|
return filterVisible(selectAll(ITEM_SELECTOR$1, this.$refs.menu));
|
|
},
|
|
getFirstItem: function getFirstItem() {
|
|
// Get the first non-disabled item
|
|
var item = this.getItems()[0];
|
|
return item || null;
|
|
},
|
|
focusFirstItem: function focusFirstItem() {
|
|
var item = this.getFirstItem();
|
|
if (item) {
|
|
this.focusItem(0, [item]);
|
|
}
|
|
},
|
|
focusToggler: function focusToggler() {
|
|
var toggler = this.toggler;
|
|
if (toggler && toggler.focus) {
|
|
toggler.focus();
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
var bDropdown = {
|
|
mixins: [idMixin, dropdownMixin],
|
|
components: { bButton: bBtn },
|
|
render: function render(h) {
|
|
var split = h(false);
|
|
if (this.split) {
|
|
split = h('b-button', {
|
|
ref: 'button',
|
|
props: {
|
|
disabled: this.disabled,
|
|
variant: this.variant,
|
|
size: this.size
|
|
},
|
|
attrs: {
|
|
id: this.safeId('_BV_button_')
|
|
},
|
|
on: {
|
|
click: this.click
|
|
}
|
|
}, [this.$slots['button-content'] || this.$slots.text || this.text]);
|
|
}
|
|
var toggle = h('b-button', {
|
|
ref: 'toggle',
|
|
class: this.toggleClasses,
|
|
props: {
|
|
variant: this.variant,
|
|
size: this.size,
|
|
disabled: this.disabled
|
|
},
|
|
attrs: {
|
|
id: this.safeId('_BV_toggle_'),
|
|
'aria-haspopup': 'true',
|
|
'aria-expanded': this.visible ? 'true' : 'false'
|
|
},
|
|
on: {
|
|
click: this.toggle, // click
|
|
keydown: this.toggle // enter, space, down
|
|
}
|
|
}, [this.split ? h('span', { class: ['sr-only'] }, [this.toggleText]) : this.$slots['button-content'] || this.$slots.text || this.text]);
|
|
var menu = h('div', {
|
|
ref: 'menu',
|
|
class: this.menuClasses,
|
|
attrs: {
|
|
role: this.role,
|
|
'aria-labelledby': this.safeId(this.split ? '_BV_button_' : '_BV_toggle_')
|
|
},
|
|
on: {
|
|
mouseover: this.onMouseOver,
|
|
keydown: this.onKeydown // tab, up, down, esc
|
|
}
|
|
}, [this.$slots.default]);
|
|
return h('div', { attrs: { id: this.safeId() }, class: this.dropdownClasses }, [split, toggle, menu]);
|
|
},
|
|
|
|
props: {
|
|
split: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
toggleText: {
|
|
type: String,
|
|
default: 'Toggle Dropdown'
|
|
},
|
|
size: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
variant: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
menuClass: {
|
|
type: [String, Array],
|
|
default: null
|
|
},
|
|
toggleClass: {
|
|
type: [String, Array],
|
|
default: null
|
|
},
|
|
noCaret: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
role: {
|
|
type: String,
|
|
default: 'menu'
|
|
},
|
|
boundary: {
|
|
// String: `scrollParent`, `window` or `viewport`
|
|
// Object: HTML Element reference
|
|
type: [String, Object],
|
|
default: 'scrollParent'
|
|
}
|
|
},
|
|
computed: {
|
|
dropdownClasses: function dropdownClasses() {
|
|
var position = '';
|
|
// Position `static` is needed to allow menu to "breakout" of the scrollParent boundaries
|
|
// when boundary is anything other than `scrollParent`
|
|
// See https://github.com/twbs/bootstrap/issues/24251#issuecomment-341413786
|
|
if (this.boundary !== 'scrollParent' || !this.boundary) {
|
|
position = 'position-static';
|
|
}
|
|
return ['btn-group', 'b-dropdown', 'dropdown', this.dropup ? 'dropup' : '', this.visible ? 'show' : '', position];
|
|
},
|
|
menuClasses: function menuClasses() {
|
|
return ['dropdown-menu', {
|
|
'dropdown-menu-right': this.right,
|
|
'show': this.visible
|
|
}, this.menuClass];
|
|
},
|
|
toggleClasses: function toggleClasses() {
|
|
return [{
|
|
'dropdown-toggle': !this.noCaret || this.split,
|
|
'dropdown-toggle-split': this.split
|
|
}, this.toggleClass];
|
|
}
|
|
}
|
|
};
|
|
|
|
var props$l = propsFactory();
|
|
|
|
var bDropdownItem = {
|
|
functional: true,
|
|
props: props$l,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
return h(bLink, mergeData(data, {
|
|
props: props,
|
|
staticClass: 'dropdown-item',
|
|
attrs: { role: 'menuitem' }
|
|
}), children);
|
|
}
|
|
};
|
|
|
|
var props$m = {
|
|
disabled: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
};
|
|
|
|
var bDropdownItemButton = {
|
|
functional: true,
|
|
props: props$m,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
parent = _ref.parent,
|
|
children = _ref.children;
|
|
|
|
return h('button', mergeData(data, {
|
|
props: props,
|
|
staticClass: 'dropdown-item',
|
|
attrs: { role: 'menuitem', type: 'button', disabled: props.disabled },
|
|
on: {
|
|
click: function click(e) {
|
|
parent.$root.$emit('clicked::link', e);
|
|
}
|
|
}
|
|
}), children);
|
|
}
|
|
};
|
|
|
|
var props$n = {
|
|
id: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
tag: {
|
|
type: String,
|
|
default: 'h6'
|
|
}
|
|
};
|
|
|
|
var bDropdownHeader = {
|
|
functional: true,
|
|
props: props$n,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
return h(props.tag, mergeData(data, {
|
|
staticClass: 'dropdown-header',
|
|
attrs: { id: props.id || null }
|
|
}), children);
|
|
}
|
|
};
|
|
|
|
var props$o = {
|
|
tag: {
|
|
type: String,
|
|
default: 'div'
|
|
}
|
|
};
|
|
|
|
var bDropdownDivider = {
|
|
functional: true,
|
|
props: props$o,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data;
|
|
|
|
return h(props.tag, mergeData(data, {
|
|
staticClass: 'dropdown-divider',
|
|
attrs: { role: 'separator' }
|
|
}));
|
|
}
|
|
};
|
|
|
|
var components$b = {
|
|
bDropdown: bDropdown,
|
|
bDd: bDropdown,
|
|
bDropdownItem: bDropdownItem,
|
|
bDdItem: bDropdownItem,
|
|
bDropdownItemButton: bDropdownItemButton,
|
|
bDropdownItemBtn: bDropdownItemButton,
|
|
bDdItemButton: bDropdownItemButton,
|
|
bDdItemBtn: bDropdownItemButton,
|
|
bDropdownHeader: bDropdownHeader,
|
|
bDdHeader: bDropdownHeader,
|
|
bDropdownDivider: bDropdownDivider,
|
|
bDdDivider: bDropdownDivider
|
|
};
|
|
|
|
var VuePlugin$c = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$b);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$c);
|
|
|
|
var props$p = {
|
|
type: {
|
|
type: String,
|
|
default: 'iframe',
|
|
validator: function validator(str) {
|
|
return arrayIncludes(['iframe', 'embed', 'video', 'object', 'img', 'b-img', 'b-img-lazy'], str);
|
|
}
|
|
},
|
|
tag: {
|
|
type: String,
|
|
default: 'div'
|
|
},
|
|
aspect: {
|
|
type: String,
|
|
default: '16by9'
|
|
}
|
|
};
|
|
|
|
var bEmbed = {
|
|
functional: true,
|
|
props: props$p,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
return h(props.tag, {
|
|
ref: data.ref,
|
|
staticClass: 'embed-responsive',
|
|
class: defineProperty({}, 'embed-responsive-' + props.aspect, Boolean(props.aspect))
|
|
}, [h(props.type, mergeData(data, { ref: '', staticClass: 'embed-responsive-item' }), children)]);
|
|
}
|
|
};
|
|
|
|
var components$c = {
|
|
bEmbed: bEmbed
|
|
};
|
|
|
|
var VuePlugin$d = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$c);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$d);
|
|
|
|
var props$q = {
|
|
id: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
inline: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
novalidate: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
validated: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
};
|
|
|
|
var Form = {
|
|
functional: true,
|
|
props: props$q,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
return h('form', mergeData(data, {
|
|
class: {
|
|
'form-inline': props.inline,
|
|
'was-validated': props.validated
|
|
},
|
|
attrs: {
|
|
id: props.id,
|
|
novalidate: props.novalidate
|
|
}
|
|
}), children);
|
|
}
|
|
};
|
|
|
|
var props$r = {
|
|
id: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
tag: {
|
|
type: String,
|
|
default: 'small'
|
|
},
|
|
textVariant: {
|
|
type: String,
|
|
default: 'muted'
|
|
},
|
|
inline: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
};
|
|
|
|
var bFormText = {
|
|
functional: true,
|
|
props: props$r,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
return h(props.tag, mergeData(data, {
|
|
class: defineProperty({
|
|
'form-text': !props.inline
|
|
}, 'text-' + props.textVariant, Boolean(props.textVariant)),
|
|
attrs: {
|
|
id: props.id
|
|
}
|
|
}), children);
|
|
}
|
|
};
|
|
|
|
var props$s = {
|
|
id: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
tag: {
|
|
type: String,
|
|
default: 'div'
|
|
},
|
|
forceShow: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
};
|
|
|
|
var bFormInvalidFeedback = {
|
|
functional: true,
|
|
props: props$s,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
return h(props.tag, mergeData(data, {
|
|
staticClass: 'invalid-feedback',
|
|
class: { 'd-block': props.forceShow },
|
|
attrs: { id: props.id }
|
|
}), children);
|
|
}
|
|
};
|
|
|
|
var props$t = {
|
|
id: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
tag: {
|
|
type: String,
|
|
default: 'div'
|
|
},
|
|
forceShow: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
};
|
|
|
|
var bFormValidFeedback = {
|
|
functional: true,
|
|
props: props$t,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
return h(props.tag, mergeData(data, {
|
|
staticClass: 'valid-feedback',
|
|
class: { 'd-block': props.forceShow },
|
|
attrs: { id: props.id }
|
|
}), children);
|
|
}
|
|
};
|
|
|
|
var components$d = {
|
|
bForm: Form,
|
|
bFormRow: bFormRow,
|
|
bFormText: bFormText,
|
|
bFormInvalidFeedback: bFormInvalidFeedback,
|
|
bFormFeedback: bFormInvalidFeedback,
|
|
bFormValidFeedback: bFormValidFeedback
|
|
};
|
|
|
|
var VuePlugin$e = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$d);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$e);
|
|
|
|
/* Form control contextual state class computation
|
|
*
|
|
* Returned class is either 'is-valid' or 'is-invalid' based on the 'state' prop
|
|
* state can be one of five values:
|
|
* - true or 'valid' for is-valid
|
|
* - false or 'invalid' for is-invalid
|
|
* - null (or empty string) for no contextual state
|
|
*/
|
|
|
|
var formStateMixin = {
|
|
props: {
|
|
state: {
|
|
// true/'valid', false/'invalid', '',null
|
|
type: [Boolean, String],
|
|
default: null
|
|
}
|
|
},
|
|
computed: {
|
|
computedState: function computedState() {
|
|
var state = this.state;
|
|
if (state === true || state === 'valid') {
|
|
return true;
|
|
} else if (state === false || state === 'invalid') {
|
|
return false;
|
|
}
|
|
return null;
|
|
},
|
|
stateClass: function stateClass() {
|
|
var state = this.computedState;
|
|
if (state === true) {
|
|
return 'is-valid';
|
|
} else if (state === false) {
|
|
return 'is-invalid';
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
};
|
|
|
|
// Selector for finding firt input in the form-group
|
|
var SELECTOR = 'input:not(:disabled),textarea:not(:disabled),select:not(:disabled)';
|
|
|
|
var bFormGroup = {
|
|
mixins: [idMixin, formStateMixin],
|
|
components: { bFormRow: bFormRow, bFormText: bFormText, bFormInvalidFeedback: bFormInvalidFeedback, bFormValidFeedback: bFormValidFeedback },
|
|
render: function render(h) {
|
|
var $slots = this.$slots;
|
|
|
|
// Label / Legend
|
|
var legend = h(false);
|
|
if (this.hasLabel) {
|
|
var children = $slots['label'];
|
|
var legendTag = this.labelFor ? 'label' : 'legend';
|
|
var legendDomProps = children ? {} : { innerHTML: this.label };
|
|
var legendAttrs = { id: this.labelId, for: this.labelFor || null };
|
|
var legendClick = this.labelFor || this.labelSrOnly ? {} : { click: this.legendClick };
|
|
if (this.horizontal) {
|
|
// Horizontal layout with label
|
|
if (this.labelSrOnly) {
|
|
// SR Only we wrap label/legend in a div to preserve layout
|
|
children = h(legendTag, { class: ['sr-only'], attrs: legendAttrs, domProps: legendDomProps }, children);
|
|
legend = h('div', { class: this.labelLayoutClasses }, [children]);
|
|
} else {
|
|
legend = h(legendTag, {
|
|
class: [this.labelLayoutClasses, this.labelClasses],
|
|
attrs: legendAttrs,
|
|
domProps: legendDomProps,
|
|
on: legendClick
|
|
}, children);
|
|
}
|
|
} else {
|
|
// Vertical layout with label
|
|
legend = h(legendTag, {
|
|
class: this.labelSrOnly ? ['sr-only'] : this.labelClasses,
|
|
attrs: legendAttrs,
|
|
domProps: legendDomProps,
|
|
on: legendClick
|
|
}, children);
|
|
}
|
|
} else if (this.horizontal) {
|
|
// No label but has horizontal layout, so we need a spacer element for layout
|
|
legend = h('div', { class: this.labelLayoutClasses });
|
|
}
|
|
|
|
// Invalid feeback text (explicitly hidden if state is valid)
|
|
var invalidFeedback = h(false);
|
|
if (this.hasInvalidFeedback) {
|
|
var domProps = {};
|
|
if (!$slots['invalid-feedback'] && !$slots['feedback']) {
|
|
domProps = { innerHTML: this.invalidFeedback || this.feedback || '' };
|
|
}
|
|
invalidFeedback = h('b-form-invalid-feedback', {
|
|
props: {
|
|
id: this.invalidFeedbackId,
|
|
forceShow: this.computedState === false
|
|
},
|
|
attrs: {
|
|
role: 'alert',
|
|
'aria-live': 'assertive',
|
|
'aria-atomic': 'true'
|
|
},
|
|
domProps: domProps
|
|
}, $slots['invalid-feedback'] || $slots['feedback']);
|
|
}
|
|
|
|
// Valid feeback text (explicitly hidden if state is invalid)
|
|
var validFeedback = h(false);
|
|
if (this.hasValidFeedback) {
|
|
var _domProps = $slots['valid-feedback'] ? {} : { innerHTML: this.validFeedback || '' };
|
|
validFeedback = h('b-form-valid-feedback', {
|
|
props: {
|
|
id: this.validFeedbackId,
|
|
forceShow: this.computedState === true
|
|
},
|
|
attrs: {
|
|
role: 'alert',
|
|
'aria-live': 'assertive',
|
|
'aria-atomic': 'true'
|
|
},
|
|
domProps: _domProps
|
|
}, $slots['valid-feedback']);
|
|
}
|
|
|
|
// Form help text (description)
|
|
var description = h(false);
|
|
if (this.hasDescription) {
|
|
var _domProps2 = $slots['description'] ? {} : { innerHTML: this.description || '' };
|
|
description = h('b-form-text', { attrs: { id: this.descriptionId }, domProps: _domProps2 }, $slots['description']);
|
|
}
|
|
|
|
// Build content layout
|
|
var content = h('div', {
|
|
ref: 'content',
|
|
class: this.inputLayoutClasses,
|
|
attrs: this.labelFor ? {} : { role: 'group', 'aria-labelledby': this.labelId }
|
|
}, [$slots['default'], invalidFeedback, validFeedback, description]);
|
|
|
|
// Generate main form-group wrapper
|
|
return h(this.labelFor ? 'div' : 'fieldset', {
|
|
class: this.groupClasses,
|
|
attrs: {
|
|
id: this.safeId(),
|
|
disabled: this.disabled,
|
|
role: 'group',
|
|
'aria-invalid': this.computedState === false ? 'true' : null,
|
|
'aria-labelledby': this.labelId,
|
|
'aria-describedby': this.labelFor ? null : this.describedByIds
|
|
}
|
|
}, this.horizontal ? [h('b-form-row', {}, [legend, content])] : [legend, content]);
|
|
},
|
|
|
|
props: {
|
|
horizontal: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
labelCols: {
|
|
type: [Number, String],
|
|
default: 3,
|
|
validator: function validator(value) {
|
|
if (Number(value) >= 1 && Number(value) <= 11) {
|
|
return true;
|
|
}
|
|
warn('b-form-group: label-cols must be a value between 1 and 11');
|
|
return false;
|
|
}
|
|
},
|
|
breakpoint: {
|
|
type: String,
|
|
default: 'sm'
|
|
},
|
|
labelTextAlign: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
label: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
labelFor: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
labelSize: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
labelSrOnly: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
labelClass: {
|
|
type: [String, Array],
|
|
default: null
|
|
},
|
|
description: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
invalidFeedback: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
feedback: {
|
|
// Deprecated in favor of invalid-feedback
|
|
type: String,
|
|
default: null
|
|
},
|
|
validFeedback: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
validated: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
},
|
|
computed: {
|
|
groupClasses: function groupClasses() {
|
|
return ['b-form-group', 'form-group', this.validated ? 'was-validated' : null, this.stateClass];
|
|
},
|
|
labelClasses: function labelClasses() {
|
|
return ['col-form-label', this.labelSize ? 'col-form-label-' + this.labelSize : null, this.labelTextAlign ? 'text-' + this.labelTextAlign : null, this.horizontal ? null : 'pt-0', this.labelClass];
|
|
},
|
|
labelLayoutClasses: function labelLayoutClasses() {
|
|
return [this.horizontal ? 'col-' + this.breakpoint + '-' + this.labelCols : null];
|
|
},
|
|
inputLayoutClasses: function inputLayoutClasses() {
|
|
return [this.horizontal ? 'col-' + this.breakpoint + '-' + (12 - Number(this.labelCols)) : null];
|
|
},
|
|
hasLabel: function hasLabel() {
|
|
return this.label || this.$slots['label'];
|
|
},
|
|
hasDescription: function hasDescription() {
|
|
return this.description || this.$slots['description'];
|
|
},
|
|
hasInvalidFeedback: function hasInvalidFeedback() {
|
|
if (this.computedState === true) {
|
|
// If the form-group state is explicityly valid, we return false
|
|
return false;
|
|
}
|
|
return this.invalidFeedback || this.feedback || this.$slots['invalid-feedback'] || this.$slots['feedback'];
|
|
},
|
|
hasValidFeedback: function hasValidFeedback() {
|
|
if (this.computedState === false) {
|
|
// If the form-group state is explicityly invalid, we return false
|
|
return false;
|
|
}
|
|
return this.validFeedback || this.$slots['valid-feedback'];
|
|
},
|
|
labelId: function labelId() {
|
|
return this.hasLabel ? this.safeId('_BV_label_') : null;
|
|
},
|
|
descriptionId: function descriptionId() {
|
|
return this.hasDescription ? this.safeId('_BV_description_') : null;
|
|
},
|
|
invalidFeedbackId: function invalidFeedbackId() {
|
|
return this.hasInvalidFeedback ? this.safeId('_BV_feedback_invalid_') : null;
|
|
},
|
|
validFeedbackId: function validFeedbackId() {
|
|
return this.hasValidFeedback ? this.safeId('_BV_feedback_valid_') : null;
|
|
},
|
|
describedByIds: function describedByIds() {
|
|
return [this.descriptionId, this.invalidFeedbackId, this.validFeedbackId].filter(function (i) {
|
|
return i;
|
|
}).join(' ') || null;
|
|
}
|
|
},
|
|
watch: {
|
|
describedByIds: function describedByIds(add, remove) {
|
|
if (add !== remove) {
|
|
this.setInputDescribedBy(add, remove);
|
|
}
|
|
}
|
|
},
|
|
methods: {
|
|
legendClick: function legendClick(evt) {
|
|
var tagName = evt.target ? evt.target.tagName : '';
|
|
if (/^(input|select|textarea|label)$/i.test(tagName)) {
|
|
// If clicked an input inside legend, we just let the default happen
|
|
return;
|
|
}
|
|
// Focus the first non-disabled visible input when the legend element is clicked
|
|
var inputs = selectAll(SELECTOR, this.$refs.content).filter(isVisible);
|
|
if (inputs[0] && inputs[0].focus) {
|
|
inputs[0].focus();
|
|
}
|
|
},
|
|
setInputDescribedBy: function setInputDescribedBy(add, remove) {
|
|
// Sets the `aria-describedby` attribute on the input if label-for is set.
|
|
// Optionally accepts a string of IDs to remove as the second parameter
|
|
if (this.labelFor && typeof document !== 'undefined') {
|
|
var input = select('#' + this.labelFor, this.$refs.content);
|
|
if (input) {
|
|
var adb = 'aria-describedby';
|
|
var ids = (getAttr(input, adb) || '').split(/\s+/);
|
|
remove = (remove || '').split(/\s+/);
|
|
// Update ID list, preserving any original IDs
|
|
ids = ids.filter(function (id) {
|
|
return remove.indexOf(id) === -1;
|
|
}).concat(add || '').join(' ').trim();
|
|
if (ids) {
|
|
setAttr(input, adb, ids);
|
|
} else {
|
|
removeAttr(input, adb);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
mounted: function mounted() {
|
|
var _this = this;
|
|
|
|
this.$nextTick(function () {
|
|
// Set the adia-describedby IDs on the input specified by label-for
|
|
// We do this in a nextTick to ensure the children have finished rendering
|
|
_this.setInputDescribedBy(_this.describedByIds);
|
|
});
|
|
}
|
|
};
|
|
|
|
var components$e = {
|
|
bFormGroup: bFormGroup,
|
|
bFormFieldset: bFormGroup
|
|
};
|
|
|
|
var VuePlugin$f = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$e);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$f);
|
|
|
|
/*
|
|
* form-radio & form-check mixin
|
|
*
|
|
*/
|
|
|
|
var formRadioCheckMixin = {
|
|
data: function data() {
|
|
return {
|
|
localChecked: this.checked,
|
|
hasFocus: false
|
|
};
|
|
},
|
|
|
|
model: {
|
|
prop: 'checked',
|
|
event: 'input'
|
|
},
|
|
props: {
|
|
value: {},
|
|
checked: {
|
|
// This is the model, except when in group mode
|
|
},
|
|
buttonVariant: {
|
|
// Only applicable when rendered with button style
|
|
type: String,
|
|
default: null
|
|
}
|
|
},
|
|
computed: {
|
|
computedLocalChecked: {
|
|
get: function get() {
|
|
if (this.is_Child) {
|
|
return this.$parent.localChecked;
|
|
} else {
|
|
return this.localChecked;
|
|
}
|
|
},
|
|
set: function set(val) {
|
|
if (this.is_Child) {
|
|
this.$parent.localChecked = val;
|
|
} else {
|
|
this.localChecked = val;
|
|
}
|
|
}
|
|
},
|
|
is_Child: function is_Child() {
|
|
return Boolean(this.$parent && this.$parent.is_RadioCheckGroup);
|
|
},
|
|
is_Disabled: function is_Disabled() {
|
|
// Child can be disabled while parent isn't
|
|
return Boolean(this.is_Child ? this.$parent.disabled || this.disabled : this.disabled);
|
|
},
|
|
is_Required: function is_Required() {
|
|
return Boolean(this.is_Child ? this.$parent.required : this.required);
|
|
},
|
|
is_Plain: function is_Plain() {
|
|
return Boolean(this.is_Child ? this.$parent.plain : this.plain);
|
|
},
|
|
is_Custom: function is_Custom() {
|
|
return !this.is_Plain;
|
|
},
|
|
get_Size: function get_Size() {
|
|
return this.is_Child ? this.$parent.size : this.size;
|
|
},
|
|
get_State: function get_State() {
|
|
// This is a tri-state prop (true, false, null)
|
|
if (this.is_Child && typeof this.$parent.get_State === 'boolean') {
|
|
return this.$parent.get_State;
|
|
}
|
|
return this.computedState;
|
|
},
|
|
get_StateClass: function get_StateClass() {
|
|
// This is a tri-state prop (true, false, null)
|
|
return typeof this.get_State === 'boolean' ? this.get_State ? 'is-valid' : 'is-invalid' : '';
|
|
},
|
|
is_Stacked: function is_Stacked() {
|
|
return Boolean(this.is_Child && this.$parent.stacked);
|
|
},
|
|
is_Inline: function is_Inline() {
|
|
return !this.is_Stacked;
|
|
},
|
|
is_ButtonMode: function is_ButtonMode() {
|
|
return Boolean(this.is_Child && this.$parent.buttons);
|
|
},
|
|
get_ButtonVariant: function get_ButtonVariant() {
|
|
// Local variant trumps parent variant
|
|
return this.buttonVariant || (this.is_Child ? this.$parent.buttonVariant : null) || 'secondary';
|
|
},
|
|
get_Name: function get_Name() {
|
|
return (this.is_Child ? this.$parent.name || this.$parent.safeId() : this.name) || null;
|
|
},
|
|
buttonClasses: function buttonClasses() {
|
|
// Same for radio & check
|
|
return ['btn', 'btn-' + this.get_ButtonVariant, this.get_Size ? 'btn-' + this.get_Size : '',
|
|
// 'disabled' class makes "button" look disabled
|
|
this.is_Disabled ? 'disabled' : '',
|
|
// 'active' class makes "button" look pressed
|
|
this.is_Checked ? 'active' : '',
|
|
// Focus class makes button look focused
|
|
this.hasFocus ? 'focus' : ''];
|
|
}
|
|
},
|
|
methods: {
|
|
handleFocus: function handleFocus(evt) {
|
|
// When in buttons mode, we need to add 'focus' class to label when radio focused
|
|
if (this.is_ButtonMode && evt.target) {
|
|
if (evt.type === 'focus') {
|
|
this.hasFocus = true;
|
|
} else if (evt.type === 'blur') {
|
|
this.hasFocus = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
var formMixin = {
|
|
props: {
|
|
name: {
|
|
type: String
|
|
},
|
|
id: {
|
|
type: String
|
|
},
|
|
disabled: {
|
|
type: Boolean
|
|
},
|
|
required: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
}
|
|
};
|
|
|
|
var formSizeMixin = {
|
|
props: {
|
|
size: {
|
|
type: String,
|
|
default: null
|
|
}
|
|
},
|
|
computed: {
|
|
sizeFormClass: function sizeFormClass() {
|
|
return [this.size ? "form-control-" + this.size : null];
|
|
},
|
|
sizeBtnClass: function sizeBtnClass() {
|
|
return [this.size ? "btn-" + this.size : null];
|
|
}
|
|
}
|
|
};
|
|
|
|
var formCustomMixin = {
|
|
computed: {
|
|
custom: function custom() {
|
|
return !this.plain;
|
|
}
|
|
},
|
|
props: {
|
|
plain: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Quick object check - this is primarily used to tell
|
|
* Objects from primitive values when we know the value
|
|
* is a JSON-compliant type.
|
|
*/
|
|
function isObject(obj) {
|
|
return obj !== null && (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object';
|
|
}
|
|
|
|
/**
|
|
* Check if two values are loosely equal - that is,
|
|
* if they are plain objects, do they have the same shape?
|
|
* Returns boolean true or false
|
|
*/
|
|
function looseEqual(a, b) {
|
|
if (a === b) return true;
|
|
var isObjectA = isObject(a);
|
|
var isObjectB = isObject(b);
|
|
if (isObjectA && isObjectB) {
|
|
try {
|
|
var isArrayA = isArray(a);
|
|
var isArrayB = isArray(b);
|
|
if (isArrayA && isArrayB) {
|
|
return a.length === b.length && a.every(function (e, i) {
|
|
return looseEqual(e, b[i]);
|
|
});
|
|
} else if (!isArrayA && !isArrayB) {
|
|
var keysA = keys(a);
|
|
var keysB = keys(b);
|
|
return keysA.length === keysB.length && keysA.every(function (key) {
|
|
return looseEqual(a[key], b[key]);
|
|
});
|
|
} else {
|
|
return false;
|
|
}
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
} else if (!isObjectA && !isObjectB) {
|
|
return String(a) === String(b);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
var bFormCheckbox = {
|
|
mixins: [idMixin, formRadioCheckMixin, formMixin, formSizeMixin, formStateMixin, formCustomMixin],
|
|
render: function render(h) {
|
|
var _this = this;
|
|
|
|
var input = h('input', {
|
|
ref: 'check',
|
|
class: [this.is_ButtonMode ? '' : this.is_Plain ? 'form-check-input' : 'custom-control-input', this.get_StateClass],
|
|
directives: [{
|
|
name: 'model',
|
|
rawName: 'v-model',
|
|
value: this.computedLocalChecked,
|
|
expression: 'computedLocalChecked'
|
|
}],
|
|
attrs: {
|
|
id: this.safeId(),
|
|
type: 'checkbox',
|
|
name: this.get_Name,
|
|
disabled: this.is_Disabled,
|
|
required: this.is_Required,
|
|
autocomplete: 'off',
|
|
'true-value': this.value,
|
|
'false-value': this.uncheckedValue,
|
|
'aria-required': this.is_Required ? 'true' : null
|
|
},
|
|
domProps: { value: this.value, checked: this.is_Checked },
|
|
on: {
|
|
focus: this.handleFocus,
|
|
blur: this.handleFocus,
|
|
change: this.emitChange,
|
|
__c: function __c(evt) {
|
|
var $$a = _this.computedLocalChecked;
|
|
var $$el = evt.target;
|
|
if (isArray($$a)) {
|
|
// Multiple checkbox
|
|
var $$v = _this.value;
|
|
var $$i = _this._i($$a, $$v); // Vue's 'loose' Array.indexOf
|
|
if ($$el.checked) {
|
|
// Append value to array
|
|
$$i < 0 && (_this.computedLocalChecked = $$a.concat([$$v]));
|
|
} else {
|
|
// Remove value from array
|
|
$$i > -1 && (_this.computedLocalChecked = $$a.slice(0, $$i).concat($$a.slice($$i + 1)));
|
|
}
|
|
} else {
|
|
// Single checkbox
|
|
_this.computedLocalChecked = $$el.checked ? _this.value : _this.uncheckedValue;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
var description = h(this.is_ButtonMode ? 'span' : 'label', {
|
|
class: this.is_ButtonMode ? null : this.is_Plain ? 'form-check-label' : 'custom-control-label',
|
|
attrs: { for: this.is_ButtonMode ? null : this.safeId() }
|
|
}, [this.$slots.default]);
|
|
|
|
if (!this.is_ButtonMode) {
|
|
return h('div', {
|
|
class: [this.is_Plain ? 'form-check' : this.labelClasses, { 'form-check-inline': this.is_Plain && !this.is_Stacked }, { 'custom-control-inline': !this.is_Plain && !this.is_Stacked }]
|
|
}, [input, description]);
|
|
} else {
|
|
return h('label', { class: [this.buttonClasses] }, [input, description]);
|
|
}
|
|
},
|
|
|
|
props: {
|
|
value: {
|
|
default: true
|
|
},
|
|
uncheckedValue: {
|
|
// Not applicable in multi-check mode
|
|
default: false
|
|
},
|
|
indeterminate: {
|
|
// Not applicable in multi-check mode
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
},
|
|
computed: {
|
|
labelClasses: function labelClasses() {
|
|
return ['custom-control', 'custom-checkbox', this.get_Size ? 'form-control-' + this.get_Size : '', this.get_StateClass];
|
|
},
|
|
is_Checked: function is_Checked() {
|
|
var checked = this.computedLocalChecked;
|
|
if (isArray(checked)) {
|
|
for (var i = 0; i < checked.length; i++) {
|
|
if (looseEqual(checked[i], this.value)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
} else {
|
|
return looseEqual(checked, this.value);
|
|
}
|
|
}
|
|
},
|
|
watch: {
|
|
computedLocalChecked: function computedLocalChecked(newVal, oldVal) {
|
|
if (looseEqual(newVal, oldVal)) {
|
|
return;
|
|
}
|
|
this.$emit('input', newVal);
|
|
this.$emit('update:indeterminate', this.$refs.check.indeterminate);
|
|
},
|
|
checked: function checked(newVal, oldVal) {
|
|
if (this.is_Child || looseEqual(newVal, oldVal)) {
|
|
return;
|
|
}
|
|
this.computedLocalChecked = newVal;
|
|
},
|
|
indeterminate: function indeterminate(newVal, oldVal) {
|
|
this.setIndeterminate(newVal);
|
|
}
|
|
},
|
|
methods: {
|
|
emitChange: function emitChange(_ref) {
|
|
var checked = _ref.target.checked;
|
|
|
|
// Change event is only fired via user interaction
|
|
// And we only emit the value of this checkbox
|
|
if (this.is_Child || isArray(this.computedLocalChecked)) {
|
|
this.$emit('change', checked ? this.value : null);
|
|
if (this.is_Child) {
|
|
// If we are a child of form-checkbbox-group, emit change on parent
|
|
this.$parent.$emit('change', this.computedLocalChecked);
|
|
}
|
|
} else {
|
|
// Single radio mode supports unchecked value
|
|
this.$emit('change', checked ? this.value : this.uncheckedValue);
|
|
}
|
|
this.$emit('update:indeterminate', this.$refs.check.indeterminate);
|
|
},
|
|
setIndeterminate: function setIndeterminate(state) {
|
|
// Indeterminate only supported in single checkbox mode
|
|
if (this.is_Child || isArray(this.computedLocalChecked)) {
|
|
return;
|
|
}
|
|
this.$refs.check.indeterminate = state;
|
|
// Emit update event to prop
|
|
this.$emit('update:indeterminate', this.$refs.check.indeterminate);
|
|
}
|
|
},
|
|
mounted: function mounted() {
|
|
// Set initial indeterminate state
|
|
this.setIndeterminate(this.indeterminate);
|
|
}
|
|
};
|
|
|
|
function isObject$1(obj) {
|
|
return obj && {}.toString.call(obj) === '[object Object]';
|
|
}
|
|
|
|
var formOptionsMixin = {
|
|
|
|
props: {
|
|
options: {
|
|
type: [Array, Object],
|
|
default: function _default() {
|
|
return [];
|
|
}
|
|
},
|
|
valueField: {
|
|
type: String,
|
|
default: 'value'
|
|
},
|
|
textField: {
|
|
type: String,
|
|
default: 'text'
|
|
},
|
|
disabledField: {
|
|
type: String,
|
|
default: 'disabled'
|
|
}
|
|
},
|
|
computed: {
|
|
formOptions: function formOptions() {
|
|
var options = this.options;
|
|
|
|
var valueField = this.valueField;
|
|
var textField = this.textField;
|
|
var disabledField = this.disabledField;
|
|
|
|
if (isArray(options)) {
|
|
// Normalize flat-ish arrays to Array of Objects
|
|
return options.map(function (option) {
|
|
if (isObject$1(option)) {
|
|
return {
|
|
value: option[valueField],
|
|
text: String(option[textField]),
|
|
disabled: option[disabledField] || false
|
|
};
|
|
}
|
|
return {
|
|
value: option,
|
|
text: String(option),
|
|
disabled: false
|
|
};
|
|
});
|
|
} else {
|
|
// options is Object
|
|
// Normalize Objects to Array of Objects
|
|
return keys(options).map(function (key) {
|
|
var option = options[key] || {};
|
|
if (isObject$1(option)) {
|
|
var value = option[valueField];
|
|
var text = option[textField];
|
|
return {
|
|
value: typeof value === 'undefined' ? key : value,
|
|
text: typeof text === 'undefined' ? key : String(text),
|
|
disabled: option[disabledField] || false
|
|
};
|
|
}
|
|
return {
|
|
value: key,
|
|
text: String(option),
|
|
disabled: false
|
|
};
|
|
});
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
var bFormCheckboxGroup = {
|
|
mixins: [idMixin, formMixin, formSizeMixin, formStateMixin, formCustomMixin, formOptionsMixin],
|
|
components: { bFormCheckbox: bFormCheckbox },
|
|
render: function render(h) {
|
|
var _this = this;
|
|
|
|
var $slots = this.$slots;
|
|
|
|
var checks = this.formOptions.map(function (option, idx) {
|
|
return h('b-form-checkbox', {
|
|
key: 'check_' + idx + '_opt',
|
|
props: {
|
|
id: _this.safeId('_BV_check_' + idx + '_opt_'),
|
|
name: _this.name,
|
|
value: option.value,
|
|
required: _this.name && _this.required,
|
|
disabled: option.disabled
|
|
}
|
|
}, [h('span', { domProps: { innerHTML: option.text } })]);
|
|
});
|
|
return h('div', {
|
|
class: this.groupClasses,
|
|
attrs: {
|
|
id: this.safeId(),
|
|
role: 'group',
|
|
tabindex: '-1',
|
|
'aria-required': this.required ? 'true' : null,
|
|
'aria-invalid': this.computedAriaInvalid
|
|
}
|
|
}, [$slots.first, checks, $slots.default]);
|
|
},
|
|
data: function data() {
|
|
return {
|
|
localChecked: this.checked || [],
|
|
// Flag for children
|
|
is_RadioCheckGroup: true
|
|
};
|
|
},
|
|
|
|
model: {
|
|
prop: 'checked',
|
|
event: 'input'
|
|
},
|
|
props: {
|
|
checked: {
|
|
type: [String, Number, Object, Array, Boolean],
|
|
default: null
|
|
},
|
|
validated: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
ariaInvalid: {
|
|
type: [Boolean, String],
|
|
default: false
|
|
},
|
|
stacked: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
buttons: {
|
|
// Render as button style
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
buttonVariant: {
|
|
// Only applicable when rendered with button style
|
|
type: String,
|
|
default: 'secondary'
|
|
}
|
|
},
|
|
watch: {
|
|
checked: function checked(newVal, oldVal) {
|
|
this.localChecked = this.checked;
|
|
},
|
|
localChecked: function localChecked(newVal, oldVal) {
|
|
this.$emit('input', newVal);
|
|
}
|
|
},
|
|
computed: {
|
|
groupClasses: function groupClasses() {
|
|
if (this.buttons) {
|
|
return ['btn-group-toggle', this.stacked ? 'btn-group-vertical' : 'btn-group', this.size ? 'btn-group-' + this.size : '', this.validated ? 'was-validated' : ''];
|
|
}
|
|
return [this.sizeFormClass, this.stacked && this.custom ? 'custom-controls-stacked' : '', this.validated ? 'was-validated' : ''];
|
|
},
|
|
computedAriaInvalid: function computedAriaInvalid() {
|
|
if (this.ariaInvalid === true || this.ariaInvalid === 'true' || this.ariaInvalid === '') {
|
|
return 'true';
|
|
}
|
|
return this.get_State === false ? 'true' : null;
|
|
},
|
|
get_State: function get_State() {
|
|
// Child radios sniff this value
|
|
return this.computedState;
|
|
}
|
|
}
|
|
};
|
|
|
|
var components$f = {
|
|
bFormCheckbox: bFormCheckbox,
|
|
bCheckbox: bFormCheckbox,
|
|
bCheck: bFormCheckbox,
|
|
bFormCheckboxGroup: bFormCheckboxGroup,
|
|
bCheckboxGroup: bFormCheckboxGroup,
|
|
bCheckGroup: bFormCheckboxGroup
|
|
};
|
|
|
|
var VuePlugin$g = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$f);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$g);
|
|
|
|
var bFormRadio = {
|
|
mixins: [idMixin, formRadioCheckMixin, formMixin, formStateMixin],
|
|
render: function render(h) {
|
|
var _this = this;
|
|
|
|
var input = h('input', {
|
|
ref: 'radio',
|
|
class: [this.is_ButtonMode ? '' : this.is_Plain ? 'form-check-input' : 'custom-control-input', this.get_StateClass],
|
|
directives: [{
|
|
name: 'model',
|
|
rawName: 'v-model',
|
|
value: this.computedLocalChecked,
|
|
expression: 'computedLocalChecked'
|
|
}],
|
|
attrs: {
|
|
id: this.safeId(),
|
|
type: 'radio',
|
|
name: this.get_Name,
|
|
required: this.get_Name && this.is_Required,
|
|
disabled: this.is_Disabled,
|
|
autocomplete: 'off'
|
|
},
|
|
domProps: {
|
|
value: this.value,
|
|
checked: looseEqual(this.computedLocalChecked, this.value)
|
|
},
|
|
on: {
|
|
focus: this.handleFocus,
|
|
blur: this.handleFocus,
|
|
change: this.emitChange,
|
|
__c: function __c(evt) {
|
|
_this.computedLocalChecked = _this.value;
|
|
}
|
|
}
|
|
});
|
|
|
|
var description = h(this.is_ButtonMode ? 'span' : 'label', {
|
|
class: this.is_ButtonMode ? null : this.is_Plain ? 'form-check-label' : 'custom-control-label',
|
|
attrs: { for: this.is_ButtonMode ? null : this.safeId() }
|
|
}, [this.$slots.default]);
|
|
|
|
if (!this.is_ButtonMode) {
|
|
return h('div', {
|
|
class: [this.is_Plain ? 'form-check' : this.labelClasses, { 'form-check-inline': this.is_Plain && !this.is_Stacked }, { 'custom-control-inline': !this.is_Plain && !this.is_Stacked }]
|
|
}, [input, description]);
|
|
} else {
|
|
return h('label', { class: [this.buttonClasses] }, [input, description]);
|
|
}
|
|
},
|
|
|
|
watch: {
|
|
// Radio Groups can only have a single value, so our watchers are simple
|
|
checked: function checked(newVal, oldVal) {
|
|
this.computedLocalChecked = newVal;
|
|
},
|
|
computedLocalChceked: function computedLocalChceked(newVal, oldVal) {
|
|
this.$emit('input', this.computedLocalChceked);
|
|
}
|
|
},
|
|
computed: {
|
|
is_Checked: function is_Checked() {
|
|
return looseEqual(this.value, this.computedLocalChecked);
|
|
},
|
|
labelClasses: function labelClasses() {
|
|
// Specific to radio
|
|
return [this.get_Size ? 'form-control-' + this.get_Size : '', 'custom-control', 'custom-radio', this.get_StateClass];
|
|
}
|
|
},
|
|
methods: {
|
|
emitChange: function emitChange(_ref) {
|
|
var checked = _ref.target.checked;
|
|
|
|
// Change is only emitted on user interaction
|
|
this.$emit('change', checked ? this.value : null);
|
|
// If this is a child of form-radio-group, we emit a change event on it as well
|
|
if (this.is_Child) {
|
|
this.$parent.$emit('change', this.computedLocalChecked);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
var bFormRadioGroup = {
|
|
mixins: [idMixin, formMixin, formSizeMixin, formStateMixin, formCustomMixin, formOptionsMixin],
|
|
components: { bFormRadio: bFormRadio },
|
|
render: function render(h) {
|
|
var _this = this;
|
|
|
|
var $slots = this.$slots;
|
|
|
|
var radios = this.formOptions.map(function (option, idx) {
|
|
return h('b-form-radio', {
|
|
key: 'radio_' + idx + '_opt',
|
|
props: {
|
|
id: _this.safeId('_BV_radio_' + idx + '_opt_'),
|
|
name: _this.name,
|
|
value: option.value,
|
|
required: Boolean(_this.name && _this.required),
|
|
disabled: option.disabled
|
|
}
|
|
}, [h('span', { domProps: { innerHTML: option.text } })]);
|
|
});
|
|
return h('div', {
|
|
class: this.groupClasses,
|
|
attrs: {
|
|
id: this.safeId(),
|
|
role: 'radiogroup',
|
|
tabindex: '-1',
|
|
'aria-required': this.required ? 'true' : null,
|
|
'aria-invalid': this.computedAriaInvalid
|
|
}
|
|
}, [$slots.first, radios, $slots.default]);
|
|
},
|
|
data: function data() {
|
|
return {
|
|
localChecked: this.checked,
|
|
// Flag for children
|
|
is_RadioCheckGroup: true
|
|
};
|
|
},
|
|
|
|
model: {
|
|
prop: 'checked',
|
|
event: 'input'
|
|
},
|
|
props: {
|
|
checked: {
|
|
type: [String, Object, Number, Boolean],
|
|
default: null
|
|
},
|
|
validated: {
|
|
// Used for applying hte `was-validated` class to the group
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
ariaInvalid: {
|
|
type: [Boolean, String],
|
|
default: false
|
|
},
|
|
stacked: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
buttons: {
|
|
// Render as button style
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
buttonVariant: {
|
|
// Only applicable when rendered with button style
|
|
type: String,
|
|
default: 'secondary'
|
|
}
|
|
},
|
|
watch: {
|
|
checked: function checked(newVal, oldVal) {
|
|
this.localChecked = this.checked;
|
|
},
|
|
localChecked: function localChecked(newVal, oldVal) {
|
|
this.$emit('input', newVal);
|
|
}
|
|
},
|
|
computed: {
|
|
groupClasses: function groupClasses() {
|
|
if (this.buttons) {
|
|
return ['btn-group-toggle', this.stacked ? 'btn-group-vertical' : 'btn-group', this.size ? 'btn-group-' + this.size : '', this.validated ? 'was-validated' : ''];
|
|
}
|
|
return [this.sizeFormClass, this.stacked && this.custom ? 'custom-controls-stacked' : '', this.validated ? 'was-validated' : ''];
|
|
},
|
|
computedAriaInvalid: function computedAriaInvalid() {
|
|
if (this.ariaInvalid === true || this.ariaInvalid === 'true' || this.ariaInvalid === '') {
|
|
return 'true';
|
|
}
|
|
return this.get_State === false ? 'true' : null;
|
|
},
|
|
get_State: function get_State() {
|
|
// Required by child radios
|
|
return this.computedState;
|
|
}
|
|
}
|
|
};
|
|
|
|
var components$g = {
|
|
bFormRadio: bFormRadio,
|
|
bRadio: bFormRadio,
|
|
bFormRadioGroup: bFormRadioGroup,
|
|
bRadioGroup: bFormRadioGroup
|
|
};
|
|
|
|
var VuePlugin$h = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$g);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$h);
|
|
|
|
// Valid supported input types
|
|
var TYPES = ['text', 'password', 'email', 'number', 'url', 'tel', 'search', 'range', 'color', 'date', 'time', 'datetime', 'datetime-local', 'month', 'week'];
|
|
|
|
var bFormInput = {
|
|
mixins: [idMixin, formMixin, formSizeMixin, formStateMixin],
|
|
render: function render(h) {
|
|
return h('input', {
|
|
ref: 'input',
|
|
class: this.inputClass,
|
|
attrs: {
|
|
id: this.safeId(),
|
|
name: this.name,
|
|
type: this.localType,
|
|
disabled: this.disabled,
|
|
required: this.required,
|
|
readonly: this.readonly || this.plaintext,
|
|
placeholder: this.placeholder,
|
|
autocomplete: this.autocomplete || null,
|
|
'aria-required': this.required ? 'true' : null,
|
|
'aria-invalid': this.computedAriaInvalid,
|
|
value: this.value
|
|
},
|
|
on: {
|
|
input: this.onInput,
|
|
change: this.onChange
|
|
}
|
|
});
|
|
},
|
|
|
|
props: {
|
|
value: {
|
|
default: null
|
|
},
|
|
type: {
|
|
type: String,
|
|
default: 'text',
|
|
validator: function validator(type) {
|
|
return arrayIncludes(TYPES, type);
|
|
}
|
|
},
|
|
ariaInvalid: {
|
|
type: [Boolean, String],
|
|
default: false
|
|
},
|
|
readonly: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
plaintext: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
autocomplete: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
placeholder: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
formatter: {
|
|
type: Function
|
|
},
|
|
lazyFormatter: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
},
|
|
computed: {
|
|
localType: function localType() {
|
|
// We only allow certain types
|
|
return arrayIncludes(TYPES, this.type) ? this.type : 'text';
|
|
},
|
|
inputClass: function inputClass() {
|
|
return [this.plaintext ? 'form-control-plaintext' : 'form-control', this.sizeFormClass, this.stateClass];
|
|
},
|
|
computedAriaInvalid: function computedAriaInvalid() {
|
|
if (!this.ariaInvalid || this.ariaInvalid === 'false') {
|
|
// this.ariaInvalid is null or false or 'false'
|
|
return this.computedState === false ? 'true' : null;
|
|
}
|
|
if (this.ariaInvalid === true) {
|
|
// User wants explicit aria-invalid=true
|
|
return 'true';
|
|
}
|
|
// Most likely a string value (which could be 'true')
|
|
return this.ariaInvalid;
|
|
}
|
|
},
|
|
mounted: function mounted() {
|
|
if (this.value) {
|
|
var fValue = this.format(this.value, null);
|
|
this.setValue(fValue);
|
|
}
|
|
},
|
|
|
|
watch: {
|
|
value: function value(newVal) {
|
|
if (this.lazyFormatter) {
|
|
this.setValue(newVal);
|
|
} else {
|
|
var fValue = this.format(newVal, null);
|
|
this.setValue(fValue);
|
|
}
|
|
}
|
|
},
|
|
methods: {
|
|
format: function format(value, e) {
|
|
if (this.formatter) {
|
|
return this.formatter(value, e);
|
|
}
|
|
return value;
|
|
},
|
|
setValue: function setValue(value) {
|
|
this.$emit('input', value);
|
|
// When formatter removes last typed character, value of text input should update to formatted value
|
|
this.$refs.input.value = value;
|
|
},
|
|
onInput: function onInput(evt) {
|
|
var value = evt.target.value;
|
|
|
|
if (this.lazyFormatter) {
|
|
this.setValue(value);
|
|
} else {
|
|
var fValue = this.format(value, evt);
|
|
this.setValue(fValue);
|
|
}
|
|
},
|
|
onChange: function onChange(evt) {
|
|
var fValue = this.format(evt.target.value, evt);
|
|
this.setValue(fValue);
|
|
this.$emit('change', fValue);
|
|
},
|
|
focus: function focus() {
|
|
if (!this.disabled) {
|
|
this.$el.focus();
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
var components$h = {
|
|
bFormInput: bFormInput,
|
|
bInput: bFormInput
|
|
};
|
|
|
|
var VuePlugin$i = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$h);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$i);
|
|
|
|
var bFormTextarea = {
|
|
mixins: [idMixin, formMixin, formSizeMixin, formStateMixin],
|
|
render: function render(h) {
|
|
var _this = this;
|
|
|
|
return h('textarea', {
|
|
ref: 'input',
|
|
class: this.inputClass,
|
|
style: this.inputStyle,
|
|
directives: [{
|
|
name: 'model',
|
|
rawName: 'v-model',
|
|
value: this.localValue,
|
|
expression: 'localValue'
|
|
}],
|
|
domProps: { value: this.value },
|
|
attrs: {
|
|
id: this.safeId(),
|
|
name: this.name,
|
|
disabled: this.disabled,
|
|
placeholder: this.placeholder,
|
|
required: this.required,
|
|
autocomplete: this.autocomplete || null,
|
|
readonly: this.readonly || this.plaintext,
|
|
rows: this.rowsCount,
|
|
wrap: this.wrap || null,
|
|
'aria-required': this.required ? 'true' : null,
|
|
'aria-invalid': this.computedAriaInvalid
|
|
},
|
|
on: {
|
|
input: function input(evt) {
|
|
_this.localValue = evt.target.value;
|
|
}
|
|
}
|
|
});
|
|
},
|
|
data: function data() {
|
|
return {
|
|
localValue: this.value
|
|
};
|
|
},
|
|
|
|
props: {
|
|
value: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
ariaInvalid: {
|
|
type: [Boolean, String],
|
|
default: false
|
|
},
|
|
readonly: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
plaintext: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
autocomplete: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
placeholder: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
rows: {
|
|
type: [Number, String],
|
|
default: null
|
|
},
|
|
maxRows: {
|
|
type: [Number, String],
|
|
default: null
|
|
},
|
|
wrap: {
|
|
// 'soft', 'hard' or 'off'. Browser default is 'soft'
|
|
type: String,
|
|
default: 'soft'
|
|
},
|
|
noResize: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
},
|
|
computed: {
|
|
rowsCount: function rowsCount() {
|
|
// A better option could be based on https://codepen.io/vsync/pen/frudD
|
|
// As linebreaks aren't added until the input is submitted
|
|
var rows = parseInt(this.rows, 10) || 1;
|
|
var maxRows = parseInt(this.maxRows, 10) || 0;
|
|
var lines = (this.localValue || '').toString().split('\n').length;
|
|
return maxRows ? Math.min(maxRows, Math.max(rows, lines)) : Math.max(rows, lines);
|
|
},
|
|
inputClass: function inputClass() {
|
|
return [this.plaintext ? 'form-control-plaintext' : 'form-control', this.sizeFormClass, this.stateClass];
|
|
},
|
|
inputStyle: function inputStyle() {
|
|
// We set width 100% in plaintext mode to get around a shortcoming in bootstrap CSS
|
|
// setting noResize to true will disable the ability for the user to resize the textarea
|
|
return {
|
|
width: this.plaintext ? '100%' : null,
|
|
resize: this.noResize ? 'none' : null
|
|
};
|
|
},
|
|
computedAriaInvalid: function computedAriaInvalid() {
|
|
if (!this.ariaInvalid || this.ariaInvalid === 'false') {
|
|
// this.ariaInvalid is null or false or 'false'
|
|
return this.computedState === false ? 'true' : null;
|
|
}
|
|
if (this.ariaInvalid === true) {
|
|
// User wants explicit aria-invalid=true
|
|
return 'true';
|
|
}
|
|
// Most likely a string value (which could be the string 'true')
|
|
return this.ariaInvalid;
|
|
}
|
|
},
|
|
watch: {
|
|
value: function value(newVal, oldVal) {
|
|
// Update our localValue
|
|
if (newVal !== oldVal) {
|
|
this.localValue = newVal;
|
|
}
|
|
},
|
|
localValue: function localValue(newVal, oldVal) {
|
|
// update Parent value
|
|
if (newVal !== oldVal) {
|
|
this.$emit('input', newVal);
|
|
}
|
|
}
|
|
},
|
|
methods: {
|
|
focus: function focus() {
|
|
// For external handler that may want a focus method
|
|
if (!this.disabled) {
|
|
this.$el.focus();
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
var components$i = {
|
|
bFormTextarea: bFormTextarea,
|
|
bTextarea: bFormTextarea
|
|
};
|
|
|
|
var VuePlugin$j = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$i);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$j);
|
|
|
|
var bFormFile = {
|
|
mixins: [idMixin, formMixin, formStateMixin, formCustomMixin],
|
|
render: function render(h) {
|
|
// Form Input
|
|
var input = h('input', {
|
|
ref: 'input',
|
|
class: [{
|
|
'form-control-file': this.plain,
|
|
'custom-file-input': this.custom,
|
|
focus: this.custom && this.hasFocus
|
|
}, this.stateClass],
|
|
attrs: {
|
|
type: 'file',
|
|
id: this.safeId(),
|
|
name: this.name,
|
|
disabled: this.disabled,
|
|
required: this.required,
|
|
capture: this.capture || null,
|
|
accept: this.accept || null,
|
|
multiple: this.multiple,
|
|
webkitdirectory: this.directory,
|
|
'aria-required': this.required ? 'true' : null,
|
|
'aria-describedby': this.plain ? null : this.safeId('_BV_file_control_')
|
|
},
|
|
on: {
|
|
change: this.onFileChange,
|
|
focusin: this.focusHandler,
|
|
focusout: this.focusHandler
|
|
}
|
|
});
|
|
|
|
if (this.plain) {
|
|
return input;
|
|
}
|
|
|
|
// Overlay Labels
|
|
var label = h('label', {
|
|
class: ['custom-file-label', this.dragging ? 'dragging' : null],
|
|
attrs: {
|
|
id: this.safeId('_BV_file_control_')
|
|
}
|
|
}, this.selectLabel);
|
|
|
|
// Return rendered custom file input
|
|
return h('div', {
|
|
class: ['custom-file', 'b-form-file', this.stateClass],
|
|
attrs: { id: this.safeId('_BV_file_outer_') },
|
|
on: { dragover: this.dragover }
|
|
}, [input, label]);
|
|
},
|
|
data: function data() {
|
|
return {
|
|
selectedFile: null,
|
|
dragging: false,
|
|
hasFocus: false
|
|
};
|
|
},
|
|
|
|
props: {
|
|
accept: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
// Instruct input to capture from camera
|
|
capture: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
placeholder: {
|
|
type: String,
|
|
default: undefined
|
|
},
|
|
multiple: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
directory: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
noTraverse: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
noDrop: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
},
|
|
computed: {
|
|
selectLabel: function selectLabel() {
|
|
// No file choosen
|
|
if (!this.selectedFile || this.selectedFile.length === 0) {
|
|
return this.placeholder;
|
|
}
|
|
|
|
// Multiple files
|
|
if (this.multiple) {
|
|
if (this.selectedFile.length === 1) {
|
|
return this.selectedFile[0].name;
|
|
}
|
|
return this.selectedFile.map(function (file) {
|
|
return file.name;
|
|
}).join(', ');
|
|
}
|
|
|
|
// Single file
|
|
return this.selectedFile.name;
|
|
}
|
|
},
|
|
watch: {
|
|
selectedFile: function selectedFile(newVal, oldVal) {
|
|
if (newVal === oldVal) {
|
|
return;
|
|
}
|
|
if (!newVal && this.multiple) {
|
|
this.$emit('input', []);
|
|
} else {
|
|
this.$emit('input', newVal);
|
|
}
|
|
}
|
|
},
|
|
methods: {
|
|
focusHandler: function focusHandler(evt) {
|
|
// Boostrap v4.beta doesn't have focus styling for custom file input
|
|
// Firefox has a borked '[type=file]:focus ~ sibling' selector issue,
|
|
// So we add a 'focus' class to get around these "bugs"
|
|
if (this.plain || evt.type === 'focusout') {
|
|
this.hasFocus = false;
|
|
} else {
|
|
// Add focus styling for custom file input
|
|
this.hasFocus = true;
|
|
}
|
|
},
|
|
reset: function reset() {
|
|
try {
|
|
// Wrapped in try in case IE < 11 craps out
|
|
this.$refs.input.value = '';
|
|
} catch (e) {}
|
|
// IE < 11 doesn't support setting input.value to '' or null
|
|
// So we use this little extra hack to reset the value, just in case
|
|
// This also appears to work on modern browsers as well.
|
|
this.$refs.input.type = '';
|
|
this.$refs.input.type = 'file';
|
|
this.selectedFile = this.multiple ? [] : null;
|
|
},
|
|
onFileChange: function onFileChange(evt) {
|
|
var _this = this;
|
|
|
|
// Always emit original event
|
|
this.$emit('change', evt);
|
|
// Check if special `items` prop is available on event (drop mode)
|
|
// Can be disabled by setting no-traverse
|
|
var items = evt.dataTransfer && evt.dataTransfer.items;
|
|
if (items && !this.noTraverse) {
|
|
var queue = [];
|
|
for (var i = 0; i < items.length; i++) {
|
|
var item = items[i].webkitGetAsEntry();
|
|
if (item) {
|
|
queue.push(this.traverseFileTree(item));
|
|
}
|
|
}
|
|
Promise.all(queue).then(function (filesArr) {
|
|
_this.setFiles(from(filesArr));
|
|
});
|
|
return;
|
|
}
|
|
// Normal handling
|
|
this.setFiles(evt.target.files || evt.dataTransfer.files);
|
|
},
|
|
setFiles: function setFiles(files) {
|
|
if (!files) {
|
|
this.selectedFile = null;
|
|
return;
|
|
}
|
|
if (!this.multiple) {
|
|
this.selectedFile = files[0];
|
|
return;
|
|
}
|
|
// Convert files to array
|
|
var filesArray = [];
|
|
for (var i = 0; i < files.length; i++) {
|
|
if (files[i].type.match(this.accept)) {
|
|
filesArray.push(files[i]);
|
|
}
|
|
}
|
|
this.selectedFile = filesArray;
|
|
},
|
|
dragover: function dragover(evt) {
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
if (this.noDrop || !this.custom) {
|
|
return;
|
|
}
|
|
this.dragging = true;
|
|
evt.dataTransfer.dropEffect = 'copy';
|
|
},
|
|
dragleave: function dragleave(evt) {
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
this.dragging = false;
|
|
},
|
|
drop: function drop(evt) {
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
if (this.noDrop) {
|
|
return;
|
|
}
|
|
this.dragging = false;
|
|
if (evt.dataTransfer.files && evt.dataTransfer.files.length > 0) {
|
|
this.onFileChange(evt);
|
|
}
|
|
},
|
|
traverseFileTree: function traverseFileTree(item, path) {
|
|
var _this2 = this;
|
|
|
|
// Based on http://stackoverflow.com/questions/3590058
|
|
return new Promise(function (resolve) {
|
|
path = path || '';
|
|
if (item.isFile) {
|
|
// Get file
|
|
item.file(function (file) {
|
|
file.$path = path; // Inject $path to file obj
|
|
resolve(file);
|
|
});
|
|
} else if (item.isDirectory) {
|
|
// Get folder contents
|
|
item.createReader().readEntries(function (entries) {
|
|
var queue = [];
|
|
for (var i = 0; i < entries.length; i++) {
|
|
queue.push(_this2.traverseFileTree(entries[i], path + item.name + '/'));
|
|
}
|
|
Promise.all(queue).then(function (filesArr) {
|
|
resolve(from(filesArr));
|
|
});
|
|
});
|
|
}
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
var components$j = {
|
|
bFormFile: bFormFile,
|
|
bFile: bFormFile
|
|
};
|
|
|
|
var VuePlugin$k = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$j);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$k);
|
|
|
|
var bFormSelect = {
|
|
mixins: [idMixin, formMixin, formSizeMixin, formStateMixin, formCustomMixin, formOptionsMixin],
|
|
render: function render(h) {
|
|
var _this = this;
|
|
|
|
var $slots = this.$slots;
|
|
var options = this.formOptions.map(function (option, index) {
|
|
return h('option', {
|
|
key: 'option_' + index + '_opt',
|
|
attrs: { disabled: Boolean(option.disabled) },
|
|
domProps: { innerHTML: option.text, value: option.value }
|
|
});
|
|
});
|
|
return h('select', {
|
|
ref: 'input',
|
|
class: this.inputClass,
|
|
directives: [{
|
|
name: 'model',
|
|
rawName: 'v-model',
|
|
value: this.localValue,
|
|
expression: 'localValue'
|
|
}],
|
|
attrs: {
|
|
id: this.safeId(),
|
|
name: this.name,
|
|
multiple: this.multiple || null,
|
|
size: this.computedSelectSize,
|
|
disabled: this.disabled,
|
|
required: this.required,
|
|
'aria-required': this.required ? 'true' : null,
|
|
'aria-invalid': this.computedAriaInvalid
|
|
},
|
|
on: {
|
|
change: function change(evt) {
|
|
var target = evt.target;
|
|
var selectedVal = from(target.options).filter(function (o) {
|
|
return o.selected;
|
|
}).map(function (o) {
|
|
return '_value' in o ? o._value : o.value;
|
|
});
|
|
_this.localValue = target.multiple ? selectedVal : selectedVal[0];
|
|
_this.$emit('change', _this.localValue);
|
|
}
|
|
}
|
|
}, [$slots.first, options, $slots.default]);
|
|
},
|
|
data: function data() {
|
|
return {
|
|
localValue: this.value
|
|
};
|
|
},
|
|
|
|
watch: {
|
|
value: function value(newVal, oldVal) {
|
|
this.localValue = newVal;
|
|
},
|
|
localValue: function localValue(newVal, oldVal) {
|
|
this.$emit('input', this.localValue);
|
|
}
|
|
},
|
|
props: {
|
|
value: {},
|
|
multiple: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
selectSize: {
|
|
// Browsers default size to 0, which shows 4 rows in most browsers in multiple mode
|
|
// Size of 1 can bork out firefox
|
|
type: Number,
|
|
default: 0
|
|
},
|
|
ariaInvalid: {
|
|
type: [Boolean, String],
|
|
default: false
|
|
}
|
|
},
|
|
computed: {
|
|
computedSelectSize: function computedSelectSize() {
|
|
// Custom selects with a size of zero causes the arrows to be hidden,
|
|
// so dont render the size attribute in this case
|
|
return !this.plain && this.selectSize === 0 ? null : this.selectSize;
|
|
},
|
|
inputClass: function inputClass() {
|
|
return ['form-control', this.stateClass, this.sizeFormClass,
|
|
// Awaiting for https://github.com/twbs/bootstrap/issues/23058
|
|
this.plain ? null : 'custom-select', this.plain || !this.size ? null : 'custom-select-' + this.size];
|
|
},
|
|
computedAriaInvalid: function computedAriaInvalid() {
|
|
if (this.ariaInvalid === true || this.ariaInvalid === 'true') {
|
|
return 'true';
|
|
}
|
|
return this.stateClass === 'is-invalid' ? 'true' : null;
|
|
}
|
|
}
|
|
};
|
|
|
|
var components$k = {
|
|
bFormSelect: bFormSelect,
|
|
bSelect: bFormSelect
|
|
};
|
|
|
|
var VuePlugin$l = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$k);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$l);
|
|
|
|
var THROTTLE = 100;
|
|
|
|
var bImgLazy = {
|
|
components: { bImg: bImg },
|
|
render: function render(h) {
|
|
return h('b-img', {
|
|
props: {
|
|
src: this.computedSrc,
|
|
alt: this.alt,
|
|
blank: this.computedBlank,
|
|
blankColor: this.blankColor,
|
|
width: this.computedWidth,
|
|
height: this.computedHeight,
|
|
fluid: this.fluid,
|
|
fluidGrow: this.fluidGrow,
|
|
block: this.block,
|
|
thumbnail: this.thumbnail,
|
|
rounded: this.rounded,
|
|
left: this.left,
|
|
right: this.right,
|
|
center: this.center
|
|
}
|
|
});
|
|
},
|
|
data: function data() {
|
|
return {
|
|
isShown: false,
|
|
scrollTimeout: null
|
|
};
|
|
},
|
|
|
|
props: {
|
|
src: {
|
|
type: String,
|
|
default: null,
|
|
required: true
|
|
},
|
|
alt: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
width: {
|
|
type: [Number, String],
|
|
default: null
|
|
},
|
|
height: {
|
|
type: [Number, String],
|
|
default: null
|
|
},
|
|
blankSrc: {
|
|
// If null, a blank image is generated
|
|
type: String,
|
|
default: null
|
|
},
|
|
blankColor: {
|
|
type: String,
|
|
default: 'transparent'
|
|
},
|
|
blankWidth: {
|
|
type: [Number, String],
|
|
default: null
|
|
},
|
|
blankHeight: {
|
|
type: [Number, String],
|
|
default: null
|
|
},
|
|
fluid: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
fluidGrow: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
block: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
thumbnail: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
rounded: {
|
|
type: [Boolean, String],
|
|
default: false
|
|
},
|
|
left: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
right: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
center: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
offset: {
|
|
type: [Number, String],
|
|
default: 360
|
|
},
|
|
throttle: {
|
|
type: [Number, String],
|
|
default: THROTTLE
|
|
}
|
|
},
|
|
computed: {
|
|
computedSrc: function computedSrc() {
|
|
return !this.blankSrc || this.isShown ? this.src : this.blankSrc;
|
|
},
|
|
computedBlank: function computedBlank() {
|
|
return !(this.isShown || this.blankSrc);
|
|
},
|
|
computedWidth: function computedWidth() {
|
|
return this.isShown ? this.width : this.blankWidth || this.width;
|
|
},
|
|
computedHeight: function computedHeight() {
|
|
return this.isShown ? this.height : this.blankHeight || this.height;
|
|
}
|
|
},
|
|
mounted: function mounted() {
|
|
this.setListeners(true);
|
|
this.checkView();
|
|
},
|
|
activated: function activated() {
|
|
this.setListeners(true);
|
|
this.checkView();
|
|
},
|
|
deactivated: function deactivated() {
|
|
this.setListeners(false);
|
|
},
|
|
beforeDdestroy: function beforeDdestroy() {
|
|
this.setListeners(false);
|
|
},
|
|
|
|
methods: {
|
|
setListeners: function setListeners(on) {
|
|
clearTimeout(this.scrollTimer);
|
|
this.scrollTimeout = null;
|
|
var root = window;
|
|
if (on) {
|
|
eventOn(root, 'scroll', this.onScroll);
|
|
eventOn(root, 'resize', this.onScroll);
|
|
eventOn(root, 'orientationchange', this.onScroll);
|
|
} else {
|
|
eventOff(root, 'scroll', this.onScroll);
|
|
eventOff(root, 'resize', this.onScroll);
|
|
eventOff(root, 'orientationchange', this.onScroll);
|
|
}
|
|
},
|
|
checkView: function checkView() {
|
|
// check bounding box + offset to see if we should show
|
|
if (!isVisible(this.$el)) {
|
|
// Element is hidden, so skip for now
|
|
return;
|
|
}
|
|
var offset$$1 = parseInt(this.offset, 10) || 0;
|
|
var docElement = document.documentElement;
|
|
var view = {
|
|
l: 0 - offset$$1,
|
|
t: 0 - offset$$1,
|
|
b: docElement.clientHeight + offset$$1,
|
|
r: docElement.clientWidth + offset$$1
|
|
};
|
|
var box = getBCR(this.$el);
|
|
if (box.right >= view.l && box.bottom >= view.t && box.left <= view.r && box.top <= view.b) {
|
|
// image is in view (or about to be in view)
|
|
this.isShown = true;
|
|
this.setListeners(false);
|
|
}
|
|
},
|
|
onScroll: function onScroll() {
|
|
if (this.isShown) {
|
|
this.setListeners(false);
|
|
} else {
|
|
clearTimeout(this.scrollTimeout);
|
|
this.scrollTimeout = setTimeout(this.checkView, parseInt(this.throttle, 10) || THROTTLE);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
var components$l = {
|
|
bImg: bImg,
|
|
bImgLazy: bImgLazy
|
|
};
|
|
|
|
var VuePlugin$m = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$l);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$m);
|
|
|
|
var props$u = {
|
|
fluid: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
containerFluid: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
header: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
headerTag: {
|
|
type: String,
|
|
default: 'h1'
|
|
},
|
|
headerLevel: {
|
|
type: [Number, String],
|
|
default: '3'
|
|
},
|
|
lead: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
leadTag: {
|
|
type: String,
|
|
default: 'p'
|
|
},
|
|
tag: {
|
|
type: String,
|
|
default: 'div'
|
|
},
|
|
bgVariant: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
borderVariant: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
textVariant: {
|
|
type: String,
|
|
default: null
|
|
}
|
|
};
|
|
|
|
var bJumbotron = {
|
|
functional: true,
|
|
props: props$u,
|
|
render: function render(h, _ref) {
|
|
var _class2;
|
|
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
slots = _ref.slots;
|
|
|
|
// The order of the conditionals matter.
|
|
// We are building the component markup in order.
|
|
var childNodes = [];
|
|
var $slots = slots();
|
|
|
|
// Header
|
|
if (props.header || $slots.header) {
|
|
childNodes.push(h(props.headerTag, {
|
|
class: defineProperty({}, 'display-' + props.headerLevel, Boolean(props.headerLevel))
|
|
}, $slots.header || props.header));
|
|
}
|
|
|
|
// Lead
|
|
if (props.lead || $slots.lead) {
|
|
childNodes.push(h(props.leadTag, { staticClass: 'lead' }, $slots.lead || props.lead));
|
|
}
|
|
|
|
// Default slot
|
|
if ($slots.default) {
|
|
childNodes.push($slots.default);
|
|
}
|
|
|
|
// If fluid, wrap content in a container/container-fluid
|
|
if (props.fluid) {
|
|
// Children become a child of a container
|
|
childNodes = [h(Container, { props: { 'fluid': props.containerFluid } }, childNodes)];
|
|
}
|
|
// Return the jumbotron
|
|
return h(props.tag, mergeData(data, {
|
|
staticClass: 'jumbotron',
|
|
class: (_class2 = {
|
|
'jumbotron-fluid': props.fluid
|
|
}, defineProperty(_class2, 'text-' + props.textVariant, Boolean(props.textVariant)), defineProperty(_class2, 'bg-' + props.bgVariant, Boolean(props.bgVariant)), defineProperty(_class2, 'border-' + props.borderVariant, Boolean(props.borderVariant)), defineProperty(_class2, 'border', Boolean(props.borderVariant)), _class2)
|
|
}), childNodes);
|
|
}
|
|
};
|
|
|
|
var components$m = {
|
|
bJumbotron: bJumbotron
|
|
};
|
|
|
|
var VuePlugin$n = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$m);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$n);
|
|
|
|
var components$n = {
|
|
bLink: bLink
|
|
};
|
|
|
|
var VuePlugin$o = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$n);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$o);
|
|
|
|
var props$v = {
|
|
tag: {
|
|
type: String,
|
|
default: 'div'
|
|
},
|
|
flush: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
};
|
|
|
|
var bListGroup = {
|
|
functional: true,
|
|
props: props$v,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
var componentData = {
|
|
staticClass: 'list-group',
|
|
class: { 'list-group-flush': props.flush }
|
|
};
|
|
|
|
return h(props.tag, mergeData(data, componentData), children);
|
|
}
|
|
};
|
|
|
|
var actionTags = ['a', 'router-link', 'button', 'b-link'];
|
|
var linkProps$2 = propsFactory();
|
|
delete linkProps$2.href.default;
|
|
delete linkProps$2.to.default;
|
|
|
|
var props$w = assign({
|
|
tag: {
|
|
type: String,
|
|
default: 'div'
|
|
},
|
|
action: {
|
|
type: Boolean,
|
|
default: null
|
|
},
|
|
button: {
|
|
type: Boolean,
|
|
default: null
|
|
},
|
|
variant: {
|
|
type: String,
|
|
default: null
|
|
}
|
|
}, linkProps$2);
|
|
|
|
var bListGroupItem = {
|
|
functional: true,
|
|
props: props$w,
|
|
render: function render(h, _ref) {
|
|
var _class;
|
|
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
var tag = props.button ? 'button' : !props.href && !props.to ? props.tag : bLink;
|
|
var isAction = Boolean(props.href || props.to || props.action || props.button || arrayIncludes(actionTags, props.tag));
|
|
var componentData = {
|
|
staticClass: 'list-group-item',
|
|
class: (_class = {}, defineProperty(_class, 'list-group-item-' + props.variant, Boolean(props.variant)), defineProperty(_class, 'list-group-item-action', isAction), defineProperty(_class, 'active', props.active), defineProperty(_class, 'disabled', props.disabled), _class),
|
|
attrs: tag === 'button' && props.disabled ? { disabled: true } : {},
|
|
props: props.button ? {} : pluckProps(linkProps$2, props)
|
|
};
|
|
|
|
return h(tag, mergeData(data, componentData), children);
|
|
}
|
|
};
|
|
|
|
var components$o = {
|
|
bListGroup: bListGroup,
|
|
bListGroupItem: bListGroupItem
|
|
};
|
|
|
|
var VuePlugin$p = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$o);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$p);
|
|
|
|
var props$x = {
|
|
tag: {
|
|
type: String,
|
|
default: 'div'
|
|
}
|
|
};
|
|
|
|
var MediaBody = {
|
|
functional: true,
|
|
props: props$x,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
return h(props.tag, mergeData(data, {
|
|
staticClass: 'media-body'
|
|
}), children);
|
|
}
|
|
};
|
|
|
|
var props$y = {
|
|
tag: {
|
|
type: String,
|
|
default: 'div'
|
|
},
|
|
verticalAlign: {
|
|
type: String,
|
|
default: 'top'
|
|
}
|
|
};
|
|
|
|
var MediaAside = {
|
|
functional: true,
|
|
props: props$y,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
return h(props.tag, mergeData(data, {
|
|
staticClass: 'd-flex',
|
|
class: defineProperty({}, 'align-self-' + props.verticalAlign, props.verticalAlign)
|
|
}), children);
|
|
}
|
|
};
|
|
|
|
var props$z = {
|
|
tag: {
|
|
type: String,
|
|
default: 'div'
|
|
},
|
|
rightAlign: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
verticalAlign: {
|
|
type: String,
|
|
default: 'top'
|
|
},
|
|
noBody: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
};
|
|
|
|
var bMedia = {
|
|
functional: true,
|
|
props: props$z,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
slots = _ref.slots,
|
|
children = _ref.children;
|
|
|
|
var childNodes = props.noBody ? children : [];
|
|
var $slots = slots();
|
|
|
|
if (!props.noBody) {
|
|
if ($slots.aside && !props.rightAlign) {
|
|
childNodes.push(h(MediaAside, { staticClass: 'me-3', props: { verticalAlign: props.verticalAlign } }, $slots.aside));
|
|
}
|
|
|
|
childNodes.push(h(MediaBody, $slots.default));
|
|
|
|
if ($slots.aside && props.rightAlign) {
|
|
childNodes.push(h(MediaAside, { staticClass: 'ms-3', props: { verticalAlign: props.verticalAlign } }, $slots.aside));
|
|
}
|
|
}
|
|
|
|
return h(props.tag, mergeData(data, { staticClass: 'media' }), childNodes);
|
|
}
|
|
};
|
|
|
|
var components$p = {
|
|
bMedia: bMedia,
|
|
bMediaAside: MediaAside,
|
|
bMediaBody: MediaBody
|
|
};
|
|
|
|
var VuePlugin$q = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$p);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$q);
|
|
|
|
// Selectors for padding/margin adjustments
|
|
var Selector = {
|
|
FIXED_CONTENT: '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top',
|
|
STICKY_CONTENT: '.sticky-top',
|
|
NAVBAR_TOGGLER: '.navbar-toggler'
|
|
|
|
// ObserveDom config
|
|
};var OBSERVER_CONFIG = {
|
|
subtree: true,
|
|
childList: true,
|
|
characterData: true,
|
|
attributes: true,
|
|
attributeFilter: ['style', 'class']
|
|
};
|
|
|
|
var bModal = {
|
|
mixins: [idMixin, listenOnRootMixin],
|
|
components: { bBtn: bBtn, bBtnClose: bBtnClose },
|
|
render: function render(h) {
|
|
var _this = this;
|
|
|
|
var $slots = this.$slots;
|
|
// Modal Header
|
|
var header = h(false);
|
|
if (!this.hideHeader) {
|
|
var modalHeader = $slots['modal-header'];
|
|
if (!modalHeader) {
|
|
var closeButton = h(false);
|
|
if (!this.hideHeaderClose) {
|
|
closeButton = h('b-btn-close', {
|
|
props: {
|
|
disabled: this.is_transitioning,
|
|
ariaLabel: this.headerCloseLabel,
|
|
textVariant: this.headerTextVariant
|
|
},
|
|
on: {
|
|
click: function click(evt) {
|
|
_this.hide('header-close');
|
|
}
|
|
}
|
|
}, [$slots['modal-header-close']]);
|
|
}
|
|
modalHeader = [h(this.titleTag, { class: ['modal-title'] }, [$slots['modal-title'] || this.title]), closeButton];
|
|
}
|
|
header = h('header', {
|
|
ref: 'header',
|
|
class: this.headerClasses,
|
|
attrs: { id: this.safeId('__BV_modal_header_') }
|
|
}, [modalHeader]);
|
|
}
|
|
// Modal Body
|
|
var body = h('div', {
|
|
ref: 'body',
|
|
class: this.bodyClasses,
|
|
attrs: { id: this.safeId('__BV_modal_body_') }
|
|
}, [$slots.default]);
|
|
// Modal Footer
|
|
var footer = h(false);
|
|
if (!this.hideFooter) {
|
|
var modalFooter = $slots['modal-footer'];
|
|
if (!modalFooter) {
|
|
var cancelButton = h(false);
|
|
if (!this.okOnly) {
|
|
cancelButton = h('b-btn', {
|
|
props: {
|
|
variant: this.cancelVariant,
|
|
size: this.buttonSize,
|
|
disabled: this.cancelDisabled || this.busy || this.is_transitioning
|
|
},
|
|
on: {
|
|
click: function click(evt) {
|
|
_this.hide('cancel');
|
|
}
|
|
}
|
|
}, [$slots['modal-cancel'] || this.cancelTitle]);
|
|
}
|
|
var okButton = h('b-btn', {
|
|
props: {
|
|
variant: this.okVariant,
|
|
size: this.buttonSize,
|
|
disabled: this.okDisabled || this.busy || this.is_transitioning
|
|
},
|
|
on: {
|
|
click: function click(evt) {
|
|
_this.hide('ok');
|
|
}
|
|
}
|
|
}, [$slots['modal-ok'] || this.okTitle]);
|
|
modalFooter = [cancelButton, okButton];
|
|
}
|
|
footer = h('footer', {
|
|
ref: 'footer',
|
|
class: this.footerClasses,
|
|
attrs: { id: this.safeId('__BV_modal_footer_') }
|
|
}, [modalFooter]);
|
|
}
|
|
// Assemble Modal Content
|
|
var modalContent = h('div', {
|
|
ref: 'content',
|
|
class: ['modal-content'],
|
|
attrs: {
|
|
tabindex: '-1',
|
|
role: 'document',
|
|
'aria-labelledby': this.hideHeader ? null : this.safeId('__BV_modal_header_'),
|
|
'aria-describedby': this.safeId('__BV_modal_body_')
|
|
},
|
|
on: {
|
|
focusout: this.onFocusout,
|
|
click: function click(evt) {
|
|
evt.stopPropagation();
|
|
// https://github.com/bootstrap-vue/bootstrap-vue/issues/1528
|
|
_this.$root.$emit('bv::dropdown::shown');
|
|
}
|
|
}
|
|
}, [header, body, footer]);
|
|
// Modal Dialog wrapper
|
|
var modalDialog = h('div', { class: this.dialogClasses }, [modalContent]);
|
|
// Modal
|
|
var modal = h('div', {
|
|
ref: 'modal',
|
|
class: this.modalClasses,
|
|
directives: [{
|
|
name: 'show',
|
|
rawName: 'v-show',
|
|
value: this.is_visible,
|
|
expression: 'is_visible'
|
|
}],
|
|
attrs: {
|
|
id: this.safeId(),
|
|
role: 'dialog',
|
|
'aria-hidden': this.is_visible ? null : 'true'
|
|
},
|
|
on: {
|
|
click: this.onClickOut,
|
|
keydown: this.onEsc
|
|
}
|
|
}, [modalDialog]);
|
|
// Wrap modal in transition
|
|
modal = h('transition', {
|
|
props: {
|
|
enterClass: '',
|
|
enterToClass: '',
|
|
enterActiveClass: '',
|
|
leaveClass: '',
|
|
leaveActiveClass: '',
|
|
leaveToClass: ''
|
|
},
|
|
on: {
|
|
'before-enter': this.onBeforeEnter,
|
|
enter: this.onEnter,
|
|
'after-enter': this.onAfterEnter,
|
|
'before-leave': this.onBeforeLeave,
|
|
leave: this.onLeave,
|
|
'after-leave': this.onAfterLeave
|
|
}
|
|
}, [modal]);
|
|
// Modal Backdrop
|
|
var backdrop = h(false);
|
|
if (!this.hideBackdrop && (this.is_visible || this.is_transitioning)) {
|
|
backdrop = h('div', {
|
|
class: this.backdropClasses,
|
|
attrs: { id: this.safeId('__BV_modal_backdrop_') }
|
|
});
|
|
}
|
|
// Assemble modal and backdrop
|
|
var outer = h(false);
|
|
if (!this.is_hidden) {
|
|
outer = h('div', { attrs: { id: this.safeId('__BV_modal_outer_') } }, [modal, backdrop]);
|
|
}
|
|
// Wrap in DIV to maintain thi.$el reference for hide/show method aceess
|
|
return h('div', {}, [outer]);
|
|
},
|
|
data: function data() {
|
|
return {
|
|
is_hidden: this.lazy || false,
|
|
is_visible: false,
|
|
is_transitioning: false,
|
|
is_show: false,
|
|
is_block: false,
|
|
scrollbarWidth: 0,
|
|
isBodyOverflowing: false,
|
|
return_focus: this.returnFocus || null
|
|
};
|
|
},
|
|
|
|
model: {
|
|
prop: 'visible',
|
|
event: 'change'
|
|
},
|
|
props: {
|
|
title: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
titleTag: {
|
|
type: String,
|
|
default: 'h5'
|
|
},
|
|
size: {
|
|
type: String,
|
|
default: 'md'
|
|
},
|
|
centered: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
buttonSize: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
noFade: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
noCloseOnBackdrop: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
noCloseOnEsc: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
noEnforceFocus: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
headerBgVariant: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
headerBorderVariant: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
headerTextVariant: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
headerClass: {
|
|
type: [String, Array],
|
|
default: null
|
|
},
|
|
bodyBgVariant: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
bodyTextVariant: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
modalClass: {
|
|
type: [String, Array],
|
|
default: null
|
|
},
|
|
bodyClass: {
|
|
type: [String, Array],
|
|
default: null
|
|
},
|
|
footerBgVariant: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
footerBorderVariant: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
footerTextVariant: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
footerClass: {
|
|
type: [String, Array],
|
|
default: null
|
|
},
|
|
hideHeader: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
hideFooter: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
hideHeaderClose: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
hideBackdrop: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
okOnly: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
okDisabled: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
cancelDisabled: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
visible: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
returnFocus: {
|
|
default: null
|
|
},
|
|
headerCloseLabel: {
|
|
type: String,
|
|
default: 'Close'
|
|
},
|
|
cancelTitle: {
|
|
type: String,
|
|
default: 'Cancel'
|
|
},
|
|
okTitle: {
|
|
type: String,
|
|
default: 'OK'
|
|
},
|
|
cancelVariant: {
|
|
type: String,
|
|
default: 'secondary'
|
|
},
|
|
okVariant: {
|
|
type: String,
|
|
default: 'primary'
|
|
},
|
|
lazy: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
busy: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
},
|
|
computed: {
|
|
modalClasses: function modalClasses() {
|
|
return ['modal', {
|
|
fade: !this.noFade,
|
|
show: this.is_show,
|
|
'd-block': this.is_block
|
|
}, this.modalClass];
|
|
},
|
|
dialogClasses: function dialogClasses() {
|
|
var _ref;
|
|
|
|
return ['modal-dialog', (_ref = {}, defineProperty(_ref, 'modal-' + this.size, Boolean(this.size)), defineProperty(_ref, 'modal-dialog-centered', this.centered), _ref)];
|
|
},
|
|
backdropClasses: function backdropClasses() {
|
|
return ['modal-backdrop', {
|
|
fade: !this.noFade,
|
|
show: this.is_show || this.noFade
|
|
}];
|
|
},
|
|
headerClasses: function headerClasses() {
|
|
var _ref2;
|
|
|
|
return ['modal-header', (_ref2 = {}, defineProperty(_ref2, 'bg-' + this.headerBgVariant, Boolean(this.headerBgVariant)), defineProperty(_ref2, 'text-' + this.headerTextVariant, Boolean(this.headerTextVariant)), defineProperty(_ref2, 'border-' + this.headerBorderVariant, Boolean(this.headerBorderVariant)), _ref2), this.headerClass];
|
|
},
|
|
bodyClasses: function bodyClasses() {
|
|
var _ref3;
|
|
|
|
return ['modal-body', (_ref3 = {}, defineProperty(_ref3, 'bg-' + this.bodyBgVariant, Boolean(this.bodyBgVariant)), defineProperty(_ref3, 'text-' + this.bodyTextVariant, Boolean(this.bodyTextVariant)), _ref3), this.bodyClass];
|
|
},
|
|
footerClasses: function footerClasses() {
|
|
var _ref4;
|
|
|
|
return ['modal-footer', (_ref4 = {}, defineProperty(_ref4, 'bg-' + this.footerBgVariant, Boolean(this.footerBgVariant)), defineProperty(_ref4, 'text-' + this.footerTextVariant, Boolean(this.footerTextVariant)), defineProperty(_ref4, 'border-' + this.footerBorderVariant, Boolean(this.footerBorderVariant)), _ref4), this.footerClass];
|
|
}
|
|
},
|
|
watch: {
|
|
visible: function visible(newVal, oldVal) {
|
|
if (newVal === oldVal) {
|
|
return;
|
|
}
|
|
this[newVal ? 'show' : 'hide']();
|
|
}
|
|
},
|
|
methods: {
|
|
// Public Methods
|
|
show: function show() {
|
|
if (this.is_visible) {
|
|
return;
|
|
}
|
|
var showEvt = new BvEvent('show', {
|
|
cancelable: true,
|
|
vueTarget: this,
|
|
target: this.$refs.modal,
|
|
relatedTarget: null
|
|
});
|
|
this.emitEvent(showEvt);
|
|
if (showEvt.defaultPrevented || this.is_visible) {
|
|
// Don't show if canceled
|
|
return;
|
|
}
|
|
if (hasClass(document.body, 'modal-open')) {
|
|
// If another modal is already open, wait for it to close
|
|
this.$root.$once('bv::modal::hidden', this.doShow);
|
|
} else {
|
|
// Show the modal
|
|
this.doShow();
|
|
}
|
|
},
|
|
hide: function hide(trigger) {
|
|
if (!this.is_visible) {
|
|
return;
|
|
}
|
|
var hideEvt = new BvEvent('hide', {
|
|
cancelable: true,
|
|
vueTarget: this,
|
|
target: this.$refs.modal,
|
|
// this could be the trigger element/component reference
|
|
relatedTarget: null,
|
|
isOK: trigger || null,
|
|
trigger: trigger || null,
|
|
cancel: function cancel() {
|
|
// Backwards compatibility
|
|
warn('b-modal: evt.cancel() is deprecated. Please use evt.preventDefault().');
|
|
this.preventDefault();
|
|
}
|
|
});
|
|
if (trigger === 'ok') {
|
|
this.$emit('ok', hideEvt);
|
|
} else if (trigger === 'cancel') {
|
|
this.$emit('cancel', hideEvt);
|
|
}
|
|
this.emitEvent(hideEvt);
|
|
// Hide if not canceled
|
|
if (hideEvt.defaultPrevented || !this.is_visible) {
|
|
return;
|
|
}
|
|
// stop observing for content changes
|
|
if (this._observer) {
|
|
this._observer.disconnect();
|
|
this._observer = null;
|
|
}
|
|
this.is_visible = false;
|
|
this.$emit('change', false);
|
|
},
|
|
|
|
// Private method to finish showing modal
|
|
doShow: function doShow() {
|
|
var _this2 = this;
|
|
|
|
// Plce modal in DOM if lazy
|
|
this.is_hidden = false;
|
|
this.$nextTick(function () {
|
|
// We do this in nextTick to ensure the modal is in DOM first before we show it
|
|
_this2.is_visible = true;
|
|
_this2.$emit('change', true);
|
|
// Observe changes in modal content and adjust if necessary
|
|
_this2._observer = observeDOM(_this2.$refs.content, _this2.adjustDialog.bind(_this2), OBSERVER_CONFIG);
|
|
});
|
|
},
|
|
|
|
// Transition Handlers
|
|
onBeforeEnter: function onBeforeEnter() {
|
|
this.is_transitioning = true;
|
|
this.checkScrollbar();
|
|
this.setScrollbar();
|
|
this.adjustDialog();
|
|
addClass(document.body, 'modal-open');
|
|
this.setResizeEvent(true);
|
|
},
|
|
onEnter: function onEnter() {
|
|
this.is_block = true;
|
|
this.$refs.modal.scrollTop = 0;
|
|
},
|
|
onAfterEnter: function onAfterEnter() {
|
|
var _this3 = this;
|
|
|
|
this.is_show = true;
|
|
this.is_transitioning = false;
|
|
this.$nextTick(function () {
|
|
_this3.focusFirst();
|
|
var shownEvt = new BvEvent('shown', {
|
|
cancelable: false,
|
|
vueTarget: _this3,
|
|
target: _this3.$refs.modal,
|
|
relatedTarget: null
|
|
});
|
|
_this3.emitEvent(shownEvt);
|
|
});
|
|
},
|
|
onBeforeLeave: function onBeforeLeave() {
|
|
this.is_transitioning = true;
|
|
this.setResizeEvent(false);
|
|
},
|
|
onLeave: function onLeave() {
|
|
// Remove the 'show' class
|
|
this.is_show = false;
|
|
},
|
|
onAfterLeave: function onAfterLeave() {
|
|
var _this4 = this;
|
|
|
|
this.is_block = false;
|
|
this.resetAdjustments();
|
|
this.resetScrollbar();
|
|
this.is_transitioning = false;
|
|
removeClass(document.body, 'modal-open');
|
|
this.$nextTick(function () {
|
|
_this4.is_hidden = _this4.lazy || false;
|
|
_this4.returnFocusTo();
|
|
var hiddenEvt = new BvEvent('hidden', {
|
|
cancelable: false,
|
|
vueTarget: _this4,
|
|
target: _this4.lazy ? null : _this4.$refs.modal,
|
|
relatedTarget: null
|
|
});
|
|
_this4.emitEvent(hiddenEvt);
|
|
});
|
|
},
|
|
|
|
// Event emitter
|
|
emitEvent: function emitEvent(bvEvt) {
|
|
var type = bvEvt.type;
|
|
this.$emit(type, bvEvt);
|
|
this.$root.$emit('bv::modal::' + type, bvEvt);
|
|
},
|
|
|
|
// UI Event Handlers
|
|
onClickOut: function onClickOut(evt) {
|
|
// If backdrop clicked, hide modal
|
|
if (this.is_visible && !this.noCloseOnBackdrop) {
|
|
this.hide('backdrop');
|
|
}
|
|
},
|
|
onEsc: function onEsc(evt) {
|
|
// If ESC pressed, hide modal
|
|
if (evt.keyCode === KeyCodes.ESC && this.is_visible && !this.noCloseOnEsc) {
|
|
this.hide('esc');
|
|
}
|
|
},
|
|
onFocusout: function onFocusout(evt) {
|
|
// If focus leaves modal, bring it back
|
|
// 'focusout' Event Listener bound on content
|
|
var content = this.$refs.content;
|
|
if (!this.noEnforceFocus && this.is_visible && content && !content.contains(evt.relatedTarget)) {
|
|
content.focus();
|
|
}
|
|
},
|
|
|
|
// Resize Listener
|
|
setResizeEvent: function setResizeEvent(on) {
|
|
var _this5 = this;
|
|
['resize', 'orientationchange'].forEach(function (evtName) {
|
|
if (on) {
|
|
eventOn(window, evtName, _this5.adjustDialog);
|
|
} else {
|
|
eventOff(window, evtName, _this5.adjustDialog);
|
|
}
|
|
});
|
|
},
|
|
|
|
// Root Listener handlers
|
|
showHandler: function showHandler(id, triggerEl) {
|
|
if (id === this.id) {
|
|
this.return_focus = triggerEl || null;
|
|
this.show();
|
|
}
|
|
},
|
|
hideHandler: function hideHandler(id) {
|
|
if (id === this.id) {
|
|
this.hide();
|
|
}
|
|
},
|
|
modalListener: function modalListener(bvEvt) {
|
|
// If another modal opens, close this one
|
|
if (bvEvt.vueTarget !== this) {
|
|
this.hide();
|
|
}
|
|
},
|
|
|
|
// Focus control handlers
|
|
focusFirst: function focusFirst() {
|
|
// Don't try and focus if we are SSR
|
|
if (typeof document === 'undefined') {
|
|
return;
|
|
}
|
|
var content = this.$refs.content;
|
|
var modal = this.$refs.modal;
|
|
var activeElement = document.activeElement;
|
|
if (activeElement && content && content.contains(activeElement)) ; else if (content) {
|
|
if (modal) {
|
|
modal.scrollTop = 0;
|
|
}
|
|
// Focus the modal content wrapper
|
|
content.focus();
|
|
}
|
|
},
|
|
returnFocusTo: function returnFocusTo() {
|
|
// Prefer returnFocus prop over event specified return_focus value
|
|
var el = this.returnFocus || this.return_focus || null;
|
|
if (typeof el === 'string') {
|
|
// CSS Selector
|
|
el = select(el);
|
|
}
|
|
if (el) {
|
|
el = el.$el || el;
|
|
if (isVisible(el)) {
|
|
el.focus();
|
|
}
|
|
}
|
|
},
|
|
|
|
// Utility methods
|
|
getScrollbarWidth: function getScrollbarWidth() {
|
|
var scrollDiv = document.createElement('div');
|
|
scrollDiv.className = 'modal-scrollbar-measure';
|
|
document.body.appendChild(scrollDiv);
|
|
this.scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth;
|
|
document.body.removeChild(scrollDiv);
|
|
},
|
|
adjustDialog: function adjustDialog() {
|
|
if (!this.is_visible) {
|
|
return;
|
|
}
|
|
var modal = this.$refs.modal;
|
|
var isModalOverflowing = modal.scrollHeight > document.documentElement.clientHeight;
|
|
if (!this.isBodyOverflowing && isModalOverflowing) {
|
|
modal.style.paddingLeft = this.scrollbarWidth + 'px';
|
|
}
|
|
if (this.isBodyOverflowing && !isModalOverflowing) {
|
|
modal.style.paddingRight = this.scrollbarWidth + 'px';
|
|
}
|
|
},
|
|
resetAdjustments: function resetAdjustments() {
|
|
var modal = this.$refs.modal;
|
|
if (modal) {
|
|
modal.style.paddingLeft = '';
|
|
modal.style.paddingRight = '';
|
|
}
|
|
},
|
|
checkScrollbar: function checkScrollbar() {
|
|
var rect = getBCR(document.body);
|
|
this.isBodyOverflowing = rect.left + rect.right < window.innerWidth;
|
|
},
|
|
setScrollbar: function setScrollbar() {
|
|
if (this.isBodyOverflowing) {
|
|
// Note: DOMNode.style.paddingRight returns the actual value or '' if not set
|
|
// while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set
|
|
var computedStyle = window.getComputedStyle;
|
|
var body = document.body;
|
|
var scrollbarWidth = this.scrollbarWidth;
|
|
// Adjust fixed content padding
|
|
selectAll(Selector.FIXED_CONTENT).forEach(function (el) {
|
|
var actualPadding = el.style.paddingRight;
|
|
var calculatedPadding = computedStyle(el).paddingRight || 0;
|
|
setAttr(el, 'data-padding-right', actualPadding);
|
|
el.style.paddingRight = parseFloat(calculatedPadding) + scrollbarWidth + 'px';
|
|
});
|
|
// Adjust sticky content margin
|
|
selectAll(Selector.STICKY_CONTENT).forEach(function (el) {
|
|
var actualMargin = el.style.marginRight;
|
|
var calculatedMargin = computedStyle(el).marginRight || 0;
|
|
setAttr(el, 'data-margin-right', actualMargin);
|
|
el.style.marginRight = parseFloat(calculatedMargin) - scrollbarWidth + 'px';
|
|
});
|
|
// Adjust navbar-toggler margin
|
|
selectAll(Selector.NAVBAR_TOGGLER).forEach(function (el) {
|
|
var actualMargin = el.style.marginRight;
|
|
var calculatedMargin = computedStyle(el).marginRight || 0;
|
|
setAttr(el, 'data-margin-right', actualMargin);
|
|
el.style.marginRight = parseFloat(calculatedMargin) + scrollbarWidth + 'px';
|
|
});
|
|
// Adjust body padding
|
|
var actualPadding = body.style.paddingRight;
|
|
var calculatedPadding = computedStyle(body).paddingRight;
|
|
setAttr(body, 'data-padding-right', actualPadding);
|
|
body.style.paddingRight = parseFloat(calculatedPadding) + scrollbarWidth + 'px';
|
|
}
|
|
},
|
|
resetScrollbar: function resetScrollbar() {
|
|
// Restore fixed content padding
|
|
selectAll(Selector.FIXED_CONTENT).forEach(function (el) {
|
|
if (hasAttr(el, 'data-padding-right')) {
|
|
el.style.paddingRight = getAttr(el, 'data-padding-right') || '';
|
|
removeAttr(el, 'data-padding-right');
|
|
}
|
|
});
|
|
// Restore sticky content and navbar-toggler margin
|
|
selectAll(Selector.STICKY_CONTENT + ', ' + Selector.NAVBAR_TOGGLER).forEach(function (el) {
|
|
if (hasAttr(el, 'data-margin-right')) {
|
|
el.style.marginRight = getAttr(el, 'data-margin-right') || '';
|
|
removeAttr(el, 'data-margin-right');
|
|
}
|
|
});
|
|
// Restore body padding
|
|
var body = document.body;
|
|
if (hasAttr(body, 'data-padding-right')) {
|
|
body.style.paddingRight = getAttr(body, 'data-padding-right') || '';
|
|
removeAttr(body, 'data-padding-right');
|
|
}
|
|
}
|
|
},
|
|
created: function created() {
|
|
// create non-reactive property
|
|
this._observer = null;
|
|
},
|
|
mounted: function mounted() {
|
|
// Measure scrollbar
|
|
this.getScrollbarWidth();
|
|
// Listen for events from others to either open or close ourselves
|
|
this.listenOnRoot('bv::show::modal', this.showHandler);
|
|
this.listenOnRoot('bv::hide::modal', this.hideHandler);
|
|
// Listen for bv:modal::show events, and close ourselves if the opening modal not us
|
|
this.listenOnRoot('bv::modal::show', this.modalListener);
|
|
// Initially show modal?
|
|
if (this.visible === true) {
|
|
this.show();
|
|
}
|
|
},
|
|
beforeDestroy: function beforeDestroy() {
|
|
// Ensure everything is back to normal
|
|
if (this._observer) {
|
|
this._observer.disconnect();
|
|
this._observer = null;
|
|
}
|
|
this.setResizeEvent(false);
|
|
// Re-adjust body/navbar/fixed padding/margins (if needed)
|
|
removeClass(document.body, 'modal-open');
|
|
this.resetAdjustments();
|
|
this.resetScrollbar();
|
|
}
|
|
};
|
|
|
|
var listenTypes$1 = { click: true };
|
|
|
|
var bModal$1 = {
|
|
// eslint-disable-next-line no-shadow-restricted-names
|
|
bind: function bind(el, binding, vnode) {
|
|
bindTargets(vnode, binding, listenTypes$1, function (_ref) {
|
|
var targets = _ref.targets,
|
|
vnode = _ref.vnode;
|
|
|
|
targets.forEach(function (target) {
|
|
vnode.context.$root.$emit('bv::show::modal', target, vnode.elm);
|
|
});
|
|
});
|
|
if (el.tagName !== 'BUTTON') {
|
|
// If element is not a button, we add `role="button"` for accessibility
|
|
setAttr(el, 'role', 'button');
|
|
}
|
|
},
|
|
unbind: function unbind(el, binding, vnode) {
|
|
unbindTargets(vnode, binding, listenTypes$1);
|
|
if (el.tagName !== 'BUTTON') {
|
|
// If element is not a button, we add `role="button"` for accessibility
|
|
removeAttr(el, 'role', 'button');
|
|
}
|
|
}
|
|
};
|
|
|
|
var directives$1 = {
|
|
bModal: bModal$1
|
|
};
|
|
|
|
var VuePlugin$r = {
|
|
install: function install(Vue) {
|
|
registerDirectives(Vue, directives$1);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$r);
|
|
|
|
var components$q = {
|
|
bModal: bModal
|
|
};
|
|
|
|
var VuePlugin$s = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$q);
|
|
Vue.use(VuePlugin$r);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$s);
|
|
|
|
var props$A = {
|
|
tag: {
|
|
type: String,
|
|
default: 'ul'
|
|
},
|
|
fill: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
justified: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
tabs: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
pills: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
vertical: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
isNavBar: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
};
|
|
|
|
var bNav = {
|
|
functional: true,
|
|
props: props$A,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
if (props.isNavBar) {
|
|
warn("b-nav: Prop 'is-nav-bar' is deprecated. Please use component '<b-navbar-nav>' instead.");
|
|
}
|
|
return h(props.tag, mergeData(data, {
|
|
class: {
|
|
'nav': !props.isNavBar,
|
|
'navbar-nav': props.isNavBar,
|
|
'nav-tabs': props.tabs && !props.isNavBar,
|
|
'nav-pills': props.pills && !props.isNavBar,
|
|
'flex-column': props.vertical && !props.isNavBar,
|
|
'nav-fill': props.fill,
|
|
'nav-justified': props.justified
|
|
}
|
|
}), children);
|
|
}
|
|
};
|
|
|
|
var props$B = propsFactory();
|
|
|
|
var bNavItem = {
|
|
functional: true,
|
|
props: props$B,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
return h('li', mergeData(data, {
|
|
staticClass: 'nav-item'
|
|
}), [h(bLink, { staticClass: 'nav-link', props: props }, children)]);
|
|
}
|
|
};
|
|
|
|
var props$C = {
|
|
tag: {
|
|
type: String,
|
|
default: 'span'
|
|
}
|
|
};
|
|
|
|
var bNavText = {
|
|
functional: true,
|
|
props: props$C,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
return h(props.tag, mergeData(data, { staticClass: 'navbar-text' }), children);
|
|
}
|
|
};
|
|
|
|
var bNavForm = {
|
|
functional: true,
|
|
props: {
|
|
id: {
|
|
type: String,
|
|
default: null
|
|
}
|
|
},
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
return h(Form, mergeData(data, { attrs: { id: props.id }, props: { inline: true } }), children);
|
|
}
|
|
};
|
|
|
|
var bNavItemDropdown = {
|
|
mixins: [idMixin, dropdownMixin],
|
|
render: function render(h) {
|
|
var button = h('a', {
|
|
class: this.toggleClasses,
|
|
ref: 'toggle',
|
|
attrs: {
|
|
href: '#',
|
|
id: this.safeId('_BV_button_'),
|
|
disabled: this.disabled,
|
|
'aria-haspopup': 'true',
|
|
'aria-expanded': this.visible ? 'true' : 'false'
|
|
},
|
|
on: {
|
|
click: this.toggle,
|
|
keydown: this.toggle // space, enter, down
|
|
}
|
|
}, [this.$slots['button-content'] || this.$slots.text || h('span', { domProps: { innerHTML: this.text } })]);
|
|
var menu = h('div', {
|
|
class: this.menuClasses,
|
|
ref: 'menu',
|
|
attrs: { 'aria-labelledby': this.safeId('_BV_button_') },
|
|
on: {
|
|
mouseover: this.onMouseOver,
|
|
keydown: this.onKeydown // tab, up, down, esc
|
|
}
|
|
}, [this.$slots.default]);
|
|
return h('li', { attrs: { id: this.safeId() }, class: this.dropdownClasses }, [button, menu]);
|
|
},
|
|
|
|
computed: {
|
|
isNav: function isNav() {
|
|
// Signal to dropdown mixin that we are in a navbar
|
|
return true;
|
|
},
|
|
dropdownClasses: function dropdownClasses() {
|
|
return ['nav-item', 'b-nav-dropdown', 'dropdown', this.dropup ? 'dropup' : '', this.visible ? 'show' : ''];
|
|
},
|
|
toggleClasses: function toggleClasses() {
|
|
return ['nav-link', this.noCaret ? '' : 'dropdown-toggle', this.disabled ? 'disabled' : '', this.extraToggleClasses ? this.extraToggleClasses : ''];
|
|
},
|
|
menuClasses: function menuClasses() {
|
|
return ['dropdown-menu', this.right ? 'dropdown-menu-right' : 'dropdown-menu-left', this.visible ? 'show' : '', this.extraMenuClasses ? this.extraMenuClasses : ''];
|
|
}
|
|
},
|
|
props: {
|
|
noCaret: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
extraToggleClasses: {
|
|
// Extra Toggle classes
|
|
type: String,
|
|
default: ''
|
|
},
|
|
extraMenuClasses: {
|
|
// Extra Menu classes
|
|
type: String,
|
|
default: ''
|
|
},
|
|
role: {
|
|
type: String,
|
|
default: 'menu'
|
|
}
|
|
}
|
|
};
|
|
|
|
var components$r = {
|
|
bNav: bNav,
|
|
bNavItem: bNavItem,
|
|
bNavText: bNavText,
|
|
bNavForm: bNavForm,
|
|
bNavItemDropdown: bNavItemDropdown,
|
|
bNavItemDd: bNavItemDropdown,
|
|
bNavDropdown: bNavItemDropdown,
|
|
bNavDd: bNavItemDropdown
|
|
};
|
|
|
|
var VuePlugin$t = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$r);
|
|
Vue.use(VuePlugin$c);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$t);
|
|
|
|
var props$D = {
|
|
tag: {
|
|
type: String,
|
|
default: 'nav'
|
|
},
|
|
type: {
|
|
type: String,
|
|
default: 'light'
|
|
},
|
|
variant: {
|
|
type: String
|
|
},
|
|
toggleable: {
|
|
type: [Boolean, String],
|
|
default: false
|
|
},
|
|
toggleBreakpoint: {
|
|
// Deprecated. Set toggleable to a string breakpoint
|
|
type: String,
|
|
default: null
|
|
},
|
|
fixed: {
|
|
type: String
|
|
},
|
|
sticky: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
};
|
|
|
|
var bNavbar = {
|
|
functional: true,
|
|
props: props$D,
|
|
render: function render(h, _ref) {
|
|
var _class;
|
|
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
var breakpoint = props.toggleBreakpoint || (props.toggleable === true ? 'sm' : props.toggleable) || 'sm';
|
|
return h(props.tag, mergeData(data, {
|
|
staticClass: 'navbar',
|
|
class: (_class = {}, defineProperty(_class, 'navbar-' + props.type, Boolean(props.type)), defineProperty(_class, 'bg-' + props.variant, Boolean(props.variant)), defineProperty(_class, 'fixed-' + props.fixed, Boolean(props.fixed)), defineProperty(_class, 'sticky-top', props.sticky), defineProperty(_class, 'navbar-expand-' + breakpoint, props.toggleable !== false), _class)
|
|
}), children);
|
|
}
|
|
};
|
|
|
|
var props$E = {
|
|
tag: {
|
|
type: String,
|
|
default: 'ul'
|
|
},
|
|
fill: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
justified: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
};
|
|
|
|
var bNavbarNav = {
|
|
functional: true,
|
|
props: props$E,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
return h(props.tag, mergeData(data, {
|
|
staticClass: 'navbar-nav',
|
|
class: {
|
|
'nav-fill': props.fill,
|
|
'nav-justified': props.justified
|
|
}
|
|
}), children);
|
|
}
|
|
};
|
|
|
|
var linkProps$3 = propsFactory();
|
|
linkProps$3.href.default = undefined;
|
|
linkProps$3.to.default = undefined;
|
|
|
|
var props$F = assign(linkProps$3, {
|
|
tag: {
|
|
type: String,
|
|
default: 'div'
|
|
}
|
|
});
|
|
|
|
var bNavbarBrand = {
|
|
functional: true,
|
|
props: props$F,
|
|
render: function render(h, _ref) {
|
|
var props = _ref.props,
|
|
data = _ref.data,
|
|
children = _ref.children;
|
|
|
|
var isLink = Boolean(props.to || props.href);
|
|
var tag = isLink ? bLink : props.tag;
|
|
|
|
return h(tag, mergeData(data, {
|
|
staticClass: 'navbar-brand',
|
|
props: isLink ? pluckProps(linkProps$3, props) : {}
|
|
}), children);
|
|
}
|
|
};
|
|
|
|
var bNavbarToggle = {
|
|
mixins: [listenOnRootMixin],
|
|
render: function render(h) {
|
|
return h('button', {
|
|
class: ['navbar-toggler'],
|
|
attrs: {
|
|
type: 'button',
|
|
'aria-label': this.label,
|
|
'aria-controls': this.target,
|
|
'aria-expanded': this.toggleState ? 'true' : 'false'
|
|
},
|
|
on: { click: this.onClick }
|
|
}, [this.$slots.default || h('span', { class: ['navbar-toggler-icon'] })]);
|
|
},
|
|
data: function data() {
|
|
return {
|
|
toggleState: false
|
|
};
|
|
},
|
|
|
|
props: {
|
|
label: {
|
|
type: String,
|
|
default: 'Toggle navigation'
|
|
},
|
|
target: {
|
|
type: String,
|
|
required: true
|
|
}
|
|
},
|
|
methods: {
|
|
onClick: function onClick() {
|
|
this.$root.$emit('bv::toggle::collapse', this.target);
|
|
},
|
|
handleStateEvt: function handleStateEvt(id, state) {
|
|
if (id === this.target) {
|
|
this.toggleState = state;
|
|
}
|
|
}
|
|
},
|
|
created: function created() {
|
|
this.listenOnRoot('bv::collapse::state', this.handleStateEvt);
|
|
}
|
|
};
|
|
|
|
var components$s = {
|
|
bNavbar: bNavbar,
|
|
bNavbarNav: bNavbarNav,
|
|
bNavbarBrand: bNavbarBrand,
|
|
bNavbarToggle: bNavbarToggle,
|
|
bNavToggle: bNavbarToggle
|
|
};
|
|
|
|
var VuePlugin$u = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$s);
|
|
Vue.use(VuePlugin$t);
|
|
Vue.use(VuePlugin$b);
|
|
Vue.use(VuePlugin$c);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$u);
|
|
|
|
/**
|
|
* @param {number} length
|
|
* @return {Array}
|
|
*/
|
|
var range = (function (length) {
|
|
return Array.apply(null, { length: length });
|
|
});
|
|
|
|
/*
|
|
* Comon props, computed, data, render function, and methods for b-pagination and b-pagination-nav
|
|
*/
|
|
|
|
// Make an array of N to N+X
|
|
function makePageArray(startNum, numPages) {
|
|
return range(numPages).map(function (value, index) {
|
|
return { number: index + startNum, className: null };
|
|
});
|
|
}
|
|
|
|
// Threshold of limit size when we start/stop showing ellipsis
|
|
var ELLIPSIS_THRESHOLD = 3;
|
|
|
|
// Props object
|
|
var props$G = {
|
|
disabled: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
value: {
|
|
type: Number,
|
|
default: 1
|
|
},
|
|
limit: {
|
|
type: Number,
|
|
default: 5
|
|
},
|
|
size: {
|
|
type: String,
|
|
default: 'md'
|
|
},
|
|
align: {
|
|
type: String,
|
|
default: 'left'
|
|
},
|
|
hideGotoEndButtons: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
ariaLabel: {
|
|
type: String,
|
|
default: 'Pagination'
|
|
},
|
|
labelFirstPage: {
|
|
type: String,
|
|
default: 'Goto first page'
|
|
},
|
|
firstText: {
|
|
type: String,
|
|
default: '«'
|
|
},
|
|
labelPrevPage: {
|
|
type: String,
|
|
default: 'Goto previous page'
|
|
},
|
|
prevText: {
|
|
type: String,
|
|
default: '‹'
|
|
},
|
|
labelNextPage: {
|
|
type: String,
|
|
default: 'Goto next page'
|
|
},
|
|
nextText: {
|
|
type: String,
|
|
default: '›'
|
|
},
|
|
labelLastPage: {
|
|
type: String,
|
|
default: 'Goto last page'
|
|
},
|
|
lastText: {
|
|
type: String,
|
|
default: '»'
|
|
},
|
|
labelPage: {
|
|
type: String,
|
|
default: 'Goto page'
|
|
},
|
|
hideEllipsis: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
ellipsisText: {
|
|
type: String,
|
|
default: '…'
|
|
}
|
|
};
|
|
|
|
var paginationMixin = {
|
|
components: { bLink: bLink },
|
|
data: function data() {
|
|
return {
|
|
showFirstDots: false,
|
|
showLastDots: false,
|
|
currentPage: this.value
|
|
};
|
|
},
|
|
|
|
props: props$G,
|
|
render: function render(h) {
|
|
var _this = this;
|
|
|
|
var buttons = [];
|
|
|
|
// Factory function for prev/next/first/last buttons
|
|
var makeEndBtns = function makeEndBtns(linkTo, ariaLabel, btnText, pageTest) {
|
|
var button = void 0;
|
|
pageTest = pageTest || linkTo; // Page # to test against to disable
|
|
if (_this.disabled || _this.isActive(pageTest)) {
|
|
button = h('li', {
|
|
class: ['page-item', 'disabled'],
|
|
attrs: { role: 'none presentation', 'aria-hidden': 'true' }
|
|
}, [h('span', {
|
|
class: ['page-link'],
|
|
domProps: { innerHTML: btnText }
|
|
})]);
|
|
} else {
|
|
button = h('li', {
|
|
class: ['page-item'],
|
|
attrs: { role: 'none presentation' }
|
|
}, [h('b-link', {
|
|
class: ['page-link'],
|
|
props: _this.linkProps(linkTo),
|
|
attrs: {
|
|
role: 'menuitem',
|
|
tabindex: '-1',
|
|
'aria-label': ariaLabel,
|
|
'aria-controls': _this.ariaControls || null
|
|
},
|
|
on: {
|
|
click: function click(evt) {
|
|
_this.onClick(linkTo, evt);
|
|
},
|
|
keydown: function keydown(evt) {
|
|
// Links don't normally respond to SPACE, so we add that functionality
|
|
if (evt.keyCode === KeyCodes.SPACE) {
|
|
evt.preventDefault();
|
|
_this.onClick(linkTo, evt);
|
|
}
|
|
}
|
|
}
|
|
}, [h('span', {
|
|
attrs: { 'aria-hidden': 'true' },
|
|
domProps: { innerHTML: btnText }
|
|
})])]);
|
|
}
|
|
return button;
|
|
};
|
|
|
|
// Ellipsis factory
|
|
var makeEllipsis = function makeEllipsis() {
|
|
return h('li', {
|
|
class: ['page-item', 'disabled', 'd-none', 'd-sm-flex'],
|
|
attrs: { role: 'separator' }
|
|
}, [h('span', {
|
|
class: ['page-link'],
|
|
domProps: { innerHTML: _this.ellipsisText }
|
|
})]);
|
|
};
|
|
|
|
// Goto First Page button
|
|
buttons.push(this.hideGotoEndButtons ? h(false) : makeEndBtns(1, this.labelFirstPage, this.firstText));
|
|
|
|
// Goto Previous page button
|
|
buttons.push(makeEndBtns(this.currentPage - 1, this.labelPrevPage, this.prevText, 1));
|
|
|
|
// First Ellipsis Bookend
|
|
buttons.push(this.showFirstDots ? makeEllipsis() : h(false));
|
|
|
|
// Individual Page links
|
|
this.pageList.forEach(function (page) {
|
|
var inner = void 0;
|
|
var pageNum = _this.makePage(page.number);
|
|
if (_this.disabled) {
|
|
inner = h('span', {
|
|
class: ['page-link'],
|
|
domProps: { innerHTML: pageNum }
|
|
});
|
|
} else {
|
|
var active = _this.isActive(page.number);
|
|
inner = h('b-link', {
|
|
class: _this.pageLinkClasses(page),
|
|
props: _this.linkProps(page.number),
|
|
attrs: {
|
|
role: 'menuitemradio',
|
|
tabindex: active ? '0' : '-1',
|
|
'aria-controls': _this.ariaControls || null,
|
|
'aria-label': _this.labelPage + ' ' + page.number,
|
|
'aria-checked': active ? 'true' : 'false',
|
|
'aria-posinset': page.number,
|
|
'aria-setsize': _this.numberOfPages
|
|
},
|
|
domProps: { innerHTML: pageNum },
|
|
on: {
|
|
click: function click(evt) {
|
|
_this.onClick(page.number, evt);
|
|
},
|
|
keydown: function keydown(evt) {
|
|
if (evt.keyCode === KeyCodes.SPACE) {
|
|
evt.preventDefault();
|
|
_this.onClick(page.number, evt);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
buttons.push(h('li', {
|
|
key: page.number,
|
|
class: _this.pageItemClasses(page),
|
|
attrs: { role: 'none presentation' }
|
|
}, [inner]));
|
|
});
|
|
|
|
// Last Ellipsis Bookend
|
|
buttons.push(this.showLastDots ? makeEllipsis() : h(false));
|
|
|
|
// Goto Next page button
|
|
buttons.push(makeEndBtns(this.currentPage + 1, this.labelNextPage, this.nextText, this.numberOfPages));
|
|
|
|
// Goto Last Page button
|
|
buttons.push(this.hideGotoEndButtons ? h(false) : makeEndBtns(this.numberOfPages, this.labelLastPage, this.lastText));
|
|
|
|
// Assemble the paginatiom buttons
|
|
var pagination = h('ul', {
|
|
ref: 'ul',
|
|
class: ['pagination', 'b-pagination', this.btnSize, this.alignment],
|
|
attrs: {
|
|
role: 'menubar',
|
|
'aria-disabled': this.disabled ? 'true' : 'false',
|
|
'aria-label': this.ariaLabel || null
|
|
},
|
|
on: {
|
|
keydown: function keydown(evt) {
|
|
var keyCode = evt.keyCode;
|
|
var shift = evt.shiftKey;
|
|
if (keyCode === KeyCodes.LEFT) {
|
|
evt.preventDefault();
|
|
shift ? _this.focusFirst() : _this.focusPrev();
|
|
} else if (keyCode === KeyCodes.RIGHT) {
|
|
evt.preventDefault();
|
|
shift ? _this.focusLast() : _this.focusNext();
|
|
}
|
|
}
|
|
}
|
|
}, buttons);
|
|
|
|
// if we are pagination-nav, wrap in '<nav>' wrapper
|
|
return this.isNav ? h('nav', {}, [pagination]) : pagination;
|
|
},
|
|
|
|
watch: {
|
|
currentPage: function currentPage(newPage, oldPage) {
|
|
if (newPage !== oldPage) {
|
|
this.$emit('input', newPage);
|
|
}
|
|
},
|
|
value: function value(newValue, oldValue) {
|
|
if (newValue !== oldValue) {
|
|
this.currentPage = newValue;
|
|
}
|
|
}
|
|
},
|
|
computed: {
|
|
btnSize: function btnSize() {
|
|
return this.size ? 'pagination-' + this.size : '';
|
|
},
|
|
alignment: function alignment() {
|
|
if (this.align === 'center') {
|
|
return 'justify-content-center';
|
|
} else if (this.align === 'end' || this.align === 'right') {
|
|
return 'justify-content-end';
|
|
}
|
|
return '';
|
|
},
|
|
pageList: function pageList() {
|
|
// Sanity checks
|
|
if (this.currentPage > this.numberOfPages) {
|
|
this.currentPage = this.numberOfPages;
|
|
} else if (this.currentPage < 1) {
|
|
this.currentPage = 1;
|
|
}
|
|
// - Hide first ellipsis marker
|
|
this.showFirstDots = false;
|
|
// - Hide last ellipsis marker
|
|
this.showLastDots = false;
|
|
var numLinks = this.limit;
|
|
var startNum = 1;
|
|
if (this.numberOfPages <= this.limit) {
|
|
// Special Case: Less pages available than the limit of displayed pages
|
|
numLinks = this.numberOfPages;
|
|
} else if (this.currentPage < this.limit - 1 && this.limit > ELLIPSIS_THRESHOLD) {
|
|
// We are near the beginning of the page list
|
|
if (!this.hideEllipsis) {
|
|
numLinks = this.limit - 1;
|
|
this.showLastDots = true;
|
|
}
|
|
} else if (this.numberOfPages - this.currentPage + 2 < this.limit && this.limit > ELLIPSIS_THRESHOLD) {
|
|
// We are near the end of the list
|
|
if (!this.hideEllipsis) {
|
|
this.showFirstDots = true;
|
|
numLinks = this.limit - 1;
|
|
}
|
|
startNum = this.numberOfPages - numLinks + 1;
|
|
} else {
|
|
// We are somewhere in the middle of the page list
|
|
if (this.limit > ELLIPSIS_THRESHOLD && !this.hideEllipsis) {
|
|
this.showFirstDots = true;
|
|
this.showLastDots = true;
|
|
numLinks = this.limit - 2;
|
|
}
|
|
startNum = this.currentPage - Math.floor(numLinks / 2);
|
|
}
|
|
// Sanity checks
|
|
if (startNum < 1) {
|
|
startNum = 1;
|
|
} else if (startNum > this.numberOfPages - numLinks) {
|
|
startNum = this.numberOfPages - numLinks + 1;
|
|
}
|
|
// Generate list of page numbers
|
|
var pages = makePageArray(startNum, numLinks);
|
|
// We limit to a total of 3 page buttons on small screens
|
|
// Ellipsis will also be hidden on small screens
|
|
if (pages.length > 3) {
|
|
var idx = this.currentPage - startNum;
|
|
if (idx === 0) {
|
|
// Keep leftmost 3 buttons visible
|
|
for (var i = 3; i < pages.length; i++) {
|
|
pages[i].className = 'd-none d-sm-flex';
|
|
}
|
|
} else if (idx === pages.length - 1) {
|
|
// Keep rightmost 3 buttons visible
|
|
for (var _i = 0; _i < pages.length - 3; _i++) {
|
|
pages[_i].className = 'd-none d-sm-flex';
|
|
}
|
|
} else {
|
|
// hide left button(s)
|
|
for (var _i2 = 0; _i2 < idx - 1; _i2++) {
|
|
pages[_i2].className = 'd-none d-sm-flex';
|
|
}
|
|
// hide right button(s)
|
|
for (var _i3 = pages.length - 1; _i3 > idx + 1; _i3--) {
|
|
pages[_i3].className = 'd-none d-sm-flex';
|
|
}
|
|
}
|
|
}
|
|
return pages;
|
|
}
|
|
},
|
|
methods: {
|
|
isActive: function isActive(pagenum) {
|
|
return pagenum === this.currentPage;
|
|
},
|
|
pageItemClasses: function pageItemClasses(page) {
|
|
return ['page-item', this.disabled ? 'disabled' : '', this.isActive(page.number) ? 'active' : '', page.className];
|
|
},
|
|
pageLinkClasses: function pageLinkClasses(page) {
|
|
return ['page-link', this.disabled ? 'disabled' : '',
|
|
// Interim workaround to get better focus styling of active button
|
|
// See https://github.com/twbs/bootstrap/issues/24838
|
|
this.isActive(page.number) ? 'btn-primary' : ''];
|
|
},
|
|
getButtons: function getButtons() {
|
|
// Return only buttons that are visible
|
|
return selectAll('a.page-link', this.$el).filter(function (btn) {
|
|
return isVisible(btn);
|
|
});
|
|
},
|
|
setBtnFocus: function setBtnFocus(btn) {
|
|
this.$nextTick(function () {
|
|
btn.focus();
|
|
});
|
|
},
|
|
focusCurrent: function focusCurrent() {
|
|
var _this2 = this;
|
|
|
|
var btn = this.getButtons().find(function (el) {
|
|
return parseInt(getAttr(el, 'aria-posinset'), 10) === _this2.currentPage;
|
|
});
|
|
if (btn && btn.focus) {
|
|
this.setBtnFocus(btn);
|
|
} else {
|
|
// Fallback if current page is not in button list
|
|
this.focusFirst();
|
|
}
|
|
},
|
|
focusFirst: function focusFirst() {
|
|
var btn = this.getButtons().find(function (el) {
|
|
return !isDisabled(el);
|
|
});
|
|
if (btn && btn.focus && btn !== document.activeElement) {
|
|
this.setBtnFocus(btn);
|
|
}
|
|
},
|
|
focusLast: function focusLast() {
|
|
var btn = this.getButtons().reverse().find(function (el) {
|
|
return !isDisabled(el);
|
|
});
|
|
if (btn && btn.focus && btn !== document.activeElement) {
|
|
this.setBtnFocus(btn);
|
|
}
|
|
},
|
|
focusPrev: function focusPrev() {
|
|
var buttons = this.getButtons();
|
|
var idx = buttons.indexOf(document.activeElement);
|
|
if (idx > 0 && !isDisabled(buttons[idx - 1]) && buttons[idx - 1].focus) {
|
|
this.setBtnFocus(buttons[idx - 1]);
|
|
}
|
|
},
|
|
focusNext: function focusNext() {
|
|
var buttons = this.getButtons();
|
|
var idx = buttons.indexOf(document.activeElement);
|
|
var cnt = buttons.length - 1;
|
|
if (idx < cnt && !isDisabled(buttons[idx + 1]) && buttons[idx + 1].focus) {
|
|
this.setBtnFocus(buttons[idx + 1]);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
var props$H = {
|
|
perPage: {
|
|
type: Number,
|
|
default: 20
|
|
},
|
|
totalRows: {
|
|
type: Number,
|
|
default: 20
|
|
},
|
|
ariaControls: {
|
|
type: String,
|
|
default: null
|
|
}
|
|
|
|
// Our render function is brought in from the pagination mixin
|
|
};var bPagination = {
|
|
mixins: [paginationMixin],
|
|
props: props$H,
|
|
computed: {
|
|
numberOfPages: function numberOfPages() {
|
|
var result = Math.ceil(this.totalRows / this.perPage);
|
|
return result < 1 ? 1 : result;
|
|
}
|
|
},
|
|
methods: {
|
|
// These methods are used by the render function
|
|
onClick: function onClick(num, evt) {
|
|
var _this = this;
|
|
|
|
// Handle edge cases where number of pages has changed (i.e. if perPage changes)
|
|
if (num > this.numberOfPages) {
|
|
num = this.numberOfPages;
|
|
} else if (num < 1) {
|
|
num = 1;
|
|
}
|
|
this.currentPage = num;
|
|
this.$nextTick(function () {
|
|
// Keep the current button focused if possible
|
|
var target = evt.target;
|
|
if (isVisible(target) && _this.$el.contains(target) && target.focus) {
|
|
target.focus();
|
|
} else {
|
|
_this.focusCurrent();
|
|
}
|
|
});
|
|
this.$emit('change', this.currentPage);
|
|
},
|
|
makePage: function makePage(pagenum) {
|
|
return pagenum;
|
|
},
|
|
linkProps: function linkProps(pagenum) {
|
|
return { href: '#' };
|
|
}
|
|
}
|
|
};
|
|
|
|
var components$t = {
|
|
bPagination: bPagination
|
|
};
|
|
|
|
var VuePlugin$v = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$t);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$v);
|
|
|
|
// Props needed for router links
|
|
var routerProps = pickLinkProps('activeClass', 'exactActiveClass', 'append', 'exact', 'replace', 'target', 'rel');
|
|
|
|
// Props object
|
|
var props$I = assign(
|
|
// pagination-nav specific props
|
|
{
|
|
numberOfPages: {
|
|
type: Number,
|
|
default: 1
|
|
},
|
|
baseUrl: {
|
|
type: String,
|
|
default: '/'
|
|
},
|
|
useRouter: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
linkGen: {
|
|
type: Function,
|
|
default: null
|
|
},
|
|
pageGen: {
|
|
type: Function,
|
|
default: null
|
|
}
|
|
},
|
|
// Router specific props
|
|
routerProps);
|
|
// Our render function is brought in via the pagination mixin
|
|
var bPaginationNav = {
|
|
mixins: [paginationMixin],
|
|
props: props$I,
|
|
computed: {
|
|
// Used by render function to trigger wraping in '<nav>' element
|
|
isNav: function isNav() {
|
|
return true;
|
|
}
|
|
},
|
|
methods: {
|
|
onClick: function onClick(pageNum, evt) {
|
|
this.currentPage = pageNum;
|
|
},
|
|
makePage: function makePage(pagenum) {
|
|
if (this.pageGen && typeof this.pageGen === 'function') {
|
|
return this.pageGen(pagenum);
|
|
}
|
|
return pagenum;
|
|
},
|
|
makeLink: function makeLink(pagenum) {
|
|
if (this.linkGen && typeof this.linkGen === 'function') {
|
|
return this.linkGen(pagenum);
|
|
}
|
|
var link = '' + this.baseUrl + pagenum;
|
|
return this.useRouter ? { path: link } : link;
|
|
},
|
|
linkProps: function linkProps(pagenum) {
|
|
var link = this.makeLink(pagenum);
|
|
var props = {
|
|
href: typeof link === 'string' ? link : void 0,
|
|
target: this.target || null,
|
|
rel: this.rel || null,
|
|
disabled: this.disabled
|
|
};
|
|
if (this.useRouter || (typeof link === 'undefined' ? 'undefined' : _typeof(link)) === 'object') {
|
|
props = assign(props, {
|
|
to: link,
|
|
exact: this.exact,
|
|
activeClass: this.activeClass,
|
|
exactActiveClass: this.exactActiveClass,
|
|
append: this.append,
|
|
replace: this.replace
|
|
});
|
|
}
|
|
return props;
|
|
}
|
|
}
|
|
};
|
|
|
|
var components$u = {
|
|
bPaginationNav: bPaginationNav
|
|
};
|
|
|
|
var VuePlugin$w = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$u);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$w);
|
|
|
|
var NAME = 'tooltip';
|
|
var CLASS_PREFIX = 'bs-tooltip';
|
|
var BSCLS_PREFIX_REGEX = new RegExp('\\b' + CLASS_PREFIX + '\\S+', 'g');
|
|
|
|
var TRANSITION_DURATION = 150;
|
|
|
|
// Modal $root hidden event
|
|
var MODAL_CLOSE_EVENT = 'bv::modal::hidden';
|
|
// Modal container for appending tip/popover
|
|
var MODAL_CLASS = '.modal-content';
|
|
|
|
var AttachmentMap$1 = {
|
|
AUTO: 'auto',
|
|
TOP: 'top',
|
|
RIGHT: 'right',
|
|
BOTTOM: 'bottom',
|
|
LEFT: 'left',
|
|
TOPLEFT: 'top',
|
|
TOPRIGHT: 'top',
|
|
RIGHTTOP: 'right',
|
|
RIGHTBOTTOM: 'right',
|
|
BOTTOMLEFT: 'bottom',
|
|
BOTTOMRIGHT: 'bottom',
|
|
LEFTTOP: 'left',
|
|
LEFTBOTTOM: 'left'
|
|
};
|
|
|
|
var OffsetMap = {
|
|
AUTO: 0,
|
|
TOPLEFT: -1,
|
|
TOP: 0,
|
|
TOPRIGHT: +1,
|
|
RIGHTTOP: -1,
|
|
RIGHT: 0,
|
|
RIGHTBOTTOM: +1,
|
|
BOTTOMLEFT: -1,
|
|
BOTTOM: 0,
|
|
BOTTOMRIGHT: +1,
|
|
LEFTTOP: -1,
|
|
LEFT: 0,
|
|
LEFTBOTTOM: +1
|
|
};
|
|
|
|
var HoverState = {
|
|
SHOW: 'show',
|
|
OUT: 'out'
|
|
};
|
|
|
|
var ClassName = {
|
|
FADE: 'fade',
|
|
SHOW: 'show'
|
|
};
|
|
|
|
var Selector$1 = {
|
|
TOOLTIP: '.tooltip',
|
|
TOOLTIP_INNER: '.tooltip-inner',
|
|
ARROW: '.arrow'
|
|
|
|
// ESLINT: Not used
|
|
// const Trigger = {
|
|
// HOVER: 'hover',
|
|
// FOCUS: 'focus',
|
|
// CLICK: 'click',
|
|
// BLUR: 'blur',
|
|
// MANUAL: 'manual'
|
|
// }
|
|
|
|
};var Defaults$1 = {
|
|
animation: true,
|
|
template: '<div class="tooltip" role="tooltip">' + '<div class="arrow"></div>' + '<div class="tooltip-inner"></div>' + '</div>',
|
|
trigger: 'hover focus',
|
|
title: '',
|
|
delay: 0,
|
|
html: false,
|
|
placement: 'top',
|
|
offset: 0,
|
|
arrowPadding: 6,
|
|
container: false,
|
|
fallbackPlacement: 'flip',
|
|
callbacks: {},
|
|
boundary: 'scrollParent'
|
|
|
|
// Transition Event names
|
|
};var TransitionEndEvents$1 = {
|
|
WebkitTransition: ['webkitTransitionEnd'],
|
|
MozTransition: ['transitionend'],
|
|
OTransition: ['otransitionend', 'oTransitionEnd'],
|
|
transition: ['transitionend']
|
|
|
|
// Client Side Tip ID counter for aria-describedby attribute
|
|
// Could use Alex's uid generator util
|
|
// Each tooltip requires a unique client side ID
|
|
};var NEXTID = 1;
|
|
/* istanbul ignore next */
|
|
function generateId(name) {
|
|
return '__BV_' + name + '_' + NEXTID++ + '__';
|
|
}
|
|
|
|
/*
|
|
* ToolTip Class definition
|
|
*/
|
|
/* istanbul ignore next: difficult to test in Jest/JSDOM environment */
|
|
|
|
var ToolTip = function () {
|
|
// Main constructor
|
|
function ToolTip(element, config, $root) {
|
|
classCallCheck(this, ToolTip);
|
|
|
|
// New tooltip object
|
|
this.$isEnabled = true;
|
|
this.$fadeTimeout = null;
|
|
this.$hoverTimeout = null;
|
|
this.$visibleInterval = null;
|
|
this.$hoverState = '';
|
|
this.$activeTrigger = {};
|
|
this.$popper = null;
|
|
this.$element = element;
|
|
this.$tip = null;
|
|
this.$id = generateId(this.constructor.NAME);
|
|
this.$root = $root || null;
|
|
this.$routeWatcher = null;
|
|
// We use a bound version of the following handlers for root/modal listeners to maintain the 'this' context
|
|
this.$forceHide = this.forceHide.bind(this);
|
|
this.$doHide = this.doHide.bind(this);
|
|
this.$doShow = this.doShow.bind(this);
|
|
this.$doDisable = this.doDisable.bind(this);
|
|
this.$doEnable = this.doEnable.bind(this);
|
|
// Set the configuration
|
|
this.updateConfig(config);
|
|
}
|
|
|
|
// NOTE: Overridden by PopOver class
|
|
|
|
|
|
createClass(ToolTip, [{
|
|
key: 'updateConfig',
|
|
|
|
|
|
// Update config
|
|
value: function updateConfig(config) {
|
|
// Merge config into defaults. We use "this" here because PopOver overrides Default
|
|
var updatedConfig = assign({}, this.constructor.Default, config);
|
|
|
|
// Sanitize delay
|
|
if (config.delay && typeof config.delay === 'number') {
|
|
updatedConfig.delay = {
|
|
show: config.delay,
|
|
hide: config.delay
|
|
};
|
|
}
|
|
|
|
// Title for tooltip and popover
|
|
if (config.title && typeof config.title === 'number') {
|
|
updatedConfig.title = config.title.toString();
|
|
}
|
|
|
|
// Content only for popover
|
|
if (config.content && typeof config.content === 'number') {
|
|
updatedConfig.content = config.content.toString();
|
|
}
|
|
|
|
// Hide element original title if needed
|
|
this.fixTitle();
|
|
// Update the config
|
|
this.$config = updatedConfig;
|
|
// Stop/Restart listening
|
|
this.unListen();
|
|
this.listen();
|
|
}
|
|
|
|
// Destroy this instance
|
|
|
|
}, {
|
|
key: 'destroy',
|
|
value: function destroy() {
|
|
// Stop listening to trigger events
|
|
this.unListen();
|
|
// Disable while open listeners/watchers
|
|
this.setWhileOpenListeners(false);
|
|
// Clear any timeouts
|
|
clearTimeout(this.$hoverTimeout);
|
|
this.$hoverTimeout = null;
|
|
clearTimeout(this.$fadeTimeout);
|
|
this.$fadeTimeout = null;
|
|
// Remove popper
|
|
if (this.$popper) {
|
|
this.$popper.destroy();
|
|
}
|
|
this.$popper = null;
|
|
// Remove tip from document
|
|
if (this.$tip && this.$tip.parentElement) {
|
|
this.$tip.parentElement.removeChild(this.$tip);
|
|
}
|
|
this.$tip = null;
|
|
// Null out other properties
|
|
this.$id = null;
|
|
this.$isEnabled = null;
|
|
this.$root = null;
|
|
this.$element = null;
|
|
this.$config = null;
|
|
this.$hoverState = null;
|
|
this.$activeTrigger = null;
|
|
this.$forceHide = null;
|
|
this.$doHide = null;
|
|
this.$doShow = null;
|
|
this.$doDisable = null;
|
|
this.$doEnable = null;
|
|
}
|
|
}, {
|
|
key: 'enable',
|
|
value: function enable() {
|
|
// Create a non-cancelable BvEvent
|
|
var enabledEvt = new BvEvent('enabled', {
|
|
cancelable: false,
|
|
target: this.$element,
|
|
relatedTarget: null
|
|
});
|
|
this.$isEnabled = true;
|
|
this.emitEvent(enabledEvt);
|
|
}
|
|
}, {
|
|
key: 'disable',
|
|
value: function disable() {
|
|
// Create a non-cancelable BvEvent
|
|
var disabledEvt = new BvEvent('disabled', {
|
|
cancelable: false,
|
|
target: this.$element,
|
|
relatedTarget: null
|
|
});
|
|
this.$isEnabled = false;
|
|
this.emitEvent(disabledEvt);
|
|
}
|
|
|
|
// Click toggler
|
|
|
|
}, {
|
|
key: 'toggle',
|
|
value: function toggle(event) {
|
|
if (!this.$isEnabled) {
|
|
return;
|
|
}
|
|
if (event) {
|
|
this.$activeTrigger.click = !this.$activeTrigger.click;
|
|
|
|
if (this.isWithActiveTrigger()) {
|
|
this.enter(null);
|
|
} else {
|
|
this.leave(null);
|
|
}
|
|
} else {
|
|
if (hasClass(this.getTipElement(), ClassName.SHOW)) {
|
|
this.leave(null);
|
|
} else {
|
|
this.enter(null);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Show tooltip
|
|
|
|
}, {
|
|
key: 'show',
|
|
value: function show() {
|
|
var _this = this;
|
|
|
|
if (!document.body.contains(this.$element) || !isVisible(this.$element)) {
|
|
// If trigger element isn't in the DOM or is not visible
|
|
return;
|
|
}
|
|
// Build tooltip element (also sets this.$tip)
|
|
var tip = this.getTipElement();
|
|
this.fixTitle();
|
|
this.setContent(tip);
|
|
if (!this.isWithContent(tip)) {
|
|
// if No content, don't bother showing
|
|
this.$tip = null;
|
|
return;
|
|
}
|
|
|
|
// Set ID on tip and aria-describedby on element
|
|
setAttr(tip, 'id', this.$id);
|
|
this.addAriaDescribedby();
|
|
|
|
// Set animation on or off
|
|
if (this.$config.animation) {
|
|
addClass(tip, ClassName.FADE);
|
|
} else {
|
|
removeClass(tip, ClassName.FADE);
|
|
}
|
|
|
|
var placement = this.getPlacement();
|
|
var attachment = this.constructor.getAttachment(placement);
|
|
this.addAttachmentClass(attachment);
|
|
|
|
// Create a cancelable BvEvent
|
|
var showEvt = new BvEvent('show', {
|
|
cancelable: true,
|
|
target: this.$element,
|
|
relatedTarget: tip
|
|
});
|
|
this.emitEvent(showEvt);
|
|
if (showEvt.defaultPrevented) {
|
|
// Don't show if event cancelled
|
|
this.$tip = null;
|
|
return;
|
|
}
|
|
|
|
// Insert tooltip if needed
|
|
var container = this.getContainer();
|
|
if (!document.body.contains(tip)) {
|
|
container.appendChild(tip);
|
|
}
|
|
|
|
// Refresh popper
|
|
this.removePopper();
|
|
this.$popper = new Popper(this.$element, tip, this.getPopperConfig(placement, tip));
|
|
|
|
// Transitionend Callback
|
|
var complete = function complete() {
|
|
if (_this.$config.animation) {
|
|
_this.fixTransition(tip);
|
|
}
|
|
var prevHoverState = _this.$hoverState;
|
|
_this.$hoverState = null;
|
|
if (prevHoverState === HoverState.OUT) {
|
|
_this.leave(null);
|
|
}
|
|
// Create a non-cancelable BvEvent
|
|
var shownEvt = new BvEvent('shown', {
|
|
cancelable: false,
|
|
target: _this.$element,
|
|
relatedTarget: tip
|
|
});
|
|
_this.emitEvent(shownEvt);
|
|
};
|
|
|
|
// Enable while open listeners/watchers
|
|
this.setWhileOpenListeners(true);
|
|
|
|
// Show tip
|
|
addClass(tip, ClassName.SHOW);
|
|
|
|
// Start the transition/animation
|
|
this.transitionOnce(tip, complete);
|
|
}
|
|
|
|
// handler for periodic visibility check
|
|
|
|
}, {
|
|
key: 'visibleCheck',
|
|
value: function visibleCheck(on) {
|
|
var _this2 = this;
|
|
|
|
clearInterval(this.$visibleInterval);
|
|
this.$visibleInterval = null;
|
|
if (on) {
|
|
this.$visibleInterval = setInterval(function () {
|
|
var tip = _this2.getTipElement();
|
|
if (tip && !isVisible(_this2.$element) && hasClass(tip, ClassName.SHOW)) {
|
|
// Element is no longer visible, so force-hide the tooltip
|
|
_this2.forceHide();
|
|
}
|
|
}, 100);
|
|
}
|
|
}
|
|
}, {
|
|
key: 'setWhileOpenListeners',
|
|
value: function setWhileOpenListeners(on) {
|
|
// Modal close events
|
|
this.setModalListener(on);
|
|
// Periodic $element visibility check
|
|
// For handling when tip is in <keepalive>, tabs, carousel, etc
|
|
this.visibleCheck(on);
|
|
// Route change events
|
|
this.setRouteWatcher(on);
|
|
// Ontouch start listeners
|
|
this.setOnTouchStartListener(on);
|
|
if (on && /(focus|blur)/.test(this.$config.trigger)) {
|
|
// If focus moves between trigger element and tip container, dont close
|
|
eventOn(this.$tip, 'focusout', this);
|
|
} else {
|
|
eventOff(this.$tip, 'focusout', this);
|
|
}
|
|
}
|
|
|
|
// force hide of tip (internal method)
|
|
|
|
}, {
|
|
key: 'forceHide',
|
|
value: function forceHide() {
|
|
if (!this.$tip || !hasClass(this.$tip, ClassName.SHOW)) {
|
|
return;
|
|
}
|
|
// Disable while open listeners/watchers
|
|
this.setWhileOpenListeners(false);
|
|
// Clear any hover enter/leave event
|
|
clearTimeout(this.$hoverTimeout);
|
|
this.$hoverTimeout = null;
|
|
this.$hoverState = '';
|
|
// Hide the tip
|
|
this.hide(null, true);
|
|
}
|
|
|
|
// Hide tooltip
|
|
|
|
}, {
|
|
key: 'hide',
|
|
value: function hide(callback, force) {
|
|
var _this3 = this;
|
|
|
|
var tip = this.$tip;
|
|
if (!tip) {
|
|
return;
|
|
}
|
|
|
|
// Create a canelable BvEvent
|
|
var hideEvt = new BvEvent('hide', {
|
|
// We disable cancelling if force is true
|
|
cancelable: !force,
|
|
target: this.$element,
|
|
relatedTarget: tip
|
|
});
|
|
this.emitEvent(hideEvt);
|
|
if (hideEvt.defaultPrevented) {
|
|
// Don't hide if event cancelled
|
|
return;
|
|
}
|
|
|
|
// Transitionend Callback
|
|
/* istanbul ignore next */
|
|
var complete = function complete() {
|
|
if (_this3.$hoverState !== HoverState.SHOW && tip.parentNode) {
|
|
// Remove tip from dom, and force recompile on next show
|
|
tip.parentNode.removeChild(tip);
|
|
_this3.removeAriaDescribedby();
|
|
_this3.removePopper();
|
|
_this3.$tip = null;
|
|
}
|
|
if (callback) {
|
|
callback();
|
|
}
|
|
// Create a non-cancelable BvEvent
|
|
var hiddenEvt = new BvEvent('hidden', {
|
|
cancelable: false,
|
|
target: _this3.$element,
|
|
relatedTarget: null
|
|
});
|
|
_this3.emitEvent(hiddenEvt);
|
|
};
|
|
|
|
// Disable while open listeners/watchers
|
|
this.setWhileOpenListeners(false);
|
|
|
|
// If forced close, disable animation
|
|
if (force) {
|
|
removeClass(tip, ClassName.FADE);
|
|
}
|
|
// Hide tip
|
|
removeClass(tip, ClassName.SHOW);
|
|
|
|
this.$activeTrigger.click = false;
|
|
this.$activeTrigger.focus = false;
|
|
this.$activeTrigger.hover = false;
|
|
|
|
// Start the hide transition
|
|
this.transitionOnce(tip, complete);
|
|
|
|
this.$hoverState = '';
|
|
}
|
|
}, {
|
|
key: 'emitEvent',
|
|
value: function emitEvent(evt) {
|
|
var evtName = evt.type;
|
|
if (this.$root && this.$root.$emit) {
|
|
// Emit an event on $root
|
|
this.$root.$emit('bv::' + this.constructor.NAME + '::' + evtName, evt);
|
|
}
|
|
var callbacks = this.$config.callbacks || {};
|
|
if (typeof callbacks[evtName] === 'function') {
|
|
callbacks[evtName](evt);
|
|
}
|
|
}
|
|
}, {
|
|
key: 'getContainer',
|
|
value: function getContainer() {
|
|
var container = this.$config.container;
|
|
var body = document.body;
|
|
// If we are in a modal, we append to the modal instead of body, unless a container is specified
|
|
return container === false ? closest(MODAL_CLASS, this.$element) || body : select(container, body) || body;
|
|
}
|
|
|
|
// Will be overritten by popover if needed
|
|
|
|
}, {
|
|
key: 'addAriaDescribedby',
|
|
value: function addAriaDescribedby() {
|
|
// Add aria-describedby on trigger element, without removing any other IDs
|
|
var desc = getAttr(this.$element, 'aria-describedby') || '';
|
|
desc = desc.split(/\s+/).concat(this.$id).join(' ').trim();
|
|
setAttr(this.$element, 'aria-describedby', desc);
|
|
}
|
|
|
|
// Will be overritten by popover if needed
|
|
|
|
}, {
|
|
key: 'removeAriaDescribedby',
|
|
value: function removeAriaDescribedby() {
|
|
var _this4 = this;
|
|
|
|
var desc = getAttr(this.$element, 'aria-describedby') || '';
|
|
desc = desc.split(/\s+/).filter(function (d) {
|
|
return d !== _this4.$id;
|
|
}).join(' ').trim();
|
|
if (desc) {
|
|
setAttr(this.$element, 'aria-describedby', desc);
|
|
} else {
|
|
removeAttr(this.$element, 'aria-describedby');
|
|
}
|
|
}
|
|
}, {
|
|
key: 'removePopper',
|
|
value: function removePopper() {
|
|
if (this.$popper) {
|
|
this.$popper.destroy();
|
|
}
|
|
this.$popper = null;
|
|
}
|
|
|
|
/* istanbul ignore next */
|
|
|
|
}, {
|
|
key: 'transitionOnce',
|
|
value: function transitionOnce(tip, complete) {
|
|
var _this5 = this;
|
|
|
|
var transEvents = this.getTransitionEndEvents();
|
|
var called = false;
|
|
clearTimeout(this.$fadeTimeout);
|
|
this.$fadeTimeout = null;
|
|
var fnOnce = function fnOnce() {
|
|
if (called) {
|
|
return;
|
|
}
|
|
called = true;
|
|
clearTimeout(_this5.$fadeTimeout);
|
|
_this5.$fadeTimeout = null;
|
|
transEvents.forEach(function (evtName) {
|
|
eventOff(tip, evtName, fnOnce);
|
|
});
|
|
// Call complete callback
|
|
complete();
|
|
};
|
|
if (hasClass(tip, ClassName.FADE)) {
|
|
transEvents.forEach(function (evtName) {
|
|
eventOn(tip, evtName, fnOnce);
|
|
});
|
|
// Fallback to setTimeout
|
|
this.$fadeTimeout = setTimeout(fnOnce, TRANSITION_DURATION);
|
|
} else {
|
|
fnOnce();
|
|
}
|
|
}
|
|
|
|
// What transitionend event(s) to use? (returns array of event names)
|
|
|
|
}, {
|
|
key: 'getTransitionEndEvents',
|
|
value: function getTransitionEndEvents() {
|
|
for (var name in TransitionEndEvents$1) {
|
|
if (this.$element.style[name] !== undefined) {
|
|
return TransitionEndEvents$1[name];
|
|
}
|
|
}
|
|
// fallback
|
|
return [];
|
|
}
|
|
}, {
|
|
key: 'update',
|
|
value: function update() {
|
|
if (this.$popper !== null) {
|
|
this.$popper.scheduleUpdate();
|
|
}
|
|
}
|
|
|
|
// NOTE: Overridden by PopOver class
|
|
|
|
}, {
|
|
key: 'isWithContent',
|
|
value: function isWithContent(tip) {
|
|
tip = tip || this.$tip;
|
|
if (!tip) {
|
|
return false;
|
|
}
|
|
return Boolean((select(Selector$1.TOOLTIP_INNER, tip) || {}).innerHTML);
|
|
}
|
|
|
|
// NOTE: Overridden by PopOver class
|
|
|
|
}, {
|
|
key: 'addAttachmentClass',
|
|
value: function addAttachmentClass(attachment) {
|
|
addClass(this.getTipElement(), CLASS_PREFIX + '-' + attachment);
|
|
}
|
|
}, {
|
|
key: 'getTipElement',
|
|
value: function getTipElement() {
|
|
if (!this.$tip) {
|
|
// Try and compile user supplied template, or fallback to default template
|
|
this.$tip = this.compileTemplate(this.$config.template) || this.compileTemplate(this.constructor.Default.template);
|
|
}
|
|
// Add tab index so tip can be focused, and to allow it to be set as relatedTargt in focusin/out events
|
|
this.$tip.tabIndex = -1;
|
|
return this.$tip;
|
|
}
|
|
}, {
|
|
key: 'compileTemplate',
|
|
value: function compileTemplate(html) {
|
|
if (!html || typeof html !== 'string') {
|
|
return null;
|
|
}
|
|
var div = document.createElement('div');
|
|
div.innerHTML = html.trim();
|
|
var node = div.firstElementChild ? div.removeChild(div.firstElementChild) : null;
|
|
div = null;
|
|
return node;
|
|
}
|
|
|
|
// NOTE: Overridden by PopOver class
|
|
|
|
}, {
|
|
key: 'setContent',
|
|
value: function setContent(tip) {
|
|
this.setElementContent(select(Selector$1.TOOLTIP_INNER, tip), this.getTitle());
|
|
removeClass(tip, ClassName.FADE);
|
|
removeClass(tip, ClassName.SHOW);
|
|
}
|
|
}, {
|
|
key: 'setElementContent',
|
|
value: function setElementContent(container, content) {
|
|
if (!container) {
|
|
// If container element doesn't exist, just return
|
|
return;
|
|
}
|
|
var allowHtml = this.$config.html;
|
|
if ((typeof content === 'undefined' ? 'undefined' : _typeof(content)) === 'object' && content.nodeType) {
|
|
// content is a DOM node
|
|
if (allowHtml) {
|
|
if (content.parentElement !== container) {
|
|
container.innerHtml = '';
|
|
container.appendChild(content);
|
|
}
|
|
} else {
|
|
container.innerText = content.innerText;
|
|
}
|
|
} else {
|
|
// We have a plain HTML string or Text
|
|
container[allowHtml ? 'innerHTML' : 'innerText'] = content;
|
|
}
|
|
}
|
|
|
|
// NOTE: Overridden by PopOver class
|
|
|
|
}, {
|
|
key: 'getTitle',
|
|
value: function getTitle() {
|
|
var title = this.$config.title || '';
|
|
if (typeof title === 'function') {
|
|
// Call the function to get the title value
|
|
title = title(this.$element);
|
|
}
|
|
if ((typeof title === 'undefined' ? 'undefined' : _typeof(title)) === 'object' && title.nodeType && !title.innerHTML.trim()) {
|
|
// We have a DOM node, but without inner content, so just return empty string
|
|
title = '';
|
|
}
|
|
if (typeof title === 'string') {
|
|
title = title.trim();
|
|
}
|
|
if (!title) {
|
|
// If an explicit title is not given, try element's title atributes
|
|
title = getAttr(this.$element, 'title') || getAttr(this.$element, 'data-original-title') || '';
|
|
title = title.trim();
|
|
}
|
|
|
|
return title;
|
|
}
|
|
}, {
|
|
key: 'listen',
|
|
value: function listen() {
|
|
var _this6 = this;
|
|
|
|
var triggers = this.$config.trigger.trim().split(/\s+/);
|
|
var el = this.$element;
|
|
|
|
// Listen for global show/hide events
|
|
this.setRootListener(true);
|
|
|
|
// Using 'this' as the handler will get automagically directed to this.handleEvent
|
|
// And maintain our binding to 'this'
|
|
triggers.forEach(function (trigger) {
|
|
if (trigger === 'click') {
|
|
eventOn(el, 'click', _this6);
|
|
} else if (trigger === 'focus') {
|
|
eventOn(el, 'focusin', _this6);
|
|
eventOn(el, 'focusout', _this6);
|
|
} else if (trigger === 'blur') {
|
|
// Used to close $tip when element looses focus
|
|
eventOn(el, 'focusout', _this6);
|
|
} else if (trigger === 'hover') {
|
|
eventOn(el, 'mouseenter', _this6);
|
|
eventOn(el, 'mouseleave', _this6);
|
|
}
|
|
}, this);
|
|
}
|
|
}, {
|
|
key: 'unListen',
|
|
value: function unListen() {
|
|
var _this7 = this;
|
|
|
|
var events = ['click', 'focusin', 'focusout', 'mouseenter', 'mouseleave'];
|
|
// Using "this" as the handler will get automagically directed to this.handleEvent
|
|
events.forEach(function (evt) {
|
|
eventOff(_this7.$element, evt, _this7);
|
|
}, this);
|
|
|
|
// Stop listening for global show/hide/enable/disable events
|
|
this.setRootListener(false);
|
|
}
|
|
}, {
|
|
key: 'handleEvent',
|
|
value: function handleEvent(e) {
|
|
// This special method allows us to use "this" as the event handlers
|
|
if (isDisabled(this.$element)) {
|
|
// If disabled, don't do anything. Note: if tip is shown before element gets
|
|
// disabled, then tip not close until no longer disabled or forcefully closed.
|
|
return;
|
|
}
|
|
if (!this.$isEnabled) {
|
|
// If not enable
|
|
return;
|
|
}
|
|
var type = e.type;
|
|
var target = e.target;
|
|
var relatedTarget = e.relatedTarget;
|
|
var $element = this.$element;
|
|
var $tip = this.$tip;
|
|
if (type === 'click') {
|
|
this.toggle(e);
|
|
} else if (type === 'focusin' || type === 'mouseenter') {
|
|
this.enter(e);
|
|
} else if (type === 'focusout') {
|
|
// target is the element which is loosing focus
|
|
// And relatedTarget is the element gaining focus
|
|
if ($tip && $element && $element.contains(target) && $tip.contains(relatedTarget)) {
|
|
// If focus moves from $element to $tip, don't trigger a leave
|
|
return;
|
|
}
|
|
if ($tip && $element && $tip.contains(target) && $element.contains(relatedTarget)) {
|
|
// If focus moves from $tip to $element, don't trigger a leave
|
|
return;
|
|
}
|
|
if ($tip && $tip.contains(target) && $tip.contains(relatedTarget)) {
|
|
// If focus moves within $tip, don't trigger a leave
|
|
return;
|
|
}
|
|
if ($element && $element.contains(target) && $element.contains(relatedTarget)) {
|
|
// If focus moves within $element, don't trigger a leave
|
|
return;
|
|
}
|
|
// Otherwise trigger a leave
|
|
this.leave(e);
|
|
} else if (type === 'mouseleave') {
|
|
this.leave(e);
|
|
}
|
|
}
|
|
|
|
/* istanbul ignore next */
|
|
|
|
}, {
|
|
key: 'setRouteWatcher',
|
|
value: function setRouteWatcher(on) {
|
|
var _this8 = this;
|
|
|
|
if (on) {
|
|
this.setRouteWatcher(false);
|
|
if (this.$root && Boolean(this.$root.$route)) {
|
|
this.$routeWatcher = this.$root.$watch('$route', function (newVal, oldVal) {
|
|
if (newVal === oldVal) {
|
|
return;
|
|
}
|
|
// If route has changed, we force hide the tooltip/popover
|
|
_this8.forceHide();
|
|
});
|
|
}
|
|
} else {
|
|
if (this.$routeWatcher) {
|
|
// cancel the route watcher by calling hte stored reference
|
|
this.$routeWatcher();
|
|
this.$routeWatcher = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* istanbul ignore next */
|
|
|
|
}, {
|
|
key: 'setModalListener',
|
|
value: function setModalListener(on) {
|
|
var modal = closest(MODAL_CLASS, this.$element);
|
|
if (!modal) {
|
|
// If we are not in a modal, don't worry. be happy
|
|
return;
|
|
}
|
|
// We can listen for modal hidden events on $root
|
|
if (this.$root) {
|
|
this.$root[on ? '$on' : '$off'](MODAL_CLOSE_EVENT, this.$forceHide);
|
|
}
|
|
}
|
|
|
|
/* istanbul ignore next */
|
|
|
|
}, {
|
|
key: 'setRootListener',
|
|
value: function setRootListener(on) {
|
|
// Listen for global 'bv::{hide|show}::{tooltip|popover}' hide request event
|
|
if (this.$root) {
|
|
this.$root[on ? '$on' : '$off']('bv::hide::' + this.constructor.NAME, this.$doHide);
|
|
this.$root[on ? '$on' : '$off']('bv::show::' + this.constructor.NAME, this.$doShow);
|
|
this.$root[on ? '$on' : '$off']('bv::disable::' + this.constructor.NAME, this.$doDisable);
|
|
this.$root[on ? '$on' : '$off']('bv::enable::' + this.constructor.NAME, this.$doEnable);
|
|
}
|
|
}
|
|
}, {
|
|
key: 'doHide',
|
|
value: function doHide(id) {
|
|
// Programmatically hide tooltip or popover
|
|
if (!id) {
|
|
// Close all tooltips or popovers
|
|
this.forceHide();
|
|
} else if (this.$element && this.$element.id && this.$element.id === id) {
|
|
// Close this specific tooltip or popover
|
|
this.hide();
|
|
}
|
|
}
|
|
}, {
|
|
key: 'doShow',
|
|
value: function doShow(id) {
|
|
// Programmatically show tooltip or popover
|
|
if (!id) {
|
|
// Open all tooltips or popovers
|
|
this.show();
|
|
} else if (id && this.$element && this.$element.id && this.$element.id === id) {
|
|
// Show this specific tooltip or popover
|
|
this.show();
|
|
}
|
|
}
|
|
}, {
|
|
key: 'doDisable',
|
|
value: function doDisable(id) {
|
|
// Programmatically disable tooltip or popover
|
|
if (!id) {
|
|
// Disable all tooltips or popovers
|
|
this.disable();
|
|
} else if (this.$element && this.$element.id && this.$element.id === id) {
|
|
// Disable this specific tooltip or popover
|
|
this.disable();
|
|
}
|
|
}
|
|
}, {
|
|
key: 'doEnable',
|
|
value: function doEnable(id) {
|
|
// Programmatically enable tooltip or popover
|
|
if (!id) {
|
|
// Enable all tooltips or popovers
|
|
this.enable();
|
|
} else if (this.$element && this.$element.id && this.$element.id === id) {
|
|
// Enable this specific tooltip or popover
|
|
this.enable();
|
|
}
|
|
}
|
|
|
|
/* istanbul ignore next */
|
|
|
|
}, {
|
|
key: 'setOnTouchStartListener',
|
|
value: function setOnTouchStartListener(on) {
|
|
var _this9 = this;
|
|
|
|
// if this is a touch-enabled device we add extra
|
|
// empty mouseover listeners to the body's immediate children;
|
|
// only needed because of broken event delegation on iOS
|
|
// https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
|
|
if ('ontouchstart' in document.documentElement) {
|
|
from(document.body.children).forEach(function (el) {
|
|
if (on) {
|
|
eventOn(el, 'mouseover', _this9._noop);
|
|
} else {
|
|
eventOff(el, 'mouseover', _this9._noop);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
/* istanbul ignore next */
|
|
|
|
}, {
|
|
key: '_noop',
|
|
value: function _noop() {
|
|
// Empty noop handler for ontouchstart devices
|
|
}
|
|
}, {
|
|
key: 'fixTitle',
|
|
value: function fixTitle() {
|
|
var el = this.$element;
|
|
var titleType = _typeof(getAttr(el, 'data-original-title'));
|
|
if (getAttr(el, 'title') || titleType !== 'string') {
|
|
setAttr(el, 'data-original-title', getAttr(el, 'title') || '');
|
|
setAttr(el, 'title', '');
|
|
}
|
|
}
|
|
|
|
// Enter handler
|
|
/* istanbul ignore next */
|
|
|
|
}, {
|
|
key: 'enter',
|
|
value: function enter(e) {
|
|
var _this10 = this;
|
|
|
|
if (e) {
|
|
this.$activeTrigger[e.type === 'focusin' ? 'focus' : 'hover'] = true;
|
|
}
|
|
if (hasClass(this.getTipElement(), ClassName.SHOW) || this.$hoverState === HoverState.SHOW) {
|
|
this.$hoverState = HoverState.SHOW;
|
|
return;
|
|
}
|
|
clearTimeout(this.$hoverTimeout);
|
|
this.$hoverState = HoverState.SHOW;
|
|
if (!this.$config.delay || !this.$config.delay.show) {
|
|
this.show();
|
|
return;
|
|
}
|
|
this.$hoverTimeout = setTimeout(function () {
|
|
if (_this10.$hoverState === HoverState.SHOW) {
|
|
_this10.show();
|
|
}
|
|
}, this.$config.delay.show);
|
|
}
|
|
|
|
// Leave handler
|
|
/* istanbul ignore next */
|
|
|
|
}, {
|
|
key: 'leave',
|
|
value: function leave(e) {
|
|
var _this11 = this;
|
|
|
|
if (e) {
|
|
this.$activeTrigger[e.type === 'focusout' ? 'focus' : 'hover'] = false;
|
|
if (e.type === 'focusout' && /blur/.test(this.$config.trigger)) {
|
|
// Special case for `blur`: we clear out the other triggers
|
|
this.$activeTrigger.click = false;
|
|
this.$activeTrigger.hover = false;
|
|
}
|
|
}
|
|
if (this.isWithActiveTrigger()) {
|
|
return;
|
|
}
|
|
clearTimeout(this.$hoverTimeout);
|
|
this.$hoverState = HoverState.OUT;
|
|
if (!this.$config.delay || !this.$config.delay.hide) {
|
|
this.hide();
|
|
return;
|
|
}
|
|
this.$hoverTimeout = setTimeout(function () {
|
|
if (_this11.$hoverState === HoverState.OUT) {
|
|
_this11.hide();
|
|
}
|
|
}, this.$config.delay.hide);
|
|
}
|
|
}, {
|
|
key: 'getPopperConfig',
|
|
value: function getPopperConfig(placement, tip) {
|
|
var _this12 = this;
|
|
|
|
return {
|
|
placement: this.constructor.getAttachment(placement),
|
|
modifiers: {
|
|
offset: { offset: this.getOffset(placement, tip) },
|
|
flip: { behavior: this.$config.fallbackPlacement },
|
|
arrow: { element: '.arrow' },
|
|
preventOverflow: { boundariesElement: this.$config.boundary }
|
|
},
|
|
onCreate: function onCreate(data) {
|
|
// Handle flipping arrow classes
|
|
if (data.originalPlacement !== data.placement) {
|
|
_this12.handlePopperPlacementChange(data);
|
|
}
|
|
},
|
|
onUpdate: function onUpdate(data) {
|
|
// Handle flipping arrow classes
|
|
_this12.handlePopperPlacementChange(data);
|
|
}
|
|
};
|
|
}
|
|
}, {
|
|
key: 'getOffset',
|
|
value: function getOffset(placement, tip) {
|
|
if (!this.$config.offset) {
|
|
var arrow = select(Selector$1.ARROW, tip);
|
|
var arrowOffset = parseFloat(getCS(arrow).width) + parseFloat(this.$config.arrowPadding);
|
|
switch (OffsetMap[placement.toUpperCase()]) {
|
|
case +1:
|
|
return '+50%p - ' + arrowOffset + 'px';
|
|
case -1:
|
|
return '-50%p + ' + arrowOffset + 'px';
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
return this.$config.offset;
|
|
}
|
|
}, {
|
|
key: 'getPlacement',
|
|
value: function getPlacement() {
|
|
var placement = this.$config.placement;
|
|
if (typeof placement === 'function') {
|
|
return placement.call(this, this.$tip, this.$element);
|
|
}
|
|
return placement;
|
|
}
|
|
}, {
|
|
key: 'isWithActiveTrigger',
|
|
value: function isWithActiveTrigger() {
|
|
for (var trigger in this.$activeTrigger) {
|
|
if (this.$activeTrigger[trigger]) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// NOTE: Overridden by PopOver class
|
|
|
|
}, {
|
|
key: 'cleanTipClass',
|
|
value: function cleanTipClass() {
|
|
var tip = this.getTipElement();
|
|
var tabClass = tip.className.match(BSCLS_PREFIX_REGEX);
|
|
if (tabClass !== null && tabClass.length > 0) {
|
|
tabClass.forEach(function (cls) {
|
|
removeClass(tip, cls);
|
|
});
|
|
}
|
|
}
|
|
}, {
|
|
key: 'handlePopperPlacementChange',
|
|
value: function handlePopperPlacementChange(data) {
|
|
this.cleanTipClass();
|
|
this.addAttachmentClass(this.constructor.getAttachment(data.placement));
|
|
}
|
|
}, {
|
|
key: 'fixTransition',
|
|
value: function fixTransition(tip) {
|
|
var initConfigAnimation = this.$config.animation || false;
|
|
if (getAttr(tip, 'x-placement') !== null) {
|
|
return;
|
|
}
|
|
removeClass(tip, ClassName.FADE);
|
|
this.$config.animation = false;
|
|
this.hide();
|
|
this.show();
|
|
this.$config.animation = initConfigAnimation;
|
|
}
|
|
}], [{
|
|
key: 'getAttachment',
|
|
value: function getAttachment(placement) {
|
|
return AttachmentMap$1[placement.toUpperCase()];
|
|
}
|
|
}, {
|
|
key: 'Default',
|
|
get: function get$$1() {
|
|
return Defaults$1;
|
|
}
|
|
|
|
// NOTE: Overridden by PopOver class
|
|
|
|
}, {
|
|
key: 'NAME',
|
|
get: function get$$1() {
|
|
return NAME;
|
|
}
|
|
}]);
|
|
return ToolTip;
|
|
}();
|
|
|
|
var NAME$1 = 'popover';
|
|
var CLASS_PREFIX$1 = 'bs-popover';
|
|
var BSCLS_PREFIX_REGEX$1 = new RegExp('\\b' + CLASS_PREFIX$1 + '\\S+', 'g');
|
|
|
|
var Defaults$2 = assign({}, ToolTip.Default, {
|
|
placement: 'right',
|
|
trigger: 'click',
|
|
content: '',
|
|
template: '<div class="popover" role="tooltip">' + '<div class="arrow"></div>' + '<h3 class="popover-header"></h3>' + '<div class="popover-body"></div></div>'
|
|
});
|
|
|
|
var ClassName$1 = {
|
|
FADE: 'fade',
|
|
SHOW: 'show'
|
|
};
|
|
|
|
var Selector$2 = {
|
|
TITLE: '.popover-header',
|
|
CONTENT: '.popover-body'
|
|
|
|
/* istanbul ignore next: dificult to test in Jest/JSDOM environment */
|
|
};
|
|
var PopOver = function (_ToolTip) {
|
|
inherits(PopOver, _ToolTip);
|
|
|
|
function PopOver() {
|
|
classCallCheck(this, PopOver);
|
|
return possibleConstructorReturn(this, (PopOver.__proto__ || Object.getPrototypeOf(PopOver)).apply(this, arguments));
|
|
}
|
|
|
|
createClass(PopOver, [{
|
|
key: 'isWithContent',
|
|
|
|
|
|
// Method overrides
|
|
|
|
value: function isWithContent(tip) {
|
|
tip = tip || this.$tip;
|
|
if (!tip) {
|
|
return false;
|
|
}
|
|
var hasTitle = Boolean((select(Selector$2.TITLE, tip) || {}).innerHTML);
|
|
var hasContent = Boolean((select(Selector$2.CONTENT, tip) || {}).innerHTML);
|
|
return hasTitle || hasContent;
|
|
}
|
|
}, {
|
|
key: 'addAttachmentClass',
|
|
value: function addAttachmentClass(attachment) {
|
|
addClass(this.getTipElement(), CLASS_PREFIX$1 + '-' + attachment);
|
|
}
|
|
}, {
|
|
key: 'setContent',
|
|
value: function setContent(tip) {
|
|
// we use append for html objects to maintain js events/components
|
|
this.setElementContent(select(Selector$2.TITLE, tip), this.getTitle());
|
|
this.setElementContent(select(Selector$2.CONTENT, tip), this.getContent());
|
|
|
|
removeClass(tip, ClassName$1.FADE);
|
|
removeClass(tip, ClassName$1.SHOW);
|
|
}
|
|
|
|
// This method may look identical to ToolTip version, but it uses a different RegEx defined above
|
|
|
|
}, {
|
|
key: 'cleanTipClass',
|
|
value: function cleanTipClass() {
|
|
var tip = this.getTipElement();
|
|
var tabClass = tip.className.match(BSCLS_PREFIX_REGEX$1);
|
|
if (tabClass !== null && tabClass.length > 0) {
|
|
tabClass.forEach(function (cls) {
|
|
removeClass(tip, cls);
|
|
});
|
|
}
|
|
}
|
|
}, {
|
|
key: 'getTitle',
|
|
value: function getTitle() {
|
|
var title = this.$config.title || '';
|
|
if (typeof title === 'function') {
|
|
title = title(this.$element);
|
|
}
|
|
if ((typeof title === 'undefined' ? 'undefined' : _typeof(title)) === 'object' && title.nodeType && !title.innerHTML.trim()) {
|
|
// We have a dom node, but without inner content, so just return an empty string
|
|
title = '';
|
|
}
|
|
if (typeof title === 'string') {
|
|
title = title.trim();
|
|
}
|
|
if (!title) {
|
|
// Try and grab element's title attribute
|
|
title = getAttr(this.$element, 'title') || getAttr(this.$element, 'data-original-title') || '';
|
|
title = title.trim();
|
|
}
|
|
return title;
|
|
}
|
|
|
|
// New methods
|
|
|
|
}, {
|
|
key: 'getContent',
|
|
value: function getContent() {
|
|
var content = this.$config.content || '';
|
|
if (typeof content === 'function') {
|
|
content = content(this.$element);
|
|
}
|
|
if ((typeof content === 'undefined' ? 'undefined' : _typeof(content)) === 'object' && content.nodeType && !content.innerHTML.trim()) {
|
|
// We have a dom node, but without inner content, so just return an empty string
|
|
content = '';
|
|
}
|
|
if (typeof content === 'string') {
|
|
content = content.trim();
|
|
}
|
|
return content;
|
|
}
|
|
}], [{
|
|
key: 'Default',
|
|
|
|
// Getter overrides
|
|
|
|
get: function get$$1() {
|
|
return Defaults$2;
|
|
}
|
|
}, {
|
|
key: 'NAME',
|
|
get: function get$$1() {
|
|
return NAME$1;
|
|
}
|
|
}]);
|
|
return PopOver;
|
|
}(ToolTip);
|
|
|
|
// Polyfills for SSR
|
|
|
|
var isSSR = typeof window === 'undefined';
|
|
|
|
var HTMLElement = isSSR ? Object : window.HTMLElement;
|
|
|
|
/*
|
|
* Tooltip/Popover component mixin
|
|
* Common props
|
|
*/
|
|
|
|
var PLACEMENTS = {
|
|
top: 'top',
|
|
topleft: 'topleft',
|
|
topright: 'topright',
|
|
right: 'right',
|
|
righttop: 'righttop',
|
|
rightbottom: 'rightbottom',
|
|
bottom: 'bottom',
|
|
bottomleft: 'bottomleft',
|
|
bottomright: 'bottomright',
|
|
left: 'left',
|
|
lefttop: 'lefttop',
|
|
leftbottom: 'leftbottom',
|
|
auto: 'auto'
|
|
};
|
|
|
|
var OBSERVER_CONFIG$1 = {
|
|
subtree: true,
|
|
childList: true,
|
|
characterData: true,
|
|
attributes: true,
|
|
attributeFilter: ['class', 'style']
|
|
};
|
|
|
|
var toolpopMixin = {
|
|
props: {
|
|
target: {
|
|
// String ID of element, or element/component reference
|
|
type: [String, Object, HTMLElement, Function]
|
|
},
|
|
delay: {
|
|
type: [Number, Object, String],
|
|
default: 0
|
|
},
|
|
offset: {
|
|
type: [Number, String],
|
|
default: 0
|
|
},
|
|
noFade: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
container: {
|
|
// String ID of container, if null body is used (default)
|
|
type: String,
|
|
default: null
|
|
},
|
|
boundary: {
|
|
// String: scrollParent, window, or viewport
|
|
// Element: element reference
|
|
type: [String, Object],
|
|
default: 'scrollParent'
|
|
},
|
|
show: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
disabled: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
},
|
|
watch: {
|
|
show: function show(_show, old) {
|
|
if (_show === old) {
|
|
return;
|
|
}
|
|
_show ? this.onOpen() : this.onClose();
|
|
},
|
|
disabled: function disabled(_disabled, old) {
|
|
if (_disabled === old) {
|
|
return;
|
|
}
|
|
_disabled ? this.onDisable() : this.onEnable();
|
|
}
|
|
},
|
|
created: function created() {
|
|
// Create non-reactive property
|
|
this._toolpop = null;
|
|
this._obs_title = null;
|
|
this._obs_content = null;
|
|
},
|
|
mounted: function mounted() {
|
|
var _this = this;
|
|
|
|
// We do this in a next tick to ensure DOM has rendered first
|
|
this.$nextTick(function () {
|
|
// Instantiate ToolTip/PopOver on target
|
|
// The createToolpop method must exist in main component
|
|
if (_this.createToolpop()) {
|
|
if (_this.disabled) {
|
|
// Initially disabled
|
|
_this.onDisable();
|
|
}
|
|
// Listen to open signals from others
|
|
_this.$on('open', _this.onOpen);
|
|
// Listen to close signals from others
|
|
_this.$on('close', _this.onClose);
|
|
// Listen to disable signals from others
|
|
_this.$on('disable', _this.onDisable);
|
|
// Listen to disable signals from others
|
|
_this.$on('enable', _this.onEnable);
|
|
// Observe content Child changes so we can notify popper of possible size change
|
|
_this.setObservers(true);
|
|
// Set intially open state
|
|
if (_this.show) {
|
|
_this.onOpen();
|
|
}
|
|
}
|
|
});
|
|
},
|
|
updated: function updated() {
|
|
// If content/props changes, etc
|
|
if (this._toolpop) {
|
|
this._toolpop.updateConfig(this.getConfig());
|
|
}
|
|
},
|
|
|
|
/* istanbul ignore next: not easy to test */
|
|
activated: function activated() {
|
|
// Called when component is inside a <keep-alive> and component brought offline
|
|
this.setObservers(true);
|
|
},
|
|
|
|
/* istanbul ignore next: not easy to test */
|
|
deactivated: function deactivated() {
|
|
// Called when component is inside a <keep-alive> and component taken offline
|
|
if (this._toolpop) {
|
|
this.setObservers(false);
|
|
this._toolpop.hide();
|
|
}
|
|
},
|
|
|
|
/* istanbul ignore next: not easy to test */
|
|
beforeDestroy: function beforeDestroy() {
|
|
// Shutdown our local event listeners
|
|
this.$off('open', this.onOpen);
|
|
this.$off('close', this.onClose);
|
|
this.$off('disable', this.onDisable);
|
|
this.$off('enable', this.onEnable);
|
|
this.setObservers(false);
|
|
// bring our content back if needed
|
|
this.bringItBack();
|
|
if (this._toolpop) {
|
|
this._toolpop.destroy();
|
|
this._toolpop = null;
|
|
}
|
|
},
|
|
|
|
computed: {
|
|
baseConfig: function baseConfig() {
|
|
var cont = this.container;
|
|
var delay = _typeof(this.delay) === 'object' ? this.delay : parseInt(this.delay, 10) || 0;
|
|
return {
|
|
// Title prop
|
|
title: (this.title || '').trim() || '',
|
|
// Contnt prop (if popover)
|
|
content: (this.content || '').trim() || '',
|
|
// Tooltip/Popover placement
|
|
placement: PLACEMENTS[this.placement] || 'auto',
|
|
// Container curently needs to be an ID with '#' prepended, if null then body is used
|
|
container: cont ? /^#/.test(cont) ? cont : '#' + cont : false,
|
|
// boundariesElement passed to popper
|
|
boundary: this.boundary,
|
|
// Show/Hide delay
|
|
delay: delay || 0,
|
|
// Offset can be css distance. if no units, pixels are assumed
|
|
offset: this.offset || 0,
|
|
// Disable fade Animation?
|
|
animation: !this.noFade,
|
|
// Open/Close Trigger(s)
|
|
trigger: isArray(this.triggers) ? this.triggers.join(' ') : this.triggers,
|
|
// Callbacks so we can trigger events on component
|
|
callbacks: {
|
|
show: this.onShow,
|
|
shown: this.onShown,
|
|
hide: this.onHide,
|
|
hidden: this.onHidden,
|
|
enabled: this.onEnabled,
|
|
disabled: this.onDisabled
|
|
}
|
|
};
|
|
}
|
|
},
|
|
methods: {
|
|
getConfig: function getConfig() {
|
|
var cfg = assign({}, this.baseConfig);
|
|
if (this.$refs.title && this.$refs.title.innerHTML.trim()) {
|
|
// If slot has content, it overrides 'title' prop
|
|
// We use the DOM node as content to allow components!
|
|
cfg.title = this.$refs.title;
|
|
cfg.html = true;
|
|
}
|
|
if (this.$refs.content && this.$refs.content.innerHTML.trim()) {
|
|
// If slot has content, it overrides 'content' prop
|
|
// We use the DOM node as content to allow components!
|
|
cfg.content = this.$refs.content;
|
|
cfg.html = true;
|
|
}
|
|
return cfg;
|
|
},
|
|
onOpen: function onOpen() {
|
|
if (this._toolpop) {
|
|
this._toolpop.show();
|
|
}
|
|
},
|
|
onClose: function onClose(callback) {
|
|
if (this._toolpop) {
|
|
this._toolpop.hide(callback);
|
|
} else if (typeof callback === 'function') {
|
|
callback();
|
|
}
|
|
},
|
|
onDisable: function onDisable() {
|
|
if (this._toolpop) {
|
|
this._toolpop.disable();
|
|
}
|
|
},
|
|
onEnable: function onEnable() {
|
|
if (this._toolpop) {
|
|
this._toolpop.enable();
|
|
}
|
|
},
|
|
updatePosition: function updatePosition() {
|
|
if (this._toolpop) {
|
|
// Instruct popper to reposition popover if necessary
|
|
this._toolpop.update();
|
|
}
|
|
},
|
|
getTarget: function getTarget() {
|
|
var target = this.target;
|
|
if (typeof target === 'function') {
|
|
target = target();
|
|
}
|
|
if (typeof target === 'string') {
|
|
// Assume ID of element
|
|
return getById(target);
|
|
} else if ((typeof target === 'undefined' ? 'undefined' : _typeof(target)) === 'object' && isElement(target.$el)) {
|
|
// Component reference
|
|
return target.$el;
|
|
} else if ((typeof target === 'undefined' ? 'undefined' : _typeof(target)) === 'object' && isElement(target)) {
|
|
// Element reference
|
|
return target;
|
|
}
|
|
return null;
|
|
},
|
|
onShow: function onShow(evt) {
|
|
this.$emit('show', evt);
|
|
},
|
|
onShown: function onShown(evt) {
|
|
this.setObservers(true);
|
|
this.$emit('update:show', true);
|
|
this.$emit('shown', evt);
|
|
},
|
|
onHide: function onHide(evt) {
|
|
this.$emit('hide', evt);
|
|
},
|
|
onHidden: function onHidden(evt) {
|
|
this.setObservers(false);
|
|
// bring our content back if needed to keep Vue happy
|
|
// Tooltip class will move it back to tip when shown again
|
|
this.bringItBack();
|
|
this.$emit('update:show', false);
|
|
this.$emit('hidden', evt);
|
|
},
|
|
onEnabled: function onEnabled(evt) {
|
|
if (!evt || evt.type !== 'enabled') {
|
|
// Prevent possible endless loop if user mistakienly fires enabled instead of enable
|
|
return;
|
|
}
|
|
this.$emit('update:disabled', false);
|
|
this.$emit('disabled');
|
|
},
|
|
onDisabled: function onDisabled(evt) {
|
|
if (!evt || evt.type !== 'disabled') {
|
|
// Prevent possible endless loop if user mistakienly fires disabled instead of disable
|
|
return;
|
|
}
|
|
this.$emit('update:disabled', true);
|
|
this.$emit('enabled');
|
|
},
|
|
bringItBack: function bringItBack() {
|
|
// bring our content back if needed to keep Vue happy
|
|
if (this.$el && this.$refs.title) {
|
|
this.$el.appendChild(this.$refs.title);
|
|
}
|
|
if (this.$el && this.$refs.content) {
|
|
this.$el.appendChild(this.$refs.content);
|
|
}
|
|
},
|
|
|
|
/* istanbul ignore next: not easy to test */
|
|
setObservers: function setObservers(on) {
|
|
if (on) {
|
|
if (this.$refs.title) {
|
|
this._obs_title = observeDOM(this.$refs.title, this.updatePosition.bind(this), OBSERVER_CONFIG$1);
|
|
}
|
|
if (this.$refs.content) {
|
|
this._obs_content = observeDOM(this.$refs.content, this.updatePosition.bind(this), OBSERVER_CONFIG$1);
|
|
}
|
|
} else {
|
|
if (this._obs_title) {
|
|
this._obs_title.disconnect();
|
|
this._obs_title = null;
|
|
}
|
|
if (this._obs_content) {
|
|
this._obs_content.disconnect();
|
|
this._obs_content = null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
var bPopover = {
|
|
mixins: [toolpopMixin],
|
|
render: function render(h) {
|
|
return h('div', {
|
|
class: ['d-none'],
|
|
style: { display: 'none' },
|
|
attrs: { 'aria-hidden': true }
|
|
}, [h('div', { ref: 'title' }, this.$slots.title), h('div', { ref: 'content' }, this.$slots.default)]);
|
|
},
|
|
data: function data() {
|
|
return {};
|
|
},
|
|
|
|
props: {
|
|
title: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
content: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
triggers: {
|
|
type: [String, Array],
|
|
default: 'click'
|
|
},
|
|
placement: {
|
|
type: String,
|
|
default: 'right'
|
|
}
|
|
},
|
|
methods: {
|
|
createToolpop: function createToolpop() {
|
|
// getTarget is in toolpop mixin
|
|
var target = this.getTarget();
|
|
if (target) {
|
|
this._toolpop = new PopOver(target, this.getConfig(), this.$root);
|
|
} else {
|
|
this._toolpop = null;
|
|
warn("b-popover: 'target' element not found!");
|
|
}
|
|
return this._toolpop;
|
|
}
|
|
}
|
|
};
|
|
|
|
var components$v = {
|
|
bPopover: bPopover
|
|
};
|
|
|
|
var VuePlugin$x = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$v);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$x);
|
|
|
|
var bProgressBar = {
|
|
render: function render(h) {
|
|
var childNodes = h(false);
|
|
if (this.$slots.default) {
|
|
childNodes = this.$slots.default;
|
|
} else if (this.label) {
|
|
childNodes = h('span', { domProps: { innerHTML: this.label } });
|
|
} else if (this.computedShowProgress) {
|
|
childNodes = this.progress.toFixed(this.computedPrecision);
|
|
} else if (this.computedShowValue) {
|
|
childNodes = this.value.toFixed(this.computedPrecision);
|
|
}
|
|
return h('div', {
|
|
class: this.progressBarClasses,
|
|
style: this.progressBarStyles,
|
|
attrs: {
|
|
role: 'progressbar',
|
|
'aria-valuemin': '0',
|
|
'aria-valuemax': this.computedMax.toString(),
|
|
'aria-valuenow': this.value.toFixed(this.computedPrecision)
|
|
}
|
|
}, [childNodes]);
|
|
},
|
|
|
|
computed: {
|
|
progressBarClasses: function progressBarClasses() {
|
|
return ['progress-bar', this.computedVariant ? 'bg-' + this.computedVariant : '', this.computedStriped || this.computedAnimated ? 'progress-bar-striped' : '', this.computedAnimated ? 'progress-bar-animated' : ''];
|
|
},
|
|
progressBarStyles: function progressBarStyles() {
|
|
return {
|
|
width: 100 * (this.value / this.computedMax) + '%'
|
|
};
|
|
},
|
|
progress: function progress() {
|
|
var p = Math.pow(10, this.computedPrecision);
|
|
return Math.round(100 * p * this.value / this.computedMax) / p;
|
|
},
|
|
computedMax: function computedMax() {
|
|
// Prefer our max over parent setting
|
|
return typeof this.max === 'number' ? this.max : this.$parent.max || 100;
|
|
},
|
|
computedVariant: function computedVariant() {
|
|
// Prefer our variant over parent setting
|
|
return this.variant || this.$parent.variant;
|
|
},
|
|
computedPrecision: function computedPrecision() {
|
|
// Prefer our precision over parent setting
|
|
return typeof this.precision === 'number' ? this.precision : this.$parent.precision || 0;
|
|
},
|
|
computedStriped: function computedStriped() {
|
|
// Prefer our striped over parent setting
|
|
return typeof this.striped === 'boolean' ? this.striped : this.$parent.striped || false;
|
|
},
|
|
computedAnimated: function computedAnimated() {
|
|
// Prefer our animated over parent setting
|
|
return typeof this.animated === 'boolean' ? this.animated : this.$parent.animated || false;
|
|
},
|
|
computedShowProgress: function computedShowProgress() {
|
|
// Prefer our showProgress over parent setting
|
|
return typeof this.showProgress === 'boolean' ? this.showProgress : this.$parent.showProgress || false;
|
|
},
|
|
computedShowValue: function computedShowValue() {
|
|
// Prefer our showValue over parent setting
|
|
return typeof this.showValue === 'boolean' ? this.showValue : this.$parent.showValue || false;
|
|
}
|
|
},
|
|
props: {
|
|
value: {
|
|
type: Number,
|
|
default: 0
|
|
},
|
|
label: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
// $parent prop values take precedence over the following props
|
|
// Which is why they are defaulted to null
|
|
max: {
|
|
type: Number,
|
|
default: null
|
|
},
|
|
precision: {
|
|
type: Number,
|
|
default: null
|
|
},
|
|
variant: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
striped: {
|
|
type: Boolean,
|
|
default: null
|
|
},
|
|
animated: {
|
|
type: Boolean,
|
|
default: null
|
|
},
|
|
showProgress: {
|
|
type: Boolean,
|
|
default: null
|
|
},
|
|
showValue: {
|
|
type: Boolean,
|
|
default: null
|
|
}
|
|
}
|
|
};
|
|
|
|
var bProgress = {
|
|
components: { bProgressBar: bProgressBar },
|
|
render: function render(h) {
|
|
var childNodes = this.$slots.default;
|
|
if (!childNodes) {
|
|
childNodes = h('b-progress-bar', {
|
|
props: {
|
|
value: this.value,
|
|
max: this.max,
|
|
precision: this.precision,
|
|
variant: this.variant,
|
|
animated: this.animated,
|
|
striped: this.striped,
|
|
showProgress: this.showProgress,
|
|
showValue: this.showValue
|
|
}
|
|
});
|
|
}
|
|
return h('div', { class: ['progress'], style: this.progressHeight }, [childNodes]);
|
|
},
|
|
|
|
props: {
|
|
// These props can be inherited via the child b-progress-bar(s)
|
|
variant: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
striped: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
animated: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
height: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
precision: {
|
|
type: Number,
|
|
default: 0
|
|
},
|
|
showProgress: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
showValue: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
max: {
|
|
type: Number,
|
|
default: 100
|
|
},
|
|
// This prop is not inherited by child b-progress-bar(s)
|
|
value: {
|
|
type: Number,
|
|
default: 0
|
|
}
|
|
},
|
|
computed: {
|
|
progressHeight: function progressHeight() {
|
|
return { height: this.height || null };
|
|
}
|
|
}
|
|
};
|
|
|
|
var components$w = {
|
|
bProgress: bProgress,
|
|
bProgressBar: bProgressBar
|
|
};
|
|
|
|
var VuePlugin$y = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$w);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$y);
|
|
|
|
var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
|
|
|
/**
|
|
* lodash (Custom Build) <https://lodash.com/>
|
|
* Build: `lodash modularize exports="npm" -o ./`
|
|
* Copyright jQuery Foundation and other contributors <https://jquery.org/>
|
|
* Released under MIT license <https://lodash.com/license>
|
|
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
|
|
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
|
*/
|
|
|
|
/** Used as references for various `Number` constants. */
|
|
var INFINITY = 1 / 0;
|
|
|
|
/** `Object#toString` result references. */
|
|
var symbolTag = '[object Symbol]';
|
|
|
|
/** Used to match words composed of alphanumeric characters. */
|
|
var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
|
|
|
|
/** Used to match Latin Unicode letters (excluding mathematical operators). */
|
|
var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g;
|
|
|
|
/** Used to compose unicode character classes. */
|
|
var rsAstralRange = '\\ud800-\\udfff',
|
|
rsComboMarksRange = '\\u0300-\\u036f\\ufe20-\\ufe23',
|
|
rsComboSymbolsRange = '\\u20d0-\\u20f0',
|
|
rsDingbatRange = '\\u2700-\\u27bf',
|
|
rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff',
|
|
rsMathOpRange = '\\xac\\xb1\\xd7\\xf7',
|
|
rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf',
|
|
rsPunctuationRange = '\\u2000-\\u206f',
|
|
rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000',
|
|
rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde',
|
|
rsVarRange = '\\ufe0e\\ufe0f',
|
|
rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange;
|
|
|
|
/** Used to compose unicode capture groups. */
|
|
var rsApos = '[\'\u2019]',
|
|
rsAstral = '[' + rsAstralRange + ']',
|
|
rsBreak = '[' + rsBreakRange + ']',
|
|
rsCombo = '[' + rsComboMarksRange + rsComboSymbolsRange + ']',
|
|
rsDigits = '\\d+',
|
|
rsDingbat = '[' + rsDingbatRange + ']',
|
|
rsLower = '[' + rsLowerRange + ']',
|
|
rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']',
|
|
rsFitz = '\\ud83c[\\udffb-\\udfff]',
|
|
rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',
|
|
rsNonAstral = '[^' + rsAstralRange + ']',
|
|
rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}',
|
|
rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]',
|
|
rsUpper = '[' + rsUpperRange + ']',
|
|
rsZWJ = '\\u200d';
|
|
|
|
/** Used to compose unicode regexes. */
|
|
var rsLowerMisc = '(?:' + rsLower + '|' + rsMisc + ')',
|
|
rsUpperMisc = '(?:' + rsUpper + '|' + rsMisc + ')',
|
|
rsOptLowerContr = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?',
|
|
rsOptUpperContr = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?',
|
|
reOptMod = rsModifier + '?',
|
|
rsOptVar = '[' + rsVarRange + ']?',
|
|
rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',
|
|
rsSeq = rsOptVar + reOptMod + rsOptJoin,
|
|
rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq,
|
|
rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';
|
|
|
|
/** Used to match apostrophes. */
|
|
var reApos = RegExp(rsApos, 'g');
|
|
|
|
/**
|
|
* Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and
|
|
* [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols).
|
|
*/
|
|
var reComboMark = RegExp(rsCombo, 'g');
|
|
|
|
/** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */
|
|
var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');
|
|
|
|
/** Used to match complex or compound words. */
|
|
var reUnicodeWord = RegExp([rsUpper + '?' + rsLower + '+' + rsOptLowerContr + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')', rsUpperMisc + '+' + rsOptUpperContr + '(?=' + [rsBreak, rsUpper + rsLowerMisc, '$'].join('|') + ')', rsUpper + '?' + rsLowerMisc + '+' + rsOptLowerContr, rsUpper + '+' + rsOptUpperContr, rsDigits, rsEmoji].join('|'), 'g');
|
|
|
|
/** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */
|
|
var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboMarksRange + rsComboSymbolsRange + rsVarRange + ']');
|
|
|
|
/** Used to detect strings that need a more robust regexp to match words. */
|
|
var reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/;
|
|
|
|
/** Used to map Latin Unicode letters to basic Latin letters. */
|
|
var deburredLetters = {
|
|
// Latin-1 Supplement block.
|
|
'\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A',
|
|
'\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a',
|
|
'\xc7': 'C', '\xe7': 'c',
|
|
'\xd0': 'D', '\xf0': 'd',
|
|
'\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E',
|
|
'\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e',
|
|
'\xcc': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I',
|
|
'\xec': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i',
|
|
'\xd1': 'N', '\xf1': 'n',
|
|
'\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O',
|
|
'\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o',
|
|
'\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U',
|
|
'\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u',
|
|
'\xdd': 'Y', '\xfd': 'y', '\xff': 'y',
|
|
'\xc6': 'Ae', '\xe6': 'ae',
|
|
'\xde': 'Th', '\xfe': 'th',
|
|
'\xdf': 'ss',
|
|
// Latin Extended-A block.
|
|
'\u0100': 'A', '\u0102': 'A', '\u0104': 'A',
|
|
'\u0101': 'a', '\u0103': 'a', '\u0105': 'a',
|
|
'\u0106': 'C', '\u0108': 'C', '\u010A': 'C', '\u010C': 'C',
|
|
'\u0107': 'c', '\u0109': 'c', '\u010B': 'c', '\u010D': 'c',
|
|
'\u010E': 'D', '\u0110': 'D', '\u010F': 'd', '\u0111': 'd',
|
|
'\u0112': 'E', '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011A': 'E',
|
|
'\u0113': 'e', '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011B': 'e',
|
|
'\u011C': 'G', '\u011E': 'G', '\u0120': 'G', '\u0122': 'G',
|
|
'\u011D': 'g', '\u011F': 'g', '\u0121': 'g', '\u0123': 'g',
|
|
'\u0124': 'H', '\u0126': 'H', '\u0125': 'h', '\u0127': 'h',
|
|
'\u0128': 'I', '\u012A': 'I', '\u012C': 'I', '\u012E': 'I', '\u0130': 'I',
|
|
'\u0129': 'i', '\u012B': 'i', '\u012D': 'i', '\u012F': 'i', '\u0131': 'i',
|
|
'\u0134': 'J', '\u0135': 'j',
|
|
'\u0136': 'K', '\u0137': 'k', '\u0138': 'k',
|
|
'\u0139': 'L', '\u013B': 'L', '\u013D': 'L', '\u013F': 'L', '\u0141': 'L',
|
|
'\u013A': 'l', '\u013C': 'l', '\u013E': 'l', '\u0140': 'l', '\u0142': 'l',
|
|
'\u0143': 'N', '\u0145': 'N', '\u0147': 'N', '\u014A': 'N',
|
|
'\u0144': 'n', '\u0146': 'n', '\u0148': 'n', '\u014B': 'n',
|
|
'\u014C': 'O', '\u014E': 'O', '\u0150': 'O',
|
|
'\u014D': 'o', '\u014F': 'o', '\u0151': 'o',
|
|
'\u0154': 'R', '\u0156': 'R', '\u0158': 'R',
|
|
'\u0155': 'r', '\u0157': 'r', '\u0159': 'r',
|
|
'\u015A': 'S', '\u015C': 'S', '\u015E': 'S', '\u0160': 'S',
|
|
'\u015B': 's', '\u015D': 's', '\u015F': 's', '\u0161': 's',
|
|
'\u0162': 'T', '\u0164': 'T', '\u0166': 'T',
|
|
'\u0163': 't', '\u0165': 't', '\u0167': 't',
|
|
'\u0168': 'U', '\u016A': 'U', '\u016C': 'U', '\u016E': 'U', '\u0170': 'U', '\u0172': 'U',
|
|
'\u0169': 'u', '\u016B': 'u', '\u016D': 'u', '\u016F': 'u', '\u0171': 'u', '\u0173': 'u',
|
|
'\u0174': 'W', '\u0175': 'w',
|
|
'\u0176': 'Y', '\u0177': 'y', '\u0178': 'Y',
|
|
'\u0179': 'Z', '\u017B': 'Z', '\u017D': 'Z',
|
|
'\u017A': 'z', '\u017C': 'z', '\u017E': 'z',
|
|
'\u0132': 'IJ', '\u0133': 'ij',
|
|
'\u0152': 'Oe', '\u0153': 'oe',
|
|
'\u0149': "'n", '\u017F': 'ss'
|
|
};
|
|
|
|
/** Detect free variable `global` from Node.js. */
|
|
var freeGlobal = _typeof(commonjsGlobal) == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal;
|
|
|
|
/** Detect free variable `self`. */
|
|
var freeSelf = (typeof self === 'undefined' ? 'undefined' : _typeof(self)) == 'object' && self && self.Object === Object && self;
|
|
|
|
/** Used as a reference to the global object. */
|
|
var root = freeGlobal || freeSelf || Function('return this')();
|
|
|
|
/**
|
|
* A specialized version of `_.reduce` for arrays without support for
|
|
* iteratee shorthands.
|
|
*
|
|
* @private
|
|
* @param {Array} [array] The array to iterate over.
|
|
* @param {Function} iteratee The function invoked per iteration.
|
|
* @param {*} [accumulator] The initial value.
|
|
* @param {boolean} [initAccum] Specify using the first element of `array` as
|
|
* the initial value.
|
|
* @returns {*} Returns the accumulated value.
|
|
*/
|
|
function arrayReduce(array, iteratee, accumulator, initAccum) {
|
|
var index = -1,
|
|
length = array ? array.length : 0;
|
|
|
|
if (initAccum && length) {
|
|
accumulator = array[++index];
|
|
}
|
|
while (++index < length) {
|
|
accumulator = iteratee(accumulator, array[index], index, array);
|
|
}
|
|
return accumulator;
|
|
}
|
|
|
|
/**
|
|
* Converts an ASCII `string` to an array.
|
|
*
|
|
* @private
|
|
* @param {string} string The string to convert.
|
|
* @returns {Array} Returns the converted array.
|
|
*/
|
|
function asciiToArray(string) {
|
|
return string.split('');
|
|
}
|
|
|
|
/**
|
|
* Splits an ASCII `string` into an array of its words.
|
|
*
|
|
* @private
|
|
* @param {string} The string to inspect.
|
|
* @returns {Array} Returns the words of `string`.
|
|
*/
|
|
function asciiWords(string) {
|
|
return string.match(reAsciiWord) || [];
|
|
}
|
|
|
|
/**
|
|
* The base implementation of `_.propertyOf` without support for deep paths.
|
|
*
|
|
* @private
|
|
* @param {Object} object The object to query.
|
|
* @returns {Function} Returns the new accessor function.
|
|
*/
|
|
function basePropertyOf(object) {
|
|
return function (key) {
|
|
return object == null ? undefined : object[key];
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A
|
|
* letters to basic Latin letters.
|
|
*
|
|
* @private
|
|
* @param {string} letter The matched letter to deburr.
|
|
* @returns {string} Returns the deburred letter.
|
|
*/
|
|
var deburrLetter = basePropertyOf(deburredLetters);
|
|
|
|
/**
|
|
* Checks if `string` contains Unicode symbols.
|
|
*
|
|
* @private
|
|
* @param {string} string The string to inspect.
|
|
* @returns {boolean} Returns `true` if a symbol is found, else `false`.
|
|
*/
|
|
function hasUnicode(string) {
|
|
return reHasUnicode.test(string);
|
|
}
|
|
|
|
/**
|
|
* Checks if `string` contains a word composed of Unicode symbols.
|
|
*
|
|
* @private
|
|
* @param {string} string The string to inspect.
|
|
* @returns {boolean} Returns `true` if a word is found, else `false`.
|
|
*/
|
|
function hasUnicodeWord(string) {
|
|
return reHasUnicodeWord.test(string);
|
|
}
|
|
|
|
/**
|
|
* Converts `string` to an array.
|
|
*
|
|
* @private
|
|
* @param {string} string The string to convert.
|
|
* @returns {Array} Returns the converted array.
|
|
*/
|
|
function stringToArray(string) {
|
|
return hasUnicode(string) ? unicodeToArray(string) : asciiToArray(string);
|
|
}
|
|
|
|
/**
|
|
* Converts a Unicode `string` to an array.
|
|
*
|
|
* @private
|
|
* @param {string} string The string to convert.
|
|
* @returns {Array} Returns the converted array.
|
|
*/
|
|
function unicodeToArray(string) {
|
|
return string.match(reUnicode) || [];
|
|
}
|
|
|
|
/**
|
|
* Splits a Unicode `string` into an array of its words.
|
|
*
|
|
* @private
|
|
* @param {string} The string to inspect.
|
|
* @returns {Array} Returns the words of `string`.
|
|
*/
|
|
function unicodeWords(string) {
|
|
return string.match(reUnicodeWord) || [];
|
|
}
|
|
|
|
/** Used for built-in method references. */
|
|
var objectProto = Object.prototype;
|
|
|
|
/**
|
|
* Used to resolve the
|
|
* [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
|
|
* of values.
|
|
*/
|
|
var objectToString = objectProto.toString;
|
|
|
|
/** Built-in value references. */
|
|
var _Symbol = root.Symbol;
|
|
|
|
/** Used to convert symbols to primitives and strings. */
|
|
var symbolProto = _Symbol ? _Symbol.prototype : undefined,
|
|
symbolToString = symbolProto ? symbolProto.toString : undefined;
|
|
|
|
/**
|
|
* The base implementation of `_.slice` without an iteratee call guard.
|
|
*
|
|
* @private
|
|
* @param {Array} array The array to slice.
|
|
* @param {number} [start=0] The start position.
|
|
* @param {number} [end=array.length] The end position.
|
|
* @returns {Array} Returns the slice of `array`.
|
|
*/
|
|
function baseSlice(array, start, end) {
|
|
var index = -1,
|
|
length = array.length;
|
|
|
|
if (start < 0) {
|
|
start = -start > length ? 0 : length + start;
|
|
}
|
|
end = end > length ? length : end;
|
|
if (end < 0) {
|
|
end += length;
|
|
}
|
|
length = start > end ? 0 : end - start >>> 0;
|
|
start >>>= 0;
|
|
|
|
var result = Array(length);
|
|
while (++index < length) {
|
|
result[index] = array[index + start];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* The base implementation of `_.toString` which doesn't convert nullish
|
|
* values to empty strings.
|
|
*
|
|
* @private
|
|
* @param {*} value The value to process.
|
|
* @returns {string} Returns the string.
|
|
*/
|
|
function baseToString(value) {
|
|
// Exit early for strings to avoid a performance hit in some environments.
|
|
if (typeof value == 'string') {
|
|
return value;
|
|
}
|
|
if (isSymbol(value)) {
|
|
return symbolToString ? symbolToString.call(value) : '';
|
|
}
|
|
var result = value + '';
|
|
return result == '0' && 1 / value == -INFINITY ? '-0' : result;
|
|
}
|
|
|
|
/**
|
|
* Casts `array` to a slice if it's needed.
|
|
*
|
|
* @private
|
|
* @param {Array} array The array to inspect.
|
|
* @param {number} start The start position.
|
|
* @param {number} [end=array.length] The end position.
|
|
* @returns {Array} Returns the cast slice.
|
|
*/
|
|
function castSlice(array, start, end) {
|
|
var length = array.length;
|
|
end = end === undefined ? length : end;
|
|
return !start && end >= length ? array : baseSlice(array, start, end);
|
|
}
|
|
|
|
/**
|
|
* Creates a function like `_.lowerFirst`.
|
|
*
|
|
* @private
|
|
* @param {string} methodName The name of the `String` case method to use.
|
|
* @returns {Function} Returns the new case function.
|
|
*/
|
|
function createCaseFirst(methodName) {
|
|
return function (string) {
|
|
string = toString(string);
|
|
|
|
var strSymbols = hasUnicode(string) ? stringToArray(string) : undefined;
|
|
|
|
var chr = strSymbols ? strSymbols[0] : string.charAt(0);
|
|
|
|
var trailing = strSymbols ? castSlice(strSymbols, 1).join('') : string.slice(1);
|
|
|
|
return chr[methodName]() + trailing;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Creates a function like `_.camelCase`.
|
|
*
|
|
* @private
|
|
* @param {Function} callback The function to combine each word.
|
|
* @returns {Function} Returns the new compounder function.
|
|
*/
|
|
function createCompounder(callback) {
|
|
return function (string) {
|
|
return arrayReduce(words(deburr(string).replace(reApos, '')), callback, '');
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is object-like. A value is object-like if it's not `null`
|
|
* and has a `typeof` result of "object".
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @since 4.0.0
|
|
* @category Lang
|
|
* @param {*} value The value to check.
|
|
* @returns {boolean} Returns `true` if `value` is object-like, else `false`.
|
|
* @example
|
|
*
|
|
* _.isObjectLike({});
|
|
* // => true
|
|
*
|
|
* _.isObjectLike([1, 2, 3]);
|
|
* // => true
|
|
*
|
|
* _.isObjectLike(_.noop);
|
|
* // => false
|
|
*
|
|
* _.isObjectLike(null);
|
|
* // => false
|
|
*/
|
|
function isObjectLike(value) {
|
|
return !!value && (typeof value === 'undefined' ? 'undefined' : _typeof(value)) == 'object';
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is classified as a `Symbol` primitive or object.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @since 4.0.0
|
|
* @category Lang
|
|
* @param {*} value The value to check.
|
|
* @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
|
|
* @example
|
|
*
|
|
* _.isSymbol(Symbol.iterator);
|
|
* // => true
|
|
*
|
|
* _.isSymbol('abc');
|
|
* // => false
|
|
*/
|
|
function isSymbol(value) {
|
|
return (typeof value === 'undefined' ? 'undefined' : _typeof(value)) == 'symbol' || isObjectLike(value) && objectToString.call(value) == symbolTag;
|
|
}
|
|
|
|
/**
|
|
* Converts `value` to a string. An empty string is returned for `null`
|
|
* and `undefined` values. The sign of `-0` is preserved.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @since 4.0.0
|
|
* @category Lang
|
|
* @param {*} value The value to process.
|
|
* @returns {string} Returns the string.
|
|
* @example
|
|
*
|
|
* _.toString(null);
|
|
* // => ''
|
|
*
|
|
* _.toString(-0);
|
|
* // => '-0'
|
|
*
|
|
* _.toString([1, 2, 3]);
|
|
* // => '1,2,3'
|
|
*/
|
|
function toString(value) {
|
|
return value == null ? '' : baseToString(value);
|
|
}
|
|
|
|
/**
|
|
* Deburrs `string` by converting
|
|
* [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table)
|
|
* and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A)
|
|
* letters to basic Latin letters and removing
|
|
* [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @since 3.0.0
|
|
* @category String
|
|
* @param {string} [string=''] The string to deburr.
|
|
* @returns {string} Returns the deburred string.
|
|
* @example
|
|
*
|
|
* _.deburr('déjà vu');
|
|
* // => 'deja vu'
|
|
*/
|
|
function deburr(string) {
|
|
string = toString(string);
|
|
return string && string.replace(reLatin, deburrLetter).replace(reComboMark, '');
|
|
}
|
|
|
|
/**
|
|
* Converts `string` to
|
|
* [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @since 3.1.0
|
|
* @category String
|
|
* @param {string} [string=''] The string to convert.
|
|
* @returns {string} Returns the start cased string.
|
|
* @example
|
|
*
|
|
* _.startCase('--foo-bar--');
|
|
* // => 'Foo Bar'
|
|
*
|
|
* _.startCase('fooBar');
|
|
* // => 'Foo Bar'
|
|
*
|
|
* _.startCase('__FOO_BAR__');
|
|
* // => 'FOO BAR'
|
|
*/
|
|
var startCase = createCompounder(function (result, word, index) {
|
|
return result + (index ? ' ' : '') + upperFirst$1(word);
|
|
});
|
|
|
|
/**
|
|
* Converts the first character of `string` to upper case.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @since 4.0.0
|
|
* @category String
|
|
* @param {string} [string=''] The string to convert.
|
|
* @returns {string} Returns the converted string.
|
|
* @example
|
|
*
|
|
* _.upperFirst('fred');
|
|
* // => 'Fred'
|
|
*
|
|
* _.upperFirst('FRED');
|
|
* // => 'FRED'
|
|
*/
|
|
var upperFirst$1 = createCaseFirst('toUpperCase');
|
|
|
|
/**
|
|
* Splits `string` into an array of its words.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @since 3.0.0
|
|
* @category String
|
|
* @param {string} [string=''] The string to inspect.
|
|
* @param {RegExp|string} [pattern] The pattern to match words.
|
|
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
|
|
* @returns {Array} Returns the words of `string`.
|
|
* @example
|
|
*
|
|
* _.words('fred, barney, & pebbles');
|
|
* // => ['fred', 'barney', 'pebbles']
|
|
*
|
|
* _.words('fred, barney, & pebbles', /[^, ]+/g);
|
|
* // => ['fred', 'barney', '&', 'pebbles']
|
|
*/
|
|
function words(string, pattern, guard) {
|
|
string = toString(string);
|
|
pattern = guard ? undefined : pattern;
|
|
|
|
if (pattern === undefined) {
|
|
return hasUnicodeWord(string) ? unicodeWords(string) : asciiWords(string);
|
|
}
|
|
return string.match(pattern) || [];
|
|
}
|
|
|
|
var lodash_startcase = startCase;
|
|
|
|
/**
|
|
* lodash (Custom Build) <https://lodash.com/>
|
|
* Build: `lodash modularize exports="npm" -o ./`
|
|
* Copyright jQuery Foundation and other contributors <https://jquery.org/>
|
|
* Released under MIT license <https://lodash.com/license>
|
|
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
|
|
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
|
*/
|
|
|
|
/** Used as the `TypeError` message for "Functions" methods. */
|
|
var FUNC_ERROR_TEXT = 'Expected a function';
|
|
|
|
/** Used to stand-in for `undefined` hash values. */
|
|
var HASH_UNDEFINED = '__lodash_hash_undefined__';
|
|
|
|
/** Used as references for various `Number` constants. */
|
|
var INFINITY$1 = 1 / 0;
|
|
|
|
/** `Object#toString` result references. */
|
|
var funcTag = '[object Function]',
|
|
genTag = '[object GeneratorFunction]',
|
|
symbolTag$1 = '[object Symbol]';
|
|
|
|
/** Used to match property names within property paths. */
|
|
var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,
|
|
reIsPlainProp = /^\w*$/,
|
|
reLeadingDot = /^\./,
|
|
rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;
|
|
|
|
/**
|
|
* Used to match `RegExp`
|
|
* [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
|
|
*/
|
|
var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
|
|
|
|
/** Used to match backslashes in property paths. */
|
|
var reEscapeChar = /\\(\\)?/g;
|
|
|
|
/** Used to detect host constructors (Safari). */
|
|
var reIsHostCtor = /^\[object .+?Constructor\]$/;
|
|
|
|
/** Detect free variable `global` from Node.js. */
|
|
var freeGlobal$1 = _typeof(commonjsGlobal) == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal;
|
|
|
|
/** Detect free variable `self`. */
|
|
var freeSelf$1 = (typeof self === 'undefined' ? 'undefined' : _typeof(self)) == 'object' && self && self.Object === Object && self;
|
|
|
|
/** Used as a reference to the global object. */
|
|
var root$1 = freeGlobal$1 || freeSelf$1 || Function('return this')();
|
|
|
|
/**
|
|
* Gets the value at `key` of `object`.
|
|
*
|
|
* @private
|
|
* @param {Object} [object] The object to query.
|
|
* @param {string} key The key of the property to get.
|
|
* @returns {*} Returns the property value.
|
|
*/
|
|
function getValue(object, key) {
|
|
return object == null ? undefined : object[key];
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is a host object in IE < 9.
|
|
*
|
|
* @private
|
|
* @param {*} value The value to check.
|
|
* @returns {boolean} Returns `true` if `value` is a host object, else `false`.
|
|
*/
|
|
function isHostObject(value) {
|
|
// Many host objects are `Object` objects that can coerce to strings
|
|
// despite having improperly defined `toString` methods.
|
|
var result = false;
|
|
if (value != null && typeof value.toString != 'function') {
|
|
try {
|
|
result = !!(value + '');
|
|
} catch (e) {}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/** Used for built-in method references. */
|
|
var arrayProto = Array.prototype,
|
|
funcProto = Function.prototype,
|
|
objectProto$1 = Object.prototype;
|
|
|
|
/** Used to detect overreaching core-js shims. */
|
|
var coreJsData = root$1['__core-js_shared__'];
|
|
|
|
/** Used to detect methods masquerading as native. */
|
|
var maskSrcKey = function () {
|
|
var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
|
|
return uid ? 'Symbol(src)_1.' + uid : '';
|
|
}();
|
|
|
|
/** Used to resolve the decompiled source of functions. */
|
|
var funcToString = funcProto.toString;
|
|
|
|
/** Used to check objects for own properties. */
|
|
var hasOwnProperty = objectProto$1.hasOwnProperty;
|
|
|
|
/**
|
|
* Used to resolve the
|
|
* [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
|
|
* of values.
|
|
*/
|
|
var objectToString$1 = objectProto$1.toString;
|
|
|
|
/** Used to detect if a method is native. */
|
|
var reIsNative = RegExp('^' + funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&').replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$');
|
|
|
|
/** Built-in value references. */
|
|
var _Symbol$1 = root$1.Symbol,
|
|
splice = arrayProto.splice;
|
|
|
|
/* Built-in method references that are verified to be native. */
|
|
var Map = getNative(root$1, 'Map'),
|
|
nativeCreate = getNative(Object, 'create');
|
|
|
|
/** Used to convert symbols to primitives and strings. */
|
|
var symbolProto$1 = _Symbol$1 ? _Symbol$1.prototype : undefined,
|
|
symbolToString$1 = symbolProto$1 ? symbolProto$1.toString : undefined;
|
|
|
|
/**
|
|
* Creates a hash object.
|
|
*
|
|
* @private
|
|
* @constructor
|
|
* @param {Array} [entries] The key-value pairs to cache.
|
|
*/
|
|
function Hash(entries) {
|
|
var index = -1,
|
|
length = entries ? entries.length : 0;
|
|
|
|
this.clear();
|
|
while (++index < length) {
|
|
var entry = entries[index];
|
|
this.set(entry[0], entry[1]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Removes all key-value entries from the hash.
|
|
*
|
|
* @private
|
|
* @name clear
|
|
* @memberOf Hash
|
|
*/
|
|
function hashClear() {
|
|
this.__data__ = nativeCreate ? nativeCreate(null) : {};
|
|
}
|
|
|
|
/**
|
|
* Removes `key` and its value from the hash.
|
|
*
|
|
* @private
|
|
* @name delete
|
|
* @memberOf Hash
|
|
* @param {Object} hash The hash to modify.
|
|
* @param {string} key The key of the value to remove.
|
|
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
|
|
*/
|
|
function hashDelete(key) {
|
|
return this.has(key) && delete this.__data__[key];
|
|
}
|
|
|
|
/**
|
|
* Gets the hash value for `key`.
|
|
*
|
|
* @private
|
|
* @name get
|
|
* @memberOf Hash
|
|
* @param {string} key The key of the value to get.
|
|
* @returns {*} Returns the entry value.
|
|
*/
|
|
function hashGet(key) {
|
|
var data = this.__data__;
|
|
if (nativeCreate) {
|
|
var result = data[key];
|
|
return result === HASH_UNDEFINED ? undefined : result;
|
|
}
|
|
return hasOwnProperty.call(data, key) ? data[key] : undefined;
|
|
}
|
|
|
|
/**
|
|
* Checks if a hash value for `key` exists.
|
|
*
|
|
* @private
|
|
* @name has
|
|
* @memberOf Hash
|
|
* @param {string} key The key of the entry to check.
|
|
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
|
|
*/
|
|
function hashHas(key) {
|
|
var data = this.__data__;
|
|
return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key);
|
|
}
|
|
|
|
/**
|
|
* Sets the hash `key` to `value`.
|
|
*
|
|
* @private
|
|
* @name set
|
|
* @memberOf Hash
|
|
* @param {string} key The key of the value to set.
|
|
* @param {*} value The value to set.
|
|
* @returns {Object} Returns the hash instance.
|
|
*/
|
|
function hashSet(key, value) {
|
|
var data = this.__data__;
|
|
data[key] = nativeCreate && value === undefined ? HASH_UNDEFINED : value;
|
|
return this;
|
|
}
|
|
|
|
// Add methods to `Hash`.
|
|
Hash.prototype.clear = hashClear;
|
|
Hash.prototype['delete'] = hashDelete;
|
|
Hash.prototype.get = hashGet;
|
|
Hash.prototype.has = hashHas;
|
|
Hash.prototype.set = hashSet;
|
|
|
|
/**
|
|
* Creates an list cache object.
|
|
*
|
|
* @private
|
|
* @constructor
|
|
* @param {Array} [entries] The key-value pairs to cache.
|
|
*/
|
|
function ListCache(entries) {
|
|
var index = -1,
|
|
length = entries ? entries.length : 0;
|
|
|
|
this.clear();
|
|
while (++index < length) {
|
|
var entry = entries[index];
|
|
this.set(entry[0], entry[1]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Removes all key-value entries from the list cache.
|
|
*
|
|
* @private
|
|
* @name clear
|
|
* @memberOf ListCache
|
|
*/
|
|
function listCacheClear() {
|
|
this.__data__ = [];
|
|
}
|
|
|
|
/**
|
|
* Removes `key` and its value from the list cache.
|
|
*
|
|
* @private
|
|
* @name delete
|
|
* @memberOf ListCache
|
|
* @param {string} key The key of the value to remove.
|
|
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
|
|
*/
|
|
function listCacheDelete(key) {
|
|
var data = this.__data__,
|
|
index = assocIndexOf(data, key);
|
|
|
|
if (index < 0) {
|
|
return false;
|
|
}
|
|
var lastIndex = data.length - 1;
|
|
if (index == lastIndex) {
|
|
data.pop();
|
|
} else {
|
|
splice.call(data, index, 1);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Gets the list cache value for `key`.
|
|
*
|
|
* @private
|
|
* @name get
|
|
* @memberOf ListCache
|
|
* @param {string} key The key of the value to get.
|
|
* @returns {*} Returns the entry value.
|
|
*/
|
|
function listCacheGet(key) {
|
|
var data = this.__data__,
|
|
index = assocIndexOf(data, key);
|
|
|
|
return index < 0 ? undefined : data[index][1];
|
|
}
|
|
|
|
/**
|
|
* Checks if a list cache value for `key` exists.
|
|
*
|
|
* @private
|
|
* @name has
|
|
* @memberOf ListCache
|
|
* @param {string} key The key of the entry to check.
|
|
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
|
|
*/
|
|
function listCacheHas(key) {
|
|
return assocIndexOf(this.__data__, key) > -1;
|
|
}
|
|
|
|
/**
|
|
* Sets the list cache `key` to `value`.
|
|
*
|
|
* @private
|
|
* @name set
|
|
* @memberOf ListCache
|
|
* @param {string} key The key of the value to set.
|
|
* @param {*} value The value to set.
|
|
* @returns {Object} Returns the list cache instance.
|
|
*/
|
|
function listCacheSet(key, value) {
|
|
var data = this.__data__,
|
|
index = assocIndexOf(data, key);
|
|
|
|
if (index < 0) {
|
|
data.push([key, value]);
|
|
} else {
|
|
data[index][1] = value;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
// Add methods to `ListCache`.
|
|
ListCache.prototype.clear = listCacheClear;
|
|
ListCache.prototype['delete'] = listCacheDelete;
|
|
ListCache.prototype.get = listCacheGet;
|
|
ListCache.prototype.has = listCacheHas;
|
|
ListCache.prototype.set = listCacheSet;
|
|
|
|
/**
|
|
* Creates a map cache object to store key-value pairs.
|
|
*
|
|
* @private
|
|
* @constructor
|
|
* @param {Array} [entries] The key-value pairs to cache.
|
|
*/
|
|
function MapCache(entries) {
|
|
var index = -1,
|
|
length = entries ? entries.length : 0;
|
|
|
|
this.clear();
|
|
while (++index < length) {
|
|
var entry = entries[index];
|
|
this.set(entry[0], entry[1]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Removes all key-value entries from the map.
|
|
*
|
|
* @private
|
|
* @name clear
|
|
* @memberOf MapCache
|
|
*/
|
|
function mapCacheClear() {
|
|
this.__data__ = {
|
|
'hash': new Hash(),
|
|
'map': new (Map || ListCache)(),
|
|
'string': new Hash()
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Removes `key` and its value from the map.
|
|
*
|
|
* @private
|
|
* @name delete
|
|
* @memberOf MapCache
|
|
* @param {string} key The key of the value to remove.
|
|
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
|
|
*/
|
|
function mapCacheDelete(key) {
|
|
return getMapData(this, key)['delete'](key);
|
|
}
|
|
|
|
/**
|
|
* Gets the map value for `key`.
|
|
*
|
|
* @private
|
|
* @name get
|
|
* @memberOf MapCache
|
|
* @param {string} key The key of the value to get.
|
|
* @returns {*} Returns the entry value.
|
|
*/
|
|
function mapCacheGet(key) {
|
|
return getMapData(this, key).get(key);
|
|
}
|
|
|
|
/**
|
|
* Checks if a map value for `key` exists.
|
|
*
|
|
* @private
|
|
* @name has
|
|
* @memberOf MapCache
|
|
* @param {string} key The key of the entry to check.
|
|
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
|
|
*/
|
|
function mapCacheHas(key) {
|
|
return getMapData(this, key).has(key);
|
|
}
|
|
|
|
/**
|
|
* Sets the map `key` to `value`.
|
|
*
|
|
* @private
|
|
* @name set
|
|
* @memberOf MapCache
|
|
* @param {string} key The key of the value to set.
|
|
* @param {*} value The value to set.
|
|
* @returns {Object} Returns the map cache instance.
|
|
*/
|
|
function mapCacheSet(key, value) {
|
|
getMapData(this, key).set(key, value);
|
|
return this;
|
|
}
|
|
|
|
// Add methods to `MapCache`.
|
|
MapCache.prototype.clear = mapCacheClear;
|
|
MapCache.prototype['delete'] = mapCacheDelete;
|
|
MapCache.prototype.get = mapCacheGet;
|
|
MapCache.prototype.has = mapCacheHas;
|
|
MapCache.prototype.set = mapCacheSet;
|
|
|
|
/**
|
|
* Gets the index at which the `key` is found in `array` of key-value pairs.
|
|
*
|
|
* @private
|
|
* @param {Array} array The array to inspect.
|
|
* @param {*} key The key to search for.
|
|
* @returns {number} Returns the index of the matched value, else `-1`.
|
|
*/
|
|
function assocIndexOf(array, key) {
|
|
var length = array.length;
|
|
while (length--) {
|
|
if (eq(array[length][0], key)) {
|
|
return length;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* The base implementation of `_.get` without support for default values.
|
|
*
|
|
* @private
|
|
* @param {Object} object The object to query.
|
|
* @param {Array|string} path The path of the property to get.
|
|
* @returns {*} Returns the resolved value.
|
|
*/
|
|
function baseGet(object, path) {
|
|
path = isKey(path, object) ? [path] : castPath(path);
|
|
|
|
var index = 0,
|
|
length = path.length;
|
|
|
|
while (object != null && index < length) {
|
|
object = object[toKey(path[index++])];
|
|
}
|
|
return index && index == length ? object : undefined;
|
|
}
|
|
|
|
/**
|
|
* The base implementation of `_.isNative` without bad shim checks.
|
|
*
|
|
* @private
|
|
* @param {*} value The value to check.
|
|
* @returns {boolean} Returns `true` if `value` is a native function,
|
|
* else `false`.
|
|
*/
|
|
function baseIsNative(value) {
|
|
if (!isObject$2(value) || isMasked(value)) {
|
|
return false;
|
|
}
|
|
var pattern = isFunction$1(value) || isHostObject(value) ? reIsNative : reIsHostCtor;
|
|
return pattern.test(toSource(value));
|
|
}
|
|
|
|
/**
|
|
* The base implementation of `_.toString` which doesn't convert nullish
|
|
* values to empty strings.
|
|
*
|
|
* @private
|
|
* @param {*} value The value to process.
|
|
* @returns {string} Returns the string.
|
|
*/
|
|
function baseToString$1(value) {
|
|
// Exit early for strings to avoid a performance hit in some environments.
|
|
if (typeof value == 'string') {
|
|
return value;
|
|
}
|
|
if (isSymbol$1(value)) {
|
|
return symbolToString$1 ? symbolToString$1.call(value) : '';
|
|
}
|
|
var result = value + '';
|
|
return result == '0' && 1 / value == -INFINITY$1 ? '-0' : result;
|
|
}
|
|
|
|
/**
|
|
* Casts `value` to a path array if it's not one.
|
|
*
|
|
* @private
|
|
* @param {*} value The value to inspect.
|
|
* @returns {Array} Returns the cast property path array.
|
|
*/
|
|
function castPath(value) {
|
|
return isArray$1(value) ? value : stringToPath(value);
|
|
}
|
|
|
|
/**
|
|
* Gets the data for `map`.
|
|
*
|
|
* @private
|
|
* @param {Object} map The map to query.
|
|
* @param {string} key The reference key.
|
|
* @returns {*} Returns the map data.
|
|
*/
|
|
function getMapData(map, key) {
|
|
var data = map.__data__;
|
|
return isKeyable(key) ? data[typeof key == 'string' ? 'string' : 'hash'] : data.map;
|
|
}
|
|
|
|
/**
|
|
* Gets the native function at `key` of `object`.
|
|
*
|
|
* @private
|
|
* @param {Object} object The object to query.
|
|
* @param {string} key The key of the method to get.
|
|
* @returns {*} Returns the function if it's native, else `undefined`.
|
|
*/
|
|
function getNative(object, key) {
|
|
var value = getValue(object, key);
|
|
return baseIsNative(value) ? value : undefined;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is a property name and not a property path.
|
|
*
|
|
* @private
|
|
* @param {*} value The value to check.
|
|
* @param {Object} [object] The object to query keys on.
|
|
* @returns {boolean} Returns `true` if `value` is a property name, else `false`.
|
|
*/
|
|
function isKey(value, object) {
|
|
if (isArray$1(value)) {
|
|
return false;
|
|
}
|
|
var type = typeof value === 'undefined' ? 'undefined' : _typeof(value);
|
|
if (type == 'number' || type == 'symbol' || type == 'boolean' || value == null || isSymbol$1(value)) {
|
|
return true;
|
|
}
|
|
return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || object != null && value in Object(object);
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is suitable for use as unique object key.
|
|
*
|
|
* @private
|
|
* @param {*} value The value to check.
|
|
* @returns {boolean} Returns `true` if `value` is suitable, else `false`.
|
|
*/
|
|
function isKeyable(value) {
|
|
var type = typeof value === 'undefined' ? 'undefined' : _typeof(value);
|
|
return type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean' ? value !== '__proto__' : value === null;
|
|
}
|
|
|
|
/**
|
|
* Checks if `func` has its source masked.
|
|
*
|
|
* @private
|
|
* @param {Function} func The function to check.
|
|
* @returns {boolean} Returns `true` if `func` is masked, else `false`.
|
|
*/
|
|
function isMasked(func) {
|
|
return !!maskSrcKey && maskSrcKey in func;
|
|
}
|
|
|
|
/**
|
|
* Converts `string` to a property path array.
|
|
*
|
|
* @private
|
|
* @param {string} string The string to convert.
|
|
* @returns {Array} Returns the property path array.
|
|
*/
|
|
var stringToPath = memoize$1(function (string) {
|
|
string = toString$1(string);
|
|
|
|
var result = [];
|
|
if (reLeadingDot.test(string)) {
|
|
result.push('');
|
|
}
|
|
string.replace(rePropName, function (match, number, quote, string) {
|
|
result.push(quote ? string.replace(reEscapeChar, '$1') : number || match);
|
|
});
|
|
return result;
|
|
});
|
|
|
|
/**
|
|
* Converts `value` to a string key if it's not a string or symbol.
|
|
*
|
|
* @private
|
|
* @param {*} value The value to inspect.
|
|
* @returns {string|symbol} Returns the key.
|
|
*/
|
|
function toKey(value) {
|
|
if (typeof value == 'string' || isSymbol$1(value)) {
|
|
return value;
|
|
}
|
|
var result = value + '';
|
|
return result == '0' && 1 / value == -INFINITY$1 ? '-0' : result;
|
|
}
|
|
|
|
/**
|
|
* Converts `func` to its source code.
|
|
*
|
|
* @private
|
|
* @param {Function} func The function to process.
|
|
* @returns {string} Returns the source code.
|
|
*/
|
|
function toSource(func) {
|
|
if (func != null) {
|
|
try {
|
|
return funcToString.call(func);
|
|
} catch (e) {}
|
|
try {
|
|
return func + '';
|
|
} catch (e) {}
|
|
}
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Creates a function that memoizes the result of `func`. If `resolver` is
|
|
* provided, it determines the cache key for storing the result based on the
|
|
* arguments provided to the memoized function. By default, the first argument
|
|
* provided to the memoized function is used as the map cache key. The `func`
|
|
* is invoked with the `this` binding of the memoized function.
|
|
*
|
|
* **Note:** The cache is exposed as the `cache` property on the memoized
|
|
* function. Its creation may be customized by replacing the `_.memoize.Cache`
|
|
* constructor with one whose instances implement the
|
|
* [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)
|
|
* method interface of `delete`, `get`, `has`, and `set`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @since 0.1.0
|
|
* @category Function
|
|
* @param {Function} func The function to have its output memoized.
|
|
* @param {Function} [resolver] The function to resolve the cache key.
|
|
* @returns {Function} Returns the new memoized function.
|
|
* @example
|
|
*
|
|
* var object = { 'a': 1, 'b': 2 };
|
|
* var other = { 'c': 3, 'd': 4 };
|
|
*
|
|
* var values = _.memoize(_.values);
|
|
* values(object);
|
|
* // => [1, 2]
|
|
*
|
|
* values(other);
|
|
* // => [3, 4]
|
|
*
|
|
* object.a = 2;
|
|
* values(object);
|
|
* // => [1, 2]
|
|
*
|
|
* // Modify the result cache.
|
|
* values.cache.set(object, ['a', 'b']);
|
|
* values(object);
|
|
* // => ['a', 'b']
|
|
*
|
|
* // Replace `_.memoize.Cache`.
|
|
* _.memoize.Cache = WeakMap;
|
|
*/
|
|
function memoize$1(func, resolver) {
|
|
if (typeof func != 'function' || resolver && typeof resolver != 'function') {
|
|
throw new TypeError(FUNC_ERROR_TEXT);
|
|
}
|
|
var memoized = function memoized() {
|
|
var args = arguments,
|
|
key = resolver ? resolver.apply(this, args) : args[0],
|
|
cache = memoized.cache;
|
|
|
|
if (cache.has(key)) {
|
|
return cache.get(key);
|
|
}
|
|
var result = func.apply(this, args);
|
|
memoized.cache = cache.set(key, result);
|
|
return result;
|
|
};
|
|
memoized.cache = new (memoize$1.Cache || MapCache)();
|
|
return memoized;
|
|
}
|
|
|
|
// Assign cache to `_.memoize`.
|
|
memoize$1.Cache = MapCache;
|
|
|
|
/**
|
|
* Performs a
|
|
* [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
|
|
* comparison between two values to determine if they are equivalent.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @since 4.0.0
|
|
* @category Lang
|
|
* @param {*} value The value to compare.
|
|
* @param {*} other The other value to compare.
|
|
* @returns {boolean} Returns `true` if the values are equivalent, else `false`.
|
|
* @example
|
|
*
|
|
* var object = { 'a': 1 };
|
|
* var other = { 'a': 1 };
|
|
*
|
|
* _.eq(object, object);
|
|
* // => true
|
|
*
|
|
* _.eq(object, other);
|
|
* // => false
|
|
*
|
|
* _.eq('a', 'a');
|
|
* // => true
|
|
*
|
|
* _.eq('a', Object('a'));
|
|
* // => false
|
|
*
|
|
* _.eq(NaN, NaN);
|
|
* // => true
|
|
*/
|
|
function eq(value, other) {
|
|
return value === other || value !== value && other !== other;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is classified as an `Array` object.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @since 0.1.0
|
|
* @category Lang
|
|
* @param {*} value The value to check.
|
|
* @returns {boolean} Returns `true` if `value` is an array, else `false`.
|
|
* @example
|
|
*
|
|
* _.isArray([1, 2, 3]);
|
|
* // => true
|
|
*
|
|
* _.isArray(document.body.children);
|
|
* // => false
|
|
*
|
|
* _.isArray('abc');
|
|
* // => false
|
|
*
|
|
* _.isArray(_.noop);
|
|
* // => false
|
|
*/
|
|
var isArray$1 = Array.isArray;
|
|
|
|
/**
|
|
* Checks if `value` is classified as a `Function` object.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @since 0.1.0
|
|
* @category Lang
|
|
* @param {*} value The value to check.
|
|
* @returns {boolean} Returns `true` if `value` is a function, else `false`.
|
|
* @example
|
|
*
|
|
* _.isFunction(_);
|
|
* // => true
|
|
*
|
|
* _.isFunction(/abc/);
|
|
* // => false
|
|
*/
|
|
function isFunction$1(value) {
|
|
// The use of `Object#toString` avoids issues with the `typeof` operator
|
|
// in Safari 8-9 which returns 'object' for typed array and other constructors.
|
|
var tag = isObject$2(value) ? objectToString$1.call(value) : '';
|
|
return tag == funcTag || tag == genTag;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is the
|
|
* [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
|
|
* of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @since 0.1.0
|
|
* @category Lang
|
|
* @param {*} value The value to check.
|
|
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
|
|
* @example
|
|
*
|
|
* _.isObject({});
|
|
* // => true
|
|
*
|
|
* _.isObject([1, 2, 3]);
|
|
* // => true
|
|
*
|
|
* _.isObject(_.noop);
|
|
* // => true
|
|
*
|
|
* _.isObject(null);
|
|
* // => false
|
|
*/
|
|
function isObject$2(value) {
|
|
var type = typeof value === 'undefined' ? 'undefined' : _typeof(value);
|
|
return !!value && (type == 'object' || type == 'function');
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is object-like. A value is object-like if it's not `null`
|
|
* and has a `typeof` result of "object".
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @since 4.0.0
|
|
* @category Lang
|
|
* @param {*} value The value to check.
|
|
* @returns {boolean} Returns `true` if `value` is object-like, else `false`.
|
|
* @example
|
|
*
|
|
* _.isObjectLike({});
|
|
* // => true
|
|
*
|
|
* _.isObjectLike([1, 2, 3]);
|
|
* // => true
|
|
*
|
|
* _.isObjectLike(_.noop);
|
|
* // => false
|
|
*
|
|
* _.isObjectLike(null);
|
|
* // => false
|
|
*/
|
|
function isObjectLike$1(value) {
|
|
return !!value && (typeof value === 'undefined' ? 'undefined' : _typeof(value)) == 'object';
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is classified as a `Symbol` primitive or object.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @since 4.0.0
|
|
* @category Lang
|
|
* @param {*} value The value to check.
|
|
* @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
|
|
* @example
|
|
*
|
|
* _.isSymbol(Symbol.iterator);
|
|
* // => true
|
|
*
|
|
* _.isSymbol('abc');
|
|
* // => false
|
|
*/
|
|
function isSymbol$1(value) {
|
|
return (typeof value === 'undefined' ? 'undefined' : _typeof(value)) == 'symbol' || isObjectLike$1(value) && objectToString$1.call(value) == symbolTag$1;
|
|
}
|
|
|
|
/**
|
|
* Converts `value` to a string. An empty string is returned for `null`
|
|
* and `undefined` values. The sign of `-0` is preserved.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @since 4.0.0
|
|
* @category Lang
|
|
* @param {*} value The value to process.
|
|
* @returns {string} Returns the string.
|
|
* @example
|
|
*
|
|
* _.toString(null);
|
|
* // => ''
|
|
*
|
|
* _.toString(-0);
|
|
* // => '-0'
|
|
*
|
|
* _.toString([1, 2, 3]);
|
|
* // => '1,2,3'
|
|
*/
|
|
function toString$1(value) {
|
|
return value == null ? '' : baseToString$1(value);
|
|
}
|
|
|
|
/**
|
|
* Gets the value at `path` of `object`. If the resolved value is
|
|
* `undefined`, the `defaultValue` is returned in its place.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @since 3.7.0
|
|
* @category Object
|
|
* @param {Object} object The object to query.
|
|
* @param {Array|string} path The path of the property to get.
|
|
* @param {*} [defaultValue] The value returned for `undefined` resolved values.
|
|
* @returns {*} Returns the resolved value.
|
|
* @example
|
|
*
|
|
* var object = { 'a': [{ 'b': { 'c': 3 } }] };
|
|
*
|
|
* _.get(object, 'a[0].b.c');
|
|
* // => 3
|
|
*
|
|
* _.get(object, ['a', '0', 'b', 'c']);
|
|
* // => 3
|
|
*
|
|
* _.get(object, 'a.b.c', 'default');
|
|
* // => 'default'
|
|
*/
|
|
function get$1(object, path, defaultValue) {
|
|
var result = object == null ? undefined : baseGet(object, path);
|
|
return result === undefined ? defaultValue : result;
|
|
}
|
|
|
|
var lodash_get = get$1;
|
|
|
|
/*
|
|
* Consitant and stable sort function across JavsaScript platforms
|
|
*
|
|
* Inconsistant sorts can cause SSR problems between client and server
|
|
* such as in <b-table> if sortBy is applied to the data on server side render.
|
|
* Chrome and V8 native sorts are inconsistant/unstable
|
|
*
|
|
* This function uses native sort with fallback to index compare when the a and b
|
|
* compare returns 0
|
|
*
|
|
* Algorithm bsaed on:
|
|
* https://stackoverflow.com/questions/1427608/fast-stable-sorting-algorithm-implementation-in-javascript/45422645#45422645
|
|
*
|
|
* @param {array} array to sort
|
|
* @param {function} sortcompare function
|
|
* @return {array}
|
|
*/
|
|
|
|
function stableSort(array, compareFn) {
|
|
// Using `.bind(compareFn)` on the wrapped anonymous function improves
|
|
// performance by avoiding the function call setup. We don't use an arrow
|
|
// function here as it binds `this` to the `stableSort` context rather than
|
|
// the `compareFn` context, which wouldn't give us the performance increase.
|
|
return array.map(function (a, index) {
|
|
return [index, a];
|
|
}).sort(function (a, b) {
|
|
return this(a[1], b[1]) || a[0] - b[0];
|
|
}.bind(compareFn)).map(function (e) {
|
|
return e[1];
|
|
});
|
|
}
|
|
|
|
function toString$2(v) {
|
|
if (!v) {
|
|
return '';
|
|
}
|
|
if (v instanceof Object) {
|
|
return keys(v).map(function (k) {
|
|
return toString$2(v[k]);
|
|
}).join(' ');
|
|
}
|
|
return String(v);
|
|
}
|
|
|
|
function recToString(obj) {
|
|
if (!(obj instanceof Object)) {
|
|
return '';
|
|
}
|
|
return toString$2(keys(obj).reduce(function (o, k) {
|
|
// Ignore fields that start with _
|
|
if (!/^_/.test(k)) {
|
|
o[k] = obj[k];
|
|
}
|
|
return o;
|
|
}, {}));
|
|
}
|
|
|
|
function defaultSortCompare(a, b, sortBy) {
|
|
if (typeof a[sortBy] === 'number' && typeof b[sortBy] === 'number') {
|
|
return a[sortBy] < b[sortBy] && -1 || a[sortBy] > b[sortBy] && 1 || 0;
|
|
}
|
|
return toString$2(a[sortBy]).localeCompare(toString$2(b[sortBy]), undefined, {
|
|
numeric: true
|
|
});
|
|
}
|
|
|
|
function processField(key, value) {
|
|
var field = null;
|
|
if (typeof value === 'string') {
|
|
// Label shortcut
|
|
field = { key: key, label: value };
|
|
} else if (typeof value === 'function') {
|
|
// Formatter shortcut
|
|
field = { key: key, formatter: value };
|
|
} else if ((typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object') {
|
|
field = assign({}, value);
|
|
field.key = field.key || key;
|
|
} else if (value !== false) {
|
|
// Fallback to just key
|
|
field = { key: key };
|
|
}
|
|
return field;
|
|
}
|
|
|
|
var bTable = {
|
|
mixins: [idMixin, listenOnRootMixin],
|
|
render: function render(h) {
|
|
var _this = this;
|
|
|
|
var $slots = this.$slots;
|
|
var $scoped = this.$scopedSlots;
|
|
var fields = this.computedFields;
|
|
var items = this.computedItems;
|
|
|
|
// Build the caption
|
|
var caption = h(false);
|
|
if (this.caption || $slots['table-caption']) {
|
|
var data = { style: this.captionStyles };
|
|
if (!$slots['table-caption']) {
|
|
data.domProps = { innerHTML: this.caption };
|
|
}
|
|
caption = h('caption', data, $slots['table-caption']);
|
|
}
|
|
|
|
// Build the colgroup
|
|
var colgroup = $slots['table-colgroup'] ? h('colgroup', {}, $slots['table-colgroup']) : h(false);
|
|
|
|
// factory function for thead and tfoot cells (th's)
|
|
var makeHeadCells = function makeHeadCells() {
|
|
var isFoot = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
|
|
|
return fields.map(function (field, colIndex) {
|
|
var data = {
|
|
key: field.key,
|
|
class: _this.fieldClasses(field),
|
|
style: field.thStyle || {},
|
|
attrs: {
|
|
tabindex: field.sortable ? '0' : null,
|
|
abbr: field.headerAbbr || null,
|
|
title: field.headerTitle || null,
|
|
'aria-colindex': String(colIndex + 1),
|
|
'aria-label': field.sortable ? _this.localSortDesc && _this.localSortBy === field.key ? _this.labelSortAsc : _this.labelSortDesc : null,
|
|
'aria-sort': field.sortable && _this.localSortBy === field.key ? _this.localSortDesc ? 'descending' : 'ascending' : null
|
|
},
|
|
on: {
|
|
click: function click(evt) {
|
|
evt.stopPropagation();
|
|
evt.preventDefault();
|
|
_this.headClicked(evt, field);
|
|
},
|
|
keydown: function keydown(evt) {
|
|
var keyCode = evt.keyCode;
|
|
if (keyCode === KeyCodes.ENTER || keyCode === KeyCodes.SPACE) {
|
|
evt.stopPropagation();
|
|
evt.preventDefault();
|
|
_this.headClicked(evt, field);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
var slot = isFoot && $scoped['FOOT_' + field.key] ? $scoped['FOOT_' + field.key] : $scoped['HEAD_' + field.key];
|
|
if (slot) {
|
|
slot = [slot({ label: field.label, column: field.key, field: field })];
|
|
} else {
|
|
data.domProps = { innerHTML: field.label };
|
|
}
|
|
return h('th', data, slot);
|
|
});
|
|
};
|
|
|
|
// Build the thead
|
|
var thead = h(false);
|
|
if (this.isStacked !== true) {
|
|
// If in always stacked mode (this.isStacked === true), then we don't bother rendering the thead
|
|
thead = h('thead', { class: this.headClasses }, [h('tr', { class: this.theadTrClass }, makeHeadCells(false))]);
|
|
}
|
|
|
|
// Build the tfoot
|
|
var tfoot = h(false);
|
|
if (this.footClone && this.isStacked !== true) {
|
|
// If in always stacked mode (this.isStacked === true), then we don't bother rendering the tfoot
|
|
tfoot = h('tfoot', { class: this.footClasses }, [h('tr', { class: this.tfootTrClass }, makeHeadCells(true))]);
|
|
}
|
|
|
|
// Prepare the tbody rows
|
|
var rows = [];
|
|
|
|
// Add static Top Row slot (hidden in visibly stacked mode as we can't control the data-label)
|
|
// If in always stacked mode, we don't bother rendering the row
|
|
if ($scoped['top-row'] && this.isStacked !== true) {
|
|
rows.push(h('tr', { key: 'top-row', class: ['b-table-top-row', this.tbodyTrClass] }, [$scoped['top-row']({ columns: fields.length, fields: fields })]));
|
|
} else {
|
|
rows.push(h(false));
|
|
}
|
|
|
|
// Add the item data rows
|
|
items.forEach(function (item, rowIndex) {
|
|
var detailsSlot = $scoped['row-details'];
|
|
var rowShowDetails = Boolean(item._showDetails && detailsSlot);
|
|
var detailsId = rowShowDetails ? _this.safeId('_details_' + rowIndex + '_') : null;
|
|
var toggleDetailsFn = function toggleDetailsFn() {
|
|
if (detailsSlot) {
|
|
_this.$set(item, '_showDetails', !item._showDetails);
|
|
}
|
|
};
|
|
// For each item data field in row
|
|
var tds = fields.map(function (field, colIndex) {
|
|
var data = {
|
|
key: 'row-' + rowIndex + '-cell-' + colIndex,
|
|
class: _this.tdClasses(field, item),
|
|
attrs: _this.tdAttrs(field, item, colIndex),
|
|
domProps: {}
|
|
};
|
|
var childNodes = void 0;
|
|
if ($scoped[field.key]) {
|
|
childNodes = [$scoped[field.key]({
|
|
item: item,
|
|
index: rowIndex,
|
|
field: field,
|
|
unformatted: lodash_get(item, field.key),
|
|
value: _this.getFormattedValue(item, field),
|
|
toggleDetails: toggleDetailsFn,
|
|
detailsShowing: Boolean(item._showDetails)
|
|
})];
|
|
if (_this.isStacked) {
|
|
// We wrap in a DIV to ensure rendered as a single cell when visually stacked!
|
|
childNodes = [h('div', {}, [childNodes])];
|
|
}
|
|
} else {
|
|
var formatted = _this.getFormattedValue(item, field);
|
|
if (_this.isStacked) {
|
|
// We innerHTML a DIV to ensure rendered as a single cell when visually stacked!
|
|
childNodes = [h('div', formatted)];
|
|
} else {
|
|
// Non stacked
|
|
childNodes = formatted;
|
|
}
|
|
}
|
|
// Render either a td or th cell
|
|
return h(field.isRowHeader ? 'th' : 'td', data, childNodes);
|
|
});
|
|
// Calculate the row number in the dataset (indexed from 1)
|
|
var ariaRowIndex = null;
|
|
if (_this.currentPage && _this.perPage && _this.perPage > 0) {
|
|
ariaRowIndex = (_this.currentPage - 1) * _this.perPage + rowIndex + 1;
|
|
}
|
|
// Assemble and add the row
|
|
rows.push(h('tr', {
|
|
key: 'row-' + rowIndex,
|
|
class: [_this.rowClasses(item), { 'b-table-has-details': rowShowDetails }],
|
|
attrs: {
|
|
'aria-describedby': detailsId,
|
|
'aria-rowindex': ariaRowIndex,
|
|
role: _this.isStacked ? 'row' : null
|
|
},
|
|
on: {
|
|
click: function click(evt) {
|
|
_this.rowClicked(evt, item, rowIndex);
|
|
},
|
|
dblclick: function dblclick(evt) {
|
|
_this.rowDblClicked(evt, item, rowIndex);
|
|
},
|
|
mouseenter: function mouseenter(evt) {
|
|
_this.rowHovered(evt, item, rowIndex);
|
|
}
|
|
}
|
|
}, tds));
|
|
// Row Details slot
|
|
if (rowShowDetails) {
|
|
var tdAttrs = { colspan: String(fields.length) };
|
|
var trAttrs = { id: detailsId };
|
|
if (_this.isStacked) {
|
|
tdAttrs['role'] = 'cell';
|
|
trAttrs['role'] = 'row';
|
|
}
|
|
var details = h('td', { attrs: tdAttrs }, [detailsSlot({
|
|
item: item,
|
|
index: rowIndex,
|
|
fields: fields,
|
|
toggleDetails: toggleDetailsFn
|
|
})]);
|
|
rows.push(h('tr', {
|
|
key: 'details-' + rowIndex,
|
|
class: ['b-table-details', _this.tbodyTrClass],
|
|
attrs: trAttrs
|
|
}, [details]));
|
|
} else if (detailsSlot) {
|
|
// Only add the placeholder if a the table has a row-details slot defined (but not shown)
|
|
rows.push(h(false));
|
|
}
|
|
});
|
|
|
|
// Empty Items / Empty Filtered Row slot
|
|
if (this.showEmpty && (!items || items.length === 0)) {
|
|
var empty = this.filter ? $slots['emptyfiltered'] : $slots['empty'];
|
|
if (!empty) {
|
|
empty = h('div', {
|
|
class: ['text-center', 'my-2'],
|
|
domProps: { innerHTML: this.filter ? this.emptyFilteredText : this.emptyText }
|
|
});
|
|
}
|
|
empty = h('td', {
|
|
attrs: {
|
|
colspan: String(fields.length),
|
|
role: this.isStacked ? 'cell' : null
|
|
}
|
|
}, [h('div', { attrs: { role: 'alert', 'aria-live': 'polite' } }, [empty])]);
|
|
rows.push(h('tr', {
|
|
key: 'empty-row',
|
|
class: ['b-table-empty-row', this.tbodyTrClass],
|
|
attrs: this.isStacked ? { role: 'row' } : {}
|
|
}, [empty]));
|
|
} else {
|
|
rows.push(h(false));
|
|
}
|
|
|
|
// Static bottom row slot (hidden in visibly stacked mode as we can't control the data-label)
|
|
// If in always stacked mode, we don't bother rendering the row
|
|
if ($scoped['bottom-row'] && this.isStacked !== true) {
|
|
rows.push(h('tr', { key: 'bottom-row', class: ['b-table-bottom-row', this.tbodyTrClass] }, [$scoped['bottom-row']({ columns: fields.length, fields: fields })]));
|
|
} else {
|
|
rows.push(h(false));
|
|
}
|
|
|
|
// Assemble the rows into the tbody
|
|
var tbody = h('tbody', { class: this.bodyClasses, attrs: this.isStacked ? { role: 'rowgroup' } : {} }, rows);
|
|
|
|
// Assemble table
|
|
var table = h('table', {
|
|
class: this.tableClasses,
|
|
attrs: {
|
|
id: this.safeId(),
|
|
role: this.isStacked ? 'table' : null,
|
|
'aria-busy': this.computedBusy ? 'true' : 'false',
|
|
'aria-colcount': String(fields.length),
|
|
'aria-rowcount': this.$attrs['aria-rowcount'] || this.items.length > this.perPage ? this.items.length : null
|
|
}
|
|
}, [caption, colgroup, thead, tfoot, tbody]);
|
|
|
|
// Add responsive wrapper if needed and return table
|
|
return this.isResponsive ? h('div', { class: this.responsiveClass }, [table]) : table;
|
|
},
|
|
data: function data() {
|
|
return {
|
|
localSortBy: this.sortBy || '',
|
|
localSortDesc: this.sortDesc || false,
|
|
localItems: [],
|
|
// Note: filteredItems only used to determine if # of items changed
|
|
filteredItems: [],
|
|
localBusy: false
|
|
};
|
|
},
|
|
|
|
props: {
|
|
items: {
|
|
type: [Array, Function],
|
|
default: function _default() {
|
|
return [];
|
|
}
|
|
},
|
|
fields: {
|
|
type: [Object, Array],
|
|
default: null
|
|
},
|
|
sortBy: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
sortDesc: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
sortDirection: {
|
|
type: String,
|
|
default: 'asc',
|
|
validator: function validator(direction) {
|
|
return arrayIncludes(['asc', 'desc', 'last'], direction);
|
|
}
|
|
},
|
|
caption: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
captionTop: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
striped: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
bordered: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
outlined: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
dark: {
|
|
type: Boolean,
|
|
default: function _default() {
|
|
if (this && typeof this.inverse === 'boolean') {
|
|
// Deprecate inverse
|
|
warn("b-table: prop 'inverse' has been deprecated. Use 'dark' instead");
|
|
return this.dark;
|
|
}
|
|
return false;
|
|
}
|
|
},
|
|
inverse: {
|
|
// Deprecated in v1.0.0 in favor of `dark`
|
|
type: Boolean,
|
|
default: null
|
|
},
|
|
hover: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
small: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
fixed: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
footClone: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
responsive: {
|
|
type: [Boolean, String],
|
|
default: false
|
|
},
|
|
stacked: {
|
|
type: [Boolean, String],
|
|
default: false
|
|
},
|
|
headVariant: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
footVariant: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
theadClass: {
|
|
type: [String, Array],
|
|
default: null
|
|
},
|
|
theadTrClass: {
|
|
type: [String, Array],
|
|
default: null
|
|
},
|
|
tbodyClass: {
|
|
type: [String, Array],
|
|
default: null
|
|
},
|
|
tbodyTrClass: {
|
|
type: [String, Array],
|
|
default: null
|
|
},
|
|
tfootClass: {
|
|
type: [String, Array],
|
|
default: null
|
|
},
|
|
tfootTrClass: {
|
|
type: [String, Array],
|
|
default: null
|
|
},
|
|
perPage: {
|
|
type: Number,
|
|
default: 0
|
|
},
|
|
currentPage: {
|
|
type: Number,
|
|
default: 1
|
|
},
|
|
filter: {
|
|
type: [String, RegExp, Function],
|
|
default: null
|
|
},
|
|
sortCompare: {
|
|
type: Function,
|
|
default: null
|
|
},
|
|
noLocalSorting: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
noProviderPaging: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
noProviderSorting: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
noProviderFiltering: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
noSortReset: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
busy: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
value: {
|
|
type: Array,
|
|
default: function _default() {
|
|
return [];
|
|
}
|
|
},
|
|
labelSortAsc: {
|
|
type: String,
|
|
default: 'Click to sort Ascending'
|
|
},
|
|
labelSortDesc: {
|
|
type: String,
|
|
default: 'Click to sort Descending'
|
|
},
|
|
showEmpty: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
emptyText: {
|
|
type: String,
|
|
default: 'There are no records to show'
|
|
},
|
|
emptyFilteredText: {
|
|
type: String,
|
|
default: 'There are no records matching your request'
|
|
},
|
|
apiUrl: {
|
|
// Passthrough prop. Passed to the context object. Not used by b-table directly
|
|
type: String,
|
|
default: ''
|
|
}
|
|
},
|
|
watch: {
|
|
items: function items(newVal, oldVal) {
|
|
if (oldVal !== newVal) {
|
|
this._providerUpdate();
|
|
}
|
|
},
|
|
context: function context(newVal, oldVal) {
|
|
if (!looseEqual(newVal, oldVal)) {
|
|
this.$emit('context-changed', newVal);
|
|
}
|
|
},
|
|
filteredItems: function filteredItems(newVal, oldVal) {
|
|
if (this.localFiltering && newVal.length !== oldVal.length) {
|
|
// Emit a filtered notification event, as number of filtered items has changed
|
|
this.$emit('filtered', newVal);
|
|
}
|
|
},
|
|
sortDesc: function sortDesc(newVal, oldVal) {
|
|
if (newVal === this.localSortDesc) {
|
|
return;
|
|
}
|
|
this.localSortDesc = newVal || false;
|
|
},
|
|
localSortDesc: function localSortDesc(newVal, oldVal) {
|
|
// Emit update to sort-desc.sync
|
|
if (newVal !== oldVal) {
|
|
this.$emit('update:sortDesc', newVal);
|
|
if (!this.noProviderSorting) {
|
|
this._providerUpdate();
|
|
}
|
|
}
|
|
},
|
|
sortBy: function sortBy(newVal, oldVal) {
|
|
if (newVal === this.localSortBy) {
|
|
return;
|
|
}
|
|
this.localSortBy = newVal || null;
|
|
},
|
|
localSortBy: function localSortBy(newVal, oldVal) {
|
|
if (newVal !== oldVal) {
|
|
this.$emit('update:sortBy', newVal);
|
|
if (!this.noProviderSorting) {
|
|
this._providerUpdate();
|
|
}
|
|
}
|
|
},
|
|
perPage: function perPage(newVal, oldVal) {
|
|
if (oldVal !== newVal && !this.noProviderPaging) {
|
|
this._providerUpdate();
|
|
}
|
|
},
|
|
currentPage: function currentPage(newVal, oldVal) {
|
|
if (oldVal !== newVal && !this.noProviderPaging) {
|
|
this._providerUpdate();
|
|
}
|
|
},
|
|
filter: function filter(newVal, oldVal) {
|
|
if (oldVal !== newVal && !this.noProviderFiltering) {
|
|
this._providerUpdate();
|
|
}
|
|
},
|
|
localBusy: function localBusy(newVal, oldVal) {
|
|
if (newVal !== oldVal) {
|
|
this.$emit('update:busy', newVal);
|
|
}
|
|
}
|
|
},
|
|
mounted: function mounted() {
|
|
var _this2 = this;
|
|
|
|
this.localSortBy = this.sortBy;
|
|
this.localSortDesc = this.sortDesc;
|
|
if (this.hasProvider) {
|
|
this._providerUpdate();
|
|
}
|
|
this.listenOnRoot('bv::refresh::table', function (id) {
|
|
if (id === _this2.id || id === _this2) {
|
|
_this2._providerUpdate();
|
|
}
|
|
});
|
|
},
|
|
|
|
computed: {
|
|
isStacked: function isStacked() {
|
|
return this.stacked === '' ? true : this.stacked;
|
|
},
|
|
isResponsive: function isResponsive() {
|
|
var responsive = this.responsive === '' ? true : this.responsive;
|
|
return this.isStacked ? false : responsive;
|
|
},
|
|
responsiveClass: function responsiveClass() {
|
|
return this.isResponsive === true ? 'table-responsive' : this.isResponsive ? 'table-responsive-' + this.responsive : '';
|
|
},
|
|
tableClasses: function tableClasses() {
|
|
return ['table', 'b-table', this.striped ? 'table-striped' : '', this.hover ? 'table-hover' : '', this.dark ? 'table-dark' : '', this.bordered ? 'table-bordered' : '', this.small ? 'table-sm' : '', this.outlined ? 'border' : '', this.fixed ? 'b-table-fixed' : '', this.isStacked === true ? 'b-table-stacked' : this.isStacked ? 'b-table-stacked-' + this.stacked : ''];
|
|
},
|
|
headClasses: function headClasses() {
|
|
return [this.headVariant ? 'thead-' + this.headVariant : '', this.theadClass];
|
|
},
|
|
bodyClasses: function bodyClasses() {
|
|
return [this.tbodyClass];
|
|
},
|
|
footClasses: function footClasses() {
|
|
var variant = this.footVariant || this.headVariant || null;
|
|
return [variant ? 'thead-' + variant : '', this.tfootClass];
|
|
},
|
|
captionStyles: function captionStyles() {
|
|
// Move caption to top
|
|
return this.captionTop ? { captionSide: 'top' } : {};
|
|
},
|
|
hasProvider: function hasProvider() {
|
|
return this.items instanceof Function;
|
|
},
|
|
localFiltering: function localFiltering() {
|
|
return this.hasProvider ? this.noProviderFiltering : true;
|
|
},
|
|
localSorting: function localSorting() {
|
|
return this.hasProvider ? this.noProviderSorting : !this.noLocalSorting;
|
|
},
|
|
localPaging: function localPaging() {
|
|
return this.hasProvider ? this.noProviderPaging : true;
|
|
},
|
|
context: function context() {
|
|
return {
|
|
perPage: this.perPage,
|
|
currentPage: this.currentPage,
|
|
filter: this.filter,
|
|
sortBy: this.localSortBy,
|
|
sortDesc: this.localSortDesc,
|
|
apiUrl: this.apiUrl
|
|
};
|
|
},
|
|
computedFields: function computedFields() {
|
|
var _this3 = this;
|
|
|
|
// We normalize fields into an array of objects
|
|
// [ { key:..., label:..., ...}, {...}, ..., {..}]
|
|
var fields = [];
|
|
if (isArray(this.fields)) {
|
|
// Normalize array Form
|
|
this.fields.filter(function (f) {
|
|
return f;
|
|
}).forEach(function (f) {
|
|
if (typeof f === 'string') {
|
|
fields.push({ key: f, label: lodash_startcase(f) });
|
|
} else if ((typeof f === 'undefined' ? 'undefined' : _typeof(f)) === 'object' && f.key && typeof f.key === 'string') {
|
|
// Full object definition. We use assign so that we don't mutate the original
|
|
fields.push(assign({}, f));
|
|
} else if ((typeof f === 'undefined' ? 'undefined' : _typeof(f)) === 'object' && keys(f).length === 1) {
|
|
// Shortcut object (i.e. { 'foo_bar': 'This is Foo Bar' }
|
|
var key = keys(f)[0];
|
|
var field = processField(key, f[key]);
|
|
if (field) {
|
|
fields.push(field);
|
|
}
|
|
}
|
|
});
|
|
} else if (this.fields && _typeof(this.fields) === 'object' && keys(this.fields).length > 0) {
|
|
// Normalize object Form
|
|
keys(this.fields).forEach(function (key) {
|
|
var field = processField(key, _this3.fields[key]);
|
|
if (field) {
|
|
fields.push(field);
|
|
}
|
|
});
|
|
}
|
|
// If no field provided, take a sample from first record (if exits)
|
|
if (fields.length === 0 && this.computedItems.length > 0) {
|
|
var sample = this.computedItems[0];
|
|
var ignoredKeys = ['_rowVariant', '_cellVariants', '_showDetails'];
|
|
keys(sample).forEach(function (k) {
|
|
if (!ignoredKeys.includes(k)) {
|
|
fields.push({ key: k, label: lodash_startcase(k) });
|
|
}
|
|
});
|
|
}
|
|
// Ensure we have a unique array of fields and that they have String labels
|
|
var memo = {};
|
|
return fields.filter(function (f) {
|
|
if (!memo[f.key]) {
|
|
memo[f.key] = true;
|
|
f.label = typeof f.label === 'string' ? f.label : lodash_startcase(f.key);
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
},
|
|
computedItems: function computedItems() {
|
|
// Grab some props/data to ensure reactivity
|
|
var perPage = this.perPage;
|
|
var currentPage = this.currentPage;
|
|
var filter = this.filter;
|
|
var sortBy = this.localSortBy;
|
|
var sortDesc = this.localSortDesc;
|
|
var sortCompare = this.sortCompare;
|
|
var localFiltering = this.localFiltering;
|
|
var localSorting = this.localSorting;
|
|
var localPaging = this.localPaging;
|
|
var items = this.hasProvider ? this.localItems : this.items;
|
|
if (!items) {
|
|
this.$nextTick(this._providerUpdate);
|
|
return [];
|
|
}
|
|
// Array copy for sorting, filtering, etc.
|
|
items = items.slice();
|
|
// Apply local filter
|
|
if (filter && localFiltering) {
|
|
if (filter instanceof Function) {
|
|
items = items.filter(filter);
|
|
} else {
|
|
var regex = void 0;
|
|
if (filter instanceof RegExp) {
|
|
regex = filter;
|
|
} else {
|
|
regex = new RegExp('.*' + filter + '.*', 'ig');
|
|
}
|
|
items = items.filter(function (item) {
|
|
var test = regex.test(recToString(item));
|
|
regex.lastIndex = 0;
|
|
return test;
|
|
});
|
|
}
|
|
}
|
|
if (localFiltering) {
|
|
// Make a local copy of filtered items to trigger filtered event
|
|
this.filteredItems = items.slice();
|
|
}
|
|
// Apply local Sort
|
|
if (sortBy && localSorting) {
|
|
items = stableSort(items, function (a, b) {
|
|
var ret = null;
|
|
if (typeof sortCompare === 'function') {
|
|
// Call user provided sortCompare routine
|
|
ret = sortCompare(a, b, sortBy);
|
|
}
|
|
if (ret === null || ret === undefined) {
|
|
// Fallback to defaultSortCompare if sortCompare not defined or returns null
|
|
ret = defaultSortCompare(a, b, sortBy);
|
|
}
|
|
// Handle sorting direction
|
|
return (ret || 0) * (sortDesc ? -1 : 1);
|
|
});
|
|
}
|
|
// Apply local pagination
|
|
if (Boolean(perPage) && localPaging) {
|
|
// Grab the current page of data (which may be past filtered items)
|
|
items = items.slice((currentPage - 1) * perPage, currentPage * perPage);
|
|
}
|
|
// Update the value model with the filtered/sorted/paginated data set
|
|
this.$emit('input', items);
|
|
return items;
|
|
},
|
|
computedBusy: function computedBusy() {
|
|
return this.busy || this.localBusy;
|
|
}
|
|
},
|
|
methods: {
|
|
keys: keys,
|
|
fieldClasses: function fieldClasses(field) {
|
|
return [field.sortable ? 'sorting' : '', field.sortable && this.localSortBy === field.key ? 'sorting_' + (this.localSortDesc ? 'desc' : 'asc') : '', field.variant ? 'table-' + field.variant : '', field.class ? field.class : '', field.thClass ? field.thClass : ''];
|
|
},
|
|
tdClasses: function tdClasses(field, item) {
|
|
var cellVariant = '';
|
|
if (item._cellVariants && item._cellVariants[field.key]) {
|
|
cellVariant = (this.dark ? 'bg' : 'table') + '-' + item._cellVariants[field.key];
|
|
}
|
|
return [field.variant && !cellVariant ? (this.dark ? 'bg' : 'table') + '-' + field.variant : '', cellVariant, field.class ? field.class : '', this.getTdValues(item, field.key, field.tdClass, '')];
|
|
},
|
|
tdAttrs: function tdAttrs(field, item, colIndex) {
|
|
var attrs = {};
|
|
attrs['aria-colindex'] = String(colIndex + 1);
|
|
if (this.isStacked) {
|
|
// Generate the "header cell" label content in stacked mode
|
|
attrs['data-label'] = field.label;
|
|
if (field.isRowHeader) {
|
|
attrs['role'] = 'rowheader';
|
|
} else {
|
|
attrs['role'] = 'cell';
|
|
}
|
|
}
|
|
return assign({}, attrs, this.getTdValues(item, field.key, field.tdAttr, {}));
|
|
},
|
|
rowClasses: function rowClasses(item) {
|
|
return [item._rowVariant ? (this.dark ? 'bg' : 'table') + '-' + item._rowVariant : '', this.tbodyTrClass];
|
|
},
|
|
rowClicked: function rowClicked(e, item, index) {
|
|
if (this.stopIfBusy(e)) {
|
|
// If table is busy (via provider) then don't propagate
|
|
return;
|
|
}
|
|
this.$emit('row-clicked', item, index, e);
|
|
},
|
|
rowDblClicked: function rowDblClicked(e, item, index) {
|
|
if (this.stopIfBusy(e)) {
|
|
// If table is busy (via provider) then don't propagate
|
|
return;
|
|
}
|
|
this.$emit('row-dblclicked', item, index, e);
|
|
},
|
|
rowHovered: function rowHovered(e, item, index) {
|
|
if (this.stopIfBusy(e)) {
|
|
// If table is busy (via provider) then don't propagate
|
|
return;
|
|
}
|
|
this.$emit('row-hovered', item, index, e);
|
|
},
|
|
headClicked: function headClicked(e, field) {
|
|
var _this4 = this;
|
|
|
|
if (this.stopIfBusy(e)) {
|
|
// If table is busy (via provider) then don't propagate
|
|
return;
|
|
}
|
|
var sortChanged = false;
|
|
var toggleLocalSortDesc = function toggleLocalSortDesc() {
|
|
var sortDirection = field.sortDirection || _this4.sortDirection;
|
|
if (sortDirection === 'asc') {
|
|
_this4.localSortDesc = false;
|
|
} else if (sortDirection === 'desc') {
|
|
_this4.localSortDesc = true;
|
|
}
|
|
};
|
|
if (field.sortable) {
|
|
if (field.key === this.localSortBy) {
|
|
// Change sorting direction on current column
|
|
this.localSortDesc = !this.localSortDesc;
|
|
} else {
|
|
// Start sorting this column ascending
|
|
this.localSortBy = field.key;
|
|
toggleLocalSortDesc();
|
|
}
|
|
sortChanged = true;
|
|
} else if (this.localSortBy && !this.noSortReset) {
|
|
this.localSortBy = null;
|
|
toggleLocalSortDesc();
|
|
sortChanged = true;
|
|
}
|
|
this.$emit('head-clicked', field.key, field, e);
|
|
if (sortChanged) {
|
|
// Sorting parameters changed
|
|
this.$emit('sort-changed', this.context);
|
|
}
|
|
},
|
|
stopIfBusy: function stopIfBusy(evt) {
|
|
if (this.computedBusy) {
|
|
// If table is busy (via provider) then don't propagate
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
refresh: function refresh() {
|
|
// Expose refresh method
|
|
if (this.hasProvider) {
|
|
this._providerUpdate();
|
|
}
|
|
},
|
|
_providerSetLocal: function _providerSetLocal(items) {
|
|
this.localItems = items && items.length > 0 ? items.slice() : [];
|
|
this.localBusy = false;
|
|
this.$emit('refreshed');
|
|
// Deprecated root emit
|
|
this.emitOnRoot('table::refreshed', this.id);
|
|
// New root emit
|
|
if (this.id) {
|
|
this.emitOnRoot('bv::table::refreshed', this.id);
|
|
}
|
|
},
|
|
_providerUpdate: function _providerUpdate() {
|
|
var _this5 = this;
|
|
|
|
// Refresh the provider items
|
|
if (this.computedBusy || !this.hasProvider) {
|
|
// Don't refresh remote data if we are 'busy' or if no provider
|
|
return;
|
|
}
|
|
// Set internal busy state
|
|
this.localBusy = true;
|
|
// Call provider function with context and optional callback
|
|
var data = this.items(this.context, this._providerSetLocal);
|
|
if (data && data.then && typeof data.then === 'function') {
|
|
// Provider returned Promise
|
|
data.then(function (items) {
|
|
_this5._providerSetLocal(items);
|
|
});
|
|
} else {
|
|
// Provider returned Array data
|
|
this._providerSetLocal(data);
|
|
}
|
|
},
|
|
getTdValues: function getTdValues(item, key, tdValue, defValue) {
|
|
var parent = this.$parent;
|
|
if (tdValue) {
|
|
if (typeof tdValue === 'function') {
|
|
var value = lodash_get(item, key);
|
|
return tdValue(value, key, item);
|
|
} else if (typeof tdValue === 'string' && typeof parent[tdValue] === 'function') {
|
|
var _value = lodash_get(item, key);
|
|
return parent[tdValue](_value, key, item);
|
|
}
|
|
return tdValue;
|
|
}
|
|
return defValue;
|
|
},
|
|
getFormattedValue: function getFormattedValue(item, field) {
|
|
var key = field.key;
|
|
var formatter = field.formatter;
|
|
var parent = this.$parent;
|
|
var value = lodash_get(item, key);
|
|
if (formatter) {
|
|
if (typeof formatter === 'function') {
|
|
value = formatter(value, key, item);
|
|
} else if (typeof formatter === 'string' && typeof parent[formatter] === 'function') {
|
|
value = parent[formatter](value, key, item);
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
}
|
|
};
|
|
|
|
var components$x = {
|
|
bTable: bTable
|
|
};
|
|
|
|
var VuePlugin$z = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$x);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$z);
|
|
|
|
// Helper component
|
|
var bTabButtonHelper = {
|
|
name: 'bTabButtonHelper',
|
|
props: {
|
|
content: { type: [String, Array], default: '' },
|
|
href: { type: String, default: '#' },
|
|
posInSet: { type: Number, default: null },
|
|
setSize: { type: Number, default: null },
|
|
controls: { type: String, default: null },
|
|
id: { type: String, default: null },
|
|
active: { type: Boolean, default: false },
|
|
disabled: { type: Boolean, default: false },
|
|
linkClass: { default: null },
|
|
itemClass: { default: null },
|
|
noKeyNav: { type: Boolean, default: false }
|
|
},
|
|
render: function render(h) {
|
|
var link = h('a', {
|
|
class: ['nav-link', { active: this.active, disabled: this.disabled }, this.linkClass],
|
|
attrs: {
|
|
role: 'tab',
|
|
tabindex: this.noKeyNav ? null : '-1',
|
|
href: this.href,
|
|
id: this.id,
|
|
disabled: this.disabled,
|
|
'aria-selected': this.active ? 'true' : 'false',
|
|
'aria-setsize': this.setSize,
|
|
'aria-posinset': this.posInSet,
|
|
'aria-controls': this.controls
|
|
},
|
|
on: {
|
|
click: this.handleClick,
|
|
keydown: this.handleClick
|
|
}
|
|
}, this.content);
|
|
return h('li', { class: ['nav-item', this.itemClass], attrs: { role: 'presentation' } }, [link]);
|
|
},
|
|
|
|
methods: {
|
|
handleClick: function handleClick(evt) {
|
|
function stop() {
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
}
|
|
if (evt.type !== 'click' && this.noKeyNav) {
|
|
return;
|
|
}
|
|
if (this.disabled) {
|
|
stop();
|
|
return;
|
|
}
|
|
if (evt.type === 'click' || evt.keyCode === KeyCodes.ENTER || evt.keyCode === KeyCodes.SPACE) {
|
|
stop();
|
|
this.$emit('click', evt);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
var bTabs = {
|
|
mixins: [idMixin],
|
|
render: function render(h) {
|
|
var _this = this,
|
|
_ref;
|
|
|
|
var tabs = this.tabs;
|
|
// Navigation 'buttons'
|
|
var buttons = tabs.map(function (tab, index) {
|
|
return h(bTabButtonHelper, {
|
|
key: index,
|
|
props: {
|
|
content: tab.$slots.title || tab.title,
|
|
href: tab.href,
|
|
id: tab.controlledBy || _this.safeId('_BV_tab_' + (index + 1) + '_'),
|
|
active: tab.localActive,
|
|
disabled: tab.disabled,
|
|
setSize: tabs.length,
|
|
posInSet: index + 1,
|
|
controls: _this.safeId('_BV_tab_container_'),
|
|
linkClass: tab.titleLinkClass,
|
|
itemClass: tab.titleItemClass,
|
|
noKeyNav: _this.noKeyNav
|
|
},
|
|
on: {
|
|
click: function click(evt) {
|
|
_this.setTab(index);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// Nav 'button' wrapper
|
|
var navs = h('ul', {
|
|
class: ['nav', (_ref = {}, defineProperty(_ref, 'nav-' + this.navStyle, !this.noNavStyle), defineProperty(_ref, 'card-header-' + this.navStyle, this.card && !this.vertical), defineProperty(_ref, 'card-header', this.card && this.vertical), defineProperty(_ref, 'h-100', this.card && this.vertical), defineProperty(_ref, 'flex-column', this.vertical), defineProperty(_ref, 'border-bottom-0', this.vertical), defineProperty(_ref, 'rounded-0', this.vertical), defineProperty(_ref, 'small', this.small), _ref), this.navClass],
|
|
attrs: {
|
|
role: 'tablist',
|
|
tabindex: this.noKeyNav ? null : '0',
|
|
id: this.safeId('_BV_tab_controls_')
|
|
},
|
|
on: { keydown: this.onKeynav }
|
|
}, [buttons, this.$slots.tabs]);
|
|
navs = h('div', {
|
|
class: [{
|
|
'card-header': this.card && !this.vertical && !(this.end || this.bottom),
|
|
'card-footer': this.card && !this.vertical && (this.end || this.bottom),
|
|
'col-auto': this.vertical
|
|
}, this.navWrapperClass]
|
|
}, [navs]);
|
|
|
|
var empty = void 0;
|
|
if (tabs && tabs.length) {
|
|
empty = h(false);
|
|
} else {
|
|
empty = h('div', { class: ['tab-pane', 'active', { 'card-body': this.card }] }, this.$slots.empty);
|
|
}
|
|
|
|
// Main content section
|
|
var content = h('div', {
|
|
ref: 'tabsContainer',
|
|
class: ['tab-content', { col: this.vertical }, this.contentClass],
|
|
attrs: { id: this.safeId('_BV_tab_container_') }
|
|
}, [this.$slots.default, empty]);
|
|
|
|
// Render final output
|
|
return h(this.tag, {
|
|
class: ['tabs', { row: this.vertical, 'no-gutters': this.vertical && this.card }],
|
|
attrs: { id: this.safeId() }
|
|
}, [this.end || this.bottom ? content : h(false), [navs], this.end || this.bottom ? h(false) : content]);
|
|
},
|
|
data: function data() {
|
|
return {
|
|
currentTab: this.value,
|
|
tabs: []
|
|
};
|
|
},
|
|
|
|
props: {
|
|
tag: {
|
|
type: String,
|
|
default: 'div'
|
|
},
|
|
card: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
small: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
value: {
|
|
type: Number,
|
|
default: null
|
|
},
|
|
pills: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
vertical: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
bottom: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
end: {
|
|
// Synonym for 'bottom'
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
noFade: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
noNavStyle: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
noKeyNav: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
lazy: {
|
|
// This prop is sniffed by the tab child
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
contentClass: {
|
|
type: [String, Array, Object],
|
|
default: null
|
|
},
|
|
navClass: {
|
|
type: [String, Array, Object],
|
|
default: null
|
|
},
|
|
navWrapperClass: {
|
|
type: [String, Array, Object],
|
|
default: null
|
|
}
|
|
},
|
|
watch: {
|
|
currentTab: function currentTab(val, old) {
|
|
if (val === old) {
|
|
return;
|
|
}
|
|
this.$root.$emit('changed::tab', this, val, this.tabs[val]);
|
|
this.$emit('input', val);
|
|
this.tabs[val].$emit('click');
|
|
},
|
|
value: function value(val, old) {
|
|
if (val === old) {
|
|
return;
|
|
}
|
|
if (typeof old !== 'number') {
|
|
old = 0;
|
|
}
|
|
// Moving left or right?
|
|
var direction = val < old ? -1 : 1;
|
|
this.setTab(val, false, direction);
|
|
}
|
|
},
|
|
computed: {
|
|
fade: function fade() {
|
|
// This computed prop is sniffed by the tab child
|
|
return !this.noFade;
|
|
},
|
|
navStyle: function navStyle() {
|
|
return this.pills ? 'pills' : 'tabs';
|
|
}
|
|
},
|
|
methods: {
|
|
/**
|
|
* Util: Return the sign of a number (as -1, 0, or 1)
|
|
*/
|
|
sign: function sign(x) {
|
|
return x === 0 ? 0 : x > 0 ? 1 : -1;
|
|
},
|
|
|
|
/*
|
|
* handle keyboard navigation
|
|
*/
|
|
onKeynav: function onKeynav(evt) {
|
|
if (this.noKeyNav) {
|
|
return;
|
|
}
|
|
var key = evt.keyCode;
|
|
var shift = evt.shiftKey;
|
|
function stop() {
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
}
|
|
if (key === KeyCodes.UP || key === KeyCodes.LEFT) {
|
|
stop();
|
|
if (shift) {
|
|
this.setTab(0, false, 1);
|
|
} else {
|
|
this.previousTab();
|
|
}
|
|
} else if (key === KeyCodes.DOWN || key === KeyCodes.RIGHT) {
|
|
stop();
|
|
if (shift) {
|
|
this.setTab(this.tabs.length - 1, false, -1);
|
|
} else {
|
|
this.nextTab();
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Move to next tab
|
|
*/
|
|
nextTab: function nextTab() {
|
|
this.setTab(this.currentTab + 1, false, 1);
|
|
},
|
|
|
|
/**
|
|
* Move to previous tab
|
|
*/
|
|
previousTab: function previousTab() {
|
|
this.setTab(this.currentTab - 1, false, -1);
|
|
},
|
|
|
|
/**
|
|
* Set active tab on the tabs collection and the child 'tab' component
|
|
* Index is the tab we want to activate. Direction is the direction we are moving
|
|
* so if the tab we requested is disabled, we can skip over it.
|
|
* Force is used by updateTabs to ensure we have cleared any previous active tabs.
|
|
*/
|
|
setTab: function setTab(index, force, direction) {
|
|
var _this2 = this;
|
|
|
|
direction = this.sign(direction || 0);
|
|
index = index || 0;
|
|
// Prevent setting same tab and infinite loops!
|
|
if (!force && index === this.currentTab) {
|
|
return;
|
|
}
|
|
var tab = this.tabs[index];
|
|
// Don't go beyond indexes!
|
|
if (!tab) {
|
|
// Reset the v-model to the current Tab
|
|
this.$emit('input', this.currentTab);
|
|
return;
|
|
}
|
|
// Ignore or Skip disabled
|
|
if (tab.disabled) {
|
|
if (direction) {
|
|
// Skip to next non disabled tab in specified direction (recursive)
|
|
this.setTab(index + direction, force, direction);
|
|
}
|
|
return;
|
|
}
|
|
// Activate requested current tab, and deactivte any old tabs
|
|
this.tabs.forEach(function (t) {
|
|
if (t === tab) {
|
|
// Set new tab as active
|
|
_this2.$set(t, 'localActive', true);
|
|
} else {
|
|
// Ensure non current tabs are not active
|
|
_this2.$set(t, 'localActive', false);
|
|
}
|
|
});
|
|
// Update currentTab
|
|
this.currentTab = index;
|
|
},
|
|
|
|
/**
|
|
* Dynamically update tabs list
|
|
*/
|
|
updateTabs: function updateTabs() {
|
|
// Probe tabs
|
|
this.tabs = this.$children.filter(function (child) {
|
|
return child._isTab;
|
|
});
|
|
// Set initial active tab
|
|
var tabIndex = null;
|
|
// Find *last* active non-dsabled tab in current tabs
|
|
// We trust tab state over currentTab
|
|
this.tabs.forEach(function (tab, index) {
|
|
if (tab.localActive && !tab.disabled) {
|
|
tabIndex = index;
|
|
}
|
|
});
|
|
// Else try setting to currentTab
|
|
if (tabIndex === null) {
|
|
if (this.currentTab >= this.tabs.length) {
|
|
// Handle last tab being removed
|
|
this.setTab(this.tabs.length - 1, true, -1);
|
|
return;
|
|
} else if (this.tabs[this.currentTab] && !this.tabs[this.currentTab].disabled) {
|
|
tabIndex = this.currentTab;
|
|
}
|
|
}
|
|
// Else find *first* non-disabled tab in current tabs
|
|
if (tabIndex === null) {
|
|
this.tabs.forEach(function (tab, index) {
|
|
if (!tab.disabled && tabIndex === null) {
|
|
tabIndex = index;
|
|
}
|
|
});
|
|
}
|
|
this.setTab(tabIndex || 0, true, 0);
|
|
}
|
|
},
|
|
mounted: function mounted() {
|
|
this.updateTabs();
|
|
// Observe Child changes so we can notify tabs change
|
|
observeDOM(this.$refs.tabsContainer, this.updateTabs.bind(this), {
|
|
subtree: false
|
|
});
|
|
}
|
|
};
|
|
|
|
var bTab = {
|
|
mixins: [idMixin],
|
|
render: function render(h) {
|
|
var content = h(false);
|
|
if (this.localActive || !this.computedLazy) {
|
|
content = h(this.tag, {
|
|
ref: 'panel',
|
|
class: this.tabClasses,
|
|
directives: [{ name: 'show', value: this.localActive }],
|
|
attrs: {
|
|
role: 'tabpanel',
|
|
id: this.safeId(),
|
|
'aria-hidden': this.localActive ? 'false' : 'true',
|
|
'aria-expanded': this.localActive ? 'true' : 'false',
|
|
'aria-lablelledby': this.controlledBy || null
|
|
}
|
|
}, [this.$slots.default]);
|
|
}
|
|
return h('transition', {
|
|
props: { mode: 'out-in' },
|
|
on: {
|
|
beforeEnter: this.beforeEnter,
|
|
beforeLeave: this.beforeLeave
|
|
}
|
|
}, [content]);
|
|
},
|
|
|
|
methods: {
|
|
beforeEnter: function beforeEnter() {
|
|
var _this = this;
|
|
|
|
// change opacity 1 frame after display
|
|
// otherwise css transition won't happen
|
|
window.requestAnimationFrame(function () {
|
|
_this.show = true;
|
|
});
|
|
},
|
|
beforeLeave: function beforeLeave() {
|
|
this.show = false;
|
|
}
|
|
},
|
|
data: function data() {
|
|
return {
|
|
localActive: this.active && !this.disabled,
|
|
show: false
|
|
};
|
|
},
|
|
mounted: function mounted() {
|
|
this.show = this.localActive;
|
|
},
|
|
|
|
computed: {
|
|
tabClasses: function tabClasses() {
|
|
return ['tab-pane', this.$parent && this.$parent.card && !this.noBody ? 'card-body' : '', this.show ? 'show' : '', this.computedFade ? 'fade' : '', this.disabled ? 'disabled' : '', this.localActive ? 'active' : ''];
|
|
},
|
|
controlledBy: function controlledBy() {
|
|
return this.buttonId || this.safeId('__BV_tab_button__');
|
|
},
|
|
computedFade: function computedFade() {
|
|
return this.$parent.fade;
|
|
},
|
|
computedLazy: function computedLazy() {
|
|
return this.$parent.lazy;
|
|
},
|
|
_isTab: function _isTab() {
|
|
// For parent sniffing of child
|
|
return true;
|
|
}
|
|
},
|
|
props: {
|
|
active: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
tag: {
|
|
type: String,
|
|
default: 'div'
|
|
},
|
|
buttonId: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
title: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
titleItemClass: {
|
|
// Sniffed by tabs.vue and added to nav 'li.nav-item'
|
|
type: [String, Array, Object],
|
|
default: null
|
|
},
|
|
titleLinkClass: {
|
|
// Sniffed by tabs.vue and added to nav 'a.nav-link'
|
|
type: [String, Array, Object],
|
|
default: null
|
|
},
|
|
headHtml: {
|
|
// Is this actually ever used?
|
|
type: String,
|
|
default: null
|
|
},
|
|
disabled: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
noBody: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
href: {
|
|
type: String,
|
|
default: '#'
|
|
}
|
|
}
|
|
};
|
|
|
|
var components$y = {
|
|
bTabs: bTabs,
|
|
bTab: bTab
|
|
};
|
|
|
|
var VuePlugin$A = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$y);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$A);
|
|
|
|
var bTooltip = {
|
|
mixins: [toolpopMixin],
|
|
render: function render(h) {
|
|
return h('div', { class: ['d-none'], style: { display: 'none' }, attrs: { 'aria-hidden': true } }, [h('div', { ref: 'title' }, this.$slots.default)]);
|
|
},
|
|
data: function data() {
|
|
return {};
|
|
},
|
|
|
|
props: {
|
|
title: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
triggers: {
|
|
type: [String, Array],
|
|
default: 'hover focus'
|
|
},
|
|
placement: {
|
|
type: String,
|
|
default: 'top'
|
|
}
|
|
},
|
|
methods: {
|
|
createToolpop: function createToolpop() {
|
|
// getTarget is in toolpop mixin
|
|
var target = this.getTarget();
|
|
if (target) {
|
|
this._toolpop = new ToolTip(target, this.getConfig(), this.$root);
|
|
} else {
|
|
this._toolpop = null;
|
|
warn("b-tooltip: 'target' element not found!");
|
|
}
|
|
return this._toolpop;
|
|
}
|
|
}
|
|
};
|
|
|
|
var components$z = {
|
|
bTooltip: bTooltip
|
|
};
|
|
|
|
var VuePlugin$B = {
|
|
install: function install(Vue) {
|
|
registerComponents(Vue, components$z);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$B);
|
|
|
|
|
|
|
|
var components$A = /*#__PURE__*/Object.freeze({
|
|
Alert: VuePlugin,
|
|
Badge: VuePlugin$1,
|
|
Breadcrumb: VuePlugin$2,
|
|
Button: VuePlugin$3,
|
|
ButtonToolbar: VuePlugin$5,
|
|
ButtonGroup: VuePlugin$4,
|
|
Card: VuePlugin$7,
|
|
Carousel: VuePlugin$8,
|
|
Collapse: VuePlugin$b,
|
|
Dropdown: VuePlugin$c,
|
|
Embed: VuePlugin$d,
|
|
Form: VuePlugin$e,
|
|
FormGroup: VuePlugin$f,
|
|
FormInput: VuePlugin$i,
|
|
FormTextarea: VuePlugin$j,
|
|
FormFile: VuePlugin$k,
|
|
FormCheckbox: VuePlugin$g,
|
|
FormRadio: VuePlugin$h,
|
|
FormSelect: VuePlugin$l,
|
|
Image: VuePlugin$m,
|
|
InputGroup: VuePlugin$6,
|
|
Jumbotron: VuePlugin$n,
|
|
Layout: VuePlugin$9,
|
|
Link: VuePlugin$o,
|
|
ListGroup: VuePlugin$p,
|
|
Media: VuePlugin$q,
|
|
Modal: VuePlugin$s,
|
|
Nav: VuePlugin$t,
|
|
Navbar: VuePlugin$u,
|
|
Pagination: VuePlugin$v,
|
|
PaginationNav: VuePlugin$w,
|
|
Popover: VuePlugin$x,
|
|
Progress: VuePlugin$y,
|
|
Table: VuePlugin$z,
|
|
Tabs: VuePlugin$A,
|
|
Tooltip: VuePlugin$B
|
|
});
|
|
|
|
/*
|
|
* ScrollSpy class definition
|
|
*/
|
|
|
|
/*
|
|
* Constants / Defaults
|
|
*/
|
|
|
|
var NAME$2 = 'v-b-scrollspy';
|
|
var ACTIVATE_EVENT = 'bv::scrollspy::activate';
|
|
|
|
var Default = {
|
|
element: 'body',
|
|
offset: 10,
|
|
method: 'auto',
|
|
throttle: 75
|
|
};
|
|
|
|
var DefaultType = {
|
|
element: '(string|element|component)',
|
|
offset: 'number',
|
|
method: 'string',
|
|
throttle: 'number'
|
|
};
|
|
|
|
var ClassName$2 = {
|
|
DROPDOWN_ITEM: 'dropdown-item',
|
|
ACTIVE: 'active'
|
|
};
|
|
|
|
var Selector$3 = {
|
|
ACTIVE: '.active',
|
|
NAV_LIST_GROUP: '.nav, .list-group',
|
|
NAV_LINKS: '.nav-link',
|
|
NAV_ITEMS: '.nav-item',
|
|
LIST_ITEMS: '.list-group-item',
|
|
DROPDOWN: '.dropdown, .dropup',
|
|
DROPDOWN_ITEMS: '.dropdown-item',
|
|
DROPDOWN_TOGGLE: '.dropdown-toggle'
|
|
};
|
|
|
|
var OffsetMethod = {
|
|
OFFSET: 'offset',
|
|
POSITION: 'position'
|
|
|
|
// HREFs must start with # but can be === '#', or start with '#/' or '#!' (which can be router links)
|
|
};var HREF_REGEX = /^#[^/!]+/;
|
|
|
|
// Transition Events
|
|
var TransitionEndEvents$2 = ['webkitTransitionEnd', 'transitionend', 'otransitionend', 'oTransitionEnd'];
|
|
|
|
/*
|
|
* Utility Methods
|
|
*/
|
|
|
|
// Better var type detection
|
|
/* istanbul ignore next: not easy to test */
|
|
function toType(obj) {
|
|
return {}.toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
|
|
}
|
|
|
|
// Check config properties for expected types
|
|
/* istanbul ignore next: not easy to test */
|
|
function typeCheckConfig(componentName, config, configTypes) {
|
|
for (var property in configTypes) {
|
|
if (Object.prototype.hasOwnProperty.call(configTypes, property)) {
|
|
var expectedTypes = configTypes[property];
|
|
var value = config[property];
|
|
var valueType = value && isElement(value) ? 'element' : toType(value);
|
|
// handle Vue instances
|
|
valueType = value && value._isVue ? 'component' : valueType;
|
|
|
|
if (!new RegExp(expectedTypes).test(valueType)) {
|
|
warn(componentName + ': Option "' + property + '" provided type "' + valueType + '", but expected type "' + expectedTypes + '"');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ------------------------------------------------------------------------
|
|
* Class Definition
|
|
* ------------------------------------------------------------------------
|
|
*/
|
|
|
|
/* istanbul ignore next: not easy to test */
|
|
|
|
var ScrollSpy = function () {
|
|
function ScrollSpy(element, config, $root) {
|
|
classCallCheck(this, ScrollSpy);
|
|
|
|
// The element we activate links in
|
|
this.$el = element;
|
|
this.$scroller = null;
|
|
this.$selector = [Selector$3.NAV_LINKS, Selector$3.LIST_ITEMS, Selector$3.DROPDOWN_ITEMS].join(',');
|
|
this.$offsets = [];
|
|
this.$targets = [];
|
|
this.$activeTarget = null;
|
|
this.$scrollHeight = 0;
|
|
this.$resizeTimeout = null;
|
|
this.$obs_scroller = null;
|
|
this.$obs_targets = null;
|
|
this.$root = $root || null;
|
|
this.$config = null;
|
|
|
|
this.updateConfig(config);
|
|
}
|
|
|
|
createClass(ScrollSpy, [{
|
|
key: 'updateConfig',
|
|
value: function updateConfig(config, $root) {
|
|
if (this.$scroller) {
|
|
// Just in case out scroll element has changed
|
|
this.unlisten();
|
|
this.$scroller = null;
|
|
}
|
|
var cfg = assign({}, this.constructor.Default, config);
|
|
if ($root) {
|
|
this.$root = $root;
|
|
}
|
|
typeCheckConfig(this.constructor.Name, cfg, this.constructor.DefaultType);
|
|
this.$config = cfg;
|
|
|
|
if (this.$root) {
|
|
var self = this;
|
|
this.$root.$nextTick(function () {
|
|
self.listen();
|
|
});
|
|
} else {
|
|
this.listen();
|
|
}
|
|
}
|
|
}, {
|
|
key: 'dispose',
|
|
value: function dispose() {
|
|
this.unlisten();
|
|
clearTimeout(this.$resizeTimeout);
|
|
this.$resizeTimeout = null;
|
|
this.$el = null;
|
|
this.$config = null;
|
|
this.$scroller = null;
|
|
this.$selector = null;
|
|
this.$offsets = null;
|
|
this.$targets = null;
|
|
this.$activeTarget = null;
|
|
this.$scrollHeight = null;
|
|
}
|
|
}, {
|
|
key: 'listen',
|
|
value: function listen() {
|
|
var _this = this;
|
|
|
|
var scroller = this.getScroller();
|
|
if (scroller && scroller.tagName !== 'BODY') {
|
|
eventOn(scroller, 'scroll', this);
|
|
}
|
|
eventOn(window, 'scroll', this);
|
|
eventOn(window, 'resize', this);
|
|
eventOn(window, 'orientationchange', this);
|
|
TransitionEndEvents$2.forEach(function (evtName) {
|
|
eventOn(window, evtName, _this);
|
|
});
|
|
this.setObservers(true);
|
|
// Scedule a refresh
|
|
this.handleEvent('refresh');
|
|
}
|
|
}, {
|
|
key: 'unlisten',
|
|
value: function unlisten() {
|
|
var _this2 = this;
|
|
|
|
var scroller = this.getScroller();
|
|
this.setObservers(false);
|
|
if (scroller && scroller.tagName !== 'BODY') {
|
|
eventOff(scroller, 'scroll', this);
|
|
}
|
|
eventOff(window, 'scroll', this);
|
|
eventOff(window, 'resize', this);
|
|
eventOff(window, 'orientationchange', this);
|
|
TransitionEndEvents$2.forEach(function (evtName) {
|
|
eventOff(window, evtName, _this2);
|
|
});
|
|
}
|
|
}, {
|
|
key: 'setObservers',
|
|
value: function setObservers(on) {
|
|
var _this3 = this;
|
|
|
|
// We observe both the scroller for content changes, and the target links
|
|
if (this.$obs_scroller) {
|
|
this.$obs_scroller.disconnect();
|
|
this.$obs_scroller = null;
|
|
}
|
|
if (this.$obs_targets) {
|
|
this.$obs_targets.disconnect();
|
|
this.$obs_targets = null;
|
|
}
|
|
if (on) {
|
|
this.$obs_targets = observeDOM(this.$el, function () {
|
|
_this3.handleEvent('mutation');
|
|
}, {
|
|
subtree: true,
|
|
childList: true,
|
|
attributes: true,
|
|
attributeFilter: ['href']
|
|
});
|
|
this.$obs_scroller = observeDOM(this.getScroller(), function () {
|
|
_this3.handleEvent('mutation');
|
|
}, {
|
|
subtree: true,
|
|
childList: true,
|
|
characterData: true,
|
|
attributes: true,
|
|
attributeFilter: ['id', 'style', 'class']
|
|
});
|
|
}
|
|
}
|
|
|
|
// general event handler
|
|
|
|
}, {
|
|
key: 'handleEvent',
|
|
value: function handleEvent(evt) {
|
|
var type = typeof evt === 'string' ? evt : evt.type;
|
|
|
|
var self = this;
|
|
function resizeThrottle() {
|
|
if (!self.$resizeTimeout) {
|
|
self.$resizeTimeout = setTimeout(function () {
|
|
self.refresh();
|
|
self.process();
|
|
self.$resizeTimeout = null;
|
|
}, self.$config.throttle);
|
|
}
|
|
}
|
|
|
|
if (type === 'scroll') {
|
|
if (!this.$obs_scroller) {
|
|
// Just in case we are added to the DOM before the scroll target is
|
|
// We re-instantiate our listeners, just in case
|
|
this.listen();
|
|
}
|
|
this.process();
|
|
} else if (/(resize|orientationchange|mutation|refresh)/.test(type)) {
|
|
// Postpone these events by throttle time
|
|
resizeThrottle();
|
|
}
|
|
}
|
|
|
|
// Refresh the list of target links on the element we are applied to
|
|
|
|
}, {
|
|
key: 'refresh',
|
|
value: function refresh() {
|
|
var _this4 = this;
|
|
|
|
var scroller = this.getScroller();
|
|
if (!scroller) {
|
|
return;
|
|
}
|
|
var autoMethod = scroller !== scroller.window ? OffsetMethod.POSITION : OffsetMethod.OFFSET;
|
|
var method = this.$config.method === 'auto' ? autoMethod : this.$config.method;
|
|
var methodFn = method === OffsetMethod.POSITION ? position : offset;
|
|
var offsetBase = method === OffsetMethod.POSITION ? this.getScrollTop() : 0;
|
|
|
|
this.$offsets = [];
|
|
this.$targets = [];
|
|
|
|
this.$scrollHeight = this.getScrollHeight();
|
|
|
|
// Find all the unique link href's
|
|
selectAll(this.$selector, this.$el).map(function (link) {
|
|
return getAttr(link, 'href');
|
|
}).filter(function (href) {
|
|
return HREF_REGEX.test(href || '');
|
|
}).map(function (href) {
|
|
var el = select(href, scroller);
|
|
if (isVisible(el)) {
|
|
return {
|
|
offset: parseInt(methodFn(el).top, 10) + offsetBase,
|
|
target: href
|
|
};
|
|
}
|
|
return null;
|
|
}).filter(function (item) {
|
|
return item;
|
|
}).sort(function (a, b) {
|
|
return a.offset - b.offset;
|
|
}).reduce(function (memo, item) {
|
|
// record only unique targets/offfsets
|
|
if (!memo[item.target]) {
|
|
_this4.$offsets.push(item.offset);
|
|
_this4.$targets.push(item.target);
|
|
memo[item.target] = true;
|
|
}
|
|
return memo;
|
|
}, {});
|
|
|
|
return this;
|
|
}
|
|
|
|
// Handle activating/clearing
|
|
|
|
}, {
|
|
key: 'process',
|
|
value: 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]);
|
|
}
|
|
}
|
|
}
|
|
}, {
|
|
key: 'getScroller',
|
|
value: function getScroller() {
|
|
if (this.$scroller) {
|
|
return this.$scroller;
|
|
}
|
|
var scroller = this.$config.element;
|
|
if (!scroller) {
|
|
return null;
|
|
} else if (isElement(scroller.$el)) {
|
|
scroller = scroller.$el;
|
|
} else if (typeof scroller === 'string') {
|
|
scroller = select(scroller);
|
|
}
|
|
if (!scroller) {
|
|
return null;
|
|
}
|
|
this.$scroller = scroller.tagName === 'BODY' ? window : scroller;
|
|
return this.$scroller;
|
|
}
|
|
}, {
|
|
key: 'getScrollTop',
|
|
value: function getScrollTop() {
|
|
var scroller = this.getScroller();
|
|
return scroller === window ? scroller.pageYOffset : scroller.scrollTop;
|
|
}
|
|
}, {
|
|
key: 'getScrollHeight',
|
|
value: function getScrollHeight() {
|
|
return this.getScroller().scrollHeight || Math.max(document.body.scrollHeight, document.documentElement.scrollHeight);
|
|
}
|
|
}, {
|
|
key: 'getOffsetHeight',
|
|
value: function getOffsetHeight() {
|
|
var scroller = this.getScroller();
|
|
return scroller === window ? window.innerHeight : getBCR(scroller).height;
|
|
}
|
|
}, {
|
|
key: 'activate',
|
|
value: function activate(target) {
|
|
var _this5 = this;
|
|
|
|
this.$activeTarget = target;
|
|
this.clear();
|
|
|
|
// Grab the list of target links (<a href="{$target}">)
|
|
var links = selectAll(this.$selector.split(',').map(function (selector) {
|
|
return selector + '[href="' + target + '"]';
|
|
}).join(','), this.$el);
|
|
|
|
links.forEach(function (link) {
|
|
if (hasClass(link, ClassName$2.DROPDOWN_ITEM)) {
|
|
// This is a dropdown item, so find the .dropdown-toggle and set it's state
|
|
var dropdown = closest(Selector$3.DROPDOWN, link);
|
|
if (dropdown) {
|
|
_this5.setActiveState(select(Selector$3.DROPDOWN_TOGGLE, dropdown), true);
|
|
}
|
|
// Also set this link's state
|
|
_this5.setActiveState(link, true);
|
|
} else {
|
|
// Set triggered link as active
|
|
_this5.setActiveState(link, true);
|
|
if (matches(link.parentElement, Selector$3.NAV_ITEMS)) {
|
|
// Handle nav-link inside nav-item, and set nav-item active
|
|
_this5.setActiveState(link.parentElement, true);
|
|
}
|
|
// Set triggered links parents as active
|
|
// With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor
|
|
var el = link;
|
|
while (el) {
|
|
el = closest(Selector$3.NAV_LIST_GROUP, el);
|
|
var sibling = el ? el.previousElementSibling : null;
|
|
if (matches(sibling, Selector$3.NAV_LINKS + ', ' + Selector$3.LIST_ITEMS)) {
|
|
_this5.setActiveState(sibling, true);
|
|
}
|
|
// Handle special case where nav-link is inside a nav-item
|
|
if (matches(sibling, Selector$3.NAV_ITEMS)) {
|
|
_this5.setActiveState(select(Selector$3.NAV_LINKS, sibling), true);
|
|
// Add active state to nav-item as well
|
|
_this5.setActiveState(sibling, true);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Signal event to via $root, passing ID of activaed target and reference to array of links
|
|
if (links && links.length > 0 && this.$root) {
|
|
this.$root.$emit(ACTIVATE_EVENT, target, links);
|
|
}
|
|
}
|
|
}, {
|
|
key: 'clear',
|
|
value: function clear() {
|
|
var _this6 = this;
|
|
|
|
selectAll(this.$selector + ', ' + Selector$3.NAV_ITEMS, this.$el).filter(function (el) {
|
|
return hasClass(el, ClassName$2.ACTIVE);
|
|
}).forEach(function (el) {
|
|
return _this6.setActiveState(el, false);
|
|
});
|
|
}
|
|
}, {
|
|
key: 'setActiveState',
|
|
value: function setActiveState(el, active) {
|
|
if (!el) {
|
|
return;
|
|
}
|
|
if (active) {
|
|
addClass(el, ClassName$2.ACTIVE);
|
|
} else {
|
|
removeClass(el, ClassName$2.ACTIVE);
|
|
}
|
|
}
|
|
}], [{
|
|
key: 'Name',
|
|
get: function get$$1() {
|
|
return NAME$2;
|
|
}
|
|
}, {
|
|
key: 'Default',
|
|
get: function get$$1() {
|
|
return Default;
|
|
}
|
|
}, {
|
|
key: 'DefaultType',
|
|
get: function get$$1() {
|
|
return DefaultType;
|
|
}
|
|
}]);
|
|
return ScrollSpy;
|
|
}();
|
|
|
|
/*
|
|
* ScrollSpy directive v-b-scrollspy
|
|
*/
|
|
|
|
var inBrowser$1 = typeof window !== 'undefined';
|
|
var isServer = !inBrowser$1;
|
|
|
|
// Key we use to store our Instance
|
|
var BVSS = '__BV_ScrollSpy__';
|
|
|
|
// Generate config from bindings
|
|
/* istanbul ignore next: not easy to test */
|
|
function makeConfig(binding) {
|
|
var config = {};
|
|
|
|
// If Argument, assume element ID
|
|
if (binding.arg) {
|
|
// Element ID specified as arg. We must pre-pend #
|
|
config.element = '#' + binding.arg;
|
|
}
|
|
|
|
// Process modifiers
|
|
keys(binding.modifiers).forEach(function (mod) {
|
|
if (/^\d+$/.test(mod)) {
|
|
// Offest value
|
|
config.offset = parseInt(mod, 10);
|
|
} else if (/^(auto|position|offset)$/.test(mod)) {
|
|
// Offset method
|
|
config.method = mod;
|
|
}
|
|
});
|
|
|
|
// Process value
|
|
if (typeof binding.value === 'string') {
|
|
// Value is a CSS ID or selector
|
|
config.element = binding.value;
|
|
} else if (typeof binding.value === 'number') {
|
|
// Value is offset
|
|
config.offset = Math.round(binding.value);
|
|
} else if (_typeof(binding.value) === 'object') {
|
|
// Value is config object
|
|
// Filter the object based on our supported config options
|
|
keys(binding.value).filter(function (k) {
|
|
return Boolean(ScrollSpy.DefaultType[k]);
|
|
}).forEach(function (k) {
|
|
config[k] = binding.value[k];
|
|
});
|
|
}
|
|
|
|
return config;
|
|
}
|
|
|
|
/* istanbul ignore next: not easy to test */
|
|
function addBVSS(el, binding, vnode) {
|
|
if (isServer) {
|
|
return;
|
|
}
|
|
var cfg = makeConfig(binding);
|
|
if (!el[BVSS]) {
|
|
el[BVSS] = new ScrollSpy(el, cfg, vnode.context.$root);
|
|
} else {
|
|
el[BVSS].updateConfig(cfg, vnode.context.$root);
|
|
}
|
|
return el[BVSS];
|
|
}
|
|
|
|
/* istanbul ignore next: not easy to test */
|
|
function removeBVSS(el) {
|
|
if (el[BVSS]) {
|
|
el[BVSS].dispose();
|
|
el[BVSS] = null;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Export our directive
|
|
*/
|
|
|
|
/* istanbul ignore next: not easy to test */
|
|
var bScrollspy = {
|
|
bind: function bind(el, binding, vnode) {
|
|
addBVSS(el, binding, vnode);
|
|
},
|
|
inserted: function inserted(el, binding, vnode) {
|
|
addBVSS(el, binding, vnode);
|
|
},
|
|
update: function update(el, binding, vnode) {
|
|
addBVSS(el, binding, vnode);
|
|
},
|
|
componentUpdated: function componentUpdated(el, binding, vnode) {
|
|
addBVSS(el, binding, vnode);
|
|
},
|
|
unbind: function unbind(el) {
|
|
if (isServer) {
|
|
return;
|
|
}
|
|
// Remove scroll event listener on scrollElId
|
|
removeBVSS(el);
|
|
}
|
|
};
|
|
|
|
var directives$2 = {
|
|
bScrollspy: bScrollspy
|
|
};
|
|
|
|
var VuePlugin$C = {
|
|
install: function install(Vue) {
|
|
registerDirectives(Vue, directives$2);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$C);
|
|
|
|
var inBrowser$2 = typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
|
|
// Key which we use to store tooltip object on element
|
|
var BVTT = '__BV_ToolTip__';
|
|
|
|
// Valid event triggers
|
|
var validTriggers = {
|
|
'focus': true,
|
|
'hover': true,
|
|
'click': true,
|
|
'blur': true
|
|
|
|
// Build a ToolTip config based on bindings (if any)
|
|
// Arguments and modifiers take precedence over passed value config object
|
|
/* istanbul ignore next: not easy to test */
|
|
};function parseBindings(bindings) {
|
|
// We start out with a blank config
|
|
var config = {};
|
|
|
|
// Process bindings.value
|
|
if (typeof bindings.value === 'string') {
|
|
// Value is tooltip content (html optionally supported)
|
|
config.title = bindings.value;
|
|
} else if (typeof bindings.value === 'function') {
|
|
// Title generator function
|
|
config.title = bindings.value;
|
|
} else if (_typeof(bindings.value) === 'object') {
|
|
// Value is config object, so merge
|
|
config = assign(bindings.value);
|
|
}
|
|
|
|
// If Argument, assume element ID of container element
|
|
if (bindings.arg) {
|
|
// Element ID specified as arg. We must prepend '#' to become a CSS selector
|
|
config.container = '#' + bindings.arg;
|
|
}
|
|
|
|
// Process modifiers
|
|
keys(bindings.modifiers).forEach(function (mod) {
|
|
if (/^html$/.test(mod)) {
|
|
// Title allows HTML
|
|
config.html = true;
|
|
} else if (/^nofade$/.test(mod)) {
|
|
// no animation
|
|
config.animation = false;
|
|
} else if (/^(auto|top(left|right)?|bottom(left|right)?|left(top|bottom)?|right(top|bottom)?)$/.test(mod)) {
|
|
// placement of tooltip
|
|
config.placement = mod;
|
|
} else if (/^(window|viewport)$/.test(mod)) {
|
|
// bounday of tooltip
|
|
config.boundary = mod;
|
|
} else if (/^d\d+$/.test(mod)) {
|
|
// delay value
|
|
var delay = parseInt(mod.slice(1), 10) || 0;
|
|
if (delay) {
|
|
config.delay = delay;
|
|
}
|
|
} else if (/^o-?\d+$/.test(mod)) {
|
|
// offset value. Negative allowed
|
|
var offset = parseInt(mod.slice(1), 10) || 0;
|
|
if (offset) {
|
|
config.offset = offset;
|
|
}
|
|
}
|
|
});
|
|
|
|
// Special handling of event trigger modifiers Trigger is a space separated list
|
|
var selectedTriggers = {};
|
|
|
|
// parse current config object trigger
|
|
var triggers = typeof config.trigger === 'string' ? config.trigger.trim().split(/\s+/) : [];
|
|
triggers.forEach(function (trigger) {
|
|
if (validTriggers[trigger]) {
|
|
selectedTriggers[trigger] = true;
|
|
}
|
|
});
|
|
|
|
// Parse Modifiers for triggers
|
|
keys(validTriggers).forEach(function (trigger) {
|
|
if (bindings.modifiers[trigger]) {
|
|
selectedTriggers[trigger] = true;
|
|
}
|
|
});
|
|
|
|
// Sanitize triggers
|
|
config.trigger = keys(selectedTriggers).join(' ');
|
|
if (config.trigger === 'blur') {
|
|
// Blur by itself is useless, so convert it to 'focus'
|
|
config.trigger = 'focus';
|
|
}
|
|
if (!config.trigger) {
|
|
// remove trigger config
|
|
delete config.trigger;
|
|
}
|
|
|
|
return config;
|
|
}
|
|
|
|
//
|
|
// Add or Update tooltip on our element
|
|
//
|
|
/* istanbul ignore next: not easy to test */
|
|
function applyBVTT(el, bindings, vnode) {
|
|
if (!inBrowser$2) {
|
|
return;
|
|
}
|
|
if (!Popper) {
|
|
// Popper is required for tooltips to work
|
|
warn('v-b-tooltip: Popper.js is required for tooltips to work');
|
|
return;
|
|
}
|
|
if (el[BVTT]) {
|
|
el[BVTT].updateConfig(parseBindings(bindings));
|
|
} else {
|
|
el[BVTT] = new ToolTip(el, parseBindings(bindings), vnode.context.$root);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Remove tooltip on our element
|
|
//
|
|
/* istanbul ignore next: not easy to test */
|
|
function removeBVTT(el) {
|
|
if (!inBrowser$2) {
|
|
return;
|
|
}
|
|
if (el[BVTT]) {
|
|
el[BVTT].destroy();
|
|
el[BVTT] = null;
|
|
delete el[BVTT];
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Export our directive
|
|
*/
|
|
/* istanbul ignore next: not easy to test */
|
|
var bTooltip$1 = {
|
|
bind: function bind(el, bindings, vnode) {
|
|
applyBVTT(el, bindings, vnode);
|
|
},
|
|
inserted: function inserted(el, bindings, vnode) {
|
|
applyBVTT(el, bindings, vnode);
|
|
},
|
|
update: function update(el, bindings, vnode) {
|
|
if (bindings.value !== bindings.oldValue) {
|
|
applyBVTT(el, bindings, vnode);
|
|
}
|
|
},
|
|
componentUpdated: function componentUpdated(el, bindings, vnode) {
|
|
if (bindings.value !== bindings.oldValue) {
|
|
applyBVTT(el, bindings, vnode);
|
|
}
|
|
},
|
|
unbind: function unbind(el) {
|
|
removeBVTT(el);
|
|
}
|
|
};
|
|
|
|
var directives$3 = {
|
|
bTooltip: bTooltip$1
|
|
};
|
|
|
|
var VuePlugin$D = {
|
|
install: function install(Vue) {
|
|
registerDirectives(Vue, directives$3);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$D);
|
|
|
|
var inBrowser$3 = typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
|
|
// Key which we use to store tooltip object on element
|
|
var BVPO = '__BV_PopOver__';
|
|
|
|
// Valid event triggers
|
|
var validTriggers$1 = {
|
|
'focus': true,
|
|
'hover': true,
|
|
'click': true,
|
|
'blur': true
|
|
|
|
// Build a PopOver config based on bindings (if any)
|
|
// Arguments and modifiers take precedence over pased value config object
|
|
/* istanbul ignore next: not easy to test */
|
|
};function parseBindings$1(bindings) {
|
|
// We start out with a blank config
|
|
var config = {};
|
|
|
|
// Process bindings.value
|
|
if (typeof bindings.value === 'string') {
|
|
// Value is popover content (html optionally supported)
|
|
config.content = bindings.value;
|
|
} else if (typeof bindings.value === 'function') {
|
|
// Content generator function
|
|
config.content = bindings.value;
|
|
} else if (_typeof(bindings.value) === 'object') {
|
|
// Value is config object, so merge
|
|
config = assign(bindings.value);
|
|
}
|
|
|
|
// If Argument, assume element ID of container element
|
|
if (bindings.arg) {
|
|
// Element ID specified as arg. We must prepend '#' to become a CSS selector
|
|
config.container = '#' + bindings.arg;
|
|
}
|
|
|
|
// Process modifiers
|
|
keys(bindings.modifiers).forEach(function (mod) {
|
|
if (/^html$/.test(mod)) {
|
|
// Title allows HTML
|
|
config.html = true;
|
|
} else if (/^nofade$/.test(mod)) {
|
|
// no animation
|
|
config.animation = false;
|
|
} else if (/^(auto|top(left|right)?|bottom(left|right)?|left(top|bottom)?|right(top|bottom)?)$/.test(mod)) {
|
|
// placement of popover
|
|
config.placement = mod;
|
|
} else if (/^(window|viewport)$/.test(mod)) {
|
|
// bounday of popover
|
|
config.boundary = mod;
|
|
} else if (/^d\d+$/.test(mod)) {
|
|
// delay value
|
|
var delay = parseInt(mod.slice(1), 10) || 0;
|
|
if (delay) {
|
|
config.delay = delay;
|
|
}
|
|
} else if (/^o-?\d+$/.test(mod)) {
|
|
// offset value (negative allowed)
|
|
var offset = parseInt(mod.slice(1), 10) || 0;
|
|
if (offset) {
|
|
config.offset = offset;
|
|
}
|
|
}
|
|
});
|
|
|
|
// Special handling of event trigger modifiers Trigger is a space separated list
|
|
var selectedTriggers = {};
|
|
|
|
// parse current config object trigger
|
|
var triggers = typeof config.trigger === 'string' ? config.trigger.trim().split(/\s+/) : [];
|
|
triggers.forEach(function (trigger) {
|
|
if (validTriggers$1[trigger]) {
|
|
selectedTriggers[trigger] = true;
|
|
}
|
|
});
|
|
|
|
// Parse Modifiers for triggers
|
|
keys(validTriggers$1).forEach(function (trigger) {
|
|
if (bindings.modifiers[trigger]) {
|
|
selectedTriggers[trigger] = true;
|
|
}
|
|
});
|
|
|
|
// Sanitize triggers
|
|
config.trigger = keys(selectedTriggers).join(' ');
|
|
if (config.trigger === 'blur') {
|
|
// Blur by itself is useless, so convert it to focus
|
|
config.trigger = 'focus';
|
|
}
|
|
if (!config.trigger) {
|
|
// remove trigger config
|
|
delete config.trigger;
|
|
}
|
|
|
|
return config;
|
|
}
|
|
|
|
//
|
|
// Add or Update popover on our element
|
|
//
|
|
/* istanbul ignore next: not easy to test */
|
|
function applyBVPO(el, bindings, vnode) {
|
|
if (!inBrowser$3) {
|
|
return;
|
|
}
|
|
if (!Popper) {
|
|
// Popper is required for tooltips to work
|
|
warn('v-b-popover: Popper.js is required for popovers to work');
|
|
return;
|
|
}
|
|
if (el[BVPO]) {
|
|
el[BVPO].updateConfig(parseBindings$1(bindings));
|
|
} else {
|
|
el[BVPO] = new PopOver(el, parseBindings$1(bindings), vnode.context.$root);
|
|
}
|
|
}
|
|
//
|
|
// Remove popover on our element
|
|
//
|
|
/* istanbul ignore next */
|
|
function removeBVPO(el) {
|
|
if (!inBrowser$3) {
|
|
return;
|
|
}
|
|
if (el[BVPO]) {
|
|
el[BVPO].destroy();
|
|
el[BVPO] = null;
|
|
delete el[BVPO];
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Export our directive
|
|
*/
|
|
/* istanbul ignore next: not easy to test */
|
|
var bPopover$1 = {
|
|
bind: function bind(el, bindings, vnode) {
|
|
applyBVPO(el, bindings, vnode);
|
|
},
|
|
inserted: function inserted(el, bindings, vnode) {
|
|
applyBVPO(el, bindings, vnode);
|
|
},
|
|
update: function update(el, bindings, vnode) {
|
|
if (bindings.value !== bindings.oldValue) {
|
|
applyBVPO(el, bindings, vnode);
|
|
}
|
|
},
|
|
componentUpdated: function componentUpdated(el, bindings, vnode) {
|
|
if (bindings.value !== bindings.oldValue) {
|
|
applyBVPO(el, bindings, vnode);
|
|
}
|
|
},
|
|
unbind: function unbind(el) {
|
|
removeBVPO(el);
|
|
}
|
|
};
|
|
|
|
var directives$4 = {
|
|
bPopover: bPopover$1
|
|
};
|
|
|
|
var VuePlugin$E = {
|
|
install: function install(Vue) {
|
|
registerDirectives(Vue, directives$4);
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$E);
|
|
|
|
|
|
|
|
var directives$5 = /*#__PURE__*/Object.freeze({
|
|
Toggle: VuePlugin$a,
|
|
Modal: VuePlugin$r,
|
|
Scrollspy: VuePlugin$C,
|
|
Tooltip: VuePlugin$D,
|
|
Popover: VuePlugin$E
|
|
});
|
|
|
|
var VuePlugin$F = {
|
|
install: function install(Vue) {
|
|
if (Vue._bootstrap_vue_installed) {
|
|
return;
|
|
}
|
|
|
|
Vue._bootstrap_vue_installed = true;
|
|
|
|
// Register component plugins
|
|
for (var plugin in components$A) {
|
|
Vue.use(components$A[plugin]);
|
|
}
|
|
|
|
// Register directive plugins
|
|
for (var _plugin in directives$5) {
|
|
Vue.use(directives$5[_plugin]);
|
|
}
|
|
}
|
|
};
|
|
|
|
vueUse(VuePlugin$F);
|
|
|
|
return VuePlugin$F;
|
|
|
|
})));
|