var _ = require('../util') var Watcher = require('../watcher') var Path = require('../parsers/path') var textParser = require('../parsers/text') var dirParser = require('../parsers/directive') var expParser = require('../parsers/expression') var filterRE = /[^|]\|[^|]/ /** * Get the value from an expression on this vm. * * @param {String} exp * @return {*} */ exports.$get = function (exp) { var res = expParser.parse(exp) if (res) { return res.get.call(this, this) } } /** * 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 */ exports.$set = function (exp, val) { var res = expParser.parse(exp, true) if (res && res.set) { res.set.call(this, this, val) } } /** * Add a property on the VM * * @param {String} key * @param {*} val */ exports.$add = function (key, val) { this._data.$add(key, val) } /** * Delete a property on the VM * * @param {String} key */ exports.$delete = function (key) { this._data.$delete(key) } /** * Watch an expression, trigger callback when its * value changes. * * @param {String} exp * @param {Function} cb * @param {Boolean} [deep] * @param {Boolean} [immediate] * @return {Function} - unwatchFn */ exports.$watch = function (exp, cb, deep, immediate) { var vm = this var key = deep ? exp + '**deep**' : exp var watcher = vm._userWatchers[key] var wrappedCb = function (val, oldVal) { cb.call(vm, val, oldVal) } if (!watcher) { watcher = vm._userWatchers[key] = new Watcher(vm, exp, wrappedCb, null, false, deep) } else { watcher.addCb(wrappedCb) } if (immediate) { wrappedCb(watcher.value) } return function unwatchFn () { watcher.removeCb(wrappedCb) if (!watcher.active) { vm._userWatchers[key] = null } } } /** * Evaluate a text directive, including filters. * * @param {String} text * @return {String} */ exports.$eval = function (text) { // check for filters. if (filterRE.test(text)) { var dir = dirParser.parse(text)[0] // the filter regex check might give false positive // for pipes inside strings, so it's possible that // we don't get any filters here return dir.filters ? _.applyFilters( this.$get(dir.expression), _.resolveFilters(this, dir.filters).read, this ) : this.$get(dir.expression) } else { // no filter return this.$get(text) } } /** * Interpolate a piece of template text. * * @param {String} text * @return {String} */ exports.$interpolate = function (text) { var tokens = textParser.parse(text) var vm = this if (tokens) { return tokens.length === 1 ? vm.$eval(tokens[0].value) : 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] */ exports.$log = function (path) { var data = path ? Path.get(this._data, path) : this._data if (data) { data = JSON.parse(JSON.stringify(data)) } console.log(data) }