UNPKG

vuetify-multiple-draggable-dialogs

Version:

A mixin that gives ability to have multiple active draggable dialogs

161 lines (138 loc) 4.65 kB
const container = {}; const wrappersSelector = '.v-dialog__content.v-dialog__content--active'; const dialogSelector = '.v-dialog.v-dialog--active'; /** * Find the closest dialog * @param event */ function closestDialog(event) { // check for left click if (event.button !== 0) { return; } let dialog; // target must contain one of provided classes ['v-card__title', 'v-toolbar__content', 'v-toolbar__title'].forEach((className) => { if (event.target.classList.contains(className)) { dialog = event.target.closest(dialogSelector); } }); return dialog } /** * Make current dialog above the rest by switching their z-indexes * @param event */ function makeDialogAbove(event) { const wrappers = document.querySelectorAll(wrappersSelector); const activeWrapper = event.target.closest(wrappersSelector); // if we clicked on non-related element if (!activeWrapper) { return false; } // list of all z-indexes of wrappers let indexes = []; // collect all the indexes wrappers.forEach((element) => { indexes.push(parseInt(element.style.zIndex)); }); const maxIndex = Math.max(...indexes); const currentIndex = parseInt(activeWrapper.style.zIndex); // if z-index of current active dialog is less than we will switch them // to make this dialog above the rest if (currentIndex < maxIndex) { wrappers.forEach((element) => { if (parseInt(element.style.zIndex) === maxIndex) { element.style.zIndex = currentIndex.toString(); activeWrapper.style.zIndex = maxIndex.toString(); } }); } } /** * Assign main styles * @param event */ function setStyles(event) { const dialog = closestDialog(event); if (dialog) { container.el = dialog; container.mouseStartX = event.clientX; container.mouseStartY = event.clientY; container.elStartX = container.el.getBoundingClientRect().left; container.elStartY = container.el.getBoundingClientRect().top; container.el.style.position = 'fixed'; container.el.style.margin = '0px'; container.oldTransition = container.el.style.transition; container.el.style.transition = 'none'; } } /** * Prevent out of bounds */ function alignDialog() { const dialog = document.querySelector(dialogSelector); if (dialog === null) return; const styleLeft = parseInt(dialog.style.left); const styleTop = parseInt(dialog.style.top); const boundingWidth = dialog.getBoundingClientRect().width; const boundingHeight = dialog.getBoundingClientRect().height; const left = Math.min(styleLeft, window.innerWidth - boundingWidth); const top = Math.min(styleTop, window.innerHeight - boundingHeight); let borderLeft = 0; let borderTop = 0; // we need to add some borders to center the dialog once the window has resized if (styleLeft > window.innerWidth) { borderLeft = left / 2; } if (styleTop + boundingHeight > window.innerHeight) { borderTop = (window.innerHeight - boundingHeight) / 2; } dialog.style.left = (left - borderLeft) + 'px'; dialog.style.top = (top - borderTop) + 'px'; } /** * Move the dialog by mouse cursor * @param event */ function moveDialog(event) { if (container.el) { container.el.style.left = Math.min( Math.max(container.elStartX + event.clientX - container.mouseStartX, 0), window.innerWidth - container.el.getBoundingClientRect().width ) + 'px'; container.el.style.top = Math.min( Math.max(container.elStartY + event.clientY - container.mouseStartY, 0), window.innerHeight - container.el.getBoundingClientRect().height ) + 'px'; } } /** * Return the initial transition * @param event */ function setTransitionBack(event) { if (container.el) { container.el.style.transition = container.oldTransition; container.el = undefined; } } module.exports = { methods: { activateMultipleDraggableDialogs() { document.addEventListener('mousedown', (event) => { makeDialogAbove(event); setStyles(event); }); document.addEventListener('mousemove', (event) => { moveDialog(event); }); document.addEventListener('mouseup', (event) => { setTransitionBack(event); }); setInterval(() => { alignDialog(); }, 500); } } };