quasar-framework
Version:
Simultaneously build desktop/mobile SPA websites & phone/tablet apps with VueJS
236 lines (221 loc) • 5.26 kB
JavaScript
import EscapeKey from '../../utils/escape-key'
import extend from '../../utils/extend'
import ModelToggleMixin from '../../mixins/model-toggle'
const positions = {
top: 'items-start justify-center with-backdrop',
bottom: 'items-end justify-center with-backdrop',
right: 'items-center justify-end with-backdrop',
left: 'items-center justify-start with-backdrop'
}
const positionCSS = __THEME__ === 'mat'
? {
maxHeight: '80vh',
height: 'auto'
}
: {
maxHeight: '80vh',
height: 'auto',
boxShadow: 'none'
}
function additionalCSS (position) {
let css = {}
if (['left', 'right'].includes(position)) {
css.maxWidth = '90vw'
}
if (__THEME__ === 'ios') {
if (['left', 'top'].includes(position)) {
css.borderTopLeftRadius = 0
}
if (['right', 'top'].includes(position)) {
css.borderTopRightRadius = 0
}
if (['left', 'bottom'].includes(position)) {
css.borderBottomLeftRadius = 0
}
if (['right', 'bottom'].includes(position)) {
css.borderBottomRightRadius = 0
}
}
return css
}
let openedModalNumber = 0
export default {
name: 'q-modal',
mixins: [ModelToggleMixin],
provide () {
return {
__qmodal: true
}
},
props: {
position: {
type: String,
default: '',
validator (val) {
return val === '' || ['top', 'bottom', 'left', 'right'].includes(val)
}
},
transition: String,
enterClass: String,
leaveClass: String,
positionClasses: {
type: String,
default: 'flex-center'
},
contentClasses: [Object, Array, String],
contentCss: [Object, Array, String],
noBackdropDismiss: {
type: Boolean,
default: false
},
noEscDismiss: {
type: Boolean,
default: false
},
noRouteDismiss: Boolean,
minimized: Boolean,
maximized: Boolean
},
watch: {
$route () {
if (!this.noRouteDismiss) {
this.hide()
}
}
},
computed: {
modalClasses () {
const cls = this.position
? positions[this.position]
: this.positionClasses
if (this.maximized) {
return ['maximized', cls]
}
else if (this.minimized) {
return ['minimized', cls]
}
return cls
},
transitionProps () {
if (this.position) {
return { name: `q-modal-${this.position}` }
}
if (this.enterClass === void 0 && this.leaveClass === void 0) {
return { name: this.transition || 'q-modal' }
}
return {
enterActiveClass: this.enterClass,
leaveActiveClass: this.leaveClass
}
},
modalCss () {
if (this.position) {
const css = Array.isArray(this.contentCss)
? this.contentCss
: [this.contentCss]
css.unshift(extend(
{},
positionCSS,
additionalCSS(this.position)
))
return css
}
return this.contentCss
}
},
methods: {
__dismiss () {
if (this.noBackdropDismiss) {
return
}
this.hide().then(() => {
this.$emit('dismiss')
})
},
__show () {
const body = document.body
body.appendChild(this.$el)
if (openedModalNumber === 0) {
body.classList.add('with-modal')
}
EscapeKey.register(() => {
if (!this.noEscDismiss) {
this.hide().then(() => {
this.$emit('escape-key')
})
}
})
openedModalNumber++
let content = this.$refs.content
content.scrollTop = 0
;['modal-scroll', 'layout-view'].forEach(c => {
[].slice.call(content.getElementsByClassName(c)).forEach(el => {
el.scrollTop = 0
})
})
},
__hide () {
EscapeKey.pop()
openedModalNumber--
if (openedModalNumber === 0) {
document.body.classList.remove('with-modal')
}
}
},
mounted () {
if (this.value) {
this.show()
}
},
beforeDestroy () {
if (this.$el.parentNode) {
this.$el.parentNode.removeChild(this.$el)
}
},
render (h) {
return h('transition', {
props: this.transitionProps,
on: {
afterEnter: () => {
this.showPromise && this.showPromiseResolve()
},
enterCancelled: () => {
this.showPromise && this.showPromiseReject()
},
afterLeave: () => {
this.hidePromise && this.hidePromiseResolve()
},
leaveCancelled: () => {
this.hidePromise && this.hidePromiseReject()
}
}
}, [
h('div', {
staticClass: 'modal fullscreen row',
'class': this.modalClasses,
on: {
click: this.__dismiss
},
directives: [{
name: 'show',
value: this.showing
}]
}, [
h('div', {
ref: 'content',
staticClass: 'modal-content scroll',
style: this.modalCss,
'class': this.contentClasses,
on: {
click (e) {
e.stopPropagation()
},
touchstart (e) {
e.stopPropagation()
}
}
}, [ this.$slots.default ])
])
])
}
}