vue-material/src/components/mdDialog/mdDialog.vue
2016-11-25 17:10:40 -02:00

146 lines
4.2 KiB
Vue

<template>
<div class="md-dialog-container" :class="classes" @keyup.esc="mdEscToClose && close()" tabindex="0">
<div class="md-dialog" ref="dialog" :style="styles" :class="dialogClasses">
<slot></slot>
</div>
<md-backdrop class="md-dialog-backdrop" :class="classes" v-if="mdBackdrop" ref="backdrop" @close="mdClickOutsideToClose && close()"></md-backdrop>
</div>
</template>
<style lang="scss" src="./mdDialog.scss"></style>
<script>
import transitionEndEventName from '../../core/utils/transitionEndEventName';
export default {
props: {
mdClickOutsideToClose: {
type: Boolean,
default: true
},
mdEscToClose: {
type: Boolean,
default: true
},
mdBackdrop: {
type: Boolean,
default: true
},
mdOpenFrom: String,
mdCloseTo: String,
mdFullscreen: {
type: Boolean,
default: false
}
},
data: () => ({
active: false,
transitionOff: false,
dialogTransform: ''
}),
computed: {
classes() {
return {
'md-active': this.active
};
},
dialogClasses() {
return {
'md-fullscreen': this.mdFullscreen,
'md-transition-off': this.transitionOff,
'md-reference': this.mdOpenFrom || this.mdCloseTo
};
},
styles() {
return {
transform: this.dialogTransform
};
}
},
methods: {
removeDialog() {
if (this.rootElement.contains(this.dialogElement)) {
this.$el.parentNode.removeChild(this.$el);
}
},
calculateDialogPos(ref) {
const reference = document.querySelector(ref);
if (reference) {
const openFromRect = reference.getBoundingClientRect();
const dialogRect = this.dialogInnerElement.getBoundingClientRect();
const widthInScale = openFromRect.width / dialogRect.width;
const heightInScale = openFromRect.height / dialogRect.height;
let distance = {
top: -(dialogRect.top - openFromRect.top),
left: -(dialogRect.left - openFromRect.left + openFromRect.width)
};
if (openFromRect.top > dialogRect.top + dialogRect.height) {
distance.top = openFromRect.top - dialogRect.top;
}
if (openFromRect.left > dialogRect.left + dialogRect.width) {
distance.left = openFromRect.left - dialogRect.left - openFromRect.width;
}
this.dialogTransform = `translate3D(${distance.left}px, ${distance.top}px, 0) scale(${widthInScale}, ${heightInScale})`;
}
},
open() {
this.rootElement.appendChild(this.dialogElement);
this.transitionOff = true;
this.calculateDialogPos(this.mdOpenFrom);
window.setTimeout(() => {
this.dialogElement.focus();
this.transitionOff = false;
this.active = true;
});
this.$emit('open');
},
close() {
if (this.rootElement.contains(this.dialogElement)) {
this.$nextTick(() => {
let cleanElement = () => {
let activeRipple = this.dialogElement.querySelector('.md-ripple.md-active');
if (activeRipple) {
activeRipple.classList.remove('md-active');
}
this.dialogInnerElement.removeEventListener(transitionEndEventName, cleanElement);
this.rootElement.removeChild(this.dialogElement);
this.dialogTransform = '';
};
this.transitionOff = true;
this.dialogTransform = '';
this.calculateDialogPos(this.mdCloseTo);
window.setTimeout(() => {
this.transitionOff = false;
this.active = false;
this.dialogInnerElement.addEventListener(transitionEndEventName, cleanElement);
});
this.$emit('close');
});
}
}
},
mounted() {
this.$nextTick(() => {
this.rootElement = this.$root.$el;
this.dialogElement = this.$el;
this.dialogInnerElement = this.$refs.dialog;
this.removeDialog();
});
},
beforeDestroy() {
this.removeDialog();
}
};
</script>