Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

32712 lines
1.0 MiB

/*!
* BootstrapVue 2.19.0
*
* @link https://bootstrap-vue.org
* @source https://github.com/bootstrap-vue/bootstrap-vue
* @copyright (c) 2016-2020 BootstrapVue
* @license MIT
* https://github.com/bootstrap-vue/bootstrap-vue/blob/master/LICENSE
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('vue')) :
typeof define === 'function' && define.amd ? define(['vue'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.bootstrapVue = factory(global.Vue));
}(this, (function (Vue) { 'use strict';
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var Vue__default = /*#__PURE__*/_interopDefaultLegacy(Vue);
function _typeof(obj) {
"@babel/helpers - typeof";
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
_typeof = function (obj) {
return typeof obj;
};
} else {
_typeof = function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
}
return _typeof(obj);
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a 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);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function ownKeys(object, enumerableOnly) {
var keys = Object.keys(object);
if (Object.getOwnPropertySymbols) {
var symbols = Object.getOwnPropertySymbols(object);
if (enumerableOnly) symbols = symbols.filter(function (sym) {
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
});
keys.push.apply(keys, symbols);
}
return keys;
}
function _objectSpread2(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? arguments[i] : {};
if (i % 2) {
ownKeys(Object(source), true).forEach(function (key) {
_defineProperty(target, key, source[key]);
});
} else if (Object.getOwnPropertyDescriptors) {
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
} else {
ownKeys(Object(source)).forEach(function (key) {
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
});
}
}
return target;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function");
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
writable: true,
configurable: true
}
});
if (superClass) _setPrototypeOf(subClass, superClass);
}
function _getPrototypeOf(o) {
_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
return o.__proto__ || Object.getPrototypeOf(o);
};
return _getPrototypeOf(o);
}
function _setPrototypeOf(o, p) {
_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}
function _isNativeReflectConstruct() {
if (typeof Reflect === "undefined" || !Reflect.construct) return false;
if (Reflect.construct.sham) return false;
if (typeof Proxy === "function") return true;
try {
Date.prototype.toString.call(Reflect.construct(Date, [], function () {}));
return true;
} catch (e) {
return false;
}
}
function _construct(Parent, args, Class) {
if (_isNativeReflectConstruct()) {
_construct = Reflect.construct;
} else {
_construct = function _construct(Parent, args, Class) {
var a = [null];
a.push.apply(a, args);
var Constructor = Function.bind.apply(Parent, a);
var instance = new Constructor();
if (Class) _setPrototypeOf(instance, Class.prototype);
return instance;
};
}
return _construct.apply(null, arguments);
}
function _isNativeFunction(fn) {
return Function.toString.call(fn).indexOf("[native code]") !== -1;
}
function _wrapNativeSuper(Class) {
var _cache = typeof Map === "function" ? new Map() : undefined;
_wrapNativeSuper = function _wrapNativeSuper(Class) {
if (Class === null || !_isNativeFunction(Class)) return Class;
if (typeof Class !== "function") {
throw new TypeError("Super expression must either be null or a function");
}
if (typeof _cache !== "undefined") {
if (_cache.has(Class)) return _cache.get(Class);
_cache.set(Class, Wrapper);
}
function Wrapper() {
return _construct(Class, arguments, _getPrototypeOf(this).constructor);
}
Wrapper.prototype = Object.create(Class.prototype, {
constructor: {
value: Wrapper,
enumerable: false,
writable: true,
configurable: true
}
});
return _setPrototypeOf(Wrapper, Class);
};
return _wrapNativeSuper(Class);
}
function _assertThisInitialized(self) {
if (self === void 0) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return self;
}
function _possibleConstructorReturn(self, call) {
if (call && (typeof call === "object" || typeof call === "function")) {
return call;
}
return _assertThisInitialized(self);
}
function _createSuper(Derived) {
var hasNativeReflectConstruct = _isNativeReflectConstruct();
return function _createSuperInternal() {
var Super = _getPrototypeOf(Derived),
result;
if (hasNativeReflectConstruct) {
var NewTarget = _getPrototypeOf(this).constructor;
result = Reflect.construct(Super, arguments, NewTarget);
} else {
result = Super.apply(this, arguments);
}
return _possibleConstructorReturn(this, result);
};
}
function _superPropBase(object, property) {
while (!Object.prototype.hasOwnProperty.call(object, property)) {
object = _getPrototypeOf(object);
if (object === null) break;
}
return object;
}
function _get(target, property, receiver) {
if (typeof Reflect !== "undefined" && Reflect.get) {
_get = Reflect.get;
} else {
_get = function _get(target, property, receiver) {
var base = _superPropBase(target, property);
if (!base) return;
var desc = Object.getOwnPropertyDescriptor(base, property);
if (desc.get) {
return desc.get.call(receiver);
}
return desc.value;
};
}
return _get(target, property, receiver || target);
}
function _slicedToArray(arr, i) {
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
}
function _toConsumableArray(arr) {
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) return _arrayLikeToArray(arr);
}
function _arrayWithHoles(arr) {
if (Array.isArray(arr)) return arr;
}
function _iterableToArray(iter) {
if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
}
function _iterableToArrayLimit(arr, i) {
if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
var _arr = [];
var _n = true;
var _d = false;
var _e = undefined;
try {
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
_arr.push(_s.value);
if (i && _arr.length === i) break;
}
} catch (err) {
_d = true;
_e = err;
} finally {
try {
if (!_n && _i["return"] != null) _i["return"]();
} finally {
if (_d) throw _e;
}
}
return _arr;
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _nonIterableRest() {
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
var e=function(){return (e=Object.assign||function(e){for(var t,r=1,s=arguments.length;r<s;r++)for(var a in t=arguments[r])Object.prototype.hasOwnProperty.call(t,a)&&(e[a]=t[a]);return e}).apply(this,arguments)},t={kebab:/-(\w)/g,styleProp:/:(.*)/,styleList:/;(?![^(]*\))/g};function r(e,t){return t?t.toUpperCase():""}function s(e){for(var s,a={},c=0,o=e.split(t.styleList);c<o.length;c++){var n=o[c].split(t.styleProp),i=n[0],l=n[1];(i=i.trim())&&("string"==typeof l&&(l=l.trim()),a[(s=i,s.replace(t.kebab,r))]=l);}return a}function a(){for(var t,r,a={},c=arguments.length;c--;)for(var o=0,n=Object.keys(arguments[c]);o<n.length;o++)switch(t=n[o]){case"class":case"style":case"directives":if(Array.isArray(a[t])||(a[t]=[]),"style"===t){var i=void 0;i=Array.isArray(arguments[c].style)?arguments[c].style:[arguments[c].style];for(var l=0;l<i.length;l++){var y=i[l];"string"==typeof y&&(i[l]=s(y));}arguments[c].style=i;}a[t]=a[t].concat(arguments[c][t]);break;case"staticClass":if(!arguments[c][t])break;void 0===a[t]&&(a[t]=""),a[t]&&(a[t]+=" "),a[t]+=arguments[c][t].trim();break;case"on":case"nativeOn":a[t]||(a[t]={});for(var p=0,f=Object.keys(arguments[c][t]||{});p<f.length;p++)r=f[p],a[t][r]?a[t][r]=[].concat(a[t][r],arguments[c][t][r]):a[t][r]=arguments[c][t][r];break;case"attrs":case"props":case"domProps":case"scopedSlots":case"staticStyle":case"hook":case"transition":a[t]||(a[t]={}),a[t]=e({},arguments[c][t],a[t]);break;case"slot":case"key":case"ref":case"tag":case"show":case"keepAlive":default:a[t]||(a[t]=arguments[c][t]);}return a}
var NAME = 'BvConfig';
var PROP_NAME = '$bvConfig';
var DEFAULT_BREAKPOINT = ['xs', 'sm', 'md', 'lg', 'xl'];
/**
* Utilities to get information about the current environment
*/
// --- Constants ---
var hasWindowSupport = typeof window !== 'undefined';
var hasDocumentSupport = typeof document !== 'undefined';
var hasNavigatorSupport = typeof navigator !== 'undefined';
var hasPromiseSupport = typeof Promise !== 'undefined';
/* istanbul ignore next: JSDOM always returns false */
var hasMutationObserverSupport = typeof MutationObserver !== 'undefined' || typeof WebKitMutationObserver !== 'undefined' || typeof MozMutationObserver !== 'undefined';
var isBrowser = hasWindowSupport && hasDocumentSupport && hasNavigatorSupport; // Browser type sniffing
var userAgent = isBrowser ? window.navigator.userAgent.toLowerCase() : '';
var isJSDOM = userAgent.indexOf('jsdom') > 0;
var isIE = /msie|trident/.test(userAgent); // Determine if the browser supports the option passive for events
var hasPassiveEventSupport = function () {
var passiveEventSupported = false;
if (isBrowser) {
try {
var options = {
get passive() {
// This function will be called when the browser
// attempts to access the passive property.
/* istanbul ignore next: will never be called in JSDOM */
passiveEventSupported = true;
}
};
window.addEventListener('test', options, options);
window.removeEventListener('test', options, options);
} catch (err) {
/* istanbul ignore next: will never be called in JSDOM */
passiveEventSupported = false;
}
}
return passiveEventSupported;
}();
var hasTouchSupport = isBrowser && ('ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0);
var hasPointerEventSupport = isBrowser && Boolean(window.PointerEvent || window.MSPointerEvent);
/* istanbul ignore next: JSDOM only checks for 'IntersectionObserver' */
var hasIntersectionObserverSupport = isBrowser && 'IntersectionObserver' in window && 'IntersectionObserverEntry' in window && // Edge 15 and UC Browser lack support for `isIntersecting`
// but we an use intersectionRatio > 0 instead
// 'isIntersecting' in window.IntersectionObserverEntry.prototype &&
'intersectionRatio' in window.IntersectionObserverEntry.prototype; // --- Getters ---
var getEnv = function getEnv(key) {
var fallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
var env = typeof process !== 'undefined' && process ? process.env || {} : {};
if (!key) {
/* istanbul ignore next */
return env;
}
return env[key] || fallback;
};
var getNoWarn = function getNoWarn() {
return getEnv('BOOTSTRAP_VUE_NO_WARN') || getEnv('NODE_ENV') === 'production';
};
var w = hasWindowSupport ? window : {};
var Element$1 = hasWindowSupport ? w.Element : /*#__PURE__*/function (_Object) {
_inherits(Element, _Object);
var _super = _createSuper(Element);
function Element() {
_classCallCheck(this, Element);
return _super.apply(this, arguments);
}
return Element;
}( /*#__PURE__*/_wrapNativeSuper(Object));
var HTMLElement = hasWindowSupport ? w.HTMLElement : /*#__PURE__*/function (_Element) {
_inherits(HTMLElement, _Element);
var _super2 = _createSuper(HTMLElement);
function HTMLElement() {
_classCallCheck(this, HTMLElement);
return _super2.apply(this, arguments);
}
return HTMLElement;
}(Element$1);
var SVGElement = hasWindowSupport ? w.SVGElement : /*#__PURE__*/function (_Element2) {
_inherits(SVGElement, _Element2);
var _super3 = _createSuper(SVGElement);
function SVGElement() {
_classCallCheck(this, SVGElement);
return _super3.apply(this, arguments);
}
return SVGElement;
}(Element$1);
var File = hasWindowSupport ? w.File : /*#__PURE__*/function (_Object2) {
_inherits(File, _Object2);
var _super4 = _createSuper(File);
function File() {
_classCallCheck(this, File);
return _super4.apply(this, arguments);
}
return File;
}( /*#__PURE__*/_wrapNativeSuper(Object));
var toType = function toType(val) {
return _typeof(val);
};
var toRawType = function toRawType(val) {
return Object.prototype.toString.call(val).slice(8, -1);
};
var isUndefined = function isUndefined(val) {
return val === undefined;
};
var isNull = function isNull(val) {
return val === null;
};
var isUndefinedOrNull = function isUndefinedOrNull(val) {
return isUndefined(val) || isNull(val);
};
var isFunction = function isFunction(val) {
return toType(val) === 'function';
};
var isBoolean = function isBoolean(val) {
return toType(val) === 'boolean';
};
var isString = function isString(val) {
return toType(val) === 'string';
};
var isNumber = function isNumber(val) {
return toType(val) === 'number';
}; // Is a value number like (i.e. a number or a number as string)
var isNumeric = function isNumeric(value) {
return !isNaN(parseInt(value, 10));
};
var isArray = function isArray(val) {
return Array.isArray(val);
}; // Quick object check
// This is primarily used to tell Objects from primitive values
// when we know the value is a JSON-compliant type
// Note object could be a complex type like array, Date, etc.
var isObject = function isObject(obj) {
return obj !== null && _typeof(obj) === 'object';
}; // Strict object type check
// Only returns true for plain JavaScript objects
var isPlainObject = function isPlainObject(obj) {
return Object.prototype.toString.call(obj) === '[object Object]';
};
var isDate = function isDate(val) {
return val instanceof Date;
};
var isEvent = function isEvent(val) {
return val instanceof Event;
};
var isFile = function isFile(val) {
return val instanceof File;
};
var isRegExp = function isRegExp(val) {
return toRawType(val) === 'RegExp';
};
var isPromise = function isPromise(val) {
return !isUndefinedOrNull(val) && isFunction(val.then) && isFunction(val.catch);
};
var assign = function assign() {
return Object.assign.apply(Object, arguments);
};
var create = function create(proto, optionalProps) {
return Object.create(proto, optionalProps);
};
var defineProperties = function defineProperties(obj, props) {
return Object.defineProperties(obj, props);
};
var defineProperty = function defineProperty(obj, prop, descriptor) {
return Object.defineProperty(obj, prop, descriptor);
};
var getOwnPropertyNames = function getOwnPropertyNames(obj) {
return Object.getOwnPropertyNames(obj);
};
var keys = function keys(obj) {
return Object.keys(obj);
}; // --- "Instance" ---
var hasOwnProperty = function hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
};
var toString = function toString(obj) {
return Object.prototype.toString.call(obj);
}; // --- Utilities ---
/**
* Shallow copy an object. If the passed in object
* is null or undefined, returns an empty object
*/
var clone = function clone(obj) {
return _objectSpread2({}, obj);
};
/**
* Return a shallow copy of object with the specified properties only
* @link https://gist.github.com/bisubus/2da8af7e801ffd813fab7ac221aa7afc
*/
var pick = function pick(obj, props) {
return keys(obj).filter(function (key) {
return props.indexOf(key) !== -1;
}).reduce(function (result, key) {
return _objectSpread2(_objectSpread2({}, result), {}, _defineProperty({}, key, obj[key]));
}, {});
};
/**
* Return a shallow copy of object with the specified properties omitted
* @link https://gist.github.com/bisubus/2da8af7e801ffd813fab7ac221aa7afc
*/
var omit = function omit(obj, props) {
return keys(obj).filter(function (key) {
return props.indexOf(key) === -1;
}).reduce(function (result, key) {
return _objectSpread2(_objectSpread2({}, result), {}, _defineProperty({}, key, obj[key]));
}, {});
};
/**
* Merges two object deeply together
* @link https://gist.github.com/Salakar/1d7137de9cb8b704e48a
*/
var mergeDeep = function mergeDeep(target, source) {
if (isObject(target) && isObject(source)) {
keys(source).forEach(function (key) {
if (isObject(source[key])) {
if (!target[key] || !isObject(target[key])) {
target[key] = source[key];
}
mergeDeep(target[key], source[key]);
} else {
assign(target, _defineProperty({}, key, source[key]));
}
});
}
return target;
};
/**
* Convenience method to create a read-only descriptor
*/
var readonlyDescriptor = function readonlyDescriptor() {
return {
enumerable: true,
configurable: false,
writable: false
};
};
var cloneDeep = function cloneDeep(obj) {
var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : obj;
if (isArray(obj)) {
return obj.reduce(function (result, val) {
return [].concat(_toConsumableArray(result), [cloneDeep(val, val)]);
}, []);
}
if (isPlainObject(obj)) {
return keys(obj).reduce(function (result, key) {
return _objectSpread2(_objectSpread2({}, result), {}, _defineProperty({}, key, cloneDeep(obj[key], obj[key])));
}, {});
}
return defaultValue;
};
// --- General ---
var RX_ARRAY_NOTATION = /\[(\d+)]/g;
var RX_DIGITS = /^\d+$/;
var RX_EXTENSION = /^\..+/;
var RX_HASH = /^#/;
var RX_HASH_ID = /^#[A-Za-z]+[\w\-:.]*$/;
var RX_HTML_TAGS = /(<([^>]+)>)/gi;
var RX_HYPHENATE = /\B([A-Z])/g;
var RX_LOWER_UPPER = /([a-z])([A-Z])/g;
var RX_NUMBER = /^[0-9]*\.?[0-9]+$/;
var RX_PLUS = /\+/g;
var RX_REGEXP_REPLACE = /[-/\\^$*+?.()|[\]{}]/g;
var RX_SPACES = /[\s\uFEFF\xA0]+/g;
var RX_SPACE_SPLIT = /\s+/;
var RX_STAR = /\/\*$/;
var RX_START_SPACE_WORD = /(\s|^)(\w)/g;
var RX_TRIM_LEFT = /^\s+/;
var RX_UNDERSCORE = /_/g;
var RX_UN_KEBAB = /-(\w)/g; // --- Date ---
// Loose YYYY-MM-DD matching, ignores any appended time inforation
// Matches '1999-12-20', '1999-1-1', '1999-01-20T22:51:49.118Z', '1999-01-02 13:00:00'
var RX_DATE = /^\d+-\d\d?-\d\d?(?:\s|T|$)/; // Used to split off the date parts of the YYYY-MM-DD string
var RX_DATE_SPLIT = /-|\s|T/; // Time string RegEx (optional seconds)
var RX_TIME = /^([0-1]?[0-9]|2[0-3]):[0-5]?[0-9](:[0-5]?[0-9])?$/; // --- URL ---
// HREFs must end with a hash followed by at least one non-hash character
var RX_HREF = /^.*(#[^#]+)$/;
var RX_ENCODED_COMMA = /%2C/g;
var RX_ENCODE_REVERSE = /[!'()*]/g;
var RX_QUERY_START = /^(\?|#|&)/; // --- Aspect ---
var RX_ASPECT = /^\d+(\.\d*)?[/:]\d+(\.\d*)?$/;
var RX_ASPECT_SEPARATOR = /[/:]/; // --- Grid ---
var RX_COL_CLASS = /^col-/; // --- Icon ---
var RX_ICON_PREFIX = /^BIcon/; // --- Locale ---
var RX_STRIP_LOCALE_MODS = /-u-.+/;
var identity = function identity(x) {
return x;
};
/**
* Get property defined by dot/array notation in string, returns undefined if not found
*
* @link https://gist.github.com/jeneg/9767afdcca45601ea44930ea03e0febf#gistcomment-1935901
*
* @param {Object} obj
* @param {string|Array} path
* @return {*}
*/
var getRaw = function getRaw(obj, path) {
var defaultValue = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
// Handle array of path values
path = isArray(path) ? path.join('.') : path; // If no path or no object passed
if (!path || !isObject(obj)) {
return defaultValue;
} // Handle edge case where user has dot(s) in top-level item field key
// See https://github.com/bootstrap-vue/bootstrap-vue/issues/2762
// Switched to `in` operator vs `hasOwnProperty` to handle obj.prototype getters
// https://github.com/bootstrap-vue/bootstrap-vue/issues/3463
if (path in obj) {
return obj[path];
} // Handle string array notation (numeric indices only)
path = String(path).replace(RX_ARRAY_NOTATION, '.$1');
var steps = path.split('.').filter(identity); // Handle case where someone passes a string of only dots
if (steps.length === 0) {
return defaultValue;
} // Traverse path in object to find result
// Switched to `in` operator vs `hasOwnProperty` to handle obj.prototype getters
// https://github.com/bootstrap-vue/bootstrap-vue/issues/3463
return steps.every(function (step) {
return isObject(obj) && step in obj && !isUndefinedOrNull(obj = obj[step]);
}) ? obj : isNull(obj) ? null : defaultValue;
};
/**
* Get property defined by dot/array notation in string.
*
* @link https://gist.github.com/jeneg/9767afdcca45601ea44930ea03e0febf#gistcomment-1935901
*
* @param {Object} obj
* @param {string|Array} path
* @param {*} defaultValue (optional)
* @return {*}
*/
var get = function get(obj, path) {
var defaultValue = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
var val = getRaw(obj, path);
return isUndefinedOrNull(val) ? defaultValue : val;
};
/**
* Log a warning message to the console with BootstrapVue formatting
* @param {string} message
*/
var warn = function warn(message)
/* istanbul ignore next */
{
var source = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
if (!getNoWarn()) {
console.warn("[BootstrapVue warn]: ".concat(source ? "".concat(source, " - ") : '').concat(message));
}
};
/**
* Warn when no Promise support is given
* @param {string} source
* @returns {boolean} warned
*/
var warnNotClient = function warnNotClient(source) {
/* istanbul ignore else */
if (isBrowser) {
return false;
} else {
warn("".concat(source, ": Can not be called during SSR."));
return true;
}
};
/**
* Warn when no Promise support is given
* @param {string} source
* @returns {boolean} warned
*/
var warnNoPromiseSupport = function warnNoPromiseSupport(source) {
/* istanbul ignore else */
if (hasPromiseSupport) {
return false;
} else {
warn("".concat(source, ": Requires Promise support."));
return true;
}
};
/**
* Warn when no MutationObserver support is given
* @param {string} source
* @returns {boolean} warned
*/
var warnNoMutationObserverSupport = function warnNoMutationObserverSupport(source) {
/* istanbul ignore else */
if (hasMutationObserverSupport) {
return false;
} else {
warn("".concat(source, ": Requires MutationObserver support."));
return true;
}
};
var BvConfig = /*#__PURE__*/function () {
function BvConfig() {
_classCallCheck(this, BvConfig);
this.$_config = {};
} // Method to merge in user config parameters
_createClass(BvConfig, [{
key: "setConfig",
value: function setConfig() {
var _this = this;
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
/* istanbul ignore next */
if (!isPlainObject(config)) {
return;
}
var configKeys = getOwnPropertyNames(config);
configKeys.forEach(function (key) {
/* istanbul ignore next */
var subConfig = config[key];
if (key === 'breakpoints') {
/* istanbul ignore if */
if (!isArray(subConfig) || subConfig.length < 2 || subConfig.some(function (b) {
return !isString(b) || b.length === 0;
})) {
warn('"breakpoints" must be an array of at least 2 breakpoint names', NAME);
} else {
_this.$_config[key] = cloneDeep(subConfig);
}
} else if (isPlainObject(subConfig)) {
// Component prop defaults
_this.$_config[key] = getOwnPropertyNames(subConfig).reduce(function (config, prop) {
if (!isUndefined(subConfig[prop])) {
config[prop] = cloneDeep(subConfig[prop]);
}
return config;
}, _this.$_config[key] || {});
}
});
} // Clear the config
}, {
key: "resetConfig",
value: function resetConfig() {
this.$_config = {};
} // Returns a deep copy of the user config
}, {
key: "getConfig",
value: function getConfig() {
return cloneDeep(this.$_config);
} // Returns a deep copy of the config value
}, {
key: "getConfigValue",
value: function getConfigValue(key) {
var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
return cloneDeep(getRaw(this.$_config, key, defaultValue));
}
}]);
return BvConfig;
}(); // Method for applying a global config
var setConfig = function setConfig() {
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var Vue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Vue__default['default'];
// Ensure we have a `$bvConfig` Object on the Vue prototype
// We set on Vue and OurVue just in case consumer has not set an alias of `vue`
Vue.prototype[PROP_NAME] = Vue__default['default'].prototype[PROP_NAME] = Vue.prototype[PROP_NAME] || Vue__default['default'].prototype[PROP_NAME] || new BvConfig(); // Apply the config values
Vue.prototype[PROP_NAME].setConfig(config);
}; // Method for resetting the user config
/**
* Checks if there are multiple instances of Vue, and warns (once) about possible issues.
* @param {object} Vue
*/
var checkMultipleVue = function () {
var checkMultipleVueWarned = false;
var MULTIPLE_VUE_WARNING = ['Multiple instances of Vue detected!', 'You may need to set up an alias for Vue in your bundler config.', 'See: https://bootstrap-vue.org/docs#using-module-bundlers'].join('\n');
return function (Vue) {
/* istanbul ignore next */
if (!checkMultipleVueWarned && Vue__default['default'] !== Vue && !isJSDOM) {
warn(MULTIPLE_VUE_WARNING);
}
checkMultipleVueWarned = true;
};
}();
/**
* Plugin install factory function.
* @param {object} { components, directives }
* @returns {function} plugin install function
*/
var installFactory = function installFactory() {
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
components = _ref.components,
directives = _ref.directives,
plugins = _ref.plugins;
var install = function install(Vue) {
var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (install.installed) {
/* istanbul ignore next */
return;
}
install.installed = true;
checkMultipleVue(Vue);
setConfig(config, Vue);
registerComponents(Vue, components);
registerDirectives(Vue, directives);
registerPlugins(Vue, plugins);
};
install.installed = false;
return install;
};
/**
* Plugin object factory function.
* @param {object} { components, directives, plugins }
* @returns {object} plugin install object
*/
var pluginFactory = function pluginFactory() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var extend = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return _objectSpread2(_objectSpread2({}, extend), {}, {
install: installFactory(options)
});
};
/**
* Load a group of plugins.
* @param {object} Vue
* @param {object} Plugin definitions
*/
var registerPlugins = function registerPlugins(Vue) {
var plugins = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
for (var plugin in plugins) {
if (plugin && plugins[plugin]) {
Vue.use(plugins[plugin]);
}
}
};
/**
* Load a component.
* @param {object} Vue
* @param {string} Component name
* @param {object} Component definition
*/
var registerComponent = function registerComponent(Vue, name, def) {
if (Vue && name && def) {
Vue.component(name, def);
}
};
/**
* Load a group of components.
* @param {object} Vue
* @param {object} Object of component definitions
*/
var registerComponents = function registerComponents(Vue) {
var components = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
for (var component in components) {
registerComponent(Vue, component, components[component]);
}
};
/**
* Load a directive.
* @param {object} Vue
* @param {string} Directive name
* @param {object} Directive definition
*/
var registerDirective = function registerDirective(Vue, name, def) {
if (Vue && name && def) {
// Ensure that any leading V is removed from the
// name, as Vue adds it automatically
Vue.directive(name.replace(/^VB/, 'B'), def);
}
};
/**
* Load a group of directives.
* @param {object} Vue
* @param {object} Object of directive definitions
*/
var registerDirectives = function registerDirectives(Vue) {
var directives = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
for (var directive in directives) {
registerDirective(Vue, directive, directives[directive]);
}
};
/**
* Install plugin if window.Vue available
* @param {object} Plugin definition
*/
var vueUse = function vueUse(VuePlugin) {
/* istanbul ignore next */
if (hasWindowSupport && window.Vue) {
window.Vue.use(VuePlugin);
}
/* istanbul ignore next */
if (hasWindowSupport && VuePlugin.NAME) {
window[VuePlugin.NAME] = VuePlugin;
}
};
var NAME_ALERT = 'BAlert';
var NAME_ASPECT = 'BAspect';
var NAME_AVATAR = 'BAvatar';
var NAME_AVATAR_GROUP = 'BAvatarGroup';
var NAME_BADGE = 'BBadge';
var NAME_BREADCRUMB = 'BBreadcrumb';
var NAME_BREADCRUMB_ITEM = 'BBreadcrumbItem';
var NAME_BREADCRUMB_LINK = 'BBreadcrumbLink';
var NAME_BUTTON = 'BButton';
var NAME_BUTTON_CLOSE = 'BButtonClose';
var NAME_BUTTON_GROUP = 'BButtonGroup';
var NAME_BUTTON_TOOLBAR = 'BButtonToolbar';
var NAME_CALENDAR = 'BCalendar';
var NAME_CARD = 'BCard';
var NAME_CARD_BODY = 'BCardBody';
var NAME_CARD_FOOTER = 'BCardFooter';
var NAME_CARD_GROUP = 'BCardGroup';
var NAME_CARD_HEADER = 'BCardHeader';
var NAME_CARD_IMG = 'BCardImg';
var NAME_CARD_IMG_LAZY = 'BCardImgLazy';
var NAME_CARD_SUB_TITLE = 'BCardSubTitle';
var NAME_CARD_TEXT = 'BCardText';
var NAME_CARD_TITLE = 'BCardTitle';
var NAME_CAROUSEL = 'BCarousel';
var NAME_CAROUSEL_SLIDE = 'BCarouselSlide';
var NAME_COL = 'BCol';
var NAME_COLLAPSE = 'BCollapse';
var NAME_COLLAPSE_HELPER = 'BVCollapse';
var NAME_CONTAINER = 'BContainer';
var NAME_DROPDOWN = 'BDropdown';
var NAME_DROPDOWN_DIVIDER = 'BDropdownDivider';
var NAME_DROPDOWN_FORM = 'BDropdownForm';
var NAME_DROPDOWN_GROUP = 'BDropdownGroup';
var NAME_DROPDOWN_HEADER = 'BDropdownHeader';
var NAME_DROPDOWN_ITEM = 'BDropdownItem';
var NAME_DROPDOWN_ITEM_BUTTON = 'BDropdownItemButton';
var NAME_DROPDOWN_TEXT = 'BDropdownText';
var NAME_EMBED = 'BEmbed';
var NAME_FORM = 'BForm';
var NAME_FORM_BUTTON_LABEL_CONTROL = 'BVFormBtnLabelControl';
var NAME_FORM_CHECKBOX = 'BFormCheckbox';
var NAME_FORM_CHECKBOX_GROUP = 'BFormCheckboxGroup';
var NAME_FORM_DATALIST = 'BFormDatalist';
var NAME_FORM_DATEPICKER = 'BFormDatepicker';
var NAME_FORM_FILE = 'BFormFile';
var NAME_FORM_GROUP = 'BFormGroup';
var NAME_FORM_INPUT = 'BFormInput';
var NAME_FORM_INVALID_FEEDBACK = 'BFormInvalidFeedback';
var NAME_FORM_RADIO = 'BFormRadio';
var NAME_FORM_RADIO_GROUP = 'BFormRadioGroup';
var NAME_FORM_RATING = 'BFormRating';
var NAME_FORM_RATING_STAR = 'BVFormRatingStar';
var NAME_FORM_ROW = 'BFormRow';
var NAME_FORM_SELECT = 'BFormSelect';
var NAME_FORM_SELECT_OPTION = 'BFormSelectOption';
var NAME_FORM_SELECT_OPTION_GROUP = 'BFormSelectOptionGroup';
var NAME_FORM_SPINBUTTON = 'BFormSpinbutton';
var NAME_FORM_TAG = 'BFormTag';
var NAME_FORM_TAGS = 'BFormTags';
var NAME_FORM_TEXT = 'BFormText';
var NAME_FORM_TEXTAREA = 'BFormTextarea';
var NAME_FORM_TIMEPICKER = 'BFormTimepicker';
var NAME_FORM_VALID_FEEDBACK = 'BFormValidFeedback';
var NAME_ICON = 'BIcon';
var NAME_ICONSTACK = 'BIconstack';
var NAME_ICON_BASE = 'BIconBase';
var NAME_IMG = 'BImg';
var NAME_IMG_LAZY = 'BImgLazy';
var NAME_INPUT_GROUP = 'BInputGroup';
var NAME_INPUT_GROUP_ADDON = 'BInputGroupAddon';
var NAME_INPUT_GROUP_APPEND = 'BInputGroupAppend';
var NAME_INPUT_GROUP_PREPEND = 'BInputGroupPrepend';
var NAME_INPUT_GROUP_TEXT = 'BInputGroupText';
var NAME_JUMBOTRON = 'BJumbotron';
var NAME_LINK = 'BLink';
var NAME_LIST_GROUP = 'BListGroup';
var NAME_LIST_GROUP_ITEM = 'BListGroupItem';
var NAME_MEDIA = 'BMedia';
var NAME_MEDIA_ASIDE = 'BMediaAside';
var NAME_MEDIA_BODY = 'BMediaBody';
var NAME_MODAL = 'BModal';
var NAME_MSG_BOX = 'BMsgBox';
var NAME_NAV = 'BNav';
var NAME_NAVBAR = 'BNavbar';
var NAME_NAVBAR_BRAND = 'BNavbarBrand';
var NAME_NAVBAR_NAV = 'BNavbarNav';
var NAME_NAVBAR_TOGGLE = 'BNavbarToggle';
var NAME_NAV_FORM = 'BNavForm';
var NAME_NAV_ITEM = 'BNavItem';
var NAME_NAV_ITEM_DROPDOWN = 'BNavItemDropdown';
var NAME_NAV_TEXT = 'BNavText';
var NAME_OVERLAY = 'BOverlay';
var NAME_PAGINATION = 'BPagination';
var NAME_PAGINATION_NAV = 'BPaginationNav';
var NAME_POPOVER = 'BPopover';
var NAME_POPOVER_HELPER = 'BVPopover';
var NAME_POPOVER_TEMPLATE = 'BVPopoverTemplate';
var NAME_POPPER = 'BVPopper';
var NAME_PROGRESS = 'BProgress';
var NAME_PROGRESS_BAR = 'BProgressBar';
var NAME_ROW = 'BRow';
var NAME_SIDEBAR = 'BSidebar';
var NAME_SKELETON = 'BSkeleton';
var NAME_SKELETON_ICON = 'BSkeletonIcon';
var NAME_SKELETON_IMG = 'BSkeletonImg';
var NAME_SKELETON_TABLE = 'BSkeletonTable';
var NAME_SKELETON_WRAPPER = 'BSkeletonWrapper';
var NAME_SPINNER = 'BSpinner';
var NAME_TAB = 'BTab';
var NAME_TABLE = 'BTable';
var NAME_TABLE_CELL = 'BTableCell';
var NAME_TABLE_LITE = 'BTableLite';
var NAME_TABLE_SIMPLE = 'BTableSimple';
var NAME_TABS = 'BTabs';
var NAME_TAB_BUTTON_HELPER = 'BVTabButton';
var NAME_TBODY = 'BTbody';
var NAME_TFOOT = 'BTfoot';
var NAME_TH = 'BTh';
var NAME_THEAD = 'BThead';
var NAME_TIME = 'BTime';
var NAME_TOAST = 'BToast';
var NAME_TOASTER = 'BToaster';
var NAME_TOAST_POP = 'BVToastPop';
var NAME_TOOLTIP = 'BTooltip';
var NAME_TOOLTIP_HELPER = 'BVTooltip';
var NAME_TOOLTIP_TEMPLATE = 'BVTooltipTemplate';
var NAME_TR = 'BTr';
var NAME_TRANSITION = 'BVTransition';
var NAME_TRANSPORTER_SINGLE = 'BTransporterSingle';
var NAME_TRANSPORTER_TARGET_SINGLE = 'BTransporterTargetSingle';
var memoize = function memoize(fn) {
var cache = create(null);
return function () {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
var argsKey = JSON.stringify(args);
return cache[argsKey] = cache[argsKey] || fn.apply(null, args);
};
};
var VueProto = Vue__default['default'].prototype; // --- Getter methods ---
var getConfigValue = function getConfigValue(key) {
var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
var bvConfig = VueProto[PROP_NAME];
return bvConfig ? bvConfig.getConfigValue(key, defaultValue) : cloneDeep(defaultValue);
}; // Method to grab a config value for a particular component
var getComponentConfig = function getComponentConfig(key) {
var propKey = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
var defaultValue = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
// Return the particular config value for key if specified,
// otherwise we return the full config (or an empty object if not found)
return propKey ? getConfigValue("".concat(key, ".").concat(propKey), defaultValue) : getConfigValue(key, {});
}; // Get all breakpoint names
var getBreakpoints = function getBreakpoints() {
return getConfigValue('breakpoints', DEFAULT_BREAKPOINT);
}; // Private method for caching breakpoint names
var _getBreakpointsCached = memoize(function () {
return getBreakpoints();
}); // Get all breakpoint names (cached)
var getBreakpointsCached = function getBreakpointsCached() {
return cloneDeep(_getBreakpointsCached());
}; // Get breakpoints with the smallest breakpoint set as ''
// Useful for components that create breakpoint specific props
var getBreakpointsUpCached = memoize(function () {
var breakpoints = getBreakpointsCached();
breakpoints[0] = '';
return breakpoints;
}); // Get breakpoints with the largest breakpoint set as ''
// Replaces the current `default` key of each prop with a `getComponentConfig()`
// call that falls back to the current default value of the prop
var makePropsConfigurable = function makePropsConfigurable(props, componentKey) {
return keys(props).reduce(function (result, prop) {
var currentProp = props[prop];
var defaultValue = currentProp.default;
result[prop] = _objectSpread2(_objectSpread2({}, cloneDeep(currentProp)), {}, {
default: function _default() {
return getComponentConfig(componentKey, prop, isFunction(defaultValue) ? defaultValue() : defaultValue);
}
});
return result;
}, {});
};
// --- Static ---
var from = function from() {
return Array.from.apply(Array, arguments);
}; // --- Instance ---
var arrayIncludes = function arrayIncludes(array, value) {
return array.indexOf(value) !== -1;
};
var concat = function concat() {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return Array.prototype.concat.apply([], args);
}; // --- Utilities ---
var createAndFillArray = function createAndFillArray(size, value) {
return Array(size).fill(value);
};
var flatten = function flatten(array) {
return array.reduce(function (result, item) {
return result.concat(item);
}, []);
};
var flattenDeep = function flattenDeep(array) {
return array.reduce(function (result, item) {
return result.concat(Array.isArray(item) ? flattenDeep(item) : item);
}, []);
};
// Number utilities
// Converts a value (string, number, etc.) to an integer number
// Assumes radix base 10
var toInteger = function toInteger(value) {
var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : NaN;
var integer = parseInt(value, 10);
return isNaN(integer) ? defaultValue : integer;
}; // Converts a value (string, number, etc.) to a number
var toFloat = function toFloat(value) {
var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : NaN;
var float = parseFloat(value);
return isNaN(float) ? defaultValue : float;
}; // Converts a value (string, number, etc.) to a string
// representation with `precision` digits after the decimal
// Returns the string 'NaN' if the value cannot be converted
var toFixed = function toFixed(val, precision) {
return toFloat(val).toFixed(toInteger(precision, 0));
};
// String utilities
// Converts PascalCase or camelCase to kebab-case
var kebabCase = function kebabCase(str) {
return str.replace(RX_HYPHENATE, '-$1').toLowerCase();
}; // Converts a kebab-case or camelCase string to PascalCase
var pascalCase = function pascalCase(str) {
str = kebabCase(str).replace(RX_UN_KEBAB, function (_, c) {
return c ? c.toUpperCase() : '';
});
return str.charAt(0).toUpperCase() + str.slice(1);
}; // Converts a string, including strings in camelCase or snake_case, into Start Case
// It keeps original single quote and hyphen in the word
// https://github.com/UrbanCompass/to-start-case
var startCase = function startCase(str) {
return str.replace(RX_UNDERSCORE, ' ').replace(RX_LOWER_UPPER, function (str, $1, $2) {
return $1 + ' ' + $2;
}).replace(RX_START_SPACE_WORD, function (str, $1, $2) {
return $1 + $2.toUpperCase();
});
}; // Lowercases the first letter of a string and returns a new string
var lowerFirst = function lowerFirst(str) {
str = isString(str) ? str.trim() : String(str);
return str.charAt(0).toLowerCase() + str.slice(1);
}; // Uppercases the first letter of a string and returns a new string
var upperFirst = function upperFirst(str) {
str = isString(str) ? str.trim() : String(str);
return str.charAt(0).toUpperCase() + str.slice(1);
}; // Escape characters to be used in building a regular expression
var escapeRegExp = function escapeRegExp(str) {
return str.replace(RX_REGEXP_REPLACE, '\\$&');
}; // Convert a value to a string that can be rendered
// `undefined`/`null` will be converted to `''`
// Plain objects and arrays will be JSON stringified
var toString$1 = function toString(val) {
var spaces = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 2;
return isUndefinedOrNull(val) ? '' : isArray(val) || isPlainObject(val) && val.toString === Object.prototype.toString ? JSON.stringify(val, null, spaces) : String(val);
}; // Remove leading white space from a string
var trimLeft = function trimLeft(str) {
return toString$1(str).replace(RX_TRIM_LEFT, '');
}; // Remove Trailing white space from a string
var trim = function trim(str) {
return toString$1(str).trim();
}; // Lower case a string
var lowerCase = function lowerCase(str) {
return toString$1(str).toLowerCase();
}; // Upper case a string
var TABABLE_SELECTOR = ['button', '[href]:not(.disabled)', 'input', 'select', 'textarea', '[tabindex]', '[contenteditable]'].map(function (s) {
return "".concat(s, ":not(:disabled):not([disabled])");
}).join(', ');
var w$1 = hasWindowSupport ? window : {};
var d = hasDocumentSupport ? document : {};
var elProto = typeof Element !== 'undefined' ? Element.prototype : {}; // --- Normalization utils ---
// See: https://developer.mozilla.org/en-US/docs/Web/API/Element/matches#Polyfill
/* istanbul ignore next */
var matchesEl = elProto.matches || elProto.msMatchesSelector || elProto.webkitMatchesSelector; // See: https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
/* istanbul ignore next */
var closestEl = elProto.closest || function (sel) {
var el = this;
do {
// Use our "patched" matches function
if (matches(el, sel)) {
return el;
}
el = el.parentElement || el.parentNode;
} while (!isNull(el) && el.nodeType === Node.ELEMENT_NODE);
return null;
}; // `requestAnimationFrame()` convenience method
/* istanbul ignore next: JSDOM always returns the first option */
var requestAF = w$1.requestAnimationFrame || w$1.webkitRequestAnimationFrame || w$1.mozRequestAnimationFrame || w$1.msRequestAnimationFrame || w$1.oRequestAnimationFrame || // Fallback, but not a true polyfill
// Only needed for Opera Mini
/* istanbul ignore next */
function (cb) {
return setTimeout(cb, 16);
};
var MutationObs = w$1.MutationObserver || w$1.WebKitMutationObserver || w$1.MozMutationObserver || null; // --- Utils ---
// Remove a node from DOM
var removeNode = function removeNode(el) {
return el && el.parentNode && el.parentNode.removeChild(el);
}; // Determine if an element is an HTML element
var isElement = function isElement(el) {
return !!(el && el.nodeType === Node.ELEMENT_NODE);
}; // Get the currently active HTML element
var getActiveElement = function getActiveElement() {
var excludes = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var activeElement = d.activeElement;
return activeElement && !excludes.some(function (el) {
return el === activeElement;
}) ? activeElement : null;
}; // Returns `true` if a tag's name equals `name`
var isTag = function isTag(tag, name) {
return toString$1(tag).toLowerCase() === toString$1(name).toLowerCase();
}; // Determine if an HTML element is the currently active element
var isActiveElement = function isActiveElement(el) {
return isElement(el) && el === getActiveElement();
}; // Determine if an HTML element is visible - Faster than CSS check
var isVisible = function isVisible(el) {
if (!isElement(el) || !el.parentNode || !contains(d.body, el)) {
// Note this can fail for shadow dom elements since they
// are not a direct descendant of document.body
return false;
}
if (getStyle(el, 'display') === 'none') {
// We do this check to help with vue-test-utils when using v-show
/* istanbul ignore next */
return false;
} // All browsers support getBoundingClientRect(), except JSDOM as it returns all 0's for values :(
// So any tests that need isVisible will fail in JSDOM
// Except when we override the getBCR prototype in some tests
var bcr = getBCR(el);
return !!(bcr && bcr.height > 0 && bcr.width > 0);
}; // Determine if an element is disabled
var isDisabled = function isDisabled(el) {
return !isElement(el) || el.disabled || hasAttr(el, 'disabled') || hasClass(el, 'disabled');
}; // Cause/wait-for an element to reflow its content (adjusting its height/width)
var reflow = function reflow(el) {
// Requesting an elements offsetHight will trigger a reflow of the element content
/* istanbul ignore next: reflow doesn't happen in JSDOM */
return isElement(el) && el.offsetHeight;
}; // Select all elements matching selector. Returns `[]` if none found
var selectAll = function selectAll(selector, root) {
return from((isElement(root) ? root : d).querySelectorAll(selector));
}; // Select a single element, returns `null` if not found
var select = function select(selector, root) {
return (isElement(root) ? root : d).querySelector(selector) || null;
}; // Determine if an element matches a selector
var matches = function matches(el, selector) {
return isElement(el) ? matchesEl.call(el, selector) : false;
}; // Finds closest element matching selector. Returns `null` if not found
var closest = function closest(selector, root) {
var includeRoot = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
if (!isElement(root)) {
return null;
}
var el = closestEl.call(root, selector); // Native closest behaviour when `includeRoot` is truthy,
// else emulate jQuery closest and return `null` if match is
// the passed in root element when `includeRoot` is falsey
return includeRoot ? el : el === root ? null : el;
}; // Returns true if the parent element contains the child element
var contains = function contains(parent, child) {
return parent && isFunction(parent.contains) ? parent.contains(child) : false;
}; // Get an element given an ID
var getById = function getById(id) {
return d.getElementById(/^#/.test(id) ? id.slice(1) : id) || null;
}; // Add a class to an element
var addClass = function addClass(el, className) {
// We are checking for `el.classList` existence here since IE 11
// returns `undefined` for some elements (e.g. SVG elements)
// See https://github.com/bootstrap-vue/bootstrap-vue/issues/2713
if (className && isElement(el) && el.classList) {
el.classList.add(className);
}
}; // Remove a class from an element
var removeClass = function removeClass(el, className) {
// We are checking for `el.classList` existence here since IE 11
// returns `undefined` for some elements (e.g. SVG elements)
// See https://github.com/bootstrap-vue/bootstrap-vue/issues/2713
if (className && isElement(el) && el.classList) {
el.classList.remove(className);
}
}; // Test if an element has a class
var hasClass = function hasClass(el, className) {
// We are checking for `el.classList` existence here since IE 11
// returns `undefined` for some elements (e.g. SVG elements)
// See https://github.com/bootstrap-vue/bootstrap-vue/issues/2713
if (className && isElement(el) && el.classList) {
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) {
return attr && isElement(el) ? el.getAttribute(attr) : 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) {
return attr && isElement(el) ? el.hasAttribute(attr) : null;
}; // Set an style property on an element
var setStyle = function setStyle(el, prop, value) {
if (prop && isElement(el)) {
el.style[prop] = value;
}
}; // Remove an style property from an element
var removeStyle = function removeStyle(el, prop) {
if (prop && isElement(el)) {
el.style[prop] = '';
}
}; // Get an style property value from an element
// Returns `null` if not found
var getStyle = function getStyle(el, prop) {
return prop && isElement(el) ? el.style[prop] || null : null;
}; // Return the Bounding Client Rect of an element
// Returns `null` if not an element
/* istanbul ignore next: getBoundingClientRect() doesn't work in JSDOM */
var getBCR = function getBCR(el) {
return isElement(el) ? el.getBoundingClientRect() : null;
}; // Get computed style object for an element
/* istanbul ignore next: getComputedStyle() doesn't work in JSDOM */
var getCS = function getCS(el) {
return hasWindowSupport && isElement(el) ? w$1.getComputedStyle(el) : {};
}; // Returns a `Selection` object representing the range of text selected
// Returns `null` if no window support is given
/* istanbul ignore next: getSelection() doesn't work in JSDOM */
var getSel = function getSel() {
return hasWindowSupport && w$1.getSelection ? w$1.getSelection() : null;
}; // Return an element's offset with respect to document element
// https://j11y.io/jquery/#v=git&fn=jQuery.fn.offset
var offset = function offset(el)
/* istanbul ignore next: getBoundingClientRect(), getClientRects() doesn't work in JSDOM */
{
var _offset = {
top: 0,
left: 0
};
if (!isElement(el) || el.getClientRects().length === 0) {
return _offset;
}
var bcr = getBCR(el);
if (bcr) {
var win = el.ownerDocument.defaultView;
_offset.top = bcr.top + win.pageYOffset;
_offset.left = bcr.left + win.pageXOffset;
}
return _offset;
}; // Return an element's offset with respect to to its offsetParent
// https://j11y.io/jquery/#v=git&fn=jQuery.fn.position
var position = function position(el)
/* istanbul ignore next: getBoundingClientRect() doesn't work in JSDOM */
{
var _offset = {
top: 0,
left: 0
};
if (!isElement(el)) {
return _offset;
}
var parentOffset = {
top: 0,
left: 0
};
var elStyles = getCS(el);
if (elStyles.position === 'fixed') {
_offset = getBCR(el) || _offset;
} else {
_offset = offset(el);
var doc = el.ownerDocument;
var 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);
var offsetParentStyles = getCS(offsetParent);
parentOffset.top += toFloat(offsetParentStyles.borderTopWidth, 0);
parentOffset.left += toFloat(offsetParentStyles.borderLeftWidth, 0);
}
}
return {
top: _offset.top - parentOffset.top - toFloat(elStyles.marginTop, 0),
left: _offset.left - parentOffset.left - toFloat(elStyles.marginLeft, 0)
};
}; // Find all tabable elements in the given element
// Assumes users have not used `tabindex` > `0` on elements
var getTabables = function getTabables() {
var rootEl = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : document;
return selectAll(TABABLE_SELECTOR, rootEl).filter(isVisible).filter(function (el) {
return el.tabIndex > -1 && !el.disabled;
});
}; // Attempt to focus an element, and return `true` if successful
var attemptFocus = function attemptFocus(el) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
try {
el.focus(options);
} catch (_unused) {}
return isActiveElement(el);
}; // Attempt to blur an element, and return `true` if successful
var attemptBlur = function attemptBlur(el) {
try {
el.blur();
} catch (_unused2) {}
return !isActiveElement(el);
};
var NO_FADE_PROPS = {
name: '',
enterClass: '',
enterActiveClass: '',
enterToClass: 'show',
leaveClass: 'show',
leaveActiveClass: '',
leaveToClass: ''
};
var FADE_PROPS = _objectSpread2(_objectSpread2({}, NO_FADE_PROPS), {}, {
enterActiveClass: 'fade',
leaveActiveClass: 'fade'
}); // @vue/component
var BVTransition = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_TRANSITION,
functional: true,
props: {
noFade: {
// Only applicable to the built in transition
// Has no effect if `trans-props` provided
type: Boolean,
default: false
},
appear: {
// Has no effect if `trans-props` provided
type: Boolean,
default: false
},
mode: {
// Can be overridden by user supplied trans-props
type: String // default: undefined
},
// For user supplied transitions (if needed)
transProps: {
type: Object,
default: null
}
},
render: function render(h, _ref) {
var children = _ref.children,
data = _ref.data,
props = _ref.props;
var transProps = props.transProps;
if (!isPlainObject(transProps)) {
transProps = props.noFade ? NO_FADE_PROPS : FADE_PROPS;
if (props.appear) {
// Default the appear classes to equal the enter classes
transProps = _objectSpread2(_objectSpread2({}, transProps), {}, {
appear: true,
appearClass: transProps.enterClass,
appearActiveClass: transProps.enterActiveClass,
appearToClass: transProps.enterToClass
});
}
}
transProps = _objectSpread2(_objectSpread2({
mode: props.mode
}, transProps), {}, {
// We always need `css` true
css: true
});
return h('transition', // Any transition event listeners will get merged here
a(data, {
props: transProps
}), children);
}
});
var SLOT_NAME_APPEND = 'append';
var SLOT_NAME_BUTTON_CONTENT = 'button-content';
var SLOT_NAME_DEFAULT = 'default';
var SLOT_NAME_DESCRIPTION = 'description';
var SLOT_NAME_FIRST = 'first';
var SLOT_NAME_FOOTER = 'footer';
var SLOT_NAME_HEADER = 'header';
var SLOT_NAME_LABEL = 'label';
var SLOT_NAME_LEAD = 'lead';
var SLOT_NAME_PREPEND = 'prepend';
var SLOT_NAME_TEXT = 'text';
var SLOT_NAME_TITLE = 'title';
// In functional components, `slots` is a function so it must be called
// first before passing to the below methods. `scopedSlots` is always an
// object and may be undefined (for Vue < 2.6.x)
/**
* Returns true if either scoped or unscoped named slot exists
*
* @param {String, Array} name or name[]
* @param {Object} scopedSlots
* @param {Object} slots
* @returns {Array|undefined} VNodes
*/
var hasNormalizedSlot = function hasNormalizedSlot(names) {
var $scopedSlots = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var $slots = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
// Ensure names is an array
names = concat(names).filter(identity); // Returns true if the either a $scopedSlot or $slot exists with the specified name
return names.some(function (name) {
return $scopedSlots[name] || $slots[name];
});
};
/**
* Returns VNodes for named slot either scoped or unscoped
*
* @param {String, Array} name or name[]
* @param {String} scope
* @param {Object} scopedSlots
* @param {Object} slots
* @returns {Array|undefined} VNodes
*/
var normalizeSlot = function normalizeSlot(names) {
var scope = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var $scopedSlots = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var $slots = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
// Ensure names is an array
names = concat(names).filter(identity);
var slot;
for (var i = 0; i < names.length && !slot; i++) {
var name = names[i];
slot = $scopedSlots[name] || $slots[name];
} // Note: in Vue 2.6.x, all named slots are also scoped slots
return isFunction(slot) ? slot(scope) : slot;
}; // Named exports
var normalizeSlotMixin = {
methods: {
hasNormalizedSlot: function hasNormalizedSlot$1() {
var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : SLOT_NAME_DEFAULT;
// Returns true if the either a $scopedSlot or $slot exists with the specified name
// `name` can be a string name or an array of names
return hasNormalizedSlot(name, this.$scopedSlots, this.$slots);
},
normalizeSlot: function normalizeSlot$1() {
var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : SLOT_NAME_DEFAULT;
var scope = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
// Returns an array of rendered VNodes if slot found.
// Returns undefined if not found.
// `name` can be a string name or an array of names
var vNodes = normalizeSlot(name, scope, this.$scopedSlots, this.$slots);
return vNodes ? concat(vNodes) : vNodes;
}
}
};
// Normalize event options based on support of passive option
// Exported only for testing purposes
var parseEventOptions = function parseEventOptions(options) {
/* istanbul ignore else: can't test in JSDOM, as it supports passive */
if (hasPassiveEventSupport) {
return isObject(options) ? options : {
capture: !!options || false
};
} else {
// Need to translate to actual Boolean value
return !!(isObject(options) ? options.capture : options);
}
}; // Attach an event listener to an element
var eventOn = function eventOn(el, evtName, handler, options) {
if (el && el.addEventListener) {
el.addEventListener(evtName, handler, parseEventOptions(options));
}
}; // Remove an event listener from an element
var eventOff = function eventOff(el, evtName, handler, options) {
if (el && el.removeEventListener) {
el.removeEventListener(evtName, handler, parseEventOptions(options));
}
}; // Utility method to add/remove a event listener based on first argument (boolean)
// It passes all other arguments to the `eventOn()` or `eventOff` method
var eventOnOff = function eventOnOff(on) {
var method = on ? eventOn : eventOff;
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
method.apply(void 0, args);
}; // Utility method to prevent the default event handling and propagation
var stopEvent = function stopEvent(evt) {
var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
_ref$preventDefault = _ref.preventDefault,
preventDefault = _ref$preventDefault === void 0 ? true : _ref$preventDefault,
_ref$propagation = _ref.propagation,
propagation = _ref$propagation === void 0 ? true : _ref$propagation,
_ref$immediatePropaga = _ref.immediatePropagation,
immediatePropagation = _ref$immediatePropaga === void 0 ? false : _ref$immediatePropaga;
if (preventDefault) {
evt.preventDefault();
}
if (propagation) {
evt.stopPropagation();
}
if (immediatePropagation) {
evt.stopImmediatePropagation();
}
};
var props = makePropsConfigurable({
content: {
type: String,
default: '&times;'
},
disabled: {
type: Boolean,
default: false
},
ariaLabel: {
type: String,
default: 'Close'
},
textVariant: {
type: String // `textVariant` is `undefined` to inherit the current text color
// default: undefined
}
}, NAME_BUTTON_CLOSE); // @vue/component
var BButtonClose = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_BUTTON_CLOSE,
functional: true,
props: props,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
slots = _ref.slots,
scopedSlots = _ref.scopedSlots;
var $slots = slots();
var $scopedSlots = scopedSlots || {};
var componentData = {
staticClass: 'close',
class: _defineProperty({}, "text-".concat(props.textVariant), props.textVariant),
attrs: {
type: 'button',
disabled: props.disabled,
'aria-label': props.ariaLabel ? String(props.ariaLabel) : null
},
on: {
click: function click(evt) {
// Ensure click on button HTML content is also disabled
/* istanbul ignore if: bug in JSDOM still emits click on inner element */
if (props.disabled && isEvent(evt)) {
stopEvent(evt);
}
}
}
}; // Careful not to override the default slot with innerHTML
if (!hasNormalizedSlot(SLOT_NAME_DEFAULT, $scopedSlots, $slots)) {
componentData.domProps = {
innerHTML: props.content
};
}
return h('button', a(data, componentData), normalizeSlot(SLOT_NAME_DEFAULT, {}, $scopedSlots, $slots));
}
});
var parseCountDown = function parseCountDown(show) {
if (show === '' || isBoolean(show)) {
return 0;
}
show = toInteger(show, 0);
return show > 0 ? show : 0;
}; // Convert `show` value to a boolean
var parseShow = function parseShow(show) {
if (show === '' || show === true) {
return true;
}
if (toInteger(show, 0) < 1) {
// Boolean will always return false for the above comparison
return false;
}
return !!show;
}; // @vue/component
var BAlert = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_ALERT,
mixins: [normalizeSlotMixin],
model: {
prop: 'show',
event: 'input'
},
props: makePropsConfigurable({
variant: {
type: String,
default: 'info'
},
dismissible: {
type: Boolean,
default: false
},
dismissLabel: {
type: String,
default: 'Close'
},
show: {
type: [Boolean, Number, String],
default: false
},
fade: {
type: Boolean,
default: false
}
}, NAME_ALERT),
data: function data() {
return {
countDown: 0,
// If initially shown, we need to set these for SSR
localShow: parseShow(this.show)
};
},
watch: {
show: function show(newVal) {
this.countDown = parseCountDown(newVal);
this.localShow = parseShow(newVal);
},
countDown: function countDown(newVal) {
var _this = this;
this.clearCountDownInterval();
if (isNumeric(this.show)) {
// Ignore if this.show transitions to a boolean value.
this.$emit('dismiss-count-down', newVal);
if (this.show !== newVal) {
// Update the v-model if needed
this.$emit('input', newVal);
}
if (newVal > 0) {
this.localShow = true;
this.$_countDownTimeout = setTimeout(function () {
_this.countDown--;
}, 1000);
} else {
// Slightly delay the hide to allow any UI updates
this.$nextTick(function () {
requestAF(function () {
_this.localShow = false;
});
});
}
}
},
localShow: function localShow(newVal) {
if (!newVal && (this.dismissible || isNumeric(this.show))) {
// Only emit dismissed events for dismissible or auto dismissing alerts
this.$emit('dismissed');
}
if (!isNumeric(this.show) && this.show !== newVal) {
// Only emit booleans if we weren't passed a number via `this.show`
this.$emit('input', newVal);
}
}
},
created: function created() {
// Create private non-reactive props
this.$_filterTimer = null;
this.countDown = parseCountDown(this.show);
this.localShow = parseShow(this.show);
},
mounted: function mounted() {
this.countDown = parseCountDown(this.show);
this.localShow = parseShow(this.show);
},
beforeDestroy: function beforeDestroy() {
this.clearCountDownInterval();
},
methods: {
dismiss: function dismiss() {
this.clearCountDownInterval();
this.countDown = 0;
this.localShow = false;
},
clearCountDownInterval: function clearCountDownInterval() {
clearTimeout(this.$_countDownTimeout);
this.$_countDownTimeout = null;
}
},
render: function render(h) {
var $alert; // undefined
if (this.localShow) {
var $dismissBtn = h();
if (this.dismissible) {
// Add dismiss button
$dismissBtn = h(BButtonClose, {
attrs: {
'aria-label': this.dismissLabel
},
on: {
click: this.dismiss
}
}, [this.normalizeSlot('dismiss')]);
}
$alert = h('div', {
key: this._uid,
staticClass: 'alert',
class: _defineProperty({
'alert-dismissible': this.dismissible
}, "alert-".concat(this.variant), this.variant),
attrs: {
role: 'alert',
'aria-live': 'polite',
'aria-atomic': true
}
}, [$dismissBtn, this.normalizeSlot()]);
$alert = [$alert];
}
return h(BVTransition, {
props: {
noFade: !this.fade
}
}, $alert);
}
});
var AlertPlugin = /*#__PURE__*/pluginFactory({
components: {
BAlert: BAlert
}
});
// Math utilty functions
var mathMin = Math.min;
var mathMax = Math.max;
var mathAbs = Math.abs;
var mathCeil = Math.ceil;
var mathFloor = Math.floor;
var mathPow = Math.pow;
var mathRound = Math.round;
var CLASS_NAME = 'b-aspect'; // --- Main Component ---
var BAspect = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_ASPECT,
mixins: [normalizeSlotMixin],
props: makePropsConfigurable({
aspect: {
// Accepts a number (i.e. `16 / 9`, `1`, `4 / 3`)
// Or a string (i.e. '16/9', '16:9', '4:3' '1:1')
type: [Number, String],
default: '1:1'
},
tag: {
type: String,
default: 'div'
}
}, NAME_ASPECT),
computed: {
padding: function padding() {
var aspect = this.aspect;
var ratio = 1;
if (RX_ASPECT.test(aspect)) {
// Width and/or Height can be a decimal value below `1`, so
// we only fallback to `1` if the value is `0` or `NaN`
var _aspect$split$map = aspect.split(RX_ASPECT_SEPARATOR).map(function (v) {
return toFloat(v) || 1;
}),
_aspect$split$map2 = _slicedToArray(_aspect$split$map, 2),
width = _aspect$split$map2[0],
height = _aspect$split$map2[1];
ratio = width / height;
} else {
ratio = toFloat(aspect) || 1;
}
return "".concat(100 / mathAbs(ratio), "%");
}
},
render: function render(h) {
var $sizer = h('div', {
staticClass: "".concat(CLASS_NAME, "-sizer flex-grow-1"),
style: {
paddingBottom: this.padding,
height: 0
}
});
var $content = h('div', {
staticClass: "".concat(CLASS_NAME, "-content flex-grow-1 w-100 mw-100"),
style: {
marginLeft: '-100%'
}
}, [this.normalizeSlot()]);
return h(this.tag, {
staticClass: "".concat(CLASS_NAME, " d-flex")
}, [$sizer, $content]);
}
});
var AspectPlugin = /*#__PURE__*/pluginFactory({
components: {
BAspect: BAspect
}
});
var prefixPropName = function prefixPropName(prefix, value) {
return prefix + upperFirst(value);
}; // Remove a prefix from a property
var unprefixPropName = function unprefixPropName(prefix, value) {
return lowerFirst(value.replace(prefix, ''));
}; // 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
var suffixPropName = function suffixPropName(suffix, str) {
return str + (suffix ? upperFirst(suffix) : '');
}; // Copies props from one array/object to a new array/object
// Prop values are also cloned as new references to prevent possible
// mutation of original prop object values
// Optionally accepts a function to transform the prop name
var copyProps = function copyProps(props) {
var transformFn = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : identity;
if (isArray(props)) {
return props.map(transformFn);
}
var copied = {};
for (var prop in props) {
/* istanbul ignore else */
if (hasOwnProperty(props, prop)) {
// If the prop value is an object, do a shallow clone
// to prevent potential mutations to the original object
copied[transformFn(prop)] = isObject(props[prop]) ? clone(props[prop]) : props[prop];
}
}
return copied;
}; // Given an array of properties or an object of property keys,
// plucks all the values off the target object, returning a new object
// that has props that reference the original prop values
var pluckProps = 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) {
memo[transformFn(prop)] = objToPluck[prop];
return memo;
}, {});
};
var ANCHOR_TAG = 'a'; // Method to replace reserved chars
var encodeReserveReplacer = function encodeReserveReplacer(c) {
return '%' + c.charCodeAt(0).toString(16);
}; // Fixed encodeURIComponent which is more conformant to RFC3986:
// - escapes [!'()*]
// - preserve commas
var encode = function encode(str) {
return encodeURIComponent(toString$1(str)).replace(RX_ENCODE_REVERSE, encodeReserveReplacer).replace(RX_ENCODED_COMMA, ',');
};
var decode = decodeURIComponent; // Stringifies an object of query parameters
// See: https://github.com/vuejs/vue-router/blob/dev/src/util/query.js
var stringifyQueryObj = function stringifyQueryObj(obj) {
if (!isPlainObject(obj)) {
return '';
}
var query = keys(obj).map(function (key) {
var val = obj[key];
if (isUndefined(val)) {
return '';
} else if (isNull(val)) {
return encode(key);
} else if (isArray(val)) {
return val.reduce(function (results, val2) {
if (isNull(val2)) {
results.push(encode(key));
} else if (!isUndefined(val2)) {
// Faster than string interpolation
results.push(encode(key) + '=' + encode(val2));
}
return results;
}, []).join('&');
} // Faster than string interpolation
return encode(key) + '=' + encode(val);
})
/* must check for length, as we only want to filter empty strings, not things that look falsey! */
.filter(function (x) {
return x.length > 0;
}).join('&');
return query ? "?".concat(query) : '';
};
var parseQuery = function parseQuery(query) {
var parsed = {};
query = toString$1(query).trim().replace(RX_QUERY_START, '');
if (!query) {
return parsed;
}
query.split('&').forEach(function (param) {
var parts = param.replace(RX_PLUS, ' ').split('=');
var key = decode(parts.shift());
var val = parts.length > 0 ? decode(parts.join('=')) : null;
if (isUndefined(parsed[key])) {
parsed[key] = val;
} else if (isArray(parsed[key])) {
parsed[key].push(val);
} else {
parsed[key] = [parsed[key], val];
}
});
return parsed;
};
var isLink = function isLink(props) {
return !!(props.href || props.to);
};
var isRouterLink = function isRouterLink(tag) {
return !!(tag && !isTag(tag, 'a'));
};
var computeTag = function computeTag(_ref, thisOrParent) {
var to = _ref.to,
disabled = _ref.disabled,
routerComponentName = _ref.routerComponentName;
var hasRouter = !!thisOrParent.$router;
if (!hasRouter || hasRouter && (disabled || !to)) {
return ANCHOR_TAG;
} // TODO:
// Check registered components for existence of user supplied router link component name
// We would need to check PascalCase, kebab-case, and camelCase versions of name:
// const name = routerComponentName
// const names = [name, PascalCase(name), KebabCase(name), CamelCase(name)]
// exists = names.some(name => !!thisOrParent.$options.components[name])
// And may want to cache the result for performance or we just let the render fail
// if the component is not registered
return routerComponentName || (thisOrParent.$nuxt ? 'nuxt-link' : 'router-link');
};
var computeRel = function computeRel() {
var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
target = _ref2.target,
rel = _ref2.rel;
return target === '_blank' && isNull(rel) ? 'noopener' : rel || null;
};
var computeHref = function computeHref() {
var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
href = _ref3.href,
to = _ref3.to;
var tag = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ANCHOR_TAG;
var fallback = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '#';
var toFallback = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : '/';
// Return `href` when explicitly provided
if (href) {
return href;
} // We've checked for `$router` in `computeTag()`, so `isRouterLink()` indicates a live router
// When deferring to Vue Router's `<router-link>`, don't use the `href` attribute at all
// We return `null`, and then remove `href` from the attributes passed to `<router-link>`
if (isRouterLink(tag)) {
return null;
} // Fallback to `to` prop (if `to` is a string)
if (isString(to)) {
return to || toFallback;
} // Fallback to `to.path' + `to.query` + `to.hash` prop (if `to` is an object)
if (isPlainObject(to) && (to.path || to.query || to.hash)) {
var path = toString$1(to.path);
var query = stringifyQueryObj(to.query);
var hash = toString$1(to.hash);
hash = !hash || hash.charAt(0) === '#' ? hash : "#".concat(hash);
return "".concat(path).concat(query).concat(hash) || toFallback;
} // If nothing is provided return the fallback
return fallback;
};
var CODE_BACKSPACE = 8;
var CODE_DELETE = 46;
var CODE_DOWN = 40;
var CODE_END = 35;
var CODE_ENTER = 13;
var CODE_ESC = 27;
var CODE_HOME = 36;
var CODE_LEFT = 37;
var CODE_PAGEDOWN = 34;
var CODE_PAGEUP = 33;
var CODE_RIGHT = 39;
var CODE_SPACE = 32;
var CODE_UP = 38;
// Handles when arrays are "sparse" (array.every(...) doesn't handle sparse)
var compareArrays = function compareArrays(a, b) {
if (a.length !== b.length) {
return false;
}
var equal = true;
for (var i = 0; equal && i < a.length; i++) {
equal = looseEqual(a[i], b[i]);
}
return equal;
};
/**
* 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
*/
var looseEqual = function looseEqual(a, b) {
if (a === b) {
return true;
}
var aValidType = isDate(a);
var bValidType = isDate(b);
if (aValidType || bValidType) {
return aValidType && bValidType ? a.getTime() === b.getTime() : false;
}
aValidType = isArray(a);
bValidType = isArray(b);
if (aValidType || bValidType) {
return aValidType && bValidType ? compareArrays(a, b) : false;
}
aValidType = isObject(a);
bValidType = isObject(b);
if (aValidType || bValidType) {
/* istanbul ignore if: this if will probably never be called */
if (!aValidType || !bValidType) {
return false;
}
var aKeysCount = keys(a).length;
var bKeysCount = keys(b).length;
if (aKeysCount !== bKeysCount) {
return false;
}
for (var key in a) {
var aHasKey = hasOwnProperty(a, key);
var bHasKey = hasOwnProperty(b, key);
if (aHasKey && !bHasKey || !aHasKey && bHasKey || !looseEqual(a[key], b[key])) {
return false;
}
}
}
return String(a) === String(b);
};
var isEmpty = function isEmpty(value) {
return !value || keys(value).length === 0;
};
var makePropWatcher = function makePropWatcher(propName) {
return {
handler: function handler(newValue, oldValue) {
if (looseEqual(newValue, oldValue)) {
return;
}
if (isEmpty(newValue) || isEmpty(oldValue)) {
this[propName] = cloneDeep(newValue);
return;
}
for (var key in oldValue) {
if (!hasOwnProperty(newValue, key)) {
this.$delete(this.$data[propName], key);
}
}
for (var _key in newValue) {
this.$set(this.$data[propName], _key, newValue[_key]);
}
}
};
};
var makePropCacheMixin = function makePropCacheMixin(propName, proxyPropName) {
return {
data: function data() {
return _defineProperty({}, proxyPropName, cloneDeep(this[propName]));
},
watch: _defineProperty({}, propName, makePropWatcher(proxyPropName))
};
};
var attrsMixin = makePropCacheMixin('$attrs', 'bvAttrs');
var listenersMixin = makePropCacheMixin('$listeners', 'bvListeners');
// <router-link> specific props
var routerLinkProps = {
to: {
type: [String, Object],
default: null
},
append: {
type: Boolean,
default: false
},
replace: {
type: Boolean,
default: false
},
event: {
type: [String, Array],
default: 'click'
},
activeClass: {
type: String // default: undefined
},
exact: {
type: Boolean,
default: false
},
exactActiveClass: {
type: String // default: undefined
},
routerTag: {
type: String,
default: 'a'
}
}; // <nuxt-link> specific props
var nuxtLinkProps = {
prefetch: {
type: Boolean,
// Must be `null` to fall back to the value defined in the
// `nuxt.config.js` configuration file for `router.prefetchLinks`
// We convert `null` to `undefined`, so that Nuxt.js will use the
// compiled default. Vue treats `undefined` as default of `false`
// for Boolean props, so we must set it as `null` here to be a
// true tri-state prop
default: null
},
noPrefetch: {
type: Boolean,
default: false
}
};
var props$1 = makePropsConfigurable(_objectSpread2(_objectSpread2(_objectSpread2({
href: {
type: String,
default: null
},
rel: {
type: String,
// Must be `null` if no value provided
default: null
},
target: {
type: String,
default: '_self'
},
active: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
}
}, routerLinkProps), nuxtLinkProps), {}, {
// To support 3rd party router links based on `<router-link>` (i.e. `g-link` for Gridsome)
// Default is to auto choose between `<router-link>` and `<nuxt-link>`
// Gridsome doesn't provide a mechanism to auto detect and has caveats
// such as not supporting FQDN URLs or hash only URLs
routerComponentName: {
type: String // default: undefined
}
}), NAME_LINK); // --- Main component ---
// @vue/component
var BLink = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_LINK,
// Mixin order is important!
mixins: [attrsMixin, listenersMixin, normalizeSlotMixin],
inheritAttrs: false,
props: props$1,
computed: {
computedTag: function computedTag() {
// We don't pass `this` as the first arg as we need reactivity of the props
var to = this.to,
disabled = this.disabled,
routerComponentName = this.routerComponentName;
return computeTag({
to: to,
disabled: disabled,
routerComponentName: routerComponentName
}, this);
},
isRouterLink: function isRouterLink$1() {
return isRouterLink(this.computedTag);
},
computedRel: function computedRel() {
// We don't pass `this` as the first arg as we need reactivity of the props
var target = this.target,
rel = this.rel;
return computeRel({
target: target,
rel: rel
});
},
computedHref: function computedHref() {
// We don't pass `this` as the first arg as we need reactivity of the props
var to = this.to,
href = this.href;
return computeHref({
to: to,
href: href
}, this.computedTag);
},
computedProps: function computedProps() {
var prefetch = this.prefetch;
return this.isRouterLink ? _objectSpread2(_objectSpread2({}, pluckProps(_objectSpread2(_objectSpread2({}, routerLinkProps), nuxtLinkProps), this)), {}, {
// Coerce `prefetch` value `null` to be `undefined`
prefetch: isBoolean(prefetch) ? prefetch : undefined,
// Pass `router-tag` as `tag` prop
tag: this.routerTag
}) : {};
},
computedAttrs: function computedAttrs() {
var bvAttrs = this.bvAttrs,
href = this.computedHref,
rel = this.computedRel,
disabled = this.disabled,
target = this.target,
routerTag = this.routerTag,
isRouterLink = this.isRouterLink;
return _objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, bvAttrs), href ? {
href: href
} : {}), isRouterLink && !isTag(routerTag, 'a') ? {} : {
rel: rel,
target: target
}), {}, {
tabindex: disabled ? '-1' : isUndefined(bvAttrs.tabindex) ? null : bvAttrs.tabindex,
'aria-disabled': disabled ? 'true' : null
});
},
computedListeners: function computedListeners() {
return _objectSpread2(_objectSpread2({}, this.bvListeners), {}, {
// We want to overwrite any click handler since our callback
// will invoke the user supplied handler(s) if `!this.disabled`
click: this.onClick
});
}
},
methods: {
onClick: function onClick(evt) {
var _arguments = arguments;
var evtIsEvent = isEvent(evt);
var isRouterLink = this.isRouterLink;
var suppliedHandler = this.bvListeners.click;
if (evtIsEvent && this.disabled) {
// Stop event from bubbling up
// Kill the event loop attached to this specific `EventTarget`
// Needed to prevent `vue-router` for doing its thing
stopEvent(evt, {
immediatePropagation: true
});
} else {
/* istanbul ignore next: difficult to test, but we know it works */
if (isRouterLink && evt.currentTarget.__vue__) {
// Router links do not emit instance `click` events, so we
// add in an `$emit('click', evt)` on its Vue instance
evt.currentTarget.__vue__.$emit('click', evt);
} // Call the suppliedHandler(s), if any provided
concat(suppliedHandler).filter(function (h) {
return isFunction(h);
}).forEach(function (handler) {
handler.apply(void 0, _toConsumableArray(_arguments));
}); // Emit the global `$root` click event
this.$root.$emit('clicked::link', evt);
} // Stop scroll-to-top behavior or navigation on
// regular links when href is just '#'
if (evtIsEvent && !isRouterLink && this.computedHref === '#') {
stopEvent(evt, {
propagation: false
});
}
},
focus: function focus() {
attemptFocus(this.$el);
},
blur: function blur() {
attemptBlur(this.$el);
}
},
render: function render(h) {
var active = this.active,
disabled = this.disabled;
return h(this.computedTag, _defineProperty({
class: {
active: active,
disabled: disabled
},
attrs: this.computedAttrs,
props: this.computedProps
}, this.isRouterLink ? 'nativeOn' : 'on', this.computedListeners), this.normalizeSlot());
}
});
var linkProps = omit(props$1, ['event', 'routerTag']);
delete linkProps.href.default;
delete linkProps.to.default;
var props$2 = makePropsConfigurable(_objectSpread2({
block: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
size: {
type: String // default: null
},
variant: {
type: String,
default: 'secondary'
},
type: {
type: String,
default: 'button'
},
tag: {
type: String,
default: 'button'
},
pill: {
type: Boolean,
default: false
},
squared: {
type: Boolean,
default: false
},
pressed: {
// Tri-state: `true`, `false` or `null`
// => On, off, not a toggle
type: Boolean,
default: null
}
}, linkProps), NAME_BUTTON); // --- Helper methods ---
// Focus handler for toggle buttons
// Needs class of 'focus' when focused
var handleFocus = function handleFocus(evt) {
if (evt.type === 'focusin') {
addClass(evt.target, 'focus');
} else if (evt.type === 'focusout') {
removeClass(evt.target, 'focus');
}
}; // Is the requested button a link?
// If tag prop is set to `a`, we use a <b-link> to get proper disabled handling
var isLink$1 = function isLink$1(props) {
return isLink(props) || isTag(props.tag, 'a');
}; // Is the button to be a toggle button?
var isToggle = function isToggle(props) {
return isBoolean(props.pressed);
}; // Is the button "really" a button?
var isButton = function isButton(props) {
return !(isLink$1(props) || props.tag && !isTag(props.tag, 'button'));
}; // Is the requested tag not a button or link?
var isNonStandardTag = function isNonStandardTag(props) {
return !isLink$1(props) && !isButton(props);
}; // Compute required classes (non static classes)
var computeClass = function computeClass(props) {
var _ref;
return ["btn-".concat(props.variant || 'secondary'), (_ref = {}, _defineProperty(_ref, "btn-".concat(props.size), props.size), _defineProperty(_ref, 'btn-block', props.block), _defineProperty(_ref, 'rounded-pill', props.pill), _defineProperty(_ref, 'rounded-0', props.squared && !props.pill), _defineProperty(_ref, "disabled", props.disabled), _defineProperty(_ref, "active", props.pressed), _ref)];
}; // Compute the link props to pass to b-link (if required)
var computeLinkProps = function computeLinkProps(props) {
return isLink$1(props) ? pluckProps(linkProps, props) : {};
}; // Compute the attributes for a button
var computeAttrs = function computeAttrs(props, data) {
var button = isButton(props);
var link = isLink$1(props);
var toggle = isToggle(props);
var nonStandardTag = isNonStandardTag(props);
var hashLink = link && props.href === '#';
var role = data.attrs && data.attrs.role ? data.attrs.role : null;
var tabindex = data.attrs ? data.attrs.tabindex : null;
if (nonStandardTag || hashLink) {
tabindex = '0';
}
return {
// Type only used for "real" buttons
type: button && !link ? props.type : null,
// Disabled only set on "real" buttons
disabled: button ? props.disabled : null,
// We add a role of button when the tag is not a link or button for ARIA
// Don't bork any role provided in `data.attrs` when `isLink` or `isButton`
// Except when link has `href` of `#`
role: nonStandardTag || hashLink ? 'button' : role,
// We set the `aria-disabled` state for non-standard tags
'aria-disabled': nonStandardTag ? String(props.disabled) : null,
// For toggles, we need to set the pressed state for ARIA
'aria-pressed': toggle ? String(props.pressed) : null,
// `autocomplete="off"` is needed in toggle mode to prevent some browsers
// from remembering the previous setting when using the back button
autocomplete: toggle ? 'off' : null,
// `tabindex` is used when the component is not a button
// Links are tabbable, but don't allow disabled, while non buttons or links
// are not tabbable, so we mimic that functionality by disabling tabbing
// when disabled, and adding a `tabindex="0"` to non buttons or non links
tabindex: props.disabled && !button ? '-1' : tabindex
};
}; // --- Main component ---
// @vue/component
var BButton = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_BUTTON,
functional: true,
props: props$2,
render: function render(h, _ref2) {
var props = _ref2.props,
data = _ref2.data,
listeners = _ref2.listeners,
children = _ref2.children;
var toggle = isToggle(props);
var link = isLink$1(props);
var nonStandardTag = isNonStandardTag(props);
var hashLink = link && props.href === '#';
var on = {
keydown: function keydown(evt) {
// When the link is a `href="#"` or a non-standard tag (has `role="button"`),
// we add a keydown handlers for CODE_SPACE/CODE_ENTER
/* istanbul ignore next */
if (props.disabled || !(nonStandardTag || hashLink)) {
return;
}
var keyCode = evt.keyCode; // Add CODE_SPACE handler for `href="#"` and CODE_ENTER handler for non-standard tags
if (keyCode === CODE_SPACE || keyCode === CODE_ENTER && nonStandardTag) {
var target = evt.currentTarget || evt.target;
stopEvent(evt, {
propagation: false
});
target.click();
}
},
click: function click(evt) {
/* istanbul ignore if: blink/button disabled should handle this */
if (props.disabled && isEvent(evt)) {
stopEvent(evt);
} else if (toggle && listeners && listeners['update:pressed']) {
// Send `.sync` updates to any "pressed" prop (if `.sync` listeners)
// `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 (isFunction(fn)) {
fn(!props.pressed);
}
});
}
}
};
if (toggle) {
on.focusin = handleFocus;
on.focusout = handleFocus;
}
var componentData = {
staticClass: 'btn',
class: computeClass(props),
props: computeLinkProps(props),
attrs: computeAttrs(props, data),
on: on
};
return h(link ? BLink : props.tag, a(data, componentData), children);
}
});
var commonIconProps = {
title: {
type: String // default: null
},
variant: {
type: String,
default: null
},
fontScale: {
type: [Number, String],
default: 1
},
scale: {
type: [Number, String],
default: 1
},
rotate: {
type: [Number, String],
default: 0
},
flipH: {
type: Boolean,
default: false
},
flipV: {
type: Boolean,
default: false
},
shiftH: {
type: [Number, String],
default: 0
},
shiftV: {
type: [Number, String],
default: 0
},
animation: {
type: String,
default: null
}
}; // Base attributes needed on all icons
var baseAttrs = {
viewBox: '0 0 16 16',
width: '1em',
height: '1em',
focusable: 'false',
role: 'img',
'aria-label': 'icon'
}; // Attributes that are nulled out when stacked
var stackedAttrs = {
width: null,
height: null,
focusable: null,
role: null,
'aria-label': null
}; // Shared private base component to reduce bundle/runtime size
// @vue/component
var BVIconBase = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_ICON_BASE,
functional: true,
props: _objectSpread2({
content: {
type: String
},
stacked: {
type: Boolean,
default: false
}
}, commonIconProps),
render: function render(h, _ref) {
var _class;
var data = _ref.data,
props = _ref.props,
children = _ref.children;
var fontScale = mathMax(toFloat(props.fontScale, 1), 0) || 1;
var scale = mathMax(toFloat(props.scale, 1), 0) || 1;
var rotate = toFloat(props.rotate, 0);
var shiftH = toFloat(props.shiftH, 0);
var shiftV = toFloat(props.shiftV, 0);
var flipH = props.flipH;
var flipV = props.flipV;
var animation = props.animation; // Compute the transforms
// Note that order is important as SVG transforms are applied in order from
// left to right and we want flipping/scale to occur before rotation
// Note shifting is applied separately
// Assumes that the viewbox is `0 0 16 16` (`8 8` is the center)
var hasScale = flipH || flipV || scale !== 1;
var hasTransforms = hasScale || rotate;
var hasShift = shiftH || shiftV;
var transforms = [hasTransforms ? 'translate(8 8)' : null, hasScale ? "scale(".concat((flipH ? -1 : 1) * scale, " ").concat((flipV ? -1 : 1) * scale, ")") : null, rotate ? "rotate(".concat(rotate, ")") : null, hasTransforms ? 'translate(-8 -8)' : null].filter(identity); // Handling stacked icons
var isStacked = props.stacked;
var hasContent = !isUndefinedOrNull(props.content); // We wrap the content in a `<g>` for handling the transforms (except shift)
var $inner = h('g', {
attrs: {
transform: transforms.join(' ') || null
},
domProps: hasContent ? {
innerHTML: props.content || ''
} : {}
}, children); // If needed, we wrap in an additional `<g>` in order to handle the shifting
if (hasShift) {
$inner = h('g', {
attrs: {
transform: "translate(".concat(16 * shiftH / 16, " ").concat(-16 * shiftV / 16, ")")
}
}, [$inner]);
}
if (isStacked) {
// Wrap in an additional `<g>` for proper
// animation handling if stacked
$inner = h('g', {}, [$inner]);
}
var $title = props.title ? h('title', props.title) : null;
return h('svg', a({
staticClass: 'b-icon bi',
class: (_class = {}, _defineProperty(_class, "text-".concat(props.variant), !!props.variant), _defineProperty(_class, "b-icon-animation-".concat(animation), !!animation), _class),
attrs: baseAttrs,
style: isStacked ? {} : {
fontSize: fontScale === 1 ? null : "".concat(fontScale * 100, "%")
}
}, // Merge in user supplied data
data, // If icon is stacked, null out some attrs
isStacked ? {
attrs: stackedAttrs
} : {}, // These cannot be overridden by users
{
attrs: {
xmlns: isStacked ? null : 'http://www.w3.org/2000/svg',
fill: 'currentColor'
}
}), [$title, $inner]);
}
});
/**
* Icon component generator function
*
* @param {string} icon name (minus the leading `BIcon`)
* @param {string} raw `innerHTML` for SVG
* @return {VueComponent}
*/
var makeIcon = function makeIcon(name, content) {
// For performance reason we pre-compute some values, so that
// they are not computed on each render of the icon component
var kebabName = kebabCase(name);
var iconName = "BIcon".concat(pascalCase(name));
var iconNameClass = "bi-".concat(kebabName);
var iconTitle = kebabName.replace(/-/g, ' ');
var svgContent = trim(content || ''); // Return the icon component definition
return /*#__PURE__*/Vue__default['default'].extend({
name: iconName,
functional: true,
props: _objectSpread2(_objectSpread2({}, commonIconProps), {}, {
stacked: {
type: Boolean,
default: false
}
}),
render: function render(h, _ref) {
var data = _ref.data,
props = _ref.props;
return h(BVIconBase, a( // Defaults
{
props: {
title: iconTitle
},
attrs: {
'aria-label': iconTitle
}
}, // User data
data, // Required data
{
staticClass: iconNameClass,
props: _objectSpread2(_objectSpread2({}, props), {}, {
content: svgContent
})
}));
}
});
};
// --- BEGIN AUTO-GENERATED FILE ---
var BIconBlank=/*#__PURE__*/makeIcon('Blank','');// --- Bootstrap Icons ---
var BIconCalendar=/*#__PURE__*/makeIcon('Calendar','<path fill-rule="evenodd" d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4H1z"/>');// eslint-disable-next-line
var BIconCalendarFill=/*#__PURE__*/makeIcon('CalendarFill','<path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V5h16V4H0V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5z"/>');// eslint-disable-next-line
var BIconChevronBarLeft=/*#__PURE__*/makeIcon('ChevronBarLeft','<path fill-rule="evenodd" d="M11.854 3.646a.5.5 0 0 1 0 .708L8.207 8l3.647 3.646a.5.5 0 0 1-.708.708l-4-4a.5.5 0 0 1 0-.708l4-4a.5.5 0 0 1 .708 0zM4.5 1a.5.5 0 0 0-.5.5v13a.5.5 0 0 0 1 0v-13a.5.5 0 0 0-.5-.5z"/>');// eslint-disable-next-line
var BIconChevronDoubleLeft=/*#__PURE__*/makeIcon('ChevronDoubleLeft','<path fill-rule="evenodd" d="M8.354 1.646a.5.5 0 0 1 0 .708L2.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z"/><path fill-rule="evenodd" d="M12.354 1.646a.5.5 0 0 1 0 .708L6.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z"/>');// eslint-disable-next-line
var BIconChevronDown=/*#__PURE__*/makeIcon('ChevronDown','<path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z"/>');// eslint-disable-next-line
var BIconChevronLeft=/*#__PURE__*/makeIcon('ChevronLeft','<path fill-rule="evenodd" d="M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z"/>');// eslint-disable-next-line
var BIconChevronUp=/*#__PURE__*/makeIcon('ChevronUp','<path fill-rule="evenodd" d="M7.646 4.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1-.708.708L8 5.707l-5.646 5.647a.5.5 0 0 1-.708-.708l6-6z"/>');// eslint-disable-next-line
var BIconCircleFill=/*#__PURE__*/makeIcon('CircleFill','<circle cx="8" cy="8" r="8"/>');// eslint-disable-next-line
var BIconClock=/*#__PURE__*/makeIcon('Clock','<path fill-rule="evenodd" d="M8 15A7 7 0 1 0 8 1a7 7 0 0 0 0 14zm8-7A8 8 0 1 1 0 8a8 8 0 0 1 16 0z"/><path fill-rule="evenodd" d="M7.5 3a.5.5 0 0 1 .5.5v5.21l3.248 1.856a.5.5 0 0 1-.496.868l-3.5-2A.5.5 0 0 1 7 9V3.5a.5.5 0 0 1 .5-.5z"/>');// eslint-disable-next-line
var BIconClockFill=/*#__PURE__*/makeIcon('ClockFill','<path fill-rule="evenodd" d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8 3.5a.5.5 0 0 0-1 0V9a.5.5 0 0 0 .252.434l3.5 2a.5.5 0 0 0 .496-.868L8 8.71V3.5z"/>');// eslint-disable-next-line
var BIconDash=/*#__PURE__*/makeIcon('Dash','<path fill-rule="evenodd" d="M4 8a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7A.5.5 0 0 1 4 8z"/>');// eslint-disable-next-line
var BIconPersonFill=/*#__PURE__*/makeIcon('PersonFill','<path fill-rule="evenodd" d="M3 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H3zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"/>');// eslint-disable-next-line
var BIconPlus=/*#__PURE__*/makeIcon('Plus','<path fill-rule="evenodd" d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z"/>');// eslint-disable-next-line
var BIconStar=/*#__PURE__*/makeIcon('Star','<path fill-rule="evenodd" d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256 4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73 3.523-3.356c.329-.314.158-.888-.283-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356-.83 4.73zm4.905-2.767l-3.686 1.894.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288l1.847-3.658 1.846 3.658a.525.525 0 0 0 .393.288l4.052.575-2.906 2.77a.564.564 0 0 0-.163.506l.694 3.957-3.686-1.894a.503.503 0 0 0-.461 0z"/>');// eslint-disable-next-line
var BIconStarFill=/*#__PURE__*/makeIcon('StarFill','<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.283.95l-3.523 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>');// eslint-disable-next-line
var BIconStarHalf=/*#__PURE__*/makeIcon('StarHalf','<path fill-rule="evenodd" d="M5.354 5.119L7.538.792A.516.516 0 0 1 8 .5c.183 0 .366.097.465.292l2.184 4.327 4.898.696A.537.537 0 0 1 16 6.32a.55.55 0 0 1-.17.445l-3.523 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256a.519.519 0 0 1-.146.05c-.341.06-.668-.254-.6-.642l.83-4.73L.173 6.765a.55.55 0 0 1-.171-.403.59.59 0 0 1 .084-.302.513.513 0 0 1 .37-.245l4.898-.696zM8 12.027c.08 0 .16.018.232.056l3.686 1.894-.694-3.957a.564.564 0 0 1 .163-.505l2.906-2.77-4.052-.576a.525.525 0 0 1-.393-.288L8.002 2.223 8 2.226v9.8z"/>');// eslint-disable-next-line
var BIconX=/*#__PURE__*/makeIcon('X','<path fill-rule="evenodd" d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"/>');// eslint-disable-next-line
// --- END AUTO-GENERATED FILE ---
var findIconComponent = function findIconComponent(ctx, iconName) {
if (!ctx) {
return null;
}
var components = (ctx.$options || {}).components;
var iconComponent = components[iconName];
return iconComponent || findIconComponent(ctx.$parent, iconName);
}; // Helper BIcon component
// Requires the requested icon component to be installed
var BIcon = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_ICON,
functional: true,
props: makePropsConfigurable(_objectSpread2(_objectSpread2({
icon: {
type: String,
default: null
}
}, commonIconProps), {}, {
stacked: {
type: Boolean,
default: false
}
}), NAME_ICON),
render: function render(h, _ref) {
var data = _ref.data,
props = _ref.props,
parent = _ref.parent;
var icon = pascalCase(trim(props.icon || '')).replace(RX_ICON_PREFIX, ''); // If parent context exists, we check to see if the icon has been registered
// either locally in the parent component, or globally at the `$root` level
// If not registered, we render a blank icon
return h(icon ? findIconComponent(parent, "BIcon".concat(icon)) || BIconBlank : BIconBlank, a(data, {
props: _objectSpread2(_objectSpread2({}, props), {}, {
icon: null
})
}));
}
});
var CLASS_NAME$1 = 'b-avatar';
var SIZES = ['sm', null, 'lg'];
var FONT_SIZE_SCALE = 0.4;
var BADGE_FONT_SIZE_SCALE = FONT_SIZE_SCALE * 0.7; // --- Utility methods ---
var computeSize = function computeSize(value) {
// Parse to number when value is a float-like string
value = isString(value) && RX_NUMBER.test(value) ? toFloat(value, 0) : value; // Convert all numbers to pixel values
return isNumber(value) ? "".concat(value, "px") : value || null;
}; // --- Props ---
var linkProps$1 = omit(props$1, ['active', 'event', 'routerTag']); // --- Main component ---
// @vue/component
var BAvatar = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_AVATAR,
mixins: [normalizeSlotMixin],
inject: {
bvAvatarGroup: {
default: null
}
},
props: makePropsConfigurable(_objectSpread2(_objectSpread2({
src: {
type: String // default: null
},
text: {
type: String // default: null
},
icon: {
type: String // default: null
},
alt: {
type: String,
default: 'avatar'
},
variant: {
type: String,
default: 'secondary'
},
size: {
type: [Number, String] // default: null
},
square: {
type: Boolean,
default: false
},
rounded: {
type: [Boolean, String],
default: false
},
button: {
type: Boolean,
default: false
},
buttonType: {
type: String,
default: 'button'
},
badge: {
type: [Boolean, String],
default: false
},
badgeVariant: {
type: String,
default: 'primary'
},
badgeTop: {
type: Boolean,
default: false
},
badgeLeft: {
type: Boolean,
default: false
},
badgeOffset: {
type: String,
default: '0px'
}
}, linkProps$1), {}, {
ariaLabel: {
type: String // default: null
}
}), NAME_AVATAR),
data: function data() {
return {
localSrc: this.src || null
};
},
computed: {
computedSize: function computedSize() {
// Always use the avatar group size
var bvAvatarGroup = this.bvAvatarGroup;
return computeSize(bvAvatarGroup ? bvAvatarGroup.size : this.size);
},
computedVariant: function computedVariant() {
var bvAvatarGroup = this.bvAvatarGroup;
return bvAvatarGroup && bvAvatarGroup.variant ? bvAvatarGroup.variant : this.variant;
},
computedRounded: function computedRounded() {
var bvAvatarGroup = this.bvAvatarGroup;
var square = bvAvatarGroup && bvAvatarGroup.square ? true : this.square;
var rounded = bvAvatarGroup && bvAvatarGroup.rounded ? bvAvatarGroup.rounded : this.rounded;
return square ? '0' : rounded === '' ? true : rounded || 'circle';
},
fontStyle: function fontStyle() {
var size = this.computedSize;
var fontSize = SIZES.indexOf(size) === -1 ? "calc(".concat(size, " * ").concat(FONT_SIZE_SCALE, ")") : null;
return fontSize ? {
fontSize: fontSize
} : {};
},
marginStyle: function marginStyle() {
var size = this.computedSize,
bvAvatarGroup = this.bvAvatarGroup;
var overlapScale = bvAvatarGroup ? bvAvatarGroup.overlapScale : 0;
var value = size && overlapScale ? "calc(".concat(size, " * -").concat(overlapScale, ")") : null;
return value ? {
marginLeft: value,
marginRight: value
} : {};
},
badgeStyle: function badgeStyle() {
var size = this.computedSize,
badgeTop = this.badgeTop,
badgeLeft = this.badgeLeft,
badgeOffset = this.badgeOffset;
var offset = badgeOffset || '0px';
return {
fontSize: SIZES.indexOf(size) === -1 ? "calc(".concat(size, " * ").concat(BADGE_FONT_SIZE_SCALE, " )") : null,
top: badgeTop ? offset : null,
bottom: badgeTop ? null : offset,
left: badgeLeft ? offset : null,
right: badgeLeft ? null : offset
};
}
},
watch: {
src: function src(newSrc, oldSrc) {
if (newSrc !== oldSrc) {
this.localSrc = newSrc || null;
}
}
},
methods: {
onImgError: function onImgError(evt) {
this.localSrc = null;
this.$emit('img-error', evt);
},
onClick: function onClick(evt) {
this.$emit('click', evt);
}
},
render: function render(h) {
var _class2;
var variant = this.computedVariant,
disabled = this.disabled,
rounded = this.computedRounded,
icon = this.icon,
src = this.localSrc,
text = this.text,
fontStyle = this.fontStyle,
marginStyle = this.marginStyle,
size = this.computedSize,
button = this.button,
type = this.buttonType,
badge = this.badge,
badgeVariant = this.badgeVariant,
badgeStyle = this.badgeStyle;
var link = !button && isLink(this);
var tag = button ? BButton : link ? BLink : 'span';
var alt = this.alt;
var ariaLabel = this.ariaLabel || null;
var $content = null;
if (this.hasNormalizedSlot()) {
// Default slot overrides props
$content = h('span', {
staticClass: 'b-avatar-custom'
}, [this.normalizeSlot()]);
} else if (src) {
$content = h('img', {
style: variant ? {} : {
width: '100%',
height: '100%'
},
attrs: {
src: src,
alt: alt
},
on: {
error: this.onImgError
}
});
$content = h('span', {
staticClass: 'b-avatar-img'
}, [$content]);
} else if (icon) {
$content = h(BIcon, {
props: {
icon: icon
},
attrs: {
'aria-hidden': 'true',
alt: alt
}
});
} else if (text) {
$content = h('span', {
staticClass: 'b-avatar-text',
style: fontStyle
}, [h('span', text)]);
} else {
// Fallback default avatar content
$content = h(BIconPersonFill, {
attrs: {
'aria-hidden': 'true',
alt: alt
}
});
}
var $badge = h();
var hasBadgeSlot = this.hasNormalizedSlot('badge');
if (badge || badge === '' || hasBadgeSlot) {
var badgeText = badge === true ? '' : badge;
$badge = h('span', {
staticClass: 'b-avatar-badge',
class: _defineProperty({}, "badge-".concat(badgeVariant), !!badgeVariant),
style: badgeStyle
}, [hasBadgeSlot ? this.normalizeSlot('badge') : badgeText]);
}
var componentData = {
staticClass: CLASS_NAME$1,
class: (_class2 = {}, _defineProperty(_class2, "".concat(CLASS_NAME$1, "-").concat(size), size && SIZES.indexOf(size) !== -1), _defineProperty(_class2, "badge-".concat(variant), !button && variant), _defineProperty(_class2, "rounded", rounded === true), _defineProperty(_class2, "rounded-".concat(rounded), rounded && rounded !== true), _defineProperty(_class2, "disabled", disabled), _class2),
style: _objectSpread2(_objectSpread2({}, marginStyle), {}, {
width: size,
height: size
}),
attrs: {
'aria-label': ariaLabel || null
},
props: button ? {
variant: variant,
disabled: disabled,
type: type
} : link ? pluckProps(linkProps$1, this) : {},
on: button || link ? {
click: this.onClick
} : {}
};
return h(tag, componentData, [$content, $badge]);
}
});
// @vue/component
var BAvatarGroup = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_AVATAR_GROUP,
mixins: [normalizeSlotMixin],
provide: function provide() {
return {
bvAvatarGroup: this
};
},
props: makePropsConfigurable({
variant: {
// Child avatars will prefer this variant over their own
type: String,
default: null
},
size: {
// Child avatars will always use this over their own size
type: String // default: null
},
overlap: {
type: [Number, String],
default: 0.3
},
square: {
// Child avatars will prefer this prop (if set) over their own
type: Boolean,
default: false
},
rounded: {
// Child avatars will prefer this prop (if set) over their own
type: [Boolean, String],
default: false
},
tag: {
type: String,
default: 'div'
}
}, NAME_AVATAR_GROUP),
computed: {
computedSize: function computedSize() {
return computeSize(this.size);
},
overlapScale: function overlapScale() {
return mathMin(mathMax(toFloat(this.overlap, 0), 0), 1) / 2;
},
paddingStyle: function paddingStyle() {
var value = this.computedSize;
value = value ? "calc(".concat(value, " * ").concat(this.overlapScale, ")") : null;
return value ? {
paddingLeft: value,
paddingRight: value
} : {};
}
},
render: function render(h) {
var $inner = h('div', {
staticClass: 'b-avatar-group-inner',
style: this.paddingStyle
}, [this.normalizeSlot()]);
return h(this.tag, {
staticClass: 'b-avatar-group',
attrs: {
role: 'group'
}
}, [$inner]);
}
});
var AvatarPlugin = /*#__PURE__*/pluginFactory({
components: {
BAvatar: BAvatar,
BAvatarGroup: BAvatarGroup
}
});
var linkProps$2 = omit(props$1, ['event', 'routerTag']);
delete linkProps$2.href.default;
delete linkProps$2.to.default;
var props$3 = makePropsConfigurable(_objectSpread2({
tag: {
type: String,
default: 'span'
},
variant: {
type: String,
default: 'secondary'
},
pill: {
type: Boolean,
default: false
}
}, linkProps$2), NAME_BADGE); // --- Main component ---
// @vue/component
var BBadge = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_BADGE,
functional: true,
props: props$3,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
var link = isLink(props);
var tag = link ? BLink : props.tag;
var componentData = {
staticClass: 'badge',
class: [props.variant ? "badge-".concat(props.variant) : 'badge-secondary', {
'badge-pill': props.pill,
active: props.active,
disabled: props.disabled
}],
props: link ? pluckProps(linkProps$2, props) : {}
};
return h(tag, a(data, componentData), children);
}
});
var BadgePlugin = /*#__PURE__*/pluginFactory({
components: {
BBadge: BBadge
}
});
var stripTags = function stripTags() {
var text = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
return String(text).replace(RX_HTML_TAGS, '');
}; // Generate a `domProps` object for either `innerHTML`, `textContent` or an empty object
var htmlOrText = function htmlOrText(innerHTML, textContent) {
return innerHTML ? {
innerHTML: innerHTML
} : textContent ? {
textContent: textContent
} : {};
};
var props$4 = makePropsConfigurable(_objectSpread2({
text: {
type: String,
default: null
},
html: {
type: String,
default: null
},
ariaCurrent: {
type: String,
default: 'location'
}
}, omit(props$1, ['event', 'routerTag'])), NAME_BREADCRUMB_LINK); // --- Main component ---
// @vue/component
var BBreadcrumbLink = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_BREADCRUMB_LINK,
functional: true,
props: props$4,
render: function render(h, _ref) {
var suppliedProps = _ref.props,
data = _ref.data,
children = _ref.children;
var active = suppliedProps.active;
var tag = active ? 'span' : BLink;
var componentData = {
attrs: {
'aria-current': active ? suppliedProps.ariaCurrent : null
},
props: pluckProps(props$4, suppliedProps)
};
if (!children) {
componentData.domProps = htmlOrText(suppliedProps.html, suppliedProps.text);
}
return h(tag, a(data, componentData), children);
}
});
var BBreadcrumbItem = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_BREADCRUMB_ITEM,
functional: true,
props: makePropsConfigurable(props$4, NAME_BREADCRUMB_ITEM),
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
return h('li', a(data, {
staticClass: 'breadcrumb-item',
class: {
active: props.active
}
}), [h(BBreadcrumbLink, {
props: props
}, children)]);
}
});
var props$5 = makePropsConfigurable({
items: {
type: Array,
default: null
}
}, NAME_BREADCRUMB); // @vue/component
var BBreadcrumb = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_BREADCRUMB,
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 (!isObject(item)) {
item = {
text: toString$1(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(BBreadcrumbItem, {
props: _objectSpread2(_objectSpread2({}, item), {}, {
active: active
})
});
});
}
return h('ol', a(data, {
staticClass: 'breadcrumb'
}), childNodes);
}
});
var BreadcrumbPlugin = /*#__PURE__*/pluginFactory({
components: {
BBreadcrumb: BBreadcrumb,
BBreadcrumbItem: BBreadcrumbItem,
BBreadcrumbLink: BBreadcrumbLink
}
});
var ButtonPlugin = /*#__PURE__*/pluginFactory({
components: {
BButton: BButton,
BBtn: BButton,
BButtonClose: BButtonClose,
BBtnClose: BButtonClose
}
});
var props$6 = makePropsConfigurable(_objectSpread2({
vertical: {
type: Boolean,
default: false
},
size: {
type: String // default: null
},
tag: {
type: String,
default: 'div'
},
ariaRole: {
type: String,
default: 'group'
}
}, pick(props$2, ['size'])), NAME_BUTTON_GROUP); // @vue/component
var BButtonGroup = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_BUTTON_GROUP,
functional: true,
props: props$6,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
return h(props.tag, a(data, {
class: _defineProperty({
'btn-group': !props.vertical,
'btn-group-vertical': props.vertical
}, "btn-group-".concat(props.size), props.size),
attrs: {
role: props.ariaRole
}
}), children);
}
});
var ButtonGroupPlugin = /*#__PURE__*/pluginFactory({
components: {
BButtonGroup: BButtonGroup,
BBtnGroup: BButtonGroup
}
});
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(','); // --- Main component ---
// @vue/component
var BButtonToolbar = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_BUTTON_TOOLBAR,
mixins: [normalizeSlotMixin],
props: makePropsConfigurable({
justify: {
type: Boolean,
default: false
},
keyNav: {
type: Boolean,
default: false
}
}, NAME_BUTTON_TOOLBAR),
mounted: function mounted() {
// Pre-set the tabindexes if the markup does not include
// `tabindex="-1"` on the toolbar items
if (this.keyNav) {
this.getItems();
}
},
methods: {
getItems: function getItems() {
var items = selectAll(ITEM_SELECTOR, this.$el); // Ensure `tabindex="-1"` is set on every item
items.forEach(function (item) {
item.tabIndex = -1;
});
return items.filter(function (el) {
return isVisible(el);
});
},
focusFirst: function focusFirst() {
var items = this.getItems();
attemptFocus(items[0]);
},
focusPrev: function focusPrev(evt) {
var items = this.getItems();
var index = items.indexOf(evt.target);
if (index > -1) {
items = items.slice(0, index).reverse();
attemptFocus(items[0]);
}
},
focusNext: function focusNext(evt) {
var items = this.getItems();
var index = items.indexOf(evt.target);
if (index > -1) {
items = items.slice(index + 1);
attemptFocus(items[0]);
}
},
focusLast: function focusLast() {
var items = this.getItems().reverse();
attemptFocus(items[0]);
},
onFocusin: function onFocusin(evt) {
var $el = this.$el;
if (evt.target === $el && !contains($el, evt.relatedTarget)) {
stopEvent(evt);
this.focusFirst(evt);
}
},
onKeydown: function onKeydown(evt) {
var keyCode = evt.keyCode,
shiftKey = evt.shiftKey;
if (keyCode === CODE_UP || keyCode === CODE_LEFT) {
stopEvent(evt);
shiftKey ? this.focusFirst(evt) : this.focusPrev(evt);
} else if (keyCode === CODE_DOWN || keyCode === CODE_RIGHT) {
stopEvent(evt);
shiftKey ? this.focusLast(evt) : this.focusNext(evt);
}
}
},
render: function render(h) {
return h('div', {
staticClass: 'btn-toolbar',
class: {
'justify-content-between': this.justify
},
attrs: {
role: 'toolbar',
tabindex: this.keyNav ? '0' : null
},
on: this.keyNav ? {
focusin: this.onFocusin,
keydown: this.onKeydown
} : {}
}, [this.normalizeSlot()]);
}
});
var ButtonToolbarPlugin = /*#__PURE__*/pluginFactory({
components: {
BButtonToolbar: BButtonToolbar,
BBtnToolbar: BButtonToolbar
}
});
var CALENDAR_GREGORY = 'gregory';
var CALENDAR_LONG = 'long';
var CALENDAR_NARROW = 'narrow';
var CALENDAR_SHORT = 'short';
var DATE_FORMAT_2_DIGIT = '2-digit';
var DATE_FORMAT_NUMERIC = 'numeric';
// Create or clone a date (`new Date(...)` shortcut)
var createDate = function createDate() {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _construct(Date, args);
}; // Parse a date sting, or Date object, into a Date object (with no time information)
var parseYMD = function parseYMD(date) {
if (isString(date) && RX_DATE.test(date.trim())) {
var _date$split$map = date.split(RX_DATE_SPLIT).map(function (v) {
return toInteger(v, 1);
}),
_date$split$map2 = _slicedToArray(_date$split$map, 3),
year = _date$split$map2[0],
month = _date$split$map2[1],
day = _date$split$map2[2];
return createDate(year, month - 1, day);
} else if (isDate(date)) {
return createDate(date.getFullYear(), date.getMonth(), date.getDate());
}
return null;
}; // Format a date object as `YYYY-MM-DD` format
var formatYMD = function formatYMD(date) {
date = parseYMD(date);
if (!date) {
return null;
}
var year = date.getFullYear();
var month = "0".concat(date.getMonth() + 1).slice(-2);
var day = "0".concat(date.getDate()).slice(-2);
return "".concat(year, "-").concat(month, "-").concat(day);
}; // Given a locale (or locales), resolve the browser available locale
var resolveLocale = function resolveLocale(locales)
/* istanbul ignore next */
{
var calendar = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : CALENDAR_GREGORY;
locales = concat(locales).filter(identity);
var fmt = new Intl.DateTimeFormat(locales, {
calendar: calendar
});
return fmt.resolvedOptions().locale;
}; // Create a `Intl.DateTimeFormat` formatter function
var createDateFormatter = function createDateFormatter(locale, options)
/* istanbul ignore next */
{
var dtf = new Intl.DateTimeFormat(locale, options);
return dtf.format;
}; // Determine if two dates are the same date (ignoring time portion)
var datesEqual = function datesEqual(date1, date2) {
// Returns true of the date portion of two date objects are equal
// We don't compare the time portion
return formatYMD(date1) === formatYMD(date2);
}; // --- Date "math" utility methods (for BCalendar component mainly) ---
var firstDateOfMonth = function firstDateOfMonth(date) {
date = createDate(date);
date.setDate(1);
return date;
};
var lastDateOfMonth = function lastDateOfMonth(date) {
date = createDate(date);
date.setMonth(date.getMonth() + 1);
date.setDate(0);
return date;
};
var addYears = function addYears(date, numberOfYears) {
date = createDate(date);
var month = date.getMonth();
date.setFullYear(date.getFullYear() + numberOfYears); // Handle Feb 29th for leap years
if (date.getMonth() !== month) {
date.setDate(0);
}
return date;
};
var oneMonthAgo = function oneMonthAgo(date) {
date = createDate(date);
var month = date.getMonth();
date.setMonth(month - 1); // Handle when days in month are different
if (date.getMonth() === month) {
date.setDate(0);
}
return date;
};
var oneMonthAhead = function oneMonthAhead(date) {
date = createDate(date);
var month = date.getMonth();
date.setMonth(month + 1); // Handle when days in month are different
if (date.getMonth() === (month + 2) % 12) {
date.setDate(0);
}
return date;
};
var oneYearAgo = function oneYearAgo(date) {
return addYears(date, -1);
};
var oneYearAhead = function oneYearAhead(date) {
return addYears(date, 1);
};
var oneDecadeAgo = function oneDecadeAgo(date) {
return addYears(date, -10);
};
var oneDecadeAhead = function oneDecadeAhead(date) {
return addYears(date, 10);
}; // Helper function to constrain a date between two values
// Always returns a `Date` object or `null` if no date passed
var constrainDate = function constrainDate(date) {
var min = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
var max = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
// Ensure values are `Date` objects (or `null`)
date = parseYMD(date);
min = parseYMD(min) || date;
max = parseYMD(max) || date; // Return a new `Date` object (or `null`)
return date ? date < min ? min : date > max ? max : date : null;
};
// Localization utilities
var RTL_LANGS = ['ar', 'az', 'ckb', 'fa', 'he', 'ks', 'lrc', 'mzn', 'ps', 'sd', 'te', 'ug', 'ur', 'yi'].map(function (locale) {
return locale.toLowerCase();
}); // Returns true if the locale is RTL
var isLocaleRTL = function isLocaleRTL(locale) {
// Determines if the locale is RTL (only single locale supported)
var parts = toString$1(locale).toLowerCase().replace(RX_STRIP_LOCALE_MODS, '').split('-');
var locale1 = parts.slice(0, 2).join('-');
var locale2 = parts[0];
return arrayIncludes(RTL_LANGS, locale1) || arrayIncludes(RTL_LANGS, locale2);
};
// SSR safe client-side ID attribute generation
// ID's can only be generated client-side, after mount
// `this._uid` is not synched between server and client
// @vue/component
var idMixin = {
props: {
id: {
type: String // default: null
}
},
data: function data() {
return {
localId_: null
};
},
computed: {
safeId: function safeId() {
// Computed property that returns a dynamic function for creating the ID
// Reacts to changes in both `.id` and `.localId_` and regenerates a new function
var id = this.id || this.localId_; // We return a function that accepts an optional suffix string
// So this computed prop looks and works like a method
// but benefits from Vue's computed prop caching
var fn = function fn(suffix) {
if (!id) {
return null;
}
suffix = String(suffix || '').replace(/\s+/g, '_');
return suffix ? id + '_' + suffix : id;
};
return fn;
}
},
mounted: function mounted() {
var _this = this;
// `mounted()` only occurs client-side
this.$nextTick(function () {
// Update DOM with auto-generated ID after mount
// to prevent SSR hydration errors
_this.localId_ = "__BVID__".concat(_this._uid);
});
}
};
var props$7 = makePropsConfigurable({
value: {
type: [String, Date] // default: null
},
valueAsDate: {
// Always return the `v-model` value as a date object
type: Boolean,
default: false
},
initialDate: {
// This specifies the calendar year/month/day that will be shown when
// first opening the datepicker if no v-model value is provided
// Default is the current date (or `min`/`max`)
type: [String, Date] // default: null
},
disabled: {
type: Boolean,
default: false
},
readonly: {
type: Boolean,
default: false
},
min: {
type: [String, Date] // default: null
},
max: {
type: [String, Date] // default: null
},
dateDisabledFn: {
type: Function // default: null
},
startWeekday: {
// `0` (Sunday), `1` (Monday), ... `6` (Saturday)
// Day of week to start calendar on
type: [Number, String],
default: 0
},
locale: {
// Locale(s) to use
// Default is to use page/browser default setting
type: [String, Array] // default: null
},
direction: {
// 'ltr', 'rtl', or `null` (for auto detect)
type: String // default: null
},
selectedVariant: {
// Variant color to use for the selected date
type: String,
default: 'primary'
},
todayVariant: {
// Variant color to use for today's date (defaults to `selectedVariant`)
type: String // default: null
},
navButtonVariant: {
// Variant color to use for the navigation buttons
type: String,
default: 'secondary'
},
noHighlightToday: {
// Disable highlighting today's date
type: Boolean,
default: false
},
dateInfoFn: {
// Function to set a class of (classes) on the date cell
// if passed a string or an array
// TODO:
// If the function returns an object, look for class prop for classes,
// and other props for handling events/details/descriptions
type: Function // default: null
},
width: {
// Has no effect if prop `block` is set
type: String,
default: '270px'
},
block: {
// Makes calendar the full width of its parent container
type: Boolean,
default: false
},
hideHeader: {
// When true makes the selected date header `sr-only`
type: Boolean,
default: false
},
showDecadeNav: {
// When `true` enables the decade navigation buttons
type: Boolean,
default: false
},
hidden: {
// When `true`, renders a comment node, but keeps the component instance active
// Mainly for <b-form-date>, so that we can get the component's value and locale
// But we might just use separate date formatters, using the resolved locale
// (adjusted for the gregorian calendar)
type: Boolean,
default: false
},
ariaControls: {
type: String // default: null
},
noKeyNav: {
type: Boolean,
default: false
},
roleDescription: {
type: String // default: null
},
// Labels for buttons and keyboard shortcuts
labelPrevDecade: {
type: String,
default: 'Previous decade'
},
labelPrevYear: {
type: String,
default: 'Previous year'
},
labelPrevMonth: {
type: String,
default: 'Previous month'
},
labelCurrentMonth: {
type: String,
default: 'Current month'
},
labelNextMonth: {
type: String,
default: 'Next month'
},
labelNextYear: {
type: String,
default: 'Next year'
},
labelNextDecade: {
type: String,
default: 'Next decade'
},
labelToday: {
type: String,
default: 'Today'
},
labelSelected: {
type: String,
default: 'Selected date'
},
labelNoDateSelected: {
type: String,
default: 'No date selected'
},
labelCalendar: {
type: String,
default: 'Calendar'
},
labelNav: {
type: String,
default: 'Calendar navigation'
},
labelHelp: {
type: String,
default: 'Use cursor keys to navigate calendar dates'
},
dateFormatOptions: {
// `Intl.DateTimeFormat` object
// Note: This value is *not* to be placed in the global config
type: Object,
default: function _default() {
return {
year: DATE_FORMAT_NUMERIC,
month: CALENDAR_LONG,
day: DATE_FORMAT_NUMERIC,
weekday: CALENDAR_LONG
};
}
},
weekdayHeaderFormat: {
// Format of the weekday names at the top of the calendar
// Note: This value is *not* to be placed in the global config
type: String,
// `short` is typically a 3 letter abbreviation,
// `narrow` is typically a single letter
// `long` is the full week day name
// Although some locales may override this (i.e `ar`, etc.)
default: CALENDAR_SHORT,
validator: function validator(value) {
return arrayIncludes([CALENDAR_LONG, CALENDAR_SHORT, CALENDAR_NARROW], value);
}
}
}, NAME_CALENDAR); // --- Main component ---
// @vue/component
var BCalendar = Vue__default['default'].extend({
name: NAME_CALENDAR,
// Mixin order is important!
mixins: [attrsMixin, idMixin, normalizeSlotMixin],
model: {
// Even though this is the default that Vue assumes, we need
// to add it for the docs to reflect that this is the model
// And also for some validation libraries to work
prop: 'value',
event: 'input'
},
props: props$7,
data: function data() {
var selected = formatYMD(this.value) || '';
return {
// Selected date
selectedYMD: selected,
// Date in calendar grid that has `tabindex` of `0`
activeYMD: selected || formatYMD(constrainDate(this.initialDate || this.getToday()), this.min, this.max),
// Will be true if the calendar grid has/contains focus
gridHasFocus: false,
// Flag to enable the `aria-live` region(s) after mount
// to prevent screen reader "outbursts" when mounting
isLive: false
};
},
computed: {
valueId: function valueId() {
return this.safeId();
},
widgetId: function widgetId() {
return this.safeId('_calendar-wrapper_');
},
navId: function navId() {
return this.safeId('_calendar-nav_');
},
gridId: function gridId() {
return this.safeId('_calendar-grid_');
},
gridCaptionId: function gridCaptionId() {
return this.safeId('_calendar-grid-caption_');
},
gridHelpId: function gridHelpId() {
return this.safeId('_calendar-grid-help_');
},
activeId: function activeId() {
return this.activeYMD ? this.safeId("_cell-".concat(this.activeYMD, "_")) : null;
},
// TODO: Use computed props to convert `YYYY-MM-DD` to `Date` object
selectedDate: function selectedDate() {
// Selected as a `Date` object
return parseYMD(this.selectedYMD);
},
activeDate: function activeDate() {
// Active as a `Date` object
return parseYMD(this.activeYMD);
},
computedMin: function computedMin() {
return parseYMD(this.min);
},
computedMax: function computedMax() {
return parseYMD(this.max);
},
computedWeekStarts: function computedWeekStarts() {
// `startWeekday` is a prop (constrained to `0` through `6`)
return mathMax(toInteger(this.startWeekday, 0), 0) % 7;
},
computedLocale: function computedLocale() {
// Returns the resolved locale used by the calendar
return resolveLocale(concat(this.locale).filter(identity), CALENDAR_GREGORY);
},
computedDateDisabledFn: function computedDateDisabledFn() {
var dateDisabledFn = this.dateDisabledFn;
var result = null;
try {
result = dateDisabledFn();
} catch (_unused) {}
return isUndefined(result) ? function () {
return false;
} : dateDisabledFn;
},
// TODO: Change `dateInfoFn` to handle events and notes as well as classes
computedDateInfoFn: function computedDateInfoFn() {
var dateInfoFn = this.dateInfoFn;
var result = null;
try {
result = dateInfoFn();
} catch (_unused2) {}
return isUndefined(result) ? function () {
return {};
} : dateInfoFn;
},
calendarLocale: function calendarLocale() {
// This locale enforces the gregorian calendar (for use in formatter functions)
// Needed because IE 11 resolves `ar-IR` as islamic-civil calendar
// and IE 11 (and some other browsers) do not support the `calendar` option
// And we currently only support the gregorian calendar
var fmt = new Intl.DateTimeFormat(this.computedLocale, {
calendar: CALENDAR_GREGORY
});
var calendar = fmt.resolvedOptions().calendar;
var locale = fmt.resolvedOptions().locale;
/* istanbul ignore if: mainly for IE 11 and a few other browsers, hard to test in JSDOM */
if (calendar !== CALENDAR_GREGORY) {
// Ensure the locale requests the gregorian calendar
// Mainly for IE 11, and currently we can't handle non-gregorian calendars
// TODO: Should we always return this value?
locale = locale.replace(/-u-.+$/i, '').concat('-u-ca-gregory');
}
return locale;
},
calendarYear: function calendarYear() {
return this.activeDate.getFullYear();
},
calendarMonth: function calendarMonth() {
return this.activeDate.getMonth();
},
calendarFirstDay: function calendarFirstDay() {
// We set the time for this date to 12pm to work around
// date formatting issues in Firefox and Safari
// See: https://github.com/bootstrap-vue/bootstrap-vue/issues/5818
return createDate(this.calendarYear, this.calendarMonth, 1, 12);
},
calendarDaysInMonth: function calendarDaysInMonth() {
// We create a new date as to not mutate the original
var date = createDate(this.calendarFirstDay);
date.setMonth(date.getMonth() + 1, 0);
return date.getDate();
},
computedVariant: function computedVariant() {
return "btn-".concat(this.selectedVariant || 'primary');
},
computedTodayVariant: function computedTodayVariant() {
return "btn-outline-".concat(this.todayVariant || this.selectedVariant || 'primary');
},
computedNavButtonVariant: function computedNavButtonVariant() {
return "btn-outline-".concat(this.navButtonVariant || 'primary');
},
isRTL: function isRTL() {
// `true` if the language requested is RTL
var dir = toString$1(this.direction).toLowerCase();
if (dir === 'rtl') {
/* istanbul ignore next */
return true;
} else if (dir === 'ltr') {
/* istanbul ignore next */
return false;
}
return isLocaleRTL(this.computedLocale);
},
context: function context() {
var selectedYMD = this.selectedYMD,
activeYMD = this.activeYMD;
var selectedDate = parseYMD(selectedYMD);
var activeDate = parseYMD(activeYMD);
return {
// The current value of the `v-model`
selectedYMD: selectedYMD,
selectedDate: selectedDate,
selectedFormatted: selectedDate ? this.formatDateString(selectedDate) : this.labelNoDateSelected,
// Which date cell is considered active due to navigation
activeYMD: activeYMD,
activeDate: activeDate,
activeFormatted: activeDate ? this.formatDateString(activeDate) : '',
// `true` if the date is disabled (when using keyboard navigation)
disabled: this.dateDisabled(activeDate),
// Locales used in formatting dates
locale: this.computedLocale,
calendarLocale: this.calendarLocale,
rtl: this.isRTL
};
},
// Computed props that return a function reference
dateOutOfRange: function dateOutOfRange() {
// Check whether a date is within the min/max range
// Returns a new function ref if the pops change
// We do this as we need to trigger the calendar computed prop
// to update when these props update
var min = this.computedMin,
max = this.computedMax;
return function (date) {
// Handle both `YYYY-MM-DD` and `Date` objects
date = parseYMD(date);
return min && date < min || max && date > max;
};
},
dateDisabled: function dateDisabled() {
var _this = this;
// Returns a function for validating if a date is within range
// We grab this variables first to ensure a new function ref
// is generated when the props value changes
// We do this as we need to trigger the calendar computed prop
// to update when these props update
var rangeFn = this.dateOutOfRange; // Return the function ref
return function (date) {
// Handle both `YYYY-MM-DD` and `Date` objects
date = parseYMD(date);
var ymd = formatYMD(date);
return !!(rangeFn(date) || _this.computedDateDisabledFn(ymd, date));
};
},
// Computed props that return date formatter functions
formatDateString: function formatDateString() {
// Returns a date formatter function
return createDateFormatter(this.calendarLocale, _objectSpread2(_objectSpread2({
// Ensure we have year, month, day shown for screen readers/ARIA
// If users really want to leave one of these out, they can
// pass `undefined` for the property value
year: DATE_FORMAT_NUMERIC,
month: DATE_FORMAT_2_DIGIT,
day: DATE_FORMAT_2_DIGIT
}, this.dateFormatOptions), {}, {
// Ensure hours/minutes/seconds are not shown
// As we do not support the time portion (yet)
hour: undefined,
minute: undefined,
second: undefined,
// Ensure calendar is gregorian
calendar: CALENDAR_GREGORY
}));
},
formatYearMonth: function formatYearMonth() {
// Returns a date formatter function
return createDateFormatter(this.calendarLocale, {
year: DATE_FORMAT_NUMERIC,
month: CALENDAR_LONG,
calendar: CALENDAR_GREGORY
});
},
formatWeekdayName: function formatWeekdayName() {
// Long weekday name for weekday header aria-label
return createDateFormatter(this.calendarLocale, {
weekday: CALENDAR_LONG,
calendar: CALENDAR_GREGORY
});
},
formatWeekdayNameShort: function formatWeekdayNameShort() {
// Weekday header cell format
// defaults to 'short' 3 letter days, where possible
return createDateFormatter(this.calendarLocale, {
weekday: this.weekdayHeaderFormat || CALENDAR_SHORT,
calendar: CALENDAR_GREGORY
});
},
formatDay: function formatDay() {
// Calendar grid day number formatter
// We don't use DateTimeFormatter here as it can place extra
// character(s) after the number (i.e the `zh` locale)
var nf = new Intl.NumberFormat([this.computedLocale], {
style: 'decimal',
minimumIntegerDigits: 1,
minimumFractionDigits: 0,
maximumFractionDigits: 0,
notation: 'standard'
}); // Return a formatter function instance
return function (date) {
return nf.format(date.getDate());
};
},
// Disabled states for the nav buttons
prevDecadeDisabled: function prevDecadeDisabled() {
var min = this.computedMin;
return this.disabled || min && lastDateOfMonth(oneDecadeAgo(this.activeDate)) < min;
},
prevYearDisabled: function prevYearDisabled() {
var min = this.computedMin;
return this.disabled || min && lastDateOfMonth(oneYearAgo(this.activeDate)) < min;
},
prevMonthDisabled: function prevMonthDisabled() {
var min = this.computedMin;
return this.disabled || min && lastDateOfMonth(oneMonthAgo(this.activeDate)) < min;
},
thisMonthDisabled: function thisMonthDisabled() {
// TODO: We could/should check if today is out of range
return this.disabled;
},
nextMonthDisabled: function nextMonthDisabled() {
var max = this.computedMax;
return this.disabled || max && firstDateOfMonth(oneMonthAhead(this.activeDate)) > max;
},
nextYearDisabled: function nextYearDisabled() {
var max = this.computedMax;
return this.disabled || max && firstDateOfMonth(oneYearAhead(this.activeDate)) > max;
},
nextDecadeDisabled: function nextDecadeDisabled() {
var max = this.computedMax;
return this.disabled || max && firstDateOfMonth(oneDecadeAhead(this.activeDate)) > max;
},
// Calendar dates generation
calendar: function calendar() {
var matrix = [];
var firstDay = this.calendarFirstDay;
var calendarYear = firstDay.getFullYear();
var calendarMonth = firstDay.getMonth();
var daysInMonth = this.calendarDaysInMonth;
var startIndex = firstDay.getDay(); // `0`..`6`
var weekOffset = (this.computedWeekStarts > startIndex ? 7 : 0) - this.computedWeekStarts; // Build the calendar matrix
var currentDay = 0 - weekOffset - startIndex;
for (var week = 0; week < 6 && currentDay < daysInMonth; week++) {
// For each week
matrix[week] = []; // The following could be a map function
for (var j = 0; j < 7; j++) {
// For each day in week
currentDay++;
var date = createDate(calendarYear, calendarMonth, currentDay);
var month = date.getMonth();
var dayYMD = formatYMD(date);
var dayDisabled = this.dateDisabled(date); // TODO: This could be a normalizer method
var dateInfo = this.computedDateInfoFn(dayYMD, parseYMD(dayYMD));
dateInfo = isString(dateInfo) || isArray(dateInfo) ?
/* istanbul ignore next */
{
class: dateInfo
} : isPlainObject(dateInfo) ? _objectSpread2({
class: ''
}, dateInfo) :
/* istanbul ignore next */
{
class: ''
};
matrix[week].push({
ymd: dayYMD,
// Cell content
day: this.formatDay(date),
label: this.formatDateString(date),
// Flags for styling
isThisMonth: month === calendarMonth,
isDisabled: dayDisabled,
// TODO: Handle other dateInfo properties such as notes/events
info: dateInfo
});
}
}
return matrix;
},
calendarHeadings: function calendarHeadings() {
var _this2 = this;
return this.calendar[0].map(function (d) {
return {
text: _this2.formatWeekdayNameShort(parseYMD(d.ymd)),
label: _this2.formatWeekdayName(parseYMD(d.ymd))
};
});
}
},
watch: {
value: function value(newVal, oldVal) {
var selected = formatYMD(newVal) || '';
var old = formatYMD(oldVal) || '';
if (!datesEqual(selected, old)) {
this.activeYMD = selected || this.activeYMD;
this.selectedYMD = selected;
}
},
selectedYMD: function selectedYMD(newYMD, oldYMD) {
// TODO:
// Should we compare to `formatYMD(this.value)` and emit
// only if they are different?
if (newYMD !== oldYMD) {
this.$emit('input', this.valueAsDate ? parseYMD(newYMD) || null : newYMD || '');
}
},
context: function context(newVal, oldVal) {
if (!looseEqual(newVal, oldVal)) {
this.$emit('context', newVal);
}
},
hidden: function hidden(newVal) {
// Reset the active focused day when hidden
this.activeYMD = this.selectedYMD || formatYMD(this.value || this.constrainDate(this.initialDate || this.getToday())); // Enable/disable the live regions
this.setLive(!newVal);
}
},
created: function created() {
var _this3 = this;
this.$nextTick(function () {
_this3.$emit('context', _this3.context);
});
},
mounted: function mounted() {
this.setLive(true);
},
/* istanbul ignore next */
activated: function activated() {
this.setLive(true);
},
/* istanbul ignore next */
deactivated: function deactivated() {
this.setLive(false);
},
beforeDestroy: function beforeDestroy() {
this.setLive(false);
},
methods: {
// Public method(s)
focus: function focus() {
if (!this.disabled) {
attemptFocus(this.$refs.grid);
}
},
blur: function blur() {
if (!this.disabled) {
attemptBlur(this.$refs.grid);
}
},
// Private methods
setLive: function setLive(on) {
var _this4 = this;
if (on) {
this.$nextTick(function () {
requestAF(function () {
_this4.isLive = true;
});
});
} else {
this.isLive = false;
}
},
getToday: function getToday() {
return parseYMD(createDate());
},
constrainDate: function constrainDate$1(date) {
// Constrains a date between min and max
// returns a new `Date` object instance
return constrainDate(date, this.computedMin, this.computedMax);
},
emitSelected: function emitSelected(date) {
var _this5 = this;
// Performed in a `$nextTick()` to (probably) ensure
// the input event has emitted first
this.$nextTick(function () {
_this5.$emit('selected', formatYMD(date) || '', parseYMD(date) || null);
});
},
// Event handlers
setGridFocusFlag: function setGridFocusFlag(evt) {
// Sets the gridHasFocus flag to make date "button" look focused
this.gridHasFocus = !this.disabled && evt.type === 'focus';
},
onKeydownWrapper: function onKeydownWrapper(evt) {
// Calendar keyboard navigation
// Handles PAGEUP/PAGEDOWN/END/HOME/LEFT/UP/RIGHT/DOWN
// Focuses grid after updating
if (this.noKeyNav) {
/* istanbul ignore next */
return;
}
var altKey = evt.altKey,
ctrlKey = evt.ctrlKey,
keyCode = evt.keyCode;
if (!arrayIncludes([CODE_PAGEUP, CODE_PAGEDOWN, CODE_END, CODE_HOME, CODE_LEFT, CODE_UP, CODE_RIGHT, CODE_DOWN], keyCode)) {
/* istanbul ignore next */
return;
}
stopEvent(evt);
var activeDate = createDate(this.activeDate);
var checkDate = createDate(this.activeDate);
var day = activeDate.getDate();
var constrainedToday = this.constrainDate(this.getToday());
var isRTL = this.isRTL;
if (keyCode === CODE_PAGEUP) {
// PAGEUP - Previous month/year
activeDate = (altKey ? ctrlKey ? oneDecadeAgo : oneYearAgo : oneMonthAgo)(activeDate); // We check the first day of month to be in rage
checkDate = createDate(activeDate);
checkDate.setDate(1);
} else if (keyCode === CODE_PAGEDOWN) {
// PAGEDOWN - Next month/year
activeDate = (altKey ? ctrlKey ? oneDecadeAhead : oneYearAhead : oneMonthAhead)(activeDate); // We check the last day of month to be in rage
checkDate = createDate(activeDate);
checkDate.setMonth(checkDate.getMonth() + 1);
checkDate.setDate(0);
} else if (keyCode === CODE_LEFT) {
// LEFT - Previous day (or next day for RTL)
activeDate.setDate(day + (isRTL ? 1 : -1));
activeDate = this.constrainDate(activeDate);
checkDate = activeDate;
} else if (keyCode === CODE_RIGHT) {
// RIGHT - Next day (or previous day for RTL)
activeDate.setDate(day + (isRTL ? -1 : 1));
activeDate = this.constrainDate(activeDate);
checkDate = activeDate;
} else if (keyCode === CODE_UP) {
// UP - Previous week
activeDate.setDate(day - 7);
activeDate = this.constrainDate(activeDate);
checkDate = activeDate;
} else if (keyCode === CODE_DOWN) {
// DOWN - Next week
activeDate.setDate(day + 7);
activeDate = this.constrainDate(activeDate);
checkDate = activeDate;
} else if (keyCode === CODE_HOME) {
// HOME - Today
activeDate = constrainedToday;
checkDate = activeDate;
} else if (keyCode === CODE_END) {
// END - Selected date, or today if no selected date
activeDate = parseYMD(this.selectedDate) || constrainedToday;
checkDate = activeDate;
}
if (!this.dateOutOfRange(checkDate) && !datesEqual(activeDate, this.activeDate)) {
// We only jump to date if within min/max
// We don't check for individual disabled dates though (via user function)
this.activeYMD = formatYMD(activeDate);
} // Ensure grid is focused
this.focus();
},
onKeydownGrid: function onKeydownGrid(evt) {
// Pressing enter/space on grid to select active date
var keyCode = evt.keyCode;
var activeDate = this.activeDate;
if (keyCode === CODE_ENTER || keyCode === CODE_SPACE) {
stopEvent(evt);
if (!this.disabled && !this.readonly && !this.dateDisabled(activeDate)) {
this.selectedYMD = formatYMD(activeDate);
this.emitSelected(activeDate);
} // Ensure grid is focused
this.focus();
}
},
onClickDay: function onClickDay(day) {
// Clicking on a date "button" to select it
var selectedDate = this.selectedDate,
activeDate = this.activeDate;
var clickedDate = parseYMD(day.ymd);
if (!this.disabled && !day.isDisabled && !this.dateDisabled(clickedDate)) {
if (!this.readonly) {
// If readonly mode, we don't set the selected date, just the active date
// If the clicked date is equal to the already selected date, we don't update the model
this.selectedYMD = formatYMD(datesEqual(clickedDate, selectedDate) ? selectedDate : clickedDate);
this.emitSelected(clickedDate);
}
this.activeYMD = formatYMD(datesEqual(clickedDate, activeDate) ? activeDate : createDate(clickedDate)); // Ensure grid is focused
this.focus();
}
},
gotoPrevDecade: function gotoPrevDecade() {
this.activeYMD = formatYMD(this.constrainDate(oneDecadeAgo(this.activeDate)));
},
gotoPrevYear: function gotoPrevYear() {
this.activeYMD = formatYMD(this.constrainDate(oneYearAgo(this.activeDate)));
},
gotoPrevMonth: function gotoPrevMonth() {
this.activeYMD = formatYMD(this.constrainDate(oneMonthAgo(this.activeDate)));
},
gotoCurrentMonth: function gotoCurrentMonth() {
// TODO: Maybe this goto date should be configurable?
this.activeYMD = formatYMD(this.constrainDate(this.getToday()));
},
gotoNextMonth: function gotoNextMonth() {
this.activeYMD = formatYMD(this.constrainDate(oneMonthAhead(this.activeDate)));
},
gotoNextYear: function gotoNextYear() {
this.activeYMD = formatYMD(this.constrainDate(oneYearAhead(this.activeDate)));
},
gotoNextDecade: function gotoNextDecade() {
this.activeYMD = formatYMD(this.constrainDate(oneDecadeAhead(this.activeDate)));
},
onHeaderClick: function onHeaderClick() {
if (!this.disabled) {
this.activeYMD = this.selectedYMD || formatYMD(this.getToday());
this.focus();
}
}
},
render: function render(h) {
var _this6 = this;
// If `hidden` prop is set, render just a placeholder node
if (this.hidden) {
return h();
}
var valueId = this.valueId,
widgetId = this.widgetId,
navId = this.navId,
gridId = this.gridId,
gridCaptionId = this.gridCaptionId,
gridHelpId = this.gridHelpId,
activeId = this.activeId,
disabled = this.disabled,
noKeyNav = this.noKeyNav,
isLive = this.isLive,
isRTL = this.isRTL,
activeYMD = this.activeYMD,
selectedYMD = this.selectedYMD,
safeId = this.safeId;
var hideDecadeNav = !this.showDecadeNav;
var todayYMD = formatYMD(this.getToday());
var highlightToday = !this.noHighlightToday; // Header showing current selected date
var $header = h('output', {
staticClass: 'form-control form-control-sm text-center',
class: {
'text-muted': disabled,
readonly: this.readonly || disabled
},
attrs: {
id: valueId,
for: gridId,
role: 'status',
tabindex: disabled ? null : '-1',
// Mainly for testing purposes, as we do not know
// the exact format `Intl` will format the date string
'data-selected': toString$1(selectedYMD),
// We wait until after mount to enable `aria-live`
// to prevent initial announcement on page render
'aria-live': isLive ? 'polite' : 'off',
'aria-atomic': isLive ? 'true' : null
},
on: {
// Transfer focus/click to focus grid
// and focus active date (or today if no selection)
click: this.onHeaderClick,
focus: this.onHeaderClick
}
}, this.selectedDate ? [// We use `bdi` elements here in case the label doesn't match the locale
// Although IE 11 does not deal with <BDI> at all (equivalent to a span)
h('bdi', {
staticClass: 'sr-only'
}, " (".concat(toString$1(this.labelSelected), ") ")), h('bdi', this.formatDateString(this.selectedDate))] : this.labelNoDateSelected || "\xA0" // '&nbsp;'
);
$header = h('header', {
staticClass: 'b-calendar-header',
class: {
'sr-only': this.hideHeader
},
attrs: {
title: this.selectedDate ? this.labelSelectedDate || null : null
}
}, [$header]); // Content for the date navigation buttons
var navScope = {
isRTL: isRTL
};
var navProps = {
shiftV: 0.5
};
var navPrevProps = _objectSpread2(_objectSpread2({}, navProps), {}, {
flipH: isRTL
});
var navNextProps = _objectSpread2(_objectSpread2({}, navProps), {}, {
flipH: !isRTL
});
var $prevDecadeIcon = this.normalizeSlot('nav-prev-decade', navScope) || h(BIconChevronBarLeft, {
props: navPrevProps
});
var $prevYearIcon = this.normalizeSlot('nav-prev-year', navScope) || h(BIconChevronDoubleLeft, {
props: navPrevProps
});
var $prevMonthIcon = this.normalizeSlot('nav-prev-month', navScope) || h(BIconChevronLeft, {
props: navPrevProps
});
var $thisMonthIcon = this.normalizeSlot('nav-this-month', navScope) || h(BIconCircleFill, {
props: navProps
});
var $nextMonthIcon = this.normalizeSlot('nav-next-month', navScope) || h(BIconChevronLeft, {
props: navNextProps
});
var $nextYearIcon = this.normalizeSlot('nav-next-year', navScope) || h(BIconChevronDoubleLeft, {
props: navNextProps
});
var $nextDecadeIcon = this.normalizeSlot('nav-next-decade', navScope) || h(BIconChevronBarLeft, {
props: navNextProps
}); // Utility to create the date navigation buttons
var makeNavBtn = function makeNavBtn(content, label, handler, btnDisabled, shortcut) {
return h('button', {
staticClass: 'btn btn-sm border-0 flex-fill',
class: [_this6.computedNavButtonVariant, {
disabled: btnDisabled
}],
attrs: {
title: label || null,
type: 'button',
tabindex: noKeyNav ? '-1' : null,
'aria-label': label || null,
'aria-disabled': btnDisabled ? 'true' : null,
'aria-keyshortcuts': shortcut || null
},
on: btnDisabled ? {} : {
click: handler
}
}, [h('div', {
attrs: {
'aria-hidden': 'true'
}
}, [content])]);
}; // Generate the date navigation buttons
var $nav = h('div', {
staticClass: 'b-calendar-nav d-flex',
attrs: {
id: navId,
role: 'group',
tabindex: noKeyNav ? '-1' : null,
'aria-hidden': disabled ? 'true' : null,
'aria-label': this.labelNav || null,
'aria-controls': gridId
}
}, [hideDecadeNav ? h() : makeNavBtn($prevDecadeIcon, this.labelPrevDecade, this.gotoPrevDecade, this.prevDecadeDisabled, 'Ctrl+Alt+PageDown'), makeNavBtn($prevYearIcon, this.labelPrevYear, this.gotoPrevYear, this.prevYearDisabled, 'Alt+PageDown'), makeNavBtn($prevMonthIcon, this.labelPrevMonth, this.gotoPrevMonth, this.prevMonthDisabled, 'PageDown'), makeNavBtn($thisMonthIcon, this.labelCurrentMonth, this.gotoCurrentMonth, this.thisMonthDisabled, 'Home'), makeNavBtn($nextMonthIcon, this.labelNextMonth, this.gotoNextMonth, this.nextMonthDisabled, 'PageUp'), makeNavBtn($nextYearIcon, this.labelNextYear, this.gotoNextYear, this.nextYearDisabled, 'Alt+PageUp'), hideDecadeNav ? h() : makeNavBtn($nextDecadeIcon, this.labelNextDecade, this.gotoNextDecade, this.nextDecadeDisabled, 'Ctrl+Alt+PageUp')]); // Caption for calendar grid
var $gridCaption = h('header', {
key: 'grid-caption',
staticClass: 'b-calendar-grid-caption text-center font-weight-bold',
class: {
'text-muted': disabled
},
attrs: {
id: gridCaptionId,
'aria-live': isLive ? 'polite' : null,
'aria-atomic': isLive ? 'true' : null
}
}, this.formatYearMonth(this.calendarFirstDay)); // Calendar weekday headings
var $gridWeekDays = h('div', {
staticClass: 'b-calendar-grid-weekdays row no-gutters border-bottom',
attrs: {
'aria-hidden': 'true'
}
}, this.calendarHeadings.map(function (d, idx) {
return h('small', {
key: idx,
staticClass: 'col text-truncate',
class: {
'text-muted': disabled
},
attrs: {
title: d.label === d.text ? null : d.label,
'aria-label': d.label
}
}, d.text);
})); // Calendar day grid
var $gridBody = this.calendar.map(function (week) {
var $cells = week.map(function (day, dIndex) {
var _class;
var isSelected = day.ymd === selectedYMD;
var isActive = day.ymd === activeYMD;
var isToday = day.ymd === todayYMD;
var idCell = safeId("_cell-".concat(day.ymd, "_")); // "fake" button
var $btn = h('span', {
staticClass: 'btn border-0 rounded-circle text-nowrap',
// Should we add some classes to signify if today/selected/etc?
class: (_class = {
// Give the fake button a focus ring
focus: isActive && _this6.gridHasFocus,
// Styling
disabled: day.isDisabled || disabled,
active: isSelected
}, _defineProperty(_class, _this6.computedVariant, isSelected), _defineProperty(_class, _this6.computedTodayVariant, isToday && highlightToday && !isSelected && day.isThisMonth), _defineProperty(_class, 'btn-outline-light', !(isToday && highlightToday) && !isSelected && !isActive), _defineProperty(_class, 'btn-light', !(isToday && highlightToday) && !isSelected && isActive), _defineProperty(_class, 'text-muted', !day.isThisMonth && !isSelected), _defineProperty(_class, 'text-dark', !(isToday && highlightToday) && !isSelected && !isActive && day.isThisMonth), _defineProperty(_class, 'font-weight-bold', (isSelected || day.isThisMonth) && !day.isDisabled), _class),
on: {
click: function click() {
return _this6.onClickDay(day);
}
}
}, day.day);
return h('div', // Cell with button
{
key: dIndex,
staticClass: 'col p-0',
class: day.isDisabled ? 'bg-light' : day.info.class || '',
attrs: {
id: idCell,
role: 'button',
'data-date': day.ymd,
// Primarily for testing purposes
// Only days in the month are presented as buttons to screen readers
'aria-hidden': day.isThisMonth ? null : 'true',
'aria-disabled': day.isDisabled || disabled ? 'true' : null,
'aria-label': [day.label, isSelected ? "(".concat(_this6.labelSelected, ")") : null, isToday ? "(".concat(_this6.labelToday, ")") : null].filter(identity).join(' '),
// NVDA doesn't convey `aria-selected`, but does `aria-current`,
// ChromeVox doesn't convey `aria-current`, but does `aria-selected`,
// so we set both attributes for robustness
'aria-selected': isSelected ? 'true' : null,
'aria-current': isSelected ? 'date' : null
}
}, [$btn]);
}); // Return the week "row"
// We use the first day of the weeks YMD value as a
// key for efficient DOM patching / element re-use
return h('div', {
key: week[0].ymd,
staticClass: 'row no-gutters'
}, $cells);
});
$gridBody = h('div', {
// A key is only required on the body if we add in transition support
// key: this.activeYMD.slice(0, -3),
staticClass: 'b-calendar-grid-body',
style: disabled ? {
pointerEvents: 'none'
} : {}
}, $gridBody);
var $gridHelp = h('footer', {
staticClass: 'b-calendar-grid-help border-top small text-muted text-center bg-light',
attrs: {
id: gridHelpId
}
}, [h('div', {
staticClass: 'small'
}, this.labelHelp)]);
var $grid = h('div', {
ref: 'grid',
staticClass: 'b-calendar-grid form-control h-auto text-center',
attrs: {
id: gridId,
role: 'application',
tabindex: noKeyNav ? '-1' : disabled ? null : '0',
'data-month': activeYMD.slice(0, -3),
// `YYYY-MM`, mainly for testing
'aria-roledescription': this.labelCalendar || null,
'aria-labelledby': gridCaptionId,
'aria-describedby': gridHelpId,
// `aria-readonly` is not considered valid on `role="application"`
// https://www.w3.org/TR/wai-aria-1.1/#aria-readonly
// 'aria-readonly': this.readonly && !disabled ? 'true' : null,
'aria-disabled': disabled ? 'true' : null,
'aria-activedescendant': activeId
},
on: {
keydown: this.onKeydownGrid,
focus: this.setGridFocusFlag,
blur: this.setGridFocusFlag
}
}, [$gridCaption, $gridWeekDays, $gridBody, $gridHelp]); // Optional bottom slot
var $slot = this.normalizeSlot();
$slot = $slot ? h('footer', {
staticClass: 'b-calendar-footer'
}, $slot) : h();
var $widget = h('div', {
staticClass: 'b-calendar-inner',
style: this.block ? {} : {
width: this.width
},
attrs: {
id: widgetId,
dir: isRTL ? 'rtl' : 'ltr',
lang: this.computedLocale || null,
role: 'group',
'aria-disabled': disabled ? 'true' : null,
// If datepicker controls an input, this will specify the ID of the input
'aria-controls': this.ariaControls || null,
// This should be a prop (so it can be changed to Date picker, etc, localized
'aria-roledescription': this.roleDescription || null,
'aria-describedby': [// Should the attr (if present) go last?
// Or should this attr be a prop?
this.bvAttrs['aria-describedby'], valueId, gridHelpId].filter(identity).join(' ')
},
on: {
keydown: this.onKeydownWrapper
}
}, [$header, $nav, $grid, $slot]); // Wrap in an outer div that can be styled
return h('div', {
staticClass: 'b-calendar',
class: {
'd-block': this.block
}
}, [$widget]);
}
});
var CalendarPlugin = /*#__PURE__*/pluginFactory({
components: {
BCalendar: BCalendar
}
});
var props$8 = makePropsConfigurable({
tag: {
type: String,
default: 'div'
},
bgVariant: {
type: String // default: null
},
borderVariant: {
type: String // default: null
},
textVariant: {
type: String // default: null
}
}, NAME_CARD); // --- Mixin ---
var props$9 = makePropsConfigurable({
title: {
type: String // default: null
},
titleTag: {
type: String,
default: 'h4'
}
}, NAME_CARD_TITLE); // @vue/component
var BCardTitle = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_CARD_TITLE,
functional: true,
props: props$9,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
return h(props.titleTag, a(data, {
staticClass: 'card-title'
}), children || toString$1(props.title));
}
});
var props$a = makePropsConfigurable({
subTitle: {
type: String // default: null
},
subTitleTag: {
type: String,
default: 'h6'
},
subTitleTextVariant: {
type: String,
default: 'muted'
}
}, NAME_CARD_SUB_TITLE); // @vue/component
var BCardSubTitle = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_CARD_SUB_TITLE,
functional: true,
props: props$a,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
return h(props.subTitleTag, a(data, {
staticClass: 'card-subtitle',
class: [props.subTitleTextVariant ? "text-".concat(props.subTitleTextVariant) : null]
}), children || toString$1(props.subTitle));
}
});
var props$b = makePropsConfigurable(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, copyProps(props$8, prefixPropName.bind(null, 'body'))), {}, {
bodyClass: {
type: [String, Object, Array] // default: null
}
}, props$9), props$a), {}, {
overlay: {
type: Boolean,
default: false
}
}), NAME_CARD_BODY); // @vue/component
var BCardBody = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_CARD_BODY,
functional: true,
props: props$b,
render: function render(h, _ref) {
var _ref2;
var props = _ref.props,
data = _ref.data,
children = _ref.children;
var cardTitle = h();
var cardSubTitle = h();
var cardContent = children || [h()];
if (props.title) {
cardTitle = h(BCardTitle, {
props: pluckProps(props$9, props)
});
}
if (props.subTitle) {
cardSubTitle = h(BCardSubTitle, {
props: pluckProps(props$a, props),
class: ['mb-2']
});
}
return h(props.bodyTag, a(data, {
staticClass: 'card-body',
class: [(_ref2 = {
'card-img-overlay': props.overlay
}, _defineProperty(_ref2, "bg-".concat(props.bodyBgVariant), props.bodyBgVariant), _defineProperty(_ref2, "border-".concat(props.bodyBorderVariant), props.bodyBorderVariant), _defineProperty(_ref2, "text-".concat(props.bodyTextVariant), props.bodyTextVariant), _ref2), props.bodyClass || {}]
}), [cardTitle, cardSubTitle].concat(_toConsumableArray(cardContent)));
}
});
var props$c = makePropsConfigurable(_objectSpread2(_objectSpread2({}, copyProps(props$8, prefixPropName.bind(null, 'header'))), {}, {
header: {
type: String // default: null
},
headerHtml: {
type: String // default: null
},
headerClass: {
type: [String, Object, Array] // default: null
}
}), NAME_CARD_HEADER); // --- Main component ---
// @vue/component
var BCardHeader = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_CARD_HEADER,
functional: true,
props: props$c,
render: function render(h, _ref) {
var _ref2;
var props = _ref.props,
data = _ref.data,
children = _ref.children;
var headerBgVariant = props.headerBgVariant,
headerBorderVariant = props.headerBorderVariant,
headerTextVariant = props.headerTextVariant;
return h(props.headerTag, a(data, {
staticClass: 'card-header',
class: [props.headerClass, (_ref2 = {}, _defineProperty(_ref2, "bg-".concat(headerBgVariant), headerBgVariant), _defineProperty(_ref2, "border-".concat(headerBorderVariant), headerBorderVariant), _defineProperty(_ref2, "text-".concat(headerTextVariant), headerTextVariant), _ref2)],
domProps: children ? {} : htmlOrText(props.headerHtml, props.header)
}), children);
}
});
var props$d = makePropsConfigurable(_objectSpread2(_objectSpread2({}, copyProps(props$8, prefixPropName.bind(null, 'footer'))), {}, {
footer: {
type: String // default: null
},
footerHtml: {
type: String // default: null
},
footerClass: {
type: [String, Object, Array] // default: null
}
}), NAME_CARD_FOOTER); // --- Main component ---
// @vue/component
var BCardFooter = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_CARD_FOOTER,
functional: true,
props: props$d,
render: function render(h, _ref) {
var _ref2;
var props = _ref.props,
data = _ref.data,
children = _ref.children;
var footerBgVariant = props.footerBgVariant,
footerBorderVariant = props.footerBorderVariant,
footerTextVariant = props.footerTextVariant;
return h(props.footerTag, a(data, {
staticClass: 'card-footer',
class: [props.footerClass, (_ref2 = {}, _defineProperty(_ref2, "bg-".concat(footerBgVariant), footerBgVariant), _defineProperty(_ref2, "border-".concat(footerBorderVariant), footerBorderVariant), _defineProperty(_ref2, "text-".concat(footerTextVariant), footerTextVariant), _ref2)],
domProps: children ? {} : htmlOrText(props.footerHtml, props.footer)
}), children);
}
});
var props$e = makePropsConfigurable({
src: {
type: String,
required: true
},
alt: {
type: String,
default: null
},
top: {
type: Boolean,
default: false
},
bottom: {
type: Boolean,
default: false
},
start: {
type: Boolean,
default: false
},
left: {
// alias of 'start'
type: Boolean,
default: false
},
end: {
type: Boolean,
default: false
},
right: {
// alias of 'end'
type: Boolean,
default: false
},
height: {
type: [Number, String] // default: null
},
width: {
type: [Number, String] // default: null
}
}, NAME_CARD_IMG); // @vue/component
var BCardImg = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_CARD_IMG,
functional: true,
props: props$e,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data;
var baseClass = 'card-img';
if (props.top) {
baseClass += '-top';
} else if (props.right || props.end) {
baseClass += '-right';
} else if (props.bottom) {
baseClass += '-bottom';
} else if (props.left || props.start) {
baseClass += '-left';
}
return h('img', a(data, {
class: [baseClass],
attrs: {
src: props.src || null,
alt: props.alt,
height: props.height || null,
width: props.width || null
}
}));
}
});
var cardImgProps = copyProps(props$e, prefixPropName.bind(null, 'img'));
cardImgProps.imgSrc.required = false;
var props$f = makePropsConfigurable(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, props$b), props$c), props$d), cardImgProps), props$8), {}, {
align: {
type: String // default: null
},
noBody: {
type: Boolean,
default: false
}
}), NAME_CARD); // --- Main component ---
// @vue/component
var BCard = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_CARD,
functional: true,
props: props$f,
render: function render(h, _ref) {
var _class;
var props = _ref.props,
data = _ref.data,
slots = _ref.slots,
scopedSlots = _ref.scopedSlots;
var imgSrc = props.imgSrc,
imgLeft = props.imgLeft,
imgRight = props.imgRight,
imgStart = props.imgStart,
imgEnd = props.imgEnd,
imgBottom = props.imgBottom,
header = props.header,
headerHtml = props.headerHtml,
footer = props.footer,
footerHtml = props.footerHtml,
align = props.align,
textVariant = props.textVariant,
bgVariant = props.bgVariant,
borderVariant = props.borderVariant;
var $scopedSlots = scopedSlots || {};
var $slots = slots();
var slotScope = {};
var $imgFirst = h();
var $imgLast = h();
if (imgSrc) {
var $img = h(BCardImg, {
props: pluckProps(cardImgProps, props, unprefixPropName.bind(null, 'img'))
});
if (imgBottom) {
$imgLast = $img;
} else {
$imgFirst = $img;
}
}
var $header = h();
var hasHeaderSlot = hasNormalizedSlot(SLOT_NAME_HEADER, $scopedSlots, $slots);
if (hasHeaderSlot || header || headerHtml) {
$header = h(BCardHeader, {
props: pluckProps(props$c, props),
domProps: hasHeaderSlot ? {} : htmlOrText(headerHtml, header)
}, normalizeSlot(SLOT_NAME_HEADER, slotScope, $scopedSlots, $slots));
}
var $content = normalizeSlot(SLOT_NAME_DEFAULT, slotScope, $scopedSlots, $slots); // Wrap content in `<card-body>` when `noBody` prop set
if (!props.noBody) {
$content = h(BCardBody, {
props: pluckProps(props$b, props)
}, $content); // When the `overlap` prop is set we need to wrap the `<b-card-img>` and `<b-card-body>`
// into a relative positioned wrapper to don't distract a potential header or footer
if (props.overlay && imgSrc) {
$content = h('div', {
staticClass: 'position-relative'
}, [$imgFirst, $content, $imgLast]); // Reset image variables since they are already in the wrapper
$imgFirst = h();
$imgLast = h();
}
}
var $footer = h();
var hasFooterSlot = hasNormalizedSlot(SLOT_NAME_FOOTER, $scopedSlots, $slots);
if (hasFooterSlot || footer || footerHtml) {
$footer = h(BCardFooter, {
props: pluckProps(props$d, props),
domProps: hasHeaderSlot ? {} : htmlOrText(footerHtml, footer)
}, normalizeSlot(SLOT_NAME_FOOTER, slotScope, $scopedSlots, $slots));
}
return h(props.tag, a(data, {
staticClass: 'card',
class: (_class = {
'flex-row': imgLeft || imgStart,
'flex-row-reverse': (imgRight || imgEnd) && !(imgLeft || imgStart)
}, _defineProperty(_class, "text-".concat(align), align), _defineProperty(_class, "bg-".concat(bgVariant), bgVariant), _defineProperty(_class, "border-".concat(borderVariant), borderVariant), _defineProperty(_class, "text-".concat(textVariant), textVariant), _class)
}), [$imgFirst, $header, $content, $footer, $imgLast]);
}
});
var OBSERVER_PROP_NAME = '__bv__visibility_observer';
var VisibilityObserver = /*#__PURE__*/function () {
function VisibilityObserver(el, options, vnode) {
_classCallCheck(this, VisibilityObserver);
this.el = el;
this.callback = options.callback;
this.margin = options.margin || 0;
this.once = options.once || false;
this.observer = null;
this.visible = undefined;
this.doneOnce = false; // Create the observer instance (if possible)
this.createObserver(vnode);
}
_createClass(VisibilityObserver, [{
key: "createObserver",
value: function createObserver(vnode) {
var _this = this;
// Remove any previous observer
if (this.observer) {
/* istanbul ignore next */
this.stop();
} // Should only be called once and `callback` prop should be a function
if (this.doneOnce || !isFunction(this.callback)) {
/* istanbul ignore next */
return;
} // Create the observer instance
try {
// Future: Possibly add in other modifiers for left/right/top/bottom
// offsets, root element reference, and thresholds
this.observer = new IntersectionObserver(this.handler.bind(this), {
// `null` = 'viewport'
root: null,
// Pixels away from view port to consider "visible"
rootMargin: this.margin,
// Intersection ratio of el and root (as a value from 0 to 1)
threshold: 0
});
} catch (_unused) {
// No IntersectionObserver support, so just stop trying to observe
this.doneOnce = true;
this.observer = undefined;
this.callback(null);
return;
} // Start observing in a `$nextTick()` (to allow DOM to complete rendering)
/* istanbul ignore next: IntersectionObserver not supported in JSDOM */
vnode.context.$nextTick(function () {
requestAF(function () {
// Placed in an `if` just in case we were destroyed before
// this `requestAnimationFrame` runs
if (_this.observer) {
_this.observer.observe(_this.el);
}
});
});
}
/* istanbul ignore next */
}, {
key: "handler",
value: function handler(entries) {
var entry = entries ? entries[0] : {};
var isIntersecting = Boolean(entry.isIntersecting || entry.intersectionRatio > 0.0);
if (isIntersecting !== this.visible) {
this.visible = isIntersecting;
this.callback(isIntersecting);
if (this.once && this.visible) {
this.doneOnce = true;
this.stop();
}
}
}
}, {
key: "stop",
value: function stop() {
/* istanbul ignore next */
this.observer && this.observer.disconnect();
this.observer = null;
}
}]);
return VisibilityObserver;
}();
var destroy = function destroy(el) {
var observer = el[OBSERVER_PROP_NAME];
if (observer && observer.stop) {
observer.stop();
}
delete el[OBSERVER_PROP_NAME];
};
var bind = function bind(el, _ref, vnode) {
var value = _ref.value,
modifiers = _ref.modifiers;
// `value` is the callback function
var options = {
margin: '0px',
once: false,
callback: value
}; // Parse modifiers
keys(modifiers).forEach(function (mod) {
/* istanbul ignore else: Until <b-img-lazy> is switched to use this directive */
if (RX_DIGITS.test(mod)) {
options.margin = "".concat(mod, "px");
} else if (mod.toLowerCase() === 'once') {
options.once = true;
}
}); // Destroy any previous observer
destroy(el); // Create new observer
el[OBSERVER_PROP_NAME] = new VisibilityObserver(el, options, vnode); // Store the current modifiers on the object (cloned)
el[OBSERVER_PROP_NAME]._prevModifiers = clone(modifiers);
}; // When the directive options may have been updated (or element)
var componentUpdated = function componentUpdated(el, _ref2, vnode) {
var value = _ref2.value,
oldValue = _ref2.oldValue,
modifiers = _ref2.modifiers;
// Compare value/oldValue and modifiers to see if anything has changed
// and if so, destroy old observer and create new observer
/* istanbul ignore next */
modifiers = clone(modifiers);
/* istanbul ignore next */
if (el && (value !== oldValue || !el[OBSERVER_PROP_NAME] || !looseEqual(modifiers, el[OBSERVER_PROP_NAME]._prevModifiers))) {
// Re-bind on element
bind(el, {
value: value,
modifiers: modifiers
}, vnode);
}
}; // When directive un-binds from element
var unbind = function unbind(el) {
// Remove the observer
destroy(el);
}; // Export the directive
var VBVisible = {
bind: bind,
componentUpdated: componentUpdated,
unbind: unbind
};
// 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>';
var props$g = makePropsConfigurable({
src: {
type: String // default: null
},
srcset: {
type: [String, Array] // default: null
},
sizes: {
type: [String, Array] // 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'
}
}, NAME_IMG); // --- Helper methods ---
var makeBlankImgSrc = function makeBlankImgSrc(width, height, color) {
var src = encodeURIComponent(BLANK_TEMPLATE.replace('%{w}', toString$1(width)).replace('%{h}', toString$1(height)).replace('%{f}', color));
return "data:image/svg+xml;charset=UTF-8,".concat(src);
}; // @vue/component
var BImg = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_IMG,
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 = toInteger(props.width) || null;
var height = toInteger(props.height) || null;
var align = null;
var block = props.block;
var srcset = concat(props.srcset).filter(identity).join(',');
var sizes = concat(props.sizes).filter(identity).join(',');
if (props.blank) {
if (!height && width) {
height = width;
} else if (!width && height) {
width = height;
}
if (!width && !height) {
width = 1;
height = 1;
} // Make a blank SVG image
src = makeBlankImgSrc(width, height, props.blankColor || 'transparent'); // Disable srcset and sizes
srcset = null;
sizes = null;
}
if (props.left) {
align = 'float-left';
} else if (props.right) {
align = 'float-right';
} else if (props.center) {
align = 'mx-auto';
block = true;
}
return h('img', a(data, {
attrs: {
src: src,
alt: props.alt,
width: width ? toString$1(width) : null,
height: height ? toString$1(height) : null,
srcset: srcset || null,
sizes: sizes || 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-".concat(props.rounded), isString(props.rounded) && props.rounded !== ''), _defineProperty(_class, align, align), _defineProperty(_class, 'd-block', block), _class)
}));
}
});
var props$h = makePropsConfigurable(_objectSpread2(_objectSpread2({}, omit(props$g, ['blank'])), {}, {
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
},
show: {
type: Boolean,
default: false
},
offset: {
// Distance away from viewport (in pixels) before being
// considered "visible"
type: [Number, String],
default: 360
}
}), NAME_IMG_LAZY); // @vue/component
var BImgLazy = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_IMG_LAZY,
directives: {
bVisible: VBVisible
},
props: props$h,
data: function data() {
return {
isShown: this.show
};
},
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;
},
computedSrcset: function computedSrcset() {
var srcset = concat(this.srcset).filter(identity).join(',');
return !this.blankSrc || this.isShown ? srcset : null;
},
computedSizes: function computedSizes() {
var sizes = concat(this.sizes).filter(identity).join(',');
return !this.blankSrc || this.isShown ? sizes : null;
}
},
watch: {
show: function show(newVal, oldVal) {
if (newVal !== oldVal) {
// If IntersectionObserver support is not available, image is always shown
var visible = hasIntersectionObserverSupport ? newVal : true;
this.isShown = visible;
if (visible !== newVal) {
// Ensure the show prop is synced (when no IntersectionObserver)
this.$nextTick(this.updateShowProp);
}
}
},
isShown: function isShown(newVal, oldVal) {
if (newVal !== oldVal) {
// Update synched show prop
this.updateShowProp();
}
}
},
mounted: function mounted() {
// If IntersectionObserver is not available, image is always shown
this.isShown = hasIntersectionObserverSupport ? this.show : true;
},
methods: {
updateShowProp: function updateShowProp() {
this.$emit('update:show', this.isShown);
},
doShow: function doShow(visible) {
// If IntersectionObserver is not supported, the callback
// will be called with `null` rather than `true` or `false`
if ((visible || visible === null) && !this.isShown) {
this.isShown = true;
}
}
},
render: function render(h) {
var directives = [];
if (!this.isShown) {
var _modifiers;
// We only add the visible directive if we are not shown
directives.push({
// Visible directive will silently do nothing if
// IntersectionObserver is not supported
name: 'b-visible',
// Value expects a callback (passed one arg of `visible` = `true` or `false`)
value: this.doShow,
modifiers: (_modifiers = {}, _defineProperty(_modifiers, "".concat(toInteger(this.offset, 0)), true), _defineProperty(_modifiers, "once", true), _modifiers)
});
}
return h(BImg, {
directives: directives,
props: {
// Computed value props
src: this.computedSrc,
blank: this.computedBlank,
width: this.computedWidth,
height: this.computedHeight,
srcset: this.computedSrcset || null,
sizes: this.computedSizes || null,
// Passthrough props
alt: this.alt,
blankColor: this.blankColor,
fluid: this.fluid,
fluidGrow: this.fluidGrow,
block: this.block,
thumbnail: this.thumbnail,
rounded: this.rounded,
left: this.left,
right: this.right,
center: this.center
}
});
}
});
// The `omit()` util creates a new object, so we can just pass the original props
var lazyProps = omit(props$h, ['left', 'right', 'center', 'block', 'rounded', 'thumbnail', 'fluid', 'fluidGrow']);
var props$i = makePropsConfigurable(_objectSpread2(_objectSpread2({}, lazyProps), {}, {
top: {
type: Boolean,
default: false
},
bottom: {
type: Boolean,
default: false
},
start: {
type: Boolean,
default: false
},
left: {
// alias of 'start'
type: Boolean,
default: false
},
end: {
type: Boolean,
default: false
},
right: {
// alias of 'end'
type: Boolean,
default: false
}
}), NAME_CARD_IMG_LAZY); // @vue/component
var BCardImgLazy = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_CARD_IMG_LAZY,
functional: true,
props: props$i,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data;
var baseClass = 'card-img';
if (props.top) {
baseClass += '-top';
} else if (props.right || props.end) {
baseClass += '-right';
} else if (props.bottom) {
baseClass += '-bottom';
} else if (props.left || props.start) {
baseClass += '-left';
} // False out the left/center/right props before passing to b-img-lazy
var lazyProps = _objectSpread2(_objectSpread2({}, props), {}, {
left: false,
right: false,
center: false
});
return h(BImgLazy, a(data, {
class: [baseClass],
props: lazyProps
}));
}
});
var props$j = makePropsConfigurable({
textTag: {
type: String,
default: 'p'
}
}, NAME_CARD_TEXT); // @vue/component
var BCardText = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_CARD_TEXT,
functional: true,
props: props$j,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
return h(props.textTag, a(data, {
staticClass: 'card-text'
}), children);
}
});
var props$k = makePropsConfigurable({
tag: {
type: String,
default: 'div'
},
deck: {
type: Boolean,
default: false
},
columns: {
type: Boolean,
default: false
}
}, NAME_CARD_GROUP); // @vue/component
var BCardGroup = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_CARD_GROUP,
functional: true,
props: props$k,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
return h(props.tag, a(data, {
class: props.deck ? 'card-deck' : props.columns ? 'card-columns' : 'card-group'
}), children);
}
});
var CardPlugin = /*#__PURE__*/pluginFactory({
components: {
BCard: BCard,
BCardHeader: BCardHeader,
BCardBody: BCardBody,
BCardTitle: BCardTitle,
BCardSubTitle: BCardSubTitle,
BCardFooter: BCardFooter,
BCardImg: BCardImg,
BCardImgLazy: BCardImgLazy,
BCardText: BCardText,
BCardGroup: BCardGroup
}
});
var EVENT_OPTIONS_PASSIVE = {
passive: true
};
var EVENT_OPTIONS_NO_CAPTURE = {
passive: true,
capture: false
};
var noop = function noop() {};
/**
* 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} [options={childList: true, subtree: true}] observe options
* @see https://stackoverflow.com/questions/3219758
*/
var observeDom = function observeDom(el, callback, options)
/* istanbul ignore next: difficult to test in JSDOM */
{
// Handle cases where we might be passed a Vue instance
el = el ? el.$el || el : null; // Early exit when we have no element
/* istanbul ignore next: difficult to test in JSDOM */
if (!isElement(el)) {
return null;
} // Exit and throw a warning when `MutationObserver` isn't available
if (warnNoMutationObserverSupport('observeDom')) {
return null;
} // Define a new observer
var obs = new MutationObs(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 mutation 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; // Detect whether a change happened based on type and 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;
}
} // We only call the callback if a change that could affect
// layout/size truly happened
if (changed) {
callback();
}
}); // Have the observer observe foo for changes in children, etc
obs.observe(el, _objectSpread2({
childList: true,
subtree: true
}, options)); // We return a reference to the observer so that `obs.disconnect()`
// can be called if necessary
// To reduce overhead when the root element is hidden
return obs;
};
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; // Time for mouse compat events to fire after touch
var TOUCH_EVENT_COMPAT_WAIT = 500; // Number of pixels to consider touch move a swipe
var SWIPE_THRESHOLD = 40; // PointerEvent pointer types
var PointerType = {
TOUCH: 'touch',
PEN: 'pen'
}; // Transition Event names
var TransitionEndEvents = {
WebkitTransition: 'webkitTransitionEnd',
MozTransition: 'transitionend',
OTransition: 'otransitionend oTransitionEnd',
transition: 'transitionend'
}; // Return the browser specific transitionEnd event name
var getTransitionEndEvent = function getTransitionEndEvent(el) {
for (var name in TransitionEndEvents) {
if (!isUndefined(el.style[name])) {
return TransitionEndEvents[name];
}
} // Fallback
/* istanbul ignore next */
return null;
}; // @vue/component
var BCarousel = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_CAROUSEL,
mixins: [idMixin, normalizeSlotMixin],
provide: function provide() {
return {
bvCarousel: this
};
},
model: {
prop: 'value',
event: 'input'
},
props: makePropsConfigurable({
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
},
noAnimation: {
// Disable slide/fade animation
type: Boolean,
default: false
},
fade: {
// Enable cross-fade animation instead of slide animation
type: Boolean,
default: false
},
noWrap: {
// Disable wrapping/looping when start/end is reached
type: Boolean,
default: false
},
noTouch: {
// Sniffed by carousel-slide
type: Boolean,
default: false
},
noHoverPause: {
// Disable pause on hover
type: Boolean,
default: false
},
imgWidth: {
// Sniffed by carousel-slide
type: [Number, String] // default: undefined
},
imgHeight: {
// Sniffed by carousel-slide
type: [Number, String] // default: undefined
},
background: {
type: String // default: undefined
},
value: {
type: Number,
default: 0
}
}, NAME_CAROUSEL),
data: function data() {
return {
index: this.value || 0,
isSliding: false,
transitionEndEvent: null,
slides: [],
direction: null,
isPaused: !(toInteger(this.interval, 0) > 0),
// Touch event handling values
touchStartX: 0,
touchDeltaX: 0
};
},
computed: {
numSlides: function numSlides() {
return this.slides.length;
}
},
watch: {
value: function value(newVal, oldVal) {
if (newVal !== oldVal) {
this.setSlide(toInteger(newVal, 0));
}
},
interval: function interval(newVal, oldVal) {
if (newVal === oldVal) {
/* istanbul ignore next */
return;
}
if (!newVal) {
// Pausing slide show
this.pause(false);
} else {
// Restarting or Changing interval
this.pause(true);
this.start(false);
}
},
isPaused: function isPaused(newVal, oldVal) {
if (newVal !== oldVal) {
this.$emit(newVal ? 'paused' : 'unpaused');
}
},
index: function index(to, from) {
if (to === from || this.isSliding) {
/* istanbul ignore next */
return;
}
this.doSlide(to, from);
}
},
created: function created() {
// Create private non-reactive props
this.$_interval = null;
this.$_animationTimeout = null;
this.$_touchTimeout = null;
this.$_observer = null; // Set initial paused state
this.isPaused = !(toInteger(this.interval, 0) > 0);
},
mounted: function mounted() {
// Cache current browser transitionend event name
this.transitionEndEvent = getTransitionEndEvent(this.$el) || null; // Get all slides
this.updateSlides(); // Observe child changes so we can update slide list
this.setObserver(true);
},
beforeDestroy: function beforeDestroy() {
this.clearInterval();
this.clearAnimationTimeout();
this.clearTouchTimeout();
this.setObserver(false);
},
methods: {
clearInterval: function (_clearInterval) {
function clearInterval() {
return _clearInterval.apply(this, arguments);
}
clearInterval.toString = function () {
return _clearInterval.toString();
};
return clearInterval;
}(function () {
clearInterval(this.$_interval);
this.$_interval = null;
}),
clearAnimationTimeout: function clearAnimationTimeout() {
clearTimeout(this.$_animationTimeout);
this.$_animationTimeout = null;
},
clearTouchTimeout: function clearTouchTimeout() {
clearTimeout(this.$_touchTimeout);
this.$_touchTimeout = null;
},
setObserver: function setObserver() {
var on = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
this.$_observer && this.$_observer.disconnect();
this.$_observer = null;
if (on) {
this.$_observer = observeDom(this.$refs.inner, this.updateSlides.bind(this), {
subtree: false,
childList: true,
attributes: true,
attributeFilter: ['id']
});
}
},
// Set slide
setSlide: function setSlide(slide) {
var _this = this;
var direction = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
// Don't animate when page is not visible
/* istanbul ignore if: difficult to test */
if (isBrowser && document.visibilityState && document.hidden) {
return;
}
var noWrap = this.noWrap;
var numSlides = this.numSlides; // Make sure we have an integer (you never know!)
slide = mathFloor(slide); // Don't do anything if nothing to slide to
if (numSlides === 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 () {
// Wrap in `requestAF()` to allow the slide to properly finish to avoid glitching
requestAF(function () {
return _this.setSlide(slide, direction);
});
});
return;
}
this.direction = direction; // Set new slide index
// Wrap around if necessary (if no-wrap not enabled)
this.index = slide >= numSlides ? noWrap ? numSlides - 1 : 0 : slide < 0 ? noWrap ? 0 : numSlides - 1 : slide; // Ensure the v-model is synched up if no-wrap is enabled
// and user tried to slide pass either ends
if (noWrap && this.index !== slide && this.index !== this.value) {
this.$emit('input', this.index);
}
},
// Previous slide
prev: function prev() {
this.setSlide(this.index - 1, 'prev');
},
// Next slide
next: function next() {
this.setSlide(this.index + 1, 'next');
},
// Pause auto rotation
pause: function pause(evt) {
if (!evt) {
this.isPaused = true;
}
this.clearInterval();
},
// Start auto rotate slides
start: function start(evt) {
if (!evt) {
this.isPaused = false;
}
/* istanbul ignore next: most likely will never happen, but just in case */
this.clearInterval(); // Don't start if no interval, or less than 2 slides
if (this.interval && this.numSlides > 1) {
this.$_interval = setInterval(this.next, mathMax(1000, this.interval));
}
},
// Restart auto rotate slides when focus/hover leaves the carousel
/* istanbul ignore next */
restart: function restart() {
if (!this.$el.contains(getActiveElement())) {
this.start();
}
},
doSlide: function doSlide(to, from) {
var _this2 = this;
var isCycling = Boolean(this.interval); // Determine sliding direction
var direction = this.calcDirection(this.direction, from, to);
var overlayClass = direction.overlayClass;
var dirClass = direction.dirClass; // Determine current and next slides
var currentSlide = this.slides[from];
var nextSlide = this.slides[to]; // Don't do anything if there aren't any slides to slide to
if (!currentSlide || !nextSlide) {
/* istanbul ignore next */
return;
} // Start animating
this.isSliding = true;
if (isCycling) {
this.pause(false);
}
this.$emit('sliding-start', to); // Update v-model
this.$emit('input', this.index);
if (this.noAnimation) {
addClass(nextSlide, 'active');
removeClass(currentSlide, 'active');
this.isSliding = false; // Notify ourselves that we're done sliding (slid)
this.$nextTick(function () {
return _this2.$emit('sliding-end', to);
});
} else {
addClass(nextSlide, overlayClass); // Trigger a reflow of next slide
reflow(nextSlide);
addClass(currentSlide, dirClass);
addClass(nextSlide, dirClass); // Transition End handler
var called = false;
/* istanbul ignore next: difficult to test */
var onceTransEnd = function onceTransEnd() {
if (called) {
return;
}
called = true;
/* istanbul ignore if: transition events cant be tested in JSDOM */
if (_this2.transitionEndEvent) {
var events = _this2.transitionEndEvent.split(/\s+/);
events.forEach(function (evt) {
return eventOff(nextSlide, evt, onceTransEnd, EVENT_OPTIONS_NO_CAPTURE);
});
}
_this2.clearAnimationTimeout();
removeClass(nextSlide, dirClass);
removeClass(nextSlide, overlayClass);
addClass(nextSlide, 'active');
removeClass(currentSlide, 'active');
removeClass(currentSlide, dirClass);
removeClass(currentSlide, overlayClass);
setAttr(currentSlide, 'aria-current', 'false');
setAttr(nextSlide, 'aria-current', 'true');
setAttr(currentSlide, 'aria-hidden', 'true');
setAttr(nextSlide, 'aria-hidden', 'false');
_this2.isSliding = false;
_this2.direction = null; // Notify ourselves that we're done sliding (slid)
_this2.$nextTick(function () {
return _this2.$emit('sliding-end', to);
});
}; // Set up transitionend handler
/* istanbul ignore if: transition events cant be tested in JSDOM */
if (this.transitionEndEvent) {
var events = this.transitionEndEvent.split(/\s+/);
events.forEach(function (event) {
return eventOn(nextSlide, event, onceTransEnd, EVENT_OPTIONS_NO_CAPTURE);
});
} // Fallback to setTimeout()
this.$_animationTimeout = setTimeout(onceTransEnd, TRANS_DURATION);
}
if (isCycling) {
this.start(false);
}
},
// Update slide list
updateSlides: function updateSlides() {
this.pause(true); // 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 = mathMax(0, mathMin(mathFloor(this.index), numSlides - 1));
this.slides.forEach(function (slide, idx) {
var n = idx + 1;
if (idx === index) {
addClass(slide, 'active');
setAttr(slide, 'aria-current', 'true');
} else {
removeClass(slide, 'active');
setAttr(slide, 'aria-current', 'false');
}
setAttr(slide, 'aria-posinset', String(n));
setAttr(slide, 'aria-setsize', String(numSlides));
}); // Set slide as active
this.setSlide(index);
this.start(this.isPaused);
},
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];
},
handleClick: function handleClick(evt, fn) {
var keyCode = evt.keyCode;
if (evt.type === 'click' || keyCode === CODE_SPACE || keyCode === CODE_ENTER) {
stopEvent(evt);
fn();
}
},
/* istanbul ignore next: JSDOM doesn't support touch events */
handleSwipe: function handleSwipe() {
var absDeltaX = mathAbs(this.touchDeltaX);
if (absDeltaX <= SWIPE_THRESHOLD) {
return;
}
var direction = absDeltaX / this.touchDeltaX; // Reset touch delta X
// https://github.com/twbs/bootstrap/pull/28558
this.touchDeltaX = 0;
if (direction > 0) {
// Swipe left
this.prev();
} else if (direction < 0) {
// Swipe right
this.next();
}
},
/* istanbul ignore next: JSDOM doesn't support touch events */
touchStart: function touchStart(evt) {
if (hasPointerEventSupport && PointerType[evt.pointerType.toUpperCase()]) {
this.touchStartX = evt.clientX;
} else if (!hasPointerEventSupport) {
this.touchStartX = evt.touches[0].clientX;
}
},
/* istanbul ignore next: JSDOM doesn't support touch events */
touchMove: function touchMove(evt) {
// Ensure swiping with one touch and not pinching
if (evt.touches && evt.touches.length > 1) {
this.touchDeltaX = 0;
} else {
this.touchDeltaX = evt.touches[0].clientX - this.touchStartX;
}
},
/* istanbul ignore next: JSDOM doesn't support touch events */
touchEnd: function touchEnd(evt) {
if (hasPointerEventSupport && PointerType[evt.pointerType.toUpperCase()]) {
this.touchDeltaX = evt.clientX - this.touchStartX;
}
this.handleSwipe(); // If it's a touch-enabled device, mouseenter/leave are fired as
// part of the mouse compatibility events on first tap - the carousel
// would stop cycling until user tapped out of it;
// here, we listen for touchend, explicitly pause the carousel
// (as if it's the second time we tap on it, mouseenter compat event
// is NOT fired) and after a timeout (to allow for mouse compatibility
// events to fire) we explicitly restart cycling
this.pause(false);
this.clearTouchTimeout();
this.$_touchTimeout = setTimeout(this.start, TOUCH_EVENT_COMPAT_WAIT + mathMax(1000, this.interval));
}
},
render: function render(h) {
var _this3 = this;
// Wrapper for slides
var inner = h('div', {
ref: 'inner',
class: ['carousel-inner'],
attrs: {
id: this.safeId('__BV_inner_'),
role: 'list'
}
}, [this.normalizeSlot()]); // Prev and next controls
var controls = h();
if (this.controls) {
var prevHandler = function prevHandler(evt) {
/* istanbul ignore next */
if (!_this3.isSliding) {
_this3.handleClick(evt, _this3.prev);
} else {
stopEvent(evt, {
propagation: false
});
}
};
var nextHandler = function nextHandler(evt) {
/* istanbul ignore next */
if (!_this3.isSliding) {
_this3.handleClick(evt, _this3.next);
} else {
stopEvent(evt, {
propagation: false
});
}
};
controls = [h('a', {
class: ['carousel-control-prev'],
attrs: {
href: '#',
role: 'button',
'aria-controls': this.safeId('__BV_inner_'),
'aria-disabled': this.isSliding ? 'true' : null
},
on: {
click: prevHandler,
keydown: prevHandler
}
}, [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_'),
'aria-disabled': this.isSliding ? 'true' : null
},
on: {
click: nextHandler,
keydown: nextHandler
}
}, [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_".concat(n),
class: {
active: n === _this3.index
},
attrs: {
role: 'button',
id: _this3.safeId("__BV_indicator_".concat(n + 1, "_")),
tabindex: _this3.indicators ? '0' : '-1',
'aria-current': n === _this3.index ? 'true' : 'false',
'aria-label': "".concat(_this3.labelGotoSlide, " ").concat(n + 1),
'aria-describedby': _this3.slides[n].id || null,
'aria-controls': _this3.safeId('__BV_inner_')
},
on: {
click: function click(evt) {
_this3.handleClick(evt, function () {
_this3.setSlide(n);
});
},
keydown: function keydown(evt) {
_this3.handleClick(evt, function () {
_this3.setSlide(n);
});
}
}
});
}));
var on = {
mouseenter: this.noHoverPause ? noop : this.pause,
mouseleave: this.noHoverPause ? noop : this.restart,
focusin: this.pause,
focusout: this.restart,
keydown: function keydown(evt) {
if (/input|textarea/i.test(evt.target.tagName)) {
/* istanbul ignore next */
return;
}
var keyCode = evt.keyCode;
if (keyCode === CODE_LEFT || keyCode === CODE_RIGHT) {
stopEvent(evt);
_this3[keyCode === CODE_LEFT ? 'prev' : 'next']();
}
}
}; // Touch support event handlers for environment
if (!this.noTouch && hasTouchSupport) {
// Attach appropriate listeners (prepend event name with '&' for passive mode)
/* istanbul ignore next: JSDOM doesn't support touch events */
if (hasPointerEventSupport) {
on['&pointerdown'] = this.touchStart;
on['&pointerup'] = this.touchEnd;
} else {
on['&touchstart'] = this.touchStart;
on['&touchmove'] = this.touchMove;
on['&touchend'] = this.touchEnd;
}
} // Return the carousel
return h('div', {
staticClass: 'carousel',
class: {
slide: !this.noAnimation,
'carousel-fade': !this.noAnimation && this.fade,
'pointer-event': !this.noTouch && hasTouchSupport && hasPointerEventSupport
},
style: {
background: this.background
},
attrs: {
role: 'region',
id: this.safeId(),
'aria-busy': this.isSliding ? 'true' : 'false'
},
on: on
}, [inner, controls, indicators]);
}
});
var imgProps = {
imgSrc: {
type: String // default: undefined
},
imgAlt: {
type: String // default: undefined
},
imgWidth: {
type: [Number, String] // default: undefined
},
imgHeight: {
type: [Number, String] // default: undefined
},
imgBlank: {
type: Boolean,
default: false
},
imgBlankColor: {
type: String,
default: 'transparent'
}
};
var props$l = makePropsConfigurable(_objectSpread2(_objectSpread2({}, imgProps), {}, {
contentVisibleUp: {
type: String
},
contentTag: {
type: String,
default: 'div'
},
caption: {
type: String
},
captionHtml: {
type: String
},
captionTag: {
type: String,
default: 'h3'
},
text: {
type: String
},
textHtml: {
type: String
},
textTag: {
type: String,
default: 'p'
},
background: {
type: String
}
}), NAME_CAROUSEL_SLIDE); // --- Main component ---
// @vue/component
var BCarouselSlide = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_CAROUSEL_SLIDE,
mixins: [idMixin, normalizeSlotMixin],
inject: {
bvCarousel: {
default: function _default() {
return {
// Explicitly disable touch if not a child of carousel
noTouch: true
};
}
}
},
props: props$l,
computed: {
contentClasses: function contentClasses() {
return [this.contentVisibleUp ? 'd-none' : '', this.contentVisibleUp ? "d-".concat(this.contentVisibleUp, "-block") : ''];
},
computedWidth: function computedWidth() {
// Use local width, or try parent width
return this.imgWidth || this.bvCarousel.imgWidth || null;
},
computedHeight: function computedHeight() {
// Use local height, or try parent height
return this.imgHeight || this.bvCarousel.imgHeight || null;
}
},
render: function render(h) {
var $img = this.normalizeSlot('img');
if (!$img && (this.imgSrc || this.imgBlank)) {
var on = {}; // Touch support event handler
/* istanbul ignore if: difficult to test in JSDOM */
if (!this.bvCarousel.noTouch && hasTouchSupport) {
on.dragstart = function (evt) {
return stopEvent(evt, {
propagation: false
});
};
}
$img = h(BImg, {
props: _objectSpread2(_objectSpread2({}, pluckProps(imgProps, this.$props, unprefixPropName.bind(null, 'img'))), {}, {
width: this.computedWidth,
height: this.computedHeight,
fluidGrow: true,
block: true
}),
on: on
});
}
var $contentChildren = [// Caption
this.caption || this.captionHtml ? h(this.captionTag, {
domProps: htmlOrText(this.captionHtml, this.caption)
}) : false, // Text
this.text || this.textHtml ? h(this.textTag, {
domProps: htmlOrText(this.textHtml, this.text)
}) : false, // Children
this.normalizeSlot() || false];
var $content = h();
if ($contentChildren.some(Boolean)) {
$content = h(this.contentTag, {
staticClass: 'carousel-caption',
class: this.contentClasses
}, $contentChildren.map(function ($child) {
return $child || h();
}));
}
return h('div', {
staticClass: 'carousel-item',
style: {
background: this.background || this.bvCarousel.background || null
},
attrs: {
id: this.safeId(),
role: 'listitem'
}
}, [$img, $content]);
}
});
var CarouselPlugin =
/*#__PURE*/
pluginFactory({
components: {
BCarousel: BCarousel,
BCarouselSlide: BCarouselSlide
}
});
// Generic collapse transion helper component
var onEnter = function onEnter(el) {
setStyle(el, 'height', 0); // In a `requestAF()` for `appear` to work
requestAF(function () {
reflow(el);
setStyle(el, 'height', "".concat(el.scrollHeight, "px"));
});
};
var onAfterEnter = function onAfterEnter(el) {
removeStyle(el, 'height');
};
var onLeave = function onLeave(el) {
setStyle(el, 'height', 'auto');
setStyle(el, 'display', 'block');
setStyle(el, 'height', "".concat(getBCR(el).height, "px"));
reflow(el);
setStyle(el, 'height', 0);
};
var onAfterLeave = function onAfterLeave(el) {
removeStyle(el, 'height');
}; // Default transition props
// `appear` will use the enter classes
var TRANSITION_PROPS = {
css: true,
enterClass: '',
enterActiveClass: 'collapsing',
enterToClass: 'collapse show',
leaveClass: 'collapse show',
leaveActiveClass: 'collapsing',
leaveToClass: 'collapse'
}; // Default transition handlers
// `appear` will use the enter handlers
var TRANSITION_HANDLERS = {
enter: onEnter,
afterEnter: onAfterEnter,
leave: onLeave,
afterLeave: onAfterLeave
}; // @vue/component
var BVCollapse = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_COLLAPSE_HELPER,
functional: true,
props: {
appear: {
// If `true` (and `visible` is `true` on mount), animate initially visible
type: Boolean,
default: false
}
},
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
return h('transition', // We merge in the `appear` prop last
a(data, {
props: TRANSITION_PROPS,
on: TRANSITION_HANDLERS
}, {
props: props
}), // Note: `<transition>` supports a single root element only
children);
}
});
// @vue/component
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
*
* When registering a `$root` listener, it also registers a listener on
* the component's `beforeDestroy()` hook to automatically remove the
* event listener from the `$root` instance
*
* @param {string} event
* @param {function} callback
*/
listenOnRoot: function listenOnRoot(event, callback) {
var _this = this;
this.$root.$on(event, callback);
this.$on('hook:beforeDestroy', function () {
_this.$root.$off(event, callback);
});
},
/**
* Safely register a `$once()` event listener 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
*
* When registering a $root listener, it also registers a listener on
* the component's `beforeDestroy` hook to automatically remove the
* event listener from the $root instance.
*
* @param {string} event
* @param {function} callback
*/
listenOnRootOnce: function listenOnRootOnce(event, callback) {
var _this2 = this;
this.$root.$once(event, callback);
this.$on('hook:beforeDestroy', function () {
_this2.$root.$off(event, callback);
});
},
/**
* Convenience method for calling `vm.$emit()` on `vm.$root`
*
* @param {string} event
* @param {*} args
*/
emitOnRoot: function emitOnRoot(event) {
var _this$$root;
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
(_this$$root = this.$root).$emit.apply(_this$$root, [event].concat(args));
}
}
};
// Classes to apply to trigger element
var CLASS_BV_TOGGLE_COLLAPSED = 'collapsed';
var CLASS_BV_TOGGLE_NOT_COLLAPSED = 'not-collapsed'; // Property key for handler storage
var BV_BASE = '__BV_toggle'; // Root event listener property (Function)
var BV_TOGGLE_ROOT_HANDLER = "".concat(BV_BASE, "_HANDLER__"); // Trigger element click handler property (Function)
var BV_TOGGLE_CLICK_HANDLER = "".concat(BV_BASE, "_CLICK__"); // Target visibility state property (Boolean)
var BV_TOGGLE_STATE = "".concat(BV_BASE, "_STATE__"); // Target ID list property (Array)
var BV_TOGGLE_TARGETS = "".concat(BV_BASE, "_TARGETS__"); // Commonly used strings
var STRING_FALSE = 'false';
var STRING_TRUE = 'true'; // Commonly used attribute names
var ATTR_ARIA_CONTROLS = 'aria-controls';
var ATTR_ARIA_EXPANDED = 'aria-expanded';
var ATTR_ROLE = 'role';
var ATTR_TABINDEX = 'tabindex'; // Commonly used style properties
var STYLE_OVERFLOW_ANCHOR = 'overflow-anchor'; // Emitted control event for collapse (emitted to collapse)
var EVENT_TOGGLE = 'bv::toggle::collapse'; // Listen to event for toggle state update (emitted by collapse)
var EVENT_STATE = 'bv::collapse::state'; // Private event emitted on `$root` to ensure the toggle state is always synced
// Gets emitted even if the state of b-collapse has not changed
// This event is NOT to be documented as people should not be using it
var EVENT_STATE_SYNC = 'bv::collapse::sync::state'; // Private event we send to collapse to request state update sync event
var EVENT_STATE_REQUEST = 'bv::request::collapse::state';
var KEYDOWN_KEY_CODES = [CODE_ENTER, CODE_SPACE]; // --- Helper methods ---
var isNonStandardTag$1 = function isNonStandardTag(el) {
return !arrayIncludes(['button', 'a'], el.tagName.toLowerCase());
};
var getTargets = function getTargets(_ref, el) {
var modifiers = _ref.modifiers,
arg = _ref.arg,
value = _ref.value;
// Any modifiers are considered target IDs
var targets = keys(modifiers || {}); // If value is a string, split out individual targets (if space delimited)
value = isString(value) ? value.split(RX_SPACE_SPLIT) : value; // Support target ID as link href (`href="#id"`)
if (isTag(el.tagName, 'a')) {
var href = getAttr(el, 'href') || '';
if (RX_HASH_ID.test(href)) {
targets.push(href.replace(RX_HASH, ''));
}
} // Add ID from `arg` (if provided), and support value
// as a single string ID or an array of string IDs
// If `value` is not an array or string, then it gets filtered out
concat(arg, value).forEach(function (t) {
return isString(t) && targets.push(t);
}); // Return only unique and truthy target IDs
return targets.filter(function (t, index, arr) {
return t && arr.indexOf(t) === index;
});
};
var removeClickListener = function removeClickListener(el) {
var handler = el[BV_TOGGLE_CLICK_HANDLER];
if (handler) {
eventOff(el, 'click', handler, EVENT_OPTIONS_PASSIVE);
eventOff(el, 'keydown', handler, EVENT_OPTIONS_PASSIVE);
}
el[BV_TOGGLE_CLICK_HANDLER] = null;
};
var addClickListener = function addClickListener(el, vnode) {
removeClickListener(el);
if (vnode.context) {
var handler = function handler(evt) {
if (!(evt.type === 'keydown' && !arrayIncludes(KEYDOWN_KEY_CODES, evt.keyCode)) && !isDisabled(el)) {
var targets = el[BV_TOGGLE_TARGETS] || [];
targets.forEach(function (target) {
vnode.context.$root.$emit(EVENT_TOGGLE, target);
});
}
};
el[BV_TOGGLE_CLICK_HANDLER] = handler;
eventOn(el, 'click', handler, EVENT_OPTIONS_PASSIVE);
if (isNonStandardTag$1(el)) {
eventOn(el, 'keydown', handler, EVENT_OPTIONS_PASSIVE);
}
}
};
var removeRootListeners = function removeRootListeners(el, vnode) {
if (el[BV_TOGGLE_ROOT_HANDLER] && vnode.context) {
vnode.context.$root.$off([EVENT_STATE, EVENT_STATE_SYNC], el[BV_TOGGLE_ROOT_HANDLER]);
}
el[BV_TOGGLE_ROOT_HANDLER] = null;
};
var addRootListeners = function addRootListeners(el, vnode) {
removeRootListeners(el, vnode);
if (vnode.context) {
var handler = function handler(id, state) {
// `state` will be `true` if target is expanded
if (arrayIncludes(el[BV_TOGGLE_TARGETS] || [], id)) {
// Set/Clear 'collapsed' visibility class state
el[BV_TOGGLE_STATE] = state; // Set `aria-expanded` and class state on trigger element
setToggleState(el, state);
}
};
el[BV_TOGGLE_ROOT_HANDLER] = handler; // Listen for toggle state changes (public) and sync (private)
vnode.context.$root.$on([EVENT_STATE, EVENT_STATE_SYNC], handler);
}
};
var setToggleState = function setToggleState(el, state) {
// State refers to the visibility of the collapse/sidebar
if (state) {
removeClass(el, CLASS_BV_TOGGLE_COLLAPSED);
addClass(el, CLASS_BV_TOGGLE_NOT_COLLAPSED);
setAttr(el, ATTR_ARIA_EXPANDED, STRING_TRUE);
} else {
removeClass(el, CLASS_BV_TOGGLE_NOT_COLLAPSED);
addClass(el, CLASS_BV_TOGGLE_COLLAPSED);
setAttr(el, ATTR_ARIA_EXPANDED, STRING_FALSE);
}
}; // Reset and remove a property from the provided element
var resetProp = function resetProp(el, prop) {
el[prop] = null;
delete el[prop];
}; // Handle directive updates
var handleUpdate = function handleUpdate(el, binding, vnode) {
/* istanbul ignore next: should never happen */
if (!isBrowser || !vnode.context) {
return;
} // If element is not a button or link, we add `role="button"`
// and `tabindex="0"` for accessibility reasons
if (isNonStandardTag$1(el)) {
if (!hasAttr(el, ATTR_ROLE)) {
setAttr(el, ATTR_ROLE, 'button');
}
if (!hasAttr(el, ATTR_TABINDEX)) {
setAttr(el, ATTR_TABINDEX, '0');
}
} // Ensure the collapse class and `aria-*` attributes persist
// after element is updated (either by parent re-rendering
// or changes to this element or its contents)
setToggleState(el, el[BV_TOGGLE_STATE]); // Parse list of target IDs
var targets = getTargets(binding, el); // Ensure the `aria-controls` hasn't been overwritten
// or removed when vnode updates
// Also ensure to set `overflow-anchor` to `none` to prevent
// the browser's scroll anchoring behavior
/* istanbul ignore else */
if (targets.length > 0) {
setAttr(el, ATTR_ARIA_CONTROLS, targets.join(' '));
setStyle(el, STYLE_OVERFLOW_ANCHOR, 'none');
} else {
removeAttr(el, ATTR_ARIA_CONTROLS);
removeStyle(el, STYLE_OVERFLOW_ANCHOR);
} // Add/Update our click listener(s)
// Wrap in a `requestAF()` to allow any previous
// click handling to occur first
requestAF(function () {
addClickListener(el, vnode);
}); // If targets array has changed, update
if (!looseEqual(targets, el[BV_TOGGLE_TARGETS])) {
// Update targets array to element storage
el[BV_TOGGLE_TARGETS] = targets; // Ensure `aria-controls` is up to date
// Request a state update from targets so that we can
// ensure expanded state is correct (in most cases)
targets.forEach(function (target) {
vnode.context.$root.$emit(EVENT_STATE_REQUEST, target);
});
}
};
/*
* Export our directive
*/
var VBToggle = {
bind: function bind(el, binding, vnode) {
// State is initially collapsed until we receive a state event
el[BV_TOGGLE_STATE] = false; // Assume no targets initially
el[BV_TOGGLE_TARGETS] = []; // Add our root listeners
addRootListeners(el, vnode); // Initial update of trigger
handleUpdate(el, binding, vnode);
},
componentUpdated: handleUpdate,
updated: handleUpdate,
unbind: function unbind(el, binding, vnode) {
removeClickListener(el); // Remove our $root listener
removeRootListeners(el, vnode); // Reset custom props
resetProp(el, BV_TOGGLE_ROOT_HANDLER);
resetProp(el, BV_TOGGLE_CLICK_HANDLER);
resetProp(el, BV_TOGGLE_STATE);
resetProp(el, BV_TOGGLE_TARGETS); // Reset classes/attrs/styles
removeClass(el, CLASS_BV_TOGGLE_COLLAPSED);
removeClass(el, CLASS_BV_TOGGLE_NOT_COLLAPSED);
removeAttr(el, ATTR_ARIA_EXPANDED);
removeAttr(el, ATTR_ARIA_CONTROLS);
removeAttr(el, ATTR_ROLE);
removeStyle(el, STYLE_OVERFLOW_ANCHOR);
}
};
// Accordion event name we emit on `$root`
var EVENT_ACCORDION = 'bv::collapse::accordion'; // --- Main component ---
// @vue/component
var BCollapse = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_COLLAPSE,
mixins: [idMixin, listenOnRootMixin, normalizeSlotMixin],
model: {
prop: 'visible',
event: 'input'
},
props: makePropsConfigurable({
isNav: {
type: Boolean,
default: false
},
accordion: {
type: String // default: null
},
visible: {
type: Boolean,
default: false
},
tag: {
type: String,
default: 'div'
},
appear: {
// If `true` (and `visible` is `true` on mount), animate initially visible
type: Boolean,
default: false
}
}, NAME_COLLAPSE),
data: function data() {
return {
show: this.visible,
transitioning: false
};
},
computed: {
classObject: function classObject() {
return {
'navbar-collapse': this.isNav,
collapse: !this.transitioning,
show: this.show && !this.transitioning
};
}
},
watch: {
visible: function visible(newVal) {
if (newVal !== this.show) {
this.show = newVal;
}
},
show: function show(newVal, oldVal) {
if (newVal !== oldVal) {
this.emitState();
}
}
},
created: function created() {
this.show = this.visible;
},
mounted: function mounted() {
var _this = this;
this.show = this.visible; // Listen for toggle events to open/close us
this.listenOnRoot(EVENT_TOGGLE, this.handleToggleEvt); // Listen to other collapses for accordion events
this.listenOnRoot(EVENT_ACCORDION, this.handleAccordionEvt);
if (this.isNav) {
// Set up handlers
this.setWindowEvents(true);
this.handleResize();
}
this.$nextTick(function () {
_this.emitState();
}); // Listen for "Sync state" requests from `v-b-toggle`
this.listenOnRoot(EVENT_STATE_REQUEST, function (id) {
if (id === _this.safeId()) {
_this.$nextTick(_this.emitSync);
}
});
},
updated: function updated() {
// Emit a private event every time this component updates to ensure
// the toggle button is in sync with the collapse's state
// It is emitted regardless if the visible state changes
this.emitSync();
},
/* istanbul ignore next */
deactivated: function deactivated() {
if (this.isNav) {
this.setWindowEvents(false);
}
},
/* istanbul ignore next */
activated: function activated() {
if (this.isNav) {
this.setWindowEvents(true);
}
this.emitSync();
},
beforeDestroy: function beforeDestroy() {
// Trigger state emit if needed
this.show = false;
if (this.isNav && isBrowser) {
this.setWindowEvents(false);
}
},
methods: {
setWindowEvents: function setWindowEvents(on) {
eventOnOff(on, window, 'resize', this.handleResize, EVENT_OPTIONS_NO_CAPTURE);
eventOnOff(on, window, 'orientationchange', this.handleResize, EVENT_OPTIONS_NO_CAPTURE);
},
toggle: function toggle() {
this.show = !this.show;
},
onEnter: function onEnter() {
this.transitioning = true; // This should be moved out so we can add cancellable events
this.$emit('show');
},
onAfterEnter: function onAfterEnter() {
this.transitioning = false;
this.$emit('shown');
},
onLeave: function onLeave() {
this.transitioning = true; // This should be moved out so we can add cancellable events
this.$emit('hide');
},
onAfterLeave: function onAfterLeave() {
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.emitOnRoot(EVENT_STATE, this.safeId(), this.show);
if (this.accordion && this.show) {
// Tell the other collapses in this accordion to close
this.emitOnRoot(EVENT_ACCORDION, this.safeId(), this.accordion);
}
},
emitSync: function emitSync() {
// Emit a private event every time this component updates to ensure
// the toggle button is in sync with the collapse's state
// It is emitted regardless if the visible state changes
this.emitOnRoot(EVENT_STATE_SYNC, this.safeId(), this.show);
},
checkDisplayBlock: function checkDisplayBlock() {
// Check to see if the collapse has `display: block !important` set
// We can't set `display: none` directly on `this.$el`, as it would
// trigger a new transition to start (or cancel a current one)
var restore = hasClass(this.$el, 'show');
removeClass(this.$el, 'show');
var isBlock = getCS(this.$el).display === 'block';
if (restore) {
addClass(this.$el, 'show');
}
return isBlock;
},
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 || getCS(this.$el).display !== 'block') {
/* istanbul ignore next: can't test getComputedStyle in JSDOM */
return;
}
if (matches(el, '.nav-link,.dropdown-item') || closest('.nav-link,.dropdown-item', el)) {
if (!this.checkDisplayBlock()) {
// Only close the collapse if it is not forced to be `display: block !important`
this.show = false;
}
}
},
handleToggleEvt: function handleToggleEvt(target) {
if (target !== this.safeId()) {
return;
}
this.toggle();
},
handleAccordionEvt: function handleAccordionEvt(openedId, accordion) {
if (!this.accordion || accordion !== this.accordion) {
return;
}
if (openedId === this.safeId()) {
// 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 = getCS(this.$el).display === 'block';
}
},
render: function render(h) {
var _this2 = this;
var scope = {
visible: this.show,
close: function close() {
return _this2.show = false;
}
};
var content = h(this.tag, {
class: this.classObject,
directives: [{
name: 'show',
value: this.show
}],
attrs: {
id: this.safeId()
},
on: {
click: this.clickHandler
}
}, [this.normalizeSlot(SLOT_NAME_DEFAULT, scope)]);
return h(BVCollapse, {
props: {
appear: this.appear
},
on: {
enter: this.onEnter,
afterEnter: this.onAfterEnter,
leave: this.onLeave,
afterLeave: this.onAfterLeave
}
}, [content]);
}
});
var VBTogglePlugin = /*#__PURE__*/pluginFactory({
directives: {
VBToggle: VBToggle
}
});
var CollapsePlugin = /*#__PURE__*/pluginFactory({
components: {
BCollapse: BCollapse
},
plugins: {
VBTogglePlugin: VBTogglePlugin
}
});
/**!
* @fileOverview Kickass library to create and place poppers near their reference elements.
* @version 1.16.1
* @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$1 = typeof window !== 'undefined' && typeof document !== 'undefined' && typeof navigator !== 'undefined';
var timeoutDuration = function () {
var longerTimeoutBrowsers = ['Edge', 'Trident', 'Firefox'];
for (var i = 0; i < longerTimeoutBrowsers.length; i += 1) {
if (isBrowser$1 && navigator.userAgent.indexOf(longerTimeoutBrowsers[i]) >= 0) {
return 1;
}
}
return 0;
}();
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$1 && 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$1(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 window = element.ownerDocument.defaultView;
var css = window.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));
}
/**
* Returns the reference node of the reference object, or the reference object itself.
* @method
* @memberof Popper.Utils
* @param {Element|Object} reference - the reference element (the popper will be relative to this)
* @returns {Element} parent
*/
function getReferenceNode(reference) {
return reference && reference.referenceNode ? reference.referenceNode : reference;
}
var isIE11 = isBrowser$1 && !!(window.MSInputMethodContext && document.documentMode);
var isIE10 = isBrowser$1 && /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$1(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$1(10) ? document.body : null;
// NOTE: 1 DOM access here
var offsetParent = element.offsetParent || null;
// 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 TH, TD or TABLE in case
// no offsetParent is present, I hate this job...
if (['TH', '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']) + parseFloat(styles['border' + sideB + 'Width']);
}
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$1(10) ? parseInt(html['offset' + axis]) + parseInt(computedStyle['margin' + (axis === 'Height' ? 'Top' : 'Left')]) + parseInt(computedStyle['margin' + (axis === 'Height' ? 'Bottom' : 'Right')]) : 0);
}
function getWindowSizes(document) {
var body = document.body;
var html = document.documentElement;
var computedStyle = isIE$1(10) && getComputedStyle(html);
return {
height: getSize('Height', body, html, computedStyle),
width: getSize('Width', body, html, computedStyle)
};
}
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$1 = 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 _extends = Object.assign || function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
/**
* 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({}, 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$1(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(element.ownerDocument) : {};
var width = sizes.width || element.clientWidth || result.width;
var height = sizes.height || element.clientHeight || result.height;
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$1(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);
var borderLeftWidth = parseFloat(styles.borderLeftWidth);
// In cases where the parent is fixed, we must ignore negative scroll in offset calc
if (fixedPosition && isHTML) {
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);
var marginLeft = parseFloat(styles.marginLeft);
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;
}
var parentNode = getParentNode(element);
if (!parentNode) {
return false;
}
return isFixed(parentNode);
}
/**
* 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$1()) {
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, getReferenceNode(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(popper.ownerDocument),
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
padding = padding || 0;
var isPaddingNumber = typeof padding === 'number';
boundaries.left += isPaddingNumber ? padding : padding.left || 0;
boundaries.top += isPaddingNumber ? padding : padding.top || 0;
boundaries.right -= isPaddingNumber ? padding : padding.right || 0;
boundaries.bottom -= isPaddingNumber ? padding : padding.bottom || 0;
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({
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, getReferenceNode(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 window = element.ownerDocument.defaultView;
var styles = window.getComputedStyle(element);
var x = parseFloat(styles.marginTop || 0) + parseFloat(styles.marginBottom || 0);
var y = parseFloat(styles.marginLeft || 0) + parseFloat(styles.marginRight || 0);
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$1(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;
}
/**
* Destroys the popper.
* @method
* @memberof Popper
*/
function destroy$1() {
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 explicitly 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$1(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$1(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 Popper.Utils
* @argument {Object} data - The data object generated by `update` method
* @argument {Boolean} shouldRound - If the offsets should be rounded at all
* @returns {Object} The popper's position offsets rounded
*
* The tale of pixel-perfect positioning. It's still not 100% perfect, but as
* good as it can be within reason.
* Discussion here: https://github.com/FezVrasta/popper.js/pull/715
*
* Low DPI screens cause a popper to be blurry if not using full pixels (Safari
* as well on High DPI screens).
*
* Firefox prefers no rounding for positioning and does not have blurriness on
* high DPI screens.
*
* Only horizontal placement and left/right values need to be considered.
*/
function getRoundedOffsets(data, shouldRound) {
var _data$offsets = data.offsets,
popper = _data$offsets.popper,
reference = _data$offsets.reference;
var round = Math.round,
floor = Math.floor;
var noRound = function noRound(v) {
return v;
};
var referenceWidth = round(reference.width);
var popperWidth = round(popper.width);
var isVertical = ['left', 'right'].indexOf(data.placement) !== -1;
var isVariation = data.placement.indexOf('-') !== -1;
var sameWidthParity = referenceWidth % 2 === popperWidth % 2;
var bothOddWidth = referenceWidth % 2 === 1 && popperWidth % 2 === 1;
var horizontalToInteger = !shouldRound ? noRound : isVertical || isVariation || sameWidthParity ? round : floor;
var verticalToInteger = !shouldRound ? noRound : round;
return {
left: horizontalToInteger(bothOddWidth && !isVariation && shouldRound ? popper.left - 1 : popper.left),
top: verticalToInteger(popper.top),
bottom: verticalToInteger(popper.bottom),
right: horizontalToInteger(popper.right)
};
}
var isFirefox = isBrowser$1 && /Firefox/i.test(navigator.userAgent);
/**
* @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
};
var offsets = getRoundedOffsets(data, window.devicePixelRatio < 2 || !isFirefox);
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') {
// when offsetParent is <html> the positioning is relative to the bottom of the screen (excluding the scrollbar)
// and not the bottom of the html element
if (offsetParent.nodeName === 'HTML') {
top = -offsetParent.clientHeight + offsets.bottom;
} else {
top = -offsetParentRect.height + offsets.bottom;
}
} else {
top = offsets.top;
}
if (sideB === 'right') {
if (offsetParent.nodeName === 'HTML') {
left = -offsetParent.clientWidth + offsets.right;
} else {
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({}, attributes, data.attributes);
data.styles = _extends({}, styles, data.styles);
data.arrowStyles = _extends({}, 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 conjunction
//
// 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]);
var popperBorderSide = parseFloat(css['border' + sideCapitalized + 'Width']);
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$1(_data$offsets$arrow, side, Math.round(sideValue)), defineProperty$1(_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-end` (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;
// flips variation if reference element overflows boundaries
var flippedVariationByRef = !!options.flipVariations && (isVertical && variation === 'start' && overflowsLeft || isVertical && variation === 'end' && overflowsRight || !isVertical && variation === 'start' && overflowsTop || !isVertical && variation === 'end' && overflowsBottom);
// flips variation if popper content overflows boundaries
var flippedVariationByContent = !!options.flipVariationsByContent && (isVertical && variation === 'start' && overflowsRight || isVertical && variation === 'end' && overflowsLeft || !isVertical && variation === 'start' && overflowsBottom || !isVertical && variation === 'end' && overflowsTop);
var flippedVariation = flippedVariationByRef || flippedVariationByContent;
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({}, 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$1(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$1(+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$1({}, 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$1({}, mainSide, value);
}
};
order.forEach(function (placement) {
var side = ['left', 'top'].indexOf(placement) !== -1 ? 'primary' : 'secondary';
popper = _extends({}, 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$1({}, side, reference[side]),
end: defineProperty$1({}, side, reference[side] + reference[measurement] - popper[measurement])
};
data.offsets.popper = _extends({}, 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 unit-less, 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.
* > You can read more on this at 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.
*
* A 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 always has 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 each other
* without leaving any gap between the two. Especially useful when the arrow is
* enabled and you want to ensure that it points 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 conjunction 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',
/**
* @prop {Boolean} flipVariations=false
* The popper will switch placement variation between `-start` and `-end` when
* the reference element overlaps its boundaries.
*
* The original placement should have a set variation.
*/
flipVariations: false,
/**
* @prop {Boolean} flipVariationsByContent=false
* The popper will switch placement variation between `-start` and `-end` when
* the popper element overlaps its reference boundaries.
*
* The original placement should have a set variation.
*/
flipVariationsByContent: false
},
/**
* 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 your 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 information used by Popper.js.
* This object is 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 overridden using the `options` argument of Popper.js.<br />
* To override an option, simply pass an object with the same
* structure of the `options` object, as the 3rd argument. For 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, it 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, it 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 () {
/**
* Creates a new Popper.js instance.
* @class Popper
* @param {Element|referenceObject} reference - The reference element used to position the popper
* @param {Element} popper - The HTML / XML element used as the 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(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({}, 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({}, Popper.Defaults.modifiers, options.modifiers)).forEach(function (name) {
_this.options.modifiers[name] = _extends({}, 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({
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$1(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(Popper, [{
key: 'update',
value: function update$$1() {
return update.call(this);
}
}, {
key: 'destroy',
value: function destroy$$1() {
return destroy$1.call(this);
}
}, {
key: 'enableEventListeners',
value: function enableEventListeners$$1() {
return enableEventListeners.call(this);
}
}, {
key: 'disableEventListeners',
value: function disableEventListeners$$1() {
return disableEventListeners.call(this);
}
/**
* Schedules 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 PLACEMENT_TOP_START = 'top-start';
var PLACEMENT_TOP_END = 'top-end';
var PLACEMENT_BOTTOM_START = 'bottom-start';
var PLACEMENT_BOTTOM_END = 'bottom-end';
var PLACEMENT_RIGHT_START = 'right-start';
var PLACEMENT_LEFT_START = 'left-start';
var BvEvent = /*#__PURE__*/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) {
/* istanbul ignore next */
throw new TypeError("Failed to construct '".concat(this.constructor.name, "'. 1 argument required, ").concat(arguments.length, " given."));
} // Merge defaults first, the eventInit, and the type last
// so it can't be overwritten
assign(this, BvEvent.Defaults, this.constructor.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(),
componentId: 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(this, 'defaultPrevented', {
enumerable: true,
get: function get() {
return defaultPrevented;
}
});
}
_createClass(BvEvent, null, [{
key: "Defaults",
get: function get() {
return {
type: '',
cancelable: true,
nativeEvent: null,
target: null,
relatedTarget: null,
vueTarget: null,
componentId: null
};
}
}]);
return BvEvent;
}(); // Named Exports
var clickOutMixin = {
data: function data() {
return {
listenForClickOut: false
};
},
watch: {
listenForClickOut: function listenForClickOut(newValue, oldValue) {
if (newValue !== oldValue) {
eventOff(this.clickOutElement, this.clickOutEventName, this._clickOutHandler, EVENT_OPTIONS_NO_CAPTURE);
if (newValue) {
eventOn(this.clickOutElement, this.clickOutEventName, this._clickOutHandler, EVENT_OPTIONS_NO_CAPTURE);
}
}
}
},
beforeCreate: function beforeCreate() {
// Declare non-reactive properties
this.clickOutElement = null;
this.clickOutEventName = null;
},
mounted: function mounted() {
if (!this.clickOutElement) {
this.clickOutElement = document;
}
if (!this.clickOutEventName) {
this.clickOutEventName = 'click';
}
if (this.listenForClickOut) {
eventOn(this.clickOutElement, this.clickOutEventName, this._clickOutHandler, EVENT_OPTIONS_NO_CAPTURE);
}
},
beforeDestroy: function beforeDestroy() {
eventOff(this.clickOutElement, this.clickOutEventName, this._clickOutHandler, EVENT_OPTIONS_NO_CAPTURE);
},
methods: {
isClickOut: function isClickOut(evt) {
return !contains(this.$el, evt.target);
},
_clickOutHandler: function _clickOutHandler(evt) {
if (this.clickOutHandler && this.isClickOut(evt)) {
this.clickOutHandler(evt);
}
}
}
};
var focusInMixin = {
data: function data() {
return {
listenForFocusIn: false
};
},
watch: {
listenForFocusIn: function listenForFocusIn(newValue, oldValue) {
if (newValue !== oldValue) {
eventOff(this.focusInElement, 'focusin', this._focusInHandler, EVENT_OPTIONS_NO_CAPTURE);
if (newValue) {
eventOn(this.focusInElement, 'focusin', this._focusInHandler, EVENT_OPTIONS_NO_CAPTURE);
}
}
}
},
beforeCreate: function beforeCreate() {
// Declare non-reactive properties
this.focusInElement = null;
},
mounted: function mounted() {
if (!this.focusInElement) {
this.focusInElement = document;
}
if (this.listenForFocusIn) {
eventOn(this.focusInElement, 'focusin', this._focusInHandler, EVENT_OPTIONS_NO_CAPTURE);
}
},
beforeDestroy: function beforeDestroy() {
eventOff(this.focusInElement, 'focusin', this._focusInHandler, EVENT_OPTIONS_NO_CAPTURE);
},
methods: {
_focusInHandler: function _focusInHandler(evt) {
if (this.focusInHandler) {
this.focusInHandler(evt);
}
}
}
};
// Root dropdown event names
var ROOT_EVENT_PREFIX = 'bv::dropdown::';
var ROOT_EVENT_SHOWN = "".concat(ROOT_EVENT_PREFIX, "shown");
var ROOT_EVENT_HIDDEN = "".concat(ROOT_EVENT_PREFIX, "hidden"); // CSS selectors
var SELECTOR_FORM_CHILD = '.dropdown form';
var SELECTOR_ITEM = ['.dropdown-item', '.b-dropdown-form'].map(function (selector) {
return "".concat(selector, ":not(.disabled):not([disabled])");
}).join(', '); // --- Utility methods ---
// Return an array of visible items
var filterVisibles = function filterVisibles(els) {
return (els || []).filter(isVisible);
}; // --- Props ---
var commonProps = makePropsConfigurable({
dropup: {
// place on top if possible
type: Boolean,
default: false
},
dropright: {
// place right if possible
type: Boolean,
default: false
},
dropleft: {
// place left 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() {}
},
boundary: {
// String: `scrollParent`, `window` or `viewport`
// HTMLElement: HTML Element reference
type: [String, HTMLElement],
default: 'scrollParent'
}
}, NAME_DROPDOWN);
var props$m = _objectSpread2(_objectSpread2({}, commonProps), makePropsConfigurable({
disabled: {
type: Boolean,
default: false
}
}, NAME_DROPDOWN)); // --- Mixin ---
// @vue/component
var dropdownMixin = {
mixins: [idMixin, clickOutMixin, focusInMixin],
provide: function provide() {
return {
bvDropdown: this
};
},
inject: {
bvNavbar: {
default: null
}
},
props: props$m,
data: function data() {
return {
visible: false,
visibleChangePrevented: false
};
},
computed: {
inNavbar: function inNavbar() {
return !isNull(this.bvNavbar);
},
toggler: function toggler() {
var toggle = this.$refs.toggle;
return toggle ? toggle.$el || toggle : null;
},
directionClass: function directionClass() {
if (this.dropup) {
return 'dropup';
} else if (this.dropright) {
return 'dropright';
} else if (this.dropleft) {
return 'dropleft';
}
return '';
},
boundaryClass: function boundaryClass() {
// 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
return this.boundary !== 'scrollParent' && !this.inNavbar ? 'position-static' : '';
}
},
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,
componentId: this.safeId ? this.safeId() : this.id || null
});
this.emitEvent(bvEvt);
if (bvEvt.defaultPrevented) {
// Reset value and exit if canceled
this.visibleChangePrevented = true;
this.visible = oldValue; // Just in case a child element triggered `this.hide(true)`
this.$off('hidden', this.focusToggler);
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;
}
}
},
created: function created() {
// Create private non-reactive props
this.$_popper = null;
this.$_hideTimeout = null;
},
/* istanbul ignore next */
deactivated: function deactivated() {
// In case we are inside a `<keep-alive>`
this.visible = false;
this.whileOpenListen(false);
this.destroyPopper();
},
beforeDestroy: function beforeDestroy() {
this.visible = false;
this.whileOpenListen(false);
this.destroyPopper();
this.clearHideTimeout();
},
methods: {
// Event emitter
emitEvent: function emitEvent(bvEvt) {
var type = bvEvt.type;
this.$emit(type, bvEvt);
this.$root.$emit("".concat(ROOT_EVENT_PREFIX).concat(type), bvEvt);
},
showMenu: function showMenu() {
var _this = this;
if (this.disabled) {
/* istanbul ignore next */
return;
} // Only instantiate Popper.js when dropdown is not in `<b-navbar>`
if (!this.inNavbar) {
if (typeof Popper === 'undefined') {
/* istanbul ignore next */
warn('Popper.js not found. Falling back to CSS positioning', NAME_DROPDOWN);
} else {
// For dropup with alignment we use the parent element as popper container
var el = this.dropup && this.right || this.split ? this.$el : this.$refs.toggle; // Make sure we have a reference to an element, not a component!
el = el.$el || el; // Instantiate Popper.js
this.createPopper(el);
}
} // Ensure other menus are closed
this.$root.$emit(ROOT_EVENT_SHOWN, this); // Enable listeners
this.whileOpenListen(true); // Wrap in `$nextTick()` to ensure menu is fully rendered/shown
this.$nextTick(function () {
// Focus on the menu container on show
_this.focusMenu(); // Emit the shown event
_this.$emit('shown');
});
},
hideMenu: function hideMenu() {
this.whileOpenListen(false);
this.$root.$emit(ROOT_EVENT_HIDDEN, this);
this.$emit('hidden');
this.destroyPopper();
},
createPopper: function createPopper(element) {
this.destroyPopper();
this.$_popper = new Popper(element, this.$refs.menu, this.getPopperConfig());
},
// Ensure popper event listeners are removed cleanly
destroyPopper: function destroyPopper() {
this.$_popper && this.$_popper.destroy();
this.$_popper = null;
},
// Instructs popper to re-computes the dropdown position
// useful if the content changes size
updatePopper: function updatePopper() {
try {
this.$_popper.scheduleUpdate();
} catch (_unused) {}
},
clearHideTimeout: function clearHideTimeout() {
clearTimeout(this.$_hideTimeout);
this.$_hideTimeout = null;
},
getPopperConfig: function getPopperConfig() {
var placement = PLACEMENT_BOTTOM_START;
if (this.dropup) {
placement = this.right ? PLACEMENT_TOP_END : PLACEMENT_TOP_START;
} else if (this.dropright) {
placement = PLACEMENT_RIGHT_START;
} else if (this.dropleft) {
placement = PLACEMENT_LEFT_START;
} else if (this.right) {
placement = PLACEMENT_BOTTOM_END;
}
var popperConfig = {
placement: placement,
modifiers: {
offset: {
offset: this.offset || 0
},
flip: {
enabled: !this.noFlip
}
}
};
var boundariesElement = this.boundary;
if (boundariesElement) {
popperConfig.modifiers.preventOverflow = {
boundariesElement: boundariesElement
};
}
return mergeDeep(popperConfig, this.popperOpts || {});
},
// Turn listeners on/off while open
whileOpenListen: function whileOpenListen(isOpen) {
// Hide the dropdown when clicked outside
this.listenForClickOut = isOpen; // Hide the dropdown when it loses focus
this.listenForFocusIn = isOpen; // Hide the dropdown when another dropdown is opened
var method = isOpen ? '$on' : '$off';
this.$root[method](ROOT_EVENT_SHOWN, this.rootCloseListener);
},
rootCloseListener: function rootCloseListener(vm) {
if (vm !== this) {
this.visible = false;
}
},
// Public method to show dropdown
show: function show() {
var _this2 = this;
if (this.disabled) {
return;
} // Wrap in a `requestAF()` to allow any previous
// click handling to occur first
requestAF(function () {
_this2.visible = true;
});
},
// Public method to hide dropdown
hide: function hide() {
var refocus = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
/* istanbul ignore next */
if (this.disabled) {
return;
}
this.visible = false;
if (refocus) {
// Child element is closing the dropdown on click
this.$once('hidden', this.focusToggler);
}
},
// Called only by a button that toggles the menu
toggle: function toggle(evt) {
evt = evt || {}; // Early exit when not a click event or ENTER, SPACE or DOWN were pressed
var _evt = evt,
type = _evt.type,
keyCode = _evt.keyCode;
if (type !== 'click' && !(type === 'keydown' && [CODE_ENTER, CODE_SPACE, CODE_DOWN].indexOf(keyCode) !== -1)) {
/* istanbul ignore next */
return;
}
/* istanbul ignore next */
if (this.disabled) {
this.visible = false;
return;
}
this.$emit('toggle', evt);
stopEvent(evt); // Toggle visibility
if (this.visible) {
this.hide(true);
} else {
this.show();
}
},
// Mousedown handler for the toggle
/* istanbul ignore next */
onMousedown: function onMousedown(evt) {
// We prevent the 'mousedown' event for the toggle to stop the
// 'focusin' event from being fired
// The event would otherwise be picked up by the global 'focusin'
// listener and there is no cross-browser solution to detect it
// relates to the toggle click
// The 'click' event will still be fired and we handle closing
// other dropdowns there too
// See https://github.com/bootstrap-vue/bootstrap-vue/issues/4328
stopEvent(evt, {
propagation: false
});
},
// Called from dropdown menu context
onKeydown: function onKeydown(evt) {
var keyCode = evt.keyCode;
if (keyCode === CODE_ESC) {
// Close on ESC
this.onEsc(evt);
} else if (keyCode === CODE_DOWN) {
// Down Arrow
this.focusNext(evt, false);
} else if (keyCode === CODE_UP) {
// Up Arrow
this.focusNext(evt, true);
}
},
// If user presses ESC, close the menu
onEsc: function onEsc(evt) {
if (this.visible) {
this.visible = false;
stopEvent(evt); // Return focus to original trigger button
this.$once('hidden', this.focusToggler);
}
},
// Called only in split button mode, for the split button
onSplitClick: function onSplitClick(evt) {
/* istanbul ignore next */
if (this.disabled) {
this.visible = false;
return;
}
this.$emit('click', evt);
},
// Shared hide handler between click-out and focus-in events
hideHandler: function hideHandler(evt) {
var _this3 = this;
var target = evt.target;
if (this.visible && !contains(this.$refs.menu, target) && !contains(this.toggler, target)) {
this.clearHideTimeout();
this.$_hideTimeout = setTimeout(function () {
return _this3.hide();
}, this.inNavbar ? 300 : 0);
}
},
// Document click-out listener
clickOutHandler: function clickOutHandler(evt) {
this.hideHandler(evt);
},
// Document focus-in listener
focusInHandler: function focusInHandler(evt) {
this.hideHandler(evt);
},
// Keyboard nav
focusNext: function focusNext(evt, up) {
var _this4 = this;
// Ignore key up/down on form elements
var target = evt.target;
if (!this.visible || evt && closest(SELECTOR_FORM_CHILD, target)) {
/* istanbul ignore next: should never happen */
return;
}
stopEvent(evt);
this.$nextTick(function () {
var items = _this4.getItems();
if (items.length < 1) {
/* istanbul ignore next: should never happen */
return;
}
var index = items.indexOf(target);
if (up && index > 0) {
index--;
} else if (!up && index < items.length - 1) {
index++;
}
if (index < 0) {
/* istanbul ignore next: should never happen */
index = 0;
}
_this4.focusItem(index, items);
});
},
focusItem: function focusItem(index, items) {
var el = items.find(function (el, i) {
return i === index;
});
attemptFocus(el);
},
getItems: function getItems() {
// Get all items
return filterVisibles(selectAll(SELECTOR_ITEM, this.$refs.menu));
},
focusMenu: function focusMenu() {
attemptFocus(this.$refs.menu);
},
focusToggler: function focusToggler() {
var _this5 = this;
this.$nextTick(function () {
attemptFocus(_this5.toggler);
});
}
}
};
var props$n = makePropsConfigurable(_objectSpread2(_objectSpread2({}, props$m), {}, {
text: {
type: String // default: null
},
html: {
type: String // default: null
},
variant: {
type: String,
default: 'secondary'
},
size: {
type: String // default: null
},
block: {
type: Boolean,
default: false
},
menuClass: {
type: [String, Array, Object] // default: null
},
toggleTag: {
type: String,
default: 'button'
},
toggleText: {
// TODO: This really should be `toggleLabel`
type: String,
default: 'Toggle dropdown'
},
toggleClass: {
type: [String, Array, Object] // default: null
},
noCaret: {
type: Boolean,
default: false
},
split: {
type: Boolean,
default: false
},
splitHref: {
type: String // default: undefined
},
splitTo: {
type: [String, Object] // default: undefined
},
splitVariant: {
type: String // default: undefined
},
splitClass: {
type: [String, Array, Object] // default: null
},
splitButtonType: {
type: String,
default: 'button',
validator: function validator(value) {
return arrayIncludes(['button', 'submit', 'reset'], value);
}
},
lazy: {
// If true, only render menu contents when open
type: Boolean,
default: false
},
role: {
type: String,
default: 'menu'
}
}), NAME_DROPDOWN); // --- Main component ---
// @vue/component
var BDropdown = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_DROPDOWN,
mixins: [idMixin, dropdownMixin, normalizeSlotMixin],
props: props$n,
computed: {
dropdownClasses: function dropdownClasses() {
var block = this.block,
split = this.split;
return [this.directionClass, this.boundaryClass, {
show: this.visible,
// The 'btn-group' class is required in `split` mode for button alignment
// It needs also to be applied when `block` is disabled to allow multiple
// dropdowns to be aligned one line
'btn-group': split || !block,
// When `block` is enabled and we are in `split` mode the 'd-flex' class
// needs to be applied to allow the buttons to stretch to full width
'd-flex': block && split
}];
},
menuClasses: function menuClasses() {
return [this.menuClass, {
'dropdown-menu-right': this.right,
show: this.visible
}];
},
toggleClasses: function toggleClasses() {
var split = this.split;
return [this.toggleClass, {
'dropdown-toggle-split': split,
'dropdown-toggle-no-caret': this.noCaret && !split
}];
}
},
render: function render(h) {
var visible = this.visible,
variant = this.variant,
size = this.size,
block = this.block,
disabled = this.disabled,
split = this.split,
role = this.role,
hide = this.hide,
toggle = this.toggle;
var commonProps = {
variant: variant,
size: size,
block: block,
disabled: disabled
};
var buttonContentSlotName = 'button-content';
var $buttonChildren = this.normalizeSlot(buttonContentSlotName);
var buttonContentDomProps = this.hasNormalizedSlot(buttonContentSlotName) ? {} : htmlOrText(this.html, this.text);
var $split = h();
if (split) {
var splitTo = this.splitTo,
splitHref = this.splitHref,
splitButtonType = this.splitButtonType;
var btnProps = _objectSpread2(_objectSpread2({}, commonProps), {}, {
variant: this.splitVariant || variant
}); // We add these as needed due to <router-link> issues with
// defined property with `undefined`/`null` values
if (splitTo) {
btnProps.to = splitTo;
} else if (splitHref) {
btnProps.href = splitHref;
} else if (splitButtonType) {
btnProps.type = splitButtonType;
}
$split = h(BButton, {
class: this.splitClass,
attrs: {
id: this.safeId('_BV_button_')
},
props: btnProps,
domProps: buttonContentDomProps,
on: {
click: this.onSplitClick
},
ref: 'button'
}, $buttonChildren); // Overwrite button content for the toggle when in `split` mode
$buttonChildren = [h('span', {
class: ['sr-only']
}, [this.toggleText])];
buttonContentDomProps = {};
}
var $toggle = h(BButton, {
staticClass: 'dropdown-toggle',
class: this.toggleClasses,
attrs: {
id: this.safeId('_BV_toggle_'),
'aria-haspopup': 'true',
'aria-expanded': toString$1(visible)
},
props: _objectSpread2(_objectSpread2({}, commonProps), {}, {
tag: this.toggleTag,
block: block && !split
}),
domProps: buttonContentDomProps,
on: {
mousedown: this.onMousedown,
click: toggle,
keydown: toggle // Handle ENTER, SPACE and DOWN
},
ref: 'toggle'
}, $buttonChildren);
var $menu = h('ul', {
staticClass: 'dropdown-menu',
class: this.menuClasses,
attrs: {
role: role,
tabindex: '-1',
'aria-labelledby': this.safeId(split ? '_BV_button_' : '_BV_toggle_')
},
on: {
keydown: this.onKeydown // Handle UP, DOWN and ESC
},
ref: 'menu'
}, [!this.lazy || visible ? this.normalizeSlot(SLOT_NAME_DEFAULT, {
hide: hide
}) : h()]);
return h('div', {
staticClass: 'dropdown b-dropdown',
class: this.dropdownClasses,
attrs: {
id: this.safeId()
}
}, [$split, $toggle, $menu]);
}
});
var props$o = omit(props$1, ['event', 'routerTag']); // @vue/component
var BDropdownItem = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_DROPDOWN_ITEM,
mixins: [attrsMixin, normalizeSlotMixin],
inject: {
bvDropdown: {
default: null
}
},
inheritAttrs: false,
props: makePropsConfigurable(_objectSpread2(_objectSpread2({}, props$o), {}, {
linkClass: {
type: [String, Array, Object] // default: null
},
variant: {
type: String // default: null
}
}), NAME_DROPDOWN_ITEM),
computed: {
computedAttrs: function computedAttrs() {
return _objectSpread2(_objectSpread2({}, this.bvAttrs), {}, {
role: 'menuitem'
});
}
},
methods: {
closeDropdown: function closeDropdown() {
var _this = this;
// Close on next animation frame to allow <b-link> time to process
requestAF(function () {
if (_this.bvDropdown) {
_this.bvDropdown.hide(true);
}
});
},
onClick: function onClick(evt) {
this.$emit('click', evt);
this.closeDropdown();
}
},
render: function render(h) {
var linkClass = this.linkClass,
variant = this.variant,
active = this.active,
disabled = this.disabled,
onClick = this.onClick;
return h('li', {
attrs: {
role: 'presentation'
}
}, [h(BLink, {
staticClass: 'dropdown-item',
class: [linkClass, _defineProperty({}, "text-".concat(variant), variant && !(active || disabled))],
props: this.$props,
attrs: this.computedAttrs,
on: {
click: onClick
},
ref: 'item'
}, this.normalizeSlot())]);
}
});
var props$p = makePropsConfigurable({
active: {
type: Boolean,
default: false
},
activeClass: {
type: String,
default: 'active'
},
buttonClass: {
type: [String, Array, Object] // default: null
},
disabled: {
type: Boolean,
default: false
},
variant: {
type: String // default: null
}
}, NAME_DROPDOWN_ITEM_BUTTON); // @vue/component
var BDropdownItemButton = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_DROPDOWN_ITEM_BUTTON,
mixins: [attrsMixin, normalizeSlotMixin],
inject: {
bvDropdown: {
default: null
}
},
inheritAttrs: false,
props: props$p,
computed: {
computedAttrs: function computedAttrs() {
return _objectSpread2(_objectSpread2({}, this.bvAttrs), {}, {
role: 'menuitem',
type: 'button',
disabled: this.disabled
});
}
},
methods: {
closeDropdown: function closeDropdown() {
if (this.bvDropdown) {
this.bvDropdown.hide(true);
}
},
onClick: function onClick(evt) {
this.$emit('click', evt);
this.closeDropdown();
}
},
render: function render(h) {
var _ref;
return h('li', {
attrs: {
role: 'presentation'
}
}, [h('button', {
staticClass: 'dropdown-item',
class: [this.buttonClass, (_ref = {}, _defineProperty(_ref, this.activeClass, this.active), _defineProperty(_ref, "text-".concat(this.variant), this.variant && !(this.active || this.disabled)), _ref)],
attrs: this.computedAttrs,
on: {
click: this.onClick
},
ref: 'button'
}, this.normalizeSlot())]);
}
});
var props$q = makePropsConfigurable({
id: {
type: String // default: null
},
tag: {
type: String,
default: 'header'
},
variant: {
type: String // default: null
}
}, NAME_DROPDOWN_HEADER); // @vue/component
var BDropdownHeader = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_DROPDOWN_HEADER,
functional: true,
props: props$q,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
var $attrs = data.attrs || {};
data.attrs = {};
return h('li', a(data, {
attrs: {
role: 'presentation'
}
}), [h(props.tag, {
staticClass: 'dropdown-header',
class: _defineProperty({}, "text-".concat(props.variant), props.variant),
attrs: _objectSpread2(_objectSpread2({}, $attrs), {}, {
id: props.id || null,
role: 'heading'
}),
ref: 'header'
}, children)]);
}
});
var props$r = makePropsConfigurable({
tag: {
type: String,
default: 'hr'
}
}, NAME_DROPDOWN_DIVIDER); // @vue/component
var BDropdownDivider = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_DROPDOWN_DIVIDER,
functional: true,
props: props$r,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data;
var $attrs = data.attrs || {};
data.attrs = {};
return h('li', a(data, {
attrs: {
role: 'presentation'
}
}), [h(props.tag, {
staticClass: 'dropdown-divider',
attrs: _objectSpread2(_objectSpread2({}, $attrs), {}, {
role: 'separator',
'aria-orientation': 'horizontal'
}),
ref: 'divider'
})]);
}
});
var props$s = makePropsConfigurable({
id: {
type: String // default: null
},
inline: {
type: Boolean,
default: false
},
novalidate: {
type: Boolean,
default: false
},
validated: {
type: Boolean,
default: false
}
}, NAME_FORM); // @vue/component
var BForm = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_FORM,
functional: true,
props: props$s,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
return h('form', a(data, {
class: {
'form-inline': props.inline,
'was-validated': props.validated
},
attrs: {
id: props.id,
novalidate: props.novalidate
}
}), children);
}
});
var BDropdownForm = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_DROPDOWN_FORM,
functional: true,
props: makePropsConfigurable(_objectSpread2(_objectSpread2({}, props$s), {}, {
disabled: {
type: Boolean,
default: false
},
formClass: {
type: [String, Object, Array] // default: null
}
}), NAME_DROPDOWN_FORM),
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
var $attrs = data.attrs || {};
var $listeners = data.on || {};
data.attrs = {};
data.on = {};
return h('li', a(data, {
attrs: {
role: 'presentation'
}
}), [h(BForm, {
ref: 'form',
staticClass: 'b-dropdown-form',
class: [props.formClass, {
disabled: props.disabled
}],
props: props,
attrs: _objectSpread2(_objectSpread2({}, $attrs), {}, {
disabled: props.disabled,
// Tab index of -1 for keyboard navigation
tabindex: props.disabled ? null : '-1'
}),
on: $listeners
}, children)]);
}
});
var BDropdownText = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_DROPDOWN_TEXT,
functional: true,
props: makePropsConfigurable({
tag: {
type: String,
default: 'p'
},
textClass: {
type: [String, Array, Object] // default: null
},
variant: {
type: String // default: null
}
}, NAME_DROPDOWN_TEXT),
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
var tag = props.tag,
textClass = props.textClass,
variant = props.variant;
var attrs = data.attrs || {};
data.attrs = {};
return h('li', a(data, {
attrs: {
role: 'presentation'
}
}), [h(tag, {
staticClass: 'b-dropdown-text',
class: [textClass, _defineProperty({}, "text-".concat(variant), variant)],
props: props,
attrs: attrs,
ref: 'text'
}, children)]);
}
});
var props$t = makePropsConfigurable({
id: {
type: String // default: null
},
header: {
type: String // default: null
},
headerTag: {
type: String,
default: 'header'
},
headerVariant: {
type: String // default: null
},
headerClasses: {
type: [String, Array, Object] // default: null
},
ariaDescribedby: {
type: String // default: null
}
}, NAME_DROPDOWN_GROUP); // @vue/component
var BDropdownGroup = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_DROPDOWN_GROUP,
functional: true,
props: props$t,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
slots = _ref.slots,
scopedSlots = _ref.scopedSlots;
var $slots = slots();
var $scopedSlots = scopedSlots || {};
var $attrs = data.attrs || {};
data.attrs = {};
var header;
var headerId = null;
if (hasNormalizedSlot(SLOT_NAME_HEADER, $scopedSlots, $slots) || props.header) {
headerId = props.id ? "_bv_".concat(props.id, "_group_dd_header") : null;
header = h(props.headerTag, {
staticClass: 'dropdown-header',
class: [props.headerClasses, _defineProperty({}, "text-".concat(props.variant), props.variant)],
attrs: {
id: headerId,
role: 'heading'
}
}, normalizeSlot(SLOT_NAME_HEADER, {}, $scopedSlots, $slots) || props.header);
}
var adb = [headerId, props.ariaDescribedBy].filter(identity).join(' ').trim();
return h('li', a(data, {
attrs: {
role: 'presentation'
}
}), [header || h(), h('ul', {
staticClass: 'list-unstyled',
attrs: _objectSpread2(_objectSpread2({}, $attrs), {}, {
id: props.id || null,
role: 'group',
'aria-describedby': adb || null
})
}, normalizeSlot(SLOT_NAME_DEFAULT, {}, $scopedSlots, $slots))]);
}
});
var DropdownPlugin = /*#__PURE__*/pluginFactory({
components: {
BDropdown: BDropdown,
BDd: BDropdown,
BDropdownItem: BDropdownItem,
BDdItem: BDropdownItem,
BDropdownItemButton: BDropdownItemButton,
BDropdownItemBtn: BDropdownItemButton,
BDdItemButton: BDropdownItemButton,
BDdItemBtn: BDropdownItemButton,
BDropdownHeader: BDropdownHeader,
BDdHeader: BDropdownHeader,
BDropdownDivider: BDropdownDivider,
BDdDivider: BDropdownDivider,
BDropdownForm: BDropdownForm,
BDdForm: BDropdownForm,
BDropdownText: BDropdownText,
BDdText: BDropdownText,
BDropdownGroup: BDropdownGroup,
BDdGroup: BDropdownGroup
}
});
var TYPES = ['iframe', 'embed', 'video', 'object', 'img', 'b-img', 'b-img-lazy']; // --- Props ---
var props$u = makePropsConfigurable({
type: {
type: String,
default: 'iframe',
validator: function validator(value) {
return arrayIncludes(TYPES, value);
}
},
tag: {
type: String,
default: 'div'
},
aspect: {
type: String,
default: '16by9'
}
}, NAME_EMBED); // --- Main component ---
// @vue/component
var BEmbed = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_EMBED,
functional: true,
props: props$u,
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-".concat(props.aspect), props.aspect)
}, [h(props.type, a(data, {
ref: '',
staticClass: 'embed-responsive-item'
}), children)]);
}
});
var EmbedPlugin = /*#__PURE__*/pluginFactory({
components: {
BEmbed: BEmbed
}
});
var OPTIONS_OBJECT_DEPRECATED_MSG = 'Setting prop "options" to an object is deprecated. Use the array format instead.'; // --- Props ---
var props$v = makePropsConfigurable({
options: {
type: [Array, Object],
default: function _default() {
return [];
}
},
valueField: {
type: String,
default: 'value'
},
textField: {
type: String,
default: 'text'
},
htmlField: {
type: String,
default: 'html'
},
disabledField: {
type: String,
default: 'disabled'
}
}, 'formOptionControls'); // --- Mixin ---
// @vue/component
var formOptionsMixin = {
props: props$v,
computed: {
formOptions: function formOptions() {
return this.normalizeOptions(this.options);
}
},
methods: {
normalizeOption: function normalizeOption(option) {
var key = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
// When the option is an object, normalize it
if (isPlainObject(option)) {
var value = get(option, this.valueField);
var text = get(option, this.textField);
return {
value: isUndefined(value) ? key || text : value,
text: stripTags(String(isUndefined(text) ? key : text)),
html: get(option, this.htmlField),
disabled: Boolean(get(option, this.disabledField))
};
} // Otherwise create an `<option>` object from the given value
return {
value: key || option,
text: stripTags(String(option)),
disabled: false
};
},
normalizeOptions: function normalizeOptions(options) {
var _this = this;
// Normalize the given options array
if (isArray(options)) {
return options.map(function (option) {
return _this.normalizeOption(option);
});
} else if (isPlainObject(options)) {
// Deprecate the object options format
warn(OPTIONS_OBJECT_DEPRECATED_MSG, this.$options.name); // Normalize a `options` object to an array of options
return keys(options).map(function (key) {
return _this.normalizeOption(options[key] || {}, key);
});
} // If not an array or object, return an empty array
/* istanbul ignore next */
return [];
}
}
};
var BFormDatalist = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_FORM_DATALIST,
mixins: [formOptionsMixin, normalizeSlotMixin],
props: makePropsConfigurable(_objectSpread2(_objectSpread2({}, props$v), {}, {
id: {
type: String,
required: true
}
}), NAME_FORM_DATALIST),
render: function render(h) {
var $options = this.formOptions.map(function (option, index) {
var value = option.value,
text = option.text,
html = option.html,
disabled = option.disabled;
return h('option', {
attrs: {
value: value,
disabled: disabled
},
domProps: htmlOrText(html, text),
key: "option_".concat(index)
});
});
return h('datalist', {
attrs: {
id: this.id
}
}, [$options, this.normalizeSlot()]);
}
});
var props$w = makePropsConfigurable({
id: {
type: String // default: null
},
tag: {
type: String,
default: 'small'
},
textVariant: {
type: String,
default: 'muted'
},
inline: {
type: Boolean,
default: false
}
}, NAME_FORM_TEXT); // @vue/component
var BFormText = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_FORM_TEXT,
functional: true,
props: props$w,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
return h(props.tag, a(data, {
class: _defineProperty({
'form-text': !props.inline
}, "text-".concat(props.textVariant), props.textVariant),
attrs: {
id: props.id
}
}), children);
}
});
var props$x = makePropsConfigurable({
id: {
type: String // default: null
},
tag: {
type: String,
default: 'div'
},
tooltip: {
type: Boolean,
default: false
},
forceShow: {
type: Boolean,
default: false
},
state: {
// Tri-state prop: `true`, `false`, or `null`
type: Boolean,
default: null
},
ariaLive: {
type: String // default: null
},
role: {
type: String // default: null
}
}, NAME_FORM_INVALID_FEEDBACK); // @vue/component
var BFormInvalidFeedback = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_FORM_INVALID_FEEDBACK,
functional: true,
props: props$x,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
var show = props.forceShow === true || props.state === false;
return h(props.tag, a(data, {
class: {
'invalid-feedback': !props.tooltip,
'invalid-tooltip': props.tooltip,
'd-block': show
},
attrs: {
id: props.id || null,
role: props.role || null,
'aria-live': props.ariaLive || null,
'aria-atomic': props.ariaLive ? 'true' : null
}
}), children);
}
});
var props$y = makePropsConfigurable({
id: {
type: String // default: null
},
tag: {
type: String,
default: 'div'
},
tooltip: {
type: Boolean,
default: false
},
forceShow: {
type: Boolean,
default: false
},
state: {
// Tri-state prop: `true`, `false`, or `null`
type: Boolean,
default: null
},
ariaLive: {
type: String // default: null
},
role: {
type: String // default: null
}
}, NAME_FORM_VALID_FEEDBACK); // @vue/component
var BFormValidFeedback = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_FORM_VALID_FEEDBACK,
functional: true,
props: props$y,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
var show = props.forceShow === true || props.state === true;
return h(props.tag, a(data, {
class: {
'valid-feedback': !props.tooltip,
'valid-tooltip': props.tooltip,
'd-block': show
},
attrs: {
id: props.id || null,
role: props.role || null,
'aria-live': props.ariaLive || null,
'aria-atomic': props.ariaLive ? 'true' : null
}
}), children);
}
});
var props$z = makePropsConfigurable({
tag: {
type: String,
default: 'div'
}
}, NAME_FORM_ROW); // @vue/component
var BFormRow = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_FORM_ROW,
functional: true,
props: props$z,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
return h(props.tag, a(data, {
staticClass: 'form-row'
}), children);
}
});
var FormPlugin = /*#__PURE__*/pluginFactory({
components: {
BForm: BForm,
BFormDatalist: BFormDatalist,
BDatalist: BFormDatalist,
BFormText: BFormText,
BFormInvalidFeedback: BFormInvalidFeedback,
BFormFeedback: BFormInvalidFeedback,
BFormValidFeedback: BFormValidFeedback,
// Added here for convenience
BFormRow: BFormRow
}
}); // BFormRow is not exported here as a named export, as it is exported by Layout
var looseIndexOf = function looseIndexOf(arr, val) {
// Assumes that the first argument is an array
for (var i = 0; i < arr.length; i++) {
if (looseEqual(arr[i], val)) {
return i;
}
}
return -1;
};
var SELECTOR = 'input, textarea, select'; // --- Props ---
var props$A = _objectSpread2({
id: {
type: String // default: undefined
},
name: {
type: String // default: undefined
}
}, makePropsConfigurable({
disabled: {
type: Boolean,
default: false
},
required: {
type: Boolean,
default: false
},
form: {
type: String // default: null
},
autofocus: {
type: Boolean,
default: false
}
}, 'formControls')); // --- Mixin ---
// @vue/component
var formControlMixin = {
props: props$A,
mounted: function mounted() {
this.handleAutofocus();
},
/* istanbul ignore next */
activated: function activated() {
this.handleAutofocus();
},
methods: {
handleAutofocus: function handleAutofocus() {
var _this = this;
this.$nextTick(function () {
requestAF(function () {
var el = _this.$el;
if (_this.autofocus && isVisible(el)) {
if (!matches(el, SELECTOR)) {
el = select(SELECTOR, el);
}
attemptFocus(el);
}
});
});
}
}
};
var props$B = makePropsConfigurable({
plain: {
type: Boolean,
default: false
}
}, 'formControls'); // --- Mixin ---
// @vue/component
var formCustomMixin = {
props: props$B,
computed: {
custom: function custom() {
return !this.plain;
}
}
};
var props$C = makePropsConfigurable(_objectSpread2(_objectSpread2({}, props$B), {}, {
value: {// Value when checked
// type: Object,
// default: undefined
},
checked: {// This is the v-model
// type: Object,
// default: undefined
},
inline: {
type: Boolean,
default: false
},
button: {
// Only applicable in standalone mode (non group)
type: Boolean,
default: false
},
buttonVariant: {
// Only applicable when rendered with button style
type: String // default: null
},
ariaLabel: {
// Placed on the input if present.
type: String // default: null
},
ariaLabelledby: {
// Placed on the input if present.
type: String // default: null
}
}), 'formRadioCheckControls'); // --- Mixin ---
// @vue/component
var formRadioCheckMixin = {
mixins: [attrsMixin, formCustomMixin, normalizeSlotMixin],
inheritAttrs: false,
model: {
prop: 'checked',
event: 'input'
},
props: props$C,
data: function data() {
return {
localChecked: this.isGroup ? this.bvGroup.checked : this.checked,
hasFocus: false
};
},
computed: {
computedLocalChecked: {
get: function get() {
return this.isGroup ? this.bvGroup.localChecked : this.localChecked;
},
set: function set(val) {
if (this.isGroup) {
this.bvGroup.localChecked = val;
} else {
this.localChecked = val;
}
}
},
isGroup: function isGroup() {
// Is this check/radio a child of check-group or radio-group?
return Boolean(this.bvGroup);
},
isBtnMode: function isBtnMode() {
// Support button style in single input mode
return this.isGroup ? this.bvGroup.buttons : this.button;
},
isPlain: function isPlain() {
return this.isBtnMode ? false : this.isGroup ? this.bvGroup.plain : this.plain;
},
isCustom: function isCustom() {
return this.isBtnMode ? false : !this.isPlain;
},
isSwitch: function isSwitch() {
// Custom switch styling (checkboxes only)
return this.isBtnMode || this.isRadio || this.isPlain ? false : this.isGroup ? this.bvGroup.switches : this.switch;
},
isInline: function isInline() {
return this.isGroup ? this.bvGroup.inline : this.inline;
},
isDisabled: function isDisabled() {
// Child can be disabled while parent isn't, but is always disabled if group is
return this.isGroup ? this.bvGroup.disabled || this.disabled : this.disabled;
},
isRequired: function isRequired() {
// Required only works when a name is provided for the input(s)
// Child can only be required when parent is
// Groups will always have a name (either user supplied or auto generated)
return this.getName && (this.isGroup ? this.bvGroup.required : this.required);
},
getName: function getName() {
// Group name preferred over local name
return (this.isGroup ? this.bvGroup.groupName : this.name) || null;
},
getForm: function getForm() {
return (this.isGroup ? this.bvGroup.form : this.form) || null;
},
getSize: function getSize() {
return (this.isGroup ? this.bvGroup.size : this.size) || '';
},
getState: function getState() {
return this.isGroup ? this.bvGroup.computedState : this.computedState;
},
getButtonVariant: function getButtonVariant() {
// Local variant preferred over group variant
if (this.buttonVariant) {
return this.buttonVariant;
} else if (this.isGroup && this.bvGroup.buttonVariant) {
return this.bvGroup.buttonVariant;
} // default variant
return 'secondary';
},
buttonClasses: function buttonClasses() {
var _ref;
// Same for radio & check
return ['btn', "btn-".concat(this.getButtonVariant), (_ref = {}, _defineProperty(_ref, "btn-".concat(this.getSize), this.getSize), _defineProperty(_ref, "disabled", this.isDisabled), _defineProperty(_ref, "active", this.isChecked), _defineProperty(_ref, "focus", this.hasFocus), _ref)];
},
computedAttrs: function computedAttrs() {
return _objectSpread2(_objectSpread2({}, this.bvAttrs), {}, {
id: this.safeId(),
type: this.isRadio ? 'radio' : 'checkbox',
name: this.getName,
form: this.getForm,
disabled: this.isDisabled,
required: this.isRequired,
'aria-required': this.isRequired || null,
'aria-label': this.ariaLabel || null,
'aria-labelledby': this.ariaLabelledby || null
});
}
},
watch: {
checked: function checked(newValue) {
if (!looseEqual(newValue, this.computedLocalChecked)) {
this.computedLocalChecked = newValue;
}
}
},
methods: {
handleFocus: function handleFocus(evt) {
// When in buttons mode, we need to add 'focus' class to label when input focused
// As it is the hidden input which has actual focus
if (evt.target) {
if (evt.type === 'focus') {
this.hasFocus = true;
} else if (evt.type === 'blur') {
this.hasFocus = false;
}
}
},
// Convenience methods for focusing the input
focus: function focus() {
if (!this.isDisabled) {
attemptFocus(this.$refs.input);
}
},
blur: function blur() {
if (!this.isDisabled) {
attemptBlur(this.$refs.input);
}
}
},
render: function render(h) {
var defaultSlot = this.normalizeSlot(); // Generate the input element
var on = {
change: this.handleChange
};
if (this.isBtnMode) {
// Handlers for focus styling when in button mode
on.focus = on.blur = this.handleFocus;
}
var input = h('input', {
ref: 'input',
key: 'input',
on: on,
class: {
'form-check-input': this.isPlain,
'custom-control-input': this.isCustom,
'is-valid': this.getState === true && !this.isBtnMode,
'is-invalid': this.getState === false && !this.isBtnMode,
// https://github.com/bootstrap-vue/bootstrap-vue/issues/2911
'position-static': this.isPlain && !defaultSlot
},
directives: [{
name: 'model',
rawName: 'v-model',
value: this.computedLocalChecked,
expression: 'computedLocalChecked'
}],
attrs: this.computedAttrs,
domProps: {
value: this.value,
checked: this.isChecked
}
});
if (this.isBtnMode) {
// Button mode
var button = h('label', {
class: this.buttonClasses
}, [input, defaultSlot]);
if (!this.isGroup) {
// Standalone button mode, so wrap in 'btn-group-toggle'
// and flag it as inline-block to mimic regular buttons
button = h('div', {
class: ['btn-group-toggle', 'd-inline-block']
}, [button]);
}
return button;
} else {
// Not button mode
var label = h(); // If no label content in plain mode we dont render the label
// https://github.com/bootstrap-vue/bootstrap-vue/issues/2911
if (!(this.isPlain && !defaultSlot)) {
label = h('label', {
class: {
'form-check-label': this.isPlain,
'custom-control-label': this.isCustom
},
attrs: {
for: this.safeId()
}
}, defaultSlot);
} // Wrap it in a div
return h('div', {
class: _defineProperty({
'form-check': this.isPlain,
'form-check-inline': this.isPlain && this.isInline,
'custom-control': this.isCustom,
'custom-control-inline': this.isCustom && this.isInline,
'custom-checkbox': this.isCustom && this.isCheck && !this.isSwitch,
'custom-switch': this.isSwitch,
'custom-radio': this.isCustom && this.isRadio
}, "b-custom-control-".concat(this.getSize), Boolean(this.getSize && !this.isBtnMode))
}, [input, label]);
}
}
};
var props$D = makePropsConfigurable({
size: {
type: String // default: null
}
}, 'formControls'); // --- Mixin ---
// @vue/component
var formSizeMixin = {
props: props$D,
computed: {
sizeFormClass: function sizeFormClass() {
return [this.size ? "form-control-".concat(this.size) : null];
}
}
};
/* 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 for is-valid
* - false for is-invalid
* - null for no contextual state
*/
var props$E = makePropsConfigurable({
state: {
// Tri-state prop: true, false, null (or undefined)
type: Boolean,
default: null
}
}, 'formState'); // --- Mixin ---
// @vue/component
var formStateMixin = {
props: props$E,
computed: {
computedState: function computedState() {
// If not a boolean, ensure that value is null
return isBoolean(this.state) ? this.state : null;
},
stateClass: function stateClass() {
var state = this.computedState;
return state === true ? 'is-valid' : state === false ? 'is-invalid' : null;
}
}
};
var BFormCheckbox = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_FORM_CHECKBOX,
mixins: [formRadioCheckMixin, // Includes shared render function
idMixin, formControlMixin, formSizeMixin, formStateMixin],
inject: {
bvGroup: {
from: 'bvCheckGroup',
default: false
}
},
props: makePropsConfigurable(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, props$A), props$C), props$D), props$E), {}, {
value: {
// type: [String, Number, Boolean, Object],
default: true
},
uncheckedValue: {
// type: [String, Number, Boolean, Object],
// Not applicable in multi-check mode
default: false
},
indeterminate: {
// Not applicable in multi-check mode
type: Boolean,
default: false
},
switch: {
// Custom switch styling
type: Boolean,
default: false
},
checked: {
// v-model (Array when multiple checkboxes have same name)
// type: [String, Number, Boolean, Object, Array],
default: null
}
}), NAME_FORM_CHECKBOX),
computed: {
isChecked: function isChecked() {
var value = this.value,
checked = this.computedLocalChecked;
return isArray(checked) ? looseIndexOf(checked, value) > -1 : looseEqual(checked, value);
},
isRadio: function isRadio() {
return false;
},
isCheck: function isCheck() {
return true;
}
},
watch: {
computedLocalChecked: function computedLocalChecked(newValue, oldValue) {
if (!looseEqual(newValue, oldValue)) {
this.$emit('input', newValue);
var $input = this.$refs.input;
if ($input) {
this.$emit('update:indeterminate', $input.indeterminate);
}
}
},
indeterminate: function indeterminate(newVal) {
this.setIndeterminate(newVal);
}
},
mounted: function mounted() {
// Set initial indeterminate state
this.setIndeterminate(this.indeterminate);
},
methods: {
handleChange: function handleChange(_ref) {
var _this = this;
var _ref$target = _ref.target,
checked = _ref$target.checked,
indeterminate = _ref$target.indeterminate;
var value = this.value,
uncheckedValue = this.uncheckedValue; // Update `computedLocalChecked`
var localChecked = this.computedLocalChecked;
if (isArray(localChecked)) {
var index = looseIndexOf(localChecked, value);
if (checked && index < 0) {
// Add value to array
localChecked = localChecked.concat(value);
} else if (!checked && index > -1) {
// Remove value from array
localChecked = localChecked.slice(0, index).concat(localChecked.slice(index + 1));
}
} else {
localChecked = checked ? value : uncheckedValue;
}
this.computedLocalChecked = localChecked; // Fire events in a `$nextTick()` to ensure the `v-model` is updated
this.$nextTick(function () {
// Change is only emitted on user interaction
_this.$emit('change', localChecked); // If this is a child of `<form-checkbox-group>`,
// we emit a change event on it as well
if (_this.isGroup) {
_this.bvGroup.$emit('change', localChecked);
}
_this.$emit('update:indeterminate', indeterminate);
});
},
setIndeterminate: function setIndeterminate(state) {
// Indeterminate only supported in single checkbox mode
if (isArray(this.computedLocalChecked)) {
state = false;
}
var $input = this.$refs.input;
if ($input) {
$input.indeterminate = state; // Emit update event to prop
this.$emit('update:indeterminate', state);
}
}
}
});
var BFormRadio = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_FORM_RADIO,
mixins: [idMixin, formRadioCheckMixin, // Includes shared render function
formControlMixin, formSizeMixin, formStateMixin],
inject: {
bvGroup: {
from: 'bvRadioGroup',
default: false
}
},
props: makePropsConfigurable(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, props$A), props$C), props$D), props$E), {}, {
checked: {
// v-model
// type: [String, Number, Boolean, Object],
default: null
}
}), NAME_FORM_RADIO),
computed: {
isChecked: function isChecked() {
return looseEqual(this.value, this.computedLocalChecked);
},
isRadio: function isRadio() {
return true;
},
isCheck: function isCheck() {
return false;
}
},
watch: {
computedLocalChecked: function computedLocalChecked(newValue, oldValue) {
if (!looseEqual(newValue, oldValue)) {
this.$emit('input', newValue);
}
}
},
methods: {
handleChange: function handleChange(_ref) {
var _this = this;
var checked = _ref.target.checked;
var value = this.value;
var localChecked = checked ? value : null;
this.computedLocalChecked = value; // Fire events in a `$nextTick()` to ensure the `v-model` is updated
this.$nextTick(function () {
// Change is only emitted on user interaction
_this.$emit('change', localChecked); // If this is a child of `<form-radio-group>`,
// we emit a change event on it as well
if (_this.isGroup) {
_this.bvGroup.$emit('change', localChecked);
}
});
}
}
});
var props$F = makePropsConfigurable(_objectSpread2(_objectSpread2({}, props$B), {}, {
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: null
}
}), 'formRadioCheckGroups'); // --- Mixin ---
// @vue/component
var formRadioCheckGroupMixin = {
mixins: [formCustomMixin, normalizeSlotMixin],
model: {
prop: 'checked',
event: 'input'
},
props: props$F,
computed: {
inline: function inline() {
return !this.stacked;
},
groupName: function groupName() {
// Checks/Radios tied to the same model must have the same name,
// especially for ARIA accessibility.
return this.name || this.safeId();
},
groupClasses: function groupClasses() {
if (this.buttons) {
return ['btn-group-toggle', this.inline ? 'btn-group' : 'btn-group-vertical', this.size ? "btn-group-".concat(this.size) : '', this.validated ? "was-validated" : ''];
}
return [this.validated ? "was-validated" : ''];
},
computedAriaInvalid: function computedAriaInvalid() {
var ariaInvalid = this.ariaInvalid;
if (ariaInvalid === true || ariaInvalid === 'true' || ariaInvalid === '') {
return 'true';
}
return this.computedState === false ? 'true' : null;
}
},
watch: {
checked: function checked(newVal) {
if (!looseEqual(newVal, this.localChecked)) {
this.localChecked = newVal;
}
},
localChecked: function localChecked(newValue, oldValue) {
if (!looseEqual(newValue, oldValue)) {
this.$emit('input', newValue);
}
}
},
render: function render(h) {
var _this = this;
var $inputs = this.formOptions.map(function (option, index) {
var key = "BV_option_".concat(index);
return h(_this.isRadioGroup ? BFormRadio : BFormCheckbox, {
props: {
id: _this.safeId(key),
value: option.value,
// Individual radios or checks can be disabled in a group
disabled: option.disabled || false // We don't need to include these, since the input's will know they are inside here
// name: this.groupName,
// form: this.form || null,
// required: Boolean(this.name && this.required)
},
key: key
}, [h('span', {
domProps: htmlOrText(option.html, option.text)
})]);
});
return h('div', {
class: [this.groupClasses, 'bv-no-focus-ring'],
attrs: {
id: this.safeId(),
role: this.isRadioGroup ? 'radiogroup' : 'group',
// Add `tabindex="-1"` to allow group to be focused if needed by screen readers
tabindex: '-1',
'aria-required': this.required ? 'true' : null,
'aria-invalid': this.computedAriaInvalid
}
}, [this.normalizeSlot(SLOT_NAME_FIRST), $inputs, this.normalizeSlot()]);
}
};
var props$G = makePropsConfigurable(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, props$A), props$v), props$F), props$D), props$E), {}, {
switches: {
// Custom switch styling
type: Boolean,
default: false
},
checked: {
type: Array,
default: null
}
}), NAME_FORM_CHECKBOX_GROUP); // --- Main component ---
// @vue/component
var BFormCheckboxGroup = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_FORM_CHECKBOX_GROUP,
mixins: [idMixin, formControlMixin, formRadioCheckGroupMixin, // Includes render function
formOptionsMixin, formSizeMixin, formStateMixin],
provide: function provide() {
return {
bvCheckGroup: this
};
},
props: props$G,
data: function data() {
return {
localChecked: this.checked || []
};
},
computed: {
isRadioGroup: function isRadioGroup() {
return false;
}
}
});
var FormCheckboxPlugin = /*#__PURE__*/pluginFactory({
components: {
BFormCheckbox: BFormCheckbox,
BCheckbox: BFormCheckbox,
BCheck: BFormCheckbox,
BFormCheckboxGroup: BFormCheckboxGroup,
BCheckboxGroup: BFormCheckboxGroup,
BCheckGroup: BFormCheckboxGroup
}
});
// v-b-hover directive
var PROP = '__BV_hover_handler__';
var MOUSEENTER = 'mouseenter';
var MOUSELEAVE = 'mouseleave'; // --- Utility methods ---
var createListener = function createListener(handler) {
var listener = function listener(evt) {
handler(evt.type === MOUSEENTER, evt);
};
listener.fn = handler;
return listener;
};
var updateListeners = function updateListeners(on, el, listener) {
eventOnOff(on, el, MOUSEENTER, listener, EVENT_OPTIONS_NO_CAPTURE);
eventOnOff(on, el, MOUSELEAVE, listener, EVENT_OPTIONS_NO_CAPTURE);
}; // --- Directive bind/unbind/update handler ---
var directive = function directive(el, _ref) {
var _ref$value = _ref.value,
handler = _ref$value === void 0 ? null : _ref$value;
if (isBrowser) {
var listener = el[PROP];
var hasListener = isFunction(listener);
var handlerChanged = !(hasListener && listener.fn === handler);
if (hasListener && handlerChanged) {
updateListeners(false, el, listener);
delete el[PROP];
}
if (isFunction(handler) && handlerChanged) {
el[PROP] = createListener(handler);
updateListeners(true, el, el[PROP]);
}
}
}; // VBHover directive
var VBHover = {
bind: directive,
componentUpdated: directive,
unbind: function unbind(el) {
directive(el, {
value: null
});
}
};
var props$H = _objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, omit(props$A, ['autofocus'])), props$D), commonProps), props$E), {}, {
value: {
// This is the value placed on the hidden input
type: String,
default: ''
},
formattedValue: {
// This is the value shown in the label
// Defaults back to `value`
type: String // default: null
},
placeholder: {
// This is the value placed on the hidden input when no value selected
type: String // default: null
},
labelSelected: {
// Value placed in sr-only span inside label when value is present
type: String // default: null
},
readonly: {
type: Boolean,
default: false
},
lang: {
type: String // default: null
},
rtl: {
// Tri-state prop: `true`, `false` or `null`
type: Boolean,
// We must explicitly default to `null` here otherwise
// Vue coerces `undefined` into Boolean `false`
default: null
},
buttonOnly: {
// When true, renders a btn-group wrapper and visually hides the label
type: Boolean,
default: false
},
buttonVariant: {
// Applicable in button mode only
type: String,
default: 'secondary'
},
menuClass: {
// Extra classes to apply to the `dropdown-menu` div
type: [String, Array, Object] // default: null
}
}); // --- Main component ---
// @vue/component
var BVFormBtnLabelControl = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_FORM_BUTTON_LABEL_CONTROL,
directives: {
BHover: VBHover
},
mixins: [idMixin, formSizeMixin, formStateMixin, dropdownMixin, normalizeSlotMixin],
props: props$H,
data: function data() {
return {
isHovered: false,
hasFocus: false
};
},
computed: {
idButton: function idButton() {
return this.safeId();
},
idLabel: function idLabel() {
return this.safeId('_value_');
},
idMenu: function idMenu() {
return this.safeId('_dialog_');
},
idWrapper: function idWrapper() {
return this.safeId('_outer_');
},
computedDir: function computedDir() {
return this.rtl === true ? 'rtl' : this.rtl === false ? 'ltr' : null;
}
},
methods: {
focus: function focus() {
if (!this.disabled) {
attemptFocus(this.$refs.toggle);
}
},
blur: function blur() {
if (!this.disabled) {
attemptBlur(this.$refs.toggle);
}
},
setFocus: function setFocus(evt) {
this.hasFocus = evt.type === 'focus';
},
handleHover: function handleHover(hovered) {
this.isHovered = hovered;
}
},
render: function render(h) {
var _class;
var idButton = this.idButton,
idLabel = this.idLabel,
idMenu = this.idMenu,
idWrapper = this.idWrapper,
disabled = this.disabled,
readonly = this.readonly,
required = this.required,
name = this.name,
state = this.state,
visible = this.visible,
size = this.size,
isHovered = this.isHovered,
hasFocus = this.hasFocus,
labelSelected = this.labelSelected,
buttonVariant = this.buttonVariant;
var value = toString$1(this.value) || '';
var buttonOnly = !!this.buttonOnly;
var invalid = state === false || required && !value;
var btnScope = {
isHovered: isHovered,
hasFocus: hasFocus,
state: state,
opened: visible
};
var $button = h('button', {
ref: 'toggle',
staticClass: 'btn',
class: (_class = {}, _defineProperty(_class, "btn-".concat(buttonVariant), buttonOnly), _defineProperty(_class, "btn-".concat(size), !!size), _defineProperty(_class, 'h-auto', !buttonOnly), _defineProperty(_class, 'dropdown-toggle', buttonOnly), _defineProperty(_class, 'dropdown-toggle-no-caret', buttonOnly), _class),
attrs: {
id: idButton,
type: 'button',
disabled: disabled,
'aria-haspopup': 'dialog',
'aria-expanded': visible ? 'true' : 'false',
'aria-invalid': invalid ? 'true' : null,
'aria-required': required ? 'true' : null
},
directives: [{
name: 'b-hover',
value: this.handleHover
}],
on: {
mousedown: this.onMousedown,
click: this.toggle,
keydown: this.toggle,
// Handle ENTER, SPACE and DOWN
'!focus': this.setFocus,
'!blur': this.setFocus
}
}, [this.hasNormalizedSlot(SLOT_NAME_BUTTON_CONTENT) ? this.normalizeSlot(SLOT_NAME_BUTTON_CONTENT, btnScope) :
/* istanbul ignore next */
h(BIconChevronDown, {
props: {
scale: 1.25
}
})]); // Hidden input
var $hidden = h();
if (name && !disabled) {
$hidden = h('input', {
attrs: {
type: 'hidden',
name: name || null,
form: this.form || null,
value: value
}
});
} // Dropdown content
var $menu = h('div', {
ref: 'menu',
staticClass: 'dropdown-menu',
class: [this.menuClass, {
show: visible,
'dropdown-menu-right': this.right
}],
attrs: {
id: idMenu,
role: 'dialog',
tabindex: '-1',
'aria-modal': 'false',
'aria-labelledby': idLabel
},
on: {
keydown: this.onKeydown // Handle ESC
}
}, [this.normalizeSlot(SLOT_NAME_DEFAULT, {
opened: visible
})]); // Value label
var $label = h('label', {
staticClass: 'form-control text-break text-wrap bg-transparent h-auto',
class: [{
// Hidden in button only mode
'sr-only': buttonOnly,
// Mute the text if showing the placeholder
'text-muted': !value
}, this.stateClass, this.sizeFormClass],
attrs: {
id: idLabel,
for: idButton,
'aria-invalid': invalid ? 'true' : null,
'aria-required': required ? 'true' : null
},
directives: [{
name: 'b-hover',
value: this.handleHover
}],
on: {
// Disable bubbling of the click event to
// prevent menu from closing and re-opening
'!click':
/* istanbul ignore next */
function click(evt) {
stopEvent(evt, {
preventDefault: false
});
}
}
}, [value ? this.formattedValue || value : this.placeholder || '', // Add the selected label for screen readers when a value is provided
value && labelSelected ? h('bdi', {
staticClass: 'sr-only'
}, labelSelected) : '']); // Return the custom form control wrapper
return h('div', {
staticClass: 'b-form-btn-label-control dropdown',
class: [this.directionClass, this.boundaryClass, [{
'btn-group': buttonOnly,
'form-control': !buttonOnly,
'd-flex': !buttonOnly,
'h-auto': !buttonOnly,
'align-items-stretch': !buttonOnly,
focus: hasFocus && !buttonOnly,
show: visible,
'is-valid': state === true,
'is-invalid': state === false
}, buttonOnly ? null : this.sizeFormClass]],
attrs: {
id: idWrapper,
role: buttonOnly ? null : 'group',
lang: this.lang || null,
dir: this.computedDir,
'aria-disabled': disabled,
'aria-readonly': readonly && !disabled,
'aria-labelledby': idLabel,
'aria-invalid': state === false || required && !value ? 'true' : null,
'aria-required': required ? 'true' : null
}
}, [$button, $hidden, $menu, $label]);
}
});
// @vue/component
var BFormDatepicker = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_FORM_DATEPICKER,
// The mixins order determines the order of appearance in the props reference section
mixins: [idMixin],
model: {
prop: 'value',
event: 'input'
},
props: makePropsConfigurable(_objectSpread2(_objectSpread2(_objectSpread2({}, props$7), omit(props$H, ['id', 'value', 'formattedValue', 'rtl', 'lang'])), {}, {
resetValue: {
type: [String, Date] // default: null
},
noCloseOnSelect: {
type: Boolean,
default: false
},
buttonOnly: {
type: Boolean,
default: false
},
buttonVariant: {
// Applicable in button only mode
type: String,
default: 'secondary'
},
calendarWidth: {
// Width of the calendar dropdown
type: String,
default: '270px'
},
todayButton: {
type: Boolean,
default: false
},
labelTodayButton: {
type: String,
default: 'Select today'
},
todayButtonVariant: {
type: String,
default: 'outline-primary'
},
resetButton: {
type: Boolean,
default: false
},
labelResetButton: {
type: String,
default: 'Reset'
},
resetButtonVariant: {
type: String,
default: 'outline-danger'
},
closeButton: {
type: Boolean,
default: false
},
labelCloseButton: {
type: String,
default: 'Close'
},
closeButtonVariant: {
type: String,
default: 'outline-secondary'
},
// Dark mode
dark: {
type: Boolean,
default: false
}
}), NAME_FORM_DATEPICKER),
data: function data() {
return {
// We always use `YYYY-MM-DD` value internally
localYMD: formatYMD(this.value) || '',
// If the popup is open
isVisible: false,
// Context data from BCalendar
localLocale: null,
isRTL: false,
formattedValue: '',
activeYMD: ''
};
},
computed: {
calendarYM: function calendarYM() {
// Returns the calendar year/month
// Returns the `YYYY-MM` portion of the active calendar date
return this.activeYMD.slice(0, -3);
},
computedLang: function computedLang() {
return (this.localLocale || '').replace(/-u-.*$/i, '') || null;
},
computedResetValue: function computedResetValue() {
return formatYMD(constrainDate(this.resetValue)) || '';
}
},
watch: {
value: function value(newVal) {
this.localYMD = formatYMD(newVal) || '';
},
localYMD: function localYMD(newVal) {
// We only update the v-model when the datepicker is open
if (this.isVisible) {
this.$emit('input', this.valueAsDate ? parseYMD(newVal) || null : newVal || '');
}
},
calendarYM: function calendarYM(newVal, oldVal) {
// Displayed calendar month has changed
// So possibly the calendar height has changed...
// We need to update popper computed position
if (newVal !== oldVal && oldVal) {
try {
this.$refs.control.updatePopper();
} catch (_unused) {}
}
}
},
methods: {
// Public methods
focus: function focus() {
if (!this.disabled) {
attemptFocus(this.$refs.control);
}
},
blur: function blur() {
if (!this.disabled) {
attemptBlur(this.$refs.control);
}
},
// Private methods
setAndClose: function setAndClose(ymd) {
var _this = this;
this.localYMD = ymd; // Close calendar popup, unless `noCloseOnSelect`
if (!this.noCloseOnSelect) {
this.$nextTick(function () {
_this.$refs.control.hide(true);
});
}
},
onSelected: function onSelected(ymd) {
var _this2 = this;
this.$nextTick(function () {
_this2.setAndClose(ymd);
});
},
onInput: function onInput(ymd) {
if (this.localYMD !== ymd) {
this.localYMD = ymd;
}
},
onContext: function onContext(ctx) {
var activeYMD = ctx.activeYMD,
isRTL = ctx.isRTL,
locale = ctx.locale,
selectedYMD = ctx.selectedYMD,
selectedFormatted = ctx.selectedFormatted;
this.isRTL = isRTL;
this.localLocale = locale;
this.formattedValue = selectedFormatted;
this.localYMD = selectedYMD;
this.activeYMD = activeYMD; // Re-emit the context event
this.$emit('context', ctx);
},
onTodayButton: function onTodayButton() {
// Set to today (or min/max if today is out of range)
this.setAndClose(formatYMD(constrainDate(createDate(), this.min, this.max)));
},
onResetButton: function onResetButton() {
this.setAndClose(this.computedResetValue);
},
onCloseButton: function onCloseButton() {
this.$refs.control.hide(true);
},
// Menu handlers
onShow: function onShow() {
this.isVisible = true;
},
onShown: function onShown() {
var _this3 = this;
this.$nextTick(function () {
attemptFocus(_this3.$refs.calendar);
_this3.$emit('shown');
});
},
onHidden: function onHidden() {
this.isVisible = false;
this.$emit('hidden');
},
// Render helpers
defaultButtonFn: function defaultButtonFn(_ref) {
var isHovered = _ref.isHovered,
hasFocus = _ref.hasFocus;
return this.$createElement(isHovered || hasFocus ? BIconCalendarFill : BIconCalendar, {
attrs: {
'aria-hidden': 'true'
}
});
}
},
render: function render(h) {
var localYMD = this.localYMD,
disabled = this.disabled,
readonly = this.readonly,
dark = this.dark,
$props = this.$props,
$scopedSlots = this.$scopedSlots;
var placeholder = isUndefinedOrNull(this.placeholder) ? this.labelNoDateSelected : this.placeholder; // Optional footer buttons
var $footer = [];
if (this.todayButton) {
var label = this.labelTodayButton;
$footer.push(h(BButton, {
props: {
size: 'sm',
disabled: disabled || readonly,
variant: this.todayButtonVariant
},
attrs: {
'aria-label': label || null
},
on: {
click: this.onTodayButton
}
}, label));
}
if (this.resetButton) {
var _label = this.labelResetButton;
$footer.push(h(BButton, {
props: {
size: 'sm',
disabled: disabled || readonly,
variant: this.resetButtonVariant
},
attrs: {
'aria-label': _label || null
},
on: {
click: this.onResetButton
}
}, _label));
}
if (this.closeButton) {
var _label2 = this.labelCloseButton;
$footer.push(h(BButton, {
props: {
size: 'sm',
disabled: disabled,
variant: this.closeButtonVariant
},
attrs: {
'aria-label': _label2 || null
},
on: {
click: this.onCloseButton
}
}, _label2));
}
if ($footer.length > 0) {
$footer = [h('div', {
staticClass: 'b-form-date-controls d-flex flex-wrap',
class: {
'justify-content-between': $footer.length > 1,
'justify-content-end': $footer.length < 2
}
}, $footer)];
}
var $calendar = h(BCalendar, {
key: 'calendar',
ref: 'calendar',
staticClass: 'b-form-date-calendar w-100',
props: _objectSpread2(_objectSpread2({}, pluckProps(props$7, $props)), {}, {
value: localYMD,
hidden: !this.isVisible
}),
on: {
selected: this.onSelected,
input: this.onInput,
context: this.onContext
},
scopedSlots: pick($scopedSlots, ['nav-prev-decade', 'nav-prev-year', 'nav-prev-month', 'nav-this-month', 'nav-next-month', 'nav-next-year', 'nav-next-decade'])
}, $footer);
return h(BVFormBtnLabelControl, {
ref: 'control',
staticClass: 'b-form-datepicker',
props: _objectSpread2(_objectSpread2({}, pluckProps(props$H, $props)), {}, {
id: this.safeId(),
value: localYMD,
formattedValue: localYMD ? this.formattedValue : '',
placeholder: placeholder,
rtl: this.isRTL,
lang: this.computedLang,
menuClass: [{
'bg-dark': !!dark,
'text-light': !!dark
}, this.menuClass]
}),
on: {
show: this.onShow,
shown: this.onShown,
hidden: this.onHidden
},
scopedSlots: {
'button-content': $scopedSlots['button-content'] || this.defaultButtonFn
}
}, [$calendar]);
}
});
var FormDatepickerPlugin = /*#__PURE__*/pluginFactory({
components: {
BFormDatepicker: BFormDatepicker,
BDatepicker: BFormDatepicker
}
});
var VALUE_EMPTY_DEPRECATED_MSG = 'Setting "value"/"v-model" to an empty string for reset is deprecated. Set to "null" instead.'; // --- Helper methods ---
var isValidValue = function isValidValue(value) {
return isFile(value) || isArray(value) && value.every(function (v) {
return isValidValue(v);
});
}; // Helper method to "safely" get the entry from a data-transfer item
/* istanbul ignore next: not supported in JSDOM */
var getDataTransferItemEntry = function getDataTransferItemEntry(item) {
return isFunction(item.getAsEntry) ? item.getAsEntry() : isFunction(item.webkitGetAsEntry) ? item.webkitGetAsEntry() : null;
}; // Drop handler function to get all files
/* istanbul ignore next: not supported in JSDOM */
var getAllFileEntries = function getAllFileEntries(dataTransferItemList) {
var traverseDirectories = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
return Promise.all(from(dataTransferItemList).filter(function (item) {
return item.kind === 'file';
}).map(function (item) {
var entry = getDataTransferItemEntry(item);
if (entry) {
if (entry.isDirectory && traverseDirectories) {
return getAllFileEntriesInDirectory(entry.createReader(), "".concat(entry.name, "/"));
} else if (entry.isFile) {
return new Promise(function (resolve) {
entry.file(function (file) {
file.$path = '';
resolve(file);
});
});
}
}
return null;
}).filter(identity));
}; // Get all the file entries (recursive) in a directory
/* istanbul ignore next: not supported in JSDOM */
var getAllFileEntriesInDirectory = function getAllFileEntriesInDirectory(directoryReader) {
var path = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
return new Promise(function (resolve) {
var entryPromises = [];
var readDirectoryEntries = function readDirectoryEntries() {
directoryReader.readEntries(function (entries) {
if (entries.length === 0) {
resolve(Promise.all(entryPromises).then(function (entries) {
return flatten(entries);
}));
} else {
entryPromises.push(Promise.all(entries.map(function (entry) {
if (entry) {
if (entry.isDirectory) {
return getAllFileEntriesInDirectory(entry.createReader(), "".concat(path).concat(entry.name, "/"));
} else if (entry.isFile) {
return new Promise(function (resolve) {
entry.file(function (file) {
file.$path = "".concat(path).concat(file.name);
resolve(file);
});
});
}
}
return null;
}).filter(identity)));
readDirectoryEntries();
}
});
};
readDirectoryEntries();
});
}; // @vue/component
var BFormFile = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_FORM_FILE,
mixins: [attrsMixin, idMixin, formControlMixin, formStateMixin, formCustomMixin, normalizeSlotMixin],
inheritAttrs: false,
model: {
prop: 'value',
event: 'input'
},
props: makePropsConfigurable(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, props$A), props$B), props$E), props$D), {}, {
value: {
type: [File, Array],
default: null,
validator: function validator(value) {
/* istanbul ignore next */
if (value === '') {
warn(VALUE_EMPTY_DEPRECATED_MSG, NAME_FORM_FILE);
return true;
}
return isUndefinedOrNull(value) || isValidValue(value);
}
},
accept: {
type: String,
default: ''
},
// Instruct input to capture from camera
capture: {
type: Boolean,
default: false
},
placeholder: {
type: String,
default: 'No file chosen'
},
browseText: {
type: String,
default: 'Browse'
},
dropPlaceholder: {
type: String,
default: 'Drop files here'
},
noDropPlaceholder: {
type: String,
default: 'Not allowed'
},
multiple: {
type: Boolean,
default: false
},
directory: {
type: Boolean,
default: false
},
// TODO:
// Should we deprecate this and only support flat file structures?
// Nested file structures are only supported when files are dropped
// A Chromium "bug" prevents `webkitEntries` from being populated
// on the file input's `change` event and is marked as "WontFix"
// Mozilla implemented the behavior the same way as Chromium
// See: https://bugs.chromium.org/p/chromium/issues/detail?id=138987
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1326031
noTraverse: {
type: Boolean,
default: false
},
noDrop: {
type: Boolean,
default: false
},
fileNameFormatter: {
type: Function // default: null
}
}), NAME_FORM_FILE),
data: function data() {
return {
files: [],
dragging: false,
// IE 11 doesn't respect setting `evt.dataTransfer.dropEffect`,
// so we handle it ourselves as well
// https://stackoverflow.com/a/46915971/2744776
dropAllowed: !this.noDrop,
hasFocus: false
};
},
computed: {
// Convert `accept` to an array of `[{ RegExpr, isMime }, ...]`
computedAccept: function computedAccept() {
var accept = this.accept;
accept = (accept || '').trim().split(/[,\s]+/).filter(Boolean); // Allow any file type/extension
if (accept.length === 0) {
return null;
}
return accept.map(function (extOrType) {
var prop = 'name';
var startMatch = '^';
var endMatch = '$';
if (RX_EXTENSION.test(extOrType)) {
// File extension /\.ext$/
startMatch = '';
} else {
// MIME type /^mime\/.+$/ or /^mime\/type$/
prop = 'type';
if (RX_STAR.test(extOrType)) {
endMatch = '.+$'; // Remove trailing `*`
extOrType = extOrType.slice(0, -1);
}
} // Escape all RegExp special chars
extOrType = escapeRegExp(extOrType);
var rx = new RegExp("".concat(startMatch).concat(extOrType).concat(endMatch));
return {
rx: rx,
prop: prop
};
});
},
computedCapture: function computedCapture() {
var capture = this.capture;
return capture === true || capture === '' ? true : capture || null;
},
computedAttrs: function computedAttrs() {
var name = this.name,
disabled = this.disabled,
required = this.required,
form = this.form,
computedCapture = this.computedCapture,
accept = this.accept,
multiple = this.multiple,
directory = this.directory;
return _objectSpread2(_objectSpread2({}, this.bvAttrs), {}, {
type: 'file',
id: this.safeId(),
name: name,
disabled: disabled,
required: required,
form: form || null,
capture: computedCapture,
accept: accept || null,
multiple: multiple,
directory: directory,
webkitdirectory: directory,
'aria-required': required ? 'true' : null
});
},
computedFileNameFormatter: function computedFileNameFormatter() {
var fileNameFormatter = this.fileNameFormatter;
var result = null;
try {
result = fileNameFormatter();
} catch (_unused) {}
return isUndefined(result) ? this.defaultFileNameFormatter : fileNameFormatter;
},
clonedFiles: function clonedFiles() {
return cloneDeep(this.files);
},
flattenedFiles: function flattenedFiles() {
return flattenDeep(this.files);
},
fileNames: function fileNames() {
return this.flattenedFiles.map(function (file) {
return file.name;
});
},
labelContent: function labelContent() {
var h = this.$createElement; // Draging active
/* istanbul ignore next: used by drag/drop which can't be tested easily */
if (this.dragging && !this.noDrop) {
return (// TODO: Add additional scope with file count, and other not-allowed reasons
this.normalizeSlot('drop-placeholder', {
allowed: this.dropAllowed
}) || (this.dropAllowed ? this.dropPlaceholder : h('span', {
staticClass: 'text-danger'
}, this.noDropPlaceholder))
);
} // No file chosen
if (this.files.length === 0) {
return this.normalizeSlot('placeholder') || this.placeholder;
}
var flattenedFiles = this.flattenedFiles,
clonedFiles = this.clonedFiles,
fileNames = this.fileNames,
computedFileNameFormatter = this.computedFileNameFormatter; // There is a slot for formatting the files/names
if (this.hasNormalizedSlot('file-name')) {
return this.normalizeSlot('file-name', {
files: flattenedFiles,
filesTraversed: clonedFiles,
names: fileNames
});
}
return computedFileNameFormatter(flattenedFiles, clonedFiles, fileNames);
}
},
watch: {
value: function value(newValue) {
if (!newValue || isArray(newValue) && newValue.length === 0) {
this.reset();
}
},
files: function files(newValue, oldValue) {
if (!looseEqual(newValue, oldValue)) {
var multiple = this.multiple,
noTraverse = this.noTraverse;
var files = !multiple || noTraverse ? flattenDeep(newValue) : newValue;
this.$emit('input', multiple ? files : files[0] || null);
}
}
},
mounted: function mounted() {
var _this = this;
// Listen for form reset events, to reset the file input
var $form = closest('form', this.$el);
if ($form) {
eventOn($form, 'reset', this.reset, EVENT_OPTIONS_PASSIVE);
this.$on('hook:beforeDestroy', function () {
eventOff($form, 'reset', _this.reset, EVENT_OPTIONS_PASSIVE);
});
}
},
methods: {
isFileValid: function isFileValid(file) {
if (!file) {
return false;
}
var accept = this.computedAccept;
return accept ? accept.some(function (a) {
return a.rx.test(file[a.prop]);
}) : true;
},
isFilesArrayValid: function isFilesArrayValid(files) {
var _this2 = this;
return isArray(files) ? files.every(function (file) {
return _this2.isFileValid(file);
}) : this.isFileValid(files);
},
defaultFileNameFormatter: function defaultFileNameFormatter(flattenedFiles, clonedFiles, fileNames) {
return fileNames.join(', ');
},
setFiles: function setFiles(files) {
// Reset the dragging flags
this.dropAllowed = !this.noDrop;
this.dragging = false; // Set the selected files
this.files = this.multiple ? this.directory ? files : flattenDeep(files) : flattenDeep(files).slice(0, 1);
},
/* istanbul ignore next: used by Drag/Drop */
setInputFiles: function setInputFiles(files) {
// Try an set the file input files array so that `required`
// constraint works for dropped files (will fail in IE11 though)
// To be used only when dropping files
try {
// Firefox < 62 workaround exploiting https://bugzilla.mozilla.org/show_bug.cgi?id=1422655
var dataTransfer = new ClipboardEvent('').clipboardData || new DataTransfer(); // Add flattened files to temp `dataTransfer` object to get a true `FileList` array
flattenDeep(cloneDeep(files)).forEach(function (file) {
// Make sure to remove the custom `$path` attribute
delete file.$path;
dataTransfer.items.add(file);
});
this.$refs.input.files = dataTransfer.files;
} catch (_unused2) {}
},
reset: function reset() {
// 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
// Wrapped in try in case IE 11 or mobile Safari crap out
try {
var $input = this.$refs.input;
$input.value = '';
$input.type = '';
$input.type = 'file';
} catch (_unused3) {}
this.files = [];
},
handleFiles: function handleFiles(files) {
var isDrop = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
if (isDrop) {
// When dropped, make sure to filter files with the internal `accept` logic
var filteredFiles = files.filter(this.isFilesArrayValid); // Only update files when we have any after filtering
if (filteredFiles.length > 0) {
this.setFiles(filteredFiles); // Try an set the file input's files array so that `required`
// constraint works for dropped files (will fail in IE 11 though)
this.setInputFiles(filteredFiles);
}
} else {
// We always update the files from the `change` event
this.setFiles(files);
}
},
focusHandler: function focusHandler(evt) {
// Bootstrap v4 doesn't have focus styling for custom file input
// Firefox has a `[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;
}
},
onChange: function onChange(evt) {
var _this3 = this;
var type = evt.type,
target = evt.target,
_evt$dataTransfer = evt.dataTransfer,
dataTransfer = _evt$dataTransfer === void 0 ? {} : _evt$dataTransfer;
var isDrop = type === 'drop'; // Always emit original event
this.$emit('change', evt);
var items = from(dataTransfer.items || []);
if (hasPromiseSupport && items.length > 0 && !isNull(getDataTransferItemEntry(items[0]))) {
// Drop handling for modern browsers
// Supports nested directory structures in `directory` mode
/* istanbul ignore next: not supported in JSDOM */
getAllFileEntries(items, this.directory).then(function (files) {
return _this3.handleFiles(files, isDrop);
});
} else {
// Standard file input handling (native file input change event),
// or fallback drop mode (IE 11 / Opera) which don't support `directory` mode
var files = from(target.files || dataTransfer.files || []).map(function (file) {
// Add custom `$path` property to each file (to be consistent with drop mode)
file.$path = file.webkitRelativePath || '';
return file;
});
this.handleFiles(files, isDrop);
}
},
onDragenter: function onDragenter(evt) {
stopEvent(evt);
this.dragging = true;
var _evt$dataTransfer2 = evt.dataTransfer,
dataTransfer = _evt$dataTransfer2 === void 0 ? {} : _evt$dataTransfer2; // Early exit when the input or dropping is disabled
if (this.noDrop || this.disabled || !this.dropAllowed) {
// Show deny feedback
/* istanbul ignore next: not supported in JSDOM */
dataTransfer.dropEffect = 'none';
this.dropAllowed = false;
return;
}
/* istanbul ignore next: not supported in JSDOM */
dataTransfer.dropEffect = 'copy';
},
// Note this event fires repeatedly while the mouse is over the dropzone at
// intervals in the milliseconds, so avoid doing much processing in here
onDragover: function onDragover(evt) {
stopEvent(evt);
this.dragging = true;
var _evt$dataTransfer3 = evt.dataTransfer,
dataTransfer = _evt$dataTransfer3 === void 0 ? {} : _evt$dataTransfer3; // Early exit when the input or dropping is disabled
if (this.noDrop || this.disabled || !this.dropAllowed) {
// Show deny feedback
/* istanbul ignore next: not supported in JSDOM */
dataTransfer.dropEffect = 'none';
this.dropAllowed = false;
return;
}
/* istanbul ignore next: not supported in JSDOM */
dataTransfer.dropEffect = 'copy';
},
onDragleave: function onDragleave(evt) {
var _this4 = this;
stopEvent(evt);
this.$nextTick(function () {
_this4.dragging = false; // Reset `dropAllowed` to default
_this4.dropAllowed = !_this4.noDrop;
});
},
// Triggered by a file drop onto drop target
onDrop: function onDrop(evt) {
var _this5 = this;
stopEvent(evt);
this.dragging = false; // Early exit when the input or dropping is disabled
if (this.noDrop || this.disabled || !this.dropAllowed) {
this.$nextTick(function () {
// Reset `dropAllowed` to default
_this5.dropAllowed = !_this5.noDrop;
});
return;
}
this.onChange(evt);
}
},
render: function render(h) {
var custom = this.custom,
plain = this.plain,
size = this.size,
dragging = this.dragging,
stateClass = this.stateClass; // Form Input
var $input = h('input', {
ref: 'input',
class: [{
'form-control-file': plain,
'custom-file-input': custom,
focus: custom && this.hasFocus
}, stateClass],
// With IE 11, the input gets in the "way" of the drop events,
// so we move it out of the way by putting it behind the label
// Bootstrap v4 has it in front
style: custom ? {
zIndex: -5
} : {},
attrs: this.computedAttrs,
on: {
change: this.onChange,
focusin: this.focusHandler,
focusout: this.focusHandler,
reset: this.reset
}
});
if (plain) {
return $input;
} // Overlay label
var $label = h('label', {
staticClass: 'custom-file-label',
class: {
dragging: dragging
},
attrs: {
for: this.safeId(),
// This goes away in Bootstrap v5
'data-browse': this.browseText || null
}
}, [h('span', {
staticClass: 'd-block form-file-text',
// `pointer-events: none` is used to make sure
// the drag events fire only on the label
style: {
pointerEvents: 'none'
}
}, [this.labelContent])]); // Return rendered custom file input
return h('div', {
staticClass: 'custom-file b-form-file',
class: [_defineProperty({}, "b-custom-control-".concat(size), size), stateClass],
attrs: {
id: this.safeId('_BV_file_outer_')
},
on: {
dragenter: this.onDragenter,
dragover: this.onDragover,
dragleave: this.onDragleave,
drop: this.onDrop
}
}, [$input, $label]);
}
});
var FormFilePlugin = /*#__PURE__*/pluginFactory({
components: {
BFormFile: BFormFile,
BFile: BFormFile
}
});
var escapeChar = function escapeChar(value) {
return '\\' + value;
}; // The `cssEscape()` util is based on this `CSS.escape()` polyfill:
// https://github.com/mathiasbynens/CSS.escape
var cssEscape = function cssEscape(value) {
value = toString$1(value);
var length = value.length;
var firstCharCode = value.charCodeAt(0);
return value.split('').reduce(function (result, char, index) {
var charCode = value.charCodeAt(index); // If the character is NULL (U+0000), use (U+FFFD) as replacement
if (charCode === 0x0000) {
return result + "\uFFFD";
} // If the character ...
if ( // ... is U+007F OR
charCode === 0x007f || // ... is in the range [\1-\1F] (U+0001 to U+001F) OR ...
charCode >= 0x0001 && charCode <= 0x001f || // ... is the first character and is in the range [0-9] (U+0030 to U+0039) OR ...
index === 0 && charCode >= 0x0030 && charCode <= 0x0039 || // ... is the second character and is in the range [0-9] (U+0030 to U+0039)
// and the first character is a `-` (U+002D) ...
index === 1 && charCode >= 0x0030 && charCode <= 0x0039 && firstCharCode === 0x002d) {
// ... https://drafts.csswg.org/cssom/#escape-a-character-as-code-point
return result + escapeChar("".concat(charCode.toString(16), " "));
} // If the character ...
if ( // ... is the first character AND ...
index === 0 && // ... is a `-` (U+002D) AND ...
charCode === 0x002d && // ... there is no second character ...
length === 1) {
// ... use the escaped character
return result + escapeChar(char);
} // If the character ...
if ( // ... is greater than or equal to U+0080 OR ...
charCode >= 0x0080 || // ... is `-` (U+002D) OR ...
charCode === 0x002d || // ... is `_` (U+005F) OR ...
charCode === 0x005f || // ... is in the range [0-9] (U+0030 to U+0039) OR ...
charCode >= 0x0030 && charCode <= 0x0039 || // ... is in the range [A-Z] (U+0041 to U+005A) OR ...
charCode >= 0x0041 && charCode <= 0x005a || // ... is in the range [a-z] (U+0061 to U+007A) ...
charCode >= 0x0061 && charCode <= 0x007a) {
// ... use the character itself
return result + char;
} // Otherwise use the escaped character
// See: https://drafts.csswg.org/cssom/#escape-a-character
return result + escapeChar(char);
}, '');
};
var ALIGN_SELF_VALUES = ['auto', 'start', 'end', 'center', 'baseline', 'stretch']; // Generates a prop object with a type of `[Boolean, String, Number]`
var boolStrNum = function boolStrNum() {
return {
type: [Boolean, String, Number],
default: false
};
}; // Generates a prop object with a type of `[String, Number]`
var strNum = function strNum() {
return {
type: [String, Number],
default: null
};
}; // Compute a breakpoint class name
var computeBreakpoint = function computeBreakpoint(type, breakpoint, val) {
var className = type;
if (isUndefinedOrNull(val) || val === false) {
return undefined;
}
if (breakpoint) {
className += "-".concat(breakpoint);
} // Handling the boolean style prop when accepting [Boolean, String, Number]
// means Vue will not convert <b-col sm></b-col> 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 lowerCase(className);
} // .order-md-6
className += "-".concat(val);
return lowerCase(className);
}; // Memoized function for better performance on generating class names
var computeBreakpointClass = memoize(computeBreakpoint); // Cached copy of the breakpoint prop names
var breakpointPropMap = create(null); // Lazy evaled props factory for BCol
var generateProps = function generateProps() {
// Grab the breakpoints from the cached config (exclude the '' (xs) breakpoint)
var breakpoints = getBreakpointsUpCached().filter(identity); // Supports classes like: .col-sm, .col-md-6, .col-lg-auto
var breakpointCol = breakpoints.reduce(function (propMap, breakpoint) {
if (breakpoint) {
// We filter out the '' breakpoint (xs), as making a prop name ''
// would not work. The `cols` prop is used for `xs`
propMap[breakpoint] = boolStrNum();
}
return propMap;
}, create(null)); // Supports classes like: .offset-md-1, .offset-lg-12
var breakpointOffset = breakpoints.reduce(function (propMap, breakpoint) {
propMap[suffixPropName(breakpoint, 'offset')] = strNum();
return propMap;
}, create(null)); // Supports classes like: .order-md-1, .order-lg-12
var breakpointOrder = breakpoints.reduce(function (propMap, breakpoint) {
propMap[suffixPropName(breakpoint, 'order')] = strNum();
return propMap;
}, create(null)); // For loop doesn't need to check hasOwnProperty
// when using an object created from null
breakpointPropMap = assign(create(null), {
col: keys(breakpointCol),
offset: keys(breakpointOffset),
order: keys(breakpointOrder)
}); // Return the generated props
return _objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({
// Generic flexbox .col (xs)
col: {
type: Boolean,
default: false
},
// .col-[1-12]|auto (xs)
cols: strNum()
}, breakpointCol), {}, {
offset: strNum()
}, breakpointOffset), {}, {
order: strNum()
}, breakpointOrder), {}, {
// Flex alignment
alignSelf: {
type: String,
default: null,
validator: function validator(value) {
return arrayIncludes(ALIGN_SELF_VALUES, value);
}
},
tag: {
type: String,
default: 'div'
}
});
}; // We do not use Vue.extend here as that would evaluate the props
// immediately, which we do not want to happen
// @vue/component
var BCol = {
name: NAME_COL,
functional: true,
get props() {
// Allow props to be lazy evaled on first access and
// then they become a non-getter afterwards.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get#Smart_self-overwriting_lazy_getters
delete this.props; // eslint-disable-next-line no-return-assign
return this.props = generateProps();
},
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++) {
// computeBreakpoint(col, colSm => Sm, value=[String, Number, Boolean])
var c = computeBreakpointClass(type, _keys[i].replace(type, ''), props[_keys[i]]); // If a class is returned, push it onto the array.
if (c) {
classList.push(c);
}
}
}
var hasColClasses = classList.some(function (className) {
return RX_COL_CLASS.test(className);
});
classList.push((_classList$push = {
// Default to .col if no other col-{bp}-* classes generated nor `cols` specified.
col: props.col || !hasColClasses && !props.cols
}, _defineProperty(_classList$push, "col-".concat(props.cols), props.cols), _defineProperty(_classList$push, "offset-".concat(props.offset), props.offset), _defineProperty(_classList$push, "order-".concat(props.order), props.order), _defineProperty(_classList$push, "align-self-".concat(props.alignSelf), props.alignSelf), _classList$push));
return h(props.tag, a(data, {
class: classList
}), children);
}
};
// Selector for finding first input in the form-group
var INPUT_SELECTOR = 'input:not([disabled]),textarea:not([disabled]),select:not([disabled])'; // A list of interactive elements (tag names) inside `<b-form-group>`'s legend
var LEGEND_INTERACTIVE_ELEMENTS = ['input', 'select', 'textarea', 'label', 'button', 'a']; // -- BFormGroup prop factory -- used for lazy generation of props
// Memoize this function to return cached values to
// save time in computed functions
var makePropName = memoize(function () {
var breakpoint = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
var prefix = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
return "".concat(prefix).concat(upperFirst(breakpoint));
}); // BFormGroup prop generator for lazy generation of props
var generateProps$1 = function generateProps() {
var CODE_BREAKPOINTS = getBreakpointsUpCached(); // Generate the `labelCol` breakpoint props
var bpLabelColProps = CODE_BREAKPOINTS.reduce(function (props, breakpoint) {
// i.e. 'label-cols', 'label-cols-sm', 'label-cols-md', ...
props[makePropName(breakpoint, 'labelCols')] = {
type: [Number, String, Boolean],
default: breakpoint ? false : null
};
return props;
}, create(null)); // Generate the `labelAlign` breakpoint props
var bpLabelAlignProps = CODE_BREAKPOINTS.reduce(function (props, breakpoint) {
// 'label-align', 'bel-align-sm', 'label-align-md', ...
props[makePropName(breakpoint, 'labelAlign')] = {
type: String // left, right, center
// default: null
};
return props;
}, create(null));
return makePropsConfigurable(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, props$E), {}, {
label: {
type: String // default: null
},
labelFor: {
type: String // default: null
},
labelSize: {
type: String // default: null
},
labelSrOnly: {
type: Boolean,
default: false
}
}, bpLabelColProps), bpLabelAlignProps), {}, {
labelClass: {
type: [String, Array, Object] // default: null
},
description: {
type: String // default: null
},
invalidFeedback: {
type: String // default: null
},
validFeedback: {
type: String // default: null
},
tooltip: {
// Enable tooltip style feedback
type: Boolean,
default: false
},
feedbackAriaLive: {
type: String,
default: 'assertive'
},
validated: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
}
}), NAME_FORM_GROUP);
}; // We do not use Vue.extend here as that would evaluate the props
// immediately, which we do not want to happen
// @vue/component
var BFormGroup = {
name: NAME_FORM_GROUP,
mixins: [idMixin, formStateMixin, normalizeSlotMixin],
get props() {
// Allow props to be lazy evaled on first access and
// then they become a non-getter afterwards
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get#Smart_self-overwriting_lazy_getters
delete this.props; // eslint-disable-next-line no-return-assign
return this.props = generateProps$1();
},
data: function data() {
return {
describedByIds: ''
};
},
computed: {
labelColProps: function labelColProps() {
var _this = this;
var props = {};
getBreakpointsUpCached().forEach(function (breakpoint) {
// Grab the value if the label column breakpoint prop
var propVal = _this[makePropName(breakpoint, 'labelCols')]; // Handle case where the prop's value is an empty string,
// which represents `true`
propVal = propVal === '' ? true : propVal || false;
if (!isBoolean(propVal) && propVal !== 'auto') {
// Convert to column size to number
propVal = toInteger(propVal, 0); // Ensure column size is greater than `0`
propVal = propVal > 0 ? propVal : false;
}
if (propVal) {
// Add the prop to the list of props to give to `<b-col>`
// If breakpoint is '' (`labelCols` is `true`), then we use the
// col prop to make equal width at 'xs'
props[breakpoint || (isBoolean(propVal) ? 'col' : 'cols')] = propVal;
}
});
return props;
},
labelAlignClasses: function labelAlignClasses() {
var _this2 = this;
var classes = [];
getBreakpointsUpCached().forEach(function (breakpoint) {
// Assemble the label column breakpoint align classes
var propVal = _this2[makePropName(breakpoint, 'labelAlign')] || null;
if (propVal) {
var className = breakpoint ? "text-".concat(breakpoint, "-").concat(propVal) : "text-".concat(propVal);
classes.push(className);
}
});
return classes;
},
isHorizontal: function isHorizontal() {
// Determine if the resultant form-group will be rendered
// horizontal (meaning it has label-col breakpoints)
return keys(this.labelColProps).length > 0;
}
},
watch: {
describedByIds: function describedByIds(newValue, oldValue) {
if (newValue !== oldValue) {
this.setInputDescribedBy(newValue, oldValue);
}
}
},
mounted: function mounted() {
var _this3 = this;
this.$nextTick(function () {
// Set the `aria-describedby` IDs on the input specified by `label-for`
// We do this in a `$nextTick()` to ensure the children have finished rendering
_this3.setInputDescribedBy(_this3.describedByIds);
});
},
methods: {
legendClick: function legendClick(evt) {
// Don't do anything if labelFor is set
/* istanbul ignore next: clicking a label will focus the input, so no need to test */
if (this.labelFor) {
return;
}
var target = evt.target;
var tagName = target ? target.tagName : ''; // If clicked an interactive element inside legend,
// we just let the default happen
/* istanbul ignore next */
if (LEGEND_INTERACTIVE_ELEMENTS.indexOf(tagName) !== -1) {
return;
}
var inputs = selectAll(INPUT_SELECTOR, this.$refs.content).filter(isVisible); // If only a single input, focus it, emulating label behaviour
if (inputs && inputs.length === 1) {
attemptFocus(inputs[0]);
}
},
// 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
// Preserves any `aria-describedby` value(s) user may have on input
setInputDescribedBy: function setInputDescribedBy(add, remove) {
if (this.labelFor && isBrowser) {
// We need to escape `labelFor` since it can be user-provided
var input = select("#".concat(cssEscape(this.labelFor)), this.$refs.content);
if (input) {
var adb = 'aria-describedby';
var ids = (getAttr(input, adb) || '').split(/\s+/);
add = (add || '').split(/\s+/);
remove = (remove || '').split(/\s+/); // Update ID list, preserving any original IDs
// and ensuring the ID's are unique
ids = ids.filter(function (id) {
return !arrayIncludes(remove, id);
}).concat(add).filter(Boolean);
ids = keys(ids.reduce(function (memo, id) {
return _objectSpread2(_objectSpread2({}, memo), {}, _defineProperty({}, id, true));
}, {})).join(' ').trim();
if (ids) {
setAttr(input, adb, ids);
} else {
// No IDs, so remove the attribute
removeAttr(input, adb);
}
}
}
}
},
render: function render(h) {
var labelFor = this.labelFor,
tooltip = this.tooltip,
feedbackAriaLive = this.feedbackAriaLive,
state = this.computedState,
isHorizontal = this.isHorizontal,
normalizeSlot = this.normalizeSlot;
var isFieldset = !labelFor;
var $label = h();
var labelContent = normalizeSlot(SLOT_NAME_LABEL) || this.label;
var labelId = labelContent ? this.safeId('_BV_label_') : null;
if (labelContent || isHorizontal) {
var labelSize = this.labelSize,
labelColProps = this.labelColProps;
var isLegend = isFieldset;
var labelTag = isLegend ? 'legend' : 'label';
if (this.labelSrOnly) {
if (labelContent) {
$label = h(labelTag, {
class: 'sr-only',
attrs: {
id: labelId,
for: labelFor || null
}
}, [labelContent]);
}
$label = h(isHorizontal ? BCol : 'div', {
props: isHorizontal ? labelColProps : {}
}, [$label]);
} else {
$label = h(isHorizontal ? BCol : labelTag, {
on: isLegend ? {
click: this.legendClick
} : {},
props: isHorizontal ? _objectSpread2({
tag: labelTag
}, labelColProps) : {},
attrs: {
id: labelId,
for: labelFor || null,
// We add a `tabindex` to legend so that screen readers
// will properly read the `aria-labelledby` in IE
tabindex: isLegend ? '-1' : null
},
class: [// Hide the focus ring on the legend
isLegend ? 'bv-no-focus-ring' : '', // When horizontal or if a legend is rendered, add 'col-form-label' class
// for correct sizing as Bootstrap has inconsistent font styling for
// legend in non-horizontal form-groups
// See: https://github.com/twbs/bootstrap/issues/27805
isHorizontal || isLegend ? 'col-form-label' : '', // Emulate label padding top of `0` on legend when not horizontal
!isHorizontal && isLegend ? 'pt-0' : '', // If not horizontal and not a legend, we add 'd-block' class to label
// so that label-align works
!isHorizontal && !isLegend ? 'd-block' : '', labelSize ? "col-form-label-".concat(labelSize) : '', this.labelAlignClasses, this.labelClass]
}, [labelContent]);
}
}
var $invalidFeedback = h();
var invalidFeedbackContent = normalizeSlot('invalid-feedback') || this.invalidFeedback;
var invalidFeedbackId = invalidFeedbackContent ? this.safeId('_BV_feedback_invalid_') : null;
if (invalidFeedbackContent) {
$invalidFeedback = h(BFormInvalidFeedback, {
props: {
id: invalidFeedbackId,
// If state is explicitly `false`, always show the feedback
state: state,
tooltip: tooltip,
ariaLive: feedbackAriaLive,
role: feedbackAriaLive ? 'alert' : null
},
attrs: {
tabindex: invalidFeedbackContent ? '-1' : null
}
}, [invalidFeedbackContent]);
}
var $validFeedback = h();
var validFeedbackContent = normalizeSlot('valid-feedback') || this.validFeedback;
var validFeedbackId = validFeedbackContent ? this.safeId('_BV_feedback_valid_') : null;
if (validFeedbackContent) {
$validFeedback = h(BFormValidFeedback, {
props: {
id: validFeedbackId,
// If state is explicitly `true`, always show the feedback
state: state,
tooltip: tooltip,
ariaLive: feedbackAriaLive,
role: feedbackAriaLive ? 'alert' : null
},
attrs: {
tabindex: validFeedbackContent ? '-1' : null
}
}, [validFeedbackContent]);
}
var $description = h();
var descriptionContent = normalizeSlot(SLOT_NAME_DESCRIPTION) || this.description;
var descriptionId = descriptionContent ? this.safeId('_BV_description_') : null;
if (descriptionContent) {
$description = h(BFormText, {
attrs: {
id: descriptionId,
tabindex: descriptionContent ? '-1' : null
}
}, [descriptionContent]);
}
var $content = h(isHorizontal ? BCol : 'div', {
ref: 'content',
// Hide focus ring
staticClass: 'bv-no-focus-ring',
attrs: {
tabindex: isFieldset ? '-1' : null,
role: isFieldset ? 'group' : null,
'aria-labelledby': isFieldset ? labelId : null
}
}, [normalizeSlot() || h(), $invalidFeedback, $validFeedback, $description]); // Update the `aria-describedby` IDs
// Screen readers will read out any content linked to by `aria-describedby`
// even if the content is hidden with `display: none;`, hence we only include
// feedback IDs if the form-group's state is explicitly valid or invalid
this.describedByIds = [descriptionId, state === false ? invalidFeedbackId : null, state === true ? validFeedbackId : null].filter(Boolean).join(' '); // Return it wrapped in a form-group
// Note: Fieldsets do not support adding `row` or `form-row` directly
// to them due to browser specific render issues, so we move the `form-row`
// to an inner wrapper div when horizontal and using a fieldset
return h(isFieldset ? 'fieldset' : isHorizontal ? BFormRow : 'div', {
staticClass: 'form-group',
class: [this.validated ? 'was-validated' : null, this.stateClass],
attrs: {
id: this.safeId(),
disabled: isFieldset ? this.disabled : null,
role: isFieldset ? null : 'group',
'aria-invalid': state === false ? 'true' : null,
// Only apply aria-labelledby if we are a horizontal fieldset
// as the legend is no longer a direct child of fieldset
'aria-labelledby': isFieldset && isHorizontal ? labelId : null,
// Only apply `aria-describedby` IDs if we are a fieldset
// as the input will have the IDs when not a fieldset
'aria-describedby': isFieldset ? this.describedByIds : null
}
}, isHorizontal && isFieldset ? [h(BFormRow, [$label, $content])] : [$label, $content]);
}
};
var FormGroupPlugin = /*#__PURE__*/pluginFactory({
components: {
BFormGroup: BFormGroup,
BFormFieldset: BFormGroup
}
});
// @vue/component
var formSelectionMixin = {
computed: {
selectionStart: {
// Expose selectionStart for formatters, etc
cache: false,
/* istanbul ignore next */
get: function get() {
return this.$refs.input.selectionStart;
},
/* istanbul ignore next */
set: function set(val) {
this.$refs.input.selectionStart = val;
}
},
selectionEnd: {
// Expose selectionEnd for formatters, etc
cache: false,
/* istanbul ignore next */
get: function get() {
return this.$refs.input.selectionEnd;
},
/* istanbul ignore next */
set: function set(val) {
this.$refs.input.selectionEnd = val;
}
},
selectionDirection: {
// Expose selectionDirection for formatters, etc
cache: false,
/* istanbul ignore next */
get: function get() {
return this.$refs.input.selectionDirection;
},
/* istanbul ignore next */
set: function set(val) {
this.$refs.input.selectionDirection = val;
}
}
},
methods: {
/* istanbul ignore next */
select: function select() {
var _this$$refs$input;
// For external handler that may want a select() method
(_this$$refs$input = this.$refs.input).select.apply(_this$$refs$input, arguments);
},
/* istanbul ignore next */
setSelectionRange: function setSelectionRange() {
var _this$$refs$input2;
// For external handler that may want a setSelectionRange(a,b,c) method
(_this$$refs$input2 = this.$refs.input).setSelectionRange.apply(_this$$refs$input2, arguments);
},
/* istanbul ignore next */
setRangeText: function setRangeText() {
var _this$$refs$input3;
// For external handler that may want a setRangeText(a,b,c) method
(_this$$refs$input3 = this.$refs.input).setRangeText.apply(_this$$refs$input3, arguments);
}
}
};
var props$I = makePropsConfigurable({
value: {
type: [String, Number],
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
},
formatter: {
type: Function // default: null
},
lazyFormatter: {
type: Boolean,
default: false
},
trim: {
type: Boolean,
default: false
},
number: {
type: Boolean,
default: false
},
lazy: {
// Only update the `v-model` on blur/change events
type: Boolean,
default: false
},
debounce: {
// Debounce timeout (in ms). Not applicable with `lazy` prop
type: [Number, String],
default: 0
}
}, 'formTextControls'); // --- Mixin ---
// @vue/component
var formTextMixin = {
model: {
prop: 'value',
event: 'update'
},
props: props$I,
data: function data() {
return {
localValue: toString$1(this.value),
vModelValue: this.value
};
},
computed: {
computedClass: function computedClass() {
return [{
// Range input needs class `custom-range`
'custom-range': this.type === 'range',
// `plaintext` not supported by `type="range"` or `type="color"`
'form-control-plaintext': this.plaintext && this.type !== 'range' && this.type !== 'color',
// `form-control` not used by `type="range"` or `plaintext`
// Always used by `type="color"`
'form-control': !this.plaintext && this.type !== 'range' || this.type === 'color'
}, 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 the string 'true')
return this.ariaInvalid;
},
computedDebounce: function computedDebounce() {
// Ensure we have a positive number equal to or greater than 0
return mathMax(toInteger(this.debounce, 0), 0);
},
hasFormatter: function hasFormatter() {
var result = null;
try {
result = this.formatter();
} catch (_unused) {}
return !isUndefined(result);
}
},
watch: {
value: function value(newVal) {
var stringifyValue = toString$1(newVal);
if (stringifyValue !== this.localValue && newVal !== this.vModelValue) {
// Clear any pending debounce timeout, as we are overwriting the user input
this.clearDebounce(); // Update the local values
this.localValue = stringifyValue;
this.vModelValue = newVal;
}
}
},
created: function created() {
// Create private non-reactive props
this.$_inputDebounceTimer = null;
},
mounted: function mounted() {
// Set up destroy handler
this.$on('hook:beforeDestroy', this.clearDebounce); // Preset the internal state
var value = this.value;
var stringifyValue = toString$1(value);
/* istanbul ignore next */
if (stringifyValue !== this.localValue && value !== this.vModelValue) {
this.localValue = stringifyValue;
this.vModelValue = value;
}
},
methods: {
clearDebounce: function clearDebounce() {
clearTimeout(this.$_inputDebounceTimer);
this.$_inputDebounceTimer = null;
},
formatValue: function formatValue(value, evt) {
var force = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
value = toString$1(value);
if (this.hasFormatter && (!this.lazyFormatter || force)) {
value = this.formatter(value, evt);
}
return value;
},
modifyValue: function modifyValue(value) {
// Emulate `.trim` modifier behaviour
if (this.trim) {
value = value.trim();
} // Emulate `.number` modifier behaviour
if (this.number) {
value = toFloat(value, value);
}
return value;
},
updateValue: function updateValue(value) {
var _this = this;
var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var lazy = this.lazy;
if (lazy && !force) {
return;
} // Make sure to always clear the debounce when `updateValue()`
// is called, even when the v-model hasn't changed
this.clearDebounce(); // Define the shared update logic in a method to be able to use
// it for immediate and debounced value changes
var doUpdate = function doUpdate() {
value = _this.modifyValue(value);
if (value !== _this.vModelValue) {
_this.vModelValue = value;
_this.$emit('update', value);
} else if (_this.hasFormatter) {
// When the `vModelValue` hasn't changed but the actual input value
// is out of sync, make sure to change it to the given one
// Usually caused by browser autocomplete and how it triggers the
// change or input event, or depending on the formatter function
// https://github.com/bootstrap-vue/bootstrap-vue/issues/2657
// https://github.com/bootstrap-vue/bootstrap-vue/issues/3498
/* istanbul ignore next: hard to test */
var $input = _this.$refs.input;
/* istanbul ignore if: hard to test out of sync value */
if ($input && value !== $input.value) {
$input.value = value;
}
}
}; // Only debounce the value update when a value greater than `0`
// is set and we are not in lazy mode or this is a forced update
var debounce = this.computedDebounce;
if (debounce > 0 && !lazy && !force) {
this.$_inputDebounceTimer = setTimeout(doUpdate, debounce);
} else {
// Immediately update the v-model
doUpdate();
}
},
onInput: function onInput(evt) {
// `evt.target.composing` is set by Vue
// https://github.com/vuejs/vue/blob/dev/src/platforms/web/runtime/directives/model.js
// TODO: Is this needed now with the latest Vue?
/* istanbul ignore if: hard to test composition events */
if (evt.target.composing) {
return;
}
var value = evt.target.value;
var formattedValue = this.formatValue(value, evt); // Exit when the `formatter` function strictly returned `false`
// or prevented the input event
/* istanbul ignore next */
if (formattedValue === false || evt.defaultPrevented) {
stopEvent(evt, {
propagation: false
});
return;
}
this.localValue = formattedValue;
this.updateValue(formattedValue);
this.$emit('input', formattedValue);
},
onChange: function onChange(evt) {
var value = evt.target.value;
var formattedValue = this.formatValue(value, evt); // Exit when the `formatter` function strictly returned `false`
// or prevented the input event
/* istanbul ignore next */
if (formattedValue === false || evt.defaultPrevented) {
stopEvent(evt, {
propagation: false
});
return;
}
this.localValue = formattedValue;
this.updateValue(formattedValue, true);
this.$emit('change', formattedValue);
},
onBlur: function onBlur(evt) {
// Apply the `localValue` on blur to prevent cursor jumps
// on mobile browsers (e.g. caused by autocomplete)
var value = evt.target.value;
var formattedValue = this.formatValue(value, evt, true);
if (formattedValue !== false) {
// We need to use the modified value here to apply the
// `.trim` and `.number` modifiers properly
this.localValue = toString$1(this.modifyValue(formattedValue)); // We pass the formatted value here since the `updateValue` method
// handles the modifiers itself
this.updateValue(formattedValue, true);
} // Emit native blur event
this.$emit('blur', evt);
},
focus: function focus() {
// For external handler that may want a focus method
if (!this.disabled) {
attemptFocus(this.$el);
}
},
blur: function blur() {
// For external handler that may want a blur method
if (!this.disabled) {
attemptBlur(this.$el);
}
}
}
};
// @vue/component
var formValidityMixin = {
computed: {
validity: {
// Expose validity property
cache: false,
/* istanbul ignore next */
get: function get() {
return this.$refs.input.validity;
}
},
validationMessage: {
// Expose validationMessage property
cache: false,
/* istanbul ignore next */
get: function get() {
return this.$refs.input.validationMessage;
}
},
willValidate: {
// Expose willValidate property
cache: false,
/* istanbul ignore next */
get: function get() {
return this.$refs.input.willValidate;
}
}
},
methods: {
/* istanbul ignore next */
setCustomValidity: function setCustomValidity() {
var _this$$refs$input;
// For external handler that may want a setCustomValidity(...) method
return (_this$$refs$input = this.$refs.input).setCustomValidity.apply(_this$$refs$input, arguments);
},
/* istanbul ignore next */
checkValidity: function checkValidity() {
var _this$$refs$input2;
// For external handler that may want a checkValidity(...) method
return (_this$$refs$input2 = this.$refs.input).checkValidity.apply(_this$$refs$input2, arguments);
},
/* istanbul ignore next */
reportValidity: function reportValidity() {
var _this$$refs$input3;
// For external handler that may want a reportValidity(...) method
return (_this$$refs$input3 = this.$refs.input).reportValidity.apply(_this$$refs$input3, arguments);
}
}
};
// Valid supported input types
var TYPES$1 = ['text', 'password', 'email', 'number', 'url', 'tel', 'search', 'range', 'color', 'date', 'time', 'datetime', 'datetime-local', 'month', 'week']; // --- Main component ---
// @vue/component
var BFormInput = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_FORM_INPUT,
// Mixin order is important!
mixins: [listenersMixin, idMixin, formControlMixin, formSizeMixin, formStateMixin, formTextMixin, formSelectionMixin, formValidityMixin],
props: makePropsConfigurable(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, props$A), props$D), props$E), props$I), {}, {
// `value` prop is defined in form-text mixin
type: {
type: String,
default: 'text',
validator: function validator(type) {
return arrayIncludes(TYPES$1, type);
}
},
noWheel: {
// Disable mousewheel to prevent wheel from
// changing values (i.e. number/date)
type: Boolean,
default: false
},
min: {
type: [String, Number] // default: null
},
max: {
type: [String, Number] // default: null
},
step: {
type: [String, Number] // default: null
},
list: {
type: String // default: null
}
}), NAME_FORM_INPUT),
computed: {
localType: function localType() {
// We only allow certain types
return arrayIncludes(TYPES$1, this.type) ? this.type : 'text';
},
computedAttrs: function computedAttrs() {
var type = this.localType,
disabled = this.disabled,
placeholder = this.placeholder,
required = this.required,
min = this.min,
max = this.max,
step = this.step;
return {
id: this.safeId(),
name: this.name || null,
form: this.form || null,
type: type,
disabled: disabled,
placeholder: placeholder,
required: required,
autocomplete: this.autocomplete || null,
readonly: this.readonly || this.plaintext,
min: min,
max: max,
step: step,
list: type !== 'password' ? this.list : null,
'aria-required': required ? 'true' : null,
'aria-invalid': this.computedAriaInvalid
};
},
computedListeners: function computedListeners() {
return _objectSpread2(_objectSpread2({}, this.bvListeners), {}, {
input: this.onInput,
change: this.onChange,
blur: this.onBlur
});
}
},
watch: {
noWheel: function noWheel(newVal) {
this.setWheelStopper(newVal);
}
},
mounted: function mounted() {
this.setWheelStopper(this.noWheel);
},
/* istanbul ignore next */
deactivated: function deactivated() {
// Turn off listeners when keep-alive component deactivated
/* istanbul ignore next */
this.setWheelStopper(false);
},
/* istanbul ignore next */
activated: function activated() {
// Turn on listeners (if no-wheel) when keep-alive component activated
/* istanbul ignore next */
this.setWheelStopper(this.noWheel);
},
beforeDestroy: function beforeDestroy() {
/* istanbul ignore next */
this.setWheelStopper(false);
},
methods: {
setWheelStopper: function setWheelStopper(on) {
var input = this.$el; // We use native events, so that we don't interfere with propagation
eventOnOff(on, input, 'focus', this.onWheelFocus);
eventOnOff(on, input, 'blur', this.onWheelBlur);
if (!on) {
eventOff(document, 'wheel', this.stopWheel);
}
},
onWheelFocus: function onWheelFocus() {
eventOn(document, 'wheel', this.stopWheel);
},
onWheelBlur: function onWheelBlur() {
eventOff(document, 'wheel', this.stopWheel);
},
stopWheel: function stopWheel(evt) {
stopEvent(evt, {
propagation: false
});
attemptBlur(this.$el);
}
},
render: function render(h) {
return h('input', {
ref: 'input',
class: this.computedClass,
attrs: this.computedAttrs,
domProps: {
value: this.localValue
},
on: this.computedListeners
});
}
});
var FormInputPlugin = /*#__PURE__*/pluginFactory({
components: {
BFormInput: BFormInput,
BInput: BFormInput
}
});
var props$J = makePropsConfigurable(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, props$A), props$v), props$F), props$D), props$E), {}, {
checked: {
// type: [String, Number, Boolean, Object],
default: null
}
}), NAME_FORM_RADIO_GROUP); // --- Main component ---
// @vue/component
var BFormRadioGroup = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_FORM_RADIO_GROUP,
mixins: [idMixin, formControlMixin, formRadioCheckGroupMixin, // Includes render function
formOptionsMixin, formSizeMixin, formStateMixin],
provide: function provide() {
return {
bvRadioGroup: this
};
},
props: props$J,
data: function data() {
return {
localChecked: this.checked
};
},
computed: {
isRadioGroup: function isRadioGroup() {
return true;
}
}
});
var FormRadioPlugin = /*#__PURE__*/pluginFactory({
components: {
BFormRadio: BFormRadio,
BRadio: BFormRadio,
BFormRadioGroup: BFormRadioGroup,
BRadioGroup: BFormRadioGroup
}
});
var MIN_STARS = 3;
var DEFAULT_STARS = 5; // --- Utility methods ---
var computeStars = function computeStars(stars) {
return mathMax(MIN_STARS, toInteger(stars, DEFAULT_STARS));
};
var clampValue = function clampValue(value, min, max) {
return mathMax(mathMin(value, max), min);
}; // --- Private helper components ---
// @vue/component
var BVFormRatingStar = Vue__default['default'].extend({
name: NAME_FORM_RATING_STAR,
mixins: [normalizeSlotMixin],
props: {
rating: {
type: Number,
default: 0
},
star: {
type: Number,
default: 0
},
focused: {
// If parent is focused
type: Boolean,
default: false
},
variant: {
type: String // default: null
},
disabled: {
type: Boolean,
default: false
},
readonly: {
type: Boolean,
default: false
},
hasClear: {
type: Boolean,
default: false
}
},
methods: {
onClick: function onClick(evt) {
if (!this.disabled && !this.readonly) {
stopEvent(evt, {
propagation: false
});
this.$emit('selected', this.star);
}
}
},
render: function render(h) {
var rating = this.rating,
star = this.star,
focused = this.focused,
hasClear = this.hasClear,
variant = this.variant,
disabled = this.disabled,
readonly = this.readonly;
var minStar = hasClear ? 0 : 1;
var type = rating >= star ? 'full' : rating >= star - 0.5 ? 'half' : 'empty';
var slotScope = {
variant: variant,
disabled: disabled,
readonly: readonly
};
return h('span', {
staticClass: 'b-rating-star',
class: {
// When not hovered, we use this class to focus the current (or first) star
focused: focused && rating === star || !toInteger(rating) && star === minStar,
// We add type classes to we can handle RTL styling
'b-rating-star-empty': type === 'empty',
'b-rating-star-half': type === 'half',
'b-rating-star-full': type === 'full'
},
attrs: {
tabindex: !disabled && !readonly ? '-1' : null
},
on: {
click: this.onClick
}
}, [h('span', {
staticClass: 'b-rating-icon'
}, [this.normalizeSlot(type, slotScope)])]);
}
}); // --- Main component ---
// @vue/component
var BFormRating = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_FORM_RATING,
components: {
BIconStar: BIconStar,
BIconStarHalf: BIconStarHalf,
BIconStarFill: BIconStarFill,
BIconX: BIconX
},
mixins: [idMixin, formSizeMixin],
model: {
prop: 'value',
event: 'change'
},
props: makePropsConfigurable(_objectSpread2(_objectSpread2(_objectSpread2({}, omit(props$A, ['required', 'autofocus'])), props$D), {}, {
value: {
type: [Number, String],
default: null
},
stars: {
type: [Number, String],
default: DEFAULT_STARS,
validator: function validator(value) {
return toInteger(value) >= MIN_STARS;
}
},
variant: {
type: String // default: undefined
},
color: {
// CSS color string (overrides variant)
type: String // default: undefined
},
showValue: {
type: Boolean,
default: false
},
showValueMax: {
type: Boolean,
default: false
},
readonly: {
type: Boolean,
default: false
},
noBorder: {
type: Boolean,
default: false
},
inline: {
type: Boolean,
default: false
},
precision: {
type: [Number, String],
default: null
},
iconEmpty: {
type: String,
default: 'star'
},
iconHalf: {
type: String,
default: 'star-half'
},
iconFull: {
type: String,
default: 'star-fill'
},
iconClear: {
type: String,
default: 'x'
},
locale: {
// Locale for the formatted value (if shown)
// Defaults to the browser locale. Falls back to `en`
type: [String, Array] // default: undefined
},
showClear: {
type: Boolean,
default: false
}
}), NAME_FORM_RATING),
data: function data() {
var value = toFloat(this.value, null);
var stars = computeStars(this.stars);
return {
localValue: isNull(value) ? null : clampValue(value, 0, stars),
hasFocus: false
};
},
computed: {
computedStars: function computedStars() {
return computeStars(this.stars);
},
computedRating: function computedRating() {
var value = toFloat(this.localValue, 0);
var precision = toInteger(this.precision, 3); // We clamp the value between `0` and stars
return clampValue(toFloat(value.toFixed(precision)), 0, this.computedStars);
},
computedLocale: function computedLocale() {
var locales = concat(this.locale).filter(identity);
var nf = new Intl.NumberFormat(locales);
return nf.resolvedOptions().locale;
},
isInteractive: function isInteractive() {
return !this.disabled && !this.readonly;
},
isRTL: function isRTL() {
return isLocaleRTL(this.computedLocale);
},
formattedRating: function formattedRating() {
var precision = toInteger(this.precision);
var showValueMax = this.showValueMax;
var locale = this.computedLocale;
var formatOptions = {
notation: 'standard',
minimumFractionDigits: isNaN(precision) ? 0 : precision,
maximumFractionDigits: isNaN(precision) ? 3 : precision
};
var stars = this.computedStars.toLocaleString(locale);
var value = this.localValue;
value = isNull(value) ? showValueMax ? '-' : '' : value.toLocaleString(locale, formatOptions);
return showValueMax ? "".concat(value, "/").concat(stars) : value;
}
},
watch: {
value: function value(newVal, oldVal) {
if (newVal !== oldVal) {
var value = toFloat(newVal, null);
this.localValue = isNull(value) ? null : clampValue(value, 0, this.computedStars);
}
},
localValue: function localValue(newVal, oldVal) {
if (newVal !== oldVal && newVal !== (this.value || 0)) {
this.$emit('change', newVal || null);
}
},
disabled: function disabled(newVal) {
if (newVal) {
this.hasFocus = false;
this.blur();
}
}
},
methods: {
// --- Public methods ---
focus: function focus() {
if (!this.disabled) {
attemptFocus(this.$el);
}
},
blur: function blur() {
if (!this.disabled) {
attemptBlur(this.$el);
}
},
// --- Private methods ---
onKeydown: function onKeydown(evt) {
var keyCode = evt.keyCode;
if (this.isInteractive && arrayIncludes([CODE_LEFT, CODE_DOWN, CODE_RIGHT, CODE_UP], keyCode)) {
stopEvent(evt, {
propagation: false
});
var value = toInteger(this.localValue, 0);
var min = this.showClear ? 0 : 1;
var stars = this.computedStars; // In RTL mode, LEFT/RIGHT are swapped
var amountRtl = this.isRTL ? -1 : 1;
if (keyCode === CODE_LEFT) {
this.localValue = clampValue(value - amountRtl, min, stars) || null;
} else if (keyCode === CODE_RIGHT) {
this.localValue = clampValue(value + amountRtl, min, stars);
} else if (keyCode === CODE_DOWN) {
this.localValue = clampValue(value - 1, min, stars) || null;
} else if (keyCode === CODE_UP) {
this.localValue = clampValue(value + 1, min, stars);
}
}
},
onSelected: function onSelected(value) {
if (this.isInteractive) {
this.localValue = value;
}
},
onFocus: function onFocus(evt) {
this.hasFocus = !this.isInteractive ? false : evt.type === 'focus';
},
// --- Render methods ---
renderIcon: function renderIcon(icon) {
return this.$createElement(BIcon, {
props: {
icon: icon,
variant: this.disabled || this.color ? null : this.variant || null
}
});
},
iconEmptyFn: function iconEmptyFn() {
return this.renderIcon(this.iconEmpty);
},
iconHalfFn: function iconHalfFn() {
return this.renderIcon(this.iconHalf);
},
iconFullFn: function iconFullFn() {
return this.renderIcon(this.iconFull);
},
iconClearFn: function iconClearFn() {
return this.$createElement(BIcon, {
props: {
icon: this.iconClear
}
});
}
},
render: function render(h) {
var _this = this;
var disabled = this.disabled,
readonly = this.readonly,
name = this.name,
form = this.form,
inline = this.inline,
variant = this.variant,
color = this.color,
noBorder = this.noBorder,
hasFocus = this.hasFocus,
computedRating = this.computedRating,
computedStars = this.computedStars,
formattedRating = this.formattedRating,
showClear = this.showClear,
isRTL = this.isRTL,
isInteractive = this.isInteractive,
$scopedSlots = this.$scopedSlots;
var $content = [];
if (showClear && !disabled && !readonly) {
var $icon = h('span', {
staticClass: 'b-rating-icon'
}, [($scopedSlots['icon-clear'] || this.iconClearFn)()]);
$content.push(h('span', {
staticClass: 'b-rating-star b-rating-star-clear flex-grow-1',
class: {
focused: hasFocus && computedRating === 0
},
attrs: {
tabindex: isInteractive ? '-1' : null
},
on: {
click: function click() {
return _this.onSelected(null);
}
},
key: 'clear'
}, [$icon]));
}
for (var index = 0; index < computedStars; index++) {
var value = index + 1;
$content.push(h(BVFormRatingStar, {
staticClass: 'flex-grow-1',
style: color && !disabled ? {
color: color
} : {},
props: {
rating: computedRating,
star: value,
variant: disabled ? null : variant || null,
disabled: disabled,
readonly: readonly,
focused: hasFocus,
hasClear: showClear
},
on: {
selected: this.onSelected
},
scopedSlots: {
empty: $scopedSlots['icon-empty'] || this.iconEmptyFn,
half: $scopedSlots['icon-half'] || this.iconHalfFn,
full: $scopedSlots['icon-full'] || this.iconFullFn
},
key: index
}));
}
if (name) {
$content.push(h('input', {
attrs: {
type: 'hidden',
value: isNull(this.localValue) ? '' : computedRating,
name: name,
form: form || null
},
key: 'hidden'
}));
}
if (this.showValue) {
$content.push(h('b', {
staticClass: 'b-rating-value flex-grow-1',
attrs: {
'aria-hidden': 'true'
},
key: 'value'
}, toString$1(formattedRating)));
}
return h('output', {
staticClass: 'b-rating form-control align-items-center',
class: [{
'd-inline-flex': inline,
'd-flex': !inline,
'border-0': noBorder,
disabled: disabled,
readonly: !disabled && readonly
}, this.sizeFormClass],
attrs: {
id: this.safeId(),
dir: isRTL ? 'rtl' : 'ltr',
tabindex: disabled ? null : '0',
disabled: disabled,
role: 'slider',
'aria-disabled': disabled ? 'true' : null,
'aria-readonly': !disabled && readonly ? 'true' : null,
'aria-live': 'off',
'aria-valuemin': showClear ? '0' : '1',
'aria-valuemax': toString$1(computedStars),
'aria-valuenow': computedRating ? toString$1(computedRating) : null
},
on: {
keydown: this.onKeydown,
focus: this.onFocus,
blur: this.onFocus
}
}, $content);
}
});
var FormRatingPlugin = /*#__PURE__*/pluginFactory({
components: {
BFormRating: BFormRating,
BRating: BFormRating
}
});
var optionsMixin = {
mixins: [formOptionsMixin],
props: makePropsConfigurable(_objectSpread2(_objectSpread2({}, props$v), {}, {
labelField: {
type: String,
default: 'label'
},
optionsField: {
type: String,
default: 'options'
}
}), 'formOptions'),
methods: {
normalizeOption: function normalizeOption(option) {
var key = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
// When the option is an object, normalize it
if (isPlainObject(option)) {
var value = get(option, this.valueField);
var text = get(option, this.textField);
var options = get(option, this.optionsField, null); // When it has options, create an `<optgroup>` object
if (!isNull(options)) {
return {
label: String(get(option, this.labelField) || text),
options: this.normalizeOptions(options)
};
} // Otherwise create an `<option>` object
return {
value: isUndefined(value) ? key || text : value,
text: String(isUndefined(text) ? key : text),
html: get(option, this.htmlField),
disabled: Boolean(get(option, this.disabledField))
};
} // Otherwise create an `<option>` object from the given value
return {
value: key || option,
text: String(option),
disabled: false
};
}
}
};
var props$K = makePropsConfigurable({
value: {
// type: [String, Number, Boolean, Object],
required: true
},
disabled: {
type: Boolean,
default: false
}
}, NAME_FORM_SELECT_OPTION); // @vue/component
var BFormSelectOption = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_FORM_SELECT_OPTION,
functional: true,
props: props$K,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
var value = props.value,
disabled = props.disabled;
return h('option', a(data, {
attrs: {
disabled: disabled
},
domProps: {
value: value
}
}), children);
}
});
var BFormSelectOptionGroup = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_FORM_SELECT_OPTION_GROUP,
mixins: [normalizeSlotMixin, formOptionsMixin],
props: makePropsConfigurable(_objectSpread2(_objectSpread2({}, props$v), {}, {
label: {
type: String,
required: true
}
}), NAME_FORM_SELECT_OPTION_GROUP),
render: function render(h) {
var $options = this.formOptions.map(function (option, index) {
var value = option.value,
text = option.text,
html = option.html,
disabled = option.disabled;
return h(BFormSelectOption, {
attrs: {
value: value,
disabled: disabled
},
domProps: htmlOrText(html, text),
key: "option_".concat(index)
});
});
return h('optgroup', {
attrs: {
label: this.label
}
}, [this.normalizeSlot(SLOT_NAME_FIRST), $options, this.normalizeSlot()]);
}
});
var BFormSelect = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_FORM_SELECT,
mixins: [idMixin, normalizeSlotMixin, formControlMixin, formSizeMixin, formStateMixin, formCustomMixin, optionsMixin],
model: {
prop: 'value',
event: 'input'
},
props: makePropsConfigurable(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, props$A), props$B), props$D), props$E), {}, {
value: {// type: [Object, Array, String, Number, Boolean],
// default: undefined
},
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
}
}), NAME_FORM_SELECT),
data: function data() {
return {
localValue: this.value
};
},
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 [this.plain ? 'form-control' : 'custom-select', this.size && this.plain ? "form-control-".concat(this.size) : null, this.size && !this.plain ? "custom-select-".concat(this.size) : null, this.stateClass];
},
computedAriaInvalid: function computedAriaInvalid() {
if (this.ariaInvalid === true || this.ariaInvalid === 'true') {
return 'true';
}
return this.stateClass === 'is-invalid' ? 'true' : null;
}
},
watch: {
value: function value(newVal) {
this.localValue = newVal;
},
localValue: function localValue() {
this.$emit('input', this.localValue);
}
},
methods: {
focus: function focus() {
attemptFocus(this.$refs.input);
},
blur: function blur() {
attemptBlur(this.$refs.input);
},
onChange: function onChange(evt) {
var _this = this;
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.$nextTick(function () {
_this.$emit('change', _this.localValue);
});
}
},
render: function render(h) {
var name = this.name,
disabled = this.disabled,
required = this.required,
size = this.computedSelectSize,
value = this.localValue;
var $options = this.formOptions.map(function (option, index) {
var value = option.value,
label = option.label,
options = option.options,
disabled = option.disabled;
var key = "option_".concat(index);
return isArray(options) ? h(BFormSelectOptionGroup, {
props: {
label: label,
options: options
},
key: key
}) : h(BFormSelectOption, {
props: {
value: value,
disabled: disabled
},
domProps: htmlOrText(option.html, option.text),
key: key
});
});
return h('select', {
class: this.inputClass,
attrs: {
id: this.safeId(),
name: name,
form: this.form || null,
multiple: this.multiple || null,
size: size,
disabled: disabled,
required: required,
'aria-required': required ? 'true' : null,
'aria-invalid': this.computedAriaInvalid
},
on: {
change: this.onChange
},
directives: [{
name: 'model',
value: value
}],
ref: 'input'
}, [this.normalizeSlot(SLOT_NAME_FIRST), $options, this.normalizeSlot()]);
}
});
var FormSelectPlugin = /*#__PURE__*/pluginFactory({
components: {
BFormSelect: BFormSelect,
BFormSelectOption: BFormSelectOption,
BFormSelectOptionGroup: BFormSelectOptionGroup,
BSelect: BFormSelect,
BSelectOption: BFormSelectOption,
BSelectOptionGroup: BFormSelectOptionGroup
}
});
// Default for spin button range and step
var DEFAULT_MIN = 1;
var DEFAULT_MAX = 100;
var DEFAULT_STEP = 1; // Delay before auto-repeat in ms
var DEFAULT_REPEAT_DELAY = 500; // Repeat interval in ms
var DEFAULT_REPEAT_INTERVAL = 100; // Repeat rate increased after number of repeats
var DEFAULT_REPEAT_THRESHOLD = 10; // Repeat speed multiplier (step multiplier, must be an integer)
var DEFAULT_REPEAT_MULTIPLIER = 4;
var KEY_CODES = [CODE_UP, CODE_DOWN, CODE_HOME, CODE_END, CODE_PAGEUP, CODE_PAGEDOWN]; // --- Props ---
var props$L = makePropsConfigurable(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, omit(props$A, ['required', 'autofocus'])), props$D), props$E), {}, {
value: {
// Should this really be String, to match native number inputs?
type: Number,
default: null
},
min: {
type: [Number, String],
default: DEFAULT_MIN
},
max: {
type: [Number, String],
default: DEFAULT_MAX
},
step: {
type: [Number, String],
default: DEFAULT_STEP
},
wrap: {
type: Boolean,
default: false
},
formatterFn: {
type: Function // default: null
},
placeholder: {
type: String // default: null
},
readonly: {
type: Boolean,
default: false
},
inline: {
type: Boolean,
default: false
},
vertical: {
type: Boolean,
default: false
},
ariaLabel: {
type: String // default: null
},
ariaControls: {
type: String // default: null
},
labelDecrement: {
type: String,
default: 'Decrement'
},
labelIncrement: {
type: String,
default: 'Increment'
},
locale: {
type: [String, Array] // default: null
},
repeatDelay: {
type: [Number, String],
default: DEFAULT_REPEAT_DELAY
},
repeatInterval: {
type: [Number, String],
default: DEFAULT_REPEAT_INTERVAL
},
repeatThreshold: {
type: [Number, String],
default: DEFAULT_REPEAT_THRESHOLD
},
repeatStepMultiplier: {
type: [Number, String],
default: DEFAULT_REPEAT_MULTIPLIER
}
}), NAME_FORM_SPINBUTTON); // --- BFormSpinbutton ---
// @vue/component
var BFormSpinbutton = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_FORM_SPINBUTTON,
// Mixin order is important!
mixins: [attrsMixin, idMixin, formSizeMixin, formStateMixin, normalizeSlotMixin],
inheritAttrs: false,
props: props$L,
data: function data() {
return {
localValue: toFloat(this.value, null),
hasFocus: false
};
},
computed: {
spinId: function spinId() {
return this.safeId();
},
computedInline: function computedInline() {
return this.inline && !this.vertical;
},
computedReadonly: function computedReadonly() {
return this.readonly && !this.disabled;
},
computedRequired: function computedRequired() {
return this.required && !this.computedReadonly && !this.disabled;
},
computedStep: function computedStep() {
return toFloat(this.step, DEFAULT_STEP);
},
computedMin: function computedMin() {
return toFloat(this.min, DEFAULT_MIN);
},
computedMax: function computedMax() {
// We round down to the nearest maximum step value
var max = toFloat(this.max, DEFAULT_MAX);
var step = this.computedStep;
var min = this.computedMin;
return mathFloor((max - min) / step) * step + min;
},
computedDelay: function computedDelay() {
var delay = toInteger(this.repeatDelay, 0);
return delay > 0 ? delay : DEFAULT_REPEAT_DELAY;
},
computedInterval: function computedInterval() {
var interval = toInteger(this.repeatInterval, 0);
return interval > 0 ? interval : DEFAULT_REPEAT_INTERVAL;
},
computedThreshold: function computedThreshold() {
return mathMax(toInteger(this.repeatThreshold, DEFAULT_REPEAT_THRESHOLD), 1);
},
computedStepMultiplier: function computedStepMultiplier() {
return mathMax(toInteger(this.repeatStepMultiplier, DEFAULT_REPEAT_MULTIPLIER), 1);
},
computedPrecision: function computedPrecision() {
// Quick and dirty way to get the number of decimals
var step = this.computedStep;
return mathFloor(step) === step ? 0 : (step.toString().split('.')[1] || '').length;
},
computedMultiplier: function computedMultiplier() {
return mathPow(10, this.computedPrecision || 0);
},
valueAsFixed: function valueAsFixed() {
var value = this.localValue;
return isNull(value) ? '' : value.toFixed(this.computedPrecision);
},
computedLocale: function computedLocale() {
var locales = concat(this.locale).filter(identity);
var nf = new Intl.NumberFormat(locales);
return nf.resolvedOptions().locale;
},
computedRTL: function computedRTL() {
return isLocaleRTL(this.computedLocale);
},
defaultFormatter: function defaultFormatter() {
// Returns and `Intl.NumberFormat` formatter method reference
var precision = this.computedPrecision;
var nf = new Intl.NumberFormat(this.computedLocale, {
style: 'decimal',
useGrouping: false,
minimumIntegerDigits: 1,
minimumFractionDigits: precision,
maximumFractionDigits: precision,
notation: 'standard'
}); // Return the format method reference
return nf.format;
},
computedFormatter: function computedFormatter() {
var formatterFn = this.formatterFn;
var result = null;
try {
result = formatterFn();
} catch (_unused) {}
return isUndefined(result) ? this.defaultFormatter : formatterFn;
},
computedAttrs: function computedAttrs() {
return _objectSpread2(_objectSpread2({}, this.bvAttrs), {}, {
role: 'group',
lang: this.computedLocale,
tabindex: this.disabled ? null : '-1',
title: this.ariaLabel
});
},
computedSpinAttrs: function computedSpinAttrs() {
var spinId = this.spinId,
value = this.localValue,
required = this.computedRequired,
disabled = this.disabled,
state = this.state,
computedFormatter = this.computedFormatter;
var hasValue = !isNull(value);
return _objectSpread2(_objectSpread2({
dir: this.computedRTL ? 'rtl' : 'ltr'
}, this.bvAttrs), {}, {
id: spinId,
role: 'spinbutton',
tabindex: disabled ? null : '0',
'aria-live': 'off',
'aria-label': this.ariaLabel || null,
'aria-controls': this.ariaControls || null,
// TODO: May want to check if the value is in range
'aria-invalid': state === false || !hasValue && required ? 'true' : null,
'aria-required': required ? 'true' : null,
// These attrs are required for role spinbutton
'aria-valuemin': toString$1(this.computedMin),
'aria-valuemax': toString$1(this.computedMax),
// These should be `null` if the value is out of range
// They must also be non-existent attrs if the value is out of range or `null`
'aria-valuenow': hasValue ? value : null,
'aria-valuetext': hasValue ? computedFormatter(value) : null
});
}
},
watch: {
value: function value(_value) {
this.localValue = toFloat(_value, null);
},
localValue: function localValue(value) {
this.$emit('input', value);
},
disabled: function disabled(_disabled) {
if (_disabled) {
this.clearRepeat();
}
},
readonly: function readonly(_readonly) {
if (_readonly) {
this.clearRepeat();
}
}
},
created: function created() {
// Create non reactive properties
this.$_autoDelayTimer = null;
this.$_autoRepeatTimer = null;
this.$_keyIsDown = false;
},
beforeDestroy: function beforeDestroy() {
this.clearRepeat();
},
/* istanbul ignore next */
deactivated: function deactivated() {
this.clearRepeat();
},
methods: {
// --- Public methods ---
focus: function focus() {
if (!this.disabled) {
attemptFocus(this.$refs.spinner);
}
},
blur: function blur() {
if (!this.disabled) {
attemptBlur(this.$refs.spinner);
}
},
// --- Private methods ---
emitChange: function emitChange() {
this.$emit('change', this.localValue);
},
stepValue: function stepValue(direction) {
// Sets a new incremented or decremented value, supporting optional wrapping
// Direction is either +1 or -1 (or a multiple thereof)
var value = this.localValue;
if (!this.disabled && !isNull(value)) {
var step = this.computedStep * direction;
var min = this.computedMin;
var max = this.computedMax;
var multiplier = this.computedMultiplier;
var wrap = this.wrap; // We ensure that the value steps like a native input
value = mathRound((value - min) / step) * step + min + step; // We ensure that precision is maintained (decimals)
value = mathRound(value * multiplier) / multiplier; // Handle if wrapping is enabled
this.localValue = value > max ? wrap ? min : max : value < min ? wrap ? max : min : value;
}
},
onFocusBlur: function onFocusBlur(evt) {
if (!this.disabled) {
this.hasFocus = evt.type === 'focus';
} else {
this.hasFocus = false;
}
},
stepUp: function stepUp() {
var multiplier = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
var value = this.localValue;
if (isNull(value)) {
this.localValue = this.computedMin;
} else {
this.stepValue(+1 * multiplier);
}
},
stepDown: function stepDown() {
var multiplier = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
var value = this.localValue;
if (isNull(value)) {
this.localValue = this.wrap ? this.computedMax : this.computedMin;
} else {
this.stepValue(-1 * multiplier);
}
},
onKeydown: function onKeydown(evt) {
var keyCode = evt.keyCode,
altKey = evt.altKey,
ctrlKey = evt.ctrlKey,
metaKey = evt.metaKey;
/* istanbul ignore if */
if (this.disabled || this.readonly || altKey || ctrlKey || metaKey) {
return;
}
if (arrayIncludes(KEY_CODES, keyCode)) {
// https://w3c.github.io/aria-practices/#spinbutton
stopEvent(evt, {
propagation: false
});
/* istanbul ignore if */
if (this.$_keyIsDown) {
// Keypress is already in progress
return;
}
this.resetTimers();
if (arrayIncludes([CODE_UP, CODE_DOWN], keyCode)) {
// The following use the custom auto-repeat handling
this.$_keyIsDown = true;
if (keyCode === CODE_UP) {
this.handleStepRepeat(evt, this.stepUp);
} else if (keyCode === CODE_DOWN) {
this.handleStepRepeat(evt, this.stepDown);
}
} else {
// These use native OS key repeating
if (keyCode === CODE_PAGEUP) {
this.stepUp(this.computedStepMultiplier);
} else if (keyCode === CODE_PAGEDOWN) {
this.stepDown(this.computedStepMultiplier);
} else if (keyCode === CODE_HOME) {
this.localValue = this.computedMin;
} else if (keyCode === CODE_END) {
this.localValue = this.computedMax;
}
}
}
},
onKeyup: function onKeyup(evt) {
// Emit a change event when the keyup happens
var keyCode = evt.keyCode,
altKey = evt.altKey,
ctrlKey = evt.ctrlKey,
metaKey = evt.metaKey;
/* istanbul ignore if */
if (this.disabled || this.readonly || altKey || ctrlKey || metaKey) {
return;
}
if (arrayIncludes(KEY_CODES, keyCode)) {
stopEvent(evt, {
propagation: false
});
this.resetTimers();
this.$_keyIsDown = false;
this.emitChange();
}
},
handleStepRepeat: function handleStepRepeat(evt, stepper) {
var _this = this;
var _ref = evt || {},
type = _ref.type,
button = _ref.button;
if (!this.disabled && !this.readonly) {
/* istanbul ignore if */
if (type === 'mousedown' && button) {
// We only respond to left (main === 0) button clicks
return;
}
this.resetTimers(); // Step the counter initially
stepper(1);
var threshold = this.computedThreshold;
var multiplier = this.computedStepMultiplier;
var delay = this.computedDelay;
var interval = this.computedInterval; // Initiate the delay/repeat interval
this.$_autoDelayTimer = setTimeout(function () {
var count = 0;
_this.$_autoRepeatTimer = setInterval(function () {
// After N initial repeats, we increase the incrementing step amount
// We do this to minimize screen reader announcements of the value
// (values are announced every change, which can be chatty for SR users)
// And to make it easer to select a value when the range is large
stepper(count < threshold ? 1 : multiplier);
count++;
}, interval);
}, delay);
}
},
onMouseup: function onMouseup(evt) {
// `<body>` listener, only enabled when mousedown starts
var _ref2 = evt || {},
type = _ref2.type,
button = _ref2.button;
/* istanbul ignore if */
if (type === 'mouseup' && button) {
// Ignore non left button (main === 0) mouse button click
return;
}
stopEvent(evt, {
propagation: false
});
this.resetTimers();
this.setMouseup(false); // Trigger the change event
this.emitChange();
},
setMouseup: function setMouseup(on) {
// Enable or disabled the body mouseup/touchend handlers
// Use try/catch to handle case when called server side
try {
eventOnOff(on, document.body, 'mouseup', this.onMouseup, false);
eventOnOff(on, document.body, 'touchend', this.onMouseup, false);
} catch (_unused2) {}
},
resetTimers: function resetTimers() {
clearTimeout(this.$_autoDelayTimer);
clearInterval(this.$_autoRepeatTimer);
this.$_autoDelayTimer = null;
this.$_autoRepeatTimer = null;
},
clearRepeat: function clearRepeat() {
this.resetTimers();
this.setMouseup(false);
this.$_keyIsDown = false;
}
},
render: function render(h) {
var _this2 = this;
var spinId = this.spinId,
value = this.localValue,
inline = this.computedInline,
readonly = this.computedReadonly,
vertical = this.vertical,
disabled = this.disabled,
computedFormatter = this.computedFormatter;
var hasValue = !isNull(value);
var makeButton = function makeButton(stepper, label, IconCmp, keyRef, shortcut, btnDisabled, slotName) {
var $icon = h(IconCmp, {
props: {
scale: _this2.hasFocus ? 1.5 : 1.25
},
attrs: {
'aria-hidden': 'true'
}
});
var scope = {
hasFocus: _this2.hasFocus
};
var handler = function handler(evt) {
if (!disabled && !readonly) {
stopEvent(evt, {
propagation: false
});
_this2.setMouseup(true); // Since we `preventDefault()`, we must manually focus the button
attemptFocus(evt.currentTarget);
_this2.handleStepRepeat(evt, stepper);
}
};
return h('button', {
key: keyRef || null,
ref: keyRef,
staticClass: 'btn btn-sm border-0 rounded-0',
class: {
'py-0': !vertical
},
attrs: {
tabindex: '-1',
type: 'button',
disabled: disabled || readonly || btnDisabled,
'aria-disabled': disabled || readonly || btnDisabled ? 'true' : null,
'aria-controls': spinId,
'aria-label': label || null,
'aria-keyshortcuts': shortcut || null
},
on: {
mousedown: handler,
touchstart: handler
}
}, [h('div', [_this2.normalizeSlot(slotName, scope) || $icon])]);
}; // TODO: Add button disabled state when `wrap` is `false` and at value max/min
var $increment = makeButton(this.stepUp, this.labelIncrement, BIconPlus, 'inc', 'ArrowUp', false, 'increment');
var $decrement = makeButton(this.stepDown, this.labelDecrement, BIconDash, 'dec', 'ArrowDown', false, 'decrement');
var $hidden = h();
if (this.name && !disabled) {
$hidden = h('input', {
key: 'hidden',
attrs: {
type: 'hidden',
name: this.name,
form: this.form || null,
// TODO: Should this be set to '' if value is out of range?
value: this.valueAsFixed
}
});
}
var $spin = h( // We use 'output' element to make this accept a `<label for="id">` (Except IE)
'output', {
ref: 'spinner',
key: 'output',
staticClass: 'flex-grow-1',
class: {
'd-flex': vertical,
'align-self-center': !vertical,
'align-items-center': vertical,
'border-top': vertical,
'border-bottom': vertical,
'border-left': !vertical,
'border-right': !vertical
},
attrs: this.computedSpinAttrs
}, [h('bdi', hasValue ? computedFormatter(value) : this.placeholder || '')]);
return h('div', {
staticClass: 'b-form-spinbutton form-control',
class: [{
disabled: disabled,
readonly: readonly,
focus: this.hasFocus,
'd-inline-flex': inline || vertical,
'd-flex': !inline && !vertical,
'align-items-stretch': !vertical,
'flex-column': vertical
}, this.sizeFormClass, this.stateClass],
attrs: this.computedAttrs,
on: {
keydown: this.onKeydown,
keyup: this.onKeyup,
// We use capture phase (`!` prefix) since focus and blur do not bubble
'!focus': this.onFocusBlur,
'!blur': this.onFocusBlur
}
}, vertical ? [$increment, $hidden, $spin, $decrement] : [$decrement, $hidden, $spin, $increment]);
}
});
var FormSpinbuttonPlugin = /*#__PURE__*/pluginFactory({
components: {
BFormSpinbutton: BFormSpinbutton,
BSpinbutton: BFormSpinbutton
}
});
var BFormTag = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_FORM_TAG,
mixins: [idMixin, normalizeSlotMixin],
props: makePropsConfigurable({
variant: {
type: String,
default: 'secondary'
},
disabled: {
type: Boolean,
default: false
},
title: {
type: String // default: null
},
pill: {
type: Boolean,
default: false
},
removeLabel: {
type: String,
default: 'Remove tag'
},
tag: {
type: String,
default: 'span'
}
}, NAME_FORM_TAG),
methods: {
onDelete: function onDelete(evt) {
var type = evt.type,
keyCode = evt.keyCode;
if (!this.disabled && (type === 'click' || type === 'keydown' && keyCode === CODE_DELETE)) {
this.$emit('remove');
}
}
},
render: function render(h) {
var tagId = this.safeId();
var tagLabelId = this.safeId('_taglabel_');
var $remove = h();
if (!this.disabled) {
$remove = h(BButtonClose, {
staticClass: 'b-form-tag-remove',
props: {
ariaLabel: this.removeLabel
},
attrs: {
'aria-controls': tagId,
'aria-describedby': tagLabelId,
'aria-keyshortcuts': 'Delete'
},
on: {
click: this.onDelete,
keydown: this.onDelete
}
});
}
var $tag = h('span', {
staticClass: 'b-form-tag-content flex-grow-1 text-truncate',
attrs: {
id: tagLabelId
}
}, this.normalizeSlot() || this.title || [h()]);
return h(BBadge, {
staticClass: 'b-form-tag d-inline-flex align-items-baseline mw-100',
class: {
disabled: this.disabled
},
attrs: {
id: tagId,
title: this.title || null,
'aria-labelledby': tagLabelId
},
props: {
tag: this.tag,
variant: this.variant,
pill: this.pill
}
}, [$tag, $remove]);
}
});
// Supported input types (for built in input)
var TYPES$2 = ['text', 'email', 'tel', 'url', 'number']; // --- Utility methods ---
// Escape special chars in string and replace
// contiguous spaces with a whitespace match
var escapeRegExpChars = function escapeRegExpChars(str) {
return escapeRegExp(str).replace(RX_SPACES, '\\s');
}; // Remove leading/trailing spaces from array of tags and remove duplicates
var cleanTags = function cleanTags(tags) {
return concat(tags).map(function (tag) {
return trim(toString$1(tag));
}).filter(function (tag, index, arr) {
return tag.length > 0 && arr.indexOf(tag) === index;
});
}; // Processes an input/change event, normalizing string or event argument
var processEventValue = function processEventValue(evt) {
return isString(evt) ? evt : isEvent(evt) ? evt.target.value || '' : '';
}; // Returns a fresh empty `tagsState` object
var cleanTagsState = function cleanTagsState() {
return {
all: [],
valid: [],
invalid: [],
duplicate: []
};
}; // --- Main component ---
// @vue/component
var BFormTags = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_FORM_TAGS,
mixins: [idMixin, formControlMixin, formSizeMixin, formStateMixin, normalizeSlotMixin],
model: {
// Even though this is the default that Vue assumes, we need
// to add it for the docs to reflect that this is the model
prop: 'value',
event: 'input'
},
props: makePropsConfigurable(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, props$A), props$D), props$E), {}, {
value: {
// The v-model prop
type: Array,
default: function _default() {
return [];
}
},
placeholder: {
type: String,
default: 'Add tag...'
},
inputId: {
type: String // default: null
},
inputType: {
type: String,
default: 'text',
validator: function validator(value) {
return arrayIncludes(TYPES$2, value);
}
},
inputClass: {
type: [String, Array, Object] // default: null
},
inputAttrs: {
// Additional attributes to add to the input element
type: Object,
default: function _default() {
return {};
}
},
addButtonText: {
type: String,
default: 'Add'
},
addButtonVariant: {
type: String,
default: 'outline-secondary'
},
tagVariant: {
type: String,
default: 'secondary'
},
tagClass: {
type: [String, Array, Object] // default: null
},
tagPills: {
type: Boolean,
default: false
},
tagRemoveLabel: {
type: String,
default: 'Remove tag'
},
tagRemovedLabel: {
type: String,
default: 'Tag removed'
},
tagValidator: {
type: Function // default: null
},
duplicateTagText: {
type: String,
default: 'Duplicate tag(s)'
},
invalidTagText: {
type: String,
default: 'Invalid tag(s)'
},
limitTagsText: {
type: String,
default: 'Tag limit reached'
},
limit: {
type: Number // default: null
},
separator: {
// Character (or characters) that trigger adding tags
type: [String, Array] // default: null
},
removeOnDelete: {
// Enable deleting last tag in list when CODE_BACKSPACE is
// pressed and input is empty
type: Boolean,
default: false
},
addOnChange: {
// Enable change event triggering tag addition
// Handy if using <select> as the input
type: Boolean,
default: false
},
noAddOnEnter: {
// Disable ENTER key from triggering tag addition
type: Boolean,
default: false
},
noOuterFocus: {
// Disable the focus ring on the root element
type: Boolean,
default: false
},
ignoreInputFocusSelector: {
// Disable the input focus behavior when clicking
// on element matching the selector (or selectors)
type: [Array, String],
default: function _default() {
return ['.b-form-tag', 'button', 'input', 'select'];
}
}
}), NAME_FORM_TAGS),
data: function data() {
return {
hasFocus: false,
newTag: '',
tags: [],
// Tags that were removed
removedTags: [],
// Populated when tags are parsed
tagsState: cleanTagsState()
};
},
computed: {
computedInputId: function computedInputId() {
return this.inputId || this.safeId('__input__');
},
computedInputType: function computedInputType() {
// We only allow certain types
return arrayIncludes(TYPES$2, this.inputType) ? this.inputType : 'text';
},
computedInputAttrs: function computedInputAttrs() {
return _objectSpread2(_objectSpread2({}, this.inputAttrs), {}, {
// Must have attributes
id: this.computedInputId,
value: this.newTag,
disabled: this.disabled || null,
form: this.form || null
});
},
computedInputHandlers: function computedInputHandlers() {
return {
input: this.onInputInput,
change: this.onInputChange,
keydown: this.onInputKeydown
};
},
computedSeparator: function computedSeparator() {
// Merge the array into a string
return concat(this.separator).filter(isString).filter(identity).join('');
},
computedSeparatorRegExp: function computedSeparatorRegExp() {
// We use a computed prop here to precompile the RegExp
// The RegExp is a character class RE in the form of `/[abc]+/`
// where a, b, and c are the valid separator characters
// -> `tags = str.split(/[abc]+/).filter(t => t)`
var separator = this.computedSeparator;
return separator ? new RegExp("[".concat(escapeRegExpChars(separator), "]+")) : null;
},
computedJoiner: function computedJoiner() {
// When tag(s) are invalid or duplicate, we leave them
// in the input so that the user can see them
// If there are more than one tag in the input, we use the
// first separator character as the separator in the input
// We append a space if the first separator is not a space
var joiner = this.computedSeparator.charAt(0);
return joiner !== ' ' ? "".concat(joiner, " ") : joiner;
},
computeIgnoreInputFocusSelector: function computeIgnoreInputFocusSelector() {
// Normalize to an single selector with selectors separated by `,`
return concat(this.ignoreInputFocusSelector).filter(identity).join(',').trim();
},
disableAddButton: function disableAddButton() {
var _this = this;
// If 'Add' button should be disabled
// If the input contains at least one tag that can
// be added, then the 'Add' button should be enabled
var newTag = trim(this.newTag);
return newTag === '' || !this.splitTags(newTag).some(function (t) {
return !arrayIncludes(_this.tags, t) && _this.validateTag(t);
});
},
duplicateTags: function duplicateTags() {
return this.tagsState.duplicate;
},
hasDuplicateTags: function hasDuplicateTags() {
return this.duplicateTags.length > 0;
},
invalidTags: function invalidTags() {
return this.tagsState.invalid;
},
hasInvalidTags: function hasInvalidTags() {
return this.invalidTags.length > 0;
},
isLimitReached: function isLimitReached() {
var limit = this.limit;
return isNumber(limit) && limit >= 0 && this.tags.length >= limit;
}
},
watch: {
value: function value(newVal) {
this.tags = cleanTags(newVal);
},
tags: function tags(newVal, oldVal) {
// Update the `v-model` (if it differs from the value prop)
if (!looseEqual(newVal, this.value)) {
this.$emit('input', newVal);
}
if (!looseEqual(newVal, oldVal)) {
newVal = concat(newVal).filter(identity);
oldVal = concat(oldVal).filter(identity);
this.removedTags = oldVal.filter(function (old) {
return !arrayIncludes(newVal, old);
});
}
},
tagsState: function tagsState(newVal, oldVal) {
// Emit a tag-state event when the `tagsState` object changes
if (!looseEqual(newVal, oldVal)) {
this.$emit('tag-state', newVal.valid, newVal.invalid, newVal.duplicate);
}
}
},
created: function created() {
// We do this in created to make sure an input event emits
// if the cleaned tags are not equal to the value prop
this.tags = cleanTags(this.value);
},
methods: {
addTag: function addTag(newTag) {
newTag = isString(newTag) ? newTag : this.newTag;
/* istanbul ignore next */
if (this.disabled || trim(newTag) === '' || this.isLimitReached) {
// Early exit
return;
}
var parsed = this.parseTags(newTag); // Add any new tags to the `tags` array, or if the
// array of `allTags` is empty, we clear the input
if (parsed.valid.length > 0 || parsed.all.length === 0) {
// Clear the user input element (and leave in any invalid/duplicate tag(s)
/* istanbul ignore if: full testing to be added later */
if (matches(this.getInput(), 'select')) {
// The following is needed to properly
// work with `<select>` elements
this.newTag = '';
} else {
var invalidAndDuplicates = [].concat(_toConsumableArray(parsed.invalid), _toConsumableArray(parsed.duplicate));
this.newTag = parsed.all.filter(function (tag) {
return arrayIncludes(invalidAndDuplicates, tag);
}).join(this.computedJoiner).concat(invalidAndDuplicates.length > 0 ? this.computedJoiner.charAt(0) : '');
}
}
if (parsed.valid.length > 0) {
// We add the new tags in one atomic operation
// to trigger reactivity once (instead of once per tag)
// We do this after we update the new tag input value
// `concat()` can be faster than array spread, when both args are arrays
this.tags = concat(this.tags, parsed.valid);
}
this.tagsState = parsed; // Attempt to re-focus the input (specifically for when using the Add
// button, as the button disappears after successfully adding a tag
this.focus();
},
removeTag: function removeTag(tag) {
var _this2 = this;
/* istanbul ignore next */
if (this.disabled) {
return;
} // TODO:
// Add `onRemoveTag(tag)` user method, which if returns `false`
// will prevent the tag from being removed (i.e. confirmation)
// Or emit cancelable `BvEvent`
this.tags = this.tags.filter(function (t) {
return t !== tag;
}); // Return focus to the input (if possible)
this.$nextTick(function () {
_this2.focus();
});
},
// --- Input element event handlers ---
onInputInput: function onInputInput(evt) {
/* istanbul ignore next: hard to test composition events */
if (this.disabled || isEvent(evt) && evt.target.composing) {
// `evt.target.composing` is set by Vue (`v-model` directive)
// https://github.com/vuejs/vue/blob/dev/src/platforms/web/runtime/directives/model.js
return;
}
var newTag = processEventValue(evt);
var separatorRe = this.computedSeparatorRegExp;
if (this.newTag !== newTag) {
this.newTag = newTag;
} // We ignore leading whitespace for the following
newTag = trimLeft(newTag);
if (separatorRe && separatorRe.test(newTag.slice(-1))) {
// A trailing separator character was entered, so add the tag(s)
// Note: More than one tag on input event is possible via copy/paste
this.addTag();
} else {
// Validate (parse tags) on input event
this.tagsState = newTag === '' ? cleanTagsState() : this.parseTags(newTag);
}
},
onInputChange: function onInputChange(evt) {
// Change is triggered on `<input>` blur, or `<select>` selected
// This event is opt-in
if (!this.disabled && this.addOnChange) {
var newTag = processEventValue(evt);
/* istanbul ignore next */
if (this.newTag !== newTag) {
this.newTag = newTag;
}
this.addTag();
}
},
onInputKeydown: function onInputKeydown(evt) {
// Early exit
/* istanbul ignore next */
if (this.disabled || !isEvent(evt)) {
return;
}
var keyCode = evt.keyCode;
var value = evt.target.value || '';
/* istanbul ignore else: testing to be added later */
if (!this.noAddOnEnter && keyCode === CODE_ENTER) {
// Attempt to add the tag when user presses enter
stopEvent(evt, {
propagation: false
});
this.addTag();
} else if (this.removeOnDelete && (keyCode === CODE_BACKSPACE || keyCode === CODE_DELETE) && value === '') {
// Remove the last tag if the user pressed backspace/delete and the input is empty
stopEvent(evt, {
propagation: false
});
this.tags = this.tags.slice(0, -1);
}
},
// --- Wrapper event handlers ---
onClick: function onClick(evt) {
var _this3 = this;
var ignoreFocusSelector = this.computeIgnoreInputFocusSelector;
var target = evt.target;
if (!this.disabled && !isActiveElement(target) && (!ignoreFocusSelector || !closest(ignoreFocusSelector, target, true))) {
this.$nextTick(function () {
_this3.focus();
});
}
},
onFocusin: function onFocusin() {
this.hasFocus = true;
},
onFocusout: function onFocusout() {
this.hasFocus = false;
},
handleAutofocus: function handleAutofocus() {
var _this4 = this;
this.$nextTick(function () {
requestAF(function () {
if (_this4.autofocus && !_this4.disabled) {
_this4.focus();
}
});
});
},
// --- Public methods ---
focus: function focus() {
if (!this.disabled) {
attemptFocus(this.getInput());
}
},
blur: function blur() {
if (!this.disabled) {
attemptBlur(this.getInput());
}
},
// --- Private methods ---
splitTags: function splitTags(newTag) {
// Split the input into an array of raw tags
newTag = toString$1(newTag);
var separatorRe = this.computedSeparatorRegExp; // Split the tag(s) via the optional separator
// Normally only a single tag is provided, but copy/paste
// can enter multiple tags in a single operation
return (separatorRe ? newTag.split(separatorRe) : [newTag]).map(trim).filter(identity);
},
parseTags: function parseTags(newTag) {
var _this5 = this;
// Takes `newTag` value and parses it into `validTags`,
// `invalidTags`, and duplicate tags as an object
// Split the input into raw tags
var tags = this.splitTags(newTag); // Base results
var parsed = {
all: tags,
valid: [],
invalid: [],
duplicate: []
}; // Parse the unique tags
tags.forEach(function (tag) {
if (arrayIncludes(_this5.tags, tag) || arrayIncludes(parsed.valid, tag)) {
// Unique duplicate tags
if (!arrayIncludes(parsed.duplicate, tag)) {
parsed.duplicate.push(tag);
}
} else if (_this5.validateTag(tag)) {
// We only add unique/valid tags
parsed.valid.push(tag);
} else {
// Unique invalid tags
if (!arrayIncludes(parsed.invalid, tag)) {
parsed.invalid.push(tag);
}
}
});
return parsed;
},
validateTag: function validateTag(tag) {
var tagValidator = this.tagValidator;
var result = null;
try {
result = tagValidator();
} catch (_unused) {}
return isUndefined(result) ? true : tagValidator(tag);
},
getInput: function getInput() {
// Returns the input element reference (or null if not found)
// We need to escape `computedInputId` since it can be user-provided
return select("#".concat(cssEscape(this.computedInputId)), this.$el);
},
// Default User Interface render
defaultRender: function defaultRender(_ref) {
var tags = _ref.tags,
inputAttrs = _ref.inputAttrs,
inputType = _ref.inputType,
inputHandlers = _ref.inputHandlers,
removeTag = _ref.removeTag,
addTag = _ref.addTag,
isInvalid = _ref.isInvalid,
isDuplicate = _ref.isDuplicate,
isLimitReached = _ref.isLimitReached,
disableAddButton = _ref.disableAddButton,
disabled = _ref.disabled,
placeholder = _ref.placeholder,
inputClass = _ref.inputClass,
tagRemoveLabel = _ref.tagRemoveLabel,
tagVariant = _ref.tagVariant,
tagPills = _ref.tagPills,
tagClass = _ref.tagClass,
addButtonText = _ref.addButtonText,
addButtonVariant = _ref.addButtonVariant,
invalidTagText = _ref.invalidTagText,
duplicateTagText = _ref.duplicateTagText,
limitTagsText = _ref.limitTagsText;
var h = this.$createElement; // Make the list of tags
var $tags = tags.map(function (tag) {
tag = toString$1(tag);
return h(BFormTag, {
class: tagClass,
props: {
// `BFormTag` will auto generate an ID
// so we do not need to set the ID prop
tag: 'li',
title: tag,
disabled: disabled,
variant: tagVariant,
pill: tagPills,
removeLabel: tagRemoveLabel
},
on: {
remove: function remove() {
return removeTag(tag);
}
},
key: "tags_".concat(tag)
}, tag);
}); // Feedback IDs if needed
var invalidFeedbackId = invalidTagText && isInvalid ? this.safeId('__invalid_feedback__') : null;
var duplicateFeedbackId = duplicateTagText && isDuplicate ? this.safeId('__duplicate_feedback__') : null;
var limitFeedbackId = limitTagsText && isLimitReached ? this.safeId('__limit_feedback__') : null; // Compute the `aria-describedby` attribute value
var ariaDescribedby = [inputAttrs['aria-describedby'], invalidFeedbackId, duplicateFeedbackId, limitFeedbackId].filter(identity).join(' '); // Input
var $input = h('input', {
ref: 'input',
// Directive needed to get `evt.target.composing` set (if needed)
directives: [{
name: 'model',
value: inputAttrs.value
}],
staticClass: 'b-form-tags-input w-100 flex-grow-1 p-0 m-0 bg-transparent border-0',
class: inputClass,
style: {
outline: 0,
minWidth: '5rem'
},
attrs: _objectSpread2(_objectSpread2({}, inputAttrs), {}, {
'aria-describedby': ariaDescribedby || null,
type: inputType,
placeholder: placeholder || null
}),
domProps: {
value: inputAttrs.value
},
on: inputHandlers
}); // Add button
var $button = h(BButton, {
ref: 'button',
staticClass: 'b-form-tags-button py-0',
class: {
// Only show the button if the tag can be added
// We use the `invisible` class instead of not rendering
// the button, so that we maintain layout to prevent
// the user input from jumping around
invisible: disableAddButton
},
style: {
fontSize: '90%'
},
props: {
variant: addButtonVariant,
disabled: disableAddButton || isLimitReached
},
on: {
click: function click() {
return addTag();
}
}
}, [this.normalizeSlot('add-button-text') || addButtonText]); // ID of the tags + input `<ul>` list
// Note we could concatenate `inputAttrs.id` with '__tag_list__'
// but `inputId` may be `null` until after mount
// `safeId()` returns `null`, if no user provided ID,
// until after mount when a unique ID is generated
var tagListId = this.safeId('__tag_list__');
var $field = h('li', {
staticClass: 'b-from-tags-field flex-grow-1',
attrs: {
role: 'none',
'aria-live': 'off',
'aria-controls': tagListId
},
key: 'tags_field'
}, [h('div', {
staticClass: 'd-flex',
attrs: {
role: 'group'
}
}, [$input, $button])]); // Wrap in an unordered list element (we use a list for accessibility)
var $ul = h('ul', {
staticClass: 'b-form-tags-list list-unstyled mb-0 d-flex flex-wrap align-items-center',
attrs: {
id: tagListId
},
key: 'tags_list'
}, [$tags, $field]); // Assemble the feedback
var $feedback = h();
if (invalidTagText || duplicateTagText || limitTagsText) {
// Add an aria live region for the invalid/duplicate tag
// messages if the user has not disabled the messages
var joiner = this.computedJoiner; // Invalid tag feedback if needed (error)
var $invalid = h();
if (invalidFeedbackId) {
$invalid = h(BFormInvalidFeedback, {
props: {
id: invalidFeedbackId,
forceShow: true
},
key: 'tags_invalid_feedback'
}, [this.invalidTagText, ': ', this.invalidTags.join(joiner)]);
} // Duplicate tag feedback if needed (warning, not error)
var $duplicate = h();
if (duplicateFeedbackId) {
$duplicate = h(BFormText, {
props: {
id: duplicateFeedbackId
},
key: 'tags_duplicate_feedback'
}, [this.duplicateTagText, ': ', this.duplicateTags.join(joiner)]);
} // Limit tags feedback if needed (warning, not error)
var $limit = h();
if (limitFeedbackId) {
$limit = h(BFormText, {
props: {
id: limitFeedbackId
},
key: 'tags_limit_feedback'
}, [limitTagsText]);
}
$feedback = h('div', {
attrs: {
'aria-live': 'polite',
'aria-atomic': 'true'
},
key: 'tags_feedback'
}, [$invalid, $duplicate, $limit]);
} // Return the content
return [$ul, $feedback];
}
},
render: function render(h) {
var _this6 = this;
var name = this.name,
disabled = this.disabled,
tags = this.tags,
computedInputId = this.computedInputId,
hasFocus = this.hasFocus,
noOuterFocus = this.noOuterFocus; // Scoped slot properties
var scope = _objectSpread2({
// Array of tags (shallow copy to prevent mutations)
tags: tags.slice(),
// <input> v-bind:inputAttrs
inputAttrs: this.computedInputAttrs,
// We don't include this in the attrs, as users may want to override this
inputType: this.computedInputType,
// <input> v-on:inputHandlers
inputHandlers: this.computedInputHandlers,
// Methods
removeTag: this.removeTag,
addTag: this.addTag,
// <input> :id="inputId"
inputId: computedInputId,
// Invalid/Duplicate state information
isInvalid: this.hasInvalidTags,
invalidTags: this.invalidTags.slice(),
isDuplicate: this.hasDuplicateTags,
duplicateTags: this.duplicateTags.slice(),
isLimitReached: this.isLimitReached,
// If the 'Add' button should be disabled
disableAddButton: this.disableAddButton
}, pick(this.$props, ['disabled', 'state', 'size', 'limit', 'separator', 'placeholder', 'inputClass', 'tagRemoveLabel', 'tagVariant', 'tagPills', 'tagClass', 'addButtonText', 'addButtonVariant', 'invalidTagText', 'duplicateTagText', 'limitTagsText'])); // Generate the user interface
var $content = this.normalizeSlot(SLOT_NAME_DEFAULT, scope) || this.defaultRender(scope); // Generate the `aria-live` region for the current value(s)
var $output = h('output', {
staticClass: 'sr-only',
attrs: {
id: this.safeId('__selected_tags__'),
role: 'status',
for: computedInputId,
'aria-live': hasFocus ? 'polite' : 'off',
'aria-atomic': 'true',
'aria-relevant': 'additions text'
}
}, this.tags.join(', ')); // Removed tag live region
var $removed = h('div', {
staticClass: 'sr-only',
attrs: {
id: this.safeId('__removed_tags__'),
role: 'status',
'aria-live': hasFocus ? 'assertive' : 'off',
'aria-atomic': 'true'
}
}, this.removedTags.length > 0 ? "(".concat(this.tagRemovedLabel, ") ").concat(this.removedTags.join(', ')) : ''); // Add hidden inputs for form submission
var $hidden = h();
if (name && !disabled) {
// We add hidden inputs for each tag if a name is provided
// for native submission of forms
$hidden = tags.map(function (tag) {
return h('input', {
attrs: {
type: 'hidden',
value: tag,
name: name,
form: _this6.form || null
},
key: "tag_input_".concat(tag)
});
});
} // Return the rendered output
return h('div', {
staticClass: 'b-form-tags form-control h-auto',
class: [{
focus: hasFocus && !noOuterFocus && !disabled,
disabled: disabled
}, this.sizeFormClass, this.stateClass],
attrs: {
id: this.safeId(),
role: 'group',
tabindex: disabled || noOuterFocus ? null : '-1',
'aria-describedby': this.safeId('__selected_tags__')
},
on: {
click: this.onClick,
focusin: this.onFocusin,
focusout: this.onFocusout
}
}, [$output, $removed, $content, $hidden]);
}
});
var FormTagsPlugin = /*#__PURE__*/pluginFactory({
components: {
BFormTags: BFormTags,
BTags: BFormTags,
BFormTag: BFormTag,
BTag: BFormTag
}
});
var BFormTextarea = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_FORM_TEXTAREA,
directives: {
'b-visible': VBVisible
},
// Mixin order is important!
mixins: [listenersMixin, idMixin, listenOnRootMixin, formControlMixin, formSizeMixin, formStateMixin, formTextMixin, formSelectionMixin, formValidityMixin],
props: makePropsConfigurable(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, props$A), props$D), props$E), props$I), {}, {
rows: {
type: [Number, String],
default: 2
},
maxRows: {
type: [Number, String] // default: null
},
wrap: {
// 'soft', 'hard' or 'off'. Browser default is 'soft'
type: String,
default: 'soft'
},
noResize: {
// Disable the resize handle of textarea
type: Boolean,
default: false
},
noAutoShrink: {
// When in auto resize mode, disable shrinking to content height
type: Boolean,
default: false
}
}), NAME_FORM_TEXTAREA),
data: function data() {
return {
heightInPx: null
};
},
computed: {
computedStyle: function computedStyle() {
var styles = {
// Setting `noResize` to true will disable the ability for the user to
// manually resize the textarea. We also disable when in auto height mode
resize: !this.computedRows || this.noResize ? 'none' : null
};
if (!this.computedRows) {
// Conditionally set the computed CSS height when auto rows/height is enabled
// We avoid setting the style to `null`, which can override user manual resize handle
styles.height = this.heightInPx; // We always add a vertical scrollbar to the textarea when auto-height is
// enabled so that the computed height calculation returns a stable value
styles.overflowY = 'scroll';
}
return styles;
},
computedMinRows: function computedMinRows() {
// Ensure rows is at least 2 and positive (2 is the native textarea value)
// A value of 1 can cause issues in some browsers, and most browsers
// only support 2 as the smallest value
return mathMax(toInteger(this.rows, 2), 2);
},
computedMaxRows: function computedMaxRows() {
return mathMax(this.computedMinRows, toInteger(this.maxRows, 0));
},
computedRows: function computedRows() {
// This is used to set the attribute 'rows' on the textarea
// If auto-height is enabled, then we return `null` as we use CSS to control height
return this.computedMinRows === this.computedMaxRows ? this.computedMinRows : null;
},
computedAttrs: function computedAttrs() {
var disabled = this.disabled,
required = this.required;
return {
id: this.safeId(),
name: this.name || null,
form: this.form || null,
disabled: disabled,
placeholder: this.placeholder || null,
required: required,
autocomplete: this.autocomplete || null,
readonly: this.readonly || this.plaintext,
rows: this.computedRows,
wrap: this.wrap || null,
'aria-required': this.required ? 'true' : null,
'aria-invalid': this.computedAriaInvalid
};
},
computedListeners: function computedListeners() {
return _objectSpread2(_objectSpread2({}, this.bvListeners), {}, {
input: this.onInput,
change: this.onChange,
blur: this.onBlur
});
}
},
watch: {
localValue: function localValue() {
this.setHeight();
}
},
mounted: function mounted() {
this.setHeight();
},
methods: {
// Called by intersection observer directive
/* istanbul ignore next */
visibleCallback: function visibleCallback(visible) {
if (visible) {
// We use a `$nextTick()` here just to make sure any
// transitions or portalling have completed
this.$nextTick(this.setHeight);
}
},
setHeight: function setHeight() {
var _this = this;
this.$nextTick(function () {
requestAF(function () {
_this.heightInPx = _this.computeHeight();
});
});
},
/* istanbul ignore next: can't test getComputedStyle in JSDOM */
computeHeight: function computeHeight() {
if (this.$isServer || !isNull(this.computedRows)) {
return null;
}
var el = this.$el; // Element must be visible (not hidden) and in document
// Must be checked after above checks
if (!isVisible(el)) {
return null;
} // Get current computed styles
var computedStyle = getCS(el); // Height of one line of text in px
var lineHeight = toFloat(computedStyle.lineHeight, 1); // Calculate height of border and padding
var border = toFloat(computedStyle.borderTopWidth, 0) + toFloat(computedStyle.borderBottomWidth, 0);
var padding = toFloat(computedStyle.paddingTop, 0) + toFloat(computedStyle.paddingBottom, 0); // Calculate offset
var offset = border + padding; // Minimum height for min rows (which must be 2 rows or greater for cross-browser support)
var minHeight = lineHeight * this.computedMinRows + offset; // Get the current style height (with `px` units)
var oldHeight = getStyle(el, 'height') || computedStyle.height; // Probe scrollHeight by temporarily changing the height to `auto`
setStyle(el, 'height', 'auto');
var scrollHeight = el.scrollHeight; // Place the original old height back on the element, just in case `computedProp`
// returns the same value as before
setStyle(el, 'height', oldHeight); // Calculate content height in 'rows' (scrollHeight includes padding but not border)
var contentRows = mathMax((scrollHeight - padding) / lineHeight, 2); // Calculate number of rows to display (limited within min/max rows)
var rows = mathMin(mathMax(contentRows, this.computedMinRows), this.computedMaxRows); // Calculate the required height of the textarea including border and padding (in pixels)
var height = mathMax(mathCeil(rows * lineHeight + offset), minHeight); // Computed height remains the larger of `oldHeight` and new `height`,
// when height is in `sticky` mode (prop `no-auto-shrink` is true)
if (this.noAutoShrink && toFloat(oldHeight, 0) > height) {
return oldHeight;
} // Return the new computed CSS height in px units
return "".concat(height, "px");
}
},
render: function render(h) {
return h('textarea', {
ref: 'input',
class: this.computedClass,
style: this.computedStyle,
directives: [{
name: 'b-visible',
value: this.visibleCallback,
// If textarea is within 640px of viewport, consider it visible
modifiers: {
'640': true
}
}],
attrs: this.computedAttrs,
domProps: {
value: this.localValue
},
on: this.computedListeners
});
}
});
var FormTextareaPlugin = /*#__PURE__*/pluginFactory({
components: {
BFormTextarea: BFormTextarea,
BTextarea: BFormTextarea
}
});
var NUMERIC = 'numeric'; // --- Helper methods ---
var padLeftZeros = function padLeftZeros(num) {
return "00".concat(num || '').slice(-2);
};
var parseHMS = function parseHMS(hms) {
hms = toString$1(hms);
var hh = null,
mm = null,
ss = null;
if (RX_TIME.test(hms)) {
var _hms$split$map = hms.split(':').map(function (v) {
return toInteger(v, null);
});
var _hms$split$map2 = _slicedToArray(_hms$split$map, 3);
hh = _hms$split$map2[0];
mm = _hms$split$map2[1];
ss = _hms$split$map2[2];
}
return {
hours: isUndefinedOrNull(hh) ? null : hh,
minutes: isUndefinedOrNull(mm) ? null : mm,
seconds: isUndefinedOrNull(ss) ? null : ss,
ampm: isUndefinedOrNull(hh) || hh < 12 ? 0 : 1
};
};
var formatHMS = function formatHMS(_ref) {
var hours = _ref.hours,
minutes = _ref.minutes,
seconds = _ref.seconds;
var requireSeconds = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
if (isNull(hours) || isNull(minutes) || requireSeconds && isNull(seconds)) {
return '';
}
var hms = [hours, minutes, requireSeconds ? seconds : 0];
return hms.map(padLeftZeros).join(':');
}; // --- Props ---
var props$M = makePropsConfigurable(_objectSpread2(_objectSpread2({
value: {
type: String,
default: ''
},
showSeconds: {
// If true, show the second spinbutton
type: Boolean,
default: false
},
hour12: {
// Explicitly force 12 or 24 hour time
// Default is to use resolved locale for 12/24 hour display
// Tri-state: `true` = 12, `false` = 24, `null` = auto
type: Boolean,
default: null
},
locale: {
type: [String, Array] // default: null
},
ariaLabelledby: {
// ID of label element
type: String // default: null
},
secondsStep: {
type: [Number, String],
default: 1
},
minutesStep: {
type: [Number, String],
default: 1
},
disabled: {
type: Boolean,
default: false
},
readonly: {
type: Boolean,
default: false
},
hideHeader: {
type: Boolean,
default: false
},
labelNoTimeSelected: {
type: String,
default: 'No time selected'
},
labelSelected: {
type: String,
default: 'Selected time'
},
labelHours: {
type: String,
default: 'Hours'
},
labelMinutes: {
type: String,
default: 'Minutes'
},
labelSeconds: {
type: String,
default: 'Seconds'
},
labelAmpm: {
type: String,
default: 'AM/PM'
},
labelAm: {
type: String,
default: 'AM'
},
labelPm: {
type: String,
default: 'PM'
}
}, pick(props$L, ['labelIncrement', 'labelDecrement'])), {}, {
hidden: {
type: Boolean,
default: false
}
}), NAME_TIME); // --- Main component ---
// @vue/component
var BTime = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_TIME,
mixins: [idMixin, normalizeSlotMixin],
model: {
prop: 'value',
event: 'input'
},
props: props$M,
data: function data() {
var parsed = parseHMS(this.value || '');
return {
// Spin button models
modelHours: parsed.hours,
modelMinutes: parsed.minutes,
modelSeconds: parsed.seconds,
modelAmpm: parsed.ampm,
// Internal flag to enable aria-live regions
isLive: false
};
},
computed: {
computedHMS: function computedHMS() {
var hours = this.modelHours;
var minutes = this.modelMinutes;
var seconds = this.modelSeconds;
return formatHMS({
hours: hours,
minutes: minutes,
seconds: seconds
}, this.showSeconds);
},
resolvedOptions: function resolvedOptions() {
// Resolved locale options
var locale = concat(this.locale).filter(identity);
var options = {
hour: NUMERIC,
minute: NUMERIC,
second: NUMERIC
};
if (!isUndefinedOrNull(this.hour12)) {
// Force 12 or 24 hour clock
options.hour12 = !!this.hour12;
}
var dtf = new Intl.DateTimeFormat(locale, options);
var resolved = dtf.resolvedOptions();
var hour12 = resolved.hour12 || false; // IE 11 doesn't resolve the hourCycle, so we make
// an assumption and fall back to common values
var hourCycle = resolved.hourCycle || (hour12 ? 'h12' : 'h23');
return {
locale: resolved.locale,
hour12: hour12,
hourCycle: hourCycle
};
},
computedLocale: function computedLocale() {
return this.resolvedOptions.locale;
},
computedLang: function computedLang() {
return (this.computedLocale || '').replace(/-u-.*$/, '');
},
computedRTL: function computedRTL() {
return isLocaleRTL(this.computedLang);
},
computedHourCycle: function computedHourCycle() {
// h11, h12, h23, or h24
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Locale/hourCycle
// h12 - Hour system using 1–12. Corresponds to 'h' in patterns. The 12 hour clock, with midnight starting at 12:00 am
// h23 - Hour system using 0–23. Corresponds to 'H' in patterns. The 24 hour clock, with midnight starting at 0:00
// h11 - Hour system using 0–11. Corresponds to 'K' in patterns. The 12 hour clock, with midnight starting at 0:00 am
// h24 - Hour system using 1–24. Corresponds to 'k' in pattern. The 24 hour clock, with midnight starting at 24:00
// For h12 or h24, we visually format 00 hours as 12
return this.resolvedOptions.hourCycle;
},
is12Hour: function is12Hour() {
return !!this.resolvedOptions.hour12;
},
context: function context() {
return {
locale: this.computedLocale,
isRTL: this.computedRTL,
hourCycle: this.computedHourCycle,
hour12: this.is12Hour,
hours: this.modelHours,
minutes: this.modelMinutes,
seconds: this.showSeconds ? this.modelSeconds : 0,
value: this.computedHMS,
formatted: this.formattedTimeString
};
},
valueId: function valueId() {
return this.safeId() || null;
},
computedAriaLabelledby: function computedAriaLabelledby() {
return [this.ariaLabelledby, this.valueId].filter(identity).join(' ') || null;
},
timeFormatter: function timeFormatter() {
// Returns a formatter function reference
// The formatter converts the time to a localized string
var options = {
hour12: this.is12Hour,
hourCycle: this.computedHourCycle,
hour: NUMERIC,
minute: NUMERIC,
timeZone: 'UTC'
};
if (this.showSeconds) {
options.second = NUMERIC;
} // Formats the time as a localized string
return createDateFormatter(this.computedLocale, options);
},
numberFormatter: function numberFormatter() {
// Returns a formatter function reference
// The formatter always formats as 2 digits and is localized
var nf = new Intl.NumberFormat(this.computedLocale, {
style: 'decimal',
minimumIntegerDigits: 2,
minimumFractionDigits: 0,
maximumFractionDigits: 0,
notation: 'standard'
});
return nf.format;
},
formattedTimeString: function formattedTimeString() {
var hours = this.modelHours;
var minutes = this.modelMinutes;
var seconds = this.showSeconds ? this.modelSeconds || 0 : 0;
if (this.computedHMS) {
return this.timeFormatter(createDate(Date.UTC(0, 0, 1, hours, minutes, seconds)));
}
return this.labelNoTimeSelected || ' ';
},
spinScopedSlots: function spinScopedSlots() {
var h = this.$createElement;
return {
increment: function increment(_ref2) {
var hasFocus = _ref2.hasFocus;
return h(BIconChevronUp, {
props: {
scale: hasFocus ? 1.5 : 1.25
},
attrs: {
'aria-hidden': 'true'
}
});
},
decrement: function decrement(_ref3) {
var hasFocus = _ref3.hasFocus;
return h(BIconChevronUp, {
props: {
flipV: true,
scale: hasFocus ? 1.5 : 1.25
},
attrs: {
'aria-hidden': 'true'
}
});
}
};
}
},
watch: {
value: function value(newVal, oldVal) {
if (newVal !== oldVal && !looseEqual(parseHMS(newVal), parseHMS(this.computedHMS))) {
var _parseHMS = parseHMS(newVal),
hours = _parseHMS.hours,
minutes = _parseHMS.minutes,
seconds = _parseHMS.seconds,
ampm = _parseHMS.ampm;
this.modelHours = hours;
this.modelMinutes = minutes;
this.modelSeconds = seconds;
this.modelAmpm = ampm;
}
},
computedHMS: function computedHMS(newVal, oldVal) {
if (newVal !== oldVal) {
this.$emit('input', newVal);
}
},
context: function context(newVal, oldVal) {
if (!looseEqual(newVal, oldVal)) {
this.$emit('context', newVal);
}
},
modelAmpm: function modelAmpm(newVal, oldVal) {
var _this = this;
if (newVal !== oldVal) {
var hours = isNull(this.modelHours) ? 0 : this.modelHours;
this.$nextTick(function () {
if (newVal === 0 && hours > 11) {
// Switched to AM
_this.modelHours = hours - 12;
} else if (newVal === 1 && hours < 12) {
// Switched to PM
_this.modelHours = hours + 12;
}
});
}
},
modelHours: function modelHours(newHours, oldHours) {
if (newHours !== oldHours) {
this.modelAmpm = newHours > 11 ? 1 : 0;
}
}
},
created: function created() {
var _this2 = this;
this.$nextTick(function () {
_this2.$emit('context', _this2.context);
});
},
mounted: function mounted() {
this.setLive(true);
},
/* istanbul ignore next */
activated: function activated() {
this.setLive(true);
},
/* istanbul ignore next */
deactivated: function deactivated() {
this.setLive(false);
},
beforeDestroy: function beforeDestroy() {
this.setLive(false);
},
methods: {
// Public methods
focus: function focus() {
if (!this.disabled) {
// We focus the first spin button
attemptFocus(this.$refs.spinners[0]);
}
},
blur: function blur() {
if (!this.disabled) {
var activeElement = getActiveElement();
if (contains(this.$el, activeElement)) {
attemptBlur(activeElement);
}
}
},
// Formatters for the spin buttons
formatHours: function formatHours(hh) {
var hourCycle = this.computedHourCycle; // We always store 0-23, but format based on h11/h12/h23/h24 formats
hh = this.is12Hour && hh > 12 ? hh - 12 : hh; // Determine how 00:00 and 12:00 are shown
hh = hh === 0 && hourCycle === 'h12' ? 12 : hh === 0 && hourCycle === 'h24' ?
/* istanbul ignore next */
24 : hh === 12 && hourCycle === 'h11' ?
/* istanbul ignore next */
0 : hh;
return this.numberFormatter(hh);
},
formatMinutes: function formatMinutes(mm) {
return this.numberFormatter(mm);
},
formatSeconds: function formatSeconds(ss) {
return this.numberFormatter(ss);
},
formatAmpm: function formatAmpm(ampm) {
// These should come from label props???
// `ampm` should always be a value of `0` or `1`
return ampm === 0 ? this.labelAm : ampm === 1 ? this.labelPm : '';
},
// Spinbutton on change handlers
setHours: function setHours(value) {
this.modelHours = value;
},
setMinutes: function setMinutes(value) {
this.modelMinutes = value;
},
setSeconds: function setSeconds(value) {
this.modelSeconds = value;
},
setAmpm: function setAmpm(value) {
this.modelAmpm = value;
},
onSpinLeftRight: function onSpinLeftRight() {
var evt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var type = evt.type,
keyCode = evt.keyCode;
if (!this.disabled && type === 'keydown' && (keyCode === CODE_LEFT || keyCode === CODE_RIGHT)) {
stopEvent(evt);
var spinners = this.$refs.spinners || [];
var index = spinners.map(function (cmp) {
return !!cmp.hasFocus;
}).indexOf(true);
index = index + (keyCode === CODE_LEFT ? -1 : 1);
index = index >= spinners.length ? 0 : index < 0 ? spinners.length - 1 : index;
attemptFocus(spinners[index]);
}
},
setLive: function setLive(on) {
var _this3 = this;
if (on) {
this.$nextTick(function () {
requestAF(function () {
_this3.isLive = true;
});
});
} else {
this.isLive = false;
}
}
},
render: function render(h) {
var _this4 = this;
/* istanbul ignore if */
if (this.hidden) {
// If hidden, we just render a placeholder comment
return h();
}
var valueId = this.valueId;
var computedAriaLabelledby = this.computedAriaLabelledby;
var spinIds = []; // Helper method to render a spinbutton
var makeSpinbutton = function makeSpinbutton(handler, key, classes) {
var spinbuttonProps = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
var id = _this4.safeId("_spinbutton_".concat(key, "_")) || null;
spinIds.push(id);
return h(BFormSpinbutton, {
key: key,
ref: 'spinners',
refInFor: true,
class: classes,
props: _objectSpread2({
id: id,
placeholder: '--',
vertical: true,
required: true,
disabled: _this4.disabled,
readonly: _this4.readonly,
locale: _this4.computedLocale,
labelIncrement: _this4.labelIncrement,
labelDecrement: _this4.labelDecrement,
wrap: true,
ariaControls: valueId,
min: 0
}, spinbuttonProps),
scopedSlots: _this4.spinScopedSlots,
on: {
// We use `change` event to minimize SR verbosity
// As the spinbutton will announce each value change
// and we don't want the formatted time to be announced
// on each value input if repeat is happening
change: handler
}
});
}; // Helper method to return a "colon" separator
var makeColon = function makeColon() {
return h('div', {
staticClass: 'd-flex flex-column',
class: {
'text-muted': _this4.disabled || _this4.readonly
},
attrs: {
'aria-hidden': 'true'
}
}, [h(BIconCircleFill, {
props: {
shiftV: 4,
scale: 0.5
}
}), h(BIconCircleFill, {
props: {
shiftV: -4,
scale: 0.5
}
})]);
};
var $spinners = []; // Hours
$spinners.push(makeSpinbutton(this.setHours, 'hours', 'b-time-hours', {
value: this.modelHours,
max: 23,
step: 1,
formatterFn: this.formatHours,
ariaLabel: this.labelHours
})); // Spacer
$spinners.push(makeColon()); // Minutes
$spinners.push(makeSpinbutton(this.setMinutes, 'minutes', 'b-time-minutes', {
value: this.modelMinutes,
max: 59,
step: this.minutesStep || 1,
formatterFn: this.formatMinutes,
ariaLabel: this.labelMinutes
}));
if (this.showSeconds) {
// Spacer
$spinners.push(makeColon()); // Seconds
$spinners.push(makeSpinbutton(this.setSeconds, 'seconds', 'b-time-seconds', {
value: this.modelSeconds,
max: 59,
step: this.secondsStep || 1,
formatterFn: this.formatSeconds,
ariaLabel: this.labelSeconds
}));
} // AM/PM ?
if (this.is12Hour) {
// TODO:
// If locale is RTL, unshift this instead of push?
// And switch class `ml-2` to `mr-2`
// Note some LTR locales (i.e. zh) also place AM/PM to the left
$spinners.push(makeSpinbutton(this.setAmpm, 'ampm', 'b-time-ampm', {
value: this.modelAmpm,
max: 1,
formatterFn: this.formatAmpm,
ariaLabel: this.labelAmpm,
// We set `required` as `false`, since this always has a value
required: false
}));
} // Assemble spinners
$spinners = h('div', {
staticClass: 'd-flex align-items-center justify-content-center mx-auto',
attrs: {
role: 'group',
tabindex: this.disabled || this.readonly ? null : '-1',
'aria-labelledby': computedAriaLabelledby
},
on: {
keydown: this.onSpinLeftRight,
click
/* istanbul ignore next */
: function click(evt)
/* istanbul ignore next */
{
if (evt.target === evt.currentTarget) {
_this4.focus();
}
}
}
}, $spinners); // Selected type display
var $value = h('output', {
staticClass: 'form-control form-control-sm text-center',
class: {
disabled: this.disabled || this.readonly
},
attrs: {
id: valueId,
role: 'status',
for: spinIds.filter(identity).join(' ') || null,
tabindex: this.disabled ? null : '-1',
'aria-live': this.isLive ? 'polite' : 'off',
'aria-atomic': 'true'
},
on: {
// Transfer focus/click to focus hours spinner
click: this.focus,
focus: this.focus
}
}, [h('bdi', this.formattedTimeString), this.computedHMS ? h('span', {
staticClass: 'sr-only'
}, " (".concat(this.labelSelected, ") ")) : '']);
var $header = h('header', {
staticClass: 'b-time-header',
class: {
'sr-only': this.hideHeader
}
}, [$value]); // Optional bottom slot
var $slot = this.normalizeSlot();
$slot = $slot ? h('footer', {
staticClass: 'b-time-footer'
}, $slot) : h();
return h('div', {
staticClass: 'b-time d-inline-flex flex-column text-center',
attrs: {
role: 'group',
lang: this.computedLang || null,
'aria-labelledby': computedAriaLabelledby || null,
'aria-disabled': this.disabled ? 'true' : null,
'aria-readonly': this.readonly && !this.disabled ? 'true' : null
}
}, [$header, $spinners, $slot]);
}
});
// @vue/component
var BFormTimepicker = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_FORM_TIMEPICKER,
// The mixins order determines the order of appearance in the props reference section
mixins: [idMixin],
model: {
prop: 'value',
event: 'input'
},
props: makePropsConfigurable(_objectSpread2(_objectSpread2(_objectSpread2({}, props$M), omit(props$H, ['id', 'value', 'formattedValue', 'rtl', 'lang'])), {}, {
resetValue: {
type: String,
default: ''
},
buttonOnly: {
type: Boolean,
default: false
},
buttonVariant: {
// Applicable in button only mode
type: String,
default: 'secondary'
},
nowButton: {
type: Boolean,
default: false
},
labelNowButton: {
type: String,
default: 'Select now'
},
nowButtonVariant: {
type: String,
default: 'outline-primary'
},
resetButton: {
type: Boolean,
default: false
},
labelResetButton: {
type: String,
default: 'Reset'
},
resetButtonVariant: {
type: String,
default: 'outline-danger'
},
noCloseButton: {
type: Boolean,
default: false
},
labelCloseButton: {
type: String,
default: 'Close'
},
closeButtonVariant: {
type: String,
default: 'outline-secondary'
}
}), NAME_FORM_TIMEPICKER),
data: function data() {
return {
// We always use `HH:mm:ss` value internally
localHMS: this.value || '',
// Context data from BTime
localLocale: null,
isRTL: false,
formattedValue: '',
// If the menu is opened
isVisible: false
};
},
computed: {
computedLang: function computedLang() {
return (this.localLocale || '').replace(/-u-.*$/i, '') || null;
}
},
watch: {
value: function value(newVal) {
this.localHMS = newVal || '';
},
localHMS: function localHMS(newVal) {
// We only update the v-model value when the timepicker
// is open, to prevent cursor jumps when bound to a
// text input in button only mode
if (this.isVisible) {
this.$emit('input', newVal || '');
}
}
},
methods: {
// Public methods
focus: function focus() {
if (!this.disabled) {
attemptFocus(this.$refs.control);
}
},
blur: function blur() {
if (!this.disabled) {
attemptBlur(this.$refs.control);
}
},
// Private methods
setAndClose: function setAndClose(value) {
var _this = this;
this.localHMS = value;
this.$nextTick(function () {
_this.$refs.control.hide(true);
});
},
onInput: function onInput(hms) {
if (this.localHMS !== hms) {
this.localHMS = hms;
}
},
onContext: function onContext(ctx) {
var isRTL = ctx.isRTL,
locale = ctx.locale,
value = ctx.value,
formatted = ctx.formatted;
this.isRTL = isRTL;
this.localLocale = locale;
this.formattedValue = formatted;
this.localHMS = value || ''; // Re-emit the context event
this.$emit('context', ctx);
},
onNowButton: function onNowButton() {
var now = new Date();
var hours = now.getHours();
var minutes = now.getMinutes();
var seconds = this.showSeconds ? now.getSeconds() : 0;
var value = [hours, minutes, seconds].map(function (v) {
return "00".concat(v || '').slice(-2);
}).join(':');
this.setAndClose(value);
},
onResetButton: function onResetButton() {
this.setAndClose(this.resetValue);
},
onCloseButton: function onCloseButton() {
this.$refs.control.hide(true);
},
onShow: function onShow() {
this.isVisible = true;
},
onShown: function onShown() {
var _this2 = this;
this.$nextTick(function () {
attemptFocus(_this2.$refs.time);
_this2.$emit('shown');
});
},
onHidden: function onHidden() {
this.isVisible = false;
this.$emit('hidden');
},
// Render function helpers
defaultButtonFn: function defaultButtonFn(_ref) {
var isHovered = _ref.isHovered,
hasFocus = _ref.hasFocus;
return this.$createElement(isHovered || hasFocus ? BIconClockFill : BIconClock, {
attrs: {
'aria-hidden': 'true'
}
});
}
},
render: function render(h) {
var localHMS = this.localHMS,
disabled = this.disabled,
readonly = this.readonly,
$props = this.$props;
var placeholder = isUndefinedOrNull(this.placeholder) ? this.labelNoTimeSelected : this.placeholder; // Footer buttons
var $footer = [];
if (this.nowButton) {
var label = this.labelNowButton;
$footer.push(h(BButton, {
key: 'now-btn',
props: {
size: 'sm',
disabled: disabled || readonly,
variant: this.nowButtonVariant
},
attrs: {
'aria-label': label || null
},
on: {
click: this.onNowButton
}
}, label));
}
if (this.resetButton) {
if ($footer.length > 0) {
// Add a "spacer" between buttons ('&nbsp;')
$footer.push(h('span', "\xA0"));
}
var _label = this.labelResetButton;
$footer.push(h(BButton, {
key: 'reset-btn',
props: {
size: 'sm',
disabled: disabled || readonly,
variant: this.resetButtonVariant
},
attrs: {
'aria-label': _label || null
},
on: {
click: this.onResetButton
}
}, _label));
}
if (!this.noCloseButton) {
if ($footer.length > 0) {
// Add a "spacer" between buttons ('&nbsp;')
$footer.push(h('span', "\xA0"));
}
var _label2 = this.labelCloseButton;
$footer.push(h(BButton, {
key: 'close-btn',
props: {
size: 'sm',
disabled: disabled,
variant: this.closeButtonVariant
},
attrs: {
'aria-label': _label2 || null
},
on: {
click: this.onCloseButton
}
}, _label2));
}
if ($footer.length > 0) {
$footer = [h('div', {
staticClass: 'b-form-date-controls d-flex flex-wrap',
class: {
'justify-content-between': $footer.length > 1,
'justify-content-end': $footer.length < 2
}
}, $footer)];
}
var $time = h(BTime, {
ref: 'time',
staticClass: 'b-form-time-control',
props: _objectSpread2(_objectSpread2({}, pluckProps(props$M, $props)), {}, {
value: localHMS,
hidden: !this.isVisible
}),
on: {
input: this.onInput,
context: this.onContext
}
}, $footer);
return h(BVFormBtnLabelControl, {
ref: 'control',
staticClass: 'b-form-timepicker',
props: _objectSpread2(_objectSpread2({}, pluckProps(props$H, $props)), {}, {
id: this.safeId(),
value: localHMS,
formattedValue: localHMS ? this.formattedValue : '',
placeholder: placeholder,
rtl: this.isRTL,
lang: this.computedLang
}),
on: {
show: this.onShow,
shown: this.onShown,
hidden: this.onHidden
},
scopedSlots: {
'button-content': this.$scopedSlots['button-content'] || this.defaultButtonFn
}
}, [$time]);
}
});
var FormTimepickerPlugin = /*#__PURE__*/pluginFactory({
components: {
BFormTimepicker: BFormTimepicker,
BTimepicker: BFormTimepicker
}
});
var ImagePlugin = /*#__PURE__*/pluginFactory({
components: {
BImg: BImg,
BImgLazy: BImgLazy
}
});
var props$N = makePropsConfigurable({
tag: {
type: String,
default: 'div'
}
}, NAME_INPUT_GROUP_TEXT); // @vue/component
var BInputGroupText = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_INPUT_GROUP_TEXT,
functional: true,
props: props$N,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
return h(props.tag, a(data, {
staticClass: 'input-group-text'
}), children);
}
});
var commonProps$1 = {
id: {
type: String,
default: null
},
tag: {
type: String,
default: 'div'
},
isText: {
type: Boolean,
default: false
}
}; // @vue/component
var BInputGroupAddon = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_INPUT_GROUP_ADDON,
functional: true,
props: makePropsConfigurable(_objectSpread2(_objectSpread2({}, commonProps$1), {}, {
append: {
type: Boolean,
default: false
}
}), NAME_INPUT_GROUP_ADDON),
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
return h(props.tag, a(data, {
class: {
'input-group-append': props.append,
'input-group-prepend': !props.append
},
attrs: {
id: props.id
}
}), props.isText ? [h(BInputGroupText, children)] : children);
}
});
var BInputGroupAppend = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_INPUT_GROUP_APPEND,
functional: true,
props: makePropsConfigurable(commonProps$1, NAME_INPUT_GROUP_APPEND),
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
// Pass all our data down to child, and set `append` to `true`
return h(BInputGroupAddon, a(data, {
props: _objectSpread2(_objectSpread2({}, props), {}, {
append: true
})
}), children);
}
});
var BInputGroupPrepend = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_INPUT_GROUP_PREPEND,
functional: true,
props: makePropsConfigurable(commonProps$1, NAME_INPUT_GROUP_PREPEND),
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
// pass all our props/attrs down to child, and set`append` to false
return h(BInputGroupAddon, a(data, {
props: _objectSpread2(_objectSpread2({}, props), {}, {
append: false
})
}), children);
}
});
var props$O = makePropsConfigurable({
id: {
type: String
},
size: {
type: String // default: undefined
},
prepend: {
type: String
},
prependHtml: {
type: String
},
append: {
type: String
},
appendHtml: {
type: String
},
tag: {
type: String,
default: 'div'
}
}, NAME_INPUT_GROUP); // --- Main component ---
// @vue/component
var BInputGroup = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_INPUT_GROUP,
functional: true,
props: props$O,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
slots = _ref.slots,
scopedSlots = _ref.scopedSlots;
var prepend = props.prepend,
prependHtml = props.prependHtml,
append = props.append,
appendHtml = props.appendHtml,
size = props.size;
var $scopedSlots = scopedSlots || {};
var $slots = slots();
var slotScope = {};
var $prepend = h();
var hasPrependSlot = hasNormalizedSlot(SLOT_NAME_PREPEND, $scopedSlots, $slots);
if (hasPrependSlot || prepend || prependHtml) {
$prepend = h(BInputGroupPrepend, [hasPrependSlot ? normalizeSlot(SLOT_NAME_PREPEND, slotScope, $scopedSlots, $slots) : h(BInputGroupText, {
domProps: htmlOrText(prependHtml, prepend)
})]);
}
var $append = h();
var hasAppendSlot = hasNormalizedSlot(SLOT_NAME_APPEND, $scopedSlots, $slots);
if (hasAppendSlot || append || appendHtml) {
$append = h(BInputGroupAppend, [hasAppendSlot ? normalizeSlot(SLOT_NAME_APPEND, slotScope, $scopedSlots, $slots) : h(BInputGroupText, {
domProps: htmlOrText(appendHtml, append)
})]);
}
return h(props.tag, a(data, {
staticClass: 'input-group',
class: _defineProperty({}, "input-group-".concat(size), size),
attrs: {
id: props.id || null,
role: 'group'
}
}), [$prepend, normalizeSlot(SLOT_NAME_DEFAULT, slotScope, $scopedSlots, $slots), $append]);
}
});
var InputGroupPlugin = /*#__PURE__*/pluginFactory({
components: {
BInputGroup: BInputGroup,
BInputGroupAddon: BInputGroupAddon,
BInputGroupPrepend: BInputGroupPrepend,
BInputGroupAppend: BInputGroupAppend,
BInputGroupText: BInputGroupText
}
});
var props$P = makePropsConfigurable({
tag: {
type: String,
default: 'div'
},
fluid: {
// String breakpoint name new in Bootstrap v4.4.x
type: [Boolean, String],
default: false
}
}, NAME_CONTAINER); // @vue/component
var BContainer = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_CONTAINER,
functional: true,
props: props$P,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
return h(props.tag, a(data, {
class: _defineProperty({
container: !(props.fluid || props.fluid === ''),
'container-fluid': props.fluid === true || props.fluid === ''
}, "container-".concat(props.fluid), props.fluid && props.fluid !== true)
}), children);
}
});
var props$Q = makePropsConfigurable({
fluid: {
type: Boolean,
default: false
},
containerFluid: {
type: [Boolean, String],
default: false
},
header: {
type: String // default: null
},
headerHtml: {
type: String // default: null
},
headerTag: {
type: String,
default: 'h1'
},
headerLevel: {
type: [Number, String],
default: '3'
},
lead: {
type: String // default: null
},
leadHtml: {
type: String // default: null
},
leadTag: {
type: String,
default: 'p'
},
tag: {
type: String,
default: 'div'
},
bgVariant: {
type: String // default: undefined
},
borderVariant: {
type: String // default: undefined
},
textVariant: {
type: String // default: undefined
}
}, NAME_JUMBOTRON); // --- Main component ---
// @vue/component
var BJumbotron = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_JUMBOTRON,
functional: true,
props: props$Q,
render: function render(h, _ref) {
var _class2;
var props = _ref.props,
data = _ref.data,
slots = _ref.slots,
scopedSlots = _ref.scopedSlots;
var header = props.header,
headerHtml = props.headerHtml,
lead = props.lead,
leadHtml = props.leadHtml,
textVariant = props.textVariant,
bgVariant = props.bgVariant,
borderVariant = props.borderVariant;
var $scopedSlots = scopedSlots || {};
var $slots = slots();
var slotScope = {};
var $header = h();
var hasHeaderSlot = hasNormalizedSlot(SLOT_NAME_HEADER, $scopedSlots, $slots);
if (hasHeaderSlot || header || headerHtml) {
var headerLevel = props.headerLevel;
$header = h(props.headerTag, {
class: _defineProperty({}, "display-".concat(headerLevel), headerLevel),
domProps: hasHeaderSlot ? {} : htmlOrText(headerHtml, header)
}, normalizeSlot(SLOT_NAME_HEADER, slotScope, $scopedSlots, $slots));
}
var $lead = h();
var hasLeadSlot = hasNormalizedSlot(SLOT_NAME_LEAD, $scopedSlots, $slots);
if (hasLeadSlot || lead || leadHtml) {
$lead = h(props.leadTag, {
staticClass: 'lead',
domProps: hasLeadSlot ? {} : htmlOrText(leadHtml, lead)
}, normalizeSlot(SLOT_NAME_LEAD, slotScope, $scopedSlots, $slots));
}
var $children = [$header, $lead, normalizeSlot(SLOT_NAME_DEFAULT, slotScope, $scopedSlots, $slots)]; // If fluid, wrap content in a container
if (props.fluid) {
$children = [h(BContainer, {
props: {
fluid: props.containerFluid
}
}, $children)];
}
return h(props.tag, a(data, {
staticClass: 'jumbotron',
class: (_class2 = {
'jumbotron-fluid': props.fluid
}, _defineProperty(_class2, "text-".concat(textVariant), textVariant), _defineProperty(_class2, "bg-".concat(bgVariant), bgVariant), _defineProperty(_class2, "border-".concat(borderVariant), borderVariant), _defineProperty(_class2, "border", borderVariant), _class2)
}), $children);
}
});
var JumbotronPlugin = /*#__PURE__*/pluginFactory({
components: {
BJumbotron: BJumbotron
}
});
var COMMON_ALIGNMENT = ['start', 'end', 'center']; // Generates a prop object with a type of `[String, Number]`
var strNum$1 = function strNum() {
return {
type: [String, Number],
default: null
};
}; // Compute a `row-cols-{breakpoint}-{cols}` class name
// Memoized function for better performance on generating class names
var computeRowColsClass = memoize(function (breakpoint, cols) {
cols = trim(toString$1(cols));
return cols ? lowerCase(['row-cols', breakpoint, cols].filter(identity).join('-')) : null;
}); // Get the breakpoint name from the `rowCols` prop name
// Memoized function for better performance on extracting breakpoint names
var computeRowColsBreakpoint = memoize(function (prop) {
return lowerCase(prop.replace('cols', ''));
}); // Cached copy of the `row-cols` breakpoint prop names
// Will be populated when the props are generated
var rowColsPropList = []; // Lazy evaled props factory for <b-row> (called only once,
// the first time the component is used)
var generateProps$2 = function generateProps() {
// Grab the breakpoints from the cached config (including the '' (xs) breakpoint)
var breakpoints = getBreakpointsUpCached(); // Supports classes like: `row-cols-2`, `row-cols-md-4`, `row-cols-xl-6`
var rowColsProps = breakpoints.reduce(function (props, breakpoint) {
props[suffixPropName(breakpoint, 'cols')] = strNum$1();
return props;
}, create(null)); // Cache the row-cols prop names
rowColsPropList = keys(rowColsProps); // Return the generated props
return makePropsConfigurable(_objectSpread2({
tag: {
type: String,
default: 'div'
},
noGutters: {
type: Boolean,
default: false
},
alignV: {
type: String,
default: null,
validator: function validator(value) {
return arrayIncludes(concat(COMMON_ALIGNMENT, 'baseline', 'stretch'), value);
}
},
alignH: {
type: String,
default: null,
validator: function validator(value) {
return arrayIncludes(concat(COMMON_ALIGNMENT, 'between', 'around'), value);
}
},
alignContent: {
type: String,
default: null,
validator: function validator(value) {
return arrayIncludes(concat(COMMON_ALIGNMENT, 'between', 'around', 'stretch'), value);
}
}
}, rowColsProps), NAME_ROW);
}; // We do not use `Vue.extend()` here as that would evaluate the props
// immediately, which we do not want to happen
// @vue/component
var BRow = {
name: NAME_ROW,
functional: true,
get props() {
// Allow props to be lazy evaled on first access and
// then they become a non-getter afterwards
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get#Smart_self-overwriting_lazy_getters
delete this.props;
this.props = generateProps$2();
return this.props;
},
render: function render(h, _ref) {
var _classList$push;
var props = _ref.props,
data = _ref.data,
children = _ref.children;
var classList = []; // Loop through row-cols breakpoint props and generate the classes
rowColsPropList.forEach(function (prop) {
var c = computeRowColsClass(computeRowColsBreakpoint(prop), props[prop]); // If a class is returned, push it onto the array
if (c) {
classList.push(c);
}
});
classList.push((_classList$push = {
'no-gutters': props.noGutters
}, _defineProperty(_classList$push, "align-items-".concat(props.alignV), props.alignV), _defineProperty(_classList$push, "justify-content-".concat(props.alignH), props.alignH), _defineProperty(_classList$push, "align-content-".concat(props.alignContent), props.alignContent), _classList$push));
return h(props.tag, a(data, {
staticClass: 'row',
class: classList
}), children);
}
};
var LayoutPlugin = /*#__PURE__*/pluginFactory({
components: {
BContainer: BContainer,
BRow: BRow,
BCol: BCol,
BFormRow: BFormRow
}
});
var LinkPlugin = /*#__PURE__*/pluginFactory({
components: {
BLink: BLink
}
});
var props$R = makePropsConfigurable({
tag: {
type: String,
default: 'div'
},
flush: {
type: Boolean,
default: false
},
horizontal: {
type: [Boolean, String],
default: false
}
}, NAME_LIST_GROUP); // @vue/component
var BListGroup = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_LIST_GROUP,
functional: true,
props: props$R,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
var horizontal = props.horizontal === '' ? true : props.horizontal;
horizontal = props.flush ? false : horizontal;
var componentData = {
staticClass: 'list-group',
class: _defineProperty({
'list-group-flush': props.flush,
'list-group-horizontal': horizontal === true
}, "list-group-horizontal-".concat(horizontal), isString(horizontal))
};
return h(props.tag, a(data, componentData), children);
}
});
var actionTags = ['a', 'router-link', 'button', 'b-link']; // --- Props ---
var linkProps$3 = omit(props$1, ['event', 'routerTag']);
delete linkProps$3.href.default;
delete linkProps$3.to.default;
var props$S = makePropsConfigurable(_objectSpread2(_objectSpread2({}, linkProps$3), {}, {
tag: {
type: String,
default: 'div'
},
action: {
type: Boolean,
default: null
},
button: {
type: Boolean,
default: null
},
variant: {
type: String // default: undefined
}
}), NAME_LIST_GROUP_ITEM); // --- Main component ---
// @vue/component
var BListGroupItem = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_LIST_GROUP_ITEM,
functional: true,
props: props$S,
render: function render(h, _ref) {
var _class;
var props = _ref.props,
data = _ref.data,
children = _ref.children;
var button = props.button,
variant = props.variant,
active = props.active,
disabled = props.disabled;
var link = isLink(props);
var tag = button ? 'button' : !link ? props.tag : BLink;
var action = !!(props.action || link || button || arrayIncludes(actionTags, props.tag));
var attrs = {};
var itemProps = {};
if (isTag(tag, 'button')) {
if (!data.attrs || !data.attrs.type) {
// Add a type for button is one not provided in passed attributes
attrs.type = 'button';
}
if (props.disabled) {
// Set disabled attribute if button and disabled
attrs.disabled = true;
}
} else {
itemProps = pluckProps(linkProps$3, props);
}
return h(tag, a(data, {
attrs: attrs,
props: itemProps,
staticClass: 'list-group-item',
class: (_class = {}, _defineProperty(_class, "list-group-item-".concat(variant), variant), _defineProperty(_class, 'list-group-item-action', action), _defineProperty(_class, "active", active), _defineProperty(_class, "disabled", disabled), _class)
}), children);
}
});
var ListGroupPlugin = /*#__PURE__*/pluginFactory({
components: {
BListGroup: BListGroup,
BListGroupItem: BListGroupItem
}
});
var props$T = makePropsConfigurable({
tag: {
type: String,
default: 'div'
},
right: {
type: Boolean,
default: false
},
verticalAlign: {
type: String,
default: 'top'
}
}, NAME_MEDIA_ASIDE); // --- Main component ---
// @vue/component
var BMediaAside = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_MEDIA_ASIDE,
functional: true,
props: props$T,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
var verticalAlign = props.verticalAlign;
var align = verticalAlign === 'top' ? 'start' : verticalAlign === 'bottom' ? 'end' :
/* istanbul ignore next */
verticalAlign;
return h(props.tag, a(data, {
staticClass: 'media-aside',
class: _defineProperty({
'media-aside-right': props.right
}, "align-self-".concat(align), align)
}), children);
}
});
var props$U = makePropsConfigurable({
tag: {
type: String,
default: 'div'
}
}, NAME_MEDIA_BODY); // --- Main component ---
// @vue/component
var BMediaBody = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_MEDIA_BODY,
functional: true,
props: props$U,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
return h(props.tag, a(data, {
staticClass: 'media-body'
}), children);
}
});
var props$V = makePropsConfigurable({
tag: {
type: String,
default: 'div'
},
noBody: {
type: Boolean,
default: false
},
rightAlign: {
type: Boolean,
default: false
},
verticalAlign: {
type: String,
default: 'top'
}
}, NAME_MEDIA); // --- Main component ---
// @vue/component
var BMedia = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_MEDIA,
functional: true,
props: props$V,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
slots = _ref.slots,
scopedSlots = _ref.scopedSlots,
children = _ref.children;
var noBody = props.noBody,
rightAlign = props.rightAlign,
verticalAlign = props.verticalAlign;
var $children = noBody ? children : [];
if (!noBody) {
var slotScope = {};
var $slots = slots();
var $scopedSlots = scopedSlots || {};
$children.push(h(BMediaBody, normalizeSlot(SLOT_NAME_DEFAULT, slotScope, $scopedSlots, $slots)));
var $aside = normalizeSlot('aside', slotScope, $scopedSlots, $slots);
if ($aside) {
$children[rightAlign ? 'push' : 'unshift'](h(BMediaAside, {
props: {
right: rightAlign,
verticalAlign: verticalAlign
}
}, $aside));
}
}
return h(props.tag, a(data, {
staticClass: 'media'
}), $children);
}
});
var MediaPlugin = /*#__PURE__*/pluginFactory({
components: {
BMedia: BMedia,
BMediaAside: BMediaAside,
BMediaBody: BMediaBody
}
});
//
// Single root node portaling of content, which retains parent/child hierarchy
// Unlike Portal-Vue where portaled content is no longer a descendent of its
// intended parent components
//
// Private components for use by Tooltips, Popovers and Modals
//
// Based on vue-simple-portal
// https://github.com/LinusBorg/vue-simple-portal
// Transporter target used by BTransporterSingle
// Supports only a single root element
// @vue/component
var BTransporterTargetSingle = /*#__PURE__*/Vue__default['default'].extend({
// As an abstract component, it doesn't appear in the $parent chain of
// components, which means the next parent of any component rendered inside
// of this one will be the parent from which is was portal'd
abstract: true,
name: NAME_TRANSPORTER_TARGET_SINGLE,
props: {
nodes: {
// Even though we only support a single root element,
// VNodes are always passed as an array
type: [Array, Function] // default: undefined
}
},
data: function data(vm) {
return {
updatedNodes: vm.nodes
};
},
destroyed: function destroyed() {
removeNode(this.$el);
},
render: function render(h) {
var nodes = isFunction(this.updatedNodes) ? this.updatedNodes({}) : this.updatedNodes;
nodes = concat(nodes).filter(Boolean);
/* istanbul ignore else */
if (nodes && nodes.length > 0 && !nodes[0].text) {
return nodes[0];
} else {
/* istanbul ignore next */
return h();
}
}
}); // This component has no root element, so only a single VNode is allowed
// @vue/component
var BTransporterSingle = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_TRANSPORTER_SINGLE,
mixins: [normalizeSlotMixin],
props: {
disabled: {
type: Boolean,
default: false
},
container: {
// String: CSS selector,
// HTMLElement: Element reference
// Mainly needed for tooltips/popovers inside modals
type: [String, HTMLElement],
default: 'body'
},
tag: {
// This should be set to match the root element type
type: String,
default: 'div'
}
},
watch: {
disabled: {
immediate: true,
handler: function handler(disabled) {
disabled ? this.unmountTarget() : this.$nextTick(this.mountTarget);
}
}
},
created: function created() {
// Create private non-reactive props
this.$_defaultFn = null;
this.$_target = null;
},
beforeMount: function beforeMount() {
this.mountTarget();
},
updated: function updated() {
// We need to make sure that all children have completed updating
// before rendering in the target
// `vue-simple-portal` has the this in a `$nextTick()`,
// while `portal-vue` doesn't
// Just trying to see if the `$nextTick()` delay is required or not
// Since all slots in Vue 2.6.x are always functions
this.updateTarget();
},
beforeDestroy: function beforeDestroy() {
this.unmountTarget();
this.$_defaultFn = null;
},
methods: {
// Get the element which the target should be appended to
getContainer: function getContainer() {
/* istanbul ignore else */
if (isBrowser) {
var container = this.container;
return isString(container) ? select(container) : container;
} else {
return null;
}
},
// Mount the target
mountTarget: function mountTarget() {
if (!this.$_target) {
var container = this.getContainer();
if (container) {
var el = document.createElement('div');
container.appendChild(el);
this.$_target = new BTransporterTargetSingle({
el: el,
parent: this,
propsData: {
// Initial nodes to be rendered
nodes: concat(this.normalizeSlot())
}
});
}
}
},
// Update the content of the target
updateTarget: function updateTarget() {
if (isBrowser && this.$_target) {
var defaultFn = this.$scopedSlots.default;
if (!this.disabled) {
/* istanbul ignore else: only applicable in Vue 2.5.x */
if (defaultFn && this.$_defaultFn !== defaultFn) {
// We only update the target component if the scoped slot
// function is a fresh one. The new slot syntax (since Vue 2.6)
// can cache unchanged slot functions and we want to respect that here
this.$_target.updatedNodes = defaultFn;
} else if (!defaultFn) {
// We also need to be back compatible with non-scoped default slot (i.e. 2.5.x)
this.$_target.updatedNodes = this.$slots.default;
}
} // Update the scoped slot function cache
this.$_defaultFn = defaultFn;
}
},
// Unmount the target
unmountTarget: function unmountTarget() {
this.$_target && this.$_target.$destroy();
this.$_target = null;
}
},
render: function render(h) {
if (this.disabled) {
var nodes = concat(this.normalizeSlot()).filter(identity);
if (nodes.length > 0 && !nodes[0].text) {
return nodes[0];
}
}
return h();
}
});
var PROP$1 = '$_bv_documentHandlers_'; // @vue/component
var listenOnDocumentMixin = {
created: function created() {
var _this = this;
/* istanbul ignore next */
if (!isBrowser) {
return;
} // Declare non-reactive property
// Object of arrays, keyed by event name,
// where value is an array of handlers
// Prop will be defined on client only
this[PROP$1] = {}; // Set up our beforeDestroy handler (client only)
this.$once('hook:beforeDestroy', function () {
var items = _this[PROP$1] || {}; // Immediately delete this[PROP] to prevent the
// listenOn/Off methods from running (which may occur
// due to requestAnimationFrame/transition delays)
delete _this[PROP$1]; // Remove all registered event handlers
keys(items).forEach(function (evtName) {
var handlers = items[evtName] || [];
handlers.forEach(function (handler) {
return eventOff(document, evtName, handler, EVENT_OPTIONS_NO_CAPTURE);
});
});
});
},
methods: {
listenDocument: function listenDocument(on, evtName, handler) {
on ? this.listenOnDocument(evtName, handler) : this.listenOffDocument(evtName, handler);
},
listenOnDocument: function listenOnDocument(evtName, handler) {
if (this[PROP$1] && isString(evtName) && isFunction(handler)) {
this[PROP$1][evtName] = this[PROP$1][evtName] || [];
if (!arrayIncludes(this[PROP$1][evtName], handler)) {
this[PROP$1][evtName].push(handler);
eventOn(document, evtName, handler, EVENT_OPTIONS_NO_CAPTURE);
}
}
},
listenOffDocument: function listenOffDocument(evtName, handler) {
if (this[PROP$1] && isString(evtName) && isFunction(handler)) {
eventOff(document, evtName, handler, EVENT_OPTIONS_NO_CAPTURE);
this[PROP$1][evtName] = (this[PROP$1][evtName] || []).filter(function (h) {
return h !== handler;
});
}
}
}
};
var PROP$2 = '$_bv_windowHandlers_'; // @vue/component
var listenOnWindowMixin = {
beforeCreate: function beforeCreate() {
// Declare non-reactive property
// Object of arrays, keyed by event name,
// where value is an array of handlers
this[PROP$2] = {};
},
beforeDestroy: function beforeDestroy() {
if (isBrowser) {
var items = this[PROP$2]; // Immediately delete this[PROP] to prevent the
// listenOn/Off methods from running (which may occur
// due to requestAnimationFrame delays)
delete this[PROP$2]; // Remove all registered event handlers
keys(items).forEach(function (evtName) {
var handlers = items[evtName] || [];
handlers.forEach(function (handler) {
return eventOff(window, evtName, handler, EVENT_OPTIONS_NO_CAPTURE);
});
});
}
},
methods: {
listenWindow: function listenWindow(on, evtName, handler) {
on ? this.listenOnWindow(evtName, handler) : this.listenOffWindow(evtName, handler);
},
listenOnWindow: function listenOnWindow(evtName, handler) {
if (isBrowser && this[PROP$2] && isString(evtName) && isFunction(handler)) {
this[PROP$2][evtName] = this[PROP$2][evtName] || [];
if (!arrayIncludes(this[PROP$2][evtName], handler)) {
this[PROP$2][evtName].push(handler);
eventOn(window, evtName, handler, EVENT_OPTIONS_NO_CAPTURE);
}
}
},
listenOffWindow: function listenOffWindow(evtName, handler) {
if (isBrowser && this[PROP$2] && isString(evtName) && isFunction(handler)) {
eventOff(window, evtName, handler, EVENT_OPTIONS_NO_CAPTURE);
this[PROP$2][evtName] = (this[PROP$2][evtName] || []).filter(function (h) {
return h !== handler;
});
}
}
}
};
// This method returns a component's scoped style attribute name: `data-v-xxxxxxx`
// The `_scopeId` options property is added by vue-loader when using scoped styles
// and will be `undefined` if no scoped styles are in use
var getScopeId = function getScopeId(vm) {
var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
return vm ? vm.$options._scopeId || defaultValue : defaultValue;
};
var scopedStyleAttrsMixin = {
computed: {
scopedStyleAttrs: function scopedStyleAttrs() {
var scopeId = getScopeId(this.$parent);
return scopeId ? _defineProperty({}, scopeId, '') : {};
}
}
};
/**
* Private ModalManager helper
* Handles controlling modal stacking zIndexes and body adjustments/classes
*/
// Default modal backdrop z-index
var DEFAULT_ZINDEX = 1040; // 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'
}; // @vue/component
var ModalManager = /*#__PURE__*/Vue__default['default'].extend({
data: function data() {
return {
modals: [],
baseZIndex: null,
scrollbarWidth: null,
isBodyOverflowing: false
};
},
computed: {
modalCount: function modalCount() {
return this.modals.length;
},
modalsAreOpen: function modalsAreOpen() {
return this.modalCount > 0;
}
},
watch: {
modalCount: function modalCount(newCount, oldCount) {
if (isBrowser) {
this.getScrollbarWidth();
if (newCount > 0 && oldCount === 0) {
// Transitioning to modal(s) open
this.checkScrollbar();
this.setScrollbar();
addClass(document.body, 'modal-open');
} else if (newCount === 0 && oldCount > 0) {
// Transitioning to modal(s) closed
this.resetScrollbar();
removeClass(document.body, 'modal-open');
}
setAttr(document.body, 'data-modal-open-count', String(newCount));
}
},
modals: function modals(newVal) {
var _this = this;
this.checkScrollbar();
requestAF(function () {
_this.updateModals(newVal || []);
});
}
},
methods: {
// Public methods
registerModal: function registerModal(modal) {
var _this2 = this;
// Register the modal if not already registered
if (modal && this.modals.indexOf(modal) === -1) {
// Add modal to modals array
this.modals.push(modal);
modal.$once('hook:beforeDestroy', function () {
_this2.unregisterModal(modal);
});
}
},
unregisterModal: function unregisterModal(modal) {
var index = this.modals.indexOf(modal);
if (index > -1) {
// Remove modal from modals array
this.modals.splice(index, 1); // Reset the modal's data
if (!(modal._isBeingDestroyed || modal._isDestroyed)) {
this.resetModal(modal);
}
}
},
getBaseZIndex: function getBaseZIndex() {
if (isNull(this.baseZIndex) && isBrowser) {
// Create a temporary `div.modal-backdrop` to get computed z-index
var div = document.createElement('div');
addClass(div, 'modal-backdrop');
addClass(div, 'd-none');
setStyle(div, 'display', 'none');
document.body.appendChild(div);
this.baseZIndex = toInteger(getCS(div).zIndex, DEFAULT_ZINDEX);
document.body.removeChild(div);
}
return this.baseZIndex || DEFAULT_ZINDEX;
},
getScrollbarWidth: function getScrollbarWidth() {
if (isNull(this.scrollbarWidth) && isBrowser) {
// Create a temporary `div.measure-scrollbar` to get computed z-index
var div = document.createElement('div');
addClass(div, 'modal-scrollbar-measure');
document.body.appendChild(div);
this.scrollbarWidth = getBCR(div).width - div.clientWidth;
document.body.removeChild(div);
}
return this.scrollbarWidth || 0;
},
// Private methods
updateModals: function updateModals(modals) {
var _this3 = this;
var baseZIndex = this.getBaseZIndex();
var scrollbarWidth = this.getScrollbarWidth();
modals.forEach(function (modal, index) {
// We update data values on each modal
modal.zIndex = baseZIndex + index;
modal.scrollbarWidth = scrollbarWidth;
modal.isTop = index === _this3.modals.length - 1;
modal.isBodyOverflowing = _this3.isBodyOverflowing;
});
},
resetModal: function resetModal(modal) {
if (modal) {
modal.zIndex = this.getBaseZIndex();
modal.isTop = true;
modal.isBodyOverflowing = false;
}
},
checkScrollbar: function checkScrollbar() {
// Determine if the body element is overflowing
var _getBCR = getBCR(document.body),
left = _getBCR.left,
right = _getBCR.right;
this.isBodyOverflowing = left + right < window.innerWidth;
},
setScrollbar: function setScrollbar() {
var body = document.body; // Storage place to cache changes to margins and padding
// Note: This assumes the following element types are not added to the
// document after the modal has opened.
body._paddingChangedForModal = body._paddingChangedForModal || [];
body._marginChangedForModal = body._marginChangedForModal || [];
if (this.isBodyOverflowing) {
var scrollbarWidth = this.scrollbarWidth; // Adjust fixed content padding
/* istanbul ignore next: difficult to test in JSDOM */
selectAll(Selector.FIXED_CONTENT).forEach(function (el) {
var actualPadding = getStyle(el, 'paddingRight') || '';
setAttr(el, 'data-padding-right', actualPadding);
setStyle(el, 'paddingRight', "".concat(toFloat(getCS(el).paddingRight, 0) + scrollbarWidth, "px"));
body._paddingChangedForModal.push(el);
}); // Adjust sticky content margin
/* istanbul ignore next: difficult to test in JSDOM */
selectAll(Selector.STICKY_CONTENT).forEach(function (el)
/* istanbul ignore next */
{
var actualMargin = getStyle(el, 'marginRight') || '';
setAttr(el, 'data-margin-right', actualMargin);
setStyle(el, 'marginRight', "".concat(toFloat(getCS(el).marginRight, 0) - scrollbarWidth, "px"));
body._marginChangedForModal.push(el);
}); // Adjust <b-navbar-toggler> margin
/* istanbul ignore next: difficult to test in JSDOM */
selectAll(Selector.NAVBAR_TOGGLER).forEach(function (el)
/* istanbul ignore next */
{
var actualMargin = getStyle(el, 'marginRight') || '';
setAttr(el, 'data-margin-right', actualMargin);
setStyle(el, 'marginRight', "".concat(toFloat(getCS(el).marginRight, 0) + scrollbarWidth, "px"));
body._marginChangedForModal.push(el);
}); // Adjust body padding
var actualPadding = getStyle(body, 'paddingRight') || '';
setAttr(body, 'data-padding-right', actualPadding);
setStyle(body, 'paddingRight', "".concat(toFloat(getCS(body).paddingRight, 0) + scrollbarWidth, "px"));
}
},
resetScrollbar: function resetScrollbar() {
var body = document.body;
if (body._paddingChangedForModal) {
// Restore fixed content padding
body._paddingChangedForModal.forEach(function (el) {
/* istanbul ignore next: difficult to test in JSDOM */
if (hasAttr(el, 'data-padding-right')) {
setStyle(el, 'paddingRight', getAttr(el, 'data-padding-right') || '');
removeAttr(el, 'data-padding-right');
}
});
}
if (body._marginChangedForModal) {
// Restore sticky content and navbar-toggler margin
body._marginChangedForModal.forEach(function (el) {
/* istanbul ignore next: difficult to test in JSDOM */
if (hasAttr(el, 'data-margin-right')) {
setStyle(el, 'marginRight', getAttr(el, 'data-margin-right') || '');
removeAttr(el, 'data-margin-right');
}
});
}
body._paddingChangedForModal = null;
body._marginChangedForModal = null; // Restore body padding
if (hasAttr(body, 'data-padding-right')) {
setStyle(body, 'paddingRight', getAttr(body, 'data-padding-right') || '');
removeAttr(body, 'data-padding-right');
}
}
}
}); // Create and export our modal manager instance
var modalManager = new ModalManager();
var BvModalEvent = /*#__PURE__*/function (_BvEvent) {
_inherits(BvModalEvent, _BvEvent);
var _super = _createSuper(BvModalEvent);
function BvModalEvent(type) {
var _this;
var eventInit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
_classCallCheck(this, BvModalEvent);
_this = _super.call(this, type, eventInit); // Freeze our new props as readonly, but leave them enumerable
defineProperties(_assertThisInitialized(_this), {
trigger: readonlyDescriptor()
});
return _this;
}
_createClass(BvModalEvent, null, [{
key: "Defaults",
get: function get() {
return _objectSpread2(_objectSpread2({}, _get(_getPrototypeOf(BvModalEvent), "Defaults", this)), {}, {
trigger: null
});
}
}]);
return BvModalEvent;
}(BvEvent); // Named exports
// ObserveDom config to detect changes in modal content
// so that we can adjust the modal padding if needed
var OBSERVER_CONFIG = {
subtree: true,
childList: true,
characterData: true,
attributes: true,
attributeFilter: ['style', 'class']
}; // --- Props ---
var props$W = makePropsConfigurable({
size: {
type: String,
default: 'md'
},
centered: {
type: Boolean,
default: false
},
scrollable: {
type: Boolean,
default: false
},
buttonSize: {
type: String // default: ''
},
noStacking: {
type: Boolean,
default: false
},
noFade: {
type: Boolean,
default: false
},
noCloseOnBackdrop: {
type: Boolean,
default: false
},
noCloseOnEsc: {
type: Boolean,
default: false
},
noEnforceFocus: {
type: Boolean,
default: false
},
ignoreEnforceFocusSelector: {
type: [Array, String],
default: ''
},
title: {
type: String,
default: ''
},
titleHtml: {
type: String
},
titleTag: {
type: String,
default: 'h5'
},
titleClass: {
type: [String, Array, Object] // default: null
},
titleSrOnly: {
type: Boolean,
default: false
},
ariaLabel: {
type: String // default: null
},
headerBgVariant: {
type: String // default: undefined
},
headerBorderVariant: {
type: String // default: undefined
},
headerTextVariant: {
type: String // default: undefined
},
headerCloseVariant: {
type: String // default: undefined
},
headerClass: {
type: [String, Array, Object] // default: null
},
bodyBgVariant: {
type: String // default: undefined
},
bodyTextVariant: {
type: String // default: undefined
},
modalClass: {
type: [String, Array, Object] // default: null
},
dialogClass: {
type: [String, Array, Object] // default: null
},
contentClass: {
type: [String, Array, Object] // default: null
},
bodyClass: {
type: [String, Array, Object] // default: null
},
footerBgVariant: {
type: String // default: undefined
},
footerBorderVariant: {
type: String // default: undefined
},
footerTextVariant: {
type: String // default: undefined
},
footerClass: {
type: [String, Array, Object] // default: null
},
// TODO: Rename to `noHeader` and deprecate `hideHeader`
hideHeader: {
type: Boolean,
default: false
},
// TODO: Rename to `noFooter` and deprecate `hideFooter`
hideFooter: {
type: Boolean,
default: false
},
// TODO: Rename to `noHeaderClose` and deprecate `hideHeaderClose`
hideHeaderClose: {
type: Boolean,
default: false
},
// TODO: Rename to `noBackdrop` and deprecate `hideBackdrop`
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: {
// HTML Element, CSS selector string or Vue component instance
type: [HTMLElement, String, Object],
default: null
},
headerCloseContent: {
type: String,
default: '&times;'
},
headerCloseLabel: {
type: String,
default: 'Close'
},
cancelTitle: {
type: String,
default: 'Cancel'
},
cancelTitleHtml: {
type: String
},
okTitle: {
type: String,
default: 'OK'
},
okTitleHtml: {
type: String
},
cancelVariant: {
type: String,
default: 'secondary'
},
okVariant: {
type: String,
default: 'primary'
},
lazy: {
type: Boolean,
default: false
},
busy: {
type: Boolean,
default: false
},
static: {
type: Boolean,
default: false
},
autoFocusButton: {
type: String,
default: null,
/* istanbul ignore next */
validator: function validator(value) {
return isUndefinedOrNull(value) || arrayIncludes(['ok', 'cancel', 'close'], value);
}
}
}, NAME_MODAL); // @vue/component
var BModal = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_MODAL,
mixins: [attrsMixin, idMixin, listenOnDocumentMixin, listenOnRootMixin, listenOnWindowMixin, normalizeSlotMixin, scopedStyleAttrsMixin],
inheritAttrs: false,
model: {
prop: 'visible',
event: 'change'
},
props: props$W,
data: function data() {
return {
isHidden: true,
// If modal should not be in document
isVisible: false,
// Controls modal visible state
isTransitioning: false,
// Used for style control
isShow: false,
// Used for style control
isBlock: false,
// Used for style control
isOpening: false,
// To signal that the modal is in the process of opening
isClosing: false,
// To signal that the modal is in the process of closing
ignoreBackdropClick: false,
// Used to signify if click out listener should ignore the click
isModalOverflowing: false,
return_focus: this.returnFocus || null,
// The following items are controlled by the modalManager instance
scrollbarWidth: 0,
zIndex: modalManager.getBaseZIndex(),
isTop: true,
isBodyOverflowing: false
};
},
computed: {
modalId: function modalId() {
return this.safeId();
},
modalOuterId: function modalOuterId() {
return this.safeId('__BV_modal_outer_');
},
modalHeaderId: function modalHeaderId() {
return this.safeId('__BV_modal_header_');
},
modalBodyId: function modalBodyId() {
return this.safeId('__BV_modal_body_');
},
modalTitleId: function modalTitleId() {
return this.safeId('__BV_modal_title_');
},
modalContentId: function modalContentId() {
return this.safeId('__BV_modal_content_');
},
modalFooterId: function modalFooterId() {
return this.safeId('__BV_modal_footer_');
},
modalBackdropId: function modalBackdropId() {
return this.safeId('__BV_modal_backdrop_');
},
modalClasses: function modalClasses() {
return [{
fade: !this.noFade,
show: this.isShow
}, this.modalClass];
},
modalStyles: function modalStyles() {
var sbWidth = "".concat(this.scrollbarWidth, "px");
return {
paddingLeft: !this.isBodyOverflowing && this.isModalOverflowing ? sbWidth : '',
paddingRight: this.isBodyOverflowing && !this.isModalOverflowing ? sbWidth : '',
// Needed to fix issue https://github.com/bootstrap-vue/bootstrap-vue/issues/3457
// Even though we are using v-show, we must ensure 'none' is restored in the styles
display: this.isBlock ? 'block' : 'none'
};
},
dialogClasses: function dialogClasses() {
var _ref;
return [(_ref = {}, _defineProperty(_ref, "modal-".concat(this.size), this.size), _defineProperty(_ref, 'modal-dialog-centered', this.centered), _defineProperty(_ref, 'modal-dialog-scrollable', this.scrollable), _ref), this.dialogClass];
},
headerClasses: function headerClasses() {
var _ref2;
return [(_ref2 = {}, _defineProperty(_ref2, "bg-".concat(this.headerBgVariant), this.headerBgVariant), _defineProperty(_ref2, "text-".concat(this.headerTextVariant), this.headerTextVariant), _defineProperty(_ref2, "border-".concat(this.headerBorderVariant), this.headerBorderVariant), _ref2), this.headerClass];
},
titleClasses: function titleClasses() {
return [{
'sr-only': this.titleSrOnly
}, this.titleClass];
},
bodyClasses: function bodyClasses() {
var _ref3;
return [(_ref3 = {}, _defineProperty(_ref3, "bg-".concat(this.bodyBgVariant), this.bodyBgVariant), _defineProperty(_ref3, "text-".concat(this.bodyTextVariant), this.bodyTextVariant), _ref3), this.bodyClass];
},
footerClasses: function footerClasses() {
var _ref4;
return [(_ref4 = {}, _defineProperty(_ref4, "bg-".concat(this.footerBgVariant), this.footerBgVariant), _defineProperty(_ref4, "text-".concat(this.footerTextVariant), this.footerTextVariant), _defineProperty(_ref4, "border-".concat(this.footerBorderVariant), this.footerBorderVariant), _ref4), this.footerClass];
},
modalOuterStyle: function modalOuterStyle() {
// Styles needed for proper stacking of modals
return {
position: 'absolute',
zIndex: this.zIndex
};
},
slotScope: function slotScope() {
return {
ok: this.onOk,
cancel: this.onCancel,
close: this.onClose,
hide: this.hide,
visible: this.isVisible
};
},
computeIgnoreEnforceFocusSelector: function computeIgnoreEnforceFocusSelector() {
// Normalize to an single selector with selectors separated by `,`
return concat(this.ignoreEnforceFocusSelector).filter(identity).join(',').trim();
},
computedAttrs: function computedAttrs() {
// If the parent has a scoped style attribute, and the modal
// is portalled, add the scoped attribute to the modal wrapper
var scopedStyleAttrs = !this.static ? this.scopedStyleAttrs : {};
return _objectSpread2(_objectSpread2(_objectSpread2({}, scopedStyleAttrs), this.bvAttrs), {}, {
id: this.modalOuterId
});
},
computedModalAttrs: function computedModalAttrs() {
var isVisible = this.isVisible,
ariaLabel = this.ariaLabel;
return {
id: this.modalId,
role: 'dialog',
'aria-hidden': isVisible ? null : 'true',
'aria-modal': isVisible ? 'true' : null,
'aria-label': ariaLabel,
'aria-labelledby': this.hideHeader || ariaLabel || // TODO: Rename slot to `title` and deprecate `modal-title`
!(this.hasNormalizedSlot('modal-title') || this.titleHtml || this.title) ? null : this.modalTitleId,
'aria-describedby': this.modalBodyId
};
}
},
watch: {
visible: function visible(newVal, oldVal) {
if (newVal !== oldVal) {
this[newVal ? 'show' : 'hide']();
}
}
},
created: function created() {
// Define non-reactive properties
this.$_observer = null;
},
mounted: function mounted() {
// Set initial z-index as queried from the DOM
this.zIndex = modalManager.getBaseZIndex(); // Listen for events from others to either open or close ourselves
// and listen to all modals to enable/disable enforce focus
this.listenOnRoot('bv::show::modal', this.showHandler);
this.listenOnRoot('bv::hide::modal', this.hideHandler);
this.listenOnRoot('bv::toggle::modal', this.toggleHandler); // 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.$nextTick(this.show);
}
},
beforeDestroy: function beforeDestroy() {
// Ensure everything is back to normal
this.setObserver(false);
if (this.isVisible) {
this.isVisible = false;
this.isShow = false;
this.isTransitioning = false;
}
},
methods: {
setObserver: function setObserver() {
var on = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
this.$_observer && this.$_observer.disconnect();
this.$_observer = null;
if (on) {
this.$_observer = observeDom(this.$refs.content, this.checkModalOverflow.bind(this), OBSERVER_CONFIG);
}
},
// Private method to update the v-model
updateModel: function updateModel(val) {
if (val !== this.visible) {
this.$emit('change', val);
}
},
// Private method to create a BvModalEvent object
buildEvent: function buildEvent(type) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return new BvModalEvent(type, _objectSpread2(_objectSpread2({
// Default options
cancelable: false,
target: this.$refs.modal || this.$el || null,
relatedTarget: null,
trigger: null
}, options), {}, {
// Options that can't be overridden
vueTarget: this,
componentId: this.modalId
}));
},
// Public method to show modal
show: function show() {
if (this.isVisible || this.isOpening) {
// If already open, or in the process of opening, do nothing
/* istanbul ignore next */
return;
}
/* istanbul ignore next */
if (this.isClosing) {
// If we are in the process of closing, wait until hidden before re-opening
/* istanbul ignore next */
this.$once('hidden', this.show);
/* istanbul ignore next */
return;
}
this.isOpening = true; // Set the element to return focus to when closed
this.return_focus = this.return_focus || this.getActiveElement();
var showEvt = this.buildEvent('show', {
cancelable: true
});
this.emitEvent(showEvt); // Don't show if canceled
if (showEvt.defaultPrevented || this.isVisible) {
this.isOpening = false; // Ensure the v-model reflects the current state
this.updateModel(false);
return;
} // Show the modal
this.doShow();
},
// Public method to hide modal
hide: function hide() {
var trigger = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
if (!this.isVisible || this.isClosing) {
/* istanbul ignore next */
return;
}
this.isClosing = true;
var hideEvt = this.buildEvent('hide', {
cancelable: trigger !== 'FORCE',
trigger: trigger || null
}); // We emit specific event for one of the three built-in buttons
if (trigger === 'ok') {
this.$emit('ok', hideEvt);
} else if (trigger === 'cancel') {
this.$emit('cancel', hideEvt);
} else if (trigger === 'headerclose') {
this.$emit('close', hideEvt);
}
this.emitEvent(hideEvt); // Hide if not canceled
if (hideEvt.defaultPrevented || !this.isVisible) {
this.isClosing = false; // Ensure v-model reflects current state
this.updateModel(true);
return;
} // Stop observing for content changes
this.setObserver(false); // Trigger the hide transition
this.isVisible = false; // Update the v-model
this.updateModel(false);
},
// Public method to toggle modal visibility
toggle: function toggle(triggerEl) {
if (triggerEl) {
this.return_focus = triggerEl;
}
if (this.isVisible) {
this.hide('toggle');
} else {
this.show();
}
},
// Private method to get the current document active element
getActiveElement: function getActiveElement$1() {
// Returning focus to `document.body` may cause unwanted scrolls,
// so we exclude setting focus on body
var activeElement = getActiveElement(isBrowser ? [document.body] : []); // Preset the fallback return focus value if it is not set
// `document.activeElement` should be the trigger element that was clicked or
// in the case of using the v-model, which ever element has current focus
// Will be overridden by some commands such as toggle, etc.
// Note: On IE 11, `document.activeElement` may be `null`
// So we test it for truthiness first
// https://github.com/bootstrap-vue/bootstrap-vue/issues/3206
return activeElement && activeElement.focus ? activeElement : null;
},
// Private method to finish showing modal
doShow: function doShow() {
var _this = this;
/* istanbul ignore next: commenting out for now until we can test stacking */
if (modalManager.modalsAreOpen && this.noStacking) {
// If another modal(s) is already open, wait for it(them) to close
this.listenOnRootOnce('bv::modal::hidden', this.doShow);
return;
}
modalManager.registerModal(this); // Place modal in DOM
this.isHidden = false;
this.$nextTick(function () {
// We do this in `$nextTick()` to ensure the modal is in DOM first
// before we show it
_this.isVisible = true;
_this.isOpening = false; // Update the v-model
_this.updateModel(true);
_this.$nextTick(function () {
// Observe changes in modal content and adjust if necessary
// In a `$nextTick()` in case modal content is lazy
_this.setObserver(true);
});
});
},
// Transition handlers
onBeforeEnter: function onBeforeEnter() {
this.isTransitioning = true;
this.setResizeEvent(true);
},
onEnter: function onEnter() {
var _this2 = this;
this.isBlock = true; // We add the `show` class 1 frame later
// `requestAF()` runs the callback before the next repaint, so we need
// two calls to guarantee the next frame has been rendered
requestAF(function () {
requestAF(function () {
_this2.isShow = true;
});
});
},
onAfterEnter: function onAfterEnter() {
var _this3 = this;
this.checkModalOverflow();
this.isTransitioning = false; // We use `requestAF()` to allow transition hooks to complete
// before passing control over to the other handlers
// This will allow users to not have to use `$nextTick()` or `requestAF()`
// when trying to pre-focus an element
requestAF(function () {
_this3.emitEvent(_this3.buildEvent('shown'));
_this3.setEnforceFocus(true);
_this3.$nextTick(function () {
// Delayed in a `$nextTick()` to allow users time to pre-focus
// an element if the wish
_this3.focusFirst();
});
});
},
onBeforeLeave: function onBeforeLeave() {
this.isTransitioning = true;
this.setResizeEvent(false);
this.setEnforceFocus(false);
},
onLeave: function onLeave() {
// Remove the 'show' class
this.isShow = false;
},
onAfterLeave: function onAfterLeave() {
var _this4 = this;
this.isBlock = false;
this.isTransitioning = false;
this.isModalOverflowing = false;
this.isHidden = true;
this.$nextTick(function () {
_this4.isClosing = false;
modalManager.unregisterModal(_this4);
_this4.returnFocusTo(); // TODO: Need to find a way to pass the `trigger` property
// to the `hidden` event, not just only the `hide` event
_this4.emitEvent(_this4.buildEvent('hidden'));
});
},
// Event emitter
emitEvent: function emitEvent(bvModalEvt) {
var type = bvModalEvt.type; // We emit on root first incase a global listener wants to cancel
// the event first before the instance emits its event
this.emitOnRoot("bv::modal::".concat(type), bvModalEvt, bvModalEvt.componentId);
this.$emit(type, bvModalEvt);
},
// UI event handlers
onDialogMousedown: function onDialogMousedown() {
var _this5 = this;
// Watch to see if the matching mouseup event occurs outside the dialog
// And if it does, cancel the clickOut handler
var modal = this.$refs.modal;
var onceModalMouseup = function onceModalMouseup(evt) {
eventOff(modal, 'mouseup', onceModalMouseup, EVENT_OPTIONS_NO_CAPTURE);
if (evt.target === modal) {
_this5.ignoreBackdropClick = true;
}
};
eventOn(modal, 'mouseup', onceModalMouseup, EVENT_OPTIONS_NO_CAPTURE);
},
onClickOut: function onClickOut(evt) {
if (this.ignoreBackdropClick) {
// Click was initiated inside the modal content, but finished outside.
// Set by the above onDialogMousedown handler
this.ignoreBackdropClick = false;
return;
} // Do nothing if not visible, backdrop click disabled, or element
// that generated click event is no longer in document body
if (!this.isVisible || this.noCloseOnBackdrop || !contains(document.body, evt.target)) {
return;
} // If backdrop clicked, hide modal
if (!contains(this.$refs.content, evt.target)) {
this.hide('backdrop');
}
},
onOk: function onOk() {
this.hide('ok');
},
onCancel: function onCancel() {
this.hide('cancel');
},
onClose: function onClose() {
this.hide('headerclose');
},
onEsc: function onEsc(evt) {
// If ESC pressed, hide modal
if (evt.keyCode === CODE_ESC && this.isVisible && !this.noCloseOnEsc) {
this.hide('esc');
}
},
// Document focusin listener
focusHandler: function focusHandler(evt) {
// If focus leaves modal content, bring it back
var content = this.$refs.content;
var target = evt.target;
if (this.noEnforceFocus || !this.isTop || !this.isVisible || !content || document === target || contains(content, target) || this.computeIgnoreEnforceFocusSelector && closest(this.computeIgnoreEnforceFocusSelector, target, true)) {
return;
}
var tabables = getTabables(this.$refs.content);
var _this$$refs = this.$refs,
bottomTrap = _this$$refs.bottomTrap,
topTrap = _this$$refs.topTrap;
if (bottomTrap && target === bottomTrap) {
// If user pressed TAB out of modal into our bottom trab trap element
// Find the first tabable element in the modal content and focus it
if (attemptFocus(tabables[0])) {
// Focus was successful
return;
}
} else if (topTrap && target === topTrap) {
// If user pressed CTRL-TAB out of modal and into our top tab trap element
// Find the last tabable element in the modal content and focus it
if (attemptFocus(tabables[tabables.length - 1])) {
// Focus was successful
return;
}
} // Otherwise focus the modal content container
attemptFocus(content, {
preventScroll: true
});
},
// Turn on/off focusin listener
setEnforceFocus: function setEnforceFocus(on) {
this.listenDocument(on, 'focusin', this.focusHandler);
},
// Resize listener
setResizeEvent: function setResizeEvent(on) {
this.listenWindow(on, 'resize', this.checkModalOverflow);
this.listenWindow(on, 'orientationchange', this.checkModalOverflow);
},
// Root listener handlers
showHandler: function showHandler(id, triggerEl) {
if (id === this.modalId) {
this.return_focus = triggerEl || this.getActiveElement();
this.show();
}
},
hideHandler: function hideHandler(id) {
if (id === this.modalId) {
this.hide('event');
}
},
toggleHandler: function toggleHandler(id, triggerEl) {
if (id === this.modalId) {
this.toggle(triggerEl);
}
},
modalListener: function modalListener(bvEvt) {
// If another modal opens, close this one if stacking not permitted
if (this.noStacking && bvEvt.vueTarget !== this) {
this.hide();
}
},
// Focus control handlers
focusFirst: function focusFirst() {
var _this6 = this;
// Don't try and focus if we are SSR
if (isBrowser) {
requestAF(function () {
var modal = _this6.$refs.modal;
var content = _this6.$refs.content;
var activeElement = _this6.getActiveElement(); // If the modal contains the activeElement, we don't do anything
if (modal && content && !(activeElement && contains(content, activeElement))) {
var ok = _this6.$refs['ok-button'];
var cancel = _this6.$refs['cancel-button'];
var close = _this6.$refs['close-button']; // Focus the appropriate button or modal content wrapper
var autoFocus = _this6.autoFocusButton;
/* istanbul ignore next */
var el = autoFocus === 'ok' && ok ? ok.$el || ok : autoFocus === 'cancel' && cancel ? cancel.$el || cancel : autoFocus === 'close' && close ? close.$el || close : content; // Focus the element
attemptFocus(el);
if (el === content) {
// Make sure top of modal is showing (if longer than the viewport)
_this6.$nextTick(function () {
modal.scrollTop = 0;
});
}
}
});
}
},
returnFocusTo: function returnFocusTo() {
// Prefer `returnFocus` prop over event specified
// `return_focus` value
var el = this.returnFocus || this.return_focus || null;
this.return_focus = null;
this.$nextTick(function () {
// Is el a string CSS selector?
el = isString(el) ? select(el) : el;
if (el) {
// Possibly could be a component reference
el = el.$el || el;
attemptFocus(el);
}
});
},
checkModalOverflow: function checkModalOverflow() {
if (this.isVisible) {
var modal = this.$refs.modal;
this.isModalOverflowing = modal.scrollHeight > document.documentElement.clientHeight;
}
},
makeModal: function makeModal(h) {
// Modal header
var $header = h();
if (!this.hideHeader) {
// TODO: Rename slot to `header` and deprecate `modal-header`
var $modalHeader = this.normalizeSlot('modal-header', this.slotScope);
if (!$modalHeader) {
var $closeButton = h();
if (!this.hideHeaderClose) {
$closeButton = h(BButtonClose, {
props: {
content: this.headerCloseContent,
disabled: this.isTransitioning,
ariaLabel: this.headerCloseLabel,
textVariant: this.headerCloseVariant || this.headerTextVariant
},
on: {
click: this.onClose
},
ref: 'close-button'
}, // TODO: Rename slot to `header-close` and deprecate `modal-header-close`
[this.normalizeSlot('modal-header-close')]);
}
$modalHeader = [h(this.titleTag, {
staticClass: 'modal-title',
class: this.titleClasses,
attrs: {
id: this.modalTitleId
},
// TODO: Rename slot to `title` and deprecate `modal-title`
domProps: this.hasNormalizedSlot('modal-title') ? {} : htmlOrText(this.titleHtml, this.title)
}, // TODO: Rename slot to `title` and deprecate `modal-title`
this.normalizeSlot('modal-title', this.slotScope)), $closeButton];
}
$header = h('header', {
staticClass: 'modal-header',
class: this.headerClasses,
attrs: {
id: this.modalHeaderId
},
ref: 'header'
}, [$modalHeader]);
} // Modal body
var $body = h('div', {
staticClass: 'modal-body',
class: this.bodyClasses,
attrs: {
id: this.modalBodyId
},
ref: 'body'
}, this.normalizeSlot(SLOT_NAME_DEFAULT, this.slotScope)); // Modal footer
var $footer = h();
if (!this.hideFooter) {
// TODO: Rename slot to `footer` and deprecate `modal-footer`
var $modalFooter = this.normalizeSlot('modal-footer', this.slotScope);
if (!$modalFooter) {
var $cancelButton = h();
if (!this.okOnly) {
$cancelButton = h(BButton, {
props: {
variant: this.cancelVariant,
size: this.buttonSize,
disabled: this.cancelDisabled || this.busy || this.isTransitioning
},
// TODO: Rename slot to `cancel-button` and deprecate `modal-cancel`
domProps: this.hasNormalizedSlot('modal-cancel') ? {} : htmlOrText(this.cancelTitleHtml, this.cancelTitle),
on: {
click: this.onCancel
},
ref: 'cancel-button'
}, // TODO: Rename slot to `cancel-button` and deprecate `modal-cancel`
this.normalizeSlot('modal-cancel'));
}
var $okButton = h(BButton, {
props: {
variant: this.okVariant,
size: this.buttonSize,
disabled: this.okDisabled || this.busy || this.isTransitioning
},
// TODO: Rename slot to `ok-button` and deprecate `modal-ok`
domProps: this.hasNormalizedSlot('modal-ok') ? {} : htmlOrText(this.okTitleHtml, this.okTitle),
on: {
click: this.onOk
},
ref: 'ok-button'
}, // TODO: Rename slot to `ok-button` and deprecate `modal-ok`
this.normalizeSlot('modal-ok'));
$modalFooter = [$cancelButton, $okButton];
}
$footer = h('footer', {
staticClass: 'modal-footer',
class: this.footerClasses,
attrs: {
id: this.modalFooterId
},
ref: 'footer'
}, [$modalFooter]);
} // Assemble modal content
var $modalContent = h('div', {
staticClass: 'modal-content',
class: this.contentClass,
attrs: {
id: this.modalContentId,
tabindex: '-1'
},
ref: 'content'
}, [$header, $body, $footer]); // Tab traps to prevent page from scrolling to next element in
// tab index during enforce-focus tab cycle
var $tabTrapTop = h();
var $tabTrapBottom = h();
if (this.isVisible && !this.noEnforceFocus) {
$tabTrapTop = h('span', {
ref: 'topTrap',
attrs: {
tabindex: '0'
}
});
$tabTrapBottom = h('span', {
ref: 'bottomTrap',
attrs: {
tabindex: '0'
}
});
} // Modal dialog wrapper
var $modalDialog = h('div', {
staticClass: 'modal-dialog',
class: this.dialogClasses,
on: {
mousedown: this.onDialogMousedown
},
ref: 'dialog'
}, [$tabTrapTop, $modalContent, $tabTrapBottom]); // Modal
var $modal = h('div', {
staticClass: 'modal',
class: this.modalClasses,
style: this.modalStyles,
attrs: this.computedModalAttrs,
on: {
keydown: this.onEsc,
click: this.onClickOut
},
directives: [{
name: 'show',
value: this.isVisible
}],
ref: 'modal'
}, [$modalDialog]); // Wrap modal in transition
// Sadly, we can't use `BVTransition` here due to the differences in
// transition durations for `.modal` and `.modal-dialog`
// At least until https://github.com/vuejs/vue/issues/9986 is resolved
$modal = h('transition', {
props: {
enterClass: '',
enterToClass: '',
enterActiveClass: '',
leaveClass: '',
leaveActiveClass: '',
leaveToClass: ''
},
on: {
beforeEnter: this.onBeforeEnter,
enter: this.onEnter,
afterEnter: this.onAfterEnter,
beforeLeave: this.onBeforeLeave,
leave: this.onLeave,
afterLeave: this.onAfterLeave
}
}, [$modal]); // Modal backdrop
var $backdrop = h();
if (!this.hideBackdrop && this.isVisible) {
$backdrop = h('div', {
staticClass: 'modal-backdrop',
attrs: {
id: this.modalBackdropId
}
}, // TODO: Rename slot to `backdrop` and deprecate `modal-backdrop`
this.normalizeSlot('modal-backdrop'));
}
$backdrop = h(BVTransition, {
props: {
noFade: this.noFade
}
}, [$backdrop]); // Assemble modal and backdrop in an outer <div>
return h('div', {
style: this.modalOuterStyle,
attrs: this.computedAttrs,
key: "modal-outer-".concat(this._uid)
}, [$modal, $backdrop]);
}
},
render: function render(h) {
if (this.static) {
return this.lazy && this.isHidden ? h() : this.makeModal(h);
} else {
return this.isHidden ? h() : h(BTransporterSingle, [this.makeModal(h)]);
}
}
});
var EVENT_SHOW = 'bv::show::modal'; // Prop name we use to store info on root element
var PROPERTY = '__bv_modal_directive__';
var getTarget = function getTarget(_ref) {
var _ref$modifiers = _ref.modifiers,
modifiers = _ref$modifiers === void 0 ? {} : _ref$modifiers,
arg = _ref.arg,
value = _ref.value;
// Try value, then arg, otherwise pick last modifier
return isString(value) ? value : isString(arg) ? arg : keys(modifiers).reverse()[0];
};
var getTriggerElement = function getTriggerElement(el) {
// If root element is a dropdown-item or nav-item, we
// need to target the inner link or button instead
return el && matches(el, '.dropdown-menu > li, li.nav-item') ? select('a, button', el) || el : el;
};
var setRole = function setRole(trigger) {
// Ensure accessibility on non button elements
if (trigger && trigger.tagName !== 'BUTTON') {
// Only set a role if the trigger element doesn't have one
if (!hasAttr(trigger, 'role')) {
setAttr(trigger, 'role', 'button');
} // Add a tabindex is not a button or link, and tabindex is not provided
if (trigger.tagName !== 'A' && !hasAttr(trigger, 'tabindex')) {
setAttr(trigger, 'tabindex', '0');
}
}
};
var bind$1 = function bind(el, binding, vnode) {
var target = getTarget(binding);
var trigger = getTriggerElement(el);
if (target && trigger) {
var handler = function handler(evt) {
// `currentTarget` is the element with the listener on it
var currentTarget = evt.currentTarget;
if (!isDisabled(currentTarget)) {
var type = evt.type;
var key = evt.keyCode; // Open modal only if trigger is not disabled
if (type === 'click' || type === 'keydown' && (key === CODE_ENTER || key === CODE_SPACE)) {
vnode.context.$root.$emit(EVENT_SHOW, target, currentTarget);
}
}
};
el[PROPERTY] = {
handler: handler,
target: target,
trigger: trigger
}; // If element is not a button, we add `role="button"` for accessibility
setRole(trigger); // Listen for click events
eventOn(trigger, 'click', handler, EVENT_OPTIONS_PASSIVE);
if (trigger.tagName !== 'BUTTON' && getAttr(trigger, 'role') === 'button') {
// If trigger isn't a button but has role button,
// we also listen for `keydown.space` && `keydown.enter`
eventOn(trigger, 'keydown', handler, EVENT_OPTIONS_PASSIVE);
}
}
};
var unbind$1 = function unbind(el) {
var oldProp = el[PROPERTY] || {};
var trigger = oldProp.trigger;
var handler = oldProp.handler;
if (trigger && handler) {
eventOff(trigger, 'click', handler, EVENT_OPTIONS_PASSIVE);
eventOff(trigger, 'keydown', handler, EVENT_OPTIONS_PASSIVE);
eventOff(el, 'click', handler, EVENT_OPTIONS_PASSIVE);
eventOff(el, 'keydown', handler, EVENT_OPTIONS_PASSIVE);
}
delete el[PROPERTY];
};
var componentUpdated$1 = function componentUpdated(el, binding, vnode) {
var oldProp = el[PROPERTY] || {};
var target = getTarget(binding);
var trigger = getTriggerElement(el);
if (target !== oldProp.target || trigger !== oldProp.trigger) {
// We bind and rebind if the target or trigger changes
unbind$1(el);
bind$1(el, binding, vnode);
} // If trigger element is not a button, ensure `role="button"`
// is still set for accessibility
setRole(trigger);
};
var updated = function updated() {};
/*
* Export our directive
*/
var VBModal = {
inserted: componentUpdated$1,
updated: updated,
componentUpdated: componentUpdated$1,
unbind: unbind$1
};
var PROP_NAME$1 = '$bvModal';
var PROP_NAME_PRIV = '_bv__modal'; // Base modal props that are allowed
// Some may be ignored or overridden on some message boxes
// Prop ID is allowed, but really only should be used for testing
// We need to add it in explicitly as it comes from the `idMixin`
var BASE_PROPS = ['id'].concat(_toConsumableArray(keys(omit(props$W, ['busy', 'lazy', 'noStacking', "static", 'visible'])))); // Fallback event resolver (returns undefined)
var defaultResolver = function defaultResolver() {}; // Map prop names to modal slot names
var propsToSlots = {
msgBoxContent: 'default',
title: 'modal-title',
okTitle: 'modal-ok',
cancelTitle: 'modal-cancel'
}; // --- Utility methods ---
// Method to filter only recognized props that are not undefined
var filterOptions = function filterOptions(options) {
return BASE_PROPS.reduce(function (memo, key) {
if (!isUndefined(options[key])) {
memo[key] = options[key];
}
return memo;
}, {});
}; // Method to install `$bvModal` VM injection
var plugin = function plugin(Vue) {
// Create a private sub-component that extends BModal
// which self-destructs after hidden
// @vue/component
var BMsgBox = Vue.extend({
name: NAME_MSG_BOX,
extends: BModal,
destroyed: function destroyed() {
// Make sure we not in document any more
if (this.$el && this.$el.parentNode) {
this.$el.parentNode.removeChild(this.$el);
}
},
mounted: function mounted() {
var _this = this;
// Self destruct handler
var handleDestroy = function handleDestroy() {
_this.$nextTick(function () {
// In a `requestAF()` to release control back to application
requestAF(function () {
_this.$destroy();
});
});
}; // Self destruct if parent destroyed
this.$parent.$once('hook:destroyed', handleDestroy); // Self destruct after hidden
this.$once('hidden', handleDestroy); // Self destruct on route change
/* istanbul ignore if */
if (this.$router && this.$route) {
// Destroy ourselves if route changes
/* istanbul ignore next */
this.$once('hook:beforeDestroy', this.$watch('$router', handleDestroy));
} // Show the `BMsgBox`
this.show();
}
}); // Method to generate the on-demand modal message box
// Returns a promise that resolves to a value returned by the resolve
var asyncMsgBox = function asyncMsgBox($parent, props) {
var resolver = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : defaultResolver;
if (warnNotClient(PROP_NAME$1) || warnNoPromiseSupport(PROP_NAME$1)) {
/* istanbul ignore next */
return;
} // Create an instance of `BMsgBox` component
var msgBox = new BMsgBox({
// We set parent as the local VM so these modals can emit events on
// the app `$root`, as needed by things like tooltips and popovers
// And it helps to ensure `BMsgBox` is destroyed when parent is destroyed
parent: $parent,
// Preset the prop values
propsData: _objectSpread2(_objectSpread2(_objectSpread2({}, filterOptions(getComponentConfig(NAME_MODAL))), {}, {
// Defaults that user can override
hideHeaderClose: true,
hideHeader: !(props.title || props.titleHtml)
}, omit(props, keys(propsToSlots))), {}, {
// Props that can't be overridden
lazy: false,
busy: false,
visible: false,
noStacking: false,
noEnforceFocus: false
})
}); // Convert certain props to scoped slots
keys(propsToSlots).forEach(function (prop) {
if (!isUndefined(props[prop])) {
// Can be a string, or array of VNodes.
// Alternatively, user can use HTML version of prop to pass an HTML string.
msgBox.$slots[propsToSlots[prop]] = concat(props[prop]);
}
}); // Return a promise that resolves when hidden, or rejects on destroyed
return new Promise(function (resolve, reject) {
var resolved = false;
msgBox.$once('hook:destroyed', function () {
if (!resolved) {
/* istanbul ignore next */
reject(new Error('BootstrapVue MsgBox destroyed before resolve'));
}
});
msgBox.$on('hide', function (bvModalEvt) {
if (!bvModalEvt.defaultPrevented) {
var result = resolver(bvModalEvt); // If resolver didn't cancel hide, we resolve
if (!bvModalEvt.defaultPrevented) {
resolved = true;
resolve(result);
}
}
}); // Create a mount point (a DIV) and mount the msgBo which will trigger it to show
var div = document.createElement('div');
document.body.appendChild(div);
msgBox.$mount(div);
});
}; // Private utility method to open a user defined message box and returns a promise.
// Not to be used directly by consumers, as this method may change calling syntax
var makeMsgBox = function makeMsgBox($parent, content) {
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var resolver = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
if (!content || warnNoPromiseSupport(PROP_NAME$1) || warnNotClient(PROP_NAME$1) || !isFunction(resolver)) {
/* istanbul ignore next */
return;
}
return asyncMsgBox($parent, _objectSpread2(_objectSpread2({}, filterOptions(options)), {}, {
msgBoxContent: content
}), resolver);
}; // BvModal instance class
var BvModal = /*#__PURE__*/function () {
function BvModal(vm) {
_classCallCheck(this, BvModal);
// Assign the new properties to this instance
assign(this, {
_vm: vm,
_root: vm.$root
}); // Set these properties as read-only and non-enumerable
defineProperties(this, {
_vm: readonlyDescriptor(),
_root: readonlyDescriptor()
});
} // --- Instance methods ---
// Show modal with the specified ID args are for future use
_createClass(BvModal, [{
key: "show",
value: function show(id) {
if (id && this._root) {
var _this$_root;
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
(_this$_root = this._root).$emit.apply(_this$_root, ['bv::show::modal', id].concat(args));
}
} // Hide modal with the specified ID args are for future use
}, {
key: "hide",
value: function hide(id) {
if (id && this._root) {
var _this$_root2;
for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
args[_key2 - 1] = arguments[_key2];
}
(_this$_root2 = this._root).$emit.apply(_this$_root2, ['bv::hide::modal', id].concat(args));
}
} // The following methods require Promise support!
// IE 11 and others do not support Promise natively, so users
// should have a Polyfill loaded (which they need anyways for IE 11 support)
// Open a message box with OK button only and returns a promise
}, {
key: "msgBoxOk",
value: function msgBoxOk(message) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
// Pick the modal props we support from options
var props = _objectSpread2(_objectSpread2({}, options), {}, {
// Add in overrides and our content prop
okOnly: true,
okDisabled: false,
hideFooter: false,
msgBoxContent: message
});
return makeMsgBox(this._vm, message, props, function () {
// Always resolve to true for OK
return true;
});
} // Open a message box modal with OK and CANCEL buttons
// and returns a promise
}, {
key: "msgBoxConfirm",
value: function msgBoxConfirm(message) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
// Set the modal props we support from options
var props = _objectSpread2(_objectSpread2({}, options), {}, {
// Add in overrides and our content prop
okOnly: false,
okDisabled: false,
cancelDisabled: false,
hideFooter: false
});
return makeMsgBox(this._vm, message, props, function (bvModalEvt) {
var trigger = bvModalEvt.trigger;
return trigger === 'ok' ? true : trigger === 'cancel' ? false : null;
});
}
}]);
return BvModal;
}(); // Add our instance mixin
Vue.mixin({
beforeCreate: function beforeCreate() {
// Because we need access to `$root` for `$emits`, and VM for parenting,
// we have to create a fresh instance of `BvModal` for each VM
this[PROP_NAME_PRIV] = new BvModal(this);
}
}); // Define our read-only `$bvModal` instance property
// Placed in an if just in case in HMR mode
if (!hasOwnProperty(Vue.prototype, PROP_NAME$1)) {
defineProperty(Vue.prototype, PROP_NAME$1, {
get: function get() {
/* istanbul ignore next */
if (!this || !this[PROP_NAME_PRIV]) {
warn("\"".concat(PROP_NAME$1, "\" must be accessed from a Vue instance \"this\" context."), NAME_MODAL);
}
return this[PROP_NAME_PRIV];
}
});
}
};
var BVModalPlugin = /*#__PURE__*/pluginFactory({
plugins: {
plugin: plugin
}
});
var ModalPlugin = /*#__PURE__*/pluginFactory({
components: {
BModal: BModal
},
directives: {
VBModal: VBModal
},
// $bvModal injection
plugins: {
BVModalPlugin: BVModalPlugin
}
});
var props$X = makePropsConfigurable({
tag: {
type: String,
default: 'ul'
},
fill: {
type: Boolean,
default: false
},
justified: {
type: Boolean,
default: false
},
align: {
type: String // default: null
},
tabs: {
type: Boolean,
default: false
},
pills: {
type: Boolean,
default: false
},
vertical: {
type: Boolean,
default: false
},
small: {
type: Boolean,
default: false
},
cardHeader: {
// Set to true if placing in a card header
type: Boolean,
default: false
}
}, NAME_NAV); // -- Utils --
var computeJustifyContent = function computeJustifyContent(value) {
// Normalize value
value = value === 'left' ? 'start' : value === 'right' ? 'end' : value;
return "justify-content-".concat(value);
}; // @vue/component
var BNav = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_NAV,
functional: true,
props: props$X,
render: function render(h, _ref) {
var _class;
var props = _ref.props,
data = _ref.data,
children = _ref.children;
return h(props.tag, a(data, {
staticClass: 'nav',
class: (_class = {
'nav-tabs': props.tabs,
'nav-pills': props.pills && !props.tabs,
'card-header-tabs': !props.vertical && props.cardHeader && props.tabs,
'card-header-pills': !props.vertical && props.cardHeader && props.pills && !props.tabs,
'flex-column': props.vertical,
'nav-fill': !props.vertical && props.fill,
'nav-justified': !props.vertical && props.justified
}, _defineProperty(_class, computeJustifyContent(props.align), !props.vertical && props.align), _defineProperty(_class, "small", props.small), _class)
}), children);
}
});
var props$Y = makePropsConfigurable(_objectSpread2(_objectSpread2({}, omit(props$1, ['event', 'routerTag'])), {}, {
linkAttrs: {
type: Object,
default: function _default() {}
},
linkClasses: {
type: [String, Object, Array],
default: null
}
}), NAME_NAV_ITEM); // --- Main component ---
// @vue/component
var BNavItem = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_NAV_ITEM,
functional: true,
props: props$Y,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
listeners = _ref.listeners,
children = _ref.children;
// We transfer the listeners to the link
delete data.on;
return h('li', a(data, {
staticClass: 'nav-item'
}), [h(BLink, {
staticClass: 'nav-link',
class: props.linkClasses,
attrs: props.linkAttrs,
props: props,
on: listeners
}, children)]);
}
});
var props$Z = {}; // @vue/component
var BNavText = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_NAV_TEXT,
functional: true,
props: props$Z,
render: function render(h, _ref) {
var data = _ref.data,
children = _ref.children;
return h('li', a(data, {
staticClass: 'navbar-text'
}), children);
}
});
var props$_ = makePropsConfigurable(_objectSpread2(_objectSpread2({}, omit(props$s, ['inline'])), {}, {
formClass: {
type: [String, Array, Object] // default: null
}
}), NAME_NAV_FORM); // @vue/component
var BNavForm = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_NAV_FORM,
functional: true,
props: props$_,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children,
_ref$listeners = _ref.listeners,
listeners = _ref$listeners === void 0 ? {} : _ref$listeners;
var attrs = data.attrs; // The following data properties are cleared out
// as they will be passed to BForm directly
data.attrs = {};
data.on = {};
var $form = h(BForm, {
class: props.formClass,
props: _objectSpread2(_objectSpread2({}, props), {}, {
inline: true
}),
attrs: attrs,
on: listeners
}, children);
return h('li', a(data, {
staticClass: 'form-inline'
}), [$form]);
}
});
var props$$ = makePropsConfigurable(pluckProps(['text', 'html', 'menuClass', 'toggleClass', 'noCaret', 'role', 'lazy'], props$n), NAME_NAV_ITEM_DROPDOWN); // --- Main component ---
// @vue/component
var BNavItemDropdown = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_NAV_ITEM_DROPDOWN,
mixins: [idMixin, dropdownMixin, normalizeSlotMixin],
props: props$$,
computed: {
toggleId: function toggleId() {
return this.safeId('_BV_toggle_');
},
dropdownClasses: function dropdownClasses() {
return [this.directionClass, this.boundaryClass, {
show: this.visible
}];
},
menuClasses: function menuClasses() {
return [this.menuClass, {
'dropdown-menu-right': this.right,
show: this.visible
}];
},
toggleClasses: function toggleClasses() {
return [this.toggleClass, {
'dropdown-toggle-no-caret': this.noCaret
}];
}
},
render: function render(h) {
var toggleId = this.toggleId,
visible = this.visible;
var $toggle = h(BLink, {
staticClass: 'nav-link dropdown-toggle',
class: this.toggleClasses,
props: {
href: "#".concat(this.id || ''),
disabled: this.disabled
},
attrs: {
id: toggleId,
role: 'button',
'aria-haspopup': 'true',
'aria-expanded': visible ? 'true' : 'false'
},
on: {
mousedown: this.onMousedown,
click: this.toggle,
keydown: this.toggle // Handle ENTER, SPACE and DOWN
},
ref: 'toggle'
}, [// TODO: The `text` slot is deprecated in favor of the `button-content` slot
this.normalizeSlot([SLOT_NAME_BUTTON_CONTENT, SLOT_NAME_TEXT]) || h('span', {
domProps: htmlOrText(this.html, this.text)
})]);
var $menu = h('ul', {
staticClass: 'dropdown-menu',
class: this.menuClasses,
attrs: {
tabindex: '-1',
'aria-labelledby': toggleId
},
on: {
keydown: this.onKeydown // Handle UP, DOWN and ESC
},
ref: 'menu'
}, !this.lazy || visible ? this.normalizeSlot(SLOT_NAME_DEFAULT, {
hide: this.hide
}) : [h()]);
return h('li', {
staticClass: 'nav-item b-nav-dropdown dropdown',
class: this.dropdownClasses,
attrs: {
id: this.safeId()
}
}, [$toggle, $menu]);
}
});
var NavPlugin = /*#__PURE__*/pluginFactory({
components: {
BNav: BNav,
BNavItem: BNavItem,
BNavText: BNavText,
BNavForm: BNavForm,
BNavItemDropdown: BNavItemDropdown,
BNavItemDd: BNavItemDropdown,
BNavDropdown: BNavItemDropdown,
BNavDd: BNavItemDropdown
},
plugins: {
DropdownPlugin: DropdownPlugin
}
});
var props$10 = makePropsConfigurable({
tag: {
type: String,
default: 'nav'
},
type: {
type: String,
default: 'light'
},
variant: {
type: String // default: undefined
},
toggleable: {
type: [Boolean, String],
default: false
},
fixed: {
type: String
},
sticky: {
type: Boolean,
default: false
},
print: {
type: Boolean,
default: false
}
}, NAME_NAVBAR); // --- Main component ---
// @vue/component
var BNavbar = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_NAVBAR,
mixins: [normalizeSlotMixin],
provide: function provide() {
return {
bvNavbar: this
};
},
props: props$10,
computed: {
breakpointClass: function breakpointClass() {
var breakpoint = null;
var xs = getBreakpoints()[0];
var toggleable = this.toggleable;
if (toggleable && isString(toggleable) && toggleable !== xs) {
breakpoint = "navbar-expand-".concat(toggleable);
} else if (toggleable === false) {
breakpoint = 'navbar-expand';
}
return breakpoint;
}
},
render: function render(h) {
var _ref;
return h(this.tag, {
staticClass: 'navbar',
class: [(_ref = {
'd-print': this.print,
'sticky-top': this.sticky
}, _defineProperty(_ref, "navbar-".concat(this.type), this.type), _defineProperty(_ref, "bg-".concat(this.variant), this.variant), _defineProperty(_ref, "fixed-".concat(this.fixed), this.fixed), _ref), this.breakpointClass],
attrs: {
role: isTag(this.tag, 'nav') ? null : 'navigation'
}
}, [this.normalizeSlot()]);
}
});
var props$11 = makePropsConfigurable(pluckProps(['tag', 'fill', 'justified', 'align', 'small'], props$X), NAME_NAVBAR_NAV); // -- Utils --
var computeJustifyContent$1 = function computeJustifyContent(value) {
// Normalize value
value = value === 'left' ? 'start' : value === 'right' ? 'end' : value;
return "justify-content-".concat(value);
}; // @vue/component
var BNavbarNav = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_NAVBAR_NAV,
functional: true,
props: props$11,
render: function render(h, _ref) {
var _class;
var props = _ref.props,
data = _ref.data,
children = _ref.children;
return h(props.tag, a(data, {
staticClass: 'navbar-nav',
class: (_class = {
'nav-fill': props.fill,
'nav-justified': props.justified
}, _defineProperty(_class, computeJustifyContent$1(props.align), props.align), _defineProperty(_class, "small", props.small), _class)
}), children);
}
});
var linkProps$4 = omit(props$1, ['event', 'routerTag']);
linkProps$4.href.default = undefined;
linkProps$4.to.default = undefined;
var props$12 = makePropsConfigurable(_objectSpread2({
tag: {
type: String,
default: 'div'
}
}, linkProps$4), NAME_NAVBAR_BRAND); // --- Main component ---
// @vue/component
var BNavbarBrand = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_NAVBAR_BRAND,
functional: true,
props: props$12,
render: function render(h, _ref) {
var props = _ref.props,
data = _ref.data,
children = _ref.children;
var isLink = props.to || props.href;
var tag = isLink ? BLink : props.tag;
return h(tag, a(data, {
staticClass: 'navbar-brand',
props: isLink ? pluckProps(linkProps$4, props) : {}
}), children);
}
});
var CLASS_NAME$2 = 'navbar-toggler'; // --- Main component ---
// @vue/component
var BNavbarToggle = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_NAVBAR_TOGGLE,
directives: {
VBToggle: VBToggle
},
mixins: [listenOnRootMixin, normalizeSlotMixin],
props: makePropsConfigurable({
label: {
type: String,
default: 'Toggle navigation'
},
target: {
type: [Array, String],
required: true
},
disabled: {
type: Boolean,
default: false
}
}, NAME_NAVBAR_TOGGLE),
data: function data() {
return {
toggleState: false
};
},
created: function created() {
this.listenOnRoot(EVENT_STATE, this.handleStateEvt);
this.listenOnRoot(EVENT_STATE_SYNC, this.handleStateEvt);
},
methods: {
onClick: function onClick(evt) {
if (!this.disabled) {
// Emit courtesy `click` event
this.$emit('click', evt);
}
},
handleStateEvt: function handleStateEvt(id, state) {
// We listen for state events so that we can pass the
// boolean expanded state to the default scoped slot
if (id === this.target) {
this.toggleState = state;
}
}
},
render: function render(h) {
var disabled = this.disabled;
return h('button', {
staticClass: CLASS_NAME$2,
class: {
disabled: disabled
},
directives: [{
name: 'VBToggle',
value: this.target
}],
attrs: {
type: 'button',
disabled: disabled,
'aria-label': this.label
},
on: {
click: this.onClick
}
}, [this.normalizeSlot(SLOT_NAME_DEFAULT, {
expanded: this.toggleState
}) || h('span', {
staticClass: "".concat(CLASS_NAME$2, "-icon")
})]);
}
});
var NavbarPlugin = /*#__PURE__*/pluginFactory({
components: {
BNavbar: BNavbar,
BNavbarNav: BNavbarNav,
BNavbarBrand: BNavbarBrand,
BNavbarToggle: BNavbarToggle,
BNavToggle: BNavbarToggle
},
plugins: {
NavPlugin: NavPlugin,
CollapsePlugin: CollapsePlugin,
DropdownPlugin: DropdownPlugin
}
});
var BSpinner = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_SPINNER,
functional: true,
props: makePropsConfigurable({
type: {
type: String,
default: 'border' // SCSS currently supports 'border' or 'grow'
},
label: {
type: String // default: null
},
variant: {
type: String // default: undefined
},
small: {
type: Boolean,
default: false
},
role: {
type: String,
default: 'status'
},
tag: {
type: String,
default: 'span'
}
}, NAME_SPINNER),
render: function render(h, _ref) {
var _class;
var props = _ref.props,
data = _ref.data,
slots = _ref.slots,
scopedSlots = _ref.scopedSlots;
var $slots = slots();
var $scopedSlots = scopedSlots || {};
var label = normalizeSlot(SLOT_NAME_LABEL, {}, $scopedSlots, $slots) || props.label;
if (label) {
label = h('span', {
staticClass: 'sr-only'
}, label);
}
return h(props.tag, a(data, {
attrs: {
role: label ? props.role || 'status' : null,
'aria-hidden': label ? null : 'true'
},
class: (_class = {}, _defineProperty(_class, "spinner-".concat(props.type), props.type), _defineProperty(_class, "spinner-".concat(props.type, "-sm"), props.small), _defineProperty(_class, "text-".concat(props.variant), props.variant), _class)
}), [label || h()]);
}
});
var positionCover = {
top: 0,
left: 0,
bottom: 0,
right: 0
};
var BOverlay = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_OVERLAY,
mixins: [normalizeSlotMixin],
props: makePropsConfigurable({
show: {
type: Boolean,
default: false
},
variant: {
type: String,
default: 'light'
},
bgColor: {
// Alternative to variant, allowing a specific
// CSS color to be applied to the overlay
type: String // default: null
},
opacity: {
type: [Number, String],
default: 0.85,
validator: function validator(value) {
var number = toFloat(value, 0);
return number >= 0 && number <= 1;
}
},
blur: {
type: String,
default: '2px'
},
rounded: {
type: [Boolean, String],
default: false
},
noCenter: {
type: Boolean,
default: false
},
noFade: {
type: Boolean,
default: false
},
spinnerType: {
type: String,
default: 'border'
},
spinnerVariant: {
type: String // default: null
},
spinnerSmall: {
type: Boolean,
default: false
},
overlayTag: {
type: String,
default: 'div'
},
wrapTag: {
type: String,
default: 'div'
},
noWrap: {
// If set, does not render the default slot
// and switches to absolute positioning
type: Boolean,
default: false
},
fixed: {
type: Boolean,
default: false
},
zIndex: {
type: [Number, String],
default: 10
}
}, NAME_OVERLAY),
computed: {
computedRounded: function computedRounded() {
var rounded = this.rounded;
return rounded === true || rounded === '' ? 'rounded' : !rounded ? '' : "rounded-".concat(rounded);
},
computedVariant: function computedVariant() {
return this.variant && !this.bgColor ? "bg-".concat(this.variant) : '';
},
overlayScope: function overlayScope() {
return {
spinnerType: this.spinnerType || null,
spinnerVariant: this.spinnerVariant || null,
spinnerSmall: this.spinnerSmall
};
}
},
methods: {
defaultOverlayFn: function defaultOverlayFn(_ref) {
var spinnerType = _ref.spinnerType,
spinnerVariant = _ref.spinnerVariant,
spinnerSmall = _ref.spinnerSmall;
return this.$createElement(BSpinner, {
props: {
type: spinnerType,
variant: spinnerVariant,
small: spinnerSmall
}
});
}
},
render: function render(h) {
var _this = this;
var $overlay = h();
if (this.show) {
var scope = this.overlayScope; // Overlay backdrop
var $background = h('div', {
staticClass: 'position-absolute',
class: [this.computedVariant, this.computedRounded],
style: _objectSpread2(_objectSpread2({}, positionCover), {}, {
opacity: this.opacity,
backgroundColor: this.bgColor || null,
backdropFilter: this.blur ? "blur(".concat(this.blur, ")") : null
})
}); // Overlay content
var $content = h('div', {
staticClass: 'position-absolute',
style: this.noCenter ?
/* istanbul ignore next */
_objectSpread2({}, positionCover) : {
top: '50%',
left: '50%',
transform: 'translateX(-50%) translateY(-50%)'
}
}, [this.normalizeSlot('overlay', scope) || this.defaultOverlayFn(scope)]); // Overlay positioning
$overlay = h(this.overlayTag, {
key: 'overlay',
staticClass: 'b-overlay',
class: {
'position-absolute': !this.noWrap || this.noWrap && !this.fixed,
'position-fixed': this.noWrap && this.fixed
},
style: _objectSpread2(_objectSpread2({}, positionCover), {}, {
zIndex: this.zIndex || 10
}),
on: {
click: function click(evt) {
return _this.$emit('click', evt);
}
}
}, [$background, $content]);
} // Wrap in a fade transition
$overlay = h(BVTransition, {
props: {
noFade: this.noFade,
appear: true
},
on: {
'after-enter': function afterEnter() {
return _this.$emit('shown');
},
'after-leave': function afterLeave() {
return _this.$emit('hidden');
}
}
}, [$overlay]);
if (this.noWrap) {
return $overlay;
}
return h(this.wrapTag, {
staticClass: 'b-overlay-wrap position-relative',
attrs: {
'aria-busy': this.show ? 'true' : null
}
}, this.noWrap ? [$overlay] : [this.normalizeSlot(), $overlay]);
}
});
var OverlayPlugin = /*#__PURE__*/pluginFactory({
components: {
BOverlay: BOverlay
}
});
/**
* @param {number} length
* @return {Array}
*/
var range = function range(length) {
return Array.apply(null, {
length: length
});
};
// for `<b-pagination>` and `<b-pagination-nav>`
// --- Constants ---
// Threshold of limit size when we start/stop showing ellipsis
var ELLIPSIS_THRESHOLD = 3; // Default # of buttons limit
var DEFAULT_LIMIT = 5; // --- Helper methods ---
// Make an array of N to N+X
var makePageArray = function makePageArray(startNumber, numberOfPages) {
return range(numberOfPages).map(function (val, i) {
return {
number: startNumber + i,
classes: null
};
});
}; // Sanitize the provided limit value (converting to a number)
var sanitizeLimit = function sanitizeLimit(val) {
var limit = toInteger(val) || 1;
return limit < 1 ? DEFAULT_LIMIT : limit;
}; // Sanitize the provided current page number (converting to a number)
var sanitizeCurrentPage = function sanitizeCurrentPage(val, numberOfPages) {
var page = toInteger(val) || 1;
return page > numberOfPages ? numberOfPages : page < 1 ? 1 : page;
}; // Links don't normally respond to SPACE, so we add that
// functionality via this handler
var onSpaceKey = function onSpaceKey(evt) {
if (evt.keyCode === CODE_SPACE) {
// Stop page from scrolling
stopEvent(evt, {
immediatePropagation: true
}); // Trigger the click event on the link
evt.currentTarget.click();
return false;
}
}; // --- Props ---
var props$13 = makePropsConfigurable({
disabled: {
type: Boolean,
default: false
},
value: {
type: [Number, String],
default: null,
/* istanbul ignore next */
validator: function validator(value) {
if (!isNull(value) && toInteger(value, 0) < 1) {
warn('"v-model" value must be a number greater than "0"', NAME_PAGINATION);
return false;
}
return true;
}
},
limit: {
type: [Number, String],
default: DEFAULT_LIMIT,
/* istanbul ignore next */
validator: function validator(value) {
if (toInteger(value, 0) < 1) {
warn('Prop "limit" must be a number greater than "0"', NAME_PAGINATION);
return false;
}
return true;
}
},
align: {
type: String,
default: 'left'
},
pills: {
type: Boolean,
default: false
},
hideGotoEndButtons: {
type: Boolean,
default: false
},
ariaLabel: {
type: String,
default: 'Pagination'
},
labelFirstPage: {
type: String,
default: 'Go to first page'
},
firstText: {
type: String,
default: "\xAB" // '«'
},
firstNumber: {
type: Boolean,
default: false
},
firstClass: {
type: [String, Array, Object],
default: null
},
labelPrevPage: {
type: String,
default: 'Go to previous page'
},
prevText: {
type: String,
default: "\u2039" // '‹'
},
prevClass: {
type: [String, Array, Object],
default: null
},
labelNextPage: {
type: String,
default: 'Go to next page'
},
nextText: {
type: String,
default: "\u203A" // '›'
},
nextClass: {
type: [String, Array, Object] // default: null
},
labelLastPage: {
type: String,
default: 'Go to last page'
},
lastText: {
type: String,
default: "\xBB" // '»'
},
lastNumber: {
type: Boolean,
default: false
},
lastClass: {
type: [String, Array, Object] // default: null
},
labelPage: {
type: [String, Function],
default: 'Go to page'
},
pageClass: {
type: [String, Array, Object] // default: null
},
hideEllipsis: {
type: Boolean,
default: false
},
ellipsisText: {
type: String,
default: "\u2026" // '…'
},
ellipsisClass: {
type: [String, Array, Object] // default: null
}
}, NAME_PAGINATION); // --- Mixin ---
// @vue/component
var paginationMixin = {
mixins: [normalizeSlotMixin],
model: {
prop: 'value',
event: 'input'
},
props: props$13,
data: function data() {
// `-1` signifies no page initially selected
var currentPage = toInteger(this.value, 0);
currentPage = currentPage > 0 ? currentPage : -1;
return {
currentPage: currentPage,
localNumberOfPages: 1,
localLimit: DEFAULT_LIMIT
};
},
computed: {
btnSize: function btnSize() {
return this.size ? "pagination-".concat(this.size) : '';
},
alignment: function alignment() {
var align = this.align;
if (align === 'center') {
return 'justify-content-center';
} else if (align === 'end' || align === 'right') {
return 'justify-content-end';
} else if (align === 'fill') {
// The page-items will also have 'flex-fill' added
// We add text centering to make the button appearance better in fill mode
return 'text-center';
}
return '';
},
styleClass: function styleClass() {
return this.pills ? 'b-pagination-pills' : '';
},
computedCurrentPage: function computedCurrentPage() {
return sanitizeCurrentPage(this.currentPage, this.localNumberOfPages);
},
paginationParams: function paginationParams() {
// Determine if we should show the the ellipsis
var limit = this.localLimit,
numberOfPages = this.localNumberOfPages,
currentPage = this.computedCurrentPage,
hideEllipsis = this.hideEllipsis,
firstNumber = this.firstNumber,
lastNumber = this.lastNumber;
var showFirstDots = false;
var showLastDots = false;
var numberOfLinks = limit;
var startNumber = 1;
if (numberOfPages <= limit) {
// Special case: Less pages available than the limit of displayed pages
numberOfLinks = numberOfPages;
} else if (currentPage < limit - 1 && limit > ELLIPSIS_THRESHOLD) {
if (!hideEllipsis || lastNumber) {
showLastDots = true;
numberOfLinks = limit - (firstNumber ? 0 : 1);
}
numberOfLinks = mathMin(numberOfLinks, limit);
} else if (numberOfPages - currentPage + 2 < limit && limit > ELLIPSIS_THRESHOLD) {
if (!hideEllipsis || firstNumber) {
showFirstDots = true;
numberOfLinks = limit - (lastNumber ? 0 : 1);
}
startNumber = numberOfPages - numberOfLinks + 1;
} else {
// We are somewhere in the middle of the page list
if (limit > ELLIPSIS_THRESHOLD) {
numberOfLinks = limit - (hideEllipsis ? 0 : 2);
showFirstDots = !!(!hideEllipsis || firstNumber);
showLastDots = !!(!hideEllipsis || lastNumber);
}
startNumber = currentPage - mathFloor(numberOfLinks / 2);
} // Sanity checks
/* istanbul ignore if */
if (startNumber < 1) {
startNumber = 1;
showFirstDots = false;
} else if (startNumber > numberOfPages - numberOfLinks) {
startNumber = numberOfPages - numberOfLinks + 1;
showLastDots = false;
}
if (showFirstDots && firstNumber && startNumber < 4) {
numberOfLinks = numberOfLinks + 2;
startNumber = 1;
showFirstDots = false;
}
var lastPageNumber = startNumber + numberOfLinks - 1;
if (showLastDots && lastNumber && lastPageNumber > numberOfPages - 3) {
numberOfLinks = numberOfLinks + (lastPageNumber === numberOfPages - 2 ? 2 : 3);
showLastDots = false;
} // Special handling for lower limits (where ellipsis are never shown)
if (limit <= ELLIPSIS_THRESHOLD) {
if (firstNumber && startNumber === 1) {
numberOfLinks = mathMin(numberOfLinks + 1, numberOfPages, limit + 1);
} else if (lastNumber && numberOfPages === startNumber + numberOfLinks - 1) {
startNumber = mathMax(startNumber - 1, 1);
numberOfLinks = mathMin(numberOfPages - startNumber + 1, numberOfPages, limit + 1);
}
}
numberOfLinks = mathMin(numberOfLinks, numberOfPages - startNumber + 1);
return {
showFirstDots: showFirstDots,
showLastDots: showLastDots,
numberOfLinks: numberOfLinks,
startNumber: startNumber
};
},
pageList: function pageList() {
// Generates the pageList array
var _this$paginationParam = this.paginationParams,
numberOfLinks = _this$paginationParam.numberOfLinks,
startNumber = _this$paginationParam.startNumber;
var currentPage = this.computedCurrentPage; // Generate list of page numbers
var pages = makePageArray(startNumber, numberOfLinks); // We limit to a total of 3 page buttons on XS screens
// So add classes to page links to hide them for XS breakpoint
// Note: Ellipsis will also be hidden on XS screens
// TODO: Make this visual limit configurable based on breakpoint(s)
if (pages.length > 3) {
var idx = currentPage - startNumber; // THe following is a bootstrap-vue custom utility class
var classes = 'bv-d-xs-down-none';
if (idx === 0) {
// Keep leftmost 3 buttons visible when current page is first page
for (var i = 3; i < pages.length; i++) {
pages[i].classes = classes;
}
} else if (idx === pages.length - 1) {
// Keep rightmost 3 buttons visible when current page is last page
for (var _i = 0; _i < pages.length - 3; _i++) {
pages[_i].classes = classes;
}
} else {
// Hide all except current page, current page - 1 and current page + 1
for (var _i2 = 0; _i2 < idx - 1; _i2++) {
// hide some left button(s)
pages[_i2].classes = classes;
}
for (var _i3 = pages.length - 1; _i3 > idx + 1; _i3--) {
// hide some right button(s)
pages[_i3].classes = classes;
}
}
}
return pages;
}
},
watch: {
value: function value(newValue, oldValue) {
if (newValue !== oldValue) {
this.currentPage = sanitizeCurrentPage(newValue, this.localNumberOfPages);
}
},
currentPage: function currentPage(newValue, oldValue) {
if (newValue !== oldValue) {
// Emit `null` if no page selected
this.$emit('input', newValue > 0 ? newValue : null);
}
},
limit: function limit(newValue, oldValue) {
if (newValue !== oldValue) {
this.localLimit = sanitizeLimit(newValue);
}
}
},
created: function created() {
var _this = this;
// Set our default values in data
this.localLimit = sanitizeLimit(this.limit);
this.$nextTick(function () {
// Sanity check
_this.currentPage = _this.currentPage > _this.localNumberOfPages ? _this.localNumberOfPages : _this.currentPage;
});
},
methods: {
handleKeyNav: function handleKeyNav(evt) {
var keyCode = evt.keyCode,
shiftKey = evt.shiftKey;
/* istanbul ignore if */
if (this.isNav) {
// We disable left/right keyboard navigation in `<b-pagination-nav>`
return;
}
if (keyCode === CODE_LEFT || keyCode === CODE_UP) {
stopEvent(evt, {
propagation: false
});
shiftKey ? this.focusFirst() : this.focusPrev();
} else if (keyCode === CODE_RIGHT || keyCode === CODE_DOWN) {
stopEvent(evt, {
propagation: false
});
shiftKey ? this.focusLast() : this.focusNext();
}
},
getButtons: function getButtons() {
// Return only buttons that are visible
return selectAll('button.page-link, a.page-link', this.$el).filter(function (btn) {
return isVisible(btn);
});
},
focusCurrent: function focusCurrent() {
var _this2 = this;
// We do this in `$nextTick()` to ensure buttons have finished rendering
this.$nextTick(function () {
var btn = _this2.getButtons().find(function (el) {
return toInteger(getAttr(el, 'aria-posinset'), 0) === _this2.computedCurrentPage;
});
if (!attemptFocus(btn)) {
// Fallback if current page is not in button list
_this2.focusFirst();
}
});
},
focusFirst: function focusFirst() {
var _this3 = this;
// We do this in `$nextTick()` to ensure buttons have finished rendering
this.$nextTick(function () {
var btn = _this3.getButtons().find(function (el) {
return !isDisabled(el);
});
attemptFocus(btn);
});
},
focusLast: function focusLast() {
var _this4 = this;
// We do this in `$nextTick()` to ensure buttons have finished rendering
this.$nextTick(function () {
var btn = _this4.getButtons().reverse().find(function (el) {
return !isDisabled(el);
});
attemptFocus(btn);
});
},
focusPrev: function focusPrev() {
var _this5 = this;
// We do this in `$nextTick()` to ensure buttons have finished rendering
this.$nextTick(function () {
var buttons = _this5.getButtons();
var index = buttons.indexOf(getActiveElement());
if (index > 0 && !isDisabled(buttons[index - 1])) {
attemptFocus(buttons[index - 1]);
}
});
},
focusNext: function focusNext() {
var _this6 = this;
// We do this in `$nextTick()` to ensure buttons have finished rendering
this.$nextTick(function () {
var buttons = _this6.getButtons();
var index = buttons.indexOf(getActiveElement());
if (index < buttons.length - 1 && !isDisabled(buttons[index + 1])) {
attemptFocus(buttons[index + 1]);
}
});
}
},
render: function render(h) {
var _this7 = this;
var buttons = [];
var numberOfPages = this.localNumberOfPages;
var pageNumbers = this.pageList.map(function (p) {
return p.number;
});
var disabled = this.disabled;
var _this$paginationParam2 = this.paginationParams,
showFirstDots = _this$paginationParam2.showFirstDots,
showLastDots = _this$paginationParam2.showLastDots;
var currentPage = this.computedCurrentPage;
var fill = this.align === 'fill'; // Used to control what type of aria attributes are rendered and wrapper
var isNav = this.isNav; // Helper function and flag
var isActivePage = function isActivePage(pageNumber) {
return pageNumber === currentPage;
};
var noCurrentPage = this.currentPage < 1; // Factory function for prev/next/first/last buttons
var makeEndBtn = function makeEndBtn(linkTo, ariaLabel, btnSlot, btnText, btnClass, pageTest, key) {
var isDisabled = disabled || isActivePage(pageTest) || noCurrentPage || linkTo < 1 || linkTo > numberOfPages;
var pageNumber = linkTo < 1 ? 1 : linkTo > numberOfPages ? numberOfPages : linkTo;
var scope = {
disabled: isDisabled,
page: pageNumber,
index: pageNumber - 1
};
var $btnContent = _this7.normalizeSlot(btnSlot, scope) || toString$1(btnText) || h();
var $inner = h(isDisabled ? 'span' : isNav ? BLink : 'button', {
staticClass: 'page-link',
class: {
'flex-grow-1': !isNav && !isDisabled && fill
},
props: isDisabled || !isNav ? {} : _this7.linkProps(linkTo),
attrs: {
role: isNav ? null : 'menuitem',
type: isNav || isDisabled ? null : 'button',
tabindex: isDisabled || isNav ? null : '-1',
'aria-label': ariaLabel,
'aria-controls': _this7.ariaControls || null,
'aria-disabled': isDisabled ? 'true' : null
},
on: isDisabled ? {} : {
'!click': function click(evt) {
_this7.onClick(evt, linkTo);
},
keydown: onSpaceKey
}
}, [$btnContent]);
return h('li', {
key: key,
staticClass: 'page-item',
class: [{
disabled: isDisabled,
'flex-fill': fill,
'd-flex': fill && !isNav && !isDisabled
}, btnClass],
attrs: {
role: isNav ? null : 'presentation',
'aria-hidden': isDisabled ? 'true' : null
}
}, [$inner]);
}; // Ellipsis factory
var makeEllipsis = function makeEllipsis(isLast) {
return h('li', {
key: "ellipsis-".concat(isLast ? 'last' : 'first'),
staticClass: 'page-item',
class: ['disabled', 'bv-d-xs-down-none', fill ? 'flex-fill' : '', _this7.ellipsisClass],
attrs: {
role: 'separator'
}
}, [h('span', {
staticClass: 'page-link'
}, [_this7.normalizeSlot('ellipsis-text') || toString$1(_this7.ellipsisText) || h()])]);
}; // Page button factory
var makePageButton = function makePageButton(page, idx) {
var active = isActivePage(page.number) && !noCurrentPage; // Active page will have tabindex of 0, or if no current page and first page button
var tabIndex = disabled ? null : active || noCurrentPage && idx === 0 ? '0' : '-1';
var attrs = {
role: isNav ? null : 'menuitemradio',
type: isNav || disabled ? null : 'button',
'aria-disabled': disabled ? 'true' : null,
'aria-controls': _this7.ariaControls || null,
'aria-label': isFunction(_this7.labelPage) && !isUndefined(_this7.labelPage(page.number)) ?
/* istanbul ignore next */
_this7.labelPage(page.number) : "".concat(_this7.labelPage, " ").concat(page.number),
'aria-checked': isNav ? null : active ? 'true' : 'false',
'aria-current': isNav && active ? 'page' : null,
'aria-posinset': isNav ? null : page.number,
'aria-setsize': isNav ? null : numberOfPages,
// ARIA "roving tabindex" method (except in `isNav` mode)
tabindex: isNav ? null : tabIndex
};
var btnContent = toString$1(_this7.makePage(page.number));
var scope = {
page: page.number,
index: page.number - 1,
content: btnContent,
active: active,
disabled: disabled
};
var $inner = h(disabled ? 'span' : isNav ? BLink : 'button', {
props: disabled || !isNav ? {} : _this7.linkProps(page.number),
staticClass: 'page-link',
class: {
'flex-grow-1': !isNav && !disabled && fill
},
attrs: attrs,
on: disabled ? {} : {
'!click': function click(evt) {
_this7.onClick(evt, page.number);
},
keydown: onSpaceKey
}
}, [_this7.normalizeSlot('page', scope) || btnContent]);
return h('li', {
key: "page-".concat(page.number),
staticClass: 'page-item',
class: [{
disabled: disabled,
active: active,
'flex-fill': fill,
'd-flex': fill && !isNav && !disabled
}, page.classes, _this7.pageClass],
attrs: {
role: isNav ? null : 'presentation'
}
}, [$inner]);
}; // Goto first page button
// Don't render button when `hideGotoEndButtons` or `firstNumber` is set
var $firstPageBtn = h();
if (!this.firstNumber && !this.hideGotoEndButtons) {
$firstPageBtn = makeEndBtn(1, this.labelFirstPage, 'first-text', this.firstText, this.firstClass, 1, 'pagination-goto-first');
}
buttons.push($firstPageBtn); // Goto previous page button
buttons.push(makeEndBtn(currentPage - 1, this.labelPrevPage, 'prev-text', this.prevText, this.prevClass, 1, 'pagination-goto-prev')); // Show first (1) button?
buttons.push(this.firstNumber && pageNumbers[0] !== 1 ? makePageButton({
number: 1
}, 0) : h()); // First ellipsis
buttons.push(showFirstDots ? makeEllipsis(false) : h()); // Individual page links
this.pageList.forEach(function (page, idx) {
var offset = showFirstDots && _this7.firstNumber && pageNumbers[0] !== 1 ? 1 : 0;
buttons.push(makePageButton(page, idx + offset));
}); // Last ellipsis
buttons.push(showLastDots ? makeEllipsis(true) : h()); // Show last page button?
buttons.push(this.lastNumber && pageNumbers[pageNumbers.length - 1] !== numberOfPages ? makePageButton({
number: numberOfPages
}, -1) : h()); // Goto next page button
buttons.push(makeEndBtn(currentPage + 1, this.labelNextPage, 'next-text', this.nextText, this.nextClass, numberOfPages, 'pagination-goto-next')); // Goto last page button
// Don't render button when `hideGotoEndButtons` or `lastNumber` is set
var $lastPageBtn = h();
if (!this.lastNumber && !this.hideGotoEndButtons) {
$lastPageBtn = makeEndBtn(numberOfPages, this.labelLastPage, 'last-text', this.lastText, this.lastClass, numberOfPages, 'pagination-goto-last');
}
buttons.push($lastPageBtn); // Assemble the pagination buttons
var $pagination = h('ul', {
ref: 'ul',
staticClass: 'pagination',
class: ['b-pagination', this.btnSize, this.alignment, this.styleClass],
attrs: {
role: isNav ? null : 'menubar',
'aria-disabled': disabled ? 'true' : 'false',
'aria-label': isNav ? null : this.ariaLabel || null
},
// We disable keyboard left/right nav when `<b-pagination-nav>`
on: isNav ? {} : {
keydown: this.handleKeyNav
}
}, buttons); // If we are `<b-pagination-nav>`, wrap in `<nav>` wrapper
if (isNav) {
return h('nav', {
attrs: {
'aria-disabled': disabled ? 'true' : null,
'aria-hidden': disabled ? 'true' : 'false',
'aria-label': isNav ? this.ariaLabel || null : null
}
}, [$pagination]);
}
return $pagination;
}
};
var DEFAULT_PER_PAGE = 20;
var DEFAULT_TOTAL_ROWS = 0; // --- Helper methods ---
// Sanitize the provided per page number (converting to a number)
var sanitizePerPage = function sanitizePerPage(val) {
return mathMax(toInteger(val) || DEFAULT_PER_PAGE, 1);
}; // Sanitize the provided total rows number (converting to a number)
var sanitizeTotalRows = function sanitizeTotalRows(val) {
return mathMax(toInteger(val) || DEFAULT_TOTAL_ROWS, 0);
}; // --- Main component ---
// The render function is brought in via the `paginationMixin`
// @vue/component
var BPagination = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_PAGINATION,
mixins: [paginationMixin],
props: makePropsConfigurable({
size: {
type: String // default: null
},
perPage: {
type: [Number, String],
default: DEFAULT_PER_PAGE
},
totalRows: {
type: [Number, String],
default: DEFAULT_TOTAL_ROWS
},
ariaControls: {
type: String // default: null
}
}, NAME_PAGINATION),
computed: {
numberOfPages: function numberOfPages() {
var result = mathCeil(sanitizeTotalRows(this.totalRows) / sanitizePerPage(this.perPage));
return result < 1 ? 1 : result;
},
pageSizeNumberOfPages: function pageSizeNumberOfPages() {
// Used for watching changes to `perPage` and `numberOfPages`
return {
perPage: sanitizePerPage(this.perPage),
totalRows: sanitizeTotalRows(this.totalRows),
numberOfPages: this.numberOfPages
};
}
},
watch: {
pageSizeNumberOfPages: function pageSizeNumberOfPages(newVal, oldVal) {
if (!isUndefinedOrNull(oldVal)) {
if (newVal.perPage !== oldVal.perPage && newVal.totalRows === oldVal.totalRows) {
// If the page size changes, reset to page 1
this.currentPage = 1;
} else if (newVal.numberOfPages !== oldVal.numberOfPages && this.currentPage > newVal.numberOfPages) {
// If `numberOfPages` changes and is less than
// the `currentPage` number, reset to page 1
this.currentPage = 1;
}
}
this.localNumberOfPages = newVal.numberOfPages;
}
},
created: function created() {
var _this = this;
// Set the initial page count
this.localNumberOfPages = this.numberOfPages; // Set the initial page value
var currentPage = toInteger(this.value, 0);
if (currentPage > 0) {
this.currentPage = currentPage;
} else {
this.$nextTick(function () {
// If this value parses to `NaN` or a value less than `1`
// trigger an initial emit of `null` if no page specified
_this.currentPage = 0;
});
}
},
mounted: function mounted() {
// Set the initial page count
this.localNumberOfPages = this.numberOfPages;
},
methods: {
// These methods are used by the render function
onClick: function onClick(evt, pageNumber) {
var _this2 = this;
// Dont do anything if clicking the current active page
if (pageNumber === this.currentPage) {
return;
}
var target = evt.target; // Emit a user-cancelable `page-click` event
var clickEvt = new BvEvent('page-click', {
cancelable: true,
vueTarget: this,
target: target
});
this.$emit(clickEvt.type, clickEvt, pageNumber);
if (clickEvt.defaultPrevented) {
return;
} // Update the `v-model`
this.currentPage = pageNumber; // Emit event triggered by user interaction
this.$emit('change', this.currentPage); // Keep the current button focused if possible
this.$nextTick(function () {
if (isVisible(target) && _this2.$el.contains(target)) {
attemptFocus(target);
} else {
_this2.focusCurrent();
}
});
},
makePage: function makePage(pageNum) {
return pageNum;
},
/* istanbul ignore next */
linkProps: function linkProps() {
// No props, since we render a plain button
/* istanbul ignore next */
return {};
}
}
});
var PaginationPlugin = /*#__PURE__*/pluginFactory({
components: {
BPagination: BPagination
}
});
// Sanitize the provided number of pages (converting to a number)
var sanitizeNumberOfPages = function sanitizeNumberOfPages(value) {
return mathMax(toInteger(value, 0), 1);
}; // --- Props ---
var _linkProps = omit(props$1, ['event', 'routerTag']); // --- Main component ---
// The render function is brought in via the pagination mixin
// @vue/component
var BPaginationNav = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_PAGINATION_NAV,
mixins: [paginationMixin],
props: makePropsConfigurable(_objectSpread2(_objectSpread2(_objectSpread2({}, props$13), _linkProps), {}, {
size: {
type: String // default: null
},
numberOfPages: {
type: [Number, String],
default: 1,
/* istanbul ignore next */
validator: function validator(value) {
var number = toInteger(value, 0);
if (number < 1) {
warn('Prop "number-of-pages" must be a number greater than "0"', NAME_PAGINATION_NAV);
return false;
}
return true;
}
},
baseUrl: {
type: String,
default: '/'
},
useRouter: {
type: Boolean,
default: false
},
linkGen: {
type: Function // default: null
},
pageGen: {
type: Function // default: null
},
pages: {
// Optional array of page links
type: Array // default: null
},
noPageDetect: {
// Disable auto page number detection if true
type: Boolean,
default: false
}
}), NAME_PAGINATION_NAV),
computed: {
// Used by render function to trigger wrapping in '<nav>' element
isNav: function isNav() {
return true;
},
computedValue: function computedValue() {
// Returns the value prop as a number or `null` if undefined or < 1
var value = toInteger(this.value, 0);
return value < 1 ? null : value;
}
},
watch: {
numberOfPages: function numberOfPages() {
var _this = this;
this.$nextTick(function () {
_this.setNumberOfPages();
});
},
pages: function pages() {
var _this2 = this;
this.$nextTick(function () {
_this2.setNumberOfPages();
});
}
},
created: function created() {
this.setNumberOfPages();
},
mounted: function mounted() {
var _this3 = this;
if (this.$router) {
// We only add the watcher if vue router is detected
this.$watch('$route', function () {
_this3.$nextTick(function () {
requestAF(function () {
_this3.guessCurrentPage();
});
});
});
}
},
methods: {
setNumberOfPages: function setNumberOfPages() {
var _this4 = this;
if (isArray(this.pages) && this.pages.length > 0) {
this.localNumberOfPages = this.pages.length;
} else {
this.localNumberOfPages = sanitizeNumberOfPages(this.numberOfPages);
}
this.$nextTick(function () {
_this4.guessCurrentPage();
});
},
onClick: function onClick(evt, pageNumber) {
var _this5 = this;
// Dont do anything if clicking the current active page
if (pageNumber === this.currentPage) {
return;
}
var target = evt.currentTarget || evt.target; // Emit a user-cancelable `page-click` event
var clickEvt = new BvEvent('page-click', {
cancelable: true,
vueTarget: this,
target: target
});
this.$emit(clickEvt.type, clickEvt, pageNumber);
if (clickEvt.defaultPrevented) {
return;
} // Update the `v-model`
// Done in in requestAF() to allow browser to complete the
// native browser click handling of a link
requestAF(function () {
_this5.currentPage = pageNumber;
_this5.$emit('change', pageNumber);
}); // Emulate native link click page reloading behaviour by blurring the
// paginator and returning focus to the document
// Done in a `nextTick()` to ensure rendering complete
this.$nextTick(function () {
attemptBlur(target);
});
},
getPageInfo: function getPageInfo(pageNum) {
if (!isArray(this.pages) || this.pages.length === 0 || isUndefined(this.pages[pageNum - 1])) {
var link = "".concat(this.baseUrl).concat(pageNum);
return {
link: this.useRouter ? {
path: link
} : link,
text: toString$1(pageNum)
};
}
var info = this.pages[pageNum - 1];
if (isObject(info)) {
var _link = info.link;
return {
// Normalize link for router use
link: isObject(_link) ? _link : this.useRouter ? {
path: _link
} : _link,
// Make sure text has a value
text: toString$1(info.text || pageNum)
};
} else {
return {
link: toString$1(info),
text: toString$1(pageNum)
};
}
},
makePage: function makePage(pageNum) {
var pageGen = this.pageGen;
var info = this.getPageInfo(pageNum);
if (pageGen && isFunction(pageGen)) {
var result = pageGen(pageNum, info);
if (!isUndefined(result)) {
return result;
}
}
return info.text;
},
makeLink: function makeLink(pageNum) {
var linkGen = this.linkGen;
var info = this.getPageInfo(pageNum);
if (linkGen && isFunction(linkGen)) {
var result = linkGen(pageNum, info);
if (!isUndefined(result)) {
return result;
}
}
return info.link;
},
linkProps: function linkProps(pageNum) {
var props = pluckProps(_linkProps, this);
var link = this.makeLink(pageNum);
if (this.useRouter || isObject(link)) {
props.to = link;
} else {
props.href = link;
}
return props;
},
resolveLink: function resolveLink() {
var to = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
// Given a to (or href string), convert to normalized route-like structure
// Works only client side!!
var link;
try {
// Convert the `to` to a HREF via a temporary `a` tag
link = document.createElement('a');
link.href = computeHref({
to: to
}, 'a', '/', '/'); // We need to add the anchor to the document to make sure the
// `pathname` is correctly detected in any browser (i.e. IE)
document.body.appendChild(link); // Once href is assigned, the link will be normalized to the full URL bits
var _link2 = link,
pathname = _link2.pathname,
hash = _link2.hash,
search = _link2.search; // Remove link from document
document.body.removeChild(link); // Return the location in a route-like object
return {
path: pathname,
hash: hash,
query: parseQuery(search)
};
} catch (e) {
/* istanbul ignore next */
try {
link && link.parentNode && link.parentNode.removeChild(link);
} catch (_unused) {}
/* istanbul ignore next */
return {};
}
},
resolveRoute: function resolveRoute() {
var to = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
// Given a to (or href string), convert to normalized route location structure
// works only when router available!!
try {
var route = this.$router.resolve(to, this.$route).route;
return {
path: route.path,
hash: route.hash,
query: route.query
};
} catch (e) {
/* istanbul ignore next */
return {};
}
},
guessCurrentPage: function guessCurrentPage() {
var guess = this.computedValue;
var $router = this.$router;
var $route = this.$route; // This section only occurs if we are client side, or server-side with $router
/* istanbul ignore else */
if (!this.noPageDetect && !guess && (isBrowser || !isBrowser && $router)) {
// Current route (if router available)
var currRoute = $router && $route ? {
path: $route.path,
hash: $route.hash,
query: $route.query
} : {}; // Current page full HREF (if client side). Can't be done as a computed prop!
var loc = isBrowser ? window.location || document.location : null;
var currLink = loc ? {
path: loc.pathname,
hash: loc.hash,
query: parseQuery(loc.search)
} :
/* istanbul ignore next */
{}; // Loop through the possible pages looking for a match until found
for (var page = 1; !guess && page <= this.localNumberOfPages; page++) {
var to = this.makeLink(page);
if ($router && (isObject(to) || this.useRouter)) {
// Resolve the page via the $router
guess = looseEqual(this.resolveRoute(to), currRoute) ? page : null;
} else if (isBrowser) {
// If no $router available (or !this.useRouter when `to` is a string)
// we compare using parsed URIs
guess = looseEqual(this.resolveLink(to), currLink) ? page : null;
} else {
// probably SSR, but no $router so we can't guess, so lets break out of
// the loop early
/* istanbul ignore next */
guess = -1;
}
}
} // We set currentPage to 0 to trigger an $emit('input', null)
// As the default for this.currentPage is -1 when no value is specified
// And valid page numbers are greater than 0
this.currentPage = guess > 0 ? guess : 0;
}
}
});
var PaginationNavPlugin = /*#__PURE__*/pluginFactory({
components: {
BPaginationNav: BPaginationNav
}
});
// Base on-demand component for tooltip / popover templates
var AttachmentMap = {
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
}; // @vue/component
var BVPopper = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_POPPER,
props: {
target: {
// Element that the tooltip/popover is positioned relative to
type: [HTMLElement, SVGElement] // default: null
},
placement: {
type: String,
default: 'top'
},
fallbackPlacement: {
type: [String, Array],
default: 'flip'
},
offset: {
type: Number,
default: 0
},
boundary: {
// 'scrollParent', 'viewport', 'window', or Element
type: [String, HTMLElement],
default: 'scrollParent'
},
boundaryPadding: {
// Tooltip/popover will try and stay away from
// boundary edge by this many pixels
type: Number,
default: 5
},
arrowPadding: {
// The minimum distance (in `px`) from the edge of the
// tooltip/popover that the arrow can be positioned
type: Number,
default: 6
}
},
data: function data() {
return {
// reactive props set by parent
noFade: false,
// State related data
localShow: true,
attachment: this.getAttachment(this.placement)
};
},
computed: {
/* istanbul ignore next */
templateType: function templateType() {
// Overridden by template component
return 'unknown';
},
popperConfig: function popperConfig() {
var _this = this;
var placement = this.placement;
return {
placement: this.getAttachment(placement),
modifiers: {
offset: {
offset: this.getOffset(placement)
},
flip: {
behavior: this.fallbackPlacement
},
// `arrow.element` can also be a reference to an HTML Element
// maybe we should make this a `$ref` in the templates?
arrow: {
element: '.arrow'
},
preventOverflow: {
padding: this.boundaryPadding,
boundariesElement: this.boundary
}
},
onCreate: function onCreate(data) {
// Handle flipping arrow classes
if (data.originalPlacement !== data.placement) {
/* istanbul ignore next: can't test in JSDOM */
_this.popperPlacementChange(data);
}
},
onUpdate: function onUpdate(data) {
// Handle flipping arrow classes
_this.popperPlacementChange(data);
}
};
}
},
created: function created() {
var _this2 = this;
// Note: We are created on-demand, and should be guaranteed that
// DOM is rendered/ready by the time the created hook runs
this.$_popper = null; // Ensure we show as we mount
this.localShow = true; // Create popper instance before shown
this.$on('show', function (el) {
_this2.popperCreate(el);
}); // Self destruct handler
var handleDestroy = function handleDestroy() {
_this2.$nextTick(function () {
// In a `requestAF()` to release control back to application
requestAF(function () {
_this2.$destroy();
});
});
}; // Self destruct if parent destroyed
this.$parent.$once('hook:destroyed', handleDestroy); // Self destruct after hidden
this.$once('hidden', handleDestroy);
},
beforeMount: function beforeMount() {
// Ensure that the attachment position is correct before mounting
// as our propsData is added after `new Template({...})`
this.attachment = this.getAttachment(this.placement);
},
updated: function updated() {
// Update popper if needed
// TODO: Should this be a watcher on `this.popperConfig` instead?
this.updatePopper();
},
beforeDestroy: function beforeDestroy() {
this.destroyPopper();
},
destroyed: function destroyed() {
// Make sure template is removed from DOM
var el = this.$el;
el && el.parentNode && el.parentNode.removeChild(el);
},
methods: {
// "Public" method to trigger hide template
hide: function hide() {
this.localShow = false;
},
// Private
getAttachment: function getAttachment(placement) {
return AttachmentMap[String(placement).toUpperCase()] || 'auto';
},
getOffset: function getOffset(placement) {
if (!this.offset) {
// Could set a ref for the arrow element
var arrow = this.$refs.arrow || select('.arrow', this.$el);
var arrowOffset = toFloat(getCS(arrow).width, 0) + toFloat(this.arrowPadding, 0);
switch (OffsetMap[String(placement).toUpperCase()] || 0) {
/* istanbul ignore next: can't test in JSDOM */
case +1:
/* istanbul ignore next: can't test in JSDOM */
return "+50%p - ".concat(arrowOffset, "px");
/* istanbul ignore next: can't test in JSDOM */
case -1:
/* istanbul ignore next: can't test in JSDOM */
return "-50%p + ".concat(arrowOffset, "px");
default:
return 0;
}
}
/* istanbul ignore next */
return this.offset;
},
popperCreate: function popperCreate(el) {
this.destroyPopper(); // We use `el` rather than `this.$el` just in case the original
// mountpoint root element type was changed by the template
this.$_popper = new Popper(this.target, el, this.popperConfig);
},
destroyPopper: function destroyPopper() {
this.$_popper && this.$_popper.destroy();
this.$_popper = null;
},
updatePopper: function updatePopper() {
this.$_popper && this.$_popper.scheduleUpdate();
},
popperPlacementChange: function popperPlacementChange(data) {
// Callback used by popper to adjust the arrow placement
this.attachment = this.getAttachment(data.placement);
},
/* istanbul ignore next */
renderTemplate: function renderTemplate(h) {
// Will be overridden by templates
return h('div');
}
},
render: function render(h) {
var _this3 = this;
// Note: `show` and 'fade' classes are only appled during transition
return h(BVTransition, {
// Transitions as soon as mounted
props: {
appear: true,
noFade: this.noFade
},
on: {
// Events used by parent component/instance
beforeEnter: function beforeEnter(el) {
return _this3.$emit('show', el);
},
afterEnter: function afterEnter(el) {
return _this3.$emit('shown', el);
},
beforeLeave: function beforeLeave(el) {
return _this3.$emit('hide', el);
},
afterLeave: function afterLeave(el) {
return _this3.$emit('hidden', el);
}
}
}, [this.localShow ? this.renderTemplate(h) : h()]);
}
});
var BVTooltipTemplate = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_TOOLTIP_TEMPLATE,
extends: BVPopper,
mixins: [scopedStyleAttrsMixin],
props: {
// Other non-reactive (while open) props are pulled in from BVPopper
id: {
type: String // default: null
},
html: {
// Used only by the directive versions
type: Boolean // default: false
}
},
data: function data() {
// We use data, rather than props to ensure reactivity
// Parent component will directly set this data
return {
title: '',
content: '',
variant: null,
customClass: null,
interactive: true
};
},
computed: {
templateType: function templateType() {
return 'tooltip';
},
templateClasses: function templateClasses() {
var _ref;
return [(_ref = {
// Disables pointer events to hide the tooltip when the user
// hovers over its content
noninteractive: !this.interactive
}, _defineProperty(_ref, "b-".concat(this.templateType, "-").concat(this.variant), this.variant), _defineProperty(_ref, "bs-".concat(this.templateType, "-").concat(this.attachment), this.attachment), _ref), this.customClass];
},
templateAttributes: function templateAttributes() {
return _objectSpread2(_objectSpread2({}, this.$parent.$parent.$attrs), {}, {
id: this.id,
role: 'tooltip',
tabindex: '-1'
}, this.scopedStyleAttrs);
},
templateListeners: function templateListeners() {
var _this = this;
// Used for hover/focus trigger listeners
return {
mouseenter
/* istanbul ignore next */
: function mouseenter(evt) {
/* istanbul ignore next: difficult to test in JSDOM */
_this.$emit('mouseenter', evt);
},
mouseleave
/* istanbul ignore next */
: function mouseleave(evt) {
/* istanbul ignore next: difficult to test in JSDOM */
_this.$emit('mouseleave', evt);
},
focusin
/* istanbul ignore next */
: function focusin(evt) {
/* istanbul ignore next: difficult to test in JSDOM */
_this.$emit('focusin', evt);
},
focusout
/* istanbul ignore next */
: function focusout(evt) {
/* istanbul ignore next: difficult to test in JSDOM */
_this.$emit('focusout', evt);
}
};
}
},
methods: {
renderTemplate: function renderTemplate(h) {
// Title can be a scoped slot function
var $title = isFunction(this.title) ? this.title({}) : isUndefinedOrNull(this.title) ?
/* istanbul ignore next */
h() : this.title; // Directive versions only
var domProps = this.html && !isFunction(this.title) ? {
innerHTML: this.title
} : {};
return h('div', {
staticClass: 'tooltip b-tooltip',
class: this.templateClasses,
attrs: this.templateAttributes,
on: this.templateListeners
}, [h('div', {
ref: 'arrow',
staticClass: 'arrow'
}), h('div', {
staticClass: 'tooltip-inner',
domProps: domProps
}, [$title])]);
}
}
});
var MODAL_SELECTOR = '.modal-content'; // Modal `$root` hidden event
var MODAL_CLOSE_EVENT = 'bv::modal::hidden'; // Sidebar container selector for appending tooltip/popover
var SIDEBAR_SELECTOR = '.b-sidebar'; // For finding the container to append to
var CONTAINER_SELECTOR = [MODAL_SELECTOR, SIDEBAR_SELECTOR].join(', '); // For dropdown sniffing
var DROPDOWN_CLASS = 'dropdown';
var DROPDOWN_OPEN_SELECTOR = '.dropdown-menu.show'; // Data attribute to temporary store the `title` attribute's value
var DATA_TITLE_ATTR = 'data-original-title'; // Data specific to popper and template
// We don't use props, as we need reactivity (we can't pass reactive props)
var templateData = {
// Text string or Scoped slot function
title: '',
// Text string or Scoped slot function
content: '',
// String
variant: null,
// String, Array, Object
customClass: null,
// String or array of Strings (overwritten by BVPopper)
triggers: '',
// String (overwritten by BVPopper)
placement: 'auto',
// String or array of strings
fallbackPlacement: 'flip',
// Element or Component reference (or function that returns element) of
// the element that will have the trigger events bound, and is also
// default element for positioning
target: null,
// HTML ID, Element or Component reference
container: null,
// 'body'
// Boolean
noFade: false,
// 'scrollParent', 'viewport', 'window', Element, or Component reference
boundary: 'scrollParent',
// Tooltip/popover will try and stay away from
// boundary edge by this many pixels (Number)
boundaryPadding: 5,
// Arrow offset (Number)
offset: 0,
// Hover/focus delay (Number or Object)
delay: 0,
// Arrow of Tooltip/popover will try and stay away from
// the edge of tooltip/popover edge by this many pixels
arrowPadding: 6,
// Interactive state (Boolean)
interactive: true,
// Disabled state (Boolean)
disabled: false,
// ID to use for tooltip/popover
id: null,
// Flag used by directives only, for HTML content
html: false
}; // @vue/component
var BVTooltip = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_TOOLTIP_HELPER,
data: function data() {
return _objectSpread2(_objectSpread2({}, templateData), {}, {
// State management data
activeTrigger: {
// manual: false,
hover: false,
click: false,
focus: false
},
localShow: false
});
},
computed: {
templateType: function templateType() {
// Overwritten by BVPopover
return 'tooltip';
},
computedId: function computedId() {
return this.id || "__bv_".concat(this.templateType, "_").concat(this._uid, "__");
},
computedDelay: function computedDelay() {
// Normalizes delay into object form
var delay = {
show: 0,
hide: 0
};
if (isPlainObject(this.delay)) {
delay.show = mathMax(toInteger(this.delay.show, 0), 0);
delay.hide = mathMax(toInteger(this.delay.hide, 0), 0);
} else if (isNumber(this.delay) || isString(this.delay)) {
delay.show = delay.hide = mathMax(toInteger(this.delay, 0), 0);
}
return delay;
},
computedTriggers: function computedTriggers() {
// Returns the triggers in sorted array form
// TODO: Switch this to object form for easier lookup
return concat(this.triggers).filter(Boolean).join(' ').trim().toLowerCase().split(/\s+/).sort();
},
isWithActiveTrigger: function isWithActiveTrigger() {
for (var trigger in this.activeTrigger) {
if (this.activeTrigger[trigger]) {
return true;
}
}
return false;
},
computedTemplateData: function computedTemplateData() {
return {
title: this.title,
content: this.content,
variant: this.variant,
customClass: this.customClass,
noFade: this.noFade,
interactive: this.interactive
};
}
},
watch: {
computedTriggers: function computedTriggers(newTriggers, oldTriggers) {
var _this = this;
// Triggers have changed, so re-register them
/* istanbul ignore next */
if (!looseEqual(newTriggers, oldTriggers)) {
this.$nextTick(function () {
// Disable trigger listeners
_this.unListen(); // Clear any active triggers that are no longer in the list of triggers
oldTriggers.forEach(function (trigger) {
if (!arrayIncludes(newTriggers, trigger)) {
if (_this.activeTrigger[trigger]) {
_this.activeTrigger[trigger] = false;
}
}
}); // Re-enable the trigger listeners
_this.listen();
});
}
},
computedTemplateData: function computedTemplateData() {
// If any of the while open reactive "props" change,
// ensure that the template updates accordingly
this.handleTemplateUpdate();
},
title: function title(newValue, oldValue) {
// Make sure to hide the tooltip when the title is set empty
if (newValue !== oldValue && !newValue) {
this.hide();
}
},
disabled: function disabled(newValue) {
if (newValue) {
this.disable();
} else {
this.enable();
}
}
},
created: function created() {
var _this2 = this;
// Create non-reactive properties
this.$_tip = null;
this.$_hoverTimeout = null;
this.$_hoverState = '';
this.$_visibleInterval = null;
this.$_enabled = !this.disabled;
this.$_noop = noop.bind(this); // Destroy ourselves when the parent is destroyed
if (this.$parent) {
this.$parent.$once('hook:beforeDestroy', function () {
_this2.$nextTick(function () {
// In a `requestAF()` to release control back to application
requestAF(function () {
_this2.$destroy();
});
});
});
}
this.$nextTick(function () {
var target = _this2.getTarget();
if (target && contains(document.body, target)) {
// Copy the parent's scoped style attribute
_this2.scopeId = getScopeId(_this2.$parent); // Set up all trigger handlers and listeners
_this2.listen();
} else {
/* istanbul ignore next */
warn(isString(_this2.target) ? "Unable to find target element by ID \"#".concat(_this2.target, "\" in document.") : 'The provided target is no valid HTML element.', _this2.templateType);
}
});
},
/* istanbul ignore next */
updated: function updated() {
// Usually called when the slots/data changes
this.$nextTick(this.handleTemplateUpdate);
},
/* istanbul ignore next */
deactivated: function deactivated() {
// In a keepalive that has been deactivated, so hide
// the tooltip/popover if it is showing
this.forceHide();
},
beforeDestroy: function beforeDestroy() {
// Remove all handler/listeners
this.unListen();
this.setWhileOpenListeners(false); // Clear any timeouts/intervals
this.clearHoverTimeout();
this.clearVisibilityInterval(); // Destroy the template
this.destroyTemplate(); // Remove any other private properties created during create
this.$_noop = null;
},
methods: {
// --- Methods for creating and destroying the template ---
getTemplate: function getTemplate() {
// Overridden by BVPopover
return BVTooltipTemplate;
},
updateData: function updateData() {
var _this3 = this;
var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
// Method for updating popper/template data
// We only update data if it exists, and has not changed
var titleUpdated = false;
keys(templateData).forEach(function (prop) {
if (!isUndefined(data[prop]) && _this3[prop] !== data[prop]) {
_this3[prop] = data[prop];
if (prop === 'title') {
titleUpdated = true;
}
}
}); // If the title has updated, we may need to handle the `title`
// attribute on the trigger target
// We only do this while the template is open
if (titleUpdated && this.localShow) {
this.fixTitle();
}
},
createTemplateAndShow: function createTemplateAndShow() {
// Creates the template instance and show it
var container = this.getContainer();
var Template = this.getTemplate();
var $tip = this.$_tip = new Template({
parent: this,
// The following is not reactive to changes in the props data
propsData: {
// These values cannot be changed while template is showing
id: this.computedId,
html: this.html,
placement: this.placement,
fallbackPlacement: this.fallbackPlacement,
target: this.getPlacementTarget(),
boundary: this.getBoundary(),
// Ensure the following are integers
offset: toInteger(this.offset, 0),
arrowPadding: toInteger(this.arrowPadding, 0),
boundaryPadding: toInteger(this.boundaryPadding, 0)
}
}); // We set the initial reactive data (values that can be changed while open)
this.handleTemplateUpdate(); // Template transition phase events (handled once only)
// When the template has mounted, but not visibly shown yet
$tip.$once('show', this.onTemplateShow); // When the template has completed showing
$tip.$once('shown', this.onTemplateShown); // When the template has started to hide
$tip.$once('hide', this.onTemplateHide); // When the template has completed hiding
$tip.$once('hidden', this.onTemplateHidden); // When the template gets destroyed for any reason
$tip.$once('hook:destroyed', this.destroyTemplate); // Convenience events from template
// To save us from manually adding/removing DOM
// listeners to tip element when it is open
$tip.$on('focusin', this.handleEvent);
$tip.$on('focusout', this.handleEvent);
$tip.$on('mouseenter', this.handleEvent);
$tip.$on('mouseleave', this.handleEvent); // Mount (which triggers the `show`)
$tip.$mount(container.appendChild(document.createElement('div'))); // Template will automatically remove its markup from DOM when hidden
},
hideTemplate: function hideTemplate() {
// Trigger the template to start hiding
// The template will emit the `hide` event after this and
// then emit the `hidden` event once it is fully hidden
// The `hook:destroyed` will also be called (safety measure)
this.$_tip && this.$_tip.hide(); // Clear out any stragging active triggers
this.clearActiveTriggers(); // Reset the hover state
this.$_hoverState = '';
},
// Destroy the template instance and reset state
destroyTemplate: function destroyTemplate() {
this.setWhileOpenListeners(false);
this.clearHoverTimeout();
this.$_hoverState = '';
this.clearActiveTriggers();
this.localPlacementTarget = null;
try {
this.$_tip.$destroy();
} catch (_unused) {}
this.$_tip = null;
this.removeAriaDescribedby();
this.restoreTitle();
this.localShow = false;
},
getTemplateElement: function getTemplateElement() {
return this.$_tip ? this.$_tip.$el : null;
},
handleTemplateUpdate: function handleTemplateUpdate() {
var _this4 = this;
// Update our template title/content "props"
// So that the template updates accordingly
var $tip = this.$_tip;
if ($tip) {
var props = ['title', 'content', 'variant', 'customClass', 'noFade', 'interactive']; // Only update the values if they have changed
props.forEach(function (prop) {
if ($tip[prop] !== _this4[prop]) {
$tip[prop] = _this4[prop];
}
});
}
},
// --- Show/Hide handlers ---
// Show the tooltip
show: function show() {
var target = this.getTarget();
if (!target || !contains(document.body, target) || !isVisible(target) || this.dropdownOpen() || (isUndefinedOrNull(this.title) || this.title === '') && (isUndefinedOrNull(this.content) || this.content === '')) {
// If trigger element isn't in the DOM or is not visible, or
// is on an open dropdown toggle, or has no content, then
// we exit without showing
return;
} // If tip already exists, exit early
if (this.$_tip || this.localShow) {
/* istanbul ignore next */
return;
} // In the process of showing
this.localShow = true; // Create a cancelable BvEvent
var showEvt = this.buildEvent('show', {
cancelable: true
});
this.emitEvent(showEvt); // Don't show if event cancelled
/* istanbul ignore if */
if (showEvt.defaultPrevented) {
// Destroy the template (if for some reason it was created)
this.destroyTemplate();
return;
} // Fix the title attribute on target
this.fixTitle(); // Set aria-describedby on target
this.addAriaDescribedby(); // Create and show the tooltip
this.createTemplateAndShow();
},
hide: function hide() {
var force = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
// Hide the tooltip
var tip = this.getTemplateElement();
/* istanbul ignore if */
if (!tip || !this.localShow) {
this.restoreTitle();
return;
} // Emit cancelable BvEvent 'hide'
// We disable cancelling if `force` is true
var hideEvt = this.buildEvent('hide', {
cancelable: !force
});
this.emitEvent(hideEvt);
/* istanbul ignore if: ignore for now */
if (hideEvt.defaultPrevented) {
// Don't hide if event cancelled
return;
} // Tell the template to hide
this.hideTemplate();
},
forceHide: function forceHide() {
// Forcefully hides/destroys the template, regardless of any active triggers
var tip = this.getTemplateElement();
if (!tip || !this.localShow) {
/* istanbul ignore next */
return;
} // Disable while open listeners/watchers
// This is also done in the template `hide` evt handler
this.setWhileOpenListeners(false); // Clear any hover enter/leave event
this.clearHoverTimeout();
this.$_hoverState = '';
this.clearActiveTriggers(); // Disable the fade animation on the template
if (this.$_tip) {
this.$_tip.noFade = true;
} // Hide the tip (with force = true)
this.hide(true);
},
enable: function enable() {
this.$_enabled = true; // Create a non-cancelable BvEvent
this.emitEvent(this.buildEvent('enabled'));
},
disable: function disable() {
this.$_enabled = false; // Create a non-cancelable BvEvent
this.emitEvent(this.buildEvent('disabled'));
},
// --- Handlers for template events ---
// When template is inserted into DOM, but not yet shown
onTemplateShow: function onTemplateShow() {
// Enable while open listeners/watchers
this.setWhileOpenListeners(true);
},
// When template show transition completes
onTemplateShown: function onTemplateShown() {
var prevHoverState = this.$_hoverState;
this.$_hoverState = '';
/* istanbul ignore next: occasional Node 10 coverage error */
if (prevHoverState === 'out') {
this.leave(null);
} // Emit a non-cancelable BvEvent 'shown'
this.emitEvent(this.buildEvent('shown'));
},
// When template is starting to hide
onTemplateHide: function onTemplateHide() {
// Disable while open listeners/watchers
this.setWhileOpenListeners(false);
},
// When template has completed closing (just before it self destructs)
onTemplateHidden: function onTemplateHidden() {
// Destroy the template
this.destroyTemplate(); // Emit a non-cancelable BvEvent 'shown'
this.emitEvent(this.buildEvent('hidden'));
},
// --- Utility methods ---
getTarget: function getTarget() {
var target = this.target;
if (isString(target)) {
target = getById(target.replace(/^#/, ''));
} else if (isFunction(target)) {
target = target();
} else if (target) {
target = target.$el || target;
}
return isElement(target) ? target : null;
},
getPlacementTarget: function getPlacementTarget() {
// This is the target that the tooltip will be placed on, which may not
// necessarily be the same element that has the trigger event listeners
// For now, this is the same as target
// TODO:
// Add in child selector support
// Add in visibility checks for this element
// Fallback to target if not found
return this.getTarget();
},
getTargetId: function getTargetId() {
// Returns the ID of the trigger element
var target = this.getTarget();
return target && target.id ? target.id : null;
},
getContainer: function getContainer() {
// Handle case where container may be a component ref
var container = this.container ? this.container.$el || this.container : false;
var body = document.body;
var target = this.getTarget(); // If we are in a modal, we append to the modal, If we
// are in a sidebar, we append to the sidebar, else append
// to body, unless a container is specified
// TODO:
// Template should periodically check to see if it is in dom
// And if not, self destruct (if container got v-if'ed out of DOM)
// Or this could possibly be part of the visibility check
return container === false ? closest(CONTAINER_SELECTOR, target) || body :
/*istanbul ignore next */
isString(container) ?
/*istanbul ignore next */
getById(container.replace(/^#/, '')) || body :
/*istanbul ignore next */
body;
},
getBoundary: function getBoundary() {
return this.boundary ? this.boundary.$el || this.boundary : 'scrollParent';
},
isInModal: function isInModal() {
var target = this.getTarget();
return target && closest(MODAL_SELECTOR, target);
},
isDropdown: function isDropdown() {
// Returns true if trigger is a dropdown
var target = this.getTarget();
return target && hasClass(target, DROPDOWN_CLASS);
},
dropdownOpen: function dropdownOpen() {
// Returns true if trigger is a dropdown and the dropdown menu is open
var target = this.getTarget();
return this.isDropdown() && target && select(DROPDOWN_OPEN_SELECTOR, target);
},
clearHoverTimeout: function clearHoverTimeout() {
clearTimeout(this.$_hoverTimeout);
this.$_hoverTimeout = null;
},
clearVisibilityInterval: function clearVisibilityInterval() {
clearInterval(this.$_visibleInterval);
this.$_visibleInterval = null;
},
clearActiveTriggers: function clearActiveTriggers() {
for (var trigger in this.activeTrigger) {
this.activeTrigger[trigger] = false;
}
},
addAriaDescribedby: function addAriaDescribedby() {
// Add aria-describedby on trigger element, without removing any other IDs
var target = this.getTarget();
var desc = getAttr(target, 'aria-describedby') || '';
desc = desc.split(/\s+/).concat(this.computedId).join(' ').trim(); // Update/add aria-described by
setAttr(target, 'aria-describedby', desc);
},
removeAriaDescribedby: function removeAriaDescribedby() {
var _this5 = this;
// Remove aria-describedby on trigger element, without removing any other IDs
var target = this.getTarget();
var desc = getAttr(target, 'aria-describedby') || '';
desc = desc.split(/\s+/).filter(function (d) {
return d !== _this5.computedId;
}).join(' ').trim(); // Update or remove aria-describedby
if (desc) {
/* istanbul ignore next */
setAttr(target, 'aria-describedby', desc);
} else {
removeAttr(target, 'aria-describedby');
}
},
fixTitle: function fixTitle() {
// If the target has a `title` attribute,
// remove it and store it on a data attribute
var target = this.getTarget();
if (hasAttr(target, 'title')) {
// Get `title` attribute value and remove it from target
var title = getAttr(target, 'title');
setAttr(target, 'title', ''); // Only set the data attribute when the value is truthy
if (title) {
setAttr(target, DATA_TITLE_ATTR, title);
}
}
},
restoreTitle: function restoreTitle() {
// If the target had a `title` attribute,
// restore it and remove the data attribute
var target = this.getTarget();
if (hasAttr(target, DATA_TITLE_ATTR)) {
// Get data attribute value and remove it from target
var title = getAttr(target, DATA_TITLE_ATTR);
removeAttr(target, DATA_TITLE_ATTR); // Only restore the `title` attribute when the value is truthy
if (title) {
setAttr(target, 'title', title);
}
}
},
// --- BvEvent helpers ---
buildEvent: function buildEvent(type) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
// Defaults to a non-cancellable event
return new BvEvent(type, _objectSpread2({
cancelable: false,
target: this.getTarget(),
relatedTarget: this.getTemplateElement() || null,
componentId: this.computedId,
vueTarget: this
}, options));
},
emitEvent: function emitEvent(bvEvt) {
// Emits a BvEvent on $root and this instance
var evtName = bvEvt.type;
var $root = this.$root;
if ($root && $root.$emit) {
// Emit an event on $root
$root.$emit("bv::".concat(this.templateType, "::").concat(evtName), bvEvt);
}
this.$emit(evtName, bvEvt);
},
// --- Event handler setup methods ---
listen: function listen() {
var _this6 = this;
// Enable trigger event handlers
var el = this.getTarget();
if (!el) {
/* istanbul ignore next */
return;
} // Listen for global show/hide events
this.setRootListener(true); // Set up our listeners on the target trigger element
this.computedTriggers.forEach(function (trigger) {
if (trigger === 'click') {
eventOn(el, 'click', _this6.handleEvent, EVENT_OPTIONS_NO_CAPTURE);
} else if (trigger === 'focus') {
eventOn(el, 'focusin', _this6.handleEvent, EVENT_OPTIONS_NO_CAPTURE);
eventOn(el, 'focusout', _this6.handleEvent, EVENT_OPTIONS_NO_CAPTURE);
} else if (trigger === 'blur') {
// Used to close $tip when element looses focus
/* istanbul ignore next */
eventOn(el, 'focusout', _this6.handleEvent, EVENT_OPTIONS_NO_CAPTURE);
} else if (trigger === 'hover') {
eventOn(el, 'mouseenter', _this6.handleEvent, EVENT_OPTIONS_NO_CAPTURE);
eventOn(el, 'mouseleave', _this6.handleEvent, EVENT_OPTIONS_NO_CAPTURE);
}
}, this);
},
/* istanbul ignore next */
unListen: function unListen() {
var _this7 = this;
// Remove trigger event handlers
var events = ['click', 'focusin', 'focusout', 'mouseenter', 'mouseleave'];
var target = this.getTarget(); // Stop listening for global show/hide/enable/disable events
this.setRootListener(false); // Clear out any active target listeners
events.forEach(function (evt) {
target && eventOff(target, evt, _this7.handleEvent, EVENT_OPTIONS_NO_CAPTURE);
}, this);
},
setRootListener: function setRootListener(on) {
// Listen for global `bv::{hide|show}::{tooltip|popover}` hide request event
var $root = this.$root;
if ($root) {
var method = on ? '$on' : '$off';
var type = this.templateType;
$root[method]("bv::hide::".concat(type), this.doHide);
$root[method]("bv::show::".concat(type), this.doShow);
$root[method]("bv::disable::".concat(type), this.doDisable);
$root[method]("bv::enable::".concat(type), this.doEnable);
}
},
setWhileOpenListeners: function setWhileOpenListeners(on) {
// Events that are only registered when the template is showing
// Modal close events
this.setModalListener(on); // Dropdown open events (if we are attached to a dropdown)
this.setDropdownListener(on); // Periodic $element visibility check
// For handling when tip target is in <keepalive>, tabs, carousel, etc
this.visibleCheck(on); // On-touch start listeners
this.setOnTouchStartListener(on);
},
// Handler for periodic visibility check
visibleCheck: function visibleCheck(on) {
var _this8 = this;
this.clearVisibilityInterval();
var target = this.getTarget();
var tip = this.getTemplateElement();
if (on) {
this.$_visibleInterval = setInterval(function () {
if (tip && _this8.localShow && (!target.parentNode || !isVisible(target))) {
// Target element is no longer visible or not in DOM, so force-hide the tooltip
_this8.forceHide();
}
}, 100);
}
},
setModalListener: function setModalListener(on) {
// Handle case where tooltip/target is in a modal
if (this.isInModal()) {
// We can listen for modal hidden events on `$root`
this.$root[on ? '$on' : '$off'](MODAL_CLOSE_EVENT, this.forceHide);
}
},
/* istanbul ignore next: JSDOM doesn't support `ontouchstart` */
setOnTouchStartListener: 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) {
eventOnOff(on, el, 'mouseover', _this9.$_noop);
});
}
},
setDropdownListener: function setDropdownListener(on) {
var target = this.getTarget();
if (!target || !this.$root || !this.isDropdown) {
return;
} // We can listen for dropdown shown events on its instance
// TODO:
// We could grab the ID from the dropdown, and listen for
// $root events for that particular dropdown id
// Dropdown shown and hidden events will need to emit
// Note: Dropdown auto-ID happens in a `$nextTick()` after mount
// So the ID lookup would need to be done in a `$nextTick()`
if (target.__vue__) {
target.__vue__[on ? '$on' : '$off']('shown', this.forceHide);
}
},
// --- Event handlers ---
handleEvent: function handleEvent(evt) {
// General trigger event handler
// target is the trigger element
var target = this.getTarget();
if (!target || isDisabled(target) || !this.$_enabled || this.dropdownOpen()) {
// If disabled or not enabled, or if a dropdown that is open, don't do anything
// If tip is shown before element gets disabled, then tip will not
// close until no longer disabled or forcefully closed
return;
}
var type = evt.type;
var triggers = this.computedTriggers;
if (type === 'click' && arrayIncludes(triggers, 'click')) {
this.click(evt);
} else if (type === 'mouseenter' && arrayIncludes(triggers, 'hover')) {
// `mouseenter` is a non-bubbling event
this.enter(evt);
} else if (type === 'focusin' && arrayIncludes(triggers, 'focus')) {
// `focusin` is a bubbling event
// `evt` includes `relatedTarget` (element losing focus)
this.enter(evt);
} else if (type === 'focusout' && (arrayIncludes(triggers, 'focus') || arrayIncludes(triggers, 'blur')) || type === 'mouseleave' && arrayIncludes(triggers, 'hover')) {
// `focusout` is a bubbling event
// `mouseleave` is a non-bubbling event
// `tip` is the template (will be null if not open)
var tip = this.getTemplateElement(); // `evtTarget` is the element which is losing focus/hover and
var evtTarget = evt.target; // `relatedTarget` is the element gaining focus/hover
var relatedTarget = evt.relatedTarget;
/* istanbul ignore next */
if ( // From tip to target
tip && contains(tip, evtTarget) && contains(target, relatedTarget) || // From target to tip
tip && contains(target, evtTarget) && contains(tip, relatedTarget) || // Within tip
tip && contains(tip, evtTarget) && contains(tip, relatedTarget) || // Within target
contains(target, evtTarget) && contains(target, relatedTarget)) {
// If focus/hover moves within `tip` and `target`, don't trigger a leave
return;
} // Otherwise trigger a leave
this.leave(evt);
}
},
doHide: function doHide(id) {
// Programmatically hide tooltip or popover
if (!id || this.getTargetId() === id || this.computedId === id) {
// Close all tooltips or popovers, or this specific tip (with ID)
this.forceHide();
}
},
doShow: function doShow(id) {
// Programmatically show tooltip or popover
if (!id || this.getTargetId() === id || this.computedId === id) {
// Open all tooltips or popovers, or this specific tip (with ID)
this.show();
}
},
/*istanbul ignore next: ignore for now */
doDisable: function doDisable(id)
/*istanbul ignore next: ignore for now */
{
// Programmatically disable tooltip or popover
if (!id || this.getTargetId() === id || this.computedId === id) {
// Disable all tooltips or popovers (no ID), or this specific tip (with ID)
this.disable();
}
},
/*istanbul ignore next: ignore for now */
doEnable: function doEnable(id)
/*istanbul ignore next: ignore for now */
{
// Programmatically enable tooltip or popover
if (!id || this.getTargetId() === id || this.computedId === id) {
// Enable all tooltips or popovers (no ID), or this specific tip (with ID)
this.enable();
}
},
click: function click(evt) {
if (!this.$_enabled || this.dropdownOpen()) {
/* istanbul ignore next */
return;
} // Get around a WebKit bug where `click` does not trigger focus events
// On most browsers, `click` triggers a `focusin`/`focus` event first
// Needed so that trigger 'click blur' works on iOS
// https://github.com/bootstrap-vue/bootstrap-vue/issues/5099
// We use `currentTarget` rather than `target` to trigger on the
// element, not the inner content
attemptFocus(evt.currentTarget);
this.activeTrigger.click = !this.activeTrigger.click;
if (this.isWithActiveTrigger) {
this.enter(null);
} else {
/* istanbul ignore next */
this.leave(null);
}
},
/* istanbul ignore next */
toggle: function toggle() {
// Manual toggle handler
if (!this.$_enabled || this.dropdownOpen()) {
/* istanbul ignore next */
return;
} // Should we register as an active trigger?
// this.activeTrigger.manual = !this.activeTrigger.manual
if (this.localShow) {
this.leave(null);
} else {
this.enter(null);
}
},
enter: function enter() {
var _this10 = this;
var evt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
// Opening trigger handler
// Note: Click events are sent with evt === null
if (evt) {
this.activeTrigger[evt.type === 'focusin' ? 'focus' : 'hover'] = true;
}
/* istanbul ignore next */
if (this.localShow || this.$_hoverState === 'in') {
this.$_hoverState = 'in';
return;
}
this.clearHoverTimeout();
this.$_hoverState = 'in';
if (!this.computedDelay.show) {
this.show();
} else {
// Hide any title attribute while enter delay is active
this.fixTitle();
this.$_hoverTimeout = setTimeout(function () {
/* istanbul ignore else */
if (_this10.$_hoverState === 'in') {
_this10.show();
} else if (!_this10.localShow) {
_this10.restoreTitle();
}
}, this.computedDelay.show);
}
},
leave: function leave() {
var _this11 = this;
var evt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
// Closing trigger handler
// Note: Click events are sent with evt === null
if (evt) {
this.activeTrigger[evt.type === 'focusout' ? 'focus' : 'hover'] = false;
/* istanbul ignore next */
if (evt.type === 'focusout' && arrayIncludes(this.computedTriggers, 'blur')) {
// Special case for `blur`: we clear out the other triggers
this.activeTrigger.click = false;
this.activeTrigger.hover = false;
}
}
/* istanbul ignore next: ignore for now */
if (this.isWithActiveTrigger) {
return;
}
this.clearHoverTimeout();
this.$_hoverState = 'out';
if (!this.computedDelay.hide) {
this.hide();
} else {
this.$_hoverTimeout = setTimeout(function () {
if (_this11.$_hoverState === 'out') {
_this11.hide();
}
}, this.computedDelay.hide);
}
}
}
});
var BTooltip = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_TOOLTIP,
inheritAttrs: false,
props: makePropsConfigurable({
title: {
type: String // default: undefined
},
// Added in by BPopover
// content: {
// type: String,
// default: undefined
// },
target: {
// String ID of element, or element/component reference
// Or function that returns one of the above
type: [String, HTMLElement, SVGElement, Function, Object],
required: true
},
triggers: {
type: [String, Array],
default: 'hover focus'
},
placement: {
type: String,
default: 'top'
},
fallbackPlacement: {
type: [String, Array],
default: 'flip',
validator: function validator(value) {
return isArray(value) && value.every(function (v) {
return isString(v);
}) || arrayIncludes(['flip', 'clockwise', 'counterclockwise'], value);
}
},
variant: {
type: String // default: undefined
},
customClass: {
type: String // default: undefined
},
delay: {
type: [Number, Object, String],
default: 50
},
boundary: {
// String: scrollParent, window, or viewport
// Element: element reference
// Object: Vue component
type: [String, HTMLElement, Object],
default: 'scrollParent'
},
boundaryPadding: {
type: [Number, String],
default: 5
},
offset: {
type: [Number, String],
default: 0
},
noFade: {
type: Boolean,
default: false
},
container: {
// String: HTML ID of container, if null body is used (default)
// HTMLElement: element reference reference
// Object: Vue Component
type: [String, HTMLElement, Object] // default: undefined
},
show: {
type: Boolean,
default: false
},
noninteractive: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
id: {
// ID to use for tooltip element
// If not provided on will automatically be generated
type: String // default: null
}
}, NAME_TOOLTIP),
data: function data() {
return {
localShow: this.show,
localTitle: '',
localContent: ''
};
},
computed: {
templateData: function templateData() {
// Data that will be passed to the template and popper
return {
// We use massaged versions of the title and content props/slots
title: this.localTitle,
content: this.localContent,
// Pass these props as is
target: this.target,
triggers: this.triggers,
placement: this.placement,
fallbackPlacement: this.fallbackPlacement,
variant: this.variant,
customClass: this.customClass,
container: this.container,
boundary: this.boundary,
boundaryPadding: this.boundaryPadding,
delay: this.delay,
offset: this.offset,
noFade: this.noFade,
interactive: !this.noninteractive,
disabled: this.disabled,
id: this.id
};
},
templateTitleContent: function templateTitleContent() {
// Used to watch for changes to the title and content props
return {
title: this.title,
content: this.content
};
}
},
watch: {
show: function show(_show, oldVal) {
if (_show !== oldVal && _show !== this.localShow && this.$_toolpop) {
if (_show) {
this.$_toolpop.show();
} else {
// We use `forceHide()` to override any active triggers
this.$_toolpop.forceHide();
}
}
},
disabled: function disabled(newVal) {
if (newVal) {
this.doDisable();
} else {
this.doEnable();
}
},
localShow: function localShow(newVal) {
// TODO: May need to be done in a `$nextTick()`
this.$emit('update:show', newVal);
},
templateData: function templateData() {
var _this = this;
this.$nextTick(function () {
if (_this.$_toolpop) {
_this.$_toolpop.updateData(_this.templateData);
}
});
},
// Watchers for title/content props (prop changes do not trigger the `updated()` hook)
templateTitleContent: function templateTitleContent() {
this.$nextTick(this.updateContent);
}
},
created: function created() {
// Create private non-reactive props
this.$_toolpop = null;
},
updated: function updated() {
// Update the `propData` object
// Done in a `$nextTick()` to ensure slot(s) have updated
this.$nextTick(this.updateContent);
},
beforeDestroy: function beforeDestroy() {
// Shutdown our local event listeners
this.$off('open', this.doOpen);
this.$off('close', this.doClose);
this.$off('disable', this.doDisable);
this.$off('enable', this.doEnable); // Destroy the tip instance
if (this.$_toolpop) {
this.$_toolpop.$destroy();
this.$_toolpop = null;
}
},
mounted: function mounted() {
var _this2 = this;
// Instantiate a new BVTooltip instance
// Done in a `$nextTick()` to ensure DOM has completed rendering
// so that target can be found
this.$nextTick(function () {
// Load the on demand child instance
var Component = _this2.getComponent(); // Ensure we have initial content
_this2.updateContent(); // Pass down the scoped style attribute if available
var scopeId = getScopeId(_this2) || getScopeId(_this2.$parent); // Create the instance
var $toolpop = _this2.$_toolpop = new Component({
parent: _this2,
// Pass down the scoped style ID
_scopeId: scopeId || undefined
}); // Set the initial data
$toolpop.updateData(_this2.templateData); // Set listeners
$toolpop.$on('show', _this2.onShow);
$toolpop.$on('shown', _this2.onShown);
$toolpop.$on('hide', _this2.onHide);
$toolpop.$on('hidden', _this2.onHidden);
$toolpop.$on('disabled', _this2.onDisabled);
$toolpop.$on('enabled', _this2.onEnabled); // Initially disabled?
if (_this2.disabled) {
// Initially disabled
_this2.doDisable();
} // Listen to open signals from others
_this2.$on('open', _this2.doOpen); // Listen to close signals from others
_this2.$on('close', _this2.doClose); // Listen to disable signals from others
_this2.$on('disable', _this2.doDisable); // Listen to enable signals from others
_this2.$on('enable', _this2.doEnable); // Initially show tooltip?
if (_this2.localShow) {
$toolpop.show();
}
});
},
methods: {
getComponent: function getComponent() {
// Overridden by BPopover
return BVTooltip;
},
updateContent: function updateContent() {
// Overridden by BPopover
// Tooltip: Default slot is `title`
// Popover: Default slot is `content`, `title` slot is title
// We pass a scoped slot function reference by default (Vue v2.6x)
// And pass the title prop as a fallback
this.setTitle(this.$scopedSlots.default || this.title);
},
// Helper methods for `updateContent()`
setTitle: function setTitle(val) {
val = isUndefinedOrNull(val) ? '' : val; // We only update the value if it has changed
if (this.localTitle !== val) {
this.localTitle = val;
}
},
setContent: function setContent(val) {
val = isUndefinedOrNull(val) ? '' : val; // We only update the value if it has changed
if (this.localContent !== val) {
this.localContent = val;
}
},
// --- Template event handlers ---
onShow: function onShow(bvEvt) {
// Placeholder
this.$emit('show', bvEvt);
if (bvEvt) {
this.localShow = !bvEvt.defaultPrevented;
}
},
onShown: function onShown(bvEvt) {
// Tip is now showing
this.localShow = true;
this.$emit('shown', bvEvt);
},
onHide: function onHide(bvEvt) {
this.$emit('hide', bvEvt);
},
onHidden: function onHidden(bvEvt) {
// Tip is no longer showing
this.$emit('hidden', bvEvt);
this.localShow = false;
},
onDisabled: function onDisabled(bvEvt) {
// Prevent possible endless loop if user mistakenly
// fires `disabled` instead of `disable`
if (bvEvt && bvEvt.type === 'disabled') {
this.$emit('update:disabled', true);
this.$emit('disabled', bvEvt);
}
},
onEnabled: function onEnabled(bvEvt) {
// Prevent possible endless loop if user mistakenly
// fires `enabled` instead of `enable`
if (bvEvt && bvEvt.type === 'enabled') {
this.$emit('update:disabled', false);
this.$emit('enabled', bvEvt);
}
},
// --- Local event listeners ---
doOpen: function doOpen() {
!this.localShow && this.$_toolpop && this.$_toolpop.show();
},
doClose: function doClose() {
this.localShow && this.$_toolpop && this.$_toolpop.hide();
},
doDisable: function doDisable() {
this.$_toolpop && this.$_toolpop.disable();
},
doEnable: function doEnable() {
this.$_toolpop && this.$_toolpop.enable();
}
},
render: function render(h) {
// Always renders a comment node
// TODO:
// Future: Possibly render a target slot (single root element)
// which we can apply the listeners to (pass `this.$el` to BVTooltip)
return h();
}
});
var BVPopoverTemplate = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_POPOVER_TEMPLATE,
extends: BVTooltipTemplate,
computed: {
templateType: function templateType() {
return 'popover';
}
},
methods: {
renderTemplate: function renderTemplate(h) {
// Title and content could be a scoped slot function
var $title = isFunction(this.title) ? this.title({}) : this.title;
var $content = isFunction(this.content) ? this.content({}) : this.content; // Directive usage only
var titleDomProps = this.html && !isFunction(this.title) ? {
innerHTML: this.title
} : {};
var contentDomProps = this.html && !isFunction(this.content) ? {
innerHTML: this.content
} : {};
return h('div', {
staticClass: 'popover b-popover',
class: this.templateClasses,
attrs: this.templateAttributes,
on: this.templateListeners
}, [h('div', {
ref: 'arrow',
staticClass: 'arrow'
}), isUndefinedOrNull($title) || $title === '' ?
/* istanbul ignore next */
h() : h('h3', {
staticClass: 'popover-header',
domProps: titleDomProps
}, [$title]), isUndefinedOrNull($content) || $content === '' ?
/* istanbul ignore next */
h() : h('div', {
staticClass: 'popover-body',
domProps: contentDomProps
}, [$content])]);
}
}
});
// Popover "Class" (Built as a renderless Vue instance)
var BVPopover = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_POPOVER_HELPER,
extends: BVTooltip,
computed: {
// Overwrites BVTooltip
templateType: function templateType() {
return 'popover';
}
},
methods: {
getTemplate: function getTemplate() {
// Overwrites BVTooltip
return BVPopoverTemplate;
}
}
});
var BPopover = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_POPOVER,
extends: BTooltip,
inheritAttrs: false,
props: makePropsConfigurable({
title: {
type: String // default: undefined
},
content: {
type: String // default: undefined
},
triggers: {
type: [String, Array],
default: 'click'
},
placement: {
type: String,
default: 'right'
},
variant: {
type: String,
default: undefined
},
customClass: {
type: String,
default: undefined
},
delay: {
type: [Number, Object, String],
default: 50
},
boundary: {
// String: scrollParent, window, or viewport
// Element: element reference
// Object: Vue component
type: [String, HTMLElement, Object],
default: 'scrollParent'
},
boundaryPadding: {
type: [Number, String],
default: 5
}
}, NAME_POPOVER),
methods: {
getComponent: function getComponent() {
// Overridden by BPopover
return BVPopover;
},
updateContent: function updateContent() {
// Tooltip: Default slot is `title`
// Popover: Default slot is `content`, `title` slot is title
// We pass a scoped slot function references by default (Vue v2.6x)
// And pass the title prop as a fallback
this.setContent(this.$scopedSlots.default || this.content);
this.setTitle(this.$scopedSlots.title || this.title);
}
} // Render function provided by BTooltip
});
var BV_POPOVER = '__BV_Popover__'; // Default trigger
var DefaultTrigger = 'click'; // Valid event triggers
var validTriggers = {
focus: true,
hover: true,
click: true,
blur: true,
manual: true
}; // Directive modifier test regular expressions. Pre-compile for performance
var htmlRE = /^html$/i;
var noFadeRE = /^nofade$/i;
var placementRE = /^(auto|top(left|right)?|bottom(left|right)?|left(top|bottom)?|right(top|bottom)?)$/i;
var boundaryRE = /^(window|viewport|scrollParent)$/i;
var delayRE = /^d\d+$/i;
var delayShowRE = /^ds\d+$/i;
var delayHideRE = /^dh\d+$/i;
var offsetRE = /^o-?\d+$/i;
var variantRE = /^v-.+$/i;
var spacesRE = /\s+/; // Build a Popover config based on bindings (if any)
// Arguments and modifiers take precedence over passed value config object
var parseBindings = function parseBindings(bindings, vnode)
/* istanbul ignore next: not easy to test */
{
// We start out with a basic config
var config = {
title: undefined,
content: undefined,
trigger: '',
// Default set below if needed
placement: 'right',
fallbackPlacement: 'flip',
container: false,
// Default of body
animation: true,
offset: 0,
disabled: false,
id: null,
html: false,
delay: getComponentConfig(NAME_POPOVER, 'delay', 50),
boundary: String(getComponentConfig(NAME_POPOVER, 'boundary', 'scrollParent')),
boundaryPadding: toInteger(getComponentConfig(NAME_POPOVER, 'boundaryPadding', 5), 0),
variant: getComponentConfig(NAME_POPOVER, 'variant'),
customClass: getComponentConfig(NAME_POPOVER, 'customClass')
}; // Process `bindings.value`
if (isString(bindings.value) || isNumber(bindings.value)) {
// Value is popover content (html optionally supported)
config.content = bindings.value;
} else if (isFunction(bindings.value)) {
// Content generator function
config.content = bindings.value;
} else if (isPlainObject(bindings.value)) {
// Value is config object, so merge
config = _objectSpread2(_objectSpread2({}, config), 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 = "#".concat(bindings.arg);
} // If title is not provided, try title attribute
if (isUndefined(config.title)) {
// Try attribute
var data = vnode.data || {};
config.title = data.attrs && !isUndefinedOrNull(data.attrs.title) ? data.attrs.title : undefined;
} // Normalize delay
if (!isPlainObject(config.delay)) {
config.delay = {
show: toInteger(config.delay, 0),
hide: toInteger(config.delay, 0)
};
} // Process modifiers
keys(bindings.modifiers).forEach(function (mod) {
if (htmlRE.test(mod)) {
// Title/content allows HTML
config.html = true;
} else if (noFadeRE.test(mod)) {
// No animation
config.animation = false;
} else if (placementRE.test(mod)) {
// Placement of popover
config.placement = mod;
} else if (boundaryRE.test(mod)) {
// Boundary of popover
mod = mod === 'scrollparent' ? 'scrollParent' : mod;
config.boundary = mod;
} else if (delayRE.test(mod)) {
// Delay value
var delay = toInteger(mod.slice(1), 0);
config.delay.show = delay;
config.delay.hide = delay;
} else if (delayShowRE.test(mod)) {
// Delay show value
config.delay.show = toInteger(mod.slice(2), 0);
} else if (delayHideRE.test(mod)) {
// Delay hide value
config.delay.hide = toInteger(mod.slice(2), 0);
} else if (offsetRE.test(mod)) {
// Offset value, negative allowed
config.offset = toInteger(mod.slice(1), 0);
} else if (variantRE.test(mod)) {
// Variant
config.variant = mod.slice(2) || null;
}
}); // Special handling of event trigger modifiers trigger is
// a space separated list
var selectedTriggers = {}; // Parse current config object trigger
concat(config.trigger || '').filter(identity).join(' ').trim().toLowerCase().split(spacesRE).forEach(function (trigger) {
if (validTriggers[trigger]) {
selectedTriggers[trigger] = true;
}
}); // Parse modifiers for triggers
keys(bindings.modifiers).forEach(function (mod) {
mod = mod.toLowerCase();
if (validTriggers[mod]) {
// If modifier is a valid trigger
selectedTriggers[mod] = 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) {
// Use default trigger
config.trigger = DefaultTrigger;
}
return config;
}; // Add or update Popover on our element
var applyPopover = function applyPopover(el, bindings, vnode) {
if (!isBrowser) {
/* istanbul ignore next */
return;
}
var config = parseBindings(bindings, vnode);
if (!el[BV_POPOVER]) {
var $parent = vnode.context;
el[BV_POPOVER] = new BVPopover({
parent: $parent,
// Add the parent's scoped style attribute data
_scopeId: getScopeId($parent, undefined)
});
el[BV_POPOVER].__bv_prev_data__ = {};
el[BV_POPOVER].$on('show', function ()
/* istanbul ignore next: for now */
{
// Before showing the popover, we update the title
// and content if they are functions
var data = {};
if (isFunction(config.title)) {
data.title = config.title(el);
}
if (isFunction(config.content)) {
data.content = config.content(el);
}
if (keys(data).length > 0) {
el[BV_POPOVER].updateData(data);
}
});
}
var data = {
title: config.title,
content: config.content,
triggers: config.trigger,
placement: config.placement,
fallbackPlacement: config.fallbackPlacement,
variant: config.variant,
customClass: config.customClass,
container: config.container,
boundary: config.boundary,
delay: config.delay,
offset: config.offset,
noFade: !config.animation,
id: config.id,
disabled: config.disabled,
html: config.html
};
var oldData = el[BV_POPOVER].__bv_prev_data__;
el[BV_POPOVER].__bv_prev_data__ = data;
if (!looseEqual(data, oldData)) {
// We only update the instance if data has changed
var newData = {
target: el
};
keys(data).forEach(function (prop) {
// We only pass data properties that have changed
if (data[prop] !== oldData[prop]) {
// If title/content is a function, we execute it here
newData[prop] = (prop === 'title' || prop === 'content') && isFunction(data[prop]) ?
/* istanbul ignore next */
data[prop](el) : data[prop];
}
});
el[BV_POPOVER].updateData(newData);
}
}; // Remove Popover from our element
var removePopover = function removePopover(el) {
if (el[BV_POPOVER]) {
el[BV_POPOVER].$destroy();
el[BV_POPOVER] = null;
}
delete el[BV_POPOVER];
}; // Export our directive
var VBPopover = {
bind: function bind(el, bindings, vnode) {
applyPopover(el, bindings, vnode);
},
// We use `componentUpdated` here instead of `update`, as the former
// waits until the containing component and children have finished updating
componentUpdated: function componentUpdated(el, bindings, vnode) {
// Performed in a `$nextTick()` to prevent endless render/update loops
vnode.context.$nextTick(function () {
applyPopover(el, bindings, vnode);
});
},
unbind: function unbind(el) {
removePopover(el);
}
};
var VBPopoverPlugin = /*#__PURE__*/pluginFactory({
directives: {
VBPopover: VBPopover
}
});
var PopoverPlugin = /*#__PURE__*/pluginFactory({
components: {
BPopover: BPopover
},
plugins: {
VBPopoverPlugin: VBPopoverPlugin
}
});
var BProgressBar = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_PROGRESS_BAR,
mixins: [normalizeSlotMixin],
inject: {
bvProgress: {
default: function _default() {
return {};
}
}
},
props: makePropsConfigurable({
value: {
type: [Number, String],
default: 0
},
label: {
type: String // default: null
},
labelHtml: {
type: String
},
// $parent (this.bvProgress) prop values may take precedence over the following props
// Which is why they are defaulted to null
max: {
type: [Number, String],
default: null
},
precision: {
type: [Number, String],
default: null
},
variant: {
type: String // default: undefined
},
striped: {
type: Boolean,
default: null
},
animated: {
type: Boolean,
default: null
},
showProgress: {
type: Boolean,
default: null
},
showValue: {
type: Boolean,
default: null
}
}, NAME_PROGRESS_BAR),
computed: {
progressBarClasses: function progressBarClasses() {
return [this.computedVariant ? "bg-".concat(this.computedVariant) : '', this.computedStriped || this.computedAnimated ? 'progress-bar-striped' : '', this.computedAnimated ? 'progress-bar-animated' : ''];
},
progressBarStyles: function progressBarStyles() {
return {
width: 100 * (this.computedValue / this.computedMax) + '%'
};
},
computedValue: function computedValue() {
return toFloat(this.value, 0);
},
computedMax: function computedMax() {
// Prefer our max over parent setting
// Default to `100` for invalid values (`-x`, `0`, `NaN`)
var max = toFloat(this.max) || toFloat(this.bvProgress.max, 0);
return max > 0 ? max : 100;
},
computedPrecision: function computedPrecision() {
// Prefer our precision over parent setting
// Default to `0` for invalid values (`-x`, `NaN`)
return mathMax(toInteger(this.precision, toInteger(this.bvProgress.precision, 0)), 0);
},
computedProgress: function computedProgress() {
var precision = this.computedPrecision;
var p = mathPow(10, precision);
return toFixed(100 * p * this.computedValue / this.computedMax / p, precision);
},
computedVariant: function computedVariant() {
// Prefer our variant over parent setting
return this.variant || this.bvProgress.variant;
},
computedStriped: function computedStriped() {
// Prefer our striped over parent setting
return isBoolean(this.striped) ? this.striped : this.bvProgress.striped || false;
},
computedAnimated: function computedAnimated() {
// Prefer our animated over parent setting
return isBoolean(this.animated) ? this.animated : this.bvProgress.animated || false;
},
computedShowProgress: function computedShowProgress() {
// Prefer our showProgress over parent setting
return isBoolean(this.showProgress) ? this.showProgress : this.bvProgress.showProgress || false;
},
computedShowValue: function computedShowValue() {
// Prefer our showValue over parent setting
return isBoolean(this.showValue) ? this.showValue : this.bvProgress.showValue || false;
}
},
render: function render(h) {
var label = this.label,
labelHtml = this.labelHtml,
computedValue = this.computedValue,
computedPrecision = this.computedPrecision;
var $children;
var domProps = {};
if (this.hasNormalizedSlot()) {
$children = this.normalizeSlot();
} else if (label || labelHtml) {
domProps = htmlOrText(labelHtml, label);
} else if (this.computedShowProgress) {
$children = this.computedProgress;
} else if (this.computedShowValue) {
$children = toFixed(computedValue, computedPrecision);
}
return h('div', {
staticClass: 'progress-bar',
class: this.progressBarClasses,
style: this.progressBarStyles,
attrs: {
role: 'progressbar',
'aria-valuemin': '0',
'aria-valuemax': toString$1(this.computedMax),
'aria-valuenow': toFixed(computedValue, computedPrecision)
},
domProps: domProps
}, $children);
}
});
var BProgress = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_PROGRESS,
mixins: [normalizeSlotMixin],
provide: function provide() {
return {
bvProgress: this
};
},
props: makePropsConfigurable({
// These props can be inherited via the child b-progress-bar(s)
variant: {
type: String // default: undefined
},
striped: {
type: Boolean,
default: false
},
animated: {
type: Boolean,
default: false
},
height: {
type: String // default: null
},
precision: {
type: [Number, String],
default: 0
},
showProgress: {
type: Boolean,
default: false
},
showValue: {
type: Boolean,
default: false
},
max: {
type: [Number, String],
default: 100
},
// This prop is not inherited by child b-progress-bar(s)
value: {
type: [Number, String],
default: 0
}
}, NAME_PROGRESS),
computed: {
progressHeight: function progressHeight() {
return {
height: this.height || null
};
}
},
render: function render(h) {
var childNodes = this.normalizeSlot();
if (!childNodes) {
childNodes = h(BProgressBar, {
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]);
}
});
var ProgressPlugin = /*#__PURE__*/pluginFactory({
components: {
BProgress: BProgress,
BProgressBar: BProgressBar
}
});
var CLASS_NAME$3 = 'b-sidebar'; // --- Render methods ---
var renderHeaderTitle = function renderHeaderTitle(h, ctx) {
// Render a empty `<span>` when to title was provided
var title = ctx.computedTile;
if (!title) {
return h('span');
}
return h('strong', {
attrs: {
id: ctx.safeId('__title__')
}
}, [title]);
};
var renderHeaderClose = function renderHeaderClose(h, ctx) {
if (ctx.noHeaderClose) {
return h();
}
var closeLabel = ctx.closeLabel,
textVariant = ctx.textVariant,
hide = ctx.hide;
return h(BButtonClose, {
ref: 'close-button',
props: {
ariaLabel: closeLabel,
textVariant: textVariant
},
on: {
click: hide
}
}, [ctx.normalizeSlot('header-close') || h(BIconX)]);
};
var renderHeader = function renderHeader(h, ctx) {
if (ctx.noHeader) {
return h();
}
var $title = renderHeaderTitle(h, ctx);
var $close = renderHeaderClose(h, ctx);
return h('header', {
key: 'header',
staticClass: "".concat(CLASS_NAME$3, "-header"),
class: ctx.headerClass
}, ctx.right ? [$close, $title] : [$title, $close]);
};
var renderBody = function renderBody(h, ctx) {
return h('div', {
key: 'body',
staticClass: "".concat(CLASS_NAME$3, "-body"),
class: ctx.bodyClass
}, [ctx.normalizeSlot(SLOT_NAME_DEFAULT, ctx.slotScope)]);
};
var renderFooter = function renderFooter(h, ctx) {
var $footer = ctx.normalizeSlot(SLOT_NAME_FOOTER, ctx.slotScope);
if (!$footer) {
return h();
}
return h('footer', {
key: 'footer',
staticClass: "".concat(CLASS_NAME$3, "-footer"),
class: ctx.footerClass
}, [$footer]);
};
var renderContent = function renderContent(h, ctx) {
// We render the header even if `lazy` is enabled as it
// acts as the accessible label for the sidebar
var $header = renderHeader(h, ctx);
if (ctx.lazy && !ctx.isOpen) {
return $header;
}
return [$header, renderBody(h, ctx), renderFooter(h, ctx)];
};
var renderBackdrop = function renderBackdrop(h, ctx) {
if (!ctx.backdrop) {
return h();
}
var backdropVariant = ctx.backdropVariant;
return h('div', {
directives: [{
name: 'show',
value: ctx.localShow
}],
staticClass: 'b-sidebar-backdrop',
class: _defineProperty({}, "bg-".concat(backdropVariant), !!backdropVariant),
on: {
click: ctx.onBackdropClick
}
});
}; // --- Main component ---
// @vue/component
var BSidebar = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_SIDEBAR,
// Mixin order is important!
mixins: [attrsMixin, idMixin, listenOnRootMixin, normalizeSlotMixin],
inheritAttrs: false,
model: {
prop: 'visible',
event: 'change'
},
props: makePropsConfigurable({
title: {
type: String // default: null
},
right: {
type: Boolean,
default: false
},
bgVariant: {
type: String,
default: 'light'
},
textVariant: {
type: String,
default: 'dark'
},
shadow: {
type: [Boolean, String],
default: false
},
width: {
type: String // default: undefined
},
zIndex: {
type: [Number, String] // default: null
},
ariaLabel: {
type: String // default: null
},
ariaLabelledby: {
type: String // default: null
},
closeLabel: {
// `aria-label` for close button
// Defaults to 'Close'
type: String // default: undefined
},
tag: {
type: String,
default: 'div'
},
sidebarClass: {
type: [String, Array, Object] // default: null
},
headerClass: {
type: [String, Array, Object] // default: null
},
bodyClass: {
type: [String, Array, Object] // default: null
},
footerClass: {
type: [String, Array, Object] // default: null
},
backdrop: {
// If `true`, shows a basic backdrop
type: Boolean,
default: false
},
backdropVariant: {
type: String,
default: 'dark'
},
noSlide: {
type: Boolean,
default: false
},
noHeader: {
type: Boolean,
default: false
},
noHeaderClose: {
type: Boolean,
default: false
},
noCloseOnEsc: {
type: Boolean,
default: false
},
noCloseOnBackdrop: {
type: Boolean,
default: false
},
noCloseOnRouteChange: {
type: Boolean,
default: false
},
noEnforceFocus: {
type: Boolean,
default: false
},
lazy: {
type: Boolean,
default: false
},
visible: {
type: Boolean,
default: false
}
}, NAME_SIDEBAR),
data: function data() {
return {
// Internal `v-model` state
localShow: !!this.visible,
// For lazy render triggering
isOpen: !!this.visible
};
},
computed: {
transitionProps: function transitionProps() {
return this.noSlide ?
/* istanbul ignore next */
{
css: true
} : {
css: true,
enterClass: '',
enterActiveClass: 'slide',
enterToClass: 'show',
leaveClass: 'show',
leaveActiveClass: 'slide',
leaveToClass: ''
};
},
slotScope: function slotScope() {
return {
visible: this.localShow,
right: this.right,
hide: this.hide
};
},
computedTile: function computedTile() {
return this.normalizeSlot(SLOT_NAME_TITLE, this.slotScope) || toString$1(this.title) || null;
},
titleId: function titleId() {
return this.computedTile ? this.safeId('__title__') : null;
},
computedAttrs: function computedAttrs() {
return _objectSpread2(_objectSpread2({}, this.bvAttrs), {}, {
id: this.safeId(),
tabindex: '-1',
role: 'dialog',
'aria-modal': this.backdrop ? 'true' : 'false',
'aria-hidden': this.localShow ? null : 'true',
'aria-label': this.ariaLabel || null,
'aria-labelledby': this.ariaLabelledby || this.titleId || null
});
}
},
watch: {
visible: function visible(newVal, oldVal) {
if (newVal !== oldVal) {
this.localShow = newVal;
}
},
localShow: function localShow(newVal, oldVal) {
if (newVal !== oldVal) {
this.emitState(newVal);
this.$emit('change', newVal);
}
},
/* istanbul ignore next */
$route: function $route() {
var newVal = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var oldVal = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (!this.noCloseOnRouteChange && newVal.fullPath !== oldVal.fullPath) {
this.hide();
}
}
},
created: function created() {
// Define non-reactive properties
this.$_returnFocusEl = null;
},
mounted: function mounted() {
var _this = this;
// Add `$root` listeners
this.listenOnRoot(EVENT_TOGGLE, this.handleToggle);
this.listenOnRoot(EVENT_STATE_REQUEST, this.handleSync); // Send out a gratuitous state event to ensure toggle button is synced
this.$nextTick(function () {
_this.emitState(_this.localShow);
});
},
/* istanbul ignore next */
activated: function activated() {
this.emitSync();
},
beforeDestroy: function beforeDestroy() {
this.localShow = false;
this.$_returnFocusEl = null;
},
methods: {
hide: function hide() {
this.localShow = false;
},
emitState: function emitState() {
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.localShow;
this.emitOnRoot(EVENT_STATE, this.safeId(), state);
},
emitSync: function emitSync() {
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.localShow;
this.emitOnRoot(EVENT_STATE_SYNC, this.safeId(), state);
},
handleToggle: function handleToggle(id) {
// Note `safeId()` can be null until after mount
if (id && id === this.safeId()) {
this.localShow = !this.localShow;
}
},
handleSync: function handleSync(id) {
var _this2 = this;
// Note `safeId()` can be null until after mount
if (id && id === this.safeId()) {
this.$nextTick(function () {
_this2.emitSync(_this2.localShow);
});
}
},
onKeydown: function onKeydown(evt) {
var keyCode = evt.keyCode;
if (!this.noCloseOnEsc && keyCode === CODE_ESC && this.localShow) {
this.hide();
}
},
onBackdropClick: function onBackdropClick() {
if (this.localShow && !this.noCloseOnBackdrop) {
this.hide();
}
},
/* istanbul ignore next */
onTopTrapFocus: function onTopTrapFocus() {
var tabables = getTabables(this.$refs.content);
this.enforceFocus(tabables.reverse()[0]);
},
/* istanbul ignore next */
onBottomTrapFocus: function onBottomTrapFocus() {
var tabables = getTabables(this.$refs.content);
this.enforceFocus(tabables[0]);
},
onBeforeEnter: function onBeforeEnter() {
// Returning focus to `document.body` may cause unwanted scrolls,
// so we exclude setting focus on body
this.$_returnFocusEl = getActiveElement(isBrowser ? [document.body] : []); // Trigger lazy render
this.isOpen = true;
},
onAfterEnter: function onAfterEnter(el) {
if (!contains(el, getActiveElement())) {
this.enforceFocus(el);
}
this.$emit('shown');
},
onAfterLeave: function onAfterLeave() {
this.enforceFocus(this.$_returnFocusEl);
this.$_returnFocusEl = null; // Trigger lazy render
this.isOpen = false;
this.$emit('hidden');
},
enforceFocus: function enforceFocus(el) {
if (!this.noEnforceFocus) {
attemptFocus(el);
}
}
},
render: function render(h) {
var _ref;
var localShow = this.localShow;
var shadow = this.shadow === '' ? true : this.shadow;
var $sidebar = h(this.tag, {
ref: 'content',
directives: [{
name: 'show',
value: localShow
}],
staticClass: CLASS_NAME$3,
class: [(_ref = {
shadow: shadow === true
}, _defineProperty(_ref, "shadow-".concat(shadow), shadow && shadow !== true), _defineProperty(_ref, "".concat(CLASS_NAME$3, "-right"), this.right), _defineProperty(_ref, "bg-".concat(this.bgVariant), !!this.bgVariant), _defineProperty(_ref, "text-".concat(this.textVariant), !!this.textVariant), _ref), this.sidebarClass],
attrs: this.computedAttrs,
style: {
width: this.width
}
}, [renderContent(h, this)]);
$sidebar = h('transition', {
props: this.transitionProps,
on: {
beforeEnter: this.onBeforeEnter,
afterEnter: this.onAfterEnter,
afterLeave: this.onAfterLeave
}
}, [$sidebar]);
var $backdrop = h(BVTransition, {
props: {
noFade: this.noSlide
}
}, [renderBackdrop(h, this)]);
var $tabTrapTop = h();
var $tabTrapBottom = h();
if (this.backdrop && this.localShow) {
$tabTrapTop = h('div', {
attrs: {
tabindex: '0'
},
on: {
focus: this.onTopTrapFocus
}
});
$tabTrapBottom = h('div', {
attrs: {
tabindex: '0'
},
on: {
focus: this.onBottomTrapFocus
}
});
}
return h('div', {
staticClass: 'b-sidebar-outer',
style: {
zIndex: this.zIndex
},
attrs: {
tabindex: '-1'
},
on: {
keydown: this.onKeydown
}
}, [$tabTrapTop, $sidebar, $tabTrapBottom, $backdrop]);
}
});
var SidebarPlugin = /*#__PURE__*/pluginFactory({
components: {
BSidebar: BSidebar
},
plugins: {
VBTogglePlugin: VBTogglePlugin
}
});
var BSkeleton = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_SKELETON,
functional: true,
props: makePropsConfigurable({
animation: {
type: String,
default: 'wave'
},
type: {
type: String,
default: 'text'
},
width: {
type: String // default: null
},
height: {
type: String // default: null
},
size: {
type: String // default: null
},
variant: {
type: String // default: null
}
}, NAME_SKELETON),
render: function render(h, _ref) {
var _class;
var data = _ref.data,
props = _ref.props;
var size = props.size,
animation = props.animation,
variant = props.variant;
return h('div', a(data, {
staticClass: 'b-skeleton',
style: {
width: size || props.width,
height: size || props.height
},
class: (_class = {}, _defineProperty(_class, "b-skeleton-".concat(props.type), true), _defineProperty(_class, "b-skeleton-animate-".concat(animation), animation), _defineProperty(_class, "bg-".concat(variant), variant), _class)
}));
}
});
var BIconstack = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_ICONSTACK,
functional: true,
props: makePropsConfigurable(commonIconProps, NAME_ICONSTACK),
render: function render(h, _ref) {
var data = _ref.data,
props = _ref.props,
children = _ref.children;
return h(BVIconBase, a(data, {
staticClass: 'b-iconstack',
props: _objectSpread2(_objectSpread2({}, props), {}, {
stacked: false
})
}), children);
}
});
var BSkeletonIcon = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_SKELETON_ICON,
functional: true,
props: makePropsConfigurable({
animation: {
type: String,
default: 'wave'
},
icon: {
type: String
},
iconProps: {
type: Object,
default: function _default() {}
}
}, NAME_SKELETON_ICON),
render: function render(h, _ref) {
var props = _ref.props;
var icon = props.icon,
animation = props.animation;
var $icon = h(BIcon, {
props: _objectSpread2({
icon: icon
}, props.iconProps),
staticClass: 'b-skeleton-icon'
});
return h('div', {
staticClass: 'b-skeleton-icon-wrapper position-relative d-inline-block overflow-hidden',
class: _defineProperty({}, "b-skeleton-animate-".concat(animation), animation)
}, [$icon]);
}
});
var BSkeletonImg = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_SKELETON_IMG,
functional: true,
props: makePropsConfigurable({
animation: {
type: String
},
aspect: {
type: String,
default: '16:9'
},
noAspect: {
type: Boolean,
default: false
},
height: {
type: String
},
width: {
type: String
},
variant: {
type: String
},
cardImg: {
type: String
}
}, NAME_SKELETON_IMG),
render: function render(h, _ref) {
var props = _ref.props;
var aspect = props.aspect,
width = props.width,
height = props.height,
animation = props.animation,
variant = props.variant,
cardImg = props.cardImg;
var $img = h(BSkeleton, {
props: {
type: 'img',
width: width,
height: height,
animation: animation,
variant: variant
},
class: _defineProperty({}, "card-img-".concat(cardImg), cardImg)
});
return props.noAspect ? $img : h(BAspect, {
props: {
aspect: aspect
}
}, [$img]);
}
});
// Mixin to determine if an event listener has been registered
var hasListenerMixin = {
methods: {
hasListener: function hasListener(name) {
// Only includes listeners registered via `v-on:name`
var $listeners = this.$listeners || {}; // Includes `v-on:name` and `this.$on('name')` registered listeners
// Note this property is not part of the public Vue API, but it is
// the only way to determine if a listener was added via `vm.$on`
var $events = this._events || {}; // Registered listeners in `this._events` are always an array,
// but might be zero length
return !isUndefined($listeners[name]) || isArray($events[name]) && $events[name].length > 0;
}
}
};
var props$14 = makePropsConfigurable({
variant: {
type: String,
default: null
}
}, NAME_TR);
var LIGHT = 'light';
var DARK = 'dark'; // TODO:
// In Bootstrap v5, we won't need "sniffing" as table element variants properly inherit
// to the child elements, so this can be converted to a functional component
// @vue/component
var BTr = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_TR,
// Mixin order is important!
mixins: [attrsMixin, listenersMixin, normalizeSlotMixin],
provide: function provide() {
return {
bvTableTr: this
};
},
inject: {
bvTableRowGroup: {
/* istanbul ignore next */
default: function _default() {
return {};
}
}
},
inheritAttrs: false,
props: props$14,
computed: {
inTbody: function inTbody() {
// Sniffed by <b-td> / <b-th>
return this.bvTableRowGroup.isTbody;
},
inThead: function inThead() {
// Sniffed by <b-td> / <b-th>
return this.bvTableRowGroup.isThead;
},
inTfoot: function inTfoot() {
// Sniffed by <b-td> / <b-th>
return this.bvTableRowGroup.isTfoot;
},
isDark: function isDark() {
// Sniffed by <b-td> / <b-th>
return this.bvTableRowGroup.isDark;
},
isStacked: function isStacked() {
// Sniffed by <b-td> / <b-th>
return this.bvTableRowGroup.isStacked;
},
isResponsive: function isResponsive() {
// Sniffed by <b-td> / <b-th>
return this.bvTableRowGroup.isResponsive;
},
isStickyHeader: function isStickyHeader() {
// Sniffed by <b-td> / <b-th>
// Sticky headers are only supported in thead
return this.bvTableRowGroup.isStickyHeader;
},
hasStickyHeader: function hasStickyHeader() {
// Sniffed by <b-tr> / <b-td> / <b-th>
// Needed to handle header background classes, due to lack of
// background color inheritance with Bootstrap v4 table CSS
return !this.isStacked && this.bvTableRowGroup.hasStickyHeader;
},
tableVariant: function tableVariant() {
// Sniffed by <b-td> / <b-th>
return this.bvTableRowGroup.tableVariant;
},
headVariant: function headVariant() {
// Sniffed by <b-td> / <b-th>
return this.inThead ? this.bvTableRowGroup.headVariant : null;
},
footVariant: function footVariant() {
// Sniffed by <b-td> / <b-th>
return this.inTfoot ? this.bvTableRowGroup.footVariant : null;
},
isRowDark: function isRowDark() {
return this.headVariant === LIGHT || this.footVariant === LIGHT ?
/* istanbul ignore next */
false : this.headVariant === DARK || this.footVariant === DARK ?
/* istanbul ignore next */
true : this.isDark;
},
trClasses: function trClasses() {
return [this.variant ? "".concat(this.isRowDark ? 'bg' : 'table', "-").concat(this.variant) : null];
},
trAttrs: function trAttrs() {
return _objectSpread2({
role: 'row'
}, this.bvAttrs);
}
},
render: function render(h) {
return h('tr', {
class: this.trClasses,
attrs: this.trAttrs,
// Pass native listeners to child
on: this.bvListeners
}, this.normalizeSlot());
}
});
var slotName = 'bottom-row';
var bottomRowMixin = {
methods: {
renderBottomRow: function renderBottomRow() {
var h = this.$createElement; // 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 (!this.hasNormalizedSlot(slotName) || this.stacked === true || this.stacked === '') {
return h();
}
var fields = this.computedFields;
return h(BTr, {
key: 'b-bottom-row',
staticClass: 'b-table-bottom-row',
class: [isFunction(this.tbodyTrClass) ?
/* istanbul ignore next */
this.tbodyTrClass(null, 'row-bottom') : this.tbodyTrClass],
attrs: isFunction(this.tbodyTrAttr) ?
/* istanbul ignore next */
this.tbodyTrAttr(null, 'row-bottom') : this.tbodyTrAttr
}, this.normalizeSlot(slotName, {
columns: fields.length,
fields: fields
}));
}
}
};
// Parse a rowspan or colspan into a digit (or `null` if < `1` )
var parseSpan = function parseSpan(value) {
value = toInteger(value, 0);
return value > 0 ? value : null;
};
/* istanbul ignore next */
var spanValidator = function spanValidator(val) {
return isUndefinedOrNull(val) || parseSpan(val) > 0;
}; // --- Props ---
var props$15 = makePropsConfigurable({
variant: {
type: String,
default: null
},
colspan: {
type: [Number, String],
default: null,
validator: spanValidator
},
rowspan: {
type: [Number, String],
default: null,
validator: spanValidator
},
stackedHeading: {
type: String,
default: null
},
stickyColumn: {
type: Boolean,
default: false
}
}, NAME_TABLE_CELL); // --- Main component ---
// TODO:
// In Bootstrap v5, we won't need "sniffing" as table element variants properly inherit
// to the child elements, so this can be converted to a functional component
// @vue/component
var BTd = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_TABLE_CELL,
// Mixin order is important!
mixins: [attrsMixin, listenersMixin, normalizeSlotMixin],
inject: {
bvTableTr: {
/* istanbul ignore next */
default: function _default() {
return {};
}
}
},
inheritAttrs: false,
props: props$15,
computed: {
tag: function tag() {
// Overridden by <b-th>
return 'td';
},
inTbody: function inTbody() {
return this.bvTableTr.inTbody;
},
inThead: function inThead() {
return this.bvTableTr.inThead;
},
inTfoot: function inTfoot() {
return this.bvTableTr.inTfoot;
},
isDark: function isDark() {
return this.bvTableTr.isDark;
},
isStacked: function isStacked() {
return this.bvTableTr.isStacked;
},
isStackedCell: function isStackedCell() {
// We only support stacked-heading in tbody in stacked mode
return this.inTbody && this.isStacked;
},
isResponsive: function isResponsive() {
return this.bvTableTr.isResponsive;
},
isStickyHeader: function isStickyHeader() {
// Needed to handle header background classes, due to lack of
// background color inheritance with Bootstrap v4 table CSS
// Sticky headers only apply to cells in table `thead`
return this.bvTableTr.isStickyHeader;
},
hasStickyHeader: function hasStickyHeader() {
// Needed to handle header background classes, due to lack of
// background color inheritance with Bootstrap v4 table CSS
return this.bvTableTr.hasStickyHeader;
},
isStickyColumn: function isStickyColumn() {
// Needed to handle background classes, due to lack of
// background color inheritance with Bootstrap v4 table CSS
// Sticky column cells are only available in responsive
// mode (horizontal scrolling) or when sticky header mode
// Applies to cells in `thead`, `tbody` and `tfoot`
return !this.isStacked && (this.isResponsive || this.hasStickyHeader) && this.stickyColumn;
},
rowVariant: function rowVariant() {
return this.bvTableTr.variant;
},
headVariant: function headVariant() {
return this.bvTableTr.headVariant;
},
footVariant: function footVariant() {
return this.bvTableTr.footVariant;
},
tableVariant: function tableVariant() {
return this.bvTableTr.tableVariant;
},
computedColspan: function computedColspan() {
return parseSpan(this.colspan);
},
computedRowspan: function computedRowspan() {
return parseSpan(this.rowspan);
},
cellClasses: function cellClasses() {
// We use computed props here for improved performance by caching
// the results of the string interpolation
var variant = this.variant;
if (!variant && this.isStickyHeader && !this.headVariant || !variant && this.isStickyColumn && this.inTfoot && !this.footVariant || !variant && this.isStickyColumn && this.inThead && !this.headVariant || !variant && this.isStickyColumn && this.inTbody) {
// Needed for sticky-header mode as Bootstrap v4 table cells do
// not inherit parent's background-color. Boo!
variant = this.rowVariant || this.tableVariant || 'b-table-default';
}
return [variant ? "".concat(this.isDark ? 'bg' : 'table', "-").concat(variant) : null, this.isStickyColumn ? 'b-table-sticky-column' : null];
},
cellAttrs: function cellAttrs() {
// We use computed props here for improved performance by caching
// the results of the object spread (Object.assign)
var headOrFoot = this.inThead || this.inTfoot; // Make sure col/rowspan's are > 0 or null
var colspan = this.computedColspan;
var rowspan = this.computedRowspan; // Default role and scope
var role = 'cell';
var scope = null; // Compute role and scope
// We only add scopes with an explicit span of 1 or greater
if (headOrFoot) {
// Header or footer cells
role = 'columnheader';
scope = colspan > 0 ? 'colspan' : 'col';
} else if (isTag(this.tag, 'th')) {
// th's in tbody
role = 'rowheader';
scope = rowspan > 0 ? 'rowgroup' : 'row';
}
return _objectSpread2(_objectSpread2({
colspan: colspan,
rowspan: rowspan,
role: role,
scope: scope
}, this.bvAttrs), {}, {
// Add in the stacked cell label data-attribute if in
// stacked mode (if a stacked heading label is provided)
'data-label': this.isStackedCell && !isUndefinedOrNull(this.stackedHeading) ?
/* istanbul ignore next */
toString$1(this.stackedHeading) : null
});
}
},
render: function render(h) {
var content = [this.normalizeSlot()];
return h(this.tag, {
class: this.cellClasses,
attrs: this.cellAttrs,
// Transfer any native listeners
on: this.bvListeners
}, [this.isStackedCell ? h('div', [content]) : content]);
}
});
var busySlotName = 'table-busy';
var busyMixin = {
props: makePropsConfigurable({
busy: {
type: Boolean,
default: false
}
}, NAME_TABLE),
data: function data() {
return {
localBusy: false
};
},
computed: {
computedBusy: function computedBusy() {
return this.busy || this.localBusy;
}
},
watch: {
localBusy: function localBusy(newVal, oldVal) {
if (newVal !== oldVal) {
this.$emit('update:busy', newVal);
}
}
},
methods: {
// Event handler helper
stopIfBusy: function stopIfBusy(evt) {
if (this.computedBusy) {
// If table is busy (via provider) then don't propagate
stopEvent(evt);
return true;
}
return false;
},
// Render the busy indicator or return `null` if not busy
renderBusy: function renderBusy() {
var h = this.$createElement; // Return a busy indicator row, or `null` if not busy
if (this.computedBusy && this.hasNormalizedSlot(busySlotName)) {
// Show the busy slot
return h(BTr, {
key: 'table-busy-slot',
staticClass: 'b-table-busy-slot',
class: [isFunction(this.tbodyTrClass) ?
/* istanbul ignore next */
this.tbodyTrClass(null, busySlotName) : this.tbodyTrClass],
attrs: isFunction(this.tbodyTrAttr) ?
/* istanbul ignore next */
this.tbodyTrAttr(null, busySlotName) : this.tbodyTrAttr
}, [h(BTd, {
props: {
colspan: this.computedFields.length || null
}
}, [this.normalizeSlot(busySlotName)])]);
} else {
// We return `null` here so that we can determine if we need to
// render the table items rows or not
return null;
}
}
}
};
var captionMixin = {
props: makePropsConfigurable({
// `caption-top` is part of table-render mixin (styling)
// captionTop: {
// type: Boolean,
// default: false
// },
caption: {
type: String // default: null
},
captionHtml: {
type: String
}
}, NAME_TABLE),
computed: {
captionId: function captionId() {
// Even though `this.safeId` looks like a method, it is a computed prop
// that returns a new function if the underlying ID changes
return this.isStacked ? this.safeId('_caption_') : null;
}
},
methods: {
renderCaption: function renderCaption() {
var caption = this.caption,
captionHtml = this.captionHtml;
var h = this.$createElement;
var $caption = h();
var hasCaptionSlot = this.hasNormalizedSlot('table-caption');
if (hasCaptionSlot || caption || captionHtml) {
$caption = h('caption', {
key: 'caption',
attrs: {
id: this.captionId
},
domProps: hasCaptionSlot ? {} : htmlOrText(captionHtml, caption)
}, this.normalizeSlot('table-caption'));
}
return $caption;
}
}
};
var colgroupMixin = {
methods: {
renderColgroup: function renderColgroup() {
var h = this.$createElement;
var fields = this.computedFields;
var $colgroup = h();
if (this.hasNormalizedSlot('table-colgroup')) {
$colgroup = h('colgroup', {
key: 'colgroup'
}, [this.normalizeSlot('table-colgroup', {
columns: fields.length,
fields: fields
})]);
}
return $colgroup;
}
}
};
var emptyMixin = {
props: makePropsConfigurable({
showEmpty: {
type: Boolean,
default: false
},
emptyText: {
type: String,
default: 'There are no records to show'
},
emptyHtml: {
type: String
},
emptyFilteredText: {
type: String,
default: 'There are no records matching your request'
},
emptyFilteredHtml: {
type: String
}
}, NAME_TABLE),
methods: {
renderEmpty: function renderEmpty() {
var h = this.$createElement;
var items = this.computedItems;
var $empty = h();
if (this.showEmpty && (!items || items.length === 0) && !(this.computedBusy && this.hasNormalizedSlot('table-busy'))) {
var isFiltered = this.isFiltered,
emptyText = this.emptyText,
emptyHtml = this.emptyHtml,
emptyFilteredText = this.emptyFilteredText,
emptyFilteredHtml = this.emptyFilteredHtml,
computedFields = this.computedFields,
tbodyTrClass = this.tbodyTrClass,
tbodyTrAttr = this.tbodyTrAttr;
$empty = this.normalizeSlot(this.isFiltered ? 'emptyfiltered' : 'empty', {
emptyFilteredHtml: emptyFilteredHtml,
emptyFilteredText: emptyFilteredText,
emptyHtml: emptyHtml,
emptyText: emptyText,
fields: computedFields,
// Not sure why this is included, as it will always be an empty array
items: this.computedItems
});
if (!$empty) {
$empty = h('div', {
class: ['text-center', 'my-2'],
domProps: isFiltered ? htmlOrText(emptyFilteredHtml, emptyFilteredText) : htmlOrText(emptyHtml, emptyText)
});
}
$empty = h(BTd, {
props: {
colspan: computedFields.length || null
}
}, [h('div', {
attrs: {
role: 'alert',
'aria-live': 'polite'
}
}, [$empty])]);
$empty = h(BTr, {
staticClass: 'b-table-empty-row',
class: [isFunction(tbodyTrClass) ?
/* istanbul ignore next */
this.tbodyTrClass(null, 'row-empty') : tbodyTrClass],
attrs: isFunction(tbodyTrAttr) ?
/* istanbul ignore next */
this.tbodyTrAttr(null, 'row-empty') : tbodyTrAttr,
key: isFiltered ? 'b-empty-filtered-row' : 'b-empty-row'
}, [$empty]);
}
return $empty;
}
}
};
// Constants used by table helpers
// Object of item keys that should be ignored for headers and
// stringification and filter events
var IGNORED_FIELD_KEYS = {
_rowVariant: true,
_cellVariants: true,
_showDetails: true
}; // Filter CSS selector for click/dblclick/etc. events
// If any of these selectors match the clicked element, we ignore the event
var EVENT_FILTER = ['a', 'a *', // Include content inside links
'button', 'button *', // Include content inside buttons
'input:not(.disabled):not([disabled])', 'select:not(.disabled):not([disabled])', 'textarea:not(.disabled):not([disabled])', '[role="link"]', '[role="link"] *', '[role="button"]', '[role="button"] *', '[tabindex]:not(.disabled):not([disabled])'].join(',');
var sanitizeRow = function sanitizeRow(row, ignoreFields, includeFields) {
var fieldsObj = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
// We first need to format the row based on the field configurations
// This ensures that we add formatted values for keys that may not
// exist in the row itself
var formattedRow = keys(fieldsObj).reduce(function (result, key) {
var field = fieldsObj[key];
var filterByFormatted = field.filterByFormatted;
var formatter = isFunction(filterByFormatted) ?
/* istanbul ignore next */
filterByFormatted : filterByFormatted ?
/* istanbul ignore next */
field.formatter : null;
if (isFunction(formatter)) {
result[key] = formatter(row[key], key, row);
}
return result;
}, clone(row)); // Determine the allowed keys:
// - Ignore special fields that start with `_`
// - Ignore fields in the `ignoreFields` array
// - Include only fields in the `includeFields` array
var allowedKeys = keys(formattedRow).filter(function (key) {
return !IGNORED_FIELD_KEYS[key] && !(isArray(ignoreFields) && ignoreFields.length > 0 && arrayIncludes(ignoreFields, key)) && !(isArray(includeFields) && includeFields.length > 0 && !arrayIncludes(includeFields, key));
});
return pick(formattedRow, allowedKeys);
};
// SSR safe deterministic way (keys are sorted before stringification)
//
// ex:
// { b: 3, c: { z: 'zzz', d: null, e: 2 }, d: [10, 12, 11], a: 'one' }
// becomes
// 'one 3 2 zzz 10 12 11'
//
// Primitives (numbers/strings) are returned as-is
// Null and undefined values are filtered out
// Dates are converted to their native string format
var stringifyObjectValues = function stringifyObjectValues(val) {
if (isUndefinedOrNull(val)) {
/* istanbul ignore next */
return '';
} // Arrays are also object, and keys just returns the array indexes
// Date objects we convert to strings
if (isObject(val) && !isDate(val)) {
return keys(val).sort() // Sort to prevent SSR issues on pre-rendered sorted tables
.filter(function (v) {
return !isUndefinedOrNull(v);
}) // Ignore undefined/null values
.map(function (k) {
return stringifyObjectValues(val[k]);
}).join(' ');
}
return toString$1(val);
};
// TODO: Add option to stringify `scopedSlot` items
var stringifyRecordValues = function stringifyRecordValues(row, ignoreFields, includeFields, fieldsObj) {
return isObject(row) ? stringifyObjectValues(sanitizeRow(row, ignoreFields, includeFields, fieldsObj)) :
/* istanbul ignore next */
'';
};
var DEBOUNCE_DEPRECATED_MSG = 'Prop "filter-debounce" is deprecated. Use the debounce feature of "<b-form-input>" instead.';
var filteringMixin = {
props: makePropsConfigurable({
filter: {
type: [String, RegExp, Object, Array],
default: null
},
filterFunction: {
type: Function // default: null
},
filterIgnoredFields: {
type: Array // default: undefined
},
filterIncludedFields: {
type: Array // default: undefined
},
filterDebounce: {
type: [Number, String],
deprecated: DEBOUNCE_DEPRECATED_MSG,
default: 0,
validator: function validator(value) {
return /^\d+/.test(String(value));
}
}
}, NAME_TABLE),
data: function data() {
return {
// Flag for displaying which empty slot to show and some event triggering
isFiltered: false,
// Where we store the copy of the filter criteria after debouncing
// We pre-set it with the sanitized filter value
localFilter: this.filterSanitize(this.filter)
};
},
computed: {
computedFilterIgnored: function computedFilterIgnored() {
return concat(this.filterIgnoredFields || []).filter(identity);
},
computedFilterIncluded: function computedFilterIncluded() {
return concat(this.filterIncludedFields || []).filter(identity);
},
computedFilterDebounce: function computedFilterDebounce() {
var ms = toInteger(this.filterDebounce, 0);
/* istanbul ignore next */
if (ms > 0) {
warn(DEBOUNCE_DEPRECATED_MSG, NAME_TABLE);
}
return ms;
},
localFiltering: function localFiltering() {
return this.hasProvider ? !!this.noProviderFiltering : true;
},
// For watching changes to `filteredItems` vs `localItems`
filteredCheck: function filteredCheck() {
return {
filteredItems: this.filteredItems,
localItems: this.localItems,
localFilter: this.localFilter
};
},
// Sanitized/normalize filter-function prop
localFilterFn: function localFilterFn() {
// Return `null` to signal to use internal filter function
var filterFunction = this.filterFunction;
var result = null;
try {
result = filterFunction();
} catch (_unused) {}
return isUndefined(result) ? null : filterFunction;
},
// Returns the records in `localItems` that match the filter criteria
// Returns the original `localItems` array if not sorting
filteredItems: function filteredItems() {
var items = this.localItems || []; // Note the criteria is debounced and sanitized
var criteria = this.localFilter; // Resolve the filtering function, when requested
// We prefer the provided filtering function and fallback to the internal one
// When no filtering criteria is specified the filtering factories will return `null`
var filterFn = this.localFiltering ? this.filterFnFactory(this.localFilterFn, criteria) || this.defaultFilterFnFactory(criteria) : null; // We only do local filtering when requested and there are records to filter
return filterFn && items.length > 0 ? items.filter(filterFn) : items;
}
},
watch: {
// Watch for debounce being set to 0
computedFilterDebounce: function computedFilterDebounce(newVal) {
if (!newVal && this.$_filterTimer) {
this.clearFilterTimer();
this.localFilter = this.filterSanitize(this.filter);
}
},
// Watch for changes to the filter criteria, and debounce if necessary
filter: {
// We need a deep watcher in case the user passes
// an object when using `filter-function`
deep: true,
handler: function handler(newCriteria) {
var _this = this;
var timeout = this.computedFilterDebounce;
this.clearFilterTimer();
if (timeout && timeout > 0) {
// If we have a debounce time, delay the update of `localFilter`
this.$_filterTimer = setTimeout(function () {
_this.localFilter = _this.filterSanitize(newCriteria);
}, timeout);
} else {
// Otherwise, immediately update `localFilter` with `newFilter` value
this.localFilter = this.filterSanitize(newCriteria);
}
}
},
// Watch for changes to the filter criteria and filtered items vs `localItems`
// Set visual state and emit events as required
filteredCheck: function filteredCheck(_ref) {
var filteredItems = _ref.filteredItems,
localFilter = _ref.localFilter;
// Determine if the dataset is filtered or not
var isFiltered = false;
if (!localFilter) {
// If filter criteria is falsey
isFiltered = false;
} else if (looseEqual(localFilter, []) || looseEqual(localFilter, {})) {
// If filter criteria is an empty array or object
isFiltered = false;
} else if (localFilter) {
// If filter criteria is truthy
isFiltered = true;
}
if (isFiltered) {
this.$emit('filtered', filteredItems, filteredItems.length);
}
this.isFiltered = isFiltered;
},
isFiltered: function isFiltered(newVal, oldVal) {
if (newVal === false && oldVal === true) {
// We need to emit a filtered event if isFiltered transitions from true to
// false so that users can update their pagination controls.
this.$emit('filtered', this.localItems, this.localItems.length);
}
}
},
created: function created() {
var _this2 = this;
// Create private non-reactive props
this.$_filterTimer = null; // If filter is "pre-set", set the criteria
// This will trigger any watchers/dependents
// this.localFilter = this.filterSanitize(this.filter)
// Set the initial filtered state in a `$nextTick()` so that
// we trigger a filtered event if needed
this.$nextTick(function () {
_this2.isFiltered = Boolean(_this2.localFilter);
});
},
beforeDestroy: function beforeDestroy() {
this.clearFilterTimer();
},
methods: {
clearFilterTimer: function clearFilterTimer() {
clearTimeout(this.$_filterTimer);
this.$_filterTimer = null;
},
filterSanitize: function filterSanitize(criteria) {
// Sanitizes filter criteria based on internal or external filtering
if (this.localFiltering && !this.localFilterFn && !(isString(criteria) || isRegExp(criteria))) {
// If using internal filter function, which only accepts string or RegExp,
// return '' to signify no filter
return '';
} // Could be a string, object or array, as needed by external filter function
// We use `cloneDeep` to ensure we have a new copy of an object or array
// without Vue's reactive observers
return cloneDeep(criteria);
},
// Filter Function factories
filterFnFactory: function filterFnFactory(filterFn, criteria) {
// Wrapper factory for external filter functions
// Wrap the provided filter-function and return a new function
// Returns `null` if no filter-function defined or if criteria is falsey
// Rather than directly grabbing `this.computedLocalFilterFn` or `this.filterFunction`
// we have it passed, so that the caller computed prop will be reactive to changes
// in the original filter-function (as this routine is a method)
if (!filterFn || !isFunction(filterFn) || !criteria || looseEqual(criteria, []) || looseEqual(criteria, {})) {
return null;
} // Build the wrapped filter test function, passing the criteria to the provided function
var fn = function fn(item) {
// Generated function returns true if the criteria matches part
// of the serialized data, otherwise false
return filterFn(item, criteria);
}; // Return the wrapped function
return fn;
},
defaultFilterFnFactory: function defaultFilterFnFactory(criteria) {
var _this3 = this;
// Generates the default filter function, using the given filter criteria
// Returns `null` if no criteria or criteria format not supported
if (!criteria || !(isString(criteria) || isRegExp(criteria))) {
// Built in filter can only support strings or RegExp criteria (at the moment)
return null;
} // Build the RegExp needed for filtering
var regExp = criteria;
if (isString(regExp)) {
// Escape special RegExp characters in the string and convert contiguous
// whitespace to \s+ matches
var pattern = escapeRegExp(criteria).replace(RX_SPACES, '\\s+'); // Build the RegExp (no need for global flag, as we only need
// to find the value once in the string)
regExp = new RegExp(".*".concat(pattern, ".*"), 'i');
} // Generate the wrapped filter test function to use
var fn = function fn(item) {
// This searches all row values (and sub property values) in the entire (excluding
// special `_` prefixed keys), because we convert the record to a space-separated
// string containing all the value properties (recursively), even ones that are
// not visible (not specified in this.fields)
// Users can ignore filtering on specific fields, or on only certain fields,
// and can optionall specify searching results of fields with formatter
//
// TODO: Enable searching on scoped slots (optional, as it will be SLOW)
//
// Generated function returns true if the criteria matches part of
// the serialized data, otherwise false
//
// We set `lastIndex = 0` on the `RegExp` in case someone specifies the `/g` global flag
regExp.lastIndex = 0;
return regExp.test(stringifyRecordValues(item, _this3.computedFilterIgnored, _this3.computedFilterIncluded, _this3.computedFieldsObj));
}; // Return the generated function
return fn;
}
}
};
var processField = function processField(key, value) {
var field = null;
if (isString(value)) {
// Label shortcut
field = {
key: key,
label: value
};
} else if (isFunction(value)) {
// Formatter shortcut
field = {
key: key,
formatter: value
};
} else if (isObject(value)) {
field = clone(value);
field.key = field.key || key;
} else if (value !== false) {
// Fallback to just key
/* istanbul ignore next */
field = {
key: key
};
}
return field;
}; // We normalize fields into an array of objects
// [ { key:..., label:..., ...}, {...}, ..., {..}]
var normalizeFields = function normalizeFields(origFields, items) {
var fields = [];
if (isArray(origFields)) {
// Normalize array Form
origFields.filter(identity).forEach(function (f) {
if (isString(f)) {
fields.push({
key: f,
label: startCase(f)
});
} else if (isObject(f) && f.key && isString(f.key)) {
// Full object definition. We use assign so that we don't mutate the original
fields.push(clone(f));
} else if (isObject(f) && 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);
}
}
});
} // If no field provided, take a sample from first record (if exits)
if (fields.length === 0 && isArray(items) && items.length > 0) {
var sample = items[0];
keys(sample).forEach(function (k) {
if (!IGNORED_FIELD_KEYS[k]) {
fields.push({
key: k,
label: 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 = isString(f.label) ? f.label : startCase(f.key);
return true;
}
return false;
});
};
var itemsMixin = {
props: makePropsConfigurable({
items: {
// Provider mixin adds in `Function` type
type: Array,
/* istanbul ignore next */
default: function _default() {
return [];
}
},
fields: {
type: Array,
default: null
},
primaryKey: {
// Primary key for record
// If provided the value in each row must be unique!
type: String // default: null
},
value: {
// `v-model` for retrieving the current displayed rows
type: Array,
default: function _default() {
return [];
}
}
}, NAME_TABLE),
data: function data() {
return {
// Our local copy of the items
// Must be an array
localItems: isArray(this.items) ? this.items.slice() : []
};
},
computed: {
computedFields: function computedFields() {
// We normalize fields into an array of objects
// `[ { key:..., label:..., ...}, {...}, ..., {..}]`
return normalizeFields(this.fields, this.localItems);
},
computedFieldsObj: function computedFieldsObj() {
// Fields as a simple lookup hash object
// Mainly for formatter lookup and use in `scopedSlots` for convenience
// If the field has a formatter, it normalizes formatter to a
// function ref or `undefined` if no formatter
var parent = this.$parent;
return this.computedFields.reduce(function (obj, f) {
// We use object spread here so we don't mutate the original field object
obj[f.key] = clone(f);
if (f.formatter) {
// Normalize formatter to a function ref or `undefined`
var formatter = f.formatter;
if (isString(formatter) && isFunction(parent[formatter])) {
formatter = parent[formatter];
} else if (!isFunction(formatter)) {
/* istanbul ignore next */
formatter = undefined;
} // Return formatter function or `undefined` if none
obj[f.key].formatter = formatter;
}
return obj;
}, {});
},
computedItems: function computedItems() {
// Fallback if various mixins not provided
return (this.paginatedItems || this.sortedItems || this.filteredItems || this.localItems ||
/* istanbul ignore next */
[]).slice();
},
context: function context() {
// Current state of sorting, filtering and pagination props/values
return {
filter: this.localFilter,
sortBy: this.localSortBy,
sortDesc: this.localSortDesc,
perPage: mathMax(toInteger(this.perPage, 0), 0),
currentPage: mathMax(toInteger(this.currentPage, 0), 1),
apiUrl: this.apiUrl
};
}
},
watch: {
items: function items(newItems) {
/* istanbul ignore else */
if (isArray(newItems)) {
// Set `localItems`/`filteredItems` to a copy of the provided array
this.localItems = newItems.slice();
} else if (isUndefinedOrNull(newItems)) {
/* istanbul ignore next */
this.localItems = [];
}
},
// Watch for changes on `computedItems` and update the `v-model`
computedItems: function computedItems(newVal, oldVal) {
if (!looseEqual(newVal, oldVal)) {
this.$emit('input', newVal);
}
},
// Watch for context changes
context: function context(newVal, oldVal) {
// Emit context information for external paging/filtering/sorting handling
if (!looseEqual(newVal, oldVal)) {
this.$emit('context-changed', newVal);
}
}
},
mounted: function mounted() {
// Initially update the `v-model` of displayed items
this.$emit('input', this.computedItems);
},
methods: {
// Method to get the formatter method for a given field key
getFieldFormatter: function getFieldFormatter(key) {
var field = this.computedFieldsObj[key]; // `this.computedFieldsObj` has pre-normalized the formatter to a
// function ref if present, otherwise `undefined`
return field ? field.formatter : undefined;
}
}
};
var paginationMixin$1 = {
props: makePropsConfigurable({
perPage: {
type: [Number, String],
default: 0
},
currentPage: {
type: [Number, String],
default: 1
}
}, NAME_TABLE),
computed: {
localPaging: function localPaging() {
return this.hasProvider ? !!this.noProviderPaging : true;
},
paginatedItems: function paginatedItems() {
var items = this.sortedItems || this.filteredItems || this.localItems || [];
var currentPage = mathMax(toInteger(this.currentPage, 1), 1);
var perPage = mathMax(toInteger(this.perPage, 0), 0); // Apply local pagination
if (this.localPaging && !!perPage) {
// Grab the current page of data (which may be past filtered items limit)
items = items.slice((currentPage - 1) * perPage, currentPage * perPage);
} // Return the items to display in the table
return items;
}
}
};
var providerMixin = {
mixins: [listenOnRootMixin],
props: makePropsConfigurable({
// Prop override(s)
items: {
// Adds in 'Function' support
type: [Array, Function],
/* istanbul ignore next */
default: function _default() {
return [];
}
},
// Additional props
noProviderPaging: {
type: Boolean,
default: false
},
noProviderSorting: {
type: Boolean,
default: false
},
noProviderFiltering: {
type: Boolean,
default: false
},
apiUrl: {
// Passthrough prop. Passed to the context object. Not used by b-table directly
type: String,
default: ''
}
}, NAME_TABLE),
computed: {
hasProvider: function hasProvider() {
return isFunction(this.items);
},
providerTriggerContext: function providerTriggerContext() {
// Used to trigger the provider function via a watcher. Only the fields that
// are needed for triggering a provider update are included. Note that the
// regular this.context is sent to the provider during fetches though, as they
// may need all the prop info.
var ctx = {
apiUrl: this.apiUrl,
filter: null,
sortBy: null,
sortDesc: null,
perPage: null,
currentPage: null
};
if (!this.noProviderFiltering) {
// Either a string, or could be an object or array.
ctx.filter = this.localFilter;
}
if (!this.noProviderSorting) {
ctx.sortBy = this.localSortBy;
ctx.sortDesc = this.localSortDesc;
}
if (!this.noProviderPaging) {
ctx.perPage = this.perPage;
ctx.currentPage = this.currentPage;
}
return clone(ctx);
}
},
watch: {
// Provider update triggering
items: function items(newVal) {
// If a new provider has been specified, trigger an update
if (this.hasProvider || isFunction(newVal)) {
this.$nextTick(this._providerUpdate);
}
},
providerTriggerContext: function providerTriggerContext(newVal, oldVal) {
// Trigger the provider to update as the relevant context values have changed.
if (!looseEqual(newVal, oldVal)) {
this.$nextTick(this._providerUpdate);
}
}
},
mounted: function mounted() {
var _this = this;
// Call the items provider if necessary
if (this.hasProvider && (!this.localItems || this.localItems.length === 0)) {
// Fetch on mount if localItems is empty
this._providerUpdate();
} // Listen for global messages to tell us to force refresh the table
this.listenOnRoot('bv::refresh::table', function (id) {
if (id === _this.id || id === _this) {
_this.refresh();
}
});
},
methods: {
refresh: function refresh() {
// Public Method: Force a refresh of the provider function
this.$off('refreshed', this.refresh);
if (this.computedBusy) {
// Can't force an update when forced busy by user (busy prop === true)
if (this.localBusy && this.hasProvider) {
// But if provider running (localBusy), re-schedule refresh once `refreshed` emitted
this.$on('refreshed', this.refresh);
}
} else {
this.clearSelected();
if (this.hasProvider) {
this.$nextTick(this._providerUpdate);
} else {
/* istanbul ignore next */
this.localItems = isArray(this.items) ? this.items.slice() : [];
}
}
},
// Provider related methods
_providerSetLocal: function _providerSetLocal(items) {
this.localItems = isArray(items) ? items.slice() : [];
this.localBusy = false;
this.$emit('refreshed'); // New root emit
if (this.id) {
this.emitOnRoot('bv::table::refreshed', this.id);
}
},
_providerUpdate: function _providerUpdate() {
var _this2 = this;
// Refresh the provider function items.
if (!this.hasProvider) {
// Do nothing if no provider
return;
} // If table is busy, wait until refreshed before calling again
if (this.computedBusy) {
// Schedule a new refresh once `refreshed` is emitted
this.$nextTick(this.refresh);
return;
} // Set internal busy state
this.localBusy = true; // Call provider function with context and optional callback after DOM is fully updated
this.$nextTick(function () {
try {
// Call provider function passing it the context and optional callback
var data = _this2.items(_this2.context, _this2._providerSetLocal);
if (isPromise(data)) {
// Provider returned Promise
data.then(function (items) {
// Provider resolved with items
_this2._providerSetLocal(items);
});
} else if (isArray(data)) {
// Provider returned Array data
_this2._providerSetLocal(data);
} else {
/* istanbul ignore if */
if (_this2.items.length !== 2) {
// Check number of arguments provider function requested
// Provider not using callback (didn't request second argument), so we clear
// busy state as most likely there was an error in the provider function
/* istanbul ignore next */
warn("Provider function didn't request callback and did not return a promise or data.", NAME_TABLE);
_this2.localBusy = false;
}
}
} catch (e)
/* istanbul ignore next */
{
// Provider function borked on us, so we spew out a warning
// and clear the busy state
warn("Provider function error [".concat(e.name, "] ").concat(e.message, "."), NAME_TABLE);
_this2.localBusy = false;
_this2.$off('refreshed', _this2.refresh);
}
});
}
}
};
var SELECT_MODES = ['range', 'multi', 'single'];
var selectableMixin = {
props: makePropsConfigurable({
selectable: {
type: Boolean,
default: false
},
selectMode: {
type: String,
default: 'multi',
validator: function validator(value) {
return arrayIncludes(SELECT_MODES, value);
}
},
selectedVariant: {
type: String,
default: 'active'
},
noSelectOnClick: {
// Disable use of click handlers for row selection
type: Boolean,
default: false
}
}, NAME_TABLE),
data: function data() {
return {
selectedRows: [],
selectedLastRow: -1
};
},
computed: {
isSelectable: function isSelectable() {
return this.selectable && this.selectMode;
},
hasSelectableRowClick: function hasSelectableRowClick() {
return this.isSelectable && !this.noSelectOnClick;
},
supportsSelectableRows: function supportsSelectableRows() {
return true;
},
selectableHasSelection: function selectableHasSelection() {
return this.isSelectable && this.selectedRows && this.selectedRows.length > 0 && this.selectedRows.some(identity);
},
selectableIsMultiSelect: function selectableIsMultiSelect() {
return this.isSelectable && arrayIncludes(['range', 'multi'], this.selectMode);
},
selectableTableClasses: function selectableTableClasses() {
var _ref;
return _ref = {
'b-table-selectable': this.isSelectable
}, _defineProperty(_ref, "b-table-select-".concat(this.selectMode), this.isSelectable), _defineProperty(_ref, 'b-table-selecting', this.selectableHasSelection), _defineProperty(_ref, 'b-table-selectable-no-click', this.isSelectable && !this.hasSelectableRowClick), _ref;
},
selectableTableAttrs: function selectableTableAttrs() {
return {
// TODO:
// Should this attribute not be included when no-select-on-click is set
// since this attribute implies keyboard navigation?
'aria-multiselectable': !this.isSelectable ? null : this.selectableIsMultiSelect ? 'true' : 'false'
};
}
},
watch: {
computedItems: function computedItems(newVal, oldVal) {
// Reset for selectable
var equal = false;
if (this.isSelectable && this.selectedRows.length > 0) {
// Quick check against array length
equal = isArray(newVal) && isArray(oldVal) && newVal.length === oldVal.length;
for (var i = 0; equal && i < newVal.length; i++) {
// Look for the first non-loosely equal row, after ignoring reserved fields
equal = looseEqual(sanitizeRow(newVal[i]), sanitizeRow(oldVal[i]));
}
}
if (!equal) {
this.clearSelected();
}
},
selectable: function selectable(newVal) {
this.clearSelected();
this.setSelectionHandlers(newVal);
},
selectMode: function selectMode() {
this.clearSelected();
},
hasSelectableRowClick: function hasSelectableRowClick(newVal) {
this.clearSelected();
this.setSelectionHandlers(!newVal);
},
selectedRows: function selectedRows(_selectedRows, oldVal) {
var _this = this;
if (this.isSelectable && !looseEqual(_selectedRows, oldVal)) {
var items = []; // `.forEach()` skips over non-existent indices (on sparse arrays)
_selectedRows.forEach(function (v, idx) {
if (v) {
items.push(_this.computedItems[idx]);
}
});
this.$emit('row-selected', items);
}
}
},
beforeMount: function beforeMount() {
// Set up handlers if needed
if (this.isSelectable) {
this.setSelectionHandlers(true);
}
},
methods: {
// Public methods
selectRow: function selectRow(index) {
// Select a particular row (indexed based on computedItems)
if (this.isSelectable && isNumber(index) && index >= 0 && index < this.computedItems.length && !this.isRowSelected(index)) {
var selectedRows = this.selectableIsMultiSelect ? this.selectedRows.slice() : [];
selectedRows[index] = true;
this.selectedLastClicked = -1;
this.selectedRows = selectedRows;
}
},
unselectRow: function unselectRow(index) {
// Un-select a particular row (indexed based on `computedItems`)
if (this.isSelectable && isNumber(index) && this.isRowSelected(index)) {
var selectedRows = this.selectedRows.slice();
selectedRows[index] = false;
this.selectedLastClicked = -1;
this.selectedRows = selectedRows;
}
},
selectAllRows: function selectAllRows() {
var length = this.computedItems.length;
if (this.isSelectable && length > 0) {
this.selectedLastClicked = -1;
this.selectedRows = this.selectableIsMultiSelect ? range(length).map(function () {
return true;
}) : [true];
}
},
isRowSelected: function isRowSelected(index) {
// Determine if a row is selected (indexed based on `computedItems`)
return !!(isNumber(index) && this.selectedRows[index]);
},
clearSelected: function clearSelected() {
// Clear any active selected row(s)
this.selectedLastClicked = -1;
this.selectedRows = [];
},
// Internal private methods
selectableRowClasses: function selectableRowClasses(index) {
if (this.isSelectable && this.isRowSelected(index)) {
var variant = this.selectedVariant;
return _defineProperty({
'b-table-row-selected': true
}, "".concat(this.dark ? 'bg' : 'table', "-").concat(variant), variant);
} else {
return {};
}
},
selectableRowAttrs: function selectableRowAttrs(index) {
return {
'aria-selected': !this.isSelectable ? null : this.isRowSelected(index) ? 'true' : 'false'
};
},
setSelectionHandlers: function setSelectionHandlers(on) {
var method = on && !this.noSelectOnClick ? '$on' : '$off'; // Handle row-clicked event
this[method]('row-clicked', this.selectionHandler); // Clear selection on filter, pagination, and sort changes
this[method]('filtered', this.clearSelected);
this[method]('context-changed', this.clearSelected);
},
selectionHandler: function selectionHandler(item, index, evt) {
/* istanbul ignore if: should never happen */
if (!this.isSelectable || this.noSelectOnClick) {
// Don't do anything if table is not in selectable mode
this.clearSelected();
return;
}
var selectMode = this.selectMode;
var selectedRows = this.selectedRows.slice();
var selected = !selectedRows[index]; // Note 'multi' mode needs no special event handling
if (selectMode === 'single') {
selectedRows = [];
} else if (selectMode === 'range') {
if (this.selectedLastRow > -1 && evt.shiftKey) {
// range
for (var idx = mathMin(this.selectedLastRow, index); idx <= mathMax(this.selectedLastRow, index); idx++) {
selectedRows[idx] = true;
}
selected = true;
} else {
if (!(evt.ctrlKey || evt.metaKey)) {
// Clear range selection if any
selectedRows = [];
selected = true;
}
this.selectedLastRow = selected ? index : -1;
}
}
selectedRows[index] = selected;
this.selectedRows = selectedRows;
}
}
};
/*
* Consistent and stable sort function across JavaScript platforms
*
* Inconsistent 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 inconsistent/unstable
*
* This function uses native sort with fallback to index compare when the a and b
* compare returns 0
*
* Algorithm based on:
* https://stackoverflow.com/questions/1427608/fast-stable-sorting-algorithm-implementation-in-javascript/45422645#45422645
*
* @param {array} array to sort
* @param {function} sort compare function
* @return {array}
*/
var stableSort = 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];
});
};
//
// TODO: Add option to sort by multiple columns (tri-state per column,
// plus order of columns in sort) where sortBy could be an array
// of objects `[ {key: 'foo', sortDir: 'asc'}, {key:'bar', sortDir: 'desc'} ...]`
// or an array of arrays `[ ['foo','asc'], ['bar','desc'] ]`
// Multisort will most likely be handled in mixin-sort.js by
// calling this method for each sortBy
var defaultSortCompare = function defaultSortCompare(a, b, sortBy, sortDesc, formatter, localeOpts, locale, nullLast) {
var aa = get(a, sortBy, null);
var bb = get(b, sortBy, null);
if (isFunction(formatter)) {
aa = formatter(aa, sortBy, a);
bb = formatter(bb, sortBy, b);
}
aa = isUndefinedOrNull(aa) ? '' : aa;
bb = isUndefinedOrNull(bb) ? '' : bb;
if (isDate(aa) && isDate(bb) || isNumber(aa) && isNumber(bb)) {
// Special case for comparing dates and numbers
// Internally dates are compared via their epoch number values
return aa < bb ? -1 : aa > bb ? 1 : 0;
} else if (nullLast && aa === '' && bb !== '') {
// Special case when sorting null/undefined/empty string last
return 1;
} else if (nullLast && aa !== '' && bb === '') {
// Special case when sorting null/undefined/empty string last
return -1;
} // Do localized string comparison
return stringifyObjectValues(aa).localeCompare(stringifyObjectValues(bb), locale, localeOpts);
};
var SORT_DIRECTIONS = ['asc', 'desc', 'last'];
var sortingMixin = {
props: makePropsConfigurable({
sortBy: {
type: String,
default: ''
},
sortDesc: {
// TODO: Make this tri-state: true, false, null
type: Boolean,
default: false
},
sortDirection: {
// This prop is named incorrectly
// It should be `initialSortDirection` as it is a bit misleading
// (not to mention it screws up the ARIA label on the headers)
type: String,
default: 'asc',
validator: function validator(value) {
return arrayIncludes(SORT_DIRECTIONS, value);
}
},
sortCompare: {
type: Function // default: null
},
sortCompareOptions: {
// Supported localCompare options, see `options` section of:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare
type: Object,
default: function _default() {
return {
numeric: true
};
}
},
sortCompareLocale: {
// String: locale code
// Array: array of Locale strings
type: [String, Array] // default: undefined
},
sortNullLast: {
// Sort null and undefined to appear last
type: Boolean,
default: false
},
noSortReset: {
// Another prop that should have had a better name.
// It should be noSortClear (on non-sortable headers).
// We will need to make sure the documentation is clear on what
// this prop does (as well as in the code for future reference)
type: Boolean,
default: false
},
labelSortAsc: {
type: String,
default: 'Click to sort Ascending'
},
labelSortDesc: {
type: String,
default: 'Click to sort Descending'
},
labelSortClear: {
type: String,
default: 'Click to clear sorting'
},
noLocalSorting: {
type: Boolean,
default: false
},
noFooterSorting: {
type: Boolean,
default: false
},
sortIconLeft: {
// Place the sorting icon on the left of the header cells
type: Boolean,
default: false
}
}, NAME_TABLE),
data: function data() {
return {
localSortBy: this.sortBy || '',
localSortDesc: this.sortDesc || false
};
},
computed: {
localSorting: function localSorting() {
return this.hasProvider ? !!this.noProviderSorting : !this.noLocalSorting;
},
isSortable: function isSortable() {
return this.computedFields.some(function (f) {
return f.sortable;
});
},
sortedItems: function sortedItems() {
// Sorts the filtered items and returns a new array of the sorted items
// or the original items array if not sorted.
var items = (this.filteredItems || this.localItems || []).slice();
var sortBy = this.localSortBy;
var sortDesc = this.localSortDesc;
var sortCompare = this.sortCompare;
var localSorting = this.localSorting;
var sortOptions = _objectSpread2(_objectSpread2({}, this.sortCompareOptions), {}, {
usage: 'sort'
});
var sortLocale = this.sortCompareLocale || undefined;
var nullLast = this.sortNullLast;
if (sortBy && localSorting) {
var field = this.computedFieldsObj[sortBy] || {};
var sortByFormatted = field.sortByFormatted;
var formatter = isFunction(sortByFormatted) ?
/* istanbul ignore next */
sortByFormatted : sortByFormatted ? this.getFieldFormatter(sortBy) : undefined; // `stableSort` returns a new array, and leaves the original array intact
return stableSort(items, function (a, b) {
var result = null;
if (isFunction(sortCompare)) {
// Call user provided sortCompare routine
result = sortCompare(a, b, sortBy, sortDesc, formatter, sortOptions, sortLocale);
}
if (isUndefinedOrNull(result) || result === false) {
// Fallback to built-in defaultSortCompare if sortCompare
// is not defined or returns null/false
result = defaultSortCompare(a, b, sortBy, sortDesc, formatter, sortOptions, sortLocale, nullLast);
} // Negate result if sorting in descending order
return (result || 0) * (sortDesc ? -1 : 1);
});
}
return items;
}
},
watch: {
/* istanbul ignore next: pain in the butt to test */
isSortable: function isSortable(newVal) {
if (newVal) {
if (this.isSortable) {
this.$on('head-clicked', this.handleSort);
}
} else {
this.$off('head-clicked', this.handleSort);
}
},
sortDesc: function sortDesc(newVal) {
if (newVal === this.localSortDesc) {
/* istanbul ignore next */
return;
}
this.localSortDesc = newVal || false;
},
sortBy: function sortBy(newVal) {
if (newVal === this.localSortBy) {
/* istanbul ignore next */
return;
}
this.localSortBy = newVal || '';
},
// Update .sync props
localSortDesc: function localSortDesc(newVal, oldVal) {
// Emit update to sort-desc.sync
if (newVal !== oldVal) {
this.$emit('update:sortDesc', newVal);
}
},
localSortBy: function localSortBy(newVal, oldVal) {
if (newVal !== oldVal) {
this.$emit('update:sortBy', newVal);
}
}
},
created: function created() {
if (this.isSortable) {
this.$on('head-clicked', this.handleSort);
}
},
methods: {
// Handlers
// Need to move from thead-mixin
handleSort: function handleSort(key, field, evt, isFoot) {
var _this = this;
if (!this.isSortable) {
/* istanbul ignore next */
return;
}
if (isFoot && this.noFooterSorting) {
return;
} // TODO: make this tri-state sorting
// cycle desc => asc => none => desc => ...
var sortChanged = false;
var toggleLocalSortDesc = function toggleLocalSortDesc() {
var sortDirection = field.sortDirection || _this.sortDirection;
if (sortDirection === 'asc') {
_this.localSortDesc = false;
} else if (sortDirection === 'desc') {
_this.localSortDesc = true;
} else ;
};
if (field.sortable) {
var sortKey = !this.localSorting && field.sortKey ? field.sortKey : key;
if (this.localSortBy === sortKey) {
// Change sorting direction on current column
this.localSortDesc = !this.localSortDesc;
} else {
// Start sorting this column ascending
this.localSortBy = sortKey; // this.localSortDesc = false
toggleLocalSortDesc();
}
sortChanged = true;
} else if (this.localSortBy && !this.noSortReset) {
this.localSortBy = '';
toggleLocalSortDesc();
sortChanged = true;
}
if (sortChanged) {
// Sorting parameters changed
this.$emit('sort-changed', this.context);
}
},
// methods to compute classes and attrs for thead>th cells
sortTheadThClasses: function sortTheadThClasses(key, field, isFoot) {
return {
// If sortable and sortIconLeft are true, then place sort icon on the left
'b-table-sort-icon-left': field.sortable && this.sortIconLeft && !(isFoot && this.noFooterSorting)
};
},
sortTheadThAttrs: function sortTheadThAttrs(key, field, isFoot) {
if (!this.isSortable || isFoot && this.noFooterSorting) {
// No attributes if not a sortable table
return {};
}
var sortable = field.sortable; // Assemble the aria-sort attribute value
var ariaSort = sortable && this.localSortBy === key ? this.localSortDesc ? 'descending' : 'ascending' : sortable ? 'none' : null; // Return the attribute
return {
'aria-sort': ariaSort
};
},
sortTheadThLabel: function sortTheadThLabel(key, field, isFoot) {
// A label to be placed in an `.sr-only` element in the header cell
if (!this.isSortable || isFoot && this.noFooterSorting) {
// No label if not a sortable table
return null;
}
var sortable = field.sortable; // The correctness of these labels is very important for screen-reader users.
var labelSorting = '';
if (sortable) {
if (this.localSortBy === key) {
// currently sorted sortable column.
labelSorting = this.localSortDesc ? this.labelSortAsc : this.labelSortDesc;
} else {
// Not currently sorted sortable column.
// Not using nested ternary's here for clarity/readability
// Default for ariaLabel
labelSorting = this.localSortDesc ? this.labelSortDesc : this.labelSortAsc; // Handle sortDirection setting
var sortDirection = this.sortDirection || field.sortDirection;
if (sortDirection === 'asc') {
labelSorting = this.labelSortAsc;
} else if (sortDirection === 'desc') {
labelSorting = this.labelSortDesc;
}
}
} else if (!this.noSortReset) {
// Non sortable column
labelSorting = this.localSortBy ? this.labelSortClear : '';
} // Return the sr-only sort label or null if no label
return trim(labelSorting) || null;
}
}
};
var stackedMixin = {
props: makePropsConfigurable({
stacked: {
type: [Boolean, String],
default: false
}
}, NAME_TABLE),
computed: {
isStacked: function isStacked() {
// `true` when always stacked, or returns breakpoint specified
return this.stacked === '' ? true : this.stacked;
},
isStackedAlways: function isStackedAlways() {
return this.isStacked === true;
},
stackedTableClasses: function stackedTableClasses() {
return _defineProperty({
'b-table-stacked': this.isStackedAlways
}, "b-table-stacked-".concat(this.stacked), !this.isStackedAlways && this.isStacked);
}
}
};
// Includes all main table styling options
var tableRendererMixin = {
// Don't place attributes on root element automatically,
// as table could be wrapped in responsive `<div>`
inheritAttrs: false,
// Mixin order is important!
mixins: [attrsMixin],
provide: function provide() {
return {
bvTable: this
};
},
props: makePropsConfigurable({
striped: {
type: Boolean,
default: false
},
bordered: {
type: Boolean,
default: false
},
borderless: {
type: Boolean,
default: false
},
outlined: {
type: Boolean,
default: false
},
dark: {
type: Boolean,
default: false
},
hover: {
type: Boolean,
default: false
},
small: {
type: Boolean,
default: false
},
fixed: {
type: Boolean,
default: false
},
responsive: {
type: [Boolean, String],
default: false
},
stickyHeader: {
// If a string, it is assumed to be the table `max-height` value
type: [Boolean, String],
default: false
},
noBorderCollapse: {
type: Boolean,
default: false
},
captionTop: {
type: Boolean,
default: false
},
tableVariant: {
type: String // default: null
},
tableClass: {
type: [String, Array, Object] // default: null
}
}, NAME_TABLE),
computed: {
// Layout related computed props
isResponsive: function isResponsive() {
var responsive = this.responsive === '' ? true : this.responsive;
return this.isStacked ? false : responsive;
},
isStickyHeader: function isStickyHeader() {
var stickyHeader = this.stickyHeader === '' ? true : this.stickyHeader;
return this.isStacked ? false : stickyHeader;
},
wrapperClasses: function wrapperClasses() {
return [this.isStickyHeader ? 'b-table-sticky-header' : '', this.isResponsive === true ? 'table-responsive' : this.isResponsive ? "table-responsive-".concat(this.responsive) : ''].filter(identity);
},
wrapperStyles: function wrapperStyles() {
return this.isStickyHeader && !isBoolean(this.isStickyHeader) ? {
maxHeight: this.isStickyHeader
} : {};
},
tableClasses: function tableClasses() {
var hover = this.isTableSimple ? this.hover : this.hover && this.computedItems.length > 0 && !this.computedBusy;
return [// User supplied classes
this.tableClass, // Styling classes
{
'table-striped': this.striped,
'table-hover': hover,
'table-dark': this.dark,
'table-bordered': this.bordered,
'table-borderless': this.borderless,
'table-sm': this.small,
// The following are b-table custom styles
border: this.outlined,
'b-table-fixed': this.fixed,
'b-table-caption-top': this.captionTop,
'b-table-no-border-collapse': this.noBorderCollapse
}, this.tableVariant ? "".concat(this.dark ? 'bg' : 'table', "-").concat(this.tableVariant) : '', // Stacked table classes
this.stackedTableClasses, // Selectable classes
this.selectableTableClasses];
},
tableAttrs: function tableAttrs() {
// Preserve user supplied aria-describedby, if provided in `$attrs`
var adb = [(this.bvAttrs || {})['aria-describedby'], this.captionId].filter(identity).join(' ') || null;
var items = this.computedItems;
var filteredItems = this.filteredItems;
var fields = this.computedFields;
var selectableAttrs = this.selectableTableAttrs || {};
var ariaAttrs = this.isTableSimple ? {} : {
'aria-busy': this.computedBusy ? 'true' : 'false',
'aria-colcount': toString$1(fields.length),
'aria-describedby': adb
};
var rowCount = items && filteredItems && filteredItems.length > items.length ? toString$1(filteredItems.length) : null;
return _objectSpread2(_objectSpread2(_objectSpread2({
// We set `aria-rowcount` before merging in `$attrs`,
// in case user has supplied their own
'aria-rowcount': rowCount
}, this.bvAttrs), {}, {
// Now we can override any `$attrs` here
id: this.safeId(),
role: 'table'
}, ariaAttrs), selectableAttrs);
}
},
render: function render(h) {
var $content = [];
if (this.isTableSimple) {
$content.push(this.normalizeSlot());
} else {
// Build the `<caption>` (from caption mixin)
$content.push(this.renderCaption ? this.renderCaption() : null); // Build the `<colgroup>`
$content.push(this.renderColgroup ? this.renderColgroup() : null); // Build the `<thead>`
$content.push(this.renderThead ? this.renderThead() : null); // Build the `<tbody>`
$content.push(this.renderTbody ? this.renderTbody() : null); // Build the `<tfoot>`
$content.push(this.renderTfoot ? this.renderTfoot() : null);
} // Assemble `<table>`
var $table = h('table', {
key: 'b-table',
staticClass: 'table b-table',
class: this.tableClasses,
attrs: this.tableAttrs
}, $content.filter(identity)); // Add responsive/sticky wrapper if needed and return table
return this.wrapperClasses.length > 0 ? h('div', {
key: 'wrap',
class: this.wrapperClasses,
style: this.wrapperStyles
}, [$table]) : $table;
}
};
var props$16 = makePropsConfigurable({
tbodyTransitionProps: {
type: Object // default: undefined
},
tbodyTransitionHandlers: {
type: Object // default: undefined
}
}, NAME_TBODY); // TODO:
// In Bootstrap v5, we won't need "sniffing" as table element variants properly inherit
// to the child elements, so this can be converted to a functional component
// @vue/component
var BTbody = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_TBODY,
// Mixin order is important!
mixins: [attrsMixin, listenersMixin, normalizeSlotMixin],
provide: function provide() {
return {
bvTableRowGroup: this
};
},
inject: {
bvTable: {
// Sniffed by <b-tr> / <b-td> / <b-th>
/* istanbul ignore next */
default: function _default() {
return {};
}
}
},
inheritAttrs: false,
props: props$16,
computed: {
isTbody: function isTbody() {
// Sniffed by <b-tr> / <b-td> / <b-th>
return true;
},
isDark: function isDark() {
// Sniffed by <b-tr> / <b-td> / <b-th>
return this.bvTable.dark;
},
isStacked: function isStacked() {
// Sniffed by <b-tr> / <b-td> / <b-th>
return this.bvTable.isStacked;
},
isResponsive: function isResponsive() {
// Sniffed by <b-tr> / <b-td> / <b-th>
return this.bvTable.isResponsive;
},
isStickyHeader: function isStickyHeader() {
// Sniffed by <b-tr> / <b-td> / <b-th>
// Sticky headers are only supported in thead
return false;
},
hasStickyHeader: function hasStickyHeader() {
// Sniffed by <b-tr> / <b-td> / <b-th>
// Needed to handle header background classes, due to lack of
// background color inheritance with Bootstrap v4 table CSS
return !this.isStacked && this.bvTable.stickyHeader;
},
tableVariant: function tableVariant() {
// Sniffed by <b-tr> / <b-td> / <b-th>
return this.bvTable.tableVariant;
},
isTransitionGroup: function isTransitionGroup() {
return this.tbodyTransitionProps || this.tbodyTransitionHandlers;
},
tbodyAttrs: function tbodyAttrs() {
return _objectSpread2({
role: 'rowgroup'
}, this.bvAttrs);
},
tbodyProps: function tbodyProps() {
return this.tbodyTransitionProps ? _objectSpread2(_objectSpread2({}, this.tbodyTransitionProps), {}, {
tag: 'tbody'
}) : {};
}
},
render: function render(h) {
var data = {
props: this.tbodyProps,
attrs: this.tbodyAttrs
};
if (this.isTransitionGroup) {
// We use native listeners if a transition group for any delegated events
data.on = this.tbodyTransitionHandlers || {};
data.nativeOn = this.bvListeners;
} else {
// Otherwise we place any listeners on the tbody element
data.on = this.bvListeners;
}
return h(this.isTransitionGroup ? 'transition-group' : 'tbody', data, this.normalizeSlot());
}
});
var TABLE_TAG_NAMES = ['TD', 'TH', 'TR']; // Returns `true` if we should ignore the click/double-click/keypress event
// Avoids having the user need to use `@click.stop` on the form control
var filterEvent = function filterEvent(evt) {
// Exit early when we don't have a target element
if (!evt || !evt.target) {
/* istanbul ignore next */
return false;
}
var el = evt.target; // Exit early when element is disabled or a table element
if (el.disabled || TABLE_TAG_NAMES.indexOf(el.tagName) !== -1) {
return false;
} // Ignore the click when it was inside a dropdown menu
if (closest('.dropdown-menu', el)) {
return true;
}
var label = el.tagName === 'LABEL' ? el : closest('label', el); // If the label's form control is not disabled then we don't propagate event
// Modern browsers have `label.control` that references the associated input, but IE 11
// does not have this property on the label element, so we resort to DOM lookups
if (label) {
var labelFor = getAttr(label, 'for');
var input = labelFor ? getById(labelFor) : select('input, select, textarea', label);
if (input && !input.disabled) {
return true;
}
} // Otherwise check if the event target matches one of the selectors in the
// event filter (i.e. anchors, non disabled inputs, etc.)
// Return `true` if we should ignore the event
return matches(el, EVENT_FILTER);
};
// Used to filter out click events caused by the mouse up at end of selection
//
// Accepts an element as only argument to test to see if selection overlaps or is
// contained within the element
var textSelectionActive = function textSelectionActive() {
var el = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : document;
var sel = getSel();
return sel && sel.toString().trim() !== '' && sel.containsNode && isElement(el) ?
/* istanbul ignore next */
sel.containsNode(el, true) : false;
};
// In Bootstrap v5, we won't need "sniffing" as table element variants properly inherit
// to the child elements, so this can be converted to a functional component
// @vue/component
var BTh = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_TH,
extends: BTd,
computed: {
tag: function tag() {
return 'th';
}
}
});
var detailsSlotName = 'row-details';
var tbodyRowMixin = {
props: makePropsConfigurable({
tbodyTrClass: {
type: [String, Array, Object, Function] // default: null
},
tbodyTrAttr: {
type: [Object, Function] // default: null
},
detailsTdClass: {
type: [String, Array, Object] // default: null
}
}, NAME_TABLE),
methods: {
// Methods for computing classes, attributes and styles for table cells
getTdValues: function getTdValues(item, key, tdValue, defValue) {
var parent = this.$parent;
if (tdValue) {
var value = get(item, key, '');
if (isFunction(tdValue)) {
return tdValue(value, key, item);
} else if (isString(tdValue) && isFunction(parent[tdValue])) {
return parent[tdValue](value, key, item);
}
return tdValue;
}
return defValue;
},
getThValues: function getThValues(item, key, thValue, type, defValue) {
var parent = this.$parent;
if (thValue) {
var value = get(item, key, '');
if (isFunction(thValue)) {
return thValue(value, key, item, type);
} else if (isString(thValue) && isFunction(parent[thValue])) {
return parent[thValue](value, key, item, type);
}
return thValue;
}
return defValue;
},
// Method to get the value for a field
getFormattedValue: function getFormattedValue(item, field) {
var key = field.key;
var formatter = this.getFieldFormatter(key);
var value = get(item, key, null);
if (isFunction(formatter)) {
value = formatter(value, key, item);
}
return isUndefinedOrNull(value) ? '' : value;
},
// Factory function methods
toggleDetailsFactory: function toggleDetailsFactory(hasDetailsSlot, item) {
var _this = this;
// Returns a function to toggle a row's details slot
return function () {
if (hasDetailsSlot) {
_this.$set(item, '_showDetails', !item._showDetails);
}
};
},
// Row event handlers
rowHovered: function rowHovered(evt) {
// `mouseenter` handler (non-bubbling)
// `this.tbodyRowEvtStopped` from tbody mixin
if (!this.tbodyRowEvtStopped(evt)) {
// `this.emitTbodyRowEvent` from tbody mixin
this.emitTbodyRowEvent('row-hovered', evt);
}
},
rowUnhovered: function rowUnhovered(evt) {
// `mouseleave` handler (non-bubbling)
// `this.tbodyRowEvtStopped` from tbody mixin
if (!this.tbodyRowEvtStopped(evt)) {
// `this.emitTbodyRowEvent` from tbody mixin
this.emitTbodyRowEvent('row-unhovered', evt);
}
},
// Render helpers
renderTbodyRowCell: function renderTbodyRowCell(field, colIndex, item, rowIndex) {
var _this2 = this;
// Renders a TD or TH for a row's field
var h = this.$createElement;
var hasDetailsSlot = this.hasNormalizedSlot(detailsSlotName);
var formatted = this.getFormattedValue(item, field);
var key = field.key;
var stickyColumn = !this.isStacked && (this.isResponsive || this.stickyHeader) && field.stickyColumn; // We only uses the helper components for sticky columns to
// improve performance of BTable/BTableLite by reducing the
// total number of vue instances created during render
var cellTag = stickyColumn ? field.isRowHeader ? BTh : BTd : field.isRowHeader ? 'th' : 'td';
var cellVariant = item._cellVariants && item._cellVariants[key] ? item._cellVariants[key] : field.variant || null;
var data = {
// For the Vue key, we concatenate the column index and
// field key (as field keys could be duplicated)
// TODO: Although we do prevent duplicate field keys...
// So we could change this to: `row-${rowIndex}-cell-${key}`
key: "row-".concat(rowIndex, "-cell-").concat(colIndex, "-").concat(key),
class: [field.class ? field.class : '', this.getTdValues(item, key, field.tdClass, '')],
props: {},
attrs: _objectSpread2({
'aria-colindex': String(colIndex + 1)
}, field.isRowHeader ? this.getThValues(item, key, field.thAttr, 'row', {}) : this.getTdValues(item, key, field.tdAttr, {}))
};
if (stickyColumn) {
// We are using the helper BTd or BTh
data.props = {
stackedHeading: this.isStacked ? field.label : null,
stickyColumn: true,
variant: cellVariant
};
} else {
// Using native TD or TH element, so we need to
// add in the attributes and variant class
data.attrs['data-label'] = this.isStacked && !isUndefinedOrNull(field.label) ? toString$1(field.label) : null;
data.attrs.role = field.isRowHeader ? 'rowheader' : 'cell';
data.attrs.scope = field.isRowHeader ? 'row' : null; // Add in the variant class
if (cellVariant) {
data.class.push("".concat(this.dark ? 'bg' : 'table', "-").concat(cellVariant));
}
}
var slotScope = {
item: item,
index: rowIndex,
field: field,
unformatted: get(item, key, ''),
value: formatted,
toggleDetails: this.toggleDetailsFactory(hasDetailsSlot, item),
detailsShowing: Boolean(item._showDetails)
}; // If table supports selectable mode, then add in the following scope
// this.supportsSelectableRows will be undefined if mixin isn't loaded
if (this.supportsSelectableRows) {
slotScope.rowSelected = this.isRowSelected(rowIndex);
slotScope.selectRow = function () {
return _this2.selectRow(rowIndex);
};
slotScope.unselectRow = function () {
return _this2.unselectRow(rowIndex);
};
} // The new `v-slot` syntax doesn't like a slot name starting with
// a square bracket and if using in-document HTML templates, the
// v-slot attributes are lower-cased by the browser.
// Switched to round bracket syntax to prevent confusion with
// dynamic slot name syntax.
// We look for slots in this order: `cell(${key})`, `cell(${key.toLowerCase()})`, 'cell()'
// Slot names are now cached by mixin tbody in `this.$_bodyFieldSlotNameCache`
// Will be `null` if no slot (or fallback slot) exists
var slotName = this.$_bodyFieldSlotNameCache[key];
var $childNodes = slotName ? this.normalizeSlot(slotName, slotScope) : toString$1(formatted);
if (this.isStacked) {
// We wrap in a DIV to ensure rendered as a single cell when visually stacked!
$childNodes = [h('div', [$childNodes])];
} // Render either a td or th cell
return h(cellTag, data, [$childNodes]);
},
renderTbodyRow: function renderTbodyRow(item, rowIndex) {
var _this3 = this;
// Renders an item's row (or rows if details supported)
var h = this.$createElement;
var fields = this.computedFields;
var tableStriped = this.striped;
var hasDetailsSlot = this.hasNormalizedSlot(detailsSlotName);
var rowShowDetails = item._showDetails && hasDetailsSlot;
var hasRowClickHandler = this.$listeners['row-clicked'] || this.hasSelectableRowClick; // We can return more than one TR if rowDetails enabled
var $rows = []; // Details ID needed for `aria-details` when details showing
// We set it to `null` when not showing so that attribute
// does not appear on the element
var detailsId = rowShowDetails ? this.safeId("_details_".concat(rowIndex, "_")) : null; // For each item data field in row
var $tds = fields.map(function (field, colIndex) {
return _this3.renderTbodyRowCell(field, colIndex, item, rowIndex);
}); // Calculate the row number in the dataset (indexed from 1)
var ariaRowIndex = null;
if (this.currentPage && this.perPage && this.perPage > 0) {
ariaRowIndex = String((this.currentPage - 1) * this.perPage + rowIndex + 1);
} // Create a unique :key to help ensure that sub components are re-rendered rather than
// re-used, which can cause issues. If a primary key is not provided we use the rendered
// rows index within the tbody.
// See: https://github.com/bootstrap-vue/bootstrap-vue/issues/2410
var primaryKey = this.primaryKey;
var primaryKeyValue = toString$1(get(item, primaryKey)) || null;
var rowKey = primaryKeyValue || toString$1(rowIndex); // If primary key is provided, use it to generate a unique ID on each tbody > tr
// In the format of '{tableId}__row_{primaryKeyValue}'
var rowId = primaryKeyValue ? this.safeId("_row_".concat(primaryKeyValue)) : null; // Selectable classes and attributes
var selectableClasses = this.selectableRowClasses ? this.selectableRowClasses(rowIndex) : {};
var selectableAttrs = this.selectableRowAttrs ? this.selectableRowAttrs(rowIndex) : {}; // Additional classes and attributes
var userTrClasses = isFunction(this.tbodyTrClass) ? this.tbodyTrClass(item, 'row') : this.tbodyTrClass;
var userTrAttrs = isFunction(this.tbodyTrAttr) ?
/* istanbul ignore next */
this.tbodyTrAttr(item, 'row') : this.tbodyTrAttr; // Add the item row
$rows.push(h(BTr, {
key: "__b-table-row-".concat(rowKey, "__"),
ref: 'itemRows',
refInFor: true,
class: [userTrClasses, selectableClasses, rowShowDetails ? 'b-table-has-details' : ''],
props: {
variant: item._rowVariant || null
},
attrs: _objectSpread2(_objectSpread2({
id: rowId
}, userTrAttrs), {}, {
// Users cannot override the following attributes
tabindex: hasRowClickHandler ? '0' : null,
'data-pk': primaryKeyValue || null,
'aria-details': detailsId,
'aria-owns': detailsId,
'aria-rowindex': ariaRowIndex
}, selectableAttrs),
on: {
// Note: These events are not A11Y friendly!
mouseenter: this.rowHovered,
mouseleave: this.rowUnhovered
}
}, $tds)); // Row Details slot
if (rowShowDetails) {
var detailsScope = {
item: item,
index: rowIndex,
fields: fields,
toggleDetails: this.toggleDetailsFactory(hasDetailsSlot, item)
}; // If table supports selectable mode, then add in the following scope
// this.supportsSelectableRows will be undefined if mixin isn't loaded
if (this.supportsSelectableRows) {
detailsScope.rowSelected = this.isRowSelected(rowIndex);
detailsScope.selectRow = function () {
return _this3.selectRow(rowIndex);
};
detailsScope.unselectRow = function () {
return _this3.unselectRow(rowIndex);
};
} // Render the details slot in a TD
var $details = h(BTd, {
props: {
colspan: fields.length
},
class: this.detailsTdClass
}, [this.normalizeSlot(detailsSlotName, detailsScope)]); // Add a hidden row to keep table row striping consistent when details showing
// Only added if the table is striped
if (tableStriped) {
$rows.push( // We don't use `BTr` here as we don't need the extra functionality
h('tr', {
key: "__b-table-details-stripe__".concat(rowKey),
staticClass: 'd-none',
attrs: {
'aria-hidden': 'true',
role: 'presentation'
}
}));
} // Add the actual details row
var userDetailsTrClasses = isFunction(this.tbodyTrClass) ?
/* istanbul ignore next */
this.tbodyTrClass(item, detailsSlotName) : this.tbodyTrClass;
var userDetailsTrAttrs = isFunction(this.tbodyTrAttr) ?
/* istanbul ignore next */
this.tbodyTrAttr(item, detailsSlotName) : this.tbodyTrAttr;
$rows.push(h(BTr, {
key: "__b-table-details__".concat(rowKey),
staticClass: 'b-table-details',
class: [userDetailsTrClasses],
props: {
variant: item._rowVariant || null
},
attrs: _objectSpread2(_objectSpread2({}, userDetailsTrAttrs), {}, {
// Users cannot override the following attributes
id: detailsId,
tabindex: '-1'
})
}, [$details]));
} else if (hasDetailsSlot) {
// Only add the placeholder if a the table has a row-details slot defined (but not shown)
$rows.push(h());
if (tableStriped) {
// Add extra placeholder if table is striped
$rows.push(h());
}
} // Return the row(s)
return $rows;
}
}
};
var props$17 = _objectSpread2(_objectSpread2({}, props$16), {}, {
tbodyClass: {
type: [String, Array, Object] // default: undefined
}
});
var tbodyMixin = {
mixins: [tbodyRowMixin],
props: props$17,
beforeDestroy: function beforeDestroy() {
this.$_bodyFieldSlotNameCache = null;
},
methods: {
// Helper methods
getTbodyTrs: function getTbodyTrs() {
// Returns all the item TR elements (excludes detail and spacer rows)
// `this.$refs.itemRows` is an array of item TR components/elements
// Rows should all be B-TR components, but we map to TR elements
// Also note that `this.$refs.itemRows` may not always be in document order
var refs = this.$refs || {};
var tbody = refs.tbody ? refs.tbody.$el || refs.tbody : null;
var trs = (refs.itemRows || []).map(function (tr) {
return tr.$el || tr;
});
return tbody && tbody.children && tbody.children.length > 0 && trs && trs.length > 0 ? from(tbody.children).filter(function (tr) {
return arrayIncludes(trs, tr);
}) :
/* istanbul ignore next */
[];
},
getTbodyTrIndex: function getTbodyTrIndex(el) {
// Returns index of a particular TBODY item TR
// We set `true` on closest to include self in result
/* istanbul ignore next: should not normally happen */
if (!isElement(el)) {
return -1;
}
var tr = el.tagName === 'TR' ? el : closest('tr', el, true);
return tr ? this.getTbodyTrs().indexOf(tr) : -1;
},
emitTbodyRowEvent: function emitTbodyRowEvent(type, evt) {
// Emits a row event, with the item object, row index and original event
if (type && this.hasListener(type) && evt && evt.target) {
var rowIndex = this.getTbodyTrIndex(evt.target);
if (rowIndex > -1) {
// The array of TRs correlate to the `computedItems` array
var item = this.computedItems[rowIndex];
this.$emit(type, item, rowIndex, evt);
}
}
},
tbodyRowEvtStopped: function tbodyRowEvtStopped(evt) {
return this.stopIfBusy && this.stopIfBusy(evt);
},
// Delegated row event handlers
onTbodyRowKeydown: function onTbodyRowKeydown(evt) {
// Keyboard navigation and row click emulation
var target = evt.target;
if (this.tbodyRowEvtStopped(evt) || target.tagName !== 'TR' || !isActiveElement(target) || target.tabIndex !== 0) {
// Early exit if not an item row TR
return;
}
var keyCode = evt.keyCode;
if (arrayIncludes([CODE_ENTER, CODE_SPACE], keyCode)) {
// Emulated click for keyboard users, transfer to click handler
stopEvent(evt);
this.onTBodyRowClicked(evt);
} else if (arrayIncludes([CODE_UP, CODE_DOWN, CODE_HOME, CODE_END], keyCode)) {
// Keyboard navigation
var rowIndex = this.getTbodyTrIndex(target);
if (rowIndex > -1) {
stopEvent(evt);
var trs = this.getTbodyTrs();
var shift = evt.shiftKey;
if (keyCode === CODE_HOME || shift && keyCode === CODE_UP) {
// Focus first row
attemptFocus(trs[0]);
} else if (keyCode === CODE_END || shift && keyCode === CODE_DOWN) {
// Focus last row
attemptFocus(trs[trs.length - 1]);
} else if (keyCode === CODE_UP && rowIndex > 0) {
// Focus previous row
attemptFocus(trs[rowIndex - 1]);
} else if (keyCode === CODE_DOWN && rowIndex < trs.length - 1) {
// Focus next row
attemptFocus(trs[rowIndex + 1]);
}
}
}
},
onTBodyRowClicked: function onTBodyRowClicked(evt) {
if (this.tbodyRowEvtStopped(evt)) {
// If table is busy, then don't propagate
return;
} else if (filterEvent(evt) || textSelectionActive(this.$el)) {
// Clicked on a non-disabled control so ignore
// Or user is selecting text, so ignore
return;
}
this.emitTbodyRowEvent('row-clicked', evt);
},
onTbodyRowMiddleMouseRowClicked: function onTbodyRowMiddleMouseRowClicked(evt) {
if (!this.tbodyRowEvtStopped(evt) && evt.which === 2) {
this.emitTbodyRowEvent('row-middle-clicked', evt);
}
},
onTbodyRowContextmenu: function onTbodyRowContextmenu(evt) {
if (!this.tbodyRowEvtStopped(evt)) {
this.emitTbodyRowEvent('row-contextmenu', evt);
}
},
onTbodyRowDblClicked: function onTbodyRowDblClicked(evt) {
if (!this.tbodyRowEvtStopped(evt) && !filterEvent(evt)) {
this.emitTbodyRowEvent('row-dblclicked', evt);
}
},
// Note: Row hover handlers are handled by the tbody-row mixin
// As mouseenter/mouseleave events do not bubble
//
// Render Helper
renderTbody: function renderTbody() {
var _this = this;
// Render the tbody element and children
var items = this.computedItems; // Shortcut to `createElement` (could use `this._c()` instead)
var h = this.$createElement;
var hasRowClickHandler = this.hasListener('row-clicked') || this.hasSelectableRowClick; // Prepare the tbody rows
var $rows = []; // Add the item data rows or the busy slot
var $busy = this.renderBusy ? this.renderBusy() : null;
if ($busy) {
// If table is busy and a busy slot, then return only the busy "row" indicator
$rows.push($busy);
} else {
// Table isn't busy, or we don't have a busy slot
// Create a slot cache for improved performance when looking up cell slot names
// Values will be keyed by the field's `key` and will store the slot's name
// Slots could be dynamic (i.e. `v-if`), so we must compute on each render
// Used by tbody-row mixin render helper
var cache = {};
var defaultSlotName = this.hasNormalizedSlot('cell()') ? 'cell()' : null;
this.computedFields.forEach(function (field) {
var key = field.key;
var fullName = "cell(".concat(key, ")");
var lowerName = "cell(".concat(key.toLowerCase(), ")");
cache[key] = _this.hasNormalizedSlot(fullName) ? fullName : _this.hasNormalizedSlot(lowerName) ?
/* istanbul ignore next */
lowerName : defaultSlotName;
}); // Created as a non-reactive property so to not trigger component updates
// Must be a fresh object each render
this.$_bodyFieldSlotNameCache = cache; // Add static top row slot (hidden in visibly stacked mode
// as we can't control `data-label` attr)
$rows.push(this.renderTopRow ? this.renderTopRow() : h()); // Render the rows
items.forEach(function (item, rowIndex) {
// Render the individual item row (rows if details slot)
$rows.push(_this.renderTbodyRow(item, rowIndex));
}); // Empty items / empty filtered row slot (only shows if `items.length < 1`)
$rows.push(this.renderEmpty ? this.renderEmpty() : h()); // Static bottom row slot (hidden in visibly stacked mode
// as we can't control `data-label` attr)
$rows.push(this.renderBottomRow ? this.renderBottomRow() : h());
} // Note: these events will only emit if a listener is registered
var handlers = {
auxclick: this.onTbodyRowMiddleMouseRowClicked,
// TODO:
// Perhaps we do want to automatically prevent the
// default context menu from showing if there is a
// `row-contextmenu` listener registered
contextmenu: this.onTbodyRowContextmenu,
// The following event(s) is not considered A11Y friendly
dblclick: this.onTbodyRowDblClicked // Hover events (`mouseenter`/`mouseleave`) are handled by `tbody-row` mixin
}; // Add in click/keydown listeners if needed
if (hasRowClickHandler) {
handlers.click = this.onTBodyRowClicked;
handlers.keydown = this.onTbodyRowKeydown;
} // Assemble rows into the tbody
var $tbody = h(BTbody, {
ref: 'tbody',
class: this.tbodyClass || null,
props: {
tbodyTransitionProps: this.tbodyTransitionProps,
tbodyTransitionHandlers: this.tbodyTransitionHandlers
},
// BTbody transfers all native event listeners to the root element
// TODO: Only set the handlers if the table is not busy
on: handlers
}, $rows); // Return the assembled tbody
return $tbody;
}
}
};
var props$18 = makePropsConfigurable({
footVariant: {
type: String,
// Supported values: 'lite', 'dark', or null
default: null
}
}, NAME_TFOOT); // TODO:
// In Bootstrap v5, we won't need "sniffing" as table element variants properly inherit
// to the child elements, so this can be converted to a functional component
// @vue/component
var BTfoot = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_TFOOT,
// Mixin order is important!
mixins: [attrsMixin, listenersMixin, normalizeSlotMixin],
provide: function provide() {
return {
bvTableRowGroup: this
};
},
inject: {
bvTable: {
// Sniffed by <b-tr> / <b-td> / <b-th>
/* istanbul ignore next */
default: function _default() {
return {};
}
}
},
inheritAttrs: false,
props: props$18,
computed: {
isTfoot: function isTfoot() {
// Sniffed by <b-tr> / <b-td> / <b-th>
return true;
},
isDark: function isDark() {
// Sniffed by <b-tr> / <b-td> / <b-th>
return this.bvTable.dark;
},
isStacked: function isStacked() {
// Sniffed by <b-tr> / <b-td> / <b-th>
return this.bvTable.isStacked;
},
isResponsive: function isResponsive() {
// Sniffed by <b-tr> / <b-td> / <b-th>
return this.bvTable.isResponsive;
},
isStickyHeader: function isStickyHeader() {
// Sniffed by <b-tr> / <b-td> / <b-th>
// Sticky headers are only supported in thead
return false;
},
hasStickyHeader: function hasStickyHeader() {
// Sniffed by <b-tr> / <b-td> / <b-th>
// Needed to handle header background classes, due to lack of
// background color inheritance with Bootstrap v4 table CSS
return !this.isStacked && this.bvTable.stickyHeader;
},
tableVariant: function tableVariant() {
// Sniffed by <b-tr> / <b-td> / <b-th>
return this.bvTable.tableVariant;
},
tfootClasses: function tfootClasses() {
return [this.footVariant ? "thead-".concat(this.footVariant) : null];
},
tfootAttrs: function tfootAttrs() {
return _objectSpread2({
role: 'rowgroup'
}, this.bvAttrs);
}
},
render: function render(h) {
return h('tfoot', {
class: this.tfootClasses,
attrs: this.tfootAttrs,
// Pass down any native listeners
on: this.bvListeners
}, this.normalizeSlot());
}
});
var tfootMixin = {
props: makePropsConfigurable({
footClone: {
type: Boolean,
default: false
},
footVariant: {
type: String // 'dark', 'light', or `null` (or custom)
// default: null
},
footRowVariant: {
// Any Bootstrap theme variant (or custom). Falls back to `headRowVariant`
type: String // default: null
},
tfootClass: {
type: [String, Array, Object] // default: null
},
tfootTrClass: {
type: [String, Array, Object] // default: null
}
}, NAME_TABLE),
methods: {
renderTFootCustom: function renderTFootCustom() {
var h = this.$createElement;
if (this.hasNormalizedSlot('custom-foot')) {
return h(BTfoot, {
key: 'bv-tfoot-custom',
class: this.tfootClass || null,
props: {
footVariant: this.footVariant || this.headVariant || null
}
}, this.normalizeSlot('custom-foot', {
items: this.computedItems.slice(),
fields: this.computedFields.slice(),
columns: this.computedFields.length
}));
} else {
return h();
}
},
renderTfoot: function renderTfoot() {
// Passing true to renderThead will make it render a tfoot
return this.footClone ? this.renderThead(true) : this.renderTFootCustom();
}
}
};
var props$19 = makePropsConfigurable({
headVariant: {
// Also sniffed by <b-tr> / <b-td> / <b-th>
type: String,
// Supported values: 'lite', 'dark', or null
default: null
}
}, NAME_THEAD); // TODO:
// In Bootstrap v5, we won't need "sniffing" as table element variants properly inherit
// to the child elements, so this can be converted to a functional component
// @vue/component
var BThead = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_THEAD,
// Mixin order is important!
mixins: [attrsMixin, listenersMixin, normalizeSlotMixin],
provide: function provide() {
return {
bvTableRowGroup: this
};
},
inject: {
bvTable: {
// Sniffed by <b-tr> / <b-td> / <b-th>
/* istanbul ignore next */
default: function _default() {
return {};
}
}
},
inheritAttrs: false,
props: props$19,
computed: {
isThead: function isThead() {
// Sniffed by <b-tr> / <b-td> / <b-th>
return true;
},
isDark: function isDark() {
// Sniffed by <b-tr> / <b-td> / <b-th>
return this.bvTable.dark;
},
isStacked: function isStacked() {
// Sniffed by <b-tr> / <b-td> / <b-th>
return this.bvTable.isStacked;
},
isResponsive: function isResponsive() {
// Sniffed by <b-tr> / <b-td> / <b-th>
return this.bvTable.isResponsive;
},
isStickyHeader: function isStickyHeader() {
// Sniffed by <b-tr> / <b-td> / <b-th>
// Needed to handle header background classes, due to lack of
// background color inheritance with Bootstrap v4 table CSS
// Sticky headers only apply to cells in table `thead`
return !this.isStacked && this.bvTable.stickyHeader;
},
hasStickyHeader: function hasStickyHeader() {
// Sniffed by <b-tr> / <b-td> / <b-th>
// Needed to handle header background classes, due to lack of
// background color inheritance with Bootstrap v4 table CSS
return !this.isStacked && this.bvTable.stickyHeader;
},
tableVariant: function tableVariant() {
// Sniffed by <b-tr> / <b-td> / <b-th>
return this.bvTable.tableVariant;
},
theadClasses: function theadClasses() {
return [this.headVariant ? "thead-".concat(this.headVariant) : null];
},
theadAttrs: function theadAttrs() {
return _objectSpread2({
role: 'rowgroup'
}, this.bvAttrs);
}
},
render: function render(h) {
return h('thead', {
class: this.theadClasses,
attrs: this.theadAttrs,
// Pass down any native listeners
on: this.bvListeners
}, this.normalizeSlot());
}
});
var theadMixin = {
props: makePropsConfigurable({
headVariant: {
type: String // 'light', 'dark' or `null` (or custom)
// default: null
},
headRowVariant: {
// Any Bootstrap theme variant (or custom)
type: String // default: null
},
theadClass: {
type: [String, Array, Object] // default: undefined
},
theadTrClass: {
type: [String, Array, Object] // default: undefined
}
}, NAME_TABLE),
methods: {
fieldClasses: function fieldClasses(field) {
// Header field (<th>) classes
return [field.class ? field.class : '', field.thClass ? field.thClass : ''];
},
headClicked: function headClicked(evt, field, isFoot) {
if (this.stopIfBusy && this.stopIfBusy(evt)) {
// If table is busy (via provider) then don't propagate
return;
} else if (filterEvent(evt)) {
// Clicked on a non-disabled control so ignore
return;
} else if (textSelectionActive(this.$el)) {
// User is selecting text, so ignore
/* istanbul ignore next: JSDOM doesn't support getSelection() */
return;
}
stopEvent(evt);
this.$emit('head-clicked', field.key, field, evt, isFoot);
},
renderThead: function renderThead() {
var _this = this;
var isFoot = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
var h = this.$createElement;
var fields = this.computedFields || []; // In always stacked mode, we don't bother rendering the head/foot
// Or if no field headings (empty table)
if (this.isStackedAlways || fields.length === 0) {
return h();
}
var isSortable = this.isSortable,
isSelectable = this.isSelectable,
headVariant = this.headVariant,
footVariant = this.footVariant,
headRowVariant = this.headRowVariant,
footRowVariant = this.footRowVariant;
var hasHeadClickListener = isSortable || this.hasListener('head-clicked'); // Reference to `selectAllRows` and `clearSelected()`, if table is selectable
var selectAllRows = isSelectable ? this.selectAllRows : noop;
var clearSelected = isSelectable ? this.clearSelected : noop; // Helper function to generate a field <th> cell
var makeCell = function makeCell(field, colIndex) {
var label = field.label,
labelHtml = field.labelHtml,
variant = field.variant,
stickyColumn = field.stickyColumn,
key = field.key;
var ariaLabel = null;
if (!field.label.trim() && !field.headerTitle) {
// In case field's label and title are empty/blank
// We need to add a hint about what the column is about for non-sighted users
/* istanbul ignore next */
ariaLabel = startCase(field.key);
}
var on = {};
if (hasHeadClickListener) {
on.click = function (evt) {
_this.headClicked(evt, field, isFoot);
};
on.keydown = function (evt) {
var keyCode = evt.keyCode;
if (keyCode === CODE_ENTER || keyCode === CODE_SPACE) {
_this.headClicked(evt, field, isFoot);
}
};
}
var sortAttrs = isSortable ? _this.sortTheadThAttrs(key, field, isFoot) : {};
var sortClass = isSortable ? _this.sortTheadThClasses(key, field, isFoot) : null;
var sortLabel = isSortable ? _this.sortTheadThLabel(key, field, isFoot) : null;
var data = {
class: [_this.fieldClasses(field), sortClass],
props: {
variant: variant,
stickyColumn: stickyColumn
},
style: field.thStyle || {},
attrs: _objectSpread2(_objectSpread2({
// We only add a tabindex of 0 if there is a head-clicked listener
tabindex: hasHeadClickListener ? '0' : null,
abbr: field.headerAbbr || null,
title: field.headerTitle || null,
'aria-colindex': colIndex + 1,
'aria-label': ariaLabel
}, _this.getThValues(null, key, field.thAttr, isFoot ? 'foot' : 'head', {})), sortAttrs),
on: on,
key: key
}; // Handle edge case where in-document templates are used with new
// `v-slot:name` syntax where the browser lower-cases the v-slot's
// name (attributes become lower cased when parsed by the browser)
// We have replaced the square bracket syntax with round brackets
// to prevent confusion with dynamic slot names
var slotNames = ["head(".concat(key, ")"), "head(".concat(key.toLowerCase(), ")"), 'head()']; // Footer will fallback to header slot names
if (isFoot) {
slotNames = ["foot(".concat(key, ")"), "foot(".concat(key.toLowerCase(), ")"), 'foot()'].concat(_toConsumableArray(slotNames));
}
var scope = {
label: label,
column: key,
field: field,
isFoot: isFoot,
// Add in row select methods
selectAllRows: selectAllRows,
clearSelected: clearSelected
};
var $content = _this.normalizeSlot(slotNames, scope) || h('div', {
domProps: htmlOrText(labelHtml, label)
});
var $srLabel = sortLabel ? h('span', {
staticClass: 'sr-only'
}, " (".concat(sortLabel, ")")) : null; // Return the header cell
return h(BTh, data, [$content, $srLabel].filter(identity));
}; // Generate the array of <th> cells
var $cells = fields.map(makeCell).filter(identity); // Generate the row(s)
var $trs = [];
if (isFoot) {
$trs.push(h(BTr, {
class: this.tfootTrClass,
props: {
variant: isUndefinedOrNull(footRowVariant) ? headRowVariant :
/* istanbul ignore next */
footRowVariant
}
}, $cells));
} else {
var scope = {
columns: fields.length,
fields: fields,
// Add in row select methods
selectAllRows: selectAllRows,
clearSelected: clearSelected
};
$trs.push(this.normalizeSlot('thead-top', scope) || h());
$trs.push(h(BTr, {
class: this.theadTrClass,
props: {
variant: headRowVariant
}
}, $cells));
}
return h(isFoot ? BTfoot : BThead, {
key: isFoot ? 'bv-tfoot' : 'bv-thead',
class: (isFoot ? this.tfootClass : this.theadClass) || null,
props: isFoot ? {
footVariant: footVariant || headVariant || null
} : {
headVariant: headVariant || null
}
}, $trs);
}
}
};
var slotName$1 = 'top-row';
var topRowMixin = {
methods: {
renderTopRow: function renderTopRow() {
var h = this.$createElement; // 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 (!this.hasNormalizedSlot(slotName$1) || this.stacked === true || this.stacked === '') {
return h();
}
var fields = this.computedFields;
return h(BTr, {
key: 'b-top-row',
staticClass: 'b-table-top-row',
class: [isFunction(this.tbodyTrClass) ? this.tbodyTrClass(null, 'row-top') : this.tbodyTrClass],
attrs: isFunction(this.tbodyTrAttr) ? this.tbodyTrAttr(null, 'row-top') : this.tbodyTrAttr
}, [this.normalizeSlot(slotName$1, {
columns: fields.length,
fields: fields
})]);
}
}
};
// @vue/component
var BTable = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_TABLE,
// Order of mixins is important!
// They are merged from first to last, followed by this component
mixins: [// General mixins
attrsMixin, hasListenerMixin, idMixin, normalizeSlotMixin, // Required table mixins
itemsMixin, tableRendererMixin, stackedMixin, theadMixin, tfootMixin, tbodyMixin, // Table features mixins
stackedMixin, filteringMixin, sortingMixin, paginationMixin$1, captionMixin, colgroupMixin, selectableMixin, emptyMixin, topRowMixin, bottomRowMixin, busyMixin, providerMixin] // Render function is provided by table-renderer mixin
});
// @vue/component
var BTableLite = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_TABLE_LITE,
// Order of mixins is important!
// They are merged from first to last, followed by this component.
mixins: [// Required mixins
hasListenerMixin, idMixin, normalizeSlotMixin, itemsMixin, tableRendererMixin, stackedMixin, theadMixin, tfootMixin, tbodyMixin, // Features Mixins
// These are pretty lightweight, and are useful for lightweight tables
captionMixin, colgroupMixin] // render function provided by table-renderer mixin
});
// @vue/component
var BTableSimple = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_TABLE_SIMPLE,
// Order of mixins is important!
// They are merged from first to last, followed by this component.
mixins: [// Required mixins
idMixin, normalizeSlotMixin, tableRendererMixin, // feature mixin
// Stacked requires extra handling by users via
// the table cell `stacked-heading` prop
stackedMixin],
computed: {
isTableSimple: function isTableSimple() {
return true;
}
} // render function provided by table-renderer mixin
});
var TableLitePlugin = /*#__PURE__*/pluginFactory({
components: {
BTableLite: BTableLite
}
});
var TableSimplePlugin = /*#__PURE__*/pluginFactory({
components: {
BTableSimple: BTableSimple,
BTbody: BTbody,
BThead: BThead,
BTfoot: BTfoot,
BTr: BTr,
BTd: BTd,
BTh: BTh
}
});
var TablePlugin = /*#__PURE__*/pluginFactory({
components: {
BTable: BTable
},
plugins: {
TableLitePlugin: TableLitePlugin,
TableSimplePlugin: TableSimplePlugin
}
});
var BSkeletonTable = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_SKELETON_TABLE,
functional: true,
props: makePropsConfigurable({
animation: {
type: String
},
rows: {
type: Number,
default: 3,
validator: function validator(value) {
return value > 0;
}
},
columns: {
type: Number,
default: 5,
validator: function validator(value) {
return value > 0;
}
},
hideHeader: {
type: Boolean,
default: false
},
showFooter: {
type: Boolean,
default: false
},
tableProps: {
type: Object,
default: function _default() {}
}
}, NAME_SKELETON_TABLE),
render: function render(h, _ref) {
var props = _ref.props;
var animation = props.animation,
columns = props.columns;
var $th = h('th', [h(BSkeleton, {
props: {
animation: animation
}
})]);
var $thTr = h('tr', createAndFillArray(columns, $th));
var $td = h('td', [h(BSkeleton, {
props: {
width: '75%',
animation: animation
}
})]);
var $tdTr = h('tr', createAndFillArray(columns, $td));
var $tbody = h('tbody', createAndFillArray(props.rows, $tdTr));
var $thead = !props.hideHeader ? h('thead', [$thTr]) : h();
var $tfoot = props.showFooter ? h('tfoot', [$thTr]) : h();
return h(BTableSimple, {
props: _objectSpread2({}, props.tableProps)
}, [$thead, $tbody, $tfoot]);
}
});
var BSkeletonWrapper = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_SKELETON_WRAPPER,
functional: true,
props: makePropsConfigurable({
loading: {
type: Boolean,
default: false
}
}, NAME_SKELETON_WRAPPER),
render: function render(h, _ref) {
var data = _ref.data,
props = _ref.props,
slots = _ref.slots,
scopedSlots = _ref.scopedSlots;
var $slots = slots();
var $scopedSlots = scopedSlots || {};
var slotScope = {};
if (props.loading) {
return h('div', a(data, {
attrs: {
role: 'alert',
'aria-live': 'polite',
'aria-busy': true
},
staticClass: 'b-skeleton-wrapper',
key: 'loading'
}), [normalizeSlot('loading', slotScope, $scopedSlots, $slots) || h()]);
}
return normalizeSlot(SLOT_NAME_DEFAULT, slotScope, $scopedSlots, $slots) || h();
}
});
var SkeletonPlugin = /*#__PURE__*/pluginFactory({
components: {
BSkeleton: BSkeleton,
BSkeletonIcon: BSkeletonIcon,
BSkeletonImg: BSkeletonImg,
BSkeletonTable: BSkeletonTable,
BSkeletonWrapper: BSkeletonWrapper
}
});
var SpinnerPlugin = /*#__PURE__*/pluginFactory({
components: {
BSpinner: BSpinner
}
});
var navProps = omit(props$X, ['tabs', 'isNavBar', 'cardHeader']); // --- Helper methods ---
// Filter function to filter out disabled tabs
var notDisabled = function notDisabled(tab) {
return !tab.disabled;
}; // --- Helper components ---
// @vue/component
var BVTabButton = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_TAB_BUTTON_HELPER,
inject: {
bvTabs: {
/* istanbul ignore next */
default: function _default() {
return {};
}
}
},
props: makePropsConfigurable({
// Reference to the child <b-tab> instance
tab: {
default: null
},
tabs: {
type: Array,
/* istanbul ignore next */
default: function _default() {
return [];
}
},
id: {
type: String,
default: null
},
controls: {
type: String,
default: null
},
tabIndex: {
type: Number,
default: null
},
posInSet: {
type: Number,
default: null
},
setSize: {
type: Number,
default: null
},
noKeyNav: {
type: Boolean,
default: false
}
}, NAME_TABS),
methods: {
focus: function focus() {
attemptFocus(this.$refs.link);
},
handleEvt: function handleEvt(evt) {
if (this.tab.disabled) {
/* istanbul ignore next */
return;
}
var type = evt.type,
keyCode = evt.keyCode,
shiftKey = evt.shiftKey;
if (type === 'click') {
stopEvent(evt);
this.$emit('click', evt);
} else if (type === 'keydown' && keyCode === CODE_SPACE) {
// For ARIA tabs the SPACE key will also trigger a click/select
// Even with keyboard navigation disabled, SPACE should "click" the button
// See: https://github.com/bootstrap-vue/bootstrap-vue/issues/4323
stopEvent(evt);
this.$emit('click', evt);
} else if (type === 'keydown' && !this.noKeyNav) {
// For keyboard navigation
if ([CODE_UP, CODE_LEFT, CODE_HOME].indexOf(keyCode) !== -1) {
stopEvent(evt);
if (shiftKey || keyCode === CODE_HOME) {
this.$emit('first', evt);
} else {
this.$emit('prev', evt);
}
} else if ([CODE_DOWN, CODE_RIGHT, CODE_END].indexOf(keyCode) !== -1) {
stopEvent(evt);
if (shiftKey || keyCode === CODE_END) {
this.$emit('last', evt);
} else {
this.$emit('next', evt);
}
}
}
}
},
render: function render(h) {
var id = this.id,
tabIndex = this.tabIndex,
setSize = this.setSize,
posInSet = this.posInSet,
controls = this.controls,
handleEvt = this.handleEvt;
var _this$tab = this.tab,
title = _this$tab.title,
localActive = _this$tab.localActive,
disabled = _this$tab.disabled,
titleItemClass = _this$tab.titleItemClass,
titleLinkClass = _this$tab.titleLinkClass,
titleLinkAttributes = _this$tab.titleLinkAttributes;
var $link = h(BLink, {
ref: 'link',
staticClass: 'nav-link',
class: [{
active: localActive && !disabled,
disabled: disabled
}, titleLinkClass, // Apply <b-tabs> `activeNavItemClass` styles when the tab is active
localActive ? this.bvTabs.activeNavItemClass : null],
props: {
disabled: disabled
},
attrs: _objectSpread2(_objectSpread2({}, titleLinkAttributes), {}, {
role: 'tab',
id: id,
// Roving tab index when keynav enabled
tabindex: tabIndex,
'aria-selected': localActive && !disabled ? 'true' : 'false',
'aria-setsize': setSize,
'aria-posinset': posInSet,
'aria-controls': controls
}),
on: {
click: handleEvt,
keydown: handleEvt
}
}, [this.tab.normalizeSlot(SLOT_NAME_TITLE) || title]);
return h('li', {
staticClass: 'nav-item',
class: [titleItemClass],
attrs: {
role: 'presentation'
}
}, [$link]);
}
}); // @vue/component
var BTabs = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_TABS,
mixins: [idMixin, normalizeSlotMixin],
provide: function provide() {
return {
bvTabs: this
};
},
model: {
prop: 'value',
event: 'input'
},
props: _objectSpread2(_objectSpread2({}, navProps), {}, {
tag: {
type: String,
default: 'div'
},
card: {
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 <b-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
},
activeNavItemClass: {
// Only applied to the currently active <b-nav-item>
type: [String, Array, Object] // default: null
},
activeTabClass: {
// Only applied to the currently active <b-tab>
// This prop is sniffed by the <b-tab> child
type: [String, Array, Object] // default: null
},
value: {
// v-model
type: Number,
default: null
}
}),
data: function data() {
return {
// Index of current tab
currentTab: toInteger(this.value, -1),
// Array of direct child <b-tab> instances, in DOM order
tabs: [],
// Array of child instances registered (for triggering reactive updates)
registeredTabs: [],
// Flag to know if we are mounted or not
isMounted: false
};
},
computed: {
fade: function fade() {
// This computed prop is sniffed by the tab child
return !this.noFade;
},
localNavClass: function localNavClass() {
var classes = [];
if (this.card && this.vertical) {
classes.push('card-header', 'h-100', 'border-bottom-0', 'rounded-0');
}
return [].concat(classes, [this.navClass]);
}
},
watch: {
currentTab: function currentTab(newVal) {
var index = -1; // Ensure only one tab is active at most
this.tabs.forEach(function (tab, idx) {
if (newVal === idx && !tab.disabled) {
tab.localActive = true;
index = idx;
} else {
tab.localActive = false;
}
}); // Update the v-model
this.$emit('input', index);
},
value: function value(newVal, oldVal) {
if (newVal !== oldVal) {
newVal = toInteger(newVal, -1);
oldVal = toInteger(oldVal, 0);
var tabs = this.tabs;
if (tabs[newVal] && !tabs[newVal].disabled) {
this.activateTab(tabs[newVal]);
} else {
// Try next or prev tabs
if (newVal < oldVal) {
this.previousTab();
} else {
this.nextTab();
}
}
}
},
registeredTabs: function registeredTabs() {
var _this = this;
// Each b-tab will register/unregister itself.
// We use this to detect when tabs are added/removed
// to trigger the update of the tabs.
this.$nextTick(function () {
requestAF(function () {
_this.updateTabs();
});
});
},
tabs: function tabs(newVal, oldVal) {
var _this2 = this;
// If tabs added, removed, or re-ordered, we emit a `changed` event.
// We use `tab._uid` instead of `tab.safeId()`, as the later is changed
// in a nextTick if no explicit ID is provided, causing duplicate emits.
if (!looseEqual(newVal.map(function (t) {
return t._uid;
}), oldVal.map(function (t) {
return t._uid;
}))) {
// In a nextTick to ensure currentTab has been set first.
this.$nextTick(function () {
// We emit shallow copies of the new and old arrays of tabs, to
// prevent users from potentially mutating the internal arrays.
_this2.$emit('changed', newVal.slice(), oldVal.slice());
});
}
},
isMounted: function isMounted(newVal) {
var _this3 = this;
// Trigger an update after mounted. Needed for tabs inside lazy modals.
if (newVal) {
requestAF(function () {
_this3.updateTabs();
});
} // Enable or disable the observer
this.setObserver(newVal);
}
},
created: function created() {
var _this4 = this;
// Create private non-reactive props
this.$_observer = null;
this.currentTab = toInteger(this.value, -1); // For SSR and to make sure only a single tab is shown on mount
// We wrap this in a `$nextTick()` to ensure the child tabs have been created
this.$nextTick(function () {
_this4.updateTabs();
});
},
mounted: function mounted() {
var _this5 = this;
// Call `updateTabs()` just in case...
this.updateTabs();
this.$nextTick(function () {
// Flag we are now mounted and to switch to DOM for tab probing.
// As this.$slots.default appears to lie about component instances
// after b-tabs is destroyed and re-instantiated.
// And this.$children does not respect DOM order.
_this5.isMounted = true;
});
},
/* istanbul ignore next */
deactivated: function deactivated() {
this.isMounted = false;
},
/* istanbul ignore next */
activated: function activated() {
var _this6 = this;
this.currentTab = toInteger(this.value, -1);
this.$nextTick(function () {
_this6.updateTabs();
_this6.isMounted = true;
});
},
beforeDestroy: function beforeDestroy() {
this.isMounted = false;
},
destroyed: function destroyed() {
// Ensure no references to child instances exist
this.tabs = [];
},
methods: {
registerTab: function registerTab(tab) {
var _this7 = this;
if (!arrayIncludes(this.registeredTabs, tab)) {
this.registeredTabs.push(tab);
tab.$once('hook:destroyed', function () {
_this7.unregisterTab(tab);
});
}
},
unregisterTab: function unregisterTab(tab) {
this.registeredTabs = this.registeredTabs.slice().filter(function (t) {
return t !== tab;
});
},
// DOM observer is needed to detect changes in order of tabs
setObserver: function setObserver(on) {
this.$_observer && this.$_observer.disconnect();
this.$_observer = null;
if (on) {
var self = this;
/* istanbul ignore next: difficult to test mutation observer in JSDOM */
var handler = function handler() {
// We delay the update to ensure that `tab.safeId()` has
// updated with the final ID value.
self.$nextTick(function () {
requestAF(function () {
self.updateTabs();
});
});
}; // Watch for changes to <b-tab> sub components
this.$_observer = observeDom(this.$refs.tabsContainer, handler, {
childList: true,
subtree: false,
attributes: true,
attributeFilter: ['id']
});
}
},
getTabs: function getTabs() {
// We use `registeredTabs` as the source of truth for child tab components
// We also filter out any `<b-tab>` components that are extended
// `<b-tab>` with a root child `<b-tab>`
// See: https://github.com/bootstrap-vue/bootstrap-vue/issues/3260
var tabs = this.registeredTabs.filter(function (tab) {
return tab.$children.filter(function (t) {
return t._isTab;
}).length === 0;
}); // DOM Order of Tabs
var order = [];
if (this.isMounted && tabs.length > 0) {
// We rely on the DOM when mounted to get the 'true' order of the `<b-tab>` children
// `querySelectorAll()` always returns elements in document order, regardless of
// order specified in the selector
var selector = tabs.map(function (tab) {
return "#".concat(tab.safeId());
}).join(', ');
order = selectAll(selector, this.$el).map(function (el) {
return el.id;
}).filter(identity);
} // Stable sort keeps the original order if not found in the `order` array,
// which will be an empty array before mount
return stableSort(tabs, function (a, b) {
return order.indexOf(a.safeId()) - order.indexOf(b.safeId());
});
},
// Update list of `<b-tab>` children
updateTabs: function updateTabs() {
// Probe tabs
var tabs = this.getTabs(); // Find *last* active non-disabled tab in current tabs
// We trust tab state over `currentTab`, in case tabs were added/removed/re-ordered
var tabIndex = tabs.indexOf(tabs.slice().reverse().find(function (tab) {
return tab.localActive && !tab.disabled;
})); // Else try setting to `currentTab`
if (tabIndex < 0) {
var currentTab = this.currentTab;
if (currentTab >= tabs.length) {
// Handle last tab being removed, so find the last non-disabled tab
tabIndex = tabs.indexOf(tabs.slice().reverse().find(notDisabled));
} else if (tabs[currentTab] && !tabs[currentTab].disabled) {
// Current tab is not disabled
tabIndex = currentTab;
}
} // Else find *first* non-disabled tab in current tabs
if (tabIndex < 0) {
tabIndex = tabs.indexOf(tabs.find(notDisabled));
} // Set the current tab state to active
tabs.forEach(function (tab) {
// tab.localActive = idx === tabIndex && !tab.disabled
tab.localActive = false;
});
if (tabs[tabIndex]) {
tabs[tabIndex].localActive = true;
} // Update the array of tab children
this.tabs = tabs; // Set the currentTab index (can be -1 if no non-disabled tabs)
this.currentTab = tabIndex;
},
// Find a button that controls a tab, given the tab reference
// Returns the button vm instance
getButtonForTab: function getButtonForTab(tab) {
return (this.$refs.buttons || []).find(function (btn) {
return btn.tab === tab;
});
},
// Force a button to re-render its content, given a <b-tab> instance
// Called by <b-tab> on `update()`
updateButton: function updateButton(tab) {
var button = this.getButtonForTab(tab);
if (button && button.$forceUpdate) {
button.$forceUpdate();
}
},
// Activate a tab given a `<b-tab>` instance
// Also accessed by `<b-tab>`
activateTab: function activateTab(tab) {
var result = false;
if (tab) {
var index = this.tabs.indexOf(tab);
if (!tab.disabled && index > -1 && index !== this.currentTab) {
var tabEvt = new BvEvent('activate-tab', {
cancelable: true,
vueTarget: this,
componentId: this.safeId()
});
this.$emit(tabEvt.type, index, this.currentTab, tabEvt);
if (!tabEvt.defaultPrevented) {
result = true;
this.currentTab = index;
}
}
} // Couldn't set tab, so ensure v-model is set to `this.currentTab`
/* istanbul ignore next: should rarely happen */
if (!result && this.currentTab !== this.value) {
this.$emit('input', this.currentTab);
}
return result;
},
// Deactivate a tab given a <b-tab> instance
// Accessed by <b-tab>
deactivateTab: function deactivateTab(tab) {
if (tab) {
// Find first non-disabled tab that isn't the one being deactivated
// If no tabs are available, then don't deactivate current tab
return this.activateTab(this.tabs.filter(function (t) {
return t !== tab;
}).find(notDisabled));
}
/* istanbul ignore next: should never/rarely happen */
return false;
},
// Focus a tab button given its <b-tab> instance
focusButton: function focusButton(tab) {
var _this8 = this;
// Wrap in `$nextTick()` to ensure DOM has completed rendering/updating before focusing
this.$nextTick(function () {
attemptFocus(_this8.getButtonForTab(tab));
});
},
// Emit a click event on a specified <b-tab> component instance
emitTabClick: function emitTabClick(tab, evt) {
if (isEvent(evt) && tab && tab.$emit && !tab.disabled) {
tab.$emit('click', evt);
}
},
// Click handler
clickTab: function clickTab(tab, evt) {
this.activateTab(tab);
this.emitTabClick(tab, evt);
},
// Move to first non-disabled tab
firstTab: function firstTab(focus) {
var tab = this.tabs.find(notDisabled);
if (this.activateTab(tab) && focus) {
this.focusButton(tab);
this.emitTabClick(tab, focus);
}
},
// Move to previous non-disabled tab
previousTab: function previousTab(focus) {
var currentIndex = mathMax(this.currentTab, 0);
var tab = this.tabs.slice(0, currentIndex).reverse().find(notDisabled);
if (this.activateTab(tab) && focus) {
this.focusButton(tab);
this.emitTabClick(tab, focus);
}
},
// Move to next non-disabled tab
nextTab: function nextTab(focus) {
var currentIndex = mathMax(this.currentTab, -1);
var tab = this.tabs.slice(currentIndex + 1).find(notDisabled);
if (this.activateTab(tab) && focus) {
this.focusButton(tab);
this.emitTabClick(tab, focus);
}
},
// Move to last non-disabled tab
lastTab: function lastTab(focus) {
var tab = this.tabs.slice().reverse().find(notDisabled);
if (this.activateTab(tab) && focus) {
this.focusButton(tab);
this.emitTabClick(tab, focus);
}
}
},
render: function render(h) {
var _this9 = this;
var tabs = this.tabs,
noKeyNav = this.noKeyNav,
firstTab = this.firstTab,
previousTab = this.previousTab,
nextTab = this.nextTab,
lastTab = this.lastTab; // Currently active tab
var activeTab = tabs.find(function (tab) {
return tab.localActive && !tab.disabled;
}); // Tab button to allow focusing when no active tab found (keynav only)
var fallbackTab = tabs.find(function (tab) {
return !tab.disabled;
}); // For each `<b-tab>` found create the tab buttons
var buttons = tabs.map(function (tab, index) {
var tabIndex = null; // Ensure at least one tab button is focusable when keynav enabled (if possible)
if (!noKeyNav) {
// Buttons are not in tab index unless active, or a fallback tab
tabIndex = -1;
if (activeTab === tab || !activeTab && fallbackTab === tab) {
// Place tab button in tab sequence
tabIndex = null;
}
}
return h(BVTabButton, {
key: tab._uid || index,
ref: 'buttons',
// Needed to make `this.$refs.buttons` an array
refInFor: true,
props: {
tab: tab,
tabs: tabs,
id: tab.controlledBy || (tab.safeId ? tab.safeId("_BV_tab_button_") : null),
controls: tab.safeId ? tab.safeId() : null,
tabIndex: tabIndex,
setSize: tabs.length,
posInSet: index + 1,
noKeyNav: noKeyNav
},
on: {
click: function click(evt) {
_this9.clickTab(tab, evt);
},
first: firstTab,
prev: previousTab,
next: nextTab,
last: lastTab
}
});
}); // Nav
var nav = h(BNav, {
ref: 'nav',
class: this.localNavClass,
attrs: {
role: 'tablist',
id: this.safeId('_BV_tab_controls_')
},
props: {
fill: this.fill,
justified: this.justified,
align: this.align,
tabs: !this.noNavStyle && !this.pills,
pills: !this.noNavStyle && this.pills,
vertical: this.vertical,
small: this.small,
cardHeader: this.card && !this.vertical
}
}, [this.normalizeSlot('tabs-start') || h(), buttons, this.normalizeSlot('tabs-end') || h()]);
nav = h('div', {
key: 'bv-tabs-nav',
class: [{
'card-header': this.card && !this.vertical && !this.end,
'card-footer': this.card && !this.vertical && this.end,
'col-auto': this.vertical
}, this.navWrapperClass]
}, [nav]);
var empty = h();
if (!tabs || tabs.length === 0) {
empty = h('div', {
key: 'bv-empty-tab',
class: ['tab-pane', 'active', {
'card-body': this.card
}]
}, this.normalizeSlot('empty'));
} // Main content section
var content = h('div', {
ref: 'tabsContainer',
key: 'bv-tabs-container',
staticClass: 'tab-content',
class: [{
col: this.vertical
}, this.contentClass],
attrs: {
id: this.safeId('_BV_tab_container_')
}
}, concat(this.normalizeSlot(), empty)); // Render final output
return h(this.tag, {
staticClass: 'tabs',
class: {
row: this.vertical,
'no-gutters': this.vertical && this.card
},
attrs: {
id: this.safeId()
}
}, [this.end ? content : h(), [nav], this.end ? h() : content]);
}
});
var BTab = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_TAB,
mixins: [idMixin, normalizeSlotMixin],
inject: {
bvTabs: {
default: function _default() {
return {};
}
}
},
props: makePropsConfigurable({
active: {
type: Boolean,
default: false
},
tag: {
type: String,
default: 'div'
},
buttonId: {
type: String // default: ''
},
title: {
type: String,
default: ''
},
titleItemClass: {
// Sniffed by `<b-tabs>` and added to nav `li.nav-item`
type: [String, Array, Object] // default: null
},
titleLinkClass: {
// Sniffed by `<b-tabs>` and added to nav `a.nav-link`
type: [String, Array, Object] // default: null
},
titleLinkAttributes: {
type: Object // default: null
},
disabled: {
type: Boolean,
default: false
},
noBody: {
type: Boolean,
default: false
},
lazy: {
type: Boolean,
default: false
}
}, NAME_TAB),
data: function data() {
return {
localActive: this.active && !this.disabled,
show: false
};
},
computed: {
tabClasses: function tabClasses() {
return [{
active: this.localActive,
disabled: this.disabled,
'card-body': this.bvTabs.card && !this.noBody
}, // Apply <b-tabs> `activeTabClass` styles when this tab is active
this.localActive ? this.bvTabs.activeTabClass : null];
},
controlledBy: function controlledBy() {
return this.buttonId || this.safeId('__BV_tab_button__');
},
computedNoFade: function computedNoFade() {
return !(this.bvTabs.fade || false);
},
computedLazy: function computedLazy() {
return this.bvTabs.lazy || this.lazy;
},
// For parent sniffing of child
_isTab: function _isTab() {
return true;
}
},
watch: {
localActive: function localActive(newValue) {
// Make `active` prop work with `.sync` modifier
this.$emit('update:active', newValue);
},
active: function active(newValue, oldValue) {
if (newValue !== oldValue) {
if (newValue) {
// If activated post mount
this.activate();
} else {
/* istanbul ignore next */
if (!this.deactivate()) {
// Tab couldn't be deactivated, so we reset the synced active prop
// Deactivation will fail if no other tabs to activate
this.$emit('update:active', this.localActive);
}
}
}
},
disabled: function disabled(newValue, oldValue) {
if (newValue !== oldValue) {
var firstTab = this.bvTabs.firstTab;
if (newValue && this.localActive && firstTab) {
this.localActive = false;
firstTab();
}
}
}
},
mounted: function mounted() {
// Inform b-tabs of our presence
this.registerTab(); // Initially show on mount if active and not disabled
this.show = this.localActive;
},
updated: function updated() {
// Force the tab button content to update (since slots are not reactive)
// Only done if we have a title slot, as the title prop is reactive
var updateButton = this.bvTabs.updateButton;
if (updateButton && this.hasNormalizedSlot(SLOT_NAME_TITLE)) {
updateButton(this);
}
},
destroyed: function destroyed() {
// inform b-tabs of our departure
this.unregisterTab();
},
methods: {
// Private methods
registerTab: function registerTab() {
// Inform `<b-tabs>` of our presence
var registerTab = this.bvTabs.registerTab;
if (registerTab) {
registerTab(this);
}
},
unregisterTab: function unregisterTab() {
// Inform `<b-tabs>` of our departure
var unregisterTab = this.bvTabs.unregisterTab;
if (unregisterTab) {
unregisterTab(this);
}
},
// Public methods
activate: function activate() {
// Not inside a `<b-tabs>` component or tab is disabled
var activateTab = this.bvTabs.activateTab;
return activateTab && !this.disabled ? activateTab(this) : false;
},
deactivate: function deactivate() {
// Not inside a `<b-tabs>` component or not active to begin with
var deactivateTab = this.bvTabs.deactivateTab;
return deactivateTab && this.localActive ? deactivateTab(this) : false;
}
},
render: function render(h) {
var localActive = this.localActive;
var $content = h(this.tag, {
ref: 'panel',
staticClass: 'tab-pane',
class: this.tabClasses,
directives: [{
name: 'show',
rawName: 'v-show',
value: localActive,
expression: 'localActive'
}],
attrs: {
role: 'tabpanel',
id: this.safeId(),
'aria-hidden': localActive ? 'false' : 'true',
'aria-labelledby': this.controlledBy || null
}
}, // Render content lazily if requested
[localActive || !this.computedLazy ? this.normalizeSlot() : h()]);
return h(BVTransition, {
props: {
mode: 'out-in',
noFade: this.computedNoFade
}
}, [$content]);
}
});
var TabsPlugin = /*#__PURE__*/pluginFactory({
components: {
BTabs: BTabs,
BTab: BTab
}
});
var TimePlugin = /*#__PURE__*/pluginFactory({
components: {
BTime: BTime
}
});
function _typeof$1(obj) {
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
_typeof$1 = function (obj) {
return typeof obj;
};
} else {
_typeof$1 = function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
}
return _typeof$1(obj);
}
function _toConsumableArray$1(arr) {
return _arrayWithoutHoles$1(arr) || _iterableToArray$1(arr) || _nonIterableSpread$1();
}
function _arrayWithoutHoles$1(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2;
}
}
function _iterableToArray$1(iter) {
if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
}
function _nonIterableSpread$1() {
throw new TypeError("Invalid attempt to spread non-iterable instance");
}
var inBrowser = typeof window !== 'undefined';
function freeze(item) {
if (Array.isArray(item) || _typeof$1(item) === 'object') {
return Object.freeze(item);
}
return item;
}
function combinePassengers(transports) {
var slotProps = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return transports.reduce(function (passengers, transport) {
var temp = transport.passengers[0];
var newPassengers = typeof temp === 'function' ? temp(slotProps) : transport.passengers;
return passengers.concat(newPassengers);
}, []);
}
function stableSort$1(array, compareFn) {
return array.map(function (v, idx) {
return [idx, v];
}).sort(function (a, b) {
return compareFn(a[1], b[1]) || a[0] - b[0];
}).map(function (c) {
return c[1];
});
}
function pick$1(obj, keys) {
return keys.reduce(function (acc, key) {
if (obj.hasOwnProperty(key)) {
acc[key] = obj[key];
}
return acc;
}, {});
}
var transports = {};
var targets = {};
var sources = {};
var Wormhole = Vue__default['default'].extend({
data: function data() {
return {
transports: transports,
targets: targets,
sources: sources,
trackInstances: inBrowser
};
},
methods: {
open: function open(transport) {
if (!inBrowser) return;
var to = transport.to,
from = transport.from,
passengers = transport.passengers,
_transport$order = transport.order,
order = _transport$order === void 0 ? Infinity : _transport$order;
if (!to || !from || !passengers) return;
var newTransport = {
to: to,
from: from,
passengers: freeze(passengers),
order: order
};
var keys = Object.keys(this.transports);
if (keys.indexOf(to) === -1) {
Vue__default['default'].set(this.transports, to, []);
}
var currentIndex = this.$_getTransportIndex(newTransport); // Copying the array here so that the PortalTarget change event will actually contain two distinct arrays
var newTransports = this.transports[to].slice(0);
if (currentIndex === -1) {
newTransports.push(newTransport);
} else {
newTransports[currentIndex] = newTransport;
}
this.transports[to] = stableSort$1(newTransports, function (a, b) {
return a.order - b.order;
});
},
close: function close(transport) {
var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var to = transport.to,
from = transport.from;
if (!to || !from && force === false) return;
if (!this.transports[to]) {
return;
}
if (force) {
this.transports[to] = [];
} else {
var index = this.$_getTransportIndex(transport);
if (index >= 0) {
// Copying the array here so that the PortalTarget change event will actually contain two distinct arrays
var newTransports = this.transports[to].slice(0);
newTransports.splice(index, 1);
this.transports[to] = newTransports;
}
}
},
registerTarget: function registerTarget(target, vm, force) {
if (!inBrowser) return;
if (this.trackInstances && !force && this.targets[target]) {
console.warn("[portal-vue]: Target ".concat(target, " already exists"));
}
this.$set(this.targets, target, Object.freeze([vm]));
},
unregisterTarget: function unregisterTarget(target) {
this.$delete(this.targets, target);
},
registerSource: function registerSource(source, vm, force) {
if (!inBrowser) return;
if (this.trackInstances && !force && this.sources[source]) {
console.warn("[portal-vue]: source ".concat(source, " already exists"));
}
this.$set(this.sources, source, Object.freeze([vm]));
},
unregisterSource: function unregisterSource(source) {
this.$delete(this.sources, source);
},
hasTarget: function hasTarget(to) {
return !!(this.targets[to] && this.targets[to][0]);
},
hasSource: function hasSource(to) {
return !!(this.sources[to] && this.sources[to][0]);
},
hasContentFor: function hasContentFor(to) {
return !!this.transports[to] && !!this.transports[to].length;
},
// Internal
$_getTransportIndex: function $_getTransportIndex(_ref) {
var to = _ref.to,
from = _ref.from;
for (var i in this.transports[to]) {
if (this.transports[to][i].from === from) {
return +i;
}
}
return -1;
}
}
});
var wormhole = new Wormhole(transports);
var _id = 1;
var Portal = Vue__default['default'].extend({
name: 'portal',
props: {
disabled: {
type: Boolean
},
name: {
type: String,
default: function _default() {
return String(_id++);
}
},
order: {
type: Number,
default: 0
},
slim: {
type: Boolean
},
slotProps: {
type: Object,
default: function _default() {
return {};
}
},
tag: {
type: String,
default: 'DIV'
},
to: {
type: String,
default: function _default() {
return String(Math.round(Math.random() * 10000000));
}
}
},
created: function created() {
var _this = this;
this.$nextTick(function () {
wormhole.registerSource(_this.name, _this);
});
},
mounted: function mounted() {
if (!this.disabled) {
this.sendUpdate();
}
},
updated: function updated() {
if (this.disabled) {
this.clear();
} else {
this.sendUpdate();
}
},
beforeDestroy: function beforeDestroy() {
wormhole.unregisterSource(this.name);
this.clear();
},
watch: {
to: function to(newValue, oldValue) {
oldValue && oldValue !== newValue && this.clear(oldValue);
this.sendUpdate();
}
},
methods: {
clear: function clear(target) {
var closer = {
from: this.name,
to: target || this.to
};
wormhole.close(closer);
},
normalizeSlots: function normalizeSlots() {
return this.$scopedSlots.default ? [this.$scopedSlots.default] : this.$slots.default;
},
normalizeOwnChildren: function normalizeOwnChildren(children) {
return typeof children === 'function' ? children(this.slotProps) : children;
},
sendUpdate: function sendUpdate() {
var slotContent = this.normalizeSlots();
if (slotContent) {
var transport = {
from: this.name,
to: this.to,
passengers: _toConsumableArray$1(slotContent),
order: this.order
};
wormhole.open(transport);
} else {
this.clear();
}
}
},
render: function render(h) {
var children = this.$slots.default || this.$scopedSlots.default || [];
var Tag = this.tag;
if (children && this.disabled) {
return children.length <= 1 && this.slim ? this.normalizeOwnChildren(children)[0] : h(Tag, [this.normalizeOwnChildren(children)]);
} else {
return this.slim ? h() : h(Tag, {
class: {
'v-portal': true
},
style: {
display: 'none'
},
key: 'v-portal-placeholder'
});
}
}
});
var PortalTarget = Vue__default['default'].extend({
name: 'portalTarget',
props: {
multiple: {
type: Boolean,
default: false
},
name: {
type: String,
required: true
},
slim: {
type: Boolean,
default: false
},
slotProps: {
type: Object,
default: function _default() {
return {};
}
},
tag: {
type: String,
default: 'div'
},
transition: {
type: [String, Object, Function]
}
},
data: function data() {
return {
transports: wormhole.transports,
firstRender: true
};
},
created: function created() {
var _this = this;
this.$nextTick(function () {
wormhole.registerTarget(_this.name, _this);
});
},
watch: {
ownTransports: function ownTransports() {
this.$emit('change', this.children().length > 0);
},
name: function name(newVal, oldVal) {
/**
* TODO
* This should warn as well ...
*/
wormhole.unregisterTarget(oldVal);
wormhole.registerTarget(newVal, this);
}
},
mounted: function mounted() {
var _this2 = this;
if (this.transition) {
this.$nextTick(function () {
// only when we have a transition, because it causes a re-render
_this2.firstRender = false;
});
}
},
beforeDestroy: function beforeDestroy() {
wormhole.unregisterTarget(this.name);
},
computed: {
ownTransports: function ownTransports() {
var transports = this.transports[this.name] || [];
if (this.multiple) {
return transports;
}
return transports.length === 0 ? [] : [transports[transports.length - 1]];
},
passengers: function passengers() {
return combinePassengers(this.ownTransports, this.slotProps);
}
},
methods: {
// can't be a computed prop because it has to "react" to $slot changes.
children: function children() {
return this.passengers.length !== 0 ? this.passengers : this.$scopedSlots.default ? this.$scopedSlots.default(this.slotProps) : this.$slots.default || [];
},
// can't be a computed prop because it has to "react" to this.children().
noWrapper: function noWrapper() {
var noWrapper = this.slim && !this.transition;
if (noWrapper && this.children().length > 1) {
console.warn('[portal-vue]: PortalTarget with `slim` option received more than one child element.');
}
return noWrapper;
}
},
render: function render(h) {
var noWrapper = this.noWrapper();
var children = this.children();
var Tag = this.transition || this.tag;
return noWrapper ? children[0] : this.slim && !Tag ? h() : h(Tag, {
props: {
// if we have a transition component, pass the tag if it exists
tag: this.transition && this.tag ? this.tag : undefined
},
class: {
'vue-portal-target': true
}
}, children);
}
});
var _id$1 = 0;
var portalProps = ['disabled', 'name', 'order', 'slim', 'slotProps', 'tag', 'to'];
var targetProps = ['multiple', 'transition'];
var MountingPortal = Vue__default['default'].extend({
name: 'MountingPortal',
inheritAttrs: false,
props: {
append: {
type: [Boolean, String]
},
bail: {
type: Boolean
},
mountTo: {
type: String,
required: true
},
// Portal
disabled: {
type: Boolean
},
// name for the portal
name: {
type: String,
default: function _default() {
return 'mounted_' + String(_id$1++);
}
},
order: {
type: Number,
default: 0
},
slim: {
type: Boolean
},
slotProps: {
type: Object,
default: function _default() {
return {};
}
},
tag: {
type: String,
default: 'DIV'
},
// name for the target
to: {
type: String,
default: function _default() {
return String(Math.round(Math.random() * 10000000));
}
},
// Target
multiple: {
type: Boolean,
default: false
},
targetSlim: {
type: Boolean
},
targetSlotProps: {
type: Object,
default: function _default() {
return {};
}
},
targetTag: {
type: String,
default: 'div'
},
transition: {
type: [String, Object, Function]
}
},
created: function created() {
if (typeof document === 'undefined') return;
var el = document.querySelector(this.mountTo);
if (!el) {
console.error("[portal-vue]: Mount Point '".concat(this.mountTo, "' not found in document"));
return;
}
var props = this.$props; // Target already exists
if (wormhole.targets[props.name]) {
if (props.bail) {
console.warn("[portal-vue]: Target ".concat(props.name, " is already mounted.\n Aborting because 'bail: true' is set"));
} else {
this.portalTarget = wormhole.targets[props.name];
}
return;
}
var append = props.append;
if (append) {
var type = typeof append === 'string' ? append : 'DIV';
var mountEl = document.createElement(type);
el.appendChild(mountEl);
el = mountEl;
} // get props for target from $props
// we have to rename a few of them
var _props = pick$1(this.$props, targetProps);
_props.slim = this.targetSlim;
_props.tag = this.targetTag;
_props.slotProps = this.targetSlotProps;
_props.name = this.to;
this.portalTarget = new PortalTarget({
el: el,
parent: this.$parent || this,
propsData: _props
});
},
beforeDestroy: function beforeDestroy() {
var target = this.portalTarget;
if (this.append) {
var el = target.$el;
el.parentNode.removeChild(el);
}
target.$destroy();
},
render: function render(h) {
if (!this.portalTarget) {
console.warn("[portal-vue] Target wasn't mounted");
return h();
} // if there's no "manual" scoped slot, so we create a <Portal> ourselves
if (!this.$scopedSlots.manual) {
var props = pick$1(this.$props, portalProps);
return h(Portal, {
props: props,
attrs: this.$attrs,
on: this.$listeners,
scopedSlots: this.$scopedSlots
}, this.$slots.default);
} // else, we render the scoped slot
var content = this.$scopedSlots.manual({
to: this.to
}); // if user used <template> for the scoped slot
// content will be an array
if (Array.isArray(content)) {
content = content[0];
}
if (!content) return h();
return content;
}
});
var props$1a = makePropsConfigurable({
name: {
type: String,
required: true
},
ariaLive: {
type: String,
default: undefined
},
// Allowed: 'true' or 'false' or null
ariaAtomic: {
type: String // default: undefined
},
role: {
// Aria role
type: String // default: undefined
}
}, NAME_TOASTER); // @vue/component
var DefaultTransition = /*#__PURE__*/Vue__default['default'].extend({
data: function data() {
return {
// Transition classes base name
name: 'b-toaster'
};
},
methods: {
onAfterEnter: function onAfterEnter(el) {
var _this = this;
// Work around a Vue.js bug where `*-enter-to` class is not removed
// See: https://github.com/vuejs/vue/pull/7901
// The `*-move` class is also stuck on elements that moved,
// but there are no JavaScript hooks to handle after move
// See: https://github.com/vuejs/vue/pull/7906
requestAF(function () {
removeClass(el, "".concat(_this.name, "-enter-to"));
});
}
},
render: function render(h) {
return h('transition-group', {
props: {
tag: 'div',
name: this.name
},
on: {
afterEnter: this.onAfterEnter
}
}, this.$slots.default);
}
}); // @vue/component
var BToaster = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_TOASTER,
props: props$1a,
data: function data() {
return {
// We don't render on SSR or if a an existing target found
doRender: false,
dead: false,
// Toaster names cannot change once created
staticName: this.name
};
},
beforeMount: function beforeMount() {
var _this2 = this;
this.staticName = this.name;
/* istanbul ignore if */
if (wormhole.hasTarget(this.staticName)) {
warn("A \"<portal-target>\" with name \"".concat(this.name, "\" already exists in the document."), NAME_TOASTER);
this.dead = true;
} else {
this.doRender = true;
this.$once('hook:beforeDestroy', function () {
// Let toasts made with `this.$bvToast.toast()` know that this toaster
// is being destroyed and should should also destroy/hide themselves
_this2.$root.$emit('bv::toaster::destroyed', _this2.staticName);
});
}
},
destroyed: function destroyed() {
// Remove from DOM if needed
/* istanbul ignore next: difficult to test */
if (this.$el && this.$el.parentNode) {
this.$el.parentNode.removeChild(this.$el);
}
},
render: function render(h) {
var $toaster = h('div', {
class: ['d-none', {
'b-dead-toaster': this.dead
}]
});
if (this.doRender) {
var $target = h(PortalTarget, {
staticClass: 'b-toaster-slot',
props: {
name: this.staticName,
multiple: true,
tag: 'div',
slim: false,
// transition: this.transition || DefaultTransition
transition: DefaultTransition
}
});
$toaster = h('div', {
staticClass: 'b-toaster',
class: [this.staticName],
attrs: {
id: this.staticName,
role: this.role || null,
// Fallback to null to make sure attribute doesn't exist
'aria-live': this.ariaLive,
'aria-atomic': this.ariaAtomic
}
}, [$target]);
}
return $toaster;
}
});
var MIN_DURATION = 1000; // --- Props ---
var linkProps$5 = pick(props$1, ['href', 'to']);
var props$1b = makePropsConfigurable(_objectSpread2({
id: {
// Even though the ID prop is provided by idMixin, we
// add it here for $bvToast props filtering
type: String // default: null
},
title: {
type: String // default: null
},
toaster: {
type: String,
default: 'b-toaster-top-right'
},
visible: {
type: Boolean,
default: false
},
variant: {
type: String // default: null
},
isStatus: {
// Switches role to 'status' and aria-live to 'polite'
type: Boolean,
default: false
},
appendToast: {
type: Boolean,
default: false
},
noAutoHide: {
type: Boolean,
default: false
},
autoHideDelay: {
type: [Number, String],
default: 5000
},
noCloseButton: {
type: Boolean,
default: false
},
noFade: {
type: Boolean,
default: false
},
noHoverPause: {
type: Boolean,
default: false
},
solid: {
type: Boolean,
default: false
},
toastClass: {
type: [String, Object, Array] // default: undefined
},
headerClass: {
type: [String, Object, Array] // default: undefined
},
bodyClass: {
type: [String, Object, Array] // default: undefined
},
static: {
// Render the toast in place, rather than in a portal-target
type: Boolean,
default: false
}
}, linkProps$5), NAME_TOAST); // @vue/component
var BToast = /*#__PURE__*/Vue__default['default'].extend({
name: NAME_TOAST,
mixins: [attrsMixin, idMixin, listenOnRootMixin, normalizeSlotMixin, scopedStyleAttrsMixin],
inheritAttrs: false,
model: {
prop: 'visible',
event: 'change'
},
props: props$1b,
data: function data() {
return {
isMounted: false,
doRender: false,
localShow: false,
isTransitioning: false,
isHiding: false,
order: 0,
dismissStarted: 0,
resumeDismiss: 0
};
},
computed: {
bToastClasses: function bToastClasses() {
return _defineProperty({
'b-toast-solid': this.solid,
'b-toast-append': this.appendToast,
'b-toast-prepend': !this.appendToast
}, "b-toast-".concat(this.variant), this.variant);
},
slotScope: function slotScope() {
return {
hide: this.hide
};
},
computedDuration: function computedDuration() {
// Minimum supported duration is 1 second
return mathMax(toInteger(this.autoHideDelay, 0), MIN_DURATION);
},
computedToaster: function computedToaster() {
return String(this.toaster);
},
transitionHandlers: function transitionHandlers() {
return {
beforeEnter: this.onBeforeEnter,
afterEnter: this.onAfterEnter,
beforeLeave: this.onBeforeLeave,
afterLeave: this.onAfterLeave
};
},
computedAttrs: function computedAttrs() {
return _objectSpread2(_objectSpread2({}, this.bvAttrs), {}, {
id: this.safeId(),
tabindex: '0'
});
}
},
watch: {
visible: function visible(newVal) {
newVal ? this.show() : this.hide();
},
localShow: function localShow(newVal) {
if (newVal !== this.visible) {
this.$emit('change', newVal);
}
},
/* istanbul ignore next */
toaster: function toaster() {
// If toaster target changed, make sure toaster exists
this.$nextTick(this.ensureToaster);
},
/* istanbul ignore next */
static: function _static(newVal) {
// If static changes to true, and the toast is showing,
// ensure the toaster target exists
if (newVal && this.localShow) {
this.ensureToaster();
}
}
},
created: function created() {
// Create private non-reactive props
this.$_dismissTimer = null;
},
mounted: function mounted() {
var _this = this;
this.isMounted = true;
this.$nextTick(function () {
if (_this.visible) {
requestAF(function () {
_this.show();
});
}
}); // Listen for global $root show events
this.listenOnRoot('bv::show::toast', function (id) {
if (id === _this.safeId()) {
_this.show();
}
}); // Listen for global $root hide events
this.listenOnRoot('bv::hide::toast', function (id) {
if (!id || id === _this.safeId()) {
_this.hide();
}
}); // Make sure we hide when toaster is destroyed
/* istanbul ignore next: difficult to test */
this.listenOnRoot('bv::toaster::destroyed', function (toaster) {
/* istanbul ignore next */
if (toaster === _this.computedToaster) {
/* istanbul ignore next */
_this.hide();
}
});
},
beforeDestroy: function beforeDestroy() {
this.clearDismissTimer();
},
methods: {
show: function show() {
var _this2 = this;
if (!this.localShow) {
this.ensureToaster();
var showEvt = this.buildEvent('show');
this.emitEvent(showEvt);
this.dismissStarted = this.resumeDismiss = 0;
this.order = Date.now() * (this.appendToast ? 1 : -1);
this.isHiding = false;
this.doRender = true;
this.$nextTick(function () {
// We show the toast after we have rendered the portal and b-toast wrapper
// so that screen readers will properly announce the toast
requestAF(function () {
_this2.localShow = true;
});
});
}
},
hide: function hide() {
var _this3 = this;
if (this.localShow) {
var hideEvt = this.buildEvent('hide');
this.emitEvent(hideEvt);
this.setHoverHandler(false);
this.dismissStarted = this.resumeDismiss = 0;
this.clearDismissTimer();
this.isHiding = true;
requestAF(function () {
_this3.localShow = false;
});
}
},
buildEvent: function buildEvent(type) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return new BvEvent(type, _objectSpread2(_objectSpread2({
cancelable: false,
target: this.$el || null,
relatedTarget: null
}, options), {}, {
vueTarget: this,
componentId: this.safeId()
}));
},
emitEvent: function emitEvent(bvEvt) {
var type = bvEvt.type;
this.emitOnRoot("bv::toast:".concat(type), bvEvt);
this.$emit(type, bvEvt);
},
ensureToaster: function ensureToaster() {
if (this.static) {
return;
}
if (!wormhole.hasTarget(this.computedToaster)) {
var div = document.createElement('div');
document.body.appendChild(div);
var toaster = new BToaster({
parent: this.$root,
propsData: {
name: this.computedToaster
}
});
toaster.$mount(div);
}
},
startDismissTimer: function startDismissTimer() {
this.clearDismissTimer();
if (!this.noAutoHide) {
this.$_dismissTimer = setTimeout(this.hide, this.resumeDismiss || this.computedDuration);
this.dismissStarted = Date.now();
this.resumeDismiss = 0;
}
},
clearDismissTimer: function clearDismissTimer() {
clearTimeout(this.$_dismissTimer);
this.$_dismissTimer = null;
},
setHoverHandler: function setHoverHandler(on) {
var el = this.$refs['b-toast'];
eventOnOff(on, el, 'mouseenter', this.onPause, EVENT_OPTIONS_NO_CAPTURE);
eventOnOff(on, el, 'mouseleave', this.onUnPause, EVENT_OPTIONS_NO_CAPTURE);
},
onPause: function onPause() {
// Determine time remaining, and then pause timer
if (this.noAutoHide || this.noHoverPause || !this.$_dismissTimer || this.resumeDismiss) {
return;
}
var passed = Date.now() - this.dismissStarted;
if (passed > 0) {
this.clearDismissTimer();
this.resumeDismiss = mathMax(this.computedDuration - passed, MIN_DURATION);
}
},
onUnPause: function onUnPause() {
// Restart timer with max of time remaining or 1 second
if (this.noAutoHide || this.noHoverPause || !this.resumeDismiss) {
this.resumeDismiss = this.dismissStarted = 0;
return;
}
this.startDismissTimer();
},
onLinkClick: function onLinkClick() {
var _this4 = this;
// We delay the close to allow time for the
// browser to process the link click
this.$nextTick(function () {
requestAF(function () {
_this4.hide();
});
});
},
onBeforeEnter: function onBeforeEnter() {
this.isTransitioning = true;
},
onAfterEnter: function onAfterEnter() {
this.isTransitioning = false;
var hiddenEvt = this.buildEvent('shown');
this.emitEvent(hiddenEvt);
this.startDismissTimer();
this.setHoverHandler(true);
},
onBeforeLeave: function onBeforeLeave() {
this.isTransitioning = true;
},
onAfterLeave: function onAfterLeave() {
this.isTransitioning = false;
this.order = 0;
this.resumeDismiss = this.dismissStarted = 0;
var hiddenEvt = this.buildEvent('hidden');
this.emitEvent(hiddenEvt);
this.doRender = false;
},
makeToast: function makeToast(h) {
var _this5 = this;
// Render helper for generating the toast
// Assemble the header content
var $headerContent = [];
var $title = this.normalizeSlot('toast-title', this.slotScope);
if ($title) {
$headerContent.push($title);
} else if (this.title) {
$headerContent.push(h('strong', {
staticClass: 'mr-2'
}, this.title));
}
if (!this.noCloseButton) {
$headerContent.push(h(BButtonClose, {
staticClass: 'ml-auto mb-1',
on: {
click: function click() {
_this5.hide();
}
}
}));
} // Assemble the header (if needed)
var $header = h();
if ($headerContent.length > 0) {
$header = h('header', {
staticClass: 'toast-header',
class: this.headerClass
}, $headerContent);
} // Toast body
var link = isLink(this);
var $body = h(link ? BLink : 'div', {
staticClass: 'toast-body',
class: this.bodyClass,
props: link ? pluckProps(linkProps$5, this) : {},
on: link ? {
click: this.onLinkClick
} : {}
}, [this.normalizeSlot(SLOT_NAME_DEFAULT, this.slotScope) || h()]); // Build the toast
var $toast = h('div', {
key: "toast-".concat(this._uid),
ref: 'toast',
staticClass: 'toast',
class: this.toastClass,
attrs: this.computedAttrs
}, [$header, $body]);
return $toast;
}
},
render: function render(h) {
if (!this.doRender || !this.isMounted) {
return h();
}
var name = "b-toast-".concat(this._uid); // If scoped styles are applied and the toast is not static,
// make sure the scoped style data attribute is applied
var scopedStyleAttrs = !this.static ? this.scopedStyleAttrs : {};
return h(Portal, {
props: {
name: name,
to: this.computedToaster,
order: this.order,
slim: true,
disabled: this.static
}
}, [h('div', {
key: name,
ref: 'b-toast',
staticClass: 'b-toast',
class: this.bToastClasses,
attrs: _objectSpread2(_objectSpread2({}, scopedStyleAttrs), {}, {
id: this.safeId('_toast_outer'),
role: this.isHiding ? null : this.isStatus ? 'status' : 'alert',
'aria-live': this.isHiding ? null : this.isStatus ? 'polite' : 'assertive',
'aria-atomic': this.isHiding ? null : 'true'
})
}, [h(BVTransition, {
props: {
noFade: this.noFade
},
on: this.transitionHandlers
}, [this.localShow ? this.makeToast(h) : h()])])]);
}
});
var PROP_NAME$2 = '$bvToast';
var PROP_NAME_PRIV$1 = '_bv__toast'; // Base toast props that are allowed
// Some may be ignored or overridden on some message boxes
// Prop ID is allowed, but really only should be used for testing
// We need to add it in explicitly as it comes from the `idMixin`
var BASE_PROPS$1 = ['id'].concat(_toConsumableArray(keys(omit(props$1b, ['static', 'visible'])))); // Map prop names to toast slot names
var propsToSlots$1 = {
toastContent: 'default',
title: 'toast-title'
}; // --- Utility methods ---
// Method to filter only recognized props that are not undefined
var filterOptions$1 = function filterOptions(options) {
return BASE_PROPS$1.reduce(function (memo, key) {
if (!isUndefined(options[key])) {
memo[key] = options[key];
}
return memo;
}, {});
}; // Method to install `$bvToast` VM injection
var plugin$1 = function plugin(Vue) {
// Create a private sub-component constructor that
// extends BToast and self-destructs after hidden
// @vue/component
var BVToastPop = Vue.extend({
name: NAME_TOAST_POP,
extends: BToast,
destroyed: function destroyed() {
// Make sure we not in document any more
if (this.$el && this.$el.parentNode) {
this.$el.parentNode.removeChild(this.$el);
}
},
mounted: function mounted() {
var _this = this;
// Self destruct handler
var handleDestroy = function handleDestroy() {
// Ensure the toast has been force hidden
_this.localShow = false;
_this.doRender = false;
_this.$nextTick(function () {
_this.$nextTick(function () {
// In a `requestAF()` to release control back to application
// and to allow the portal-target time to remove the content
requestAF(function () {
_this.$destroy();
});
});
});
}; // Self destruct if parent destroyed
this.$parent.$once('hook:destroyed', handleDestroy); // Self destruct after hidden
this.$once('hidden', handleDestroy); // Self destruct when toaster is destroyed
this.listenOnRoot('bv::toaster::destroyed', function (toaster) {
/* istanbul ignore next: hard to test */
if (toaster === _this.toaster) {
handleDestroy();
}
});
}
}); // Private method to generate the on-demand toast
var makeToast = function makeToast(props, $parent) {
if (warnNotClient(PROP_NAME$2)) {
/* istanbul ignore next */
return;
} // Create an instance of `BVToastPop` component
var toast = new BVToastPop({
// We set parent as the local VM so these toasts can emit events on the
// app `$root`, and it ensures `BToast` is destroyed when parent is destroyed
parent: $parent,
propsData: _objectSpread2(_objectSpread2(_objectSpread2({}, filterOptions$1(getComponentConfig(NAME_TOAST))), omit(props, keys(propsToSlots$1))), {}, {
// Props that can't be overridden
static: false,
visible: true
})
}); // Convert certain props to slots
keys(propsToSlots$1).forEach(function (prop) {
var value = props[prop];
if (!isUndefined(value)) {
// Can be a string, or array of VNodes
if (prop === 'title' && isString(value)) {
// Special case for title if it is a string, we wrap in a <strong>
value = [$parent.$createElement('strong', {
class: 'mr-2'
}, value)];
}
toast.$slots[propsToSlots$1[prop]] = concat(value);
}
}); // Create a mount point (a DIV) and mount it (which triggers the show)
var div = document.createElement('div');
document.body.appendChild(div);
toast.$mount(div);
}; // Declare BvToast instance property class
var BvToast = /*#__PURE__*/function () {
function BvToast(vm) {
_classCallCheck(this, BvToast);
// Assign the new properties to this instance
assign(this, {
_vm: vm,
_root: vm.$root
}); // Set these properties as read-only and non-enumerable
defineProperties(this, {
_vm: readonlyDescriptor(),
_root: readonlyDescriptor()
});
} // --- Public Instance methods ---
// Opens a user defined toast and returns immediately
_createClass(BvToast, [{
key: "toast",
value: function toast(content) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (!content || warnNotClient(PROP_NAME$2)) {
/* istanbul ignore next */
return;
}
makeToast(_objectSpread2(_objectSpread2({}, filterOptions$1(options)), {}, {
toastContent: content
}), this._vm);
} // shows a `<b-toast>` component with the specified ID
}, {
key: "show",
value: function show(id) {
if (id) {
this._root.$emit('bv::show::toast', id);
}
} // Hide a toast with specified ID, or if not ID all toasts
}, {
key: "hide",
value: function hide() {
var id = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
this._root.$emit('bv::hide::toast', id);
}
}]);
return BvToast;
}(); // Add our instance mixin
Vue.mixin({
beforeCreate: function beforeCreate() {
// Because we need access to `$root` for `$emits`, and VM for parenting,
// we have to create a fresh instance of `BvToast` for each VM
this[PROP_NAME_PRIV$1] = new BvToast(this);
}
}); // Define our read-only `$bvToast` instance property
// Placed in an if just in case in HMR mode
if (!hasOwnProperty(Vue.prototype, PROP_NAME$2)) {
defineProperty(Vue.prototype, PROP_NAME$2, {
get: function get() {
/* istanbul ignore next */
if (!this || !this[PROP_NAME_PRIV$1]) {
warn("\"".concat(PROP_NAME$2, "\" must be accessed from a Vue instance \"this\" context."), NAME_TOAST);
}
return this[PROP_NAME_PRIV$1];
}
});
}
};
var BVToastPlugin = /*#__PURE__*/pluginFactory({
plugins: {
plugin: plugin$1
}
});
var ToastPlugin = /*#__PURE__*/pluginFactory({
components: {
BToast: BToast,
BToaster: BToaster
},
// $bvToast injection
plugins: {
BVToastPlugin: BVToastPlugin
}
});
var BV_TOOLTIP = '__BV_Tooltip__'; // Default trigger
var DefaultTrigger$1 = 'hover focus'; // Valid event triggers
var validTriggers$1 = {
focus: true,
hover: true,
click: true,
blur: true,
manual: true
}; // Directive modifier test regular expressions. Pre-compile for performance
var htmlRE$1 = /^html$/i;
var noninteractiveRE = /^noninteractive$/i;
var noFadeRE$1 = /^nofade$/i;
var placementRE$1 = /^(auto|top(left|right)?|bottom(left|right)?|left(top|bottom)?|right(top|bottom)?)$/i;
var boundaryRE$1 = /^(window|viewport|scrollParent)$/i;
var delayRE$1 = /^d\d+$/i;
var delayShowRE$1 = /^ds\d+$/i;
var delayHideRE$1 = /^dh\d+$/i;
var offsetRE$1 = /^o-?\d+$/i;
var variantRE$1 = /^v-.+$/i;
var spacesRE$1 = /\s+/; // Build a Tooltip config based on bindings (if any)
// Arguments and modifiers take precedence over passed value config object
var parseBindings$1 = function parseBindings(bindings, vnode)
/* istanbul ignore next: not easy to test */
{
// We start out with a basic config
var config = {
title: undefined,
trigger: '',
// Default set below if needed
placement: 'top',
fallbackPlacement: 'flip',
container: false,
// Default of body
animation: true,
offset: 0,
id: null,
html: false,
interactive: true,
disabled: false,
delay: getComponentConfig(NAME_TOOLTIP, 'delay', 50),
boundary: String(getComponentConfig(NAME_TOOLTIP, 'boundary', 'scrollParent')),
boundaryPadding: toInteger(getComponentConfig(NAME_TOOLTIP, 'boundaryPadding', 5), 0),
variant: getComponentConfig(NAME_TOOLTIP, 'variant'),
customClass: getComponentConfig(NAME_TOOLTIP, 'customClass')
}; // Process `bindings.value`
if (isString(bindings.value) || isNumber(bindings.value)) {
// Value is tooltip content (HTML optionally supported)
config.title = bindings.value;
} else if (isFunction(bindings.value)) {
// Title generator function
config.title = bindings.value;
} else if (isPlainObject(bindings.value)) {
// Value is config object, so merge
config = _objectSpread2(_objectSpread2({}, config), bindings.value);
} // If title is not provided, try title attribute
if (isUndefined(config.title)) {
// Try attribute
var data = vnode.data || {};
config.title = data.attrs && !isUndefinedOrNull(data.attrs.title) ? data.attrs.title : undefined;
} // Normalize delay
if (!isPlainObject(config.delay)) {
config.delay = {
show: toInteger(config.delay, 0),
hide: toInteger(config.delay, 0)
};
} // 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 = "#".concat(bindings.arg);
} // Process modifiers
keys(bindings.modifiers).forEach(function (mod) {
if (htmlRE$1.test(mod)) {
// Title allows HTML
config.html = true;
} else if (noninteractiveRE.test(mod)) {
// Noninteractive
config.interactive = false;
} else if (noFadeRE$1.test(mod)) {
// No animation
config.animation = false;
} else if (placementRE$1.test(mod)) {
// Placement of tooltip
config.placement = mod;
} else if (boundaryRE$1.test(mod)) {
// Boundary of tooltip
mod = mod === 'scrollparent' ? 'scrollParent' : mod;
config.boundary = mod;
} else if (delayRE$1.test(mod)) {
// Delay value
var delay = toInteger(mod.slice(1), 0);
config.delay.show = delay;
config.delay.hide = delay;
} else if (delayShowRE$1.test(mod)) {
// Delay show value
config.delay.show = toInteger(mod.slice(2), 0);
} else if (delayHideRE$1.test(mod)) {
// Delay hide value
config.delay.hide = toInteger(mod.slice(2), 0);
} else if (offsetRE$1.test(mod)) {
// Offset value, negative allowed
config.offset = toInteger(mod.slice(1), 0);
} else if (variantRE$1.test(mod)) {
// Variant
config.variant = mod.slice(2) || null;
}
}); // Special handling of event trigger modifiers trigger is
// a space separated list
var selectedTriggers = {}; // Parse current config object trigger
concat(config.trigger || '').filter(identity).join(' ').trim().toLowerCase().split(spacesRE$1).forEach(function (trigger) {
if (validTriggers$1[trigger]) {
selectedTriggers[trigger] = true;
}
}); // Parse modifiers for triggers
keys(bindings.modifiers).forEach(function (mod) {
mod = mod.toLowerCase();
if (validTriggers$1[mod]) {
// If modifier is a valid trigger
selectedTriggers[mod] = 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) {
// Use default trigger
config.trigger = DefaultTrigger$1;
} // Return the config
return config;
}; // Add/update Tooltip on our element
var applyTooltip = function applyTooltip(el, bindings, vnode) {
if (!isBrowser) {
/* istanbul ignore next */
return;
}
var config = parseBindings$1(bindings, vnode);
if (!el[BV_TOOLTIP]) {
var $parent = vnode.context;
el[BV_TOOLTIP] = new BVTooltip({
parent: $parent,
// Add the parent's scoped style attribute data
_scopeId: getScopeId($parent, undefined)
});
el[BV_TOOLTIP].__bv_prev_data__ = {};
el[BV_TOOLTIP].$on('show', function ()
/* istanbul ignore next: for now */
{
// Before showing the tooltip, we update the title if it is a function
if (isFunction(config.title)) {
el[BV_TOOLTIP].updateData({
title: config.title(el)
});
}
});
}
var data = {
title: config.title,
triggers: config.trigger,
placement: config.placement,
fallbackPlacement: config.fallbackPlacement,
variant: config.variant,
customClass: config.customClass,
container: config.container,
boundary: config.boundary,
delay: config.delay,
offset: config.offset,
noFade: !config.animation,
id: config.id,
interactive: config.interactive,
disabled: config.disabled,
html: config.html
};
var oldData = el[BV_TOOLTIP].__bv_prev_data__;
el[BV_TOOLTIP].__bv_prev_data__ = data;
if (!looseEqual(data, oldData)) {
// We only update the instance if data has changed
var newData = {
target: el
};
keys(data).forEach(function (prop) {
// We only pass data properties that have changed
if (data[prop] !== oldData[prop]) {
// if title is a function, we execute it here
newData[prop] = prop === 'title' && isFunction(data[prop]) ? data[prop](el) : data[prop];
}
});
el[BV_TOOLTIP].updateData(newData);
}
}; // Remove Tooltip on our element
var removeTooltip = function removeTooltip(el) {
if (el[BV_TOOLTIP]) {
el[BV_TOOLTIP].$destroy();
el[BV_TOOLTIP] = null;
}
delete el[BV_TOOLTIP];
}; // Export our directive
var VBTooltip = {
bind: function bind(el, bindings, vnode) {
applyTooltip(el, bindings, vnode);
},
// We use `componentUpdated` here instead of `update`, as the former
// waits until the containing component and children have finished updating
componentUpdated: function componentUpdated(el, bindings, vnode) {
// Performed in a `$nextTick()` to prevent render update loops
vnode.context.$nextTick(function () {
applyTooltip(el, bindings, vnode);
});
},
unbind: function unbind(el) {
removeTooltip(el);
}
};
var VBTooltipPlugin = /*#__PURE__*/pluginFactory({
directives: {
VBTooltip: VBTooltip
}
});
var TooltipPlugin = /*#__PURE__*/pluginFactory({
components: {
BTooltip: BTooltip
},
plugins: {
VBTooltipPlugin: VBTooltipPlugin
}
});
var componentsPlugin = /*#__PURE__*/pluginFactory({
plugins: {
AlertPlugin: AlertPlugin,
AspectPlugin: AspectPlugin,
AvatarPlugin: AvatarPlugin,
BadgePlugin: BadgePlugin,
BreadcrumbPlugin: BreadcrumbPlugin,
ButtonPlugin: ButtonPlugin,
ButtonGroupPlugin: ButtonGroupPlugin,
ButtonToolbarPlugin: ButtonToolbarPlugin,
CalendarPlugin: CalendarPlugin,
CardPlugin: CardPlugin,
CarouselPlugin: CarouselPlugin,
CollapsePlugin: CollapsePlugin,
DropdownPlugin: DropdownPlugin,
EmbedPlugin: EmbedPlugin,
FormPlugin: FormPlugin,
FormCheckboxPlugin: FormCheckboxPlugin,
FormDatepickerPlugin: FormDatepickerPlugin,
FormFilePlugin: FormFilePlugin,
FormGroupPlugin: FormGroupPlugin,
FormInputPlugin: FormInputPlugin,
FormRadioPlugin: FormRadioPlugin,
FormRatingPlugin: FormRatingPlugin,
FormSelectPlugin: FormSelectPlugin,
FormSpinbuttonPlugin: FormSpinbuttonPlugin,
FormTagsPlugin: FormTagsPlugin,
FormTextareaPlugin: FormTextareaPlugin,
FormTimepickerPlugin: FormTimepickerPlugin,
ImagePlugin: ImagePlugin,
InputGroupPlugin: InputGroupPlugin,
JumbotronPlugin: JumbotronPlugin,
LayoutPlugin: LayoutPlugin,
LinkPlugin: LinkPlugin,
ListGroupPlugin: ListGroupPlugin,
MediaPlugin: MediaPlugin,
ModalPlugin: ModalPlugin,
NavPlugin: NavPlugin,
NavbarPlugin: NavbarPlugin,
OverlayPlugin: OverlayPlugin,
PaginationPlugin: PaginationPlugin,
PaginationNavPlugin: PaginationNavPlugin,
PopoverPlugin: PopoverPlugin,
ProgressPlugin: ProgressPlugin,
SidebarPlugin: SidebarPlugin,
SkeletonPlugin: SkeletonPlugin,
SpinnerPlugin: SpinnerPlugin,
TablePlugin: TablePlugin,
TabsPlugin: TabsPlugin,
TimePlugin: TimePlugin,
ToastPlugin: ToastPlugin,
TooltipPlugin: TooltipPlugin
}
});
var VBHoverPlugin = /*#__PURE__*/pluginFactory({
directives: {
VBHover: VBHover
}
});
var VBModalPlugin = /*#__PURE__*/pluginFactory({
directives: {
VBModal: VBModal
}
});
/*
* Constants / Defaults
*/
var NAME$1 = 'v-b-scrollspy';
var ACTIVATE_EVENT = 'bv::scrollspy::activate';
var CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item';
var CLASS_NAME_ACTIVE = 'active';
var SELECTOR_NAV_LIST_GROUP = '.nav, .list-group';
var SELECTOR_NAV_LINKS = '.nav-link';
var SELECTOR_NAV_ITEMS = '.nav-item';
var SELECTOR_LIST_ITEMS = '.list-group-item';
var SELECTOR_DROPDOWN = '.dropdown, .dropup';
var SELECTOR_DROPDOWN_ITEMS = '.dropdown-item';
var SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle';
var METHOD_OFFSET = 'offset';
var METHOD_POSITION = 'position';
var Default = {
element: 'body',
offset: 10,
method: 'auto',
throttle: 75
};
var DefaultType = {
element: '(string|element|component)',
offset: 'number',
method: 'string',
throttle: 'number'
}; // Transition Events
var TransitionEndEvents$1 = ['webkitTransitionEnd', 'transitionend', 'otransitionend', 'oTransitionEnd'];
/*
* Utility Methods
*/
// Better var type detection
var toType$1 = function toType(obj)
/* istanbul ignore next: not easy to test */
{
return toString(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
}; // Check config properties for expected types
/* istanbul ignore next */
var typeCheckConfig = function typeCheckConfig(componentName, config, configTypes)
/* istanbul ignore next: not easy to test */
{
for (var property in configTypes) {
if (hasOwnProperty(configTypes, property)) {
var expectedTypes = configTypes[property];
var value = config[property];
var valueType = value && isElement(value) ? 'element' : toType$1(value); // handle Vue instances
valueType = value && value._isVue ? 'component' : valueType;
if (!new RegExp(expectedTypes).test(valueType)) {
/* istanbul ignore next */
warn("".concat(componentName, ": Option \"").concat(property, "\" provided type \"").concat(valueType, "\" but expected type \"").concat(expectedTypes, "\""));
}
}
}
};
/*
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
/* istanbul ignore next: not easy to test */
var ScrollSpy
/* istanbul ignore next: not easy to test */
= /*#__PURE__*/function () {
function ScrollSpy(element, config, $root) {
_classCallCheck(this, ScrollSpy);
// The element we activate links in
this.$el = element;
this.$scroller = null;
this.$selector = [SELECTOR_NAV_LINKS, SELECTOR_LIST_ITEMS, SELECTOR_DROPDOWN_ITEMS].join(',');
this.$offsets = [];
this.$targets = [];
this.$activeTarget = null;
this.$scrollHeight = 0;
this.$resizeTimeout = null;
this.$scrollerObserver = null;
this.$targetsObserver = 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 = _objectSpread2(_objectSpread2({}, 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, EVENT_OPTIONS_NO_CAPTURE);
}
eventOn(window, 'scroll', this, EVENT_OPTIONS_NO_CAPTURE);
eventOn(window, 'resize', this, EVENT_OPTIONS_NO_CAPTURE);
eventOn(window, 'orientationchange', this, EVENT_OPTIONS_NO_CAPTURE);
TransitionEndEvents$1.forEach(function (evtName) {
eventOn(window, evtName, _this, EVENT_OPTIONS_NO_CAPTURE);
});
this.setObservers(true); // Schedule 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, EVENT_OPTIONS_NO_CAPTURE);
}
eventOff(window, 'scroll', this, EVENT_OPTIONS_NO_CAPTURE);
eventOff(window, 'resize', this, EVENT_OPTIONS_NO_CAPTURE);
eventOff(window, 'orientationchange', this, EVENT_OPTIONS_NO_CAPTURE);
TransitionEndEvents$1.forEach(function (evtName) {
eventOff(window, evtName, _this2, EVENT_OPTIONS_NO_CAPTURE);
});
}
}, {
key: "setObservers",
value: function setObservers(on) {
var _this3 = this;
// We observe both the scroller for content changes, and the target links
this.$scrollerObserver && this.$scrollerObserver.disconnect();
this.$targetsObserver && this.$targetsObserver.disconnect();
this.$scrollerObserver = null;
this.$targetsObserver = null;
if (on) {
this.$targetsObserver = observeDom(this.$el, function () {
_this3.handleEvent('mutation');
}, {
subtree: true,
childList: true,
attributes: true,
attributeFilter: ['href']
});
this.$scrollerObserver = 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 = isString(evt) ? evt : evt.type;
var self = this;
var resizeThrottle = function resizeThrottle() {
if (!self.$resizeTimeout) {
self.$resizeTimeout = setTimeout(function () {
self.refresh();
self.process();
self.$resizeTimeout = null;
}, self.$config.throttle);
}
};
if (type === 'scroll') {
if (!this.$scrollerObserver) {
// 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 ? METHOD_POSITION : METHOD_OFFSET;
var method = this.$config.method === 'auto' ? autoMethod : this.$config.method;
var methodFn = method === METHOD_POSITION ? position : offset;
var offsetBase = method === METHOD_POSITION ? this.getScrollTop() : 0;
this.$offsets = [];
this.$targets = [];
this.$scrollHeight = this.getScrollHeight(); // Find all the unique link HREFs that we will control
selectAll(this.$selector, this.$el) // Get HREF value
.map(function (link) {
return getAttr(link, 'href');
}) // Filter out HREFs that do not match our RegExp
.filter(function (href) {
return href && RX_HREF.test(href || '');
}) // Find all elements with ID that match HREF hash
.map(function (href) {
// Convert HREF into an ID (including # at beginning)
var id = href.replace(RX_HREF, '$1').trim();
if (!id) {
return null;
} // Find the element with the ID specified by id
var el = select(id, scroller);
if (el && isVisible(el)) {
return {
offset: toInteger(methodFn(el).top, 0) + offsetBase,
target: id
};
}
return null;
}).filter(Boolean) // Sort them by their offsets (smallest first)
.sort(function (a, b) {
return a.offset - b.offset;
}) // record only unique targets/offsets
.reduce(function (memo, item) {
if (!memo[item.target]) {
_this4.$offsets.push(item.offset);
_this4.$targets.push(item.target);
memo[item.target] = true;
}
return memo;
}, {}); // Return this for easy chaining
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] && (isUndefined(this.$offsets[i + 1]) || 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 (isString(scroller)) {
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 || mathMax(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 out the base selectors
.split(',') // Map to a selector that matches links with HREF ending in the ID (including '#')
.map(function (selector) {
return "".concat(selector, "[href$=\"").concat(target, "\"]");
}) // Join back into a single selector string
.join(','), this.$el);
links.forEach(function (link) {
if (hasClass(link, CLASS_NAME_DROPDOWN_ITEM)) {
// This is a dropdown item, so find the .dropdown-toggle and set its state
var dropdown = closest(SELECTOR_DROPDOWN, link);
if (dropdown) {
_this5.setActiveState(select(SELECTOR_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_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_NAV_LIST_GROUP, el);
var sibling = el ? el.previousElementSibling : null;
if (sibling && matches(sibling, "".concat(SELECTOR_NAV_LINKS, ", ").concat(SELECTOR_LIST_ITEMS))) {
_this5.setActiveState(sibling, true);
} // Handle special case where nav-link is inside a nav-item
if (sibling && matches(sibling, SELECTOR_NAV_ITEMS)) {
_this5.setActiveState(select(SELECTOR_NAV_LINKS, sibling), true); // Add active state to nav-item as well
_this5.setActiveState(sibling, true);
}
}
}
}); // Signal event to via $root, passing ID of activated 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("".concat(this.$selector, ", ").concat(SELECTOR_NAV_ITEMS), this.$el).filter(function (el) {
return hasClass(el, CLASS_NAME_ACTIVE);
}).forEach(function (el) {
return _this6.setActiveState(el, false);
});
}
}, {
key: "setActiveState",
value: function setActiveState(el, active) {
if (!el) {
return;
}
if (active) {
addClass(el, CLASS_NAME_ACTIVE);
} else {
removeClass(el, CLASS_NAME_ACTIVE);
}
}
}], [{
key: "Name",
get: function get() {
return NAME$1;
}
}, {
key: "Default",
get: function get() {
return Default;
}
}, {
key: "DefaultType",
get: function get() {
return DefaultType;
}
}]);
return ScrollSpy;
}();
var BV_SCROLLSPY = '__BV_ScrollSpy__'; // Pre-compiled regular expressions
var onlyDigitsRE = /^\d+$/;
var offsetRE$2 = /^(auto|position|offset)$/; // Build a ScrollSpy config based on bindings (if any)
// Arguments and modifiers take precedence over passed value config object
/* istanbul ignore next: not easy to test */
var parseBindings$2 = function parseBindings(bindings)
/* istanbul ignore next: not easy to test */
{
var config = {}; // If argument, assume element ID
if (bindings.arg) {
// Element ID specified as arg
// We must prepend '#' to become a CSS selector
config.element = "#".concat(bindings.arg);
} // Process modifiers
keys(bindings.modifiers).forEach(function (mod) {
if (onlyDigitsRE.test(mod)) {
// Offset value
config.offset = toInteger(mod, 0);
} else if (offsetRE$2.test(mod)) {
// Offset method
config.method = mod;
}
}); // Process value
if (isString(bindings.value)) {
// Value is a CSS ID or selector
config.element = bindings.value;
} else if (isNumber(bindings.value)) {
// Value is offset
config.offset = mathRound(bindings.value);
} else if (isObject(bindings.value)) {
// Value is config object
// Filter the object based on our supported config options
keys(bindings.value).filter(function (k) {
return !!ScrollSpy.DefaultType[k];
}).forEach(function (k) {
config[k] = bindings.value[k];
});
}
return config;
}; // Add or update ScrollSpy on our element
var applyScrollspy = function applyScrollspy(el, bindings, vnode)
/* istanbul ignore next: not easy to test */
{
if (!isBrowser) {
/* istanbul ignore next */
return;
}
var config = parseBindings$2(bindings);
if (el[BV_SCROLLSPY]) {
el[BV_SCROLLSPY].updateConfig(config, vnode.context.$root);
} else {
el[BV_SCROLLSPY] = new ScrollSpy(el, config, vnode.context.$root);
}
}; // Remove ScrollSpy on our element
/* istanbul ignore next: not easy to test */
var removeScrollspy = function removeScrollspy(el)
/* istanbul ignore next: not easy to test */
{
if (el[BV_SCROLLSPY]) {
el[BV_SCROLLSPY].dispose();
el[BV_SCROLLSPY] = null;
delete el[BV_SCROLLSPY];
}
};
/*
* Export our directive
*/
var VBScrollspy = {
/* istanbul ignore next: not easy to test */
bind: function bind(el, bindings, vnode) {
applyScrollspy(el, bindings, vnode);
},
/* istanbul ignore next: not easy to test */
inserted: function inserted(el, bindings, vnode) {
applyScrollspy(el, bindings, vnode);
},
/* istanbul ignore next: not easy to test */
update: function update(el, bindings, vnode) {
if (bindings.value !== bindings.oldValue) {
applyScrollspy(el, bindings, vnode);
}
},
/* istanbul ignore next: not easy to test */
componentUpdated: function componentUpdated(el, bindings, vnode) {
if (bindings.value !== bindings.oldValue) {
applyScrollspy(el, bindings, vnode);
}
},
/* istanbul ignore next: not easy to test */
unbind: function unbind(el) {
removeScrollspy(el);
}
};
var VBScrollspyPlugin = /*#__PURE__*/pluginFactory({
directives: {
VBScrollspy: VBScrollspy
}
});
var VBVisiblePlugin = /*#__PURE__*/pluginFactory({
directives: {
VBVisible: VBVisible
}
});
var directivesPlugin = /*#__PURE__*/pluginFactory({
plugins: {
VBHoverPlugin: VBHoverPlugin,
VBModalPlugin: VBModalPlugin,
VBPopoverPlugin: VBPopoverPlugin,
VBScrollspyPlugin: VBScrollspyPlugin,
VBTogglePlugin: VBTogglePlugin,
VBTooltipPlugin: VBTooltipPlugin,
VBVisiblePlugin: VBVisiblePlugin
}
});
var NAME$2 = 'BootstrapVue'; // --- BootstrapVue installer ---
var install = /*#__PURE__*/installFactory({
plugins: {
componentsPlugin: componentsPlugin,
directivesPlugin: directivesPlugin
}
}); // --- BootstrapVue plugin ---
var BootstrapVue = /*#__PURE__*/{
install: install,
NAME: NAME$2
}; // --- Named exports for BvConfigPlugin ---
// Main entry point for the browser build
vueUse(BootstrapVue);
return BootstrapVue;
})));
//# sourceMappingURL=bootstrap-vue.js.map