var _ = require('../util') var compiler = require('../compiler') var templateParser = require('../parsers/template') var transition = require('../transition') var Cache = require('../cache') var cache = new Cache(1000) module.exports = { bind: function () { var el = this.el if (!el.__vue__) { this.start = _.createAnchor('v-if-start') this.end = _.createAnchor('v-if-end') _.replace(el, this.end) _.before(this.start, this.end) if (_.isTemplate(el)) { this.template = templateParser.parse(el, true) } else { this.template = document.createDocumentFragment() this.template.appendChild(templateParser.clone(el)) } // compile the nested partial var cacheId = (this.vm.constructor.cid || '') + el.outerHTML this.linker = cache.get(cacheId) if (!this.linker) { this.linker = compiler.compile( this.template, this.vm.$options, true, // partial this._host // important ) cache.put(cacheId, this.linker) } } else { process.env.NODE_ENV !== 'production' && _.warn( 'v-if="' + this.expression + '" cannot be ' + 'used on an instance root element.' ) this.invalid = true } }, update: function (value) { if (this.invalid) return if (value) { // avoid duplicate compiles, since update() can be // called with different truthy values if (!this.unlink) { this.link( templateParser.clone(this.template), this.linker ) } } else { this.teardown() } }, link: function (frag, linker) { var vm = this.vm this.unlink = linker(vm, frag) transition.blockAppend(frag, this.end, vm) // call attached for all the child components created // during the compilation if (_.inDoc(vm.$el)) { var children = this.getContainedComponents() if (children) children.forEach(callAttach) } }, teardown: function () { if (!this.unlink) return // collect children beforehand var children if (_.inDoc(this.vm.$el)) { children = this.getContainedComponents() } transition.blockRemove(this.start, this.end, this.vm) if (children) children.forEach(callDetach) this.unlink() this.unlink = null }, getContainedComponents: function () { var vm = this.vm var start = this.start.nextSibling var end = this.end function contains (c) { var cur = start var next while (next !== end) { next = cur.nextSibling if ( cur === c.$el || cur.contains && cur.contains(c.$el) ) { return true } cur = next } return false } return vm.$children.length && vm.$children.filter(contains) }, unbind: function () { if (this.unlink) this.unlink() } } function callAttach (child) { if (!child._isAttached) { child._callHook('attached') } } function callDetach (child) { if (child._isAttached) { child._callHook('detached') } }