From 1023576b3449c5a8e12d7cf36d5b814ef0cf9050 Mon Sep 17 00:00:00 2001 From: PMKuipers Date: Wed, 17 May 2023 21:19:14 +0200 Subject: [PATCH] Loading recovered files from server crash --- .gitignore | 3 + LICENSE | 4 + README.md | 2 + amd/src/bootstrap-vue.js | 33153 ++++++++++++++++ amd/src/cfg-grades.js | 69 + amd/src/debounce.js | 29 + amd/src/debugger.js | 51 + amd/src/downloader.js | 71 + amd/src/leaderline.js | 6 + amd/src/modedit-modal.js | 110 + amd/src/page-edit-plan.js | 264 + amd/src/page-invitemanager.js | 51 + amd/src/page-myreport.js | 103 + amd/src/page-view-plan.js | 216 + amd/src/portal-vue.js | 628 + amd/src/reflect-metadata.js | 1134 + amd/src/report-viewer-components.js | 1336 + amd/src/string-helper.js | 56 + amd/src/studyplan-editor-components.js | 2597 ++ amd/src/studyplan-processor.js | 142 + amd/src/treestudyplan-components.js | 107 + amd/src/vue-class-component.js | 268 + amd/src/vue-easy-dnd.js | 1578 + amd/src/vue-hsluv-picker.js | 84 + amd/src/vue-property-decorator.js | 282 + amd/src/vue.js | 11967 ++++++ cfg_grades.php | 232 + classes/aggregator.php | 120 + classes/associationservice.php | 408 + classes/badgeinfo.php | 107 + classes/completion.php | 56 + classes/contextinfo.php | 49 + classes/corecompletioninfo.php | 560 + classes/courseinfo.php | 274 + classes/coursemoduleinfo.php | 36 + classes/courseservice.php | 279 + classes/debug.php | 30 + classes/gradeinfo.php | 394 + classes/gradingscanner.php | 100 + .../local/aggregators/bistate_aggregator.php | 294 + classes/local/aggregators/core_aggregator.php | 245 + .../local/aggregators/tristate_aggregator.php | 156 + classes/local/gradegenerator.php | 280 + classes/local/helpers/webservicehelper.php | 90 + .../local/ungradedscanners/assign_scanner.php | 66 + .../local/ungradedscanners/quiz_scanner.php | 67 + .../local/ungradedscanners/scanner_base.php | 19 + classes/reportinvite_form.php | 91 + classes/studentstudyplanservice.php | 274 + classes/studyitem.php | 516 + classes/studyitemconnection.php | 110 + classes/studyline.php | 369 + classes/studyplan.php | 718 + classes/studyplanservice.php | 1167 + classes/success.php | 45 + classes/task/deepcopy.php | 137 + cli/prime_students.php | 78 + cli/randomize_grades.php | 167 + css/bootstrap-vue.min.css | 4 + css/devstyles.css | 955 + css/vue-hsluv-picker.css | 91 + db/access.php | 51 + db/install.xml | 139 + db/itemsetup.txt | 18 + db/services.php | 517 + db/upgrade.php | 189 + edit-invite.php | 164 + edit-plan.php | 190 + invitations.php | 103 + invited.php | 66 + lang/en/local_treestudyplan.php | 246 + lang/nl/local_treestudyplan.php | 249 + lib.php | 280 + myreport-embed.php | 46 + myreport.php | 57 + reports.php | 168 + settings.php | 145 + styles.css | 73 + test/bistate_aggregator_test.php | 182 + version.php | 8 + view-plan.php | 134 + 81 files changed, 65920 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 amd/src/bootstrap-vue.js create mode 100644 amd/src/cfg-grades.js create mode 100644 amd/src/debounce.js create mode 100644 amd/src/debugger.js create mode 100644 amd/src/downloader.js create mode 100644 amd/src/leaderline.js create mode 100644 amd/src/modedit-modal.js create mode 100644 amd/src/page-edit-plan.js create mode 100644 amd/src/page-invitemanager.js create mode 100644 amd/src/page-myreport.js create mode 100644 amd/src/page-view-plan.js create mode 100644 amd/src/portal-vue.js create mode 100644 amd/src/reflect-metadata.js create mode 100644 amd/src/report-viewer-components.js create mode 100644 amd/src/string-helper.js create mode 100644 amd/src/studyplan-editor-components.js create mode 100644 amd/src/studyplan-processor.js create mode 100644 amd/src/treestudyplan-components.js create mode 100644 amd/src/vue-class-component.js create mode 100644 amd/src/vue-easy-dnd.js create mode 100644 amd/src/vue-hsluv-picker.js create mode 100644 amd/src/vue-property-decorator.js create mode 100644 amd/src/vue.js create mode 100644 cfg_grades.php create mode 100644 classes/aggregator.php create mode 100644 classes/associationservice.php create mode 100644 classes/badgeinfo.php create mode 100644 classes/completion.php create mode 100644 classes/contextinfo.php create mode 100644 classes/corecompletioninfo.php create mode 100644 classes/courseinfo.php create mode 100644 classes/coursemoduleinfo.php create mode 100644 classes/courseservice.php create mode 100644 classes/debug.php create mode 100644 classes/gradeinfo.php create mode 100644 classes/gradingscanner.php create mode 100644 classes/local/aggregators/bistate_aggregator.php create mode 100644 classes/local/aggregators/core_aggregator.php create mode 100644 classes/local/aggregators/tristate_aggregator.php create mode 100644 classes/local/gradegenerator.php create mode 100644 classes/local/helpers/webservicehelper.php create mode 100644 classes/local/ungradedscanners/assign_scanner.php create mode 100644 classes/local/ungradedscanners/quiz_scanner.php create mode 100644 classes/local/ungradedscanners/scanner_base.php create mode 100644 classes/reportinvite_form.php create mode 100644 classes/studentstudyplanservice.php create mode 100644 classes/studyitem.php create mode 100644 classes/studyitemconnection.php create mode 100644 classes/studyline.php create mode 100644 classes/studyplan.php create mode 100644 classes/studyplanservice.php create mode 100644 classes/success.php create mode 100644 classes/task/deepcopy.php create mode 100644 cli/prime_students.php create mode 100644 cli/randomize_grades.php create mode 100644 css/bootstrap-vue.min.css create mode 100644 css/devstyles.css create mode 100644 css/vue-hsluv-picker.css create mode 100644 db/access.php create mode 100644 db/install.xml create mode 100644 db/itemsetup.txt create mode 100644 db/services.php create mode 100644 db/upgrade.php create mode 100644 edit-invite.php create mode 100644 edit-plan.php create mode 100644 invitations.php create mode 100644 invited.php create mode 100644 lang/en/local_treestudyplan.php create mode 100644 lang/nl/local_treestudyplan.php create mode 100644 lib.php create mode 100644 myreport-embed.php create mode 100644 myreport.php create mode 100644 reports.php create mode 100644 settings.php create mode 100644 styles.css create mode 100644 test/bistate_aggregator_test.php create mode 100644 version.php create mode 100644 view-plan.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7c6e0dc --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/.vs +/node_modules +/amd/build diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c17f2e0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,4 @@ +Copyright (C) 2022 Peter-Martijn Kuipers +This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 , USA. Also add information on how to contact you by electronic and paper mail. diff --git a/README.md b/README.md new file mode 100644 index 0000000..a08838d --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# moodle-local_treestudyplan + diff --git a/amd/src/bootstrap-vue.js b/amd/src/bootstrap-vue.js new file mode 100644 index 0000000..bff609a --- /dev/null +++ b/amd/src/bootstrap-vue.js @@ -0,0 +1,33153 @@ +/* eslint-disable */ +/*! + * BootstrapVue 2.16.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'; + + Vue = Vue && Object.prototype.hasOwnProperty.call(Vue, 'default') ? Vue['default'] : 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."); + } + + // --- Static --- + var from = function from() { + return Array.from.apply(Array, arguments); + }; + var isArray = function isArray(val) { + return Array.isArray(val); + }; // --- 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); + }; + + 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 freeze = function freeze(obj) { + return Object.freeze(obj); + }; + 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 --- + + /** + * 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]'; + }; + /** + * 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])); + }, {}); + }; + /** + * Convenience method to create a read-only descriptor + */ + + var readonlyDescriptor = function readonlyDescriptor() { + return { + enumerable: true, + configurable: false, + writable: false + }; + }; + /** + * Deep-freezes and object, making it immutable / read-only. + * Returns the same object passed-in, but frozen. + * Freezes inner object/array/values first. + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze + * Note: this method will not work for property values using Symbol() as a key + */ + + var deepFreeze = function deepFreeze(obj) { + // Retrieve the property names defined on object/array + // Note: `keys` will ignore properties that are keyed by a `Symbol()` + var props = keys(obj); // Iterate over each prop and recursively freeze it + + props.forEach(function (prop) { + var value = obj[prop]; // If value is a plain object or array, we deepFreeze it + + obj[prop] = value && (isPlainObject(value) || isArray(value)) ? deepFreeze(value) : value; + }); + return freeze(obj); + }; + + /** + * 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'); + }; + + 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'; + }; + 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); + }; // Extra convenience named re-exports + + 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; + }; + + var identity = function identity(x) { + return x; + }; + + var RX_ARRAY_NOTATION = /\[(\d+)]/g; + /** + * 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; + } + }; + + // NOTES + // + // The global config SHALL NOT be used to set defaults for Boolean props, as the props + // would loose their semantic meaning, and force people writing 3rd party components to + // explicitly set a true or false value using the v-bind syntax on boolean props + // + // Supported config values (depending on the prop's supported type(s)): + // `String`, `Array`, `Object`, `null` or `undefined` + // BREAKPOINT DEFINITIONS + // + // Some components (`` and ``) generate props based on breakpoints, + // and this occurs when the component is first loaded (evaluated), which may happen + // before the config is created/modified + // + // To get around this we make these components' props async (lazy evaluation) + // The component definition is only called/executed when the first access to the + // component is used (and cached on subsequent uses) + // PROP DEFAULTS + // + // For default values on props, we use the default value factory function approach so + // that the default values are pulled in at each component instantiation + // + // props: { + // variant: { + // type: String, + // default: () => getConfigComponent('BAlert', 'variant') + // } + // } + // + // We also provide a cached getter for breakpoints, which are "frozen" on first access + // prettier-ignore + + var DEFAULTS = deepFreeze({ + // Breakpoints + breakpoints: ['xs', 'sm', 'md', 'lg', 'xl'], + // Form controls + formControls: { + size: undefined + }, + // Component specific defaults are keyed by the component + // name (PascalCase) and prop name (camelCase) + BAlert: { + dismissLabel: 'Close', + variant: 'info' + }, + BAvatar: { + variant: 'secondary', + badgeVariant: 'primary' + }, + BBadge: { + variant: 'secondary' + }, + BButton: { + size: undefined, + variant: 'secondary' + }, + BButtonClose: { + content: '×', + // `textVariant` is `null` to inherit the current text color + textVariant: undefined, + ariaLabel: 'Close' + }, + BCalendar: { + // BFormDate will choose these first if not provided in BFormDate section + labelPrevDecade: 'Previous decade', + labelPrevYear: 'Previous year', + labelPrevMonth: 'Previous month', + labelCurrentMonth: 'Current month', + labelNextMonth: 'Next month', + labelNextYear: 'Next year', + labelNextDecade: 'Next decade', + labelToday: 'Today', + labelSelected: 'Selected date', + labelNoDateSelected: 'No date selected', + labelCalendar: 'Calendar', + labelNav: 'Calendar navigation', + labelHelp: 'Use cursor keys to navigate calendar dates' + }, + BCardSubTitle: { + // `` and `` also inherit this prop + subTitleTextVariant: 'muted' + }, + BCarousel: { + labelPrev: 'Previous Slide', + labelNext: 'Next Slide', + labelGotoSlide: 'Goto Slide', + labelIndicators: 'Select a slide to display' + }, + BDropdown: { + toggleText: 'Toggle Dropdown', + size: undefined, + variant: 'secondary', + splitVariant: undefined + }, + BFormDatepicker: { + // BFormDatepicker will choose from BCalendar first if not provided here + labelPrevDecade: undefined, + labelPrevYear: undefined, + labelPrevMonth: undefined, + labelCurrentMonth: undefined, + labelNextMonth: undefined, + labelNextYear: undefined, + labelNextDecade: undefined, + labelToday: undefined, + labelSelected: undefined, + labelNoDateSelected: undefined, + labelCalendar: undefined, + labelNav: undefined, + labelHelp: undefined, + // These props are specific to BFormDatepicker + labelTodayButton: 'Select today', + labelResetButton: 'Reset', + labelCloseButton: 'Close' + }, + BFormFile: { + browseText: 'Browse', + // Chrome default file prompt + placeholder: 'No file chosen', + dropPlaceholder: 'Drop files here' + }, + BFormRating: { + variant: null, + color: null + }, + BFormTag: { + removeLabel: 'Remove tag', + variant: 'secondary' + }, + BFormTags: { + addButtonText: 'Add', + addButtonVariant: 'outline-secondary', + duplicateTagText: 'Duplicate tag(s)', + invalidTagText: 'Invalid tag(s)', + placeholder: 'Add tag...', + tagRemoveLabel: 'Remove tag', + tagRemovedLabel: 'Tag removed', + tagVariant: 'secondary' + }, + BFormText: { + textVariant: 'muted' + }, + BFormTimepicker: { + // Fallback to BTime + labelNoTimeSelected: undefined, + labelSelected: undefined, + labelHours: undefined, + labelMinutes: undefined, + labelSeconds: undefined, + labelAmpm: undefined, + labelAm: undefined, + labelPm: undefined, + // Fallback to BTime then BFormSpinbutton + labelDecrement: undefined, + labelIncrement: undefined, + // These props are specific to BFormTimepicker + labelNowButton: 'Select now', + labelResetButton: 'Reset', + labelCloseButton: 'Close' + }, + BFormSpinbutton: { + labelDecrement: 'Decrement', + labelIncrement: 'Increment' + }, + BImg: { + blankColor: 'transparent' + }, + BImgLazy: { + blankColor: 'transparent' + }, + BInputGroup: { + size: undefined + }, + BJumbotron: { + bgVariant: undefined, + borderVariant: undefined, + textVariant: undefined + }, + BLink: { + routerComponentName: undefined + }, + BListGroupItem: { + variant: undefined + }, + BModal: { + titleTag: 'h5', + size: 'md', + headerBgVariant: undefined, + headerBorderVariant: undefined, + headerTextVariant: undefined, + headerCloseVariant: undefined, + bodyBgVariant: undefined, + bodyTextVariant: undefined, + footerBgVariant: undefined, + footerBorderVariant: undefined, + footerTextVariant: undefined, + cancelTitle: 'Cancel', + cancelVariant: 'secondary', + okTitle: 'OK', + okVariant: 'primary', + headerCloseContent: '×', + headerCloseLabel: 'Close' + }, + BNavbar: { + variant: null + }, + BNavbarToggle: { + label: 'Toggle navigation' + }, + BPagination: { + size: undefined + }, + BPaginationNav: { + size: undefined + }, + BPopover: { + boundary: 'scrollParent', + boundaryPadding: 5, + customClass: undefined, + delay: 50, + variant: undefined + }, + BProgress: { + variant: undefined + }, + BProgressBar: { + variant: undefined + }, + BSpinner: { + variant: undefined + }, + BSidebar: { + bgVariant: 'light', + textVariant: 'dark', + shadow: false, + width: undefined, + tag: 'div', + backdropVariant: 'dark' + }, + BTable: { + selectedVariant: 'active', + headVariant: undefined, + footVariant: undefined + }, + BTime: { + labelNoTimeSelected: 'No time selected', + labelSelected: 'Selected time', + labelHours: 'Hours', + labelMinutes: 'Minutes', + labelSeconds: 'Seconds', + labelAmpm: 'AM/PM', + // It would be nice to be able to get these from Intl.DateTimeFormat somehow + labelAm: 'AM', + labelPm: 'PM', + // The following inherit from BFormSpinbutton if not provided + labelIncrement: undefined, + labelDecrement: undefined + }, + BToast: { + toaster: 'b-toaster-top-right', + autoHideDelay: 5000, + variant: undefined, + toastClass: undefined, + headerClass: undefined, + bodyClass: undefined + }, + BToaster: { + ariaLive: undefined, + ariaAtomic: undefined, + role: undefined + }, + BTooltip: { + boundary: 'scrollParent', + boundaryPadding: 5, + customClass: undefined, + delay: 50, + variant: undefined + } + }); + + var NAME = 'BvConfig'; + var PROP_NAME = '$bvConfig'; // Config manager class + + var BvConfig = /*#__PURE__*/function () { + function BvConfig() { + _classCallCheck(this, BvConfig); + + // TODO: pre-populate with default config values (needs updated tests) + // this.$_config = cloneDeep(DEFAULTS) + this.$_config = {}; + this.$_cachedBreakpoints = null; + } + /* istanbul ignore next */ + + + _createClass(BvConfig, [{ + key: "getDefaults", + // Returns the defaults + + /* istanbul ignore next */ + value: function getDefaults() + /* istanbul ignore next */ + { + return this.defaults; + } // Method to merge in user config parameters + + }, { + key: "setConfig", + value: function setConfig() { + var _this = this; + + var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + if (!isPlainObject(config)) { + /* istanbul ignore next */ + return; + } + + var configKeys = getOwnPropertyNames(config); + configKeys.forEach(function (cmpName) { + /* istanbul ignore next */ + if (!hasOwnProperty(DEFAULTS, cmpName)) { + warn("Unknown config property \"".concat(cmpName, "\""), NAME); + return; + } + + var cmpConfig = config[cmpName]; + + if (cmpName === 'breakpoints') { + // Special case for breakpoints + var breakpoints = config.breakpoints; + /* istanbul ignore if */ + + if (!isArray(breakpoints) || breakpoints.length < 2 || breakpoints.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.breakpoints = cloneDeep(breakpoints); + } + } else if (isPlainObject(cmpConfig)) { + // Component prop defaults + var props = getOwnPropertyNames(cmpConfig); + props.forEach(function (prop) { + /* istanbul ignore if */ + if (!hasOwnProperty(DEFAULTS[cmpName], prop)) { + warn("Unknown config property \"".concat(cmpName, ".").concat(prop, "\""), NAME); + } else { + // TODO: If we pre-populate the config with defaults, we can skip this line + _this.$_config[cmpName] = _this.$_config[cmpName] || {}; + + if (!isUndefined(cmpConfig[prop])) { + _this.$_config[cmpName][prop] = cloneDeep(cmpConfig[prop]); + } + } + }); + } + }); + } // Clear the config. For testing purposes only + + }, { + key: "resetConfig", + value: function resetConfig() { + this.$_config = {}; + } // Returns a deep copy of the user config + + }, { + key: "getConfig", + value: function getConfig() { + return cloneDeep(this.$_config); + } + }, { + key: "getConfigValue", + value: function getConfigValue(key) { + // First we try the user config, and if key not found we fall back to default value + // NOTE: If we deep clone DEFAULTS into config, then we can skip the fallback for get + return cloneDeep(getRaw(this.$_config, key, getRaw(DEFAULTS, key))); + } + }, { + key: "defaults", + + /* istanbul ignore next */ + get: function get() + /* istanbul ignore next */ + { + return DEFAULTS; + } + }], [{ + key: "Defaults", + get: function get() + /* istanbul ignore next */ + { + return DEFAULTS; + } + }]); + + return BvConfig; + }(); // Method for applying a global config + + + var setConfig = function setConfig() { + var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var Vue$1 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Vue; + // 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$1.prototype[PROP_NAME] = Vue.prototype[PROP_NAME] = Vue$1.prototype[PROP_NAME] || Vue.prototype[PROP_NAME] || new BvConfig(); // Apply the config values + + Vue$1.prototype[PROP_NAME].setConfig(config); + }; // Method for resetting the user config. Exported for testing purposes only. + + /** + * 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$1) { + /* istanbul ignore next */ + if (!checkMultipleVueWarned && Vue !== Vue$1 && !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 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 PROP_NAME$1 = '$bvConfig'; + var VueProto = Vue.prototype; // --- Getter methods --- + + var getConfigValue = function getConfigValue(key) { + return VueProto[PROP_NAME$1] ? VueProto[PROP_NAME$1].getConfigValue(key) : cloneDeep(getRaw(DEFAULTS, key)); + }; // Method to grab a config value for a particular component + + var getComponentConfig = function getComponentConfig(cmpName) { + var key = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + // Return the particular config value for key for if specified, + // otherwise we return the full config (or an empty object if not found) + return key ? getConfigValue("".concat(cmpName, ".").concat(key)) : getConfigValue(cmpName) || {}; + }; // Convenience method for getting all breakpoint names + + var getBreakpoints = function getBreakpoints() { + return getConfigValue('breakpoints'); + }; // Private function for caching / locking-in breakpoint names + + var _getBreakpointsCached = memoize(function () { + return getBreakpoints(); + }); // Convenience method for getting all breakpoint names. + // Caches the results after first access. + + + var getBreakpointsCached = function getBreakpointsCached() { + return cloneDeep(_getBreakpointsCached()); + }; // Convenience method for getting breakpoints with + // the smallest breakpoint set as ''. + // Useful for components that create breakpoint specific props. + // Caches the results after first access. + + var getBreakpointsUpCached = memoize(function () { + var breakpoints = getBreakpointsCached(); + breakpoints[0] = ''; + return breakpoints; + }); // Convenience method for getting breakpoints with + + // 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 + + var RX_TRIM_LEFT = /^\s+/; + var RX_REGEXP_REPLACE = /[-/\\^$*+?.()|[\]{}]/g; + var RX_UN_KEBAB = /-(\w)/g; + var RX_HYPHENATE = /\B([A-Z])/g; // --- 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); + }; // 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) + /* istanbul ignore next */ + { + 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 (el.style.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, val) { + if (attr && isElement(el)) { + el.setAttribute(attr, val); + } + }; // 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; + }; // 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 e=function(){return (e=Object.assign||function(e){for(var t,r=1,s=arguments.length;r 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(names) { + // Returns true if the either a $scopedSlot or $slot exists with the specified name + // `names` can be a string name or an array of names + return hasNormalizedSlot(names, this.$scopedSlots, this.$slots); + }, + normalizeSlot: function normalizeSlot$1(names) { + var scope = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + // Returns an array of rendered VNodes if slot found. + // Returns undefined if not found. + // `names` can be a string name or an array of names + var vNodes = normalizeSlot(names, scope, this.$scopedSlots, this.$slots); + + return vNodes ? concat(vNodes) : vNodes; + } + } + }; + + var NAME$1 = 'BButtonClose'; + var props = { + content: { + type: String, + default: function _default() { + return getComponentConfig(NAME$1, 'content'); + } + }, + disabled: { + type: Boolean, + default: false + }, + ariaLabel: { + type: String, + default: function _default() { + return getComponentConfig(NAME$1, 'ariaLabel'); + } + }, + textVariant: { + type: String, + default: function _default() { + return getComponentConfig(NAME$1, 'textVariant'); + } + } + }; // @vue/component + + var BButtonClose = /*#__PURE__*/Vue.extend({ + name: NAME$1, + 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)) { + evt.stopPropagation(); + evt.preventDefault(); + } + } + } + }; // Careful not to override the default slot with innerHTML + + if (!hasNormalizedSlot('default', $scopedSlots, $slots)) { + componentData.domProps = { + innerHTML: props.content + }; + } + + return h('button', a(data, componentData), normalizeSlot('default', {}, $scopedSlots, $slots)); + } + }); + + var NAME$2 = 'BAlert'; // Convert `show` value to a number + + 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; + }; // Is a value number like (i.e. a number or a number as string) + + + var isNumericLike = function isNumericLike(value) { + return !isNaN(toInteger(value)); + }; // @vue/component + + + var BAlert = /*#__PURE__*/Vue.extend({ + name: NAME$2, + mixins: [normalizeSlotMixin], + model: { + prop: 'show', + event: 'input' + }, + props: { + variant: { + type: String, + default: function _default() { + return getComponentConfig(NAME$2, 'variant'); + } + }, + dismissible: { + type: Boolean, + default: false + }, + dismissLabel: { + type: String, + default: function _default() { + return getComponentConfig(NAME$2, 'dismissLabel'); + } + }, + show: { + type: [Boolean, Number, String], + default: false + }, + fade: { + type: Boolean, + default: false + } + }, + data: function data() { + return { + countDown: 0, + countDownTimeout: null, + // 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 (isNumericLike(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 || isNumericLike(this.show))) { + // Only emit dismissed events for dismissible or auto dismissing alerts + this.$emit('dismissed'); + } + + if (!isNumericLike(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() { + 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() { + if (this.countDownTimeout) { + 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('default')]); + $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 NAME$3 = 'BAspect'; + var CLASS_NAME = 'b-aspect'; + var RX_ASPECT = /^\d+(\.\d*)?[/:]\d+(\.\d*)?$/; + var RX_SEPARATOR = /[/:]/; // --- Main Component --- + + var BAspect = /*#__PURE__*/Vue.extend({ + name: NAME$3, + mixins: [normalizeSlotMixin], + props: { + 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' + } + }, + 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_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('default')]); + 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'; // Precompile RegExp + + var commaRE = /%2C/g; + var encodeReserveRE = /[!'()*]/g; + var plusRE = /\+/g; + var queryStartRE = /^(\?|#|&)/; // 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(encodeReserveRE, encodeReserveReplacer).replace(commaRE, ','); + }; + + 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(queryStartRE, ''); + + if (!query) { + return parsed; + } + + query.split('&').forEach(function (param) { + var parts = param.replace(plusRE, ' ').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 !isTag(tag, ANCHOR_TAG); + }; + var computeTag = function computeTag() { + var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, + to = _ref.to, + disabled = _ref.disabled, + routerComponentName = _ref.routerComponentName; + + var thisOrParent = arguments.length > 1 ? arguments[1] : undefined; + var hasRouter = thisOrParent.$router; + + if (!hasRouter || hasRouter && disabled || hasRouter && !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; + + if (target === '_blank' && isNull(rel)) { + return 'noopener'; + } + + return 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] : '/'; + + // We've already checked the $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; + } // Return `href` when explicitly provided + + + if (href) { + return href; + } // Reconstruct `href` when `to` used, but no router + + + if (to) { + // Fallback to `to` prop (if `to` is a string) + if (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; + }; + + /* + * Key Codes (events) + */ + var KEY_CODES = freeze({ + SPACE: 32, + ENTER: 13, + ESC: 27, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40, + PAGEUP: 33, + PAGEDOWN: 34, + HOME: 36, + END: 35, + TAB: 9, + SHIFT: 16, + CTRL: 17, + BACKSPACE: 8, + ALT: 18, + PAUSE: 19, + BREAK: 19, + INSERT: 45, + INS: 45, + DELETE: 46 + }); + + var makePropWatcher = function makePropWatcher(propName) { + return { + handler: function handler(newVal, oldVal) { + for (var key in oldVal) { + if (!hasOwnProperty(newVal, key)) { + this.$delete(this.$data[propName], key); + } + } + + for (var _key in newVal) { + this.$set(this.$data[propName], _key, newVal[_key]); + } + } + }; + }; + var makePropCacheMixin = function makePropCacheMixin(propName, proxyPropName) { + return { + data: function data() { + return _defineProperty({}, proxyPropName, {}); + }, + watch: _defineProperty({}, propName, makePropWatcher(proxyPropName)), + created: function created() { + this[proxyPropName] = _objectSpread2({}, this[propName]); + } + }; + }; + + var attrsMixin = makePropCacheMixin('$attrs', 'bvAttrs'); + + var listenersMixin = makePropCacheMixin('$listeners', 'bvListeners'); + + var NAME$4 = 'BLink'; // --- Props --- + // 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' + } + }; // 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 = _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 `` (i.e. `g-link` for Gridsome) + // Default is to auto choose between `` and `` + // 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: function _default() { + return getComponentConfig(NAME$4, 'routerComponentName'); + } + } + }); // --- Main component --- + // @vue/component + + var BLink = /*#__PURE__*/Vue.extend({ + name: 'BLink', + // 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 + return computeRel({ + target: this.target, + rel: this.rel + }); + }, + computedHref: function computedHref() { + // We don't pass `this` as the first arg as we need reactivity of the props + return computeHref({ + to: this.to, + href: this.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 && routerTag !== 'a' && routerTag !== 'area' ? {} : { + 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 + evt.stopPropagation(); // Kill the event loop attached to this specific `EventTarget` + // Needed to prevent `vue-router` for doing its thing + + evt.stopImmediatePropagation(); + } 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 && (this.disabled || !isRouterLink && this.computedHref === '#')) { + evt.preventDefault(); + } + }, + 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('default')); + } + }); + + var NAME$5 = 'BButton'; // --- Props --- + + var linkProps = omit(props$1, ['event', 'routerTag']); + delete linkProps.href.default; + delete linkProps.to.default; + var btnProps = { + block: { + type: Boolean, + default: false + }, + disabled: { + type: Boolean, + default: false + }, + size: { + type: String, + default: function _default() { + return getComponentConfig(NAME$5, 'size'); + } + }, + variant: { + type: String, + default: function _default() { + return getComponentConfig(NAME$5, 'variant'); + } + }, + 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 + } + }; + var props$2 = _objectSpread2(_objectSpread2({}, btnProps), linkProps); // --- 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 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 || getComponentConfig(NAME$5, 'variant')), (_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.extend({ + name: NAME$5, + 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 SPACE/ENTER + + /* istanbul ignore next */ + if (props.disabled || !(nonStandardTag || hashLink)) { + return; + } + + var keyCode = evt.keyCode; // Add SPACE handler for `href="#"` and ENTER handler for non-standard tags + + if (keyCode === KEY_CODES.SPACE || keyCode === KEY_CODES.ENTER && nonStandardTag) { + var target = evt.currentTarget || evt.target; + evt.preventDefault(); + target.click(); + } + }, + click: function click(evt) { + /* istanbul ignore if: blink/button disabled should handle this */ + if (props.disabled && isEvent(evt)) { + evt.stopPropagation(); + evt.preventDefault(); + } 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 = { + 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.extend({ + name: 'BVIconBase', + 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 `` 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 `` 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 `` for proper + // animation handling if stacked + $inner = h('g', {}, [$inner]); + } + + 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' + } + }), [$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 svgContent = trim(content || ''); // Return the icon component definition + + return /*#__PURE__*/Vue.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(data, { + staticClass: iconNameClass, + props: _objectSpread2(_objectSpread2({}, props), {}, { + content: svgContent + }), + attrs: { + 'aria-label': kebabName.replace(/-/g, ' ') + } + })); + } + }); + }; + + // --- BEGIN AUTO-GENERATED FILE --- + var BIconBlank=/*#__PURE__*/makeIcon('Blank','');// --- Bootstrap Icons --- + var BIconCalendar=/*#__PURE__*/makeIcon('Calendar','');// eslint-disable-next-line + var BIconCalendarFill=/*#__PURE__*/makeIcon('CalendarFill','');// eslint-disable-next-line + var BIconChevronBarLeft=/*#__PURE__*/makeIcon('ChevronBarLeft','');// eslint-disable-next-line + var BIconChevronDoubleLeft=/*#__PURE__*/makeIcon('ChevronDoubleLeft','');// eslint-disable-next-line + var BIconChevronDown=/*#__PURE__*/makeIcon('ChevronDown','');// eslint-disable-next-line + var BIconChevronLeft=/*#__PURE__*/makeIcon('ChevronLeft','');// eslint-disable-next-line + var BIconChevronUp=/*#__PURE__*/makeIcon('ChevronUp','');// eslint-disable-next-line + var BIconCircleFill=/*#__PURE__*/makeIcon('CircleFill','');// eslint-disable-next-line + var BIconClock=/*#__PURE__*/makeIcon('Clock','');// eslint-disable-next-line + var BIconClockFill=/*#__PURE__*/makeIcon('ClockFill','');// eslint-disable-next-line + var BIconDash=/*#__PURE__*/makeIcon('Dash','');// eslint-disable-next-line + var BIconPersonFill=/*#__PURE__*/makeIcon('PersonFill','');// eslint-disable-next-line + var BIconPlus=/*#__PURE__*/makeIcon('Plus','');// eslint-disable-next-line + var BIconStar=/*#__PURE__*/makeIcon('Star','');// eslint-disable-next-line + var BIconStarFill=/*#__PURE__*/makeIcon('StarFill','');// eslint-disable-next-line + var BIconStarHalf=/*#__PURE__*/makeIcon('StarHalf','');// eslint-disable-next-line + var BIconX=/*#__PURE__*/makeIcon('X','');// eslint-disable-next-line + // --- END AUTO-GENERATED FILE --- + + var RX_ICON_PREFIX = /^BIcon/; // Helper BIcon component + // Requires the requested icon component to be installed + + var BIcon = /*#__PURE__*/Vue.extend({ + name: 'BIcon', + functional: true, + props: _objectSpread2(_objectSpread2({ + icon: { + type: String, + default: null + } + }, commonIconProps), {}, { + stacked: { + type: Boolean, + default: false + } + }), + 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, ''); + var iconName = "BIcon".concat(icon); // 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 + + var components = ((parent || {}).$options || {}).components; + var componentRefOrName = icon && components ? components[iconName] || BIconBlank : icon ? iconName : BIconBlank; + return h(componentRefOrName, a(data, { + props: _objectSpread2(_objectSpread2({}, props), {}, { + icon: null + }) + })); + } + }); + + var NAME$6 = 'BAvatar'; + var CLASS_NAME$1 = 'b-avatar'; + var RX_NUMBER = /^[0-9]*\.?[0-9]+$/; + var FONT_SIZE_SCALE = 0.4; + var BADGE_FONT_SIZE_SCALE = FONT_SIZE_SCALE * 0.7; + var DEFAULT_SIZES = { + sm: '1.5em', + md: '2.5em', + lg: '3.5em' + }; // --- Props --- + + var linkProps$1 = omit(props$1, ['active', 'event', 'routerTag']); + + var props$3 = _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: function _default() { + return getComponentConfig(NAME$6, 'variant'); + } + }, + 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: function _default() { + return getComponentConfig(NAME$6, 'badgeVariant'); + } + }, + badgeTop: { + type: Boolean, + default: false + }, + badgeLeft: { + type: Boolean, + default: false + }, + badgeOffset: { + type: String, + default: '0px' + } + }, linkProps$1), {}, { + ariaLabel: { + type: String // default: null + + } + }); // --- Utility methods --- + + + var computeSize = function computeSize(value) { + // Default to `md` size when `null`, or parse to + // number when value is a float-like string + value = isUndefinedOrNull(value) || value === '' ? 'md' : isString(value) && RX_NUMBER.test(value) ? toFloat(value, 0) : value; // Convert all numbers to pixel values + // Handle default sizes when `sm`, `md` or `lg` + // Or use value as is + + return isNumber(value) ? "".concat(value, "px") : DEFAULT_SIZES[value] || value; + }; // --- Main component --- + // @vue/component + + var BAvatar = /*#__PURE__*/Vue.extend({ + name: NAME$6, + mixins: [normalizeSlotMixin], + inject: { + bvAvatarGroup: { + default: null + } + }, + props: props$3, + data: function data() { + return { + localSrc: this.src || null + }; + }, + computed: { + computedSize: function computedSize() { + // Always use the avatar group size + return computeSize(this.bvAvatarGroup ? this.bvAvatarGroup.size : this.size); + }, + computedVariant: function computedVariant() { + // Prefer avatar-group variant if provided + var avatarGroup = this.bvAvatarGroup; + return avatarGroup && avatarGroup.variant ? avatarGroup.variant : this.variant; + }, + computedRounded: function computedRounded() { + var avatarGroup = this.bvAvatarGroup; + var square = avatarGroup && avatarGroup.square ? true : this.square; + var rounded = avatarGroup && avatarGroup.rounded ? avatarGroup.rounded : this.rounded; + return square ? '0' : rounded === '' ? true : rounded || 'circle'; + }, + fontStyle: function fontStyle() { + var fontSize = this.computedSize; + fontSize = fontSize ? "calc(".concat(fontSize, " * ").concat(FONT_SIZE_SCALE, ")") : null; + return fontSize ? { + fontSize: fontSize + } : {}; + }, + marginStyle: function marginStyle() { + var avatarGroup = this.bvAvatarGroup; + var overlapScale = avatarGroup ? avatarGroup.overlapScale : 0; + var size = this.computedSize; + 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: size ? "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')) { + // Default slot overrides props + $content = h('span', { + staticClass: 'b-avatar-custom' + }, [this.normalizeSlot('default')]); + } 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, "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({ + width: size, + height: size + }, marginStyle), + 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]); + } + }); + + var NAME$7 = 'BAvatarGroup'; // --- Main component --- + // @vue/component + + var BAvatarGroup = /*#__PURE__*/Vue.extend({ + name: NAME$7, + mixins: [normalizeSlotMixin], + provide: function provide() { + return { + bvAvatarGroup: this + }; + }, + props: { + 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' + } + }, + 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('default')]); + return h(this.tag, { + staticClass: 'b-avatar-group', + attrs: { + role: 'group' + } + }, [$inner]); + } + }); + + var AvatarPlugin = /*#__PURE__*/pluginFactory({ + components: { + BAvatar: BAvatar, + BAvatarGroup: BAvatarGroup + } + }); + + var NAME$8 = 'BBadge'; // --- Props --- + + var linkProps$2 = omit(props$1, ['event', 'routerTag']); + delete linkProps$2.href.default; + delete linkProps$2.to.default; + var props$4 = _objectSpread2({ + tag: { + type: String, + default: 'span' + }, + variant: { + type: String, + default: function _default() { + return getComponentConfig(NAME$8, 'variant'); + } + }, + pill: { + type: Boolean, + default: false + } + }, linkProps$2); // --- Main component --- + // @vue/component + + var BBadge = /*#__PURE__*/Vue.extend({ + name: NAME$8, + functional: true, + props: props$4, + 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 RX_HTML_TAGS = /(<([^>]+)>)/gi; // Removes anything that looks like an HTML tag from the supplied string + + 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$5 = _objectSpread2({ + text: { + type: String, + default: null + }, + html: { + type: String, + default: null + }, + ariaCurrent: { + type: String, + default: 'location' + } + }, omit(props$1, ['event', 'routerTag'])); // --- Main component --- + // @vue/component + + var BBreadcrumbLink = /*#__PURE__*/Vue.extend({ + name: 'BBreadcrumbLink', + functional: true, + props: props$5, + 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$5, suppliedProps) + }; + + if (!children) { + componentData.domProps = htmlOrText(suppliedProps.html, suppliedProps.text); + } + + return h(tag, a(data, componentData), children); + } + }); + + var BBreadcrumbItem = /*#__PURE__*/Vue.extend({ + name: 'BBreadcrumbItem', + functional: true, + props: props$5, + 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$6 = { + items: { + type: Array, + default: null + } + }; // @vue/component + + var BBreadcrumb = /*#__PURE__*/Vue.extend({ + name: 'BBreadcrumb', + functional: true, + props: props$6, + 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 NAME$9 = 'BButtonGroup'; + var props$7 = { + vertical: { + type: Boolean, + default: false + }, + size: { + type: String, + default: function _default() { + return getComponentConfig('BButton', 'size'); + } + }, + tag: { + type: String, + default: 'div' + }, + ariaRole: { + type: String, + default: 'group' + } + }; // @vue/component + + var BButtonGroup = /*#__PURE__*/Vue.extend({ + name: NAME$9, + functional: true, + props: props$7, + 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(','); // @vue/component + + var BButtonToolbar = /*#__PURE__*/Vue.extend({ + name: 'BButtonToolbar', + mixins: [normalizeSlotMixin], + props: { + justify: { + type: Boolean, + default: false + }, + keyNav: { + type: Boolean, + default: false + } + }, + mounted: function mounted() { + if (this.keyNav) { + // Pre-set the tabindexes if the markup does not include tabindex="-1" on the toolbar items + this.getItems(); + } + }, + methods: { + onFocusin: function onFocusin(evt) { + if (evt.target === this.$el) { + evt.preventDefault(); + evt.stopPropagation(); + this.focusFirst(evt); + } + }, + stop: function stop(evt) { + evt.preventDefault(); + evt.stopPropagation(); + }, + onKeydown: function onKeydown(evt) { + if (!this.keyNav) { + /* istanbul ignore next: should never happen */ + return; + } + + var key = evt.keyCode; + var shift = evt.shiftKey; + + if (key === KEY_CODES.UP || key === KEY_CODES.LEFT) { + this.stop(evt); + shift ? this.focusFirst(evt) : this.focusPrev(evt); + } else if (key === KEY_CODES.DOWN || key === KEY_CODES.RIGHT) { + this.stop(evt); + shift ? this.focusLast(evt) : this.focusNext(evt); + } + }, + 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]); + }, + getItems: function getItems() { + var items = selectAll(ITEM_SELECTOR, this.$el); + items.forEach(function (item) { + // Ensure tabfocus is -1 on any new elements + item.tabIndex = -1; + }); + return items.filter(function (el) { + return isVisible(el); + }); + } + }, + 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('default')]); + } + }); + + var ButtonToolbarPlugin = /*#__PURE__*/pluginFactory({ + components: { + BButtonToolbar: BButtonToolbar, + BBtnToolbar: BButtonToolbar + } + }); + + // 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); + }; + + // 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/; // --- Date utility methods --- + // 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] : '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(); + }); // Precompile RegExpr + + var RX_STRIP_MODS = /-u-.+/; // 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_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 NAME$a = 'BCalendar'; // Key Codes + + var UP = KEY_CODES.UP, + DOWN = KEY_CODES.DOWN, + LEFT = KEY_CODES.LEFT, + RIGHT = KEY_CODES.RIGHT, + PAGEUP = KEY_CODES.PAGEUP, + PAGEDOWN = KEY_CODES.PAGEDOWN, + HOME = KEY_CODES.HOME, + END = KEY_CODES.END, + ENTER = KEY_CODES.ENTER, + SPACE = KEY_CODES.SPACE; // Common calendar option value strings + + var STR_GREGORY = 'gregory'; + var STR_NUMERIC = 'numeric'; + var STR_2_DIGIT = '2-digit'; + var STR_LONG = 'long'; + var STR_SHORT = 'short'; + var STR_NARROW = 'narrow'; // --- BCalendar component --- + // @vue/component + + var BCalendar = Vue.extend({ + name: NAME$a, + // 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: { + 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 `variant`) + type: String // default: null + + }, + 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 , 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 + + }, + roleDescription: { + type: String // default: null + + }, + // Labels for buttons and keyboard shortcuts + labelPrevDecade: { + type: String, + default: function _default() { + return getComponentConfig(NAME$a, 'labelPrevDecade'); + } + }, + labelPrevYear: { + type: String, + default: function _default() { + return getComponentConfig(NAME$a, 'labelPrevYear'); + } + }, + labelPrevMonth: { + type: String, + default: function _default() { + return getComponentConfig(NAME$a, 'labelPrevMonth'); + } + }, + labelCurrentMonth: { + type: String, + default: function _default() { + return getComponentConfig(NAME$a, 'labelCurrentMonth'); + } + }, + labelNextMonth: { + type: String, + default: function _default() { + return getComponentConfig(NAME$a, 'labelNextMonth'); + } + }, + labelNextYear: { + type: String, + default: function _default() { + return getComponentConfig(NAME$a, 'labelNextYear'); + } + }, + labelNextDecade: { + type: String, + default: function _default() { + return getComponentConfig(NAME$a, 'labelNextDecade'); + } + }, + labelToday: { + type: String, + default: function _default() { + return getComponentConfig(NAME$a, 'labelToday'); + } + }, + labelSelected: { + type: String, + default: function _default() { + return getComponentConfig(NAME$a, 'labelSelected'); + } + }, + labelNoDateSelected: { + type: String, + default: function _default() { + return getComponentConfig(NAME$a, 'labelNoDateSelected'); + } + }, + labelCalendar: { + type: String, + default: function _default() { + return getComponentConfig(NAME$a, 'labelCalendar'); + } + }, + labelNav: { + type: String, + default: function _default() { + return getComponentConfig(NAME$a, 'labelNav'); + } + }, + labelHelp: { + type: String, + default: function _default() { + return getComponentConfig(NAME$a, 'labelHelp'); + } + }, + dateFormatOptions: { + // `Intl.DateTimeFormat` object + // Note: This value is *not* to be placed in the global config + type: Object, + default: function _default() { + return { + year: STR_NUMERIC, + month: STR_LONG, + day: STR_NUMERIC, + weekday: STR_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: STR_SHORT, + validator: function validator(value) { + return arrayIncludes([STR_LONG, STR_SHORT, STR_NARROW], value); + } + } + }, + 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), STR_GREGORY); + }, + 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: STR_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 !== STR_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() { + return createDate(this.calendarYear, this.calendarMonth, 1); + }, + 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'); + }, + 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; + var selectedDate = parseYMD(selectedYMD); + var activeYMD = this.activeYMD; + 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; + var 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() { + // 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; + var disabledFn = isFunction(this.dateDisabledFn) ? this.dateDisabledFn : function () { + return false; + }; // 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) || disabledFn(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: STR_NUMERIC, + month: STR_2_DIGIT, + day: STR_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: STR_GREGORY + })); + }, + formatYearMonth: function formatYearMonth() { + // Returns a date formatter function + return createDateFormatter(this.calendarLocale, { + year: STR_NUMERIC, + month: STR_LONG, + calendar: STR_GREGORY + }); + }, + formatWeekdayName: function formatWeekdayName() { + // Long weekday name for weekday header aria-label + return createDateFormatter(this.calendarLocale, { + weekday: STR_LONG, + calendar: STR_GREGORY + }); + }, + formatWeekdayNameShort: function formatWeekdayNameShort() { + // Weekday header cell format + // defaults to 'short' 3 letter days, where possible + return createDateFormatter(this.calendarLocale, { + weekday: this.weekdayHeaderFormat || STR_SHORT, + calendar: STR_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; // TODO: Change `dateInfoFn` to handle events and notes as well as classes + + var dateInfoFn = isFunction(this.dateInfoFn) ? this.dateInfoFn : function () { + return {}; + }; // 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 = dateInfoFn(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 _this = this; + + return this.calendar[0].map(function (d) { + return { + text: _this.formatWeekdayNameShort(parseYMD(d.ymd)), + label: _this.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 _this2 = this; + + this.$nextTick(function () { + _this2.$emit('context', _this2.context); + }); + }, + mounted: function mounted() { + this.setLive(true); + }, + + /* istanbul ignore next */ + activated: function activated() + /* istanbul ignore next */ + { + this.setLive(true); + }, + + /* istanbul ignore next */ + deactivated: function deactivated() + /* istanbul ignore next */ + { + 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 _this3 = this; + + if (on) { + this.$nextTick(function () { + requestAF(function () { + _this3.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 _this4 = this; + + // Performed in a `$nextTick()` to (probably) ensure + // the input event has emitted first + this.$nextTick(function () { + _this4.$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 + var altKey = evt.altKey, + ctrlKey = evt.ctrlKey, + keyCode = evt.keyCode; + + if (!arrayIncludes([PAGEUP, PAGEDOWN, END, HOME, LEFT, UP, RIGHT, DOWN], keyCode)) { + /* istanbul ignore next */ + return; + } + + evt.preventDefault(); + evt.stopPropagation(); + 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 === 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 === 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 === LEFT) { + // LEFT - Previous day (or next day for RTL) + activeDate.setDate(day + (isRTL ? 1 : -1)); + activeDate = this.constrainDate(activeDate); + checkDate = activeDate; + } else if (keyCode === RIGHT) { + // RIGHT - Next day (or previous day for RTL) + activeDate.setDate(day + (isRTL ? -1 : 1)); + activeDate = this.constrainDate(activeDate); + checkDate = activeDate; + } else if (keyCode === UP) { + // UP - Previous week + activeDate.setDate(day - 7); + activeDate = this.constrainDate(activeDate); + checkDate = activeDate; + } else if (keyCode === DOWN) { + // DOWN - Next week + activeDate.setDate(day + 7); + activeDate = this.constrainDate(activeDate); + checkDate = activeDate; + } else if (keyCode === HOME) { + // HOME - Today + activeDate = constrainedToday; + checkDate = activeDate; + } else if (keyCode === 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 === ENTER || keyCode === SPACE) { + evt.preventDefault(); + evt.stopPropagation(); + + 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; + var 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 _this5 = 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, + 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': this.disabled, + readonly: this.readonly || this.disabled + }, + attrs: { + id: valueId, + for: gridId, + role: 'status', + tabindex: this.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 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 btn-outline-secondary border-0 flex-fill', + class: { + disabled: btnDisabled + }, + attrs: { + title: label || null, + type: 'button', + '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', + 'aria-hidden': this.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': this.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': _this5.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 && _this5.gridHasFocus, + // Styling + disabled: day.isDisabled || _this5.disabled, + active: isSelected + }, _defineProperty(_class, _this5.computedVariant, isSelected), _defineProperty(_class, _this5.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 _this5.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 || _this5.disabled ? 'true' : null, + 'aria-label': [day.label, isSelected ? "(".concat(_this5.labelSelected, ")") : null, isToday ? "(".concat(_this5.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: this.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: this.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 && !this.disabled ? 'true' : null, + 'aria-disabled': this.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('default'); + $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': this.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 + } + }); + + // @vue/component + var cardMixin = { + props: { + tag: { + type: String, + default: 'div' + }, + bgVariant: { + type: String // default: null + + }, + borderVariant: { + type: String // default: null + + }, + textVariant: { + type: String // default: null + + } + } + }; + + var props$8 = { + title: { + type: String // default: null + + }, + titleTag: { + type: String, + default: 'h4' + } + }; // @vue/component + + var BCardTitle = /*#__PURE__*/Vue.extend({ + name: 'BCardTitle', + functional: true, + props: props$8, + 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 NAME$b = 'BCardSubTitle'; + var props$9 = { + subTitle: { + type: String // default: null + + }, + subTitleTag: { + type: String, + default: 'h6' + }, + subTitleTextVariant: { + type: String, + default: function _default() { + return getComponentConfig(NAME$b, 'subTitleTextVariant'); + } + } + }; // @vue/component + + var BCardSubTitle = /*#__PURE__*/Vue.extend({ + name: NAME$b, + functional: true, + props: props$9, + 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$a = _objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, copyProps(cardMixin.props, prefixPropName.bind(null, 'body'))), {}, { + bodyClass: { + type: [String, Object, Array] // default: null + + } + }, props$8), props$9), {}, { + overlay: { + type: Boolean, + default: false + } + }); // @vue/component + + var BCardBody = /*#__PURE__*/Vue.extend({ + name: 'BCardBody', + functional: true, + props: props$a, + 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$8, props) + }); + } + + if (props.subTitle) { + cardSubTitle = h(BCardSubTitle, { + props: pluckProps(props$9, 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$b = _objectSpread2(_objectSpread2({}, copyProps(cardMixin.props, prefixPropName.bind(null, 'header'))), {}, { + header: { + type: String // default: null + + }, + headerHtml: { + type: String // default: null + + }, + headerClass: { + type: [String, Object, Array] // default: null + + } + }); // --- Main component --- + // @vue/component + + var BCardHeader = /*#__PURE__*/Vue.extend({ + name: 'BCardHeader', + functional: true, + props: props$b, + 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$c = _objectSpread2(_objectSpread2({}, copyProps(cardMixin.props, prefixPropName.bind(null, 'footer'))), {}, { + footer: { + type: String // default: null + + }, + footerHtml: { + type: String // default: null + + }, + footerClass: { + type: [String, Object, Array] // default: null + + } + }); // --- Main component --- + // @vue/component + + var BCardFooter = /*#__PURE__*/Vue.extend({ + name: 'BCardFooter', + functional: true, + props: props$c, + 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$d = { + 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 + + } + }; // @vue/component + + var BCardImg = /*#__PURE__*/Vue.extend({ + name: 'BCardImg', + functional: true, + props: props$d, + 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$d, prefixPropName.bind(null, 'img')); + cardImgProps.imgSrc.required = false; + var props$e = _objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, props$a), props$b), props$c), cardImgProps), copyProps(cardMixin.props)), {}, { + align: { + type: String // default: null + + }, + noBody: { + type: Boolean, + default: false + } + }); // @vue/component + + var BCard = /*#__PURE__*/Vue.extend({ + name: 'BCard', + functional: true, + props: props$e, + render: function render(h, _ref) { + var _class; + + var props = _ref.props, + data = _ref.data, + slots = _ref.slots, + scopedSlots = _ref.scopedSlots; + var imgLeft = props.imgLeft, + imgRight = props.imgRight, + imgStart = props.imgStart, + imgEnd = props.imgEnd, + 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 (props.imgSrc) { + var $img = h(BCardImg, { + props: pluckProps(cardImgProps, props, unprefixPropName.bind(null, 'img')) + }); + + if (props.imgBottom) { + $imgLast = $img; + } else { + $imgFirst = $img; + } + } + + var $header = h(); + var hasHeaderSlot = hasNormalizedSlot('header', $scopedSlots, $slots); + + if (hasHeaderSlot || header || headerHtml) { + $header = h(BCardHeader, { + props: pluckProps(props$b, props), + domProps: hasHeaderSlot ? {} : htmlOrText(headerHtml, header) + }, normalizeSlot('header', slotScope, $scopedSlots, $slots)); + } + + var $content = normalizeSlot('default', slotScope, $scopedSlots, $slots); // Wrap content in when `noBody` prop set + + if (!props.noBody) { + $content = h(BCardBody, { + props: pluckProps(props$a, props) + }, $content); + } + + var $footer = h(); + var hasFooterSlot = hasNormalizedSlot('footer', $scopedSlots, $slots); + + if (hasFooterSlot || footer || footerHtml) { + $footer = h(BCardFooter, { + props: pluckProps(props$c, props), + domProps: hasHeaderSlot ? {} : htmlOrText(footerHtml, footer) + }, normalizeSlot('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 RX_ONLY_DIGITS = /^\d+$/; + + 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) + /* istanbul ignore next: IntersectionObserver not supported in JSDOM */ + { + 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 is switched to use this directive */ + if (RX_ONLY_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 + }; + + var NAME$c = 'BImg'; // Blank image with fill template + + var BLANK_TEMPLATE = '' + '' + ''; + var props$f = { + 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: function _default() { + return getComponentConfig(NAME$c, 'blankColor'); + } + } + }; // --- 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.extend({ + name: NAME$c, + functional: true, + props: props$f, + 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 NAME$d = 'BImgLazy'; + var props$g = { + src: { + type: String, + required: true + }, + 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 + + }, + blankSrc: { + // If null, a blank image is generated + type: String, + default: null + }, + blankColor: { + type: String, + default: function _default() { + return getComponentConfig(NAME$d, 'blankColor'); + } + }, + blankWidth: { + type: [Number, String] // default: null + + }, + blankHeight: { + type: [Number, String] // default: null + + }, + show: { + type: Boolean, + default: false + }, + fluid: { + type: Boolean, + default: false + }, + fluidGrow: { + type: Boolean, + default: false + }, + block: { + type: Boolean, + default: false + }, + thumbnail: { + type: Boolean, + default: false + }, + rounded: { + type: [Boolean, String], + default: false + }, + left: { + type: Boolean, + default: false + }, + right: { + type: Boolean, + default: false + }, + center: { + type: Boolean, + default: false + }, + offset: { + // Distance away from viewport (in pixels) before being + // considered "visible" + type: [Number, String], + default: 360 + } + }; // @vue/component + + var BImgLazy = /*#__PURE__*/Vue.extend({ + name: NAME$d, + directives: { + bVisible: VBVisible + }, + props: props$g, + 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$g, ['left', 'right', 'center', 'block', 'rounded', 'thumbnail', 'fluid', 'fluidGrow']); + var props$h = _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 + } + }); // @vue/component + + var BCardImgLazy = /*#__PURE__*/Vue.extend({ + name: 'BCardImgLazy', + functional: true, + props: props$h, + 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$i = { + textTag: { + type: String, + default: 'p' + } + }; // @vue/component + + var BCardText = /*#__PURE__*/Vue.extend({ + name: 'BCardText', + functional: true, + props: props$i, + 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$j = { + tag: { + type: String, + default: 'div' + }, + deck: { + type: Boolean, + default: false + }, + columns: { + type: Boolean, + default: false + } + }; // @vue/component + + var BCardGroup = /*#__PURE__*/Vue.extend({ + name: 'BCardGroup', + functional: true, + props: props$j, + 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 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 EVENT_OPTIONS_PASSIVE = { + passive: true + }; + var EVENT_OPTIONS_NO_CAPTURE = { + passive: true, + capture: false + }; // --- Utils --- + // 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); + }; + + var NAME$e = 'BCarousel'; // Slide directional classes + + var DIRECTION = { + next: { + dirClass: 'carousel-item-left', + overlayClass: 'carousel-item-next' + }, + prev: { + dirClass: 'carousel-item-right', + overlayClass: 'carousel-item-prev' + } + }; // Fallback Transition duration (with a little buffer) in ms + + var TRANS_DURATION = 600 + 50; // 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.extend({ + name: NAME$e, + mixins: [idMixin, normalizeSlotMixin], + provide: function provide() { + return { + bvCarousel: this + }; + }, + model: { + prop: 'value', + event: 'input' + }, + props: { + labelPrev: { + type: String, + default: function _default() { + return getComponentConfig(NAME$e, 'labelPrev'); + } + }, + labelNext: { + type: String, + default: function _default() { + return getComponentConfig(NAME$e, 'labelNext'); + } + }, + labelGotoSlide: { + type: String, + default: function _default() { + return getComponentConfig(NAME$e, 'labelGotoSlide'); + } + }, + labelIndicators: { + type: String, + default: function _default() { + return getComponentConfig(NAME$e, 'labelIndicators'); + } + }, + 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 + } + }, + 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 () { + 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() + /* istanbul ignore next: difficult to test */ + { + 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 === KEY_CODES.SPACE || keyCode === KEY_CODES.ENTER) { + evt.preventDefault(); + evt.stopPropagation(); + fn(); + } + }, + + /* istanbul ignore next */ + handleSwipe: function handleSwipe() + /* istanbul ignore next: JSDOM doesn't support touch events */ + { + 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 */ + touchStart: function touchStart(evt) + /* istanbul ignore next: JSDOM doesn't support touch events */ + { + if (hasPointerEventSupport && PointerType[evt.pointerType.toUpperCase()]) { + this.touchStartX = evt.clientX; + } else if (!hasPointerEventSupport) { + this.touchStartX = evt.touches[0].clientX; + } + }, + + /* istanbul ignore next */ + touchMove: function touchMove(evt) + /* istanbul ignore next: JSDOM doesn't support touch events */ + { + // 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 */ + touchEnd: function touchEnd(evt) + /* istanbul ignore next: JSDOM doesn't support touch events */ + { + 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('default')]); // 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 { + evt.preventDefault(); + } + }; + + var nextHandler = function nextHandler(evt) { + /* istanbul ignore next */ + if (!_this3.isSliding) { + _this3.handleClick(evt, _this3.next); + } else { + evt.preventDefault(); + } + }; + + 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 === KEY_CODES.LEFT || keyCode === KEY_CODES.RIGHT) { + evt.preventDefault(); + evt.stopPropagation(); + + _this3[keyCode === KEY_CODES.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$k = _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 + } + }); // --- Main component --- + // @vue/component + + var BCarouselSlide = /*#__PURE__*/Vue.extend({ + name: 'BCarouselSlide', + mixins: [idMixin, normalizeSlotMixin], + inject: { + bvCarousel: { + default: function _default() { + return { + // Explicitly disable touch if not a child of carousel + noTouch: true + }; + } + } + }, + props: props$k, + 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) { + evt.preventDefault(); + }; + } + + $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('default') || 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) { + el.style.height = 0; // Animaton frame delay needed for `appear` to work + + requestAF(function () { + reflow(el); + el.style.height = "".concat(el.scrollHeight, "px"); + }); + }; + + var onAfterEnter = function onAfterEnter(el) { + el.style.height = null; + }; + + var onLeave = function onLeave(el) { + el.style.height = 'auto'; + el.style.display = 'block'; + el.style.height = "".concat(getBCR(el).height, "px"); + reflow(el); + el.style.height = 0; + }; + + var onAfterLeave = function onAfterLeave(el) { + el.style.height = null; + }; // 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.extend({ + name: 'BVCollapse', + 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: `` 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)); + } + } + }; + + var ENTER$1 = KEY_CODES.ENTER, + SPACE$1 = KEY_CODES.SPACE; // 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'; // 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 = [ENTER$1, SPACE$1]; + var RX_HASH = /^#/; + var RX_HASH_ID = /^#[A-Za-z]+[\w\-:.]*$/; + var RX_SPLIT_SEPARATOR = /\s+/; // --- 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_SPLIT_SEPARATOR) : 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); + eventOff(el, 'keydown', handler); + } + + 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); + + if (isNonStandardTag$1(el)) { + eventOn(el, 'keydown', handler); + } + } + }; + + 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); + /* istanbul ignore else */ + // Ensure the `aria-controls` hasn't been overwritten + // or removed when vnode updates + + if (targets.length) { + setAttr(el, ATTR_ARIA_CONTROLS, targets.join(' ')); + } else { + removeAttr(el, ATTR_ARIA_CONTROLS); + } // Add/Update our click listener(s) + + + 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 + + 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); + } + }; + + // Accordion event name we emit on `$root` + + var EVENT_ACCORDION = 'bv::collapse::accordion'; // --- Main component --- + // @vue/component + + var BCollapse = /*#__PURE__*/Vue.extend({ + name: 'BCollapse', + mixins: [idMixin, listenOnRootMixin, normalizeSlotMixin], + model: { + prop: 'visible', + event: 'input' + }, + props: { + 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 + } + }, + 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() + /* istanbul ignore next */ + { + if (this.isNav) { + this.setWindowEvents(false); + } + }, + + /* istanbul ignore next */ + activated: function activated() + /* istanbul ignore next */ + { + 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('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.
+ * 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(n) { + return n !== '' && !isNaN(parseFloat(n)) && isFinite(n); + } + + /** + * Set the style to the given popper + * @method + * @memberof Popper.Utils + * @argument {Element} element - Element to apply the style to + * @argument {Object} styles + * Object with a list of properties and values which will be applied to the element + */ + function setStyles(element, styles) { + Object.keys(styles).forEach(function (prop) { + var unit = ''; + // add unit if the value is numeric and is one of the following + if (['width', 'height', 'top', 'right', 'bottom', 'left'].indexOf(prop) !== -1 && isNumeric(styles[prop])) { + unit = 'px'; + } + element.style[prop] = styles[prop] + unit; + }); + } + + /** + * Set the attributes to the given popper + * @method + * @memberof Popper.Utils + * @argument {Element} element - Element to apply the attributes to + * @argument {Object} styles + * Object with a list of properties and values which will be applied to the element + */ + function setAttributes(element, attributes) { + Object.keys(attributes).forEach(function (prop) { + var value = attributes[prop]; + if (value !== false) { + element.setAttribute(prop, attributes[prop]); + } else { + element.removeAttribute(prop); + } + }); + } + + /** + * @function + * @memberof Modifiers + * @argument {Object} data - The data object generated by `update` method + * @argument {Object} data.styles - List of style properties - values to apply to popper element + * @argument {Object} data.attributes - List of attribute properties - values to apply to popper element + * @argument {Object} options - Modifiers configuration and options + * @returns {Object} The same data object + */ + function applyStyle(data) { + // any property present in `data.styles` will be applied to the popper, + // in this way we can make the 3rd party modifiers add custom styles to it + // Be aware, modifiers could override the properties defined in the previous + // lines of this modifier! + setStyles(data.instance.popper, data.styles); + + // any property present in `data.attributes` will be applied to the popper, + // they will be set as HTML attributes of the element + setAttributes(data.instance.popper, data.attributes); + + // if arrowElement is defined and arrowStyles has some properties + if (data.arrowElement && Object.keys(data.arrowStyles).length) { + setStyles(data.arrowElement, data.arrowStyles); + } + + return data; + } + + /** + * Set the x-placement attribute before everything else because it could be used + * to add margins to the popper margins needs to be calculated to get the + * correct popper offsets. + * @method + * @memberof Popper.modifiers + * @param {HTMLElement} reference - The reference element used to position the popper + * @param {HTMLElement} popper - The HTML element used as popper + * @param {Object} options - Popper.js options + */ + function applyStyleOnLoad(reference, popper, options, modifierOptions, state) { + // compute reference element offsets + var referenceOffsets = getReferenceOffsets(state, popper, reference, options.positionFixed); + + // compute auto placement, store placement inside the data object, + // modifiers will be able to edit `placement` if needed + // and refer to originalPlacement to know the original value + var placement = computeAutoPlacement(options.placement, referenceOffsets, popper, reference, options.modifiers.flip.boundariesElement, options.modifiers.flip.padding); + + popper.setAttribute('x-placement', placement); + + // Apply `position` to popper before anything else because + // without the position applied we can't guarantee correct computations + setStyles(popper, { position: options.positionFixed ? 'fixed' : 'absolute' }); + + return options; + } + + /** + * @function + * @memberof 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 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.
+ * 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.
+ * 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.
+ * 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(frag)) { + offsets[index] += frag * (op[index2 - 1] === '-' ? -1 : 1); + } + }); + }); + return offsets; + } + + /** + * @function + * @memberof Modifiers + * @argument {Object} data - The data object generated by update method + * @argument {Object} options - Modifiers configuration and options + * @argument {Number|String} options.offset=0 + * The offset value as described in the modifier description + * @returns {Object} The data object, properly modified + */ + function offset$1(data, _ref) { + var offset = _ref.offset; + var placement = data.placement, + _data$offsets = data.offsets, + popper = _data$offsets.popper, + reference = _data$offsets.reference; + + var basePlacement = placement.split('-')[0]; + + var offsets = void 0; + if (isNumeric(+offset)) { + offsets = [+offset, 0]; + } else { + offsets = parseOffset(offset, popper, reference, basePlacement); + } + + if (basePlacement === 'left') { + popper.top += offsets[0]; + popper.left -= offsets[1]; + } else if (basePlacement === 'right') { + popper.top += offsets[0]; + popper.left += offsets[1]; + } else if (basePlacement === 'top') { + popper.left += offsets[0]; + popper.top -= offsets[1]; + } else if (basePlacement === 'bottom') { + popper.left += offsets[0]; + popper.top += offsets[1]; + } + + data.popper = popper; + return data; + } + + /** + * @function + * @memberof Modifiers + * @argument {Object} data - The data object generated by `update` method + * @argument {Object} options - Modifiers configuration and options + * @returns {Object} The data object, properly modified + */ + function preventOverflow(data, options) { + var boundariesElement = options.boundariesElement || getOffsetParent(data.instance.popper); + + // If offsetParent is the reference element, we really want to + // go one step up and use the next offsetParent as reference to + // avoid to make this modifier completely useless and look like broken + if (data.instance.reference === boundariesElement) { + boundariesElement = getOffsetParent(boundariesElement); + } + + // NOTE: DOM access here + // resets the popper's position so that the document size can be calculated excluding + // the size of the popper element itself + var transformProp = getSupportedPropertyName('transform'); + var popperStyles = data.instance.popper.style; // assignment to help minification + var top = popperStyles.top, + left = popperStyles.left, + transform = popperStyles[transformProp]; + + popperStyles.top = ''; + popperStyles.left = ''; + popperStyles[transformProp] = ''; + + var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, boundariesElement, data.positionFixed); + + // NOTE: DOM access here + // restores the original style properties after the offsets have been computed + popperStyles.top = top; + popperStyles.left = left; + popperStyles[transformProp] = transform; + + options.boundaries = boundaries; + + var order = options.priority; + var popper = data.offsets.popper; + + var check = { + primary: function primary(placement) { + var value = popper[placement]; + if (popper[placement] < boundaries[placement] && !options.escapeWithReference) { + value = Math.max(popper[placement], boundaries[placement]); + } + return defineProperty$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.
+ * 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.
+ * 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.
+ * It will read the variation of the `placement` property.
+ * 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.
+ * 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.
+ * The latter is a deprecated method because it leads to confusion and will be + * removed in v2.
+ * 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.
+ * We can say it has "escaped the boundaries" — or just "escaped".
+ * 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.
+ * These can be overridden using the `options` argument of Popper.js.
+ * 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.
+ * By default, it is set to no-op.
+ * 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.
+ * By default, it is set to no-op.
+ * 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.
+ * 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 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() + /* istanbul ignore next */ + { + 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() + /* istanbul ignore next */ + { + eventOff(this.focusInElement, 'focusin', this._focusInHandler, EVENT_OPTIONS_NO_CAPTURE); + }, + methods: { + _focusInHandler: function _focusInHandler(evt) { + if (this.focusInHandler) { + this.focusInHandler(evt); + } + } + } + }; + + var filterVisibles = function filterVisibles(els) { + return (els || []).filter(isVisible); + }; // Root dropdown event names + + + var ROOT_DROPDOWN_PREFIX = 'bv::dropdown::'; + var ROOT_DROPDOWN_SHOWN = "".concat(ROOT_DROPDOWN_PREFIX, "shown"); + var ROOT_DROPDOWN_HIDDEN = "".concat(ROOT_DROPDOWN_PREFIX, "hidden"); // Dropdown item CSS selectors + + var Selector = { + FORM_CHILD: '.dropdown form', + ITEM_SELECTOR: ['.dropdown-item', '.b-dropdown-form'].map(function (selector) { + return "".concat(selector, ":not(.disabled):not([disabled])"); + }).join(', ') + }; // Popper attachment positions + + var AttachmentMap = { + // Dropup left align + TOP: 'top-start', + // Dropup right align + TOPEND: 'top-end', + // Dropdown left align + BOTTOM: 'bottom-start', + // Dropdown right align + BOTTOMEND: 'bottom-end', + // Dropright left align + RIGHT: 'right-start', + // Dropright right align + RIGHTEND: 'right-end', + // Dropleft left align + LEFT: 'left-start', + // Dropleft right align + LEFTEND: 'left-end' + }; + var commonProps = { + 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' + } + }; // @vue/component + + var dropdownMixin = { + mixins: [idMixin, clickOutMixin, focusInMixin], + provide: function provide() { + return { + bvDropdown: this + }; + }, + inject: { + bvNavbar: { + default: null + } + }, + props: _objectSpread2({ + disabled: { + type: Boolean, + default: false + } + }, commonProps), + 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 ''; + } + }, + 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; + }, + + /* istanbul ignore next */ + deactivated: function deactivated() + /* istanbul ignore next: not easy to test */ + { + // In case we are inside a `` + this.visible = false; + this.whileOpenListen(false); + this.destroyPopper(); + }, + beforeDestroy: function beforeDestroy() { + this.visible = false; + this.whileOpenListen(false); + this.destroyPopper(); + }, + methods: { + // Event emitter + emitEvent: function emitEvent(bvEvt) { + var type = bvEvt.type; + this.$emit(type, bvEvt); + this.$root.$emit("".concat(ROOT_DROPDOWN_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 `` + + + if (!this.inNavbar) { + if (typeof Popper === 'undefined') { + /* istanbul ignore next */ + warn('Popper.js not found. Falling back to CSS positioning', 'BDropdown'); + } 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_DROPDOWN_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_DROPDOWN_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() + /* istanbul ignore next: not easy to test */ + { + try { + this.$_popper.scheduleUpdate(); + } catch (_unused) {} + }, + getPopperConfig: function getPopperConfig() { + var placement = AttachmentMap.BOTTOM; + + if (this.dropup) { + placement = this.right ? AttachmentMap.TOPEND : AttachmentMap.TOP; + } else if (this.dropright) { + placement = AttachmentMap.RIGHT; + } else if (this.dropleft) { + placement = AttachmentMap.LEFT; + } else if (this.right) { + placement = AttachmentMap.BOTTOMEND; + } + + var popperConfig = { + placement: placement, + modifiers: { + offset: { + offset: this.offset || 0 + }, + flip: { + enabled: !this.noFlip + } + } + }; + + if (this.boundary) { + popperConfig.modifiers.preventOverflow = { + boundariesElement: this.boundary + }; + } + + return _objectSpread2(_objectSpread2({}, 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_DROPDOWN_SHOWN, this.rootCloseListener); + }, + rootCloseListener: function rootCloseListener(vm) { + if (vm !== this) { + this.visible = false; + } + }, + show: function show() { + var _this2 = this; + + // Public method to show dropdown + if (this.disabled) { + return; + } // Wrap in a `requestAF()` to allow any previous + // click handling to occur first + + + requestAF(function () { + _this2.visible = true; + }); + }, + hide: function hide() { + var refocus = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + // Public method to hide dropdown + if (this.disabled) { + /* istanbul ignore next */ + 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' && [KEY_CODES.ENTER, KEY_CODES.SPACE, KEY_CODES.DOWN].indexOf(keyCode) !== -1)) { + /* istanbul ignore next */ + return; + } + /* istanbul ignore next */ + + + if (this.disabled) { + this.visible = false; + return; + } + + this.$emit('toggle', evt); + evt.preventDefault(); + evt.stopPropagation(); // Toggle visibility + + if (this.visible) { + this.hide(true); + } else { + this.show(); + } + }, + // Mousedown handler for the toggle + + /* istanbul ignore next */ + onMousedown: function onMousedown(evt) + /* istanbul ignore next */ + { + // 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 + evt.preventDefault(); + }, + // Called from dropdown menu context + onKeydown: function onKeydown(evt) { + var keyCode = evt.keyCode; + + if (keyCode === KEY_CODES.ESC) { + // Close on ESC + this.onEsc(evt); + } else if (keyCode === KEY_CODES.DOWN) { + // Down Arrow + this.focusNext(evt, false); + } else if (keyCode === KEY_CODES.UP) { + // Up Arrow + this.focusNext(evt, true); + } + }, + // If user presses ESC, close the menu + onEsc: function onEsc(evt) { + if (this.visible) { + this.visible = false; + evt.preventDefault(); + evt.stopPropagation(); // 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 target = evt.target; + + if (this.visible && !contains(this.$refs.menu, target) && !contains(this.toggler, target)) { + this.hide(); + } + }, + // 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 _this3 = 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; + } + + evt.preventDefault(); + evt.stopPropagation(); + this.$nextTick(function () { + var items = _this3.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; + } + + _this3.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_SELECTOR, this.$refs.menu)); + }, + focusMenu: function focusMenu() { + attemptFocus(this.$refs.menu); + }, + focusToggler: function focusToggler() { + var _this4 = this; + + this.$nextTick(function () { + attemptFocus(_this4.toggler); + }); + } + } + }; + + var NAME$f = 'BDropdown'; // --- Props --- + + var props$l = { + text: { + // Button label + type: String, + default: '' + }, + html: { + // Button label + type: String // default: undefined + + }, + variant: { + type: String, + default: function _default() { + return getComponentConfig(NAME$f, 'variant'); + } + }, + size: { + type: String, + default: function _default() { + return getComponentConfig(NAME$f, 'size'); + } + }, + block: { + type: Boolean, + default: false + }, + menuClass: { + type: [String, Array, Object] // default: null + + }, + toggleTag: { + type: String, + default: 'button' + }, + toggleText: { + // This really should be toggleLabel + type: String, + default: function _default() { + return getComponentConfig(NAME$f, 'toggleText'); + } + }, + 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: function _default() { + return getComponentConfig(NAME$f, 'splitVariant'); + } + }, + 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' + } + }; // --- Main component --- + // @vue/component + + var BDropdown = /*#__PURE__*/Vue.extend({ + name: NAME$f, + mixins: [idMixin, dropdownMixin, normalizeSlotMixin], + props: props$l, + computed: { + dropdownClasses: function dropdownClasses() { + var block = this.block, + split = this.split, + boundary = this.boundary; + return [this.directionClass, { + 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, + // 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 + 'position-static': boundary !== 'scrollParent' || !boundary + }]; + }, + 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 variant = this.variant, + size = this.size, + block = this.block, + disabled = this.disabled, + split = this.split, + role = this.role; + var commonProps = { + variant: variant, + size: size, + block: block, + disabled: disabled + }; + var $buttonContent = this.normalizeSlot('button-content'); + var buttonContentProps = this.hasNormalizedSlot('button-content') ? {} : 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 || this.variant + }); // We add these as needed due to 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: buttonContentProps, + on: { + click: this.onSplitClick + }, + ref: 'button' + }, [$buttonContent]); + } + + var $toggle = h(BButton, { + staticClass: 'dropdown-toggle', + class: this.toggleClasses, + attrs: { + id: this.safeId('_BV_toggle_'), + 'aria-haspopup': 'true', + 'aria-expanded': this.visible ? 'true' : 'false' + }, + props: _objectSpread2(_objectSpread2({}, commonProps), {}, { + tag: this.toggleTag, + block: block && !split + }), + domProps: split ? {} : buttonContentProps, + on: { + mousedown: this.onMousedown, + click: this.toggle, + keydown: this.toggle // Handle ENTER, SPACE and DOWN + + }, + ref: 'toggle' + }, [split ? h('span', { + class: ['sr-only'] + }, [this.toggleText]) : $buttonContent]); + 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 || this.visible ? this.normalizeSlot('default', { + hide: this.hide + }) : [h()]); + return h('div', { + staticClass: 'dropdown b-dropdown', + class: this.dropdownClasses, + attrs: { + id: this.safeId() + } + }, [$split, $toggle, $menu]); + } + }); + + var props$m = omit(props$1, ['event', 'routerTag']); // @vue/component + + var BDropdownItem = /*#__PURE__*/Vue.extend({ + name: 'BDropdownItem', + mixins: [attrsMixin, normalizeSlotMixin], + inheritAttrs: false, + inject: { + bvDropdown: { + default: null + } + }, + props: _objectSpread2(_objectSpread2({}, props$m), {}, { + linkClass: { + type: [String, Array, Object], + default: null + }, + variant: { + type: String, + default: null + } + }), + 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 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) { + return h('li', { + attrs: { + role: 'presentation' + } + }, [h(BLink, { + props: this.$props, + staticClass: 'dropdown-item', + class: [this.linkClass, _defineProperty({}, "text-".concat(this.variant), this.variant && !(this.active || this.disabled))], + attrs: this.computedAttrs, + on: { + click: this.onClick + }, + ref: 'item' + }, this.normalizeSlot('default'))]); + } + }); + + var props$n = { + 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 + + } + }; // @vue/component + + var BDropdownItemButton = /*#__PURE__*/Vue.extend({ + name: 'BDropdownItemButton', + mixins: [attrsMixin, normalizeSlotMixin], + inheritAttrs: false, + inject: { + bvDropdown: { + default: null + } + }, + props: props$n, + 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('default'))]); + } + }); + + var props$o = { + id: { + type: String // default: null + + }, + tag: { + type: String, + default: 'header' + }, + variant: { + type: String // default: null + + } + }; // @vue/component + + var BDropdownHeader = /*#__PURE__*/Vue.extend({ + name: 'BDropdownHeader', + functional: true, + props: props$o, + 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$p = { + tag: { + type: String, + default: 'hr' + } + }; // @vue/component + + var BDropdownDivider = /*#__PURE__*/Vue.extend({ + name: 'BDropdownDivider', + functional: true, + props: props$p, + 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$q = { + id: { + type: String // default: null + + }, + inline: { + type: Boolean, + default: false + }, + novalidate: { + type: Boolean, + default: false + }, + validated: { + type: Boolean, + default: false + } + }; // @vue/component + + var BForm = /*#__PURE__*/Vue.extend({ + name: 'BForm', + functional: true, + props: props$q, + 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.extend({ + name: 'BDropdownForm', + functional: true, + props: _objectSpread2(_objectSpread2({}, props$q), {}, { + disabled: { + type: Boolean, + default: false + }, + formClass: { + type: [String, Object, Array] // default: null + + } + }), + 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.extend({ + name: 'BDropdownText', + functional: true, + props: { + tag: { + type: String, + default: 'p' + }, + variant: { + type: String // default: null + + } + }, + 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: 'b-dropdown-text', + class: _defineProperty({}, "text-".concat(props.variant), props.variant), + props: props, + attrs: $attrs, + ref: 'text' + }, children)]); + } + }); + + var props$r = { + 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 + + } + }; // @vue/component + + var BDropdownGroup = /*#__PURE__*/Vue.extend({ + name: 'BDropdownGroup', + functional: true, + props: props$r, + 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('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('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('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 props$s = { + type: { + type: String, + default: 'iframe', + validator: function validator(str) { + return arrayIncludes(['iframe', 'embed', 'video', 'object', 'img', 'b-img', 'b-img-lazy'], str); + } + }, + tag: { + type: String, + default: 'div' + }, + aspect: { + type: String, + default: '16by9' + } + }; // @vue/component + + var BEmbed = /*#__PURE__*/Vue.extend({ + name: 'BEmbed', + functional: true, + props: props$s, + 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.'; // @vue/component + + var formOptionsMixin = { + props: { + 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' + } + }, + 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 `