quasar
Version:
Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time
226 lines (182 loc) • 4.33 kB
JavaScript
import morph from '../utils/morph.js'
const morphGroups = {}
const props = [
'duration', 'delay', 'easing', 'fill',
'classes', 'style', 'duration', 'resize',
'useCSS', 'hideFromClone', 'keepToClone', 'tween',
'tweenFromOpacity', 'tweenToOpacity',
'waitFor', 'onEnd'
]
const mods = [
'resize', 'useCSS', 'hideFromClone', 'keepToClone', 'tween'
]
function changeClass (ctx, action) {
if (ctx.clsAction !== action) {
ctx.clsAction = action
ctx.el.classList[action]('q-morph--invisible')
}
}
function trigger (group) {
if (group.animating === true || group.queue.length < 2) {
return
}
const [ from, to ] = group.queue
group.animating = true
from.animating = true
to.animating = true
changeClass(from, 'remove')
changeClass(to, 'remove')
const cancelFn = morph({
from: from.el,
to: to.el,
onToggle () {
changeClass(from, 'add')
changeClass(to, 'remove')
},
...to.opts,
onEnd (dir, aborted) {
to.opts.onEnd !== void 0 && to.opts.onEnd(dir, aborted)
if (aborted === true) {
return
}
from.animating = false
to.animating = false
group.animating = false
group.cancel = void 0
group.queue.shift()
trigger(group)
}
})
group.cancel = () => {
cancelFn(true) // abort
group.cancel = void 0
}
}
function updateModifiers (mod, ctx) {
const opts = ctx.opts
mods.forEach(name => {
opts[name] = mod[name] === true
})
}
function insertArgs (arg, ctx) {
const opts = typeof arg === 'string' && arg.length > 0
? arg.split(':') : []
ctx.name = opts[0]
ctx.group = opts[1]
Object.assign(ctx.opts, {
duration: isNaN(opts[2]) === true
? 300
: parseFloat(opts[2]),
waitFor: opts[3]
})
}
function updateArgs (arg, ctx) {
if (arg.group !== void 0) {
ctx.group = arg.group
}
if (arg.name !== void 0) {
ctx.name = arg.name
}
const opts = ctx.opts
props.forEach(name => {
if (arg[name] !== void 0) {
opts[name] = arg[name]
}
})
}
function updateModel (name, ctx) {
if (ctx.name === name) {
const group = morphGroups[ctx.group]
// if group is not registered
if (group === void 0) {
morphGroups[ctx.group] = {
name: ctx.group,
model: name,
queue: [ ctx ],
animating: false
}
changeClass(ctx, 'remove')
}
// if model changed
else if (group.model !== name) {
group.model = name
group.queue.push(ctx)
if (group.animating === false && group.queue.length === 2) {
trigger(group)
}
}
return
}
if (ctx.animating === false) {
changeClass(ctx, 'add')
}
}
function updateValue (ctx, value) {
let model
if (Object(value) === value) {
model = '' + value.model
updateArgs(value, ctx)
updateModifiers(value, ctx)
}
else {
model = '' + value
}
if (model !== ctx.model) {
ctx.model = model
updateModel(model, ctx)
}
else if (ctx.animating === false && ctx.clsAction !== void 0) {
// ensure HMR
ctx.el.classList[ctx.clsAction]('q-morph--invisible')
}
}
function destroy (el) {
const ctx = el.__qmorph
if (ctx !== void 0) {
const group = morphGroups[ctx.group]
if (group !== void 0) {
const index = group.queue.indexOf(ctx)
if (index !== -1) {
group.queue = group.queue.filter(item => item !== ctx)
if (group.queue.length === 0) {
group.cancel !== void 0 && group.cancel()
delete morphGroups[ctx.group]
}
}
}
if (ctx.clsAction === 'add') {
el.classList.remove('q-morph--invisible')
}
delete el.__qmorph
}
}
export default {
name: 'morph',
inserted (el, binding) {
if (el.__qmorph !== void 0) {
destroy(el)
el.__qmorph_destroyed = true
}
const ctx = {
el,
animating: false,
opts: {}
}
updateModifiers(binding.modifiers, ctx)
insertArgs(binding.arg, ctx)
updateValue(ctx, binding.value)
el.__qmorph = ctx
},
update (el, binding) {
const ctx = el.__qmorph
ctx !== void 0 && updateValue(ctx, binding.value)
},
unbind (el) {
if (el.__qmorph_destroyed === void 0) {
destroy(el)
}
else {
delete el.__qmorph_destroyed
}
}
}