silk-gui
Version:
GUI for developers and Node OS
166 lines (156 loc) • 4.26 kB
JavaScript
var _ = require('../util')
var Directive = require('../directive')
var compile = require('../compiler/compile')
var transclude = require('../compiler/transclude')
/**
* Transclude, compile and link element.
*
* If a pre-compiled linker is available, that means the
* passed in element will be pre-transcluded and compiled
* as well - all we need to do is to call the linker.
*
* Otherwise we need to call transclude/compile/link here.
*
* @param {Element} el
* @return {Element}
*/
exports._compile = function (el) {
var options = this.$options
if (options._linkFn) {
// pre-transcluded with linker, just use it
this._initElement(el)
options._linkFn(this, el)
} else {
// transclude and init element
// transclude can potentially replace original
// so we need to keep reference
var original = el
el = transclude(el, options)
this._initElement(el)
// compile and link the rest
compile(el, options)(this, el)
// finally replace original
if (options.replace) {
_.replace(original, el)
}
}
return el
}
/**
* Initialize instance element. Called in the public
* $mount() method.
*
* @param {Element} el
*/
exports._initElement = function (el) {
if (el instanceof DocumentFragment) {
this._isBlock = true
this.$el = this._blockStart = el.firstChild
this._blockEnd = el.lastChild
this._blockFragment = el
} else {
this.$el = el
}
this.$el.__vue__ = this
this._callHook('beforeCompile')
}
/**
* Create and bind a directive to an element.
*
* @param {String} name - directive name
* @param {Node} node - target node
* @param {Object} desc - parsed directive descriptor
* @param {Object} def - directive definition object
* @param {Vue|undefined} host - transclusion host component
*/
exports._bindDir = function (name, node, desc, def, host) {
this._directives.push(
new Directive(name, node, this, desc, def, host)
)
}
/**
* Teardown an instance, unobserves the data, unbind all the
* directives, turn off all the event listeners, etc.
*
* @param {Boolean} remove - whether to remove the DOM node.
* @param {Boolean} deferCleanup - if true, defer cleanup to
* be called later
*/
exports._destroy = function (remove, deferCleanup) {
if (this._isBeingDestroyed) {
return
}
this._callHook('beforeDestroy')
this._isBeingDestroyed = true
var i
// remove self from parent. only necessary
// if parent is not being destroyed as well.
var parent = this.$parent
if (parent && !parent._isBeingDestroyed) {
i = parent._children.indexOf(this)
parent._children.splice(i, 1)
}
// same for transclusion host.
var host = this._host
if (host && !host._isBeingDestroyed) {
i = host._transCpnts.indexOf(this)
host._transCpnts.splice(i, 1)
}
// destroy all children.
i = this._children.length
while (i--) {
this._children[i].$destroy()
}
// teardown all directives. this also tearsdown all
// directive-owned watchers. intentionally check for
// directives array length on every loop since directives
// that manages partial compilation can splice ones out
for (i = 0; i < this._directives.length; i++) {
this._directives[i]._teardown()
}
// teardown all user watchers.
var watcher
for (i in this._userWatchers) {
watcher = this._userWatchers[i]
if (watcher) {
watcher.teardown()
}
}
// remove reference to self on $el
if (this.$el) {
this.$el.__vue__ = null
}
// remove DOM element
var self = this
if (remove && this.$el) {
this.$remove(function () {
self._cleanup()
})
} else if (!deferCleanup) {
this._cleanup()
}
}
/**
* Clean up to ensure garbage collection.
* This is called after the leave transition if there
* is any.
*/
exports._cleanup = function () {
// remove reference from data ob
this._data.__ob__.removeVm(this)
this._data =
this._watchers =
this._userWatchers =
this._watcherList =
this.$el =
this.$parent =
this.$root =
this._children =
this._transCpnts =
this._directives = null
// call the last hook...
this._isDestroyed = true
this._callHook('destroyed')
// turn off all instance listeners.
this.$off()
}