silk-gui
Version:
GUI for developers and Node OS
230 lines (207 loc) • 5.31 kB
JavaScript
var _ = require('../util')
var templateParser = require('../parsers/template')
module.exports = {
isLiteral: true,
/**
* Setup. Two possible usages:
*
* - static:
* v-component="comp"
*
* - dynamic:
* v-component="{{currentView}}"
*/
bind: function () {
if (!this.el.__vue__) {
// create a ref anchor
this.ref = document.createComment('v-component')
_.replace(this.el, this.ref)
// check keep-alive options.
// If yes, instead of destroying the active vm when
// hiding (v-if) or switching (dynamic literal) it,
// we simply remove it from the DOM and save it in a
// cache object, with its constructor id as the key.
this.keepAlive = this._checkParam('keep-alive') != null
// check ref
this.refID = _.attr(this.el, 'ref')
if (this.keepAlive) {
this.cache = {}
}
// check inline-template
if (this._checkParam('inline-template') !== null) {
// extract inline template as a DocumentFragment
this.template = _.extractContent(this.el, true)
}
// if static, build right now.
if (!this._isDynamicLiteral) {
this.resolveCtor(this.expression)
var child = this.build()
child.$before(this.ref)
this.setCurrent(child)
} else {
// check dynamic component params
this.readyEvent = this._checkParam('wait-for')
this.transMode = this._checkParam('transition-mode')
}
} else {
_.warn(
'v-component="' + this.expression + '" cannot be ' +
'used on an already mounted instance.'
)
}
},
/**
* Resolve the component constructor to use when creating
* the child vm.
*/
resolveCtor: function (id) {
this.ctorId = id
this.Ctor = this.vm.$options.components[id]
_.assertAsset(this.Ctor, 'component', id)
},
/**
* Instantiate/insert a new child vm.
* If keep alive and has cached instance, insert that
* instance; otherwise build a new one and cache it.
*
* @return {Vue} - the created instance
*/
build: function () {
if (this.keepAlive) {
var cached = this.cache[this.ctorId]
if (cached) {
return cached
}
}
var vm = this.vm
var el = templateParser.clone(this.el)
if (this.Ctor) {
var child = vm.$addChild({
el: el,
template: this.template,
_asComponent: true,
_host: this._host
}, this.Ctor)
if (this.keepAlive) {
this.cache[this.ctorId] = child
}
return child
}
},
/**
* Teardown the current child, but defers cleanup so
* that we can separate the destroy and removal steps.
*/
unbuild: function () {
var child = this.childVM
if (!child || this.keepAlive) {
return
}
// the sole purpose of `deferCleanup` is so that we can
// "deactivate" the vm right now and perform DOM removal
// later.
child.$destroy(false, true)
},
/**
* Remove current destroyed child and manually do
* the cleanup after removal.
*
* @param {Function} cb
*/
remove: function (child, cb) {
var keepAlive = this.keepAlive
if (child) {
child.$remove(function () {
if (!keepAlive) child._cleanup()
if (cb) cb()
})
} else if (cb) {
cb()
}
},
/**
* Update callback for the dynamic literal scenario,
* e.g. v-component="{{view}}"
*/
update: function (value) {
if (!value) {
// just destroy and remove current
this.unbuild()
this.remove(this.childVM)
this.unsetCurrent()
} else {
this.resolveCtor(value)
this.unbuild()
var newComponent = this.build()
var self = this
if (this.readyEvent) {
newComponent.$once(this.readyEvent, function () {
self.swapTo(newComponent)
})
} else {
this.swapTo(newComponent)
}
}
},
/**
* Actually swap the components, depending on the
* transition mode. Defaults to simultaneous.
*
* @param {Vue} target
*/
swapTo: function (target) {
var self = this
var current = this.childVM
this.unsetCurrent()
this.setCurrent(target)
switch (self.transMode) {
case 'in-out':
target.$before(self.ref, function () {
self.remove(current)
})
break
case 'out-in':
self.remove(current, function () {
target.$before(self.ref)
})
break
default:
self.remove(current)
target.$before(self.ref)
}
},
/**
* Set childVM and parent ref
*/
setCurrent: function (child) {
this.childVM = child
var refID = child._refID || this.refID
if (refID) {
this.vm.$[refID] = child
}
},
/**
* Unset childVM and parent ref
*/
unsetCurrent: function () {
var child = this.childVM
this.childVM = null
var refID = (child && child._refID) || this.refID
if (refID) {
this.vm.$[refID] = null
}
},
/**
* Unbind.
*/
unbind: function () {
this.unbuild()
// destroy all keep-alive cached instances
if (this.cache) {
for (var key in this.cache) {
this.cache[key].$destroy()
}
this.cache = null
}
}
}