Fixed #85 - Draggable Dialog
parent
2acf800b43
commit
fa39c21c34
|
@ -100,7 +100,31 @@ const DialogProps = [
|
||||||
type: "object",
|
type: "object",
|
||||||
default: "null",
|
default: "null",
|
||||||
description: "Object literal to define widths per screen size."
|
description: "Object literal to define widths per screen size."
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
name: "draggable",
|
||||||
|
type: "boolean",
|
||||||
|
default: "true",
|
||||||
|
description: "Whether the dialog can be displayed full screen."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "minX",
|
||||||
|
type: "number",
|
||||||
|
default: "0",
|
||||||
|
description: "Minimum value for the left coordinate of dialog in dragging."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "minY",
|
||||||
|
type: "number",
|
||||||
|
default: "0",
|
||||||
|
description: "Minimum value for the top coordinate of dialog in dragging."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "keepInViewport",
|
||||||
|
type: "boolean",
|
||||||
|
default: "true",
|
||||||
|
description: "Keeps dialog in the viewport when dragging."
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const DialogEvents = [
|
const DialogEvents = [
|
||||||
|
|
|
@ -18,6 +18,10 @@ interface DialogProps {
|
||||||
position?: string;
|
position?: string;
|
||||||
maximizable?: boolean;
|
maximizable?: boolean;
|
||||||
breakpoints?: {[key: string]: string};
|
breakpoints?: {[key: string]: string};
|
||||||
|
draggable: boolean;
|
||||||
|
keepInViewPort: boolean;
|
||||||
|
minX: number;
|
||||||
|
minY: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare class Dialog {
|
declare class Dialog {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<div :ref="maskRef" :class="maskClass" v-if="containerVisible" @click="onMaskClick">
|
<div :ref="maskRef" :class="maskClass" v-if="containerVisible" @click="onMaskClick">
|
||||||
<transition name="p-dialog" @before-enter="onBeforeEnter" @enter="onEnter" @before-leave="onBeforeLeave" @leave="onLeave" @after-leave="onAfterLeave" appear>
|
<transition name="p-dialog" @before-enter="onBeforeEnter" @enter="onEnter" @before-leave="onBeforeLeave" @leave="onLeave" @after-leave="onAfterLeave" appear>
|
||||||
<div :ref="containerRef" :class="dialogClass" v-if="visible" v-bind="$attrs" role="dialog" :aria-labelledby="ariaLabelledById" :aria-modal="modal">
|
<div :ref="containerRef" :class="dialogClass" v-if="visible" v-bind="$attrs" role="dialog" :aria-labelledby="ariaLabelledById" :aria-modal="modal">
|
||||||
<div class="p-dialog-header" v-if="showHeader">
|
<div class="p-dialog-header" v-if="showHeader" @mousedown="initDrag">
|
||||||
<slot name="header">
|
<slot name="header">
|
||||||
<span :id="ariaLabelledById" class="p-dialog-title" v-if="header">{{header}}</span>
|
<span :id="ariaLabelledById" class="p-dialog-title" v-if="header">{{header}}</span>
|
||||||
</slot>
|
</slot>
|
||||||
|
@ -35,7 +35,7 @@ import Ripple from 'primevue/ripple';
|
||||||
export default {
|
export default {
|
||||||
name: 'Dialog',
|
name: 'Dialog',
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
emits: ['update:visible','show','hide','maximize','unmaximize'],
|
emits: ['update:visible','show','hide','maximize','unmaximize','dragend'],
|
||||||
props: {
|
props: {
|
||||||
header: null,
|
header: null,
|
||||||
footer: null,
|
footer: null,
|
||||||
|
@ -77,6 +77,22 @@ export default {
|
||||||
breakpoints: {
|
breakpoints: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: null
|
default: null
|
||||||
|
},
|
||||||
|
draggable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
keepInViewport: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
minX: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
minY: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
@ -89,6 +105,11 @@ export default {
|
||||||
container: null,
|
container: null,
|
||||||
mask: null,
|
mask: null,
|
||||||
styleElement: null,
|
styleElement: null,
|
||||||
|
dragging: null,
|
||||||
|
documentDragListener: null,
|
||||||
|
documentDragEndListener: null,
|
||||||
|
lastPageX: null,
|
||||||
|
lastPageY: null,
|
||||||
updated() {
|
updated() {
|
||||||
if (this.visible) {
|
if (this.visible) {
|
||||||
this.containerVisible = this.visible;
|
this.containerVisible = this.visible;
|
||||||
|
@ -96,6 +117,7 @@ export default {
|
||||||
},
|
},
|
||||||
beforeUnmount() {
|
beforeUnmount() {
|
||||||
this.unbindDocumentState();
|
this.unbindDocumentState();
|
||||||
|
this.unbindGlobalListeners();
|
||||||
this.destroyStyle();
|
this.destroyStyle();
|
||||||
|
|
||||||
this.mask = null;
|
this.mask = null;
|
||||||
|
@ -127,11 +149,13 @@ export default {
|
||||||
this.$emit('show');
|
this.$emit('show');
|
||||||
this.focus();
|
this.focus();
|
||||||
this.enableDocumentSettings();
|
this.enableDocumentSettings();
|
||||||
|
this.bindGlobalListeners();
|
||||||
},
|
},
|
||||||
onBeforeLeave() {
|
onBeforeLeave() {
|
||||||
DomHandler.addClass(this.mask, 'p-dialog-mask-leave');
|
DomHandler.addClass(this.mask, 'p-dialog-mask-leave');
|
||||||
},
|
},
|
||||||
onLeave() {
|
onLeave() {
|
||||||
|
|
||||||
this.$emit('hide');
|
this.$emit('hide');
|
||||||
},
|
},
|
||||||
onAfterLeave(el) {
|
onAfterLeave(el) {
|
||||||
|
@ -140,6 +164,7 @@ export default {
|
||||||
}
|
}
|
||||||
this.containerVisible = false;
|
this.containerVisible = false;
|
||||||
this.unbindDocumentState();
|
this.unbindDocumentState();
|
||||||
|
this.unbindGlobalListeners();
|
||||||
},
|
},
|
||||||
onMaskClick(event) {
|
onMaskClick(event) {
|
||||||
if (this.dismissableMask && this.closable && this.modal && this.mask === event.target) {
|
if (this.dismissableMask && this.closable && this.modal && this.mask === event.target) {
|
||||||
|
@ -264,6 +289,88 @@ export default {
|
||||||
document.head.removeChild(this.styleElement);
|
document.head.removeChild(this.styleElement);
|
||||||
this.styleElement = null;
|
this.styleElement = null;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
initDrag(event) {
|
||||||
|
if (DomHandler.hasClass(event.target, 'p-dialog-header-icon') || DomHandler.hasClass(event.target.parentElement, 'p-dialog-header-icon')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.draggable) {
|
||||||
|
this.dragging = true;
|
||||||
|
this.lastPageX = event.pageX;
|
||||||
|
this.lastPageY = event.pageY;
|
||||||
|
|
||||||
|
this.container.style.margin = '0';
|
||||||
|
DomHandler.addClass(document.body, 'p-unselectable-text');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
bindGlobalListeners() {
|
||||||
|
if (this.draggable) {
|
||||||
|
this.bindDocumentDragListener();
|
||||||
|
this.bindDocumentDragEndListener();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
unbindGlobalListeners() {
|
||||||
|
this.unbindDocumentDragListener();
|
||||||
|
this.unbindDocumentDragEndListener();
|
||||||
|
},
|
||||||
|
bindDocumentDragListener() {
|
||||||
|
this.documentDragListener = (event) => {
|
||||||
|
if (this.dragging) {
|
||||||
|
let width = DomHandler.getOuterWidth(this.container);
|
||||||
|
let height = DomHandler.getOuterHeight(this.container);
|
||||||
|
let deltaX = event.pageX - this.lastPageX;
|
||||||
|
let deltaY = event.pageY - this.lastPageY;
|
||||||
|
let offset = this.container.getBoundingClientRect();
|
||||||
|
let leftPos = offset.left + deltaX;
|
||||||
|
let topPos = offset.top + deltaY;
|
||||||
|
let viewport = DomHandler.getViewport();
|
||||||
|
|
||||||
|
this.container.style.position = 'fixed';
|
||||||
|
|
||||||
|
if (this.keepInViewport) {
|
||||||
|
if (leftPos >= this.minX && (leftPos + width) < viewport.width) {
|
||||||
|
this.lastPageX = event.pageX;
|
||||||
|
this.container.style.left = leftPos + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (topPos >= this.minY && (topPos + height) < viewport.height) {
|
||||||
|
this.lastPageY = event.pageY;
|
||||||
|
this.container.style.top = topPos + 'px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.lastPageX = event.pageX;
|
||||||
|
this.container.style.left = leftPos + 'px';
|
||||||
|
this.lastPageY = event.pageY;
|
||||||
|
this.container.style.top = topPos + 'px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window.document.addEventListener('mousemove', this.documentDragListener);
|
||||||
|
},
|
||||||
|
unbindDocumentDragListener() {
|
||||||
|
if (this.documentDragListener) {
|
||||||
|
window.document.removeEventListener('mousemove', this.documentDragListener);
|
||||||
|
this.documentDragListener = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
bindDocumentDragEndListener() {
|
||||||
|
this.documentDragEndListener = (event) => {
|
||||||
|
if (this.dragging) {
|
||||||
|
this.dragging = false;
|
||||||
|
DomHandler.removeClass(document.body, 'p-unselectable-text');
|
||||||
|
|
||||||
|
this.$emit('dragend', event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
window.document.addEventListener('mouseup', this.documentDragEndListener);
|
||||||
|
},
|
||||||
|
unbindDocumentDragEndListener() {
|
||||||
|
if (this.documentDragEndListener) {
|
||||||
|
window.document.removeEventListener('mouseup', this.documentDragEndListener);
|
||||||
|
this.documentDragEndListener = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
|
@ -197,6 +197,30 @@ export default {
|
||||||
<td>object</td>
|
<td>object</td>
|
||||||
<td>null</td>
|
<td>null</td>
|
||||||
<td>Object literal to define widths per screen size.</td>
|
<td>Object literal to define widths per screen size.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>draggable</td>
|
||||||
|
<td>boolean</td>
|
||||||
|
<td>true</td>
|
||||||
|
<td>Enables dragging to change the position using header.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>minX</td>
|
||||||
|
<td>number</td>
|
||||||
|
<td>0</td>
|
||||||
|
<td>Minimum value for the left coordinate of dialog in dragging.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>minY</td>
|
||||||
|
<td>number</td>
|
||||||
|
<td>0</td>
|
||||||
|
<td>Minimum value for the top coordinate of dialog in dragging.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>keepInViewport</td>
|
||||||
|
<td>boolean</td>
|
||||||
|
<td>true</td>
|
||||||
|
<td>Keeps dialog in the viewport when dragging.</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
Loading…
Reference in New Issue