PHP Classes

File: public/js/lib/vue/src/directive.js

Recommend this page to a friend!
  Classes of Sergey Beskorovayniy   Silex MVC Blog   public/js/lib/vue/src/directive.js   Download  
File: public/js/lib/vue/src/directive.js
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: Silex MVC Blog
MVC based blog using on the Silex micro-framework
Author: By
Last change:
Date: 7 years ago
Size: 8,060 bytes
 

Contents

Class file image Download
import { extend, bind, on, off, getAttr, getBindAttr, camelize, hyphenate, nextTick, warn } from './util/index' import Watcher from './watcher' import { parseExpression, isSimplePath } from './parsers/expression' function noop () {} /** * A directive links a DOM element with a piece of data, * which is the result of evaluating an expression. * It registers a watcher with the expression and calls * the DOM update function when a change is triggered. * * @param {Object} descriptor * - {String} name * - {Object} def * - {String} expression * - {Array<Object>} [filters] * - {Object} [modifiers] * - {Boolean} literal * - {String} attr * - {String} arg * - {String} raw * - {String} [ref] * - {Array<Object>} [interp] * - {Boolean} [hasOneTime] * @param {Vue} vm * @param {Node} el * @param {Vue} [host] - transclusion host component * @param {Object} [scope] - v-for scope * @param {Fragment} [frag] - owner fragment * @constructor */ export default function Directive (descriptor, vm, el, host, scope, frag) { this.vm = vm this.el = el // copy descriptor properties this.descriptor = descriptor this.name = descriptor.name this.expression = descriptor.expression this.arg = descriptor.arg this.modifiers = descriptor.modifiers this.filters = descriptor.filters this.literal = this.modifiers && this.modifiers.literal // private this._locked = false this._bound = false this._listeners = null // link context this._host = host this._scope = scope this._frag = frag // store directives on node in dev mode if (process.env.NODE_ENV !== 'production' && this.el) { this.el._vue_directives = this.el._vue_directives || [] this.el._vue_directives.push(this) } } /** * Initialize the directive, mixin definition properties, * setup the watcher, call definition bind() and update() * if present. */ Directive.prototype._bind = function () { var name = this.name var descriptor = this.descriptor // remove attribute if ( (name !== 'cloak' || this.vm._isCompiled) && this.el && this.el.removeAttribute ) { var attr = descriptor.attr || ('v-' + name) this.el.removeAttribute(attr) } // copy def properties var def = descriptor.def if (typeof def === 'function') { this.update = def } else { extend(this, def) } // setup directive params this._setupParams() // initial bind if (this.bind) { this.bind() } this._bound = true if (this.literal) { this.update && this.update(descriptor.raw) } else if ( (this.expression || this.modifiers) && (this.update || this.twoWay) && !this._checkStatement() ) { // wrapped updater for context var dir = this if (this.update) { this._update = function (val, oldVal) { if (!dir._locked) { dir.update(val, oldVal) } } } else { this._update = noop } var preProcess = this._preProcess ? bind(this._preProcess, this) : null var postProcess = this._postProcess ? bind(this._postProcess, this) : null var watcher = this._watcher = new Watcher( this.vm, this.expression, this._update, // callback { filters: this.filters, twoWay: this.twoWay, deep: this.deep, preProcess: preProcess, postProcess: postProcess, scope: this._scope } ) // v-model with inital inline value need to sync back to // model instead of update to DOM on init. They would // set the afterBind hook to indicate that. if (this.afterBind) { this.afterBind() } else if (this.update) { this.update(watcher.value) } } } /** * Setup all param attributes, e.g. track-by, * transition-mode, etc... */ Directive.prototype._setupParams = function () { if (!this.params) { return } var params = this.params // swap the params array with a fresh object. this.params = Object.create(null) var i = params.length var key, val, mappedKey while (i--) { key = hyphenate(params[i]) mappedKey = camelize(key) val = getBindAttr(this.el, key) if (val != null) { // dynamic this._setupParamWatcher(mappedKey, val) } else { // static val = getAttr(this.el, key) if (val != null) { this.params[mappedKey] = val === '' ? true : val } } } } /** * Setup a watcher for a dynamic param. * * @param {String} key * @param {String} expression */ Directive.prototype._setupParamWatcher = function (key, expression) { var self = this var called = false var unwatch = (this._scope || this.vm).$watch(expression, function (val, oldVal) { self.params[key] = val // since we are in immediate mode, // only call the param change callbacks if this is not the first update. if (called) { var cb = self.paramWatchers && self.paramWatchers[key] if (cb) { cb.call(self, val, oldVal) } } else { called = true } }, { immediate: true, user: false }) ;(this._paramUnwatchFns || (this._paramUnwatchFns = [])).push(unwatch) } /** * Check if the directive is a function caller * and if the expression is a callable one. If both true, * we wrap up the expression and use it as the event * handler. * * e.g. on-click="a++" * * @return {Boolean} */ Directive.prototype._checkStatement = function () { var expression = this.expression if ( expression && this.acceptStatement && !isSimplePath(expression) ) { var fn = parseExpression(expression).get var scope = this._scope || this.vm var handler = function (e) { scope.$event = e fn.call(scope, scope) scope.$event = null } if (this.filters) { handler = scope._applyFilters(handler, null, this.filters) } this.update(handler) return true } } /** * Set the corresponding value with the setter. * This should only be used in two-way directives * e.g. v-model. * * @param {*} value * @public */ Directive.prototype.set = function (value) { /* istanbul ignore else */ if (this.twoWay) { this._withLock(function () { this._watcher.set(value) }) } else if (process.env.NODE_ENV !== 'production') { warn( 'Directive.set() can only be used inside twoWay' + 'directives.' ) } } /** * Execute a function while preventing that function from * triggering updates on this directive instance. * * @param {Function} fn */ Directive.prototype._withLock = function (fn) { var self = this self._locked = true fn.call(self) nextTick(function () { self._locked = false }) } /** * Convenience method that attaches a DOM event listener * to the directive element and autometically tears it down * during unbind. * * @param {String} event * @param {Function} handler * @param {Boolean} [useCapture] */ Directive.prototype.on = function (event, handler, useCapture) { on(this.el, event, handler, useCapture) ;(this._listeners || (this._listeners = [])) .push([event, handler]) } /** * Teardown the watcher and call unbind. */ Directive.prototype._teardown = function () { if (this._bound) { this._bound = false if (this.unbind) { this.unbind() } if (this._watcher) { this._watcher.teardown() } var listeners = this._listeners var i if (listeners) { i = listeners.length while (i--) { off(this.el, listeners[i][0], listeners[i][1]) } } var unwatchFns = this._paramUnwatchFns if (unwatchFns) { i = unwatchFns.length while (i--) { unwatchFns[i]() } } if (process.env.NODE_ENV !== 'production' && this.el) { this.el._vue_directives.$remove(this) } this.vm = this.el = this._watcher = this._listeners = null } }