%PDF- %PDF-
Direktori : /home/ugotscom/.trash/karetakers/node_modules/bootstrap-vue/dist/ |
Current File : /home/ugotscom/.trash/karetakers/node_modules/bootstrap-vue/dist/bootstrap-vue.js |
/*! * 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: '×' }, 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" // ' ' ); $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 (' ') $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 (' ') $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: '×' }, 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