bootstrap-vue
Version:
BootstrapVue, with over 40 plugins and more than 75 custom components, provides one of the most comprehensive implementations of Bootstrap v4 components and grid system for Vue.js. With extensive and automated WAI-ARIA accessibility markup.
247 lines (208 loc) • 8.7 kB
JavaScript
;
exports.__esModule = true;
exports.default = void 0;
var _vue = _interopRequireDefault(require("../../../utils/vue"));
var _dom = require("../../../utils/dom");
var _env = require("../../../utils/env");
var _inspect = require("../../../utils/inspect");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Private ModalManager helper
* Handles controlling modal stacking zIndexes and body adjustments/classes
*/
// --- Constants ---
// Default modal backdrop z-index
var DEFAULT_ZINDEX = 1040; // Selectors for padding/margin adjustments
var Selector = {
FIXED_CONTENT: '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top',
STICKY_CONTENT: '.sticky-top',
NAVBAR_TOGGLER: '.navbar-toggler' // @vue/component
};
var ModalManager =
/*#__PURE__*/
_vue.default.extend({
data: function data() {
return {
modals: [],
baseZIndex: null,
scrollbarWidth: null,
isBodyOverflowing: false
};
},
computed: {
modalCount: function modalCount() {
return this.modals.length;
},
modalsAreOpen: function modalsAreOpen() {
return this.modalCount > 0;
}
},
watch: {
modalCount: function modalCount(newCount, oldCount) {
if (_env.isBrowser) {
this.getScrollbarWidth();
if (newCount > 0 && oldCount === 0) {
// Transitioning to modal(s) open
this.checkScrollbar();
this.setScrollbar();
(0, _dom.addClass)(document.body, 'modal-open');
} else if (newCount === 0 && oldCount > 0) {
// Transitioning to modal(s) closed
this.resetScrollbar();
(0, _dom.removeClass)(document.body, 'modal-open');
}
(0, _dom.setAttr)(document.body, 'data-modal-open-count', String(newCount));
}
},
modals: function modals(newVal, oldVal) {
var _this = this;
this.checkScrollbar();
(0, _dom.requestAF)(function () {
_this.updateModals(newVal || []);
});
}
},
methods: {
// Public methods
registerModal: function registerModal(modal) {
var _this2 = this;
// Register the modal if not already registered
if (modal && this.modals.indexOf(modal) === -1) {
// Add modal to modals array
this.modals.push(modal);
modal.$once('hook:beforeDestroy', function () {
_this2.unregisterModal(modal);
});
}
},
unregisterModal: function unregisterModal(modal) {
var index = this.modals.indexOf(modal);
if (index > -1) {
// Remove modal from modals array
this.modals.splice(index, 1); // Reset the modal's data
if (!(modal._isBeingDestroyed || modal._isDestroyed)) {
this.resetModal(modal);
}
}
},
getBaseZIndex: function getBaseZIndex() {
if ((0, _inspect.isNull)(this.baseZIndex) && _env.isBrowser) {
// Create a temporary `div.modal-backdrop` to get computed z-index
var div = document.createElement('div');
div.className = 'modal-backdrop d-none';
div.style.display = 'none';
document.body.appendChild(div);
this.baseZIndex = parseInt((0, _dom.getCS)(div).zIndex || DEFAULT_ZINDEX, 10);
document.body.removeChild(div);
}
return this.baseZIndex || DEFAULT_ZINDEX;
},
getScrollbarWidth: function getScrollbarWidth() {
if ((0, _inspect.isNull)(this.scrollbarWidth) && _env.isBrowser) {
// Create a temporary `div.measure-scrollbar` to get computed z-index
var div = document.createElement('div');
div.className = 'modal-scrollbar-measure';
document.body.appendChild(div);
this.scrollbarWidth = (0, _dom.getBCR)(div).width - div.clientWidth;
document.body.removeChild(div);
}
return this.scrollbarWidth || 0;
},
// Private methods
updateModals: function updateModals(modals) {
var _this3 = this;
var baseZIndex = this.getBaseZIndex();
var scrollbarWidth = this.getScrollbarWidth();
modals.forEach(function (modal, index) {
// We update data values on each modal
modal.zIndex = baseZIndex + index;
modal.scrollbarWidth = scrollbarWidth;
modal.isTop = index === _this3.modals.length - 1;
modal.isBodyOverflowing = _this3.isBodyOverflowing;
});
},
resetModal: function resetModal(modal) {
if (modal) {
modal.zIndex = this.getBaseZIndex();
modal.isTop = true;
modal.isBodyOverflowing = false;
}
},
checkScrollbar: function checkScrollbar() {
// Determine if the body element is overflowing
var _getBCR = (0, _dom.getBCR)(document.body),
left = _getBCR.left,
right = _getBCR.right;
this.isBodyOverflowing = left + right < window.innerWidth;
},
setScrollbar: function setScrollbar() {
var body = document.body; // Storage place to cache changes to margins and padding
// Note: This assumes the following element types are not added to the
// document after the modal has opened.
body._paddingChangedForModal = body._paddingChangedForModal || [];
body._marginChangedForModal = body._marginChangedForModal || [];
if (this.isBodyOverflowing) {
var scrollbarWidth = this.scrollbarWidth; // Adjust fixed content padding
/* istanbul ignore next: difficult to test in JSDOM */
(0, _dom.selectAll)(Selector.FIXED_CONTENT).forEach(function (el) {
var actualPadding = el.style.paddingRight;
var calculatedPadding = (0, _dom.getCS)(el).paddingRight || 0;
(0, _dom.setAttr)(el, 'data-padding-right', actualPadding);
el.style.paddingRight = "".concat(parseFloat(calculatedPadding) + scrollbarWidth, "px");
body._paddingChangedForModal.push(el);
}); // Adjust sticky content margin
/* istanbul ignore next: difficult to test in JSDOM */
(0, _dom.selectAll)(Selector.STICKY_CONTENT).forEach(function (el) {
var actualMargin = el.style.marginRight;
var calculatedMargin = (0, _dom.getCS)(el).marginRight || 0;
(0, _dom.setAttr)(el, 'data-margin-right', actualMargin);
el.style.marginRight = "".concat(parseFloat(calculatedMargin) - scrollbarWidth, "px");
body._marginChangedForModal.push(el);
}); // Adjust <b-navbar-toggler> margin
/* istanbul ignore next: difficult to test in JSDOM */
(0, _dom.selectAll)(Selector.NAVBAR_TOGGLER).forEach(function (el) {
var actualMargin = el.style.marginRight;
var calculatedMargin = (0, _dom.getCS)(el).marginRight || 0;
(0, _dom.setAttr)(el, 'data-margin-right', actualMargin);
el.style.marginRight = "".concat(parseFloat(calculatedMargin) + scrollbarWidth, "px");
body._marginChangedForModal.push(el);
}); // Adjust body padding
var actualPadding = body.style.paddingRight;
var calculatedPadding = (0, _dom.getCS)(body).paddingRight;
(0, _dom.setAttr)(body, 'data-padding-right', actualPadding);
body.style.paddingRight = "".concat(parseFloat(calculatedPadding) + scrollbarWidth, "px");
}
},
resetScrollbar: function resetScrollbar() {
var body = document.body;
if (body._paddingChangedForModal) {
// Restore fixed content padding
body._paddingChangedForModal.forEach(function (el) {
/* istanbul ignore next: difficult to test in JSDOM */
if ((0, _dom.hasAttr)(el, 'data-padding-right')) {
el.style.paddingRight = (0, _dom.getAttr)(el, 'data-padding-right') || '';
(0, _dom.removeAttr)(el, 'data-padding-right');
}
});
}
if (body._marginChangedForModal) {
// Restore sticky content and navbar-toggler margin
body._marginChangedForModal.forEach(function (el) {
/* istanbul ignore next: difficult to test in JSDOM */
if ((0, _dom.hasAttr)(el, 'data-margin-right')) {
el.style.marginRight = (0, _dom.getAttr)(el, 'data-margin-right') || '';
(0, _dom.removeAttr)(el, 'data-margin-right');
}
});
}
body._paddingChangedForModal = null;
body._marginChangedForModal = null; // Restore body padding
if ((0, _dom.hasAttr)(body, 'data-padding-right')) {
body.style.paddingRight = (0, _dom.getAttr)(body, 'data-padding-right') || '';
(0, _dom.removeAttr)(body, 'data-padding-right');
}
}
}
}); // Export our ModalManager
var _default = new ModalManager();
exports.default = _default;