import Watcher from '../../watcher'
import { del, toArray } from '../../util/index'
import { parseText } from '../../parsers/text'
import { parseDirective } from '../../parsers/directive'
import { getPath } from '../../parsers/path'
import { parseExpression } from '../../parsers/expression'
const filterRE = /[^|]\|[^|]/
export default function (Vue) {
/**
* Get the value from an expression on this vm.
*
* @param {String} exp
* @param {Boolean} [asStatement]
* @return {*}
*/
Vue.prototype.$get = function (exp, asStatement) {
var res = parseExpression(exp)
if (res) {
if (asStatement) {
var self = this
return function statementHandler () {
self.$arguments = toArray(arguments)
var result = res.get.call(self, self)
self.$arguments = null
return result
}
} else {
try {
return res.get.call(this, this)
} catch (e) {}
}
}
}
/**
* Set the value from an expression on this vm.
* The expression must be a valid left-hand
* expression in an assignment.
*
* @param {String} exp
* @param {*} val
*/
Vue.prototype.$set = function (exp, val) {
var res = parseExpression(exp, true)
if (res && res.set) {
res.set.call(this, this, val)
}
}
/**
* Delete a property on the VM
*
* @param {String} key
*/
Vue.prototype.$delete = function (key) {
del(this._data, key)
}
/**
* Watch an expression, trigger callback when its
* value changes.
*
* @param {String|Function} expOrFn
* @param {Function} cb
* @param {Object} [options]
* - {Boolean} deep
* - {Boolean} immediate
* @return {Function} - unwatchFn
*/
Vue.prototype.$watch = function (expOrFn, cb, options) {
var vm = this
var parsed
if (typeof expOrFn === 'string') {
parsed = parseDirective(expOrFn)
expOrFn = parsed.expression
}
var watcher = new Watcher(vm, expOrFn, cb, {
deep: options && options.deep,
sync: options && options.sync,
filters: parsed && parsed.filters,
user: !options || options.user !== false
})
if (options && options.immediate) {
cb.call(vm, watcher.value)
}
return function unwatchFn () {
watcher.teardown()
}
}
/**
* Evaluate a text directive, including filters.
*
* @param {String} text
* @param {Boolean} [asStatement]
* @return {String}
*/
Vue.prototype.$eval = function (text, asStatement) {
// check for filters.
if (filterRE.test(text)) {
var dir = parseDirective(text)
// the filter regex check might give false positive
// for pipes inside strings, so it's possible that
// we don't get any filters here
var val = this.$get(dir.expression, asStatement)
return dir.filters
? this._applyFilters(val, null, dir.filters)
: val
} else {
// no filter
return this.$get(text, asStatement)
}
}
/**
* Interpolate a piece of template text.
*
* @param {String} text
* @return {String}
*/
Vue.prototype.$interpolate = function (text) {
var tokens = parseText(text)
var vm = this
if (tokens) {
if (tokens.length === 1) {
return vm.$eval(tokens[0].value) + ''
} else {
return tokens.map(function (token) {
return token.tag
? vm.$eval(token.value)
: token.value
}).join('')
}
} else {
return text
}
}
/**
* Log instance data as a plain JS object
* so that it is easier to inspect in console.
* This method assumes console is available.
*
* @param {String} [path]
*/
Vue.prototype.$log = function (path) {
var data = path
? getPath(this._data, path)
: this._data
if (data) {
data = clean(data)
}
// include computed fields
if (!path) {
var key
for (key in this.$options.computed) {
data[key] = clean(this[key])
}
if (this._props) {
for (key in this._props) {
data[key] = clean(this[key])
}
}
}
console.log(data)
}
/**
* "clean" a getter/setter converted object into a plain
* object copy.
*
* @param {Object} - obj
* @return {Object}
*/
function clean (obj) {
return JSON.parse(JSON.stringify(obj))
}
}
|