quasar
Version:
Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time
216 lines (181 loc) • 4.59 kB
JavaScript
import { h, ref, computed, nextTick, getCurrentInstance } from 'vue'
import QMenu from '../menu/QMenu.js'
import QBtn from '../btn/QBtn.js'
import { createComponent } from '../../utils/private.create/create.js'
import clone from '../../utils/clone/clone.js'
import { isDeepEqual } from '../../utils/is/is.js'
import { injectProp } from '../../utils/private.inject-obj-prop/inject-obj-prop.js'
export default createComponent({
name: 'QPopupEdit',
props: {
modelValue: {
required: true
},
title: String,
buttons: Boolean,
labelSet: String,
labelCancel: String,
color: {
type: String,
default: 'primary'
},
validate: {
type: Function,
default: () => true
},
autoSave: Boolean,
/* menu props overrides */
cover: {
type: Boolean,
default: true
},
/* end of menu props */
disable: Boolean
},
emits: [
'update:modelValue',
'save',
'cancel',
'beforeShow',
'show',
'beforeHide',
'hide'
],
setup(props, { slots, emit }) {
const { proxy } = getCurrentInstance()
const { $q } = proxy
const menuRef = ref(null)
const initialValue = ref('')
const currentModel = ref('')
let validated = false
const scope = computed(() =>
injectProp(
{
initialValue: initialValue.value,
validate: props.validate,
set,
cancel,
updatePosition
},
'value',
() => currentModel.value,
val => {
currentModel.value = val
}
)
)
function set() {
if (props.validate(currentModel.value) === false) return
if (hasModelChanged() === true) {
emit('save', currentModel.value, initialValue.value)
emit('update:modelValue', currentModel.value)
}
closeMenu()
}
function cancel() {
if (hasModelChanged() === true) {
emit('cancel', currentModel.value, initialValue.value)
}
closeMenu()
}
function updatePosition() {
nextTick(() => {
menuRef.value.updatePosition()
})
}
function hasModelChanged() {
return isDeepEqual(currentModel.value, initialValue.value) === false
}
function closeMenu() {
validated = true
menuRef.value.hide()
}
function onBeforeShow() {
validated = false
initialValue.value = clone(props.modelValue)
currentModel.value = clone(props.modelValue)
emit('beforeShow')
}
function onShow() {
emit('show')
}
function onBeforeHide() {
if (validated === false && hasModelChanged() === true) {
if (
props.autoSave === true &&
props.validate(currentModel.value) === true
) {
emit('save', currentModel.value, initialValue.value)
emit('update:modelValue', currentModel.value)
} else {
emit('cancel', currentModel.value, initialValue.value)
}
}
emit('beforeHide')
}
function onHide() {
emit('hide')
}
function getContent() {
const child =
slots.default !== void 0 ? [].concat(slots.default(scope.value)) : []
if (props.title) {
child.unshift(
h('div', { class: 'q-dialog__title q-mt-sm q-mb-sm' }, props.title)
)
}
if (props.buttons === true) {
child.push(
h(
'div',
{ class: 'q-popup-edit__buttons row justify-center no-wrap' },
[
h(QBtn, {
flat: true,
color: props.color,
label: props.labelCancel || $q.lang.label.cancel,
onClick: cancel
}),
h(QBtn, {
flat: true,
color: props.color,
label: props.labelSet || $q.lang.label.set,
onClick: set
})
]
)
)
}
return child
}
// expose public methods
Object.assign(proxy, {
set,
cancel,
show(e) {
menuRef.value?.show(e)
},
hide(e) {
menuRef.value?.hide(e)
},
updatePosition
})
return () => {
if (props.disable === true) return
return h(
QMenu,
{
ref: menuRef,
class: 'q-popup-edit',
cover: props.cover,
onBeforeShow,
onShow,
onBeforeHide,
onHide,
onEscapeKey: cancel
},
getContent
)
}
}
})