diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..b7c5611 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.gem +.bundle +Gemfile.lock diff --git a/Gemfile b/Gemfile new file mode 100755 index 0000000..1aa98e4 --- /dev/null +++ b/Gemfile @@ -0,0 +1,2 @@ +source "http://rubygems.org" +gemspec diff --git a/LICENSE.md b/LICENSE.md new file mode 100755 index 0000000..edeb7e2 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013 Adam Butler + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Rakefile b/Rakefile new file mode 100755 index 0000000..2995527 --- /dev/null +++ b/Rakefile @@ -0,0 +1 @@ +require "bundler/gem_tasks" diff --git a/Readme.md b/Readme.md new file mode 100755 index 0000000..909fda6 --- /dev/null +++ b/Readme.md @@ -0,0 +1,15 @@ +# vuejs-rails Gem Version + +### About + +Rails 3.1+ asset-pipeline gem to provide vue.js + +### Setup + +Have in your Gemfile: + + gem 'vuejs-rails' + +And, have in your application.js manifest: + + //= require vue diff --git a/lib/vuejs-rails.rb b/lib/vuejs-rails.rb new file mode 100755 index 0000000..cd2a8b9 --- /dev/null +++ b/lib/vuejs-rails.rb @@ -0,0 +1,10 @@ +require "vuejs-rails/version" + +module Vue + module Rails + if defined?(::Rails) and Gem::Requirement.new('>= 3.1').satisfied_by?(Gem::Version.new ::Rails.version) + class Rails::Engine < ::Rails::Engine + end + end + end +end diff --git a/lib/vuejs-rails/version.rb b/lib/vuejs-rails/version.rb new file mode 100755 index 0000000..5b251d4 --- /dev/null +++ b/lib/vuejs-rails/version.rb @@ -0,0 +1,5 @@ +module Vue + module Rails + VERSION = "0.8.1" + end +end diff --git a/vendor/assets/javascripts/vue.js b/vendor/assets/javascripts/vue.js new file mode 100755 index 0000000..90c799c --- /dev/null +++ b/vendor/assets/javascripts/vue.js @@ -0,0 +1,3378 @@ +/* + VueJS v0.8.1 + (c) 2014 Evan You + License: MIT +*/ +;(function(){ + +/** + * Require the given path. + * + * @param {String} path + * @return {Object} exports + * @api public + */ + +function require(path, parent, orig) { + var resolved = require.resolve(path); + + // lookup failed + if (null == resolved) { + orig = orig || path; + parent = parent || 'root'; + var err = new Error('Failed to require "' + orig + '" from "' + parent + '"'); + err.path = orig; + err.parent = parent; + err.require = true; + throw err; + } + + var module = require.modules[resolved]; + + // perform real require() + // by invoking the module's + // registered function + if (!module._resolving && !module.exports) { + var mod = {}; + mod.exports = {}; + mod.client = mod.component = true; + module._resolving = true; + module.call(this, mod.exports, require.relative(resolved), mod); + delete module._resolving; + module.exports = mod.exports; + } + + return module.exports; +} + +/** + * Registered modules. + */ + +require.modules = {}; + +/** + * Registered aliases. + */ + +require.aliases = {}; + +/** + * Resolve `path`. + * + * Lookup: + * + * - PATH/index.js + * - PATH.js + * - PATH + * + * @param {String} path + * @return {String} path or null + * @api private + */ + +require.resolve = function(path) { + if (path.charAt(0) === '/') path = path.slice(1); + + var paths = [ + path, + path + '.js', + path + '.json', + path + '/index.js', + path + '/index.json' + ]; + + for (var i = 0; i < paths.length; i++) { + var path = paths[i]; + if (require.modules.hasOwnProperty(path)) return path; + if (require.aliases.hasOwnProperty(path)) return require.aliases[path]; + } +}; + +/** + * Normalize `path` relative to the current path. + * + * @param {String} curr + * @param {String} path + * @return {String} + * @api private + */ + +require.normalize = function(curr, path) { + var segs = []; + + if ('.' != path.charAt(0)) return path; + + curr = curr.split('/'); + path = path.split('/'); + + for (var i = 0; i < path.length; ++i) { + if ('..' == path[i]) { + curr.pop(); + } else if ('.' != path[i] && '' != path[i]) { + segs.push(path[i]); + } + } + + return curr.concat(segs).join('/'); +}; + +/** + * Register module at `path` with callback `definition`. + * + * @param {String} path + * @param {Function} definition + * @api private + */ + +require.register = function(path, definition) { + require.modules[path] = definition; +}; + +/** + * Alias a module definition. + * + * @param {String} from + * @param {String} to + * @api private + */ + +require.alias = function(from, to) { + if (!require.modules.hasOwnProperty(from)) { + throw new Error('Failed to alias "' + from + '", it does not exist'); + } + require.aliases[to] = from; +}; + +/** + * Return a require function relative to the `parent` path. + * + * @param {String} parent + * @return {Function} + * @api private + */ + +require.relative = function(parent) { + var p = require.normalize(parent, '..'); + + /** + * lastIndexOf helper. + */ + + function lastIndexOf(arr, obj) { + var i = arr.length; + while (i--) { + if (arr[i] === obj) return i; + } + return -1; + } + + /** + * The relative require() itself. + */ + + function localRequire(path) { + var resolved = localRequire.resolve(path); + return require(resolved, parent, path); + } + + /** + * Resolve relative to the parent. + */ + + localRequire.resolve = function(path) { + var c = path.charAt(0); + if ('/' == c) return path.slice(1); + if ('.' == c) return require.normalize(p, path); + + // resolve deps by returning + // the dep in the nearest "deps" + // directory + var segs = parent.split('/'); + var i = lastIndexOf(segs, 'deps') + 1; + if (!i) i = 0; + path = segs.slice(0, i + 1).join('/') + '/deps/' + path; + return path; + }; + + /** + * Check if module is defined at `path`. + */ + + localRequire.exists = function(path) { + return require.modules.hasOwnProperty(localRequire.resolve(path)); + }; + + return localRequire; +}; +require.register("component-emitter/index.js", function(exports, require, module){ + +/** + * Expose `Emitter`. + */ + +module.exports = Emitter; + +/** + * Initialize a new `Emitter`. + * + * @api public + */ + +function Emitter(obj) { + if (obj) return mixin(obj); +}; + +/** + * Mixin the emitter properties. + * + * @param {Object} obj + * @return {Object} + * @api private + */ + +function mixin(obj) { + for (var key in Emitter.prototype) { + obj[key] = Emitter.prototype[key]; + } + return obj; +} + +/** + * Listen on the given `event` with `fn`. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ + +Emitter.prototype.on = +Emitter.prototype.addEventListener = function(event, fn){ + this._callbacks = this._callbacks || {}; + (this._callbacks[event] = this._callbacks[event] || []) + .push(fn); + return this; +}; + +/** + * Adds an `event` listener that will be invoked a single + * time then automatically removed. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ + +Emitter.prototype.once = function(event, fn){ + var self = this; + this._callbacks = this._callbacks || {}; + + function on() { + self.off(event, on); + fn.apply(this, arguments); + } + + on.fn = fn; + this.on(event, on); + return this; +}; + +/** + * Remove the given callback for `event` or all + * registered callbacks. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ + +Emitter.prototype.off = +Emitter.prototype.removeListener = +Emitter.prototype.removeAllListeners = +Emitter.prototype.removeEventListener = function(event, fn){ + this._callbacks = this._callbacks || {}; + + // all + if (0 == arguments.length) { + this._callbacks = {}; + return this; + } + + // specific event + var callbacks = this._callbacks[event]; + if (!callbacks) return this; + + // remove all handlers + if (1 == arguments.length) { + delete this._callbacks[event]; + return this; + } + + // remove specific handler + var cb; + for (var i = 0; i < callbacks.length; i++) { + cb = callbacks[i]; + if (cb === fn || cb.fn === fn) { + callbacks.splice(i, 1); + break; + } + } + return this; +}; + +/** + * Emit `event` with the given args. + * + * @param {String} event + * @param {Mixed} ... + * @return {Emitter} + */ + +Emitter.prototype.emit = function(event){ + this._callbacks = this._callbacks || {}; + var args = [].slice.call(arguments, 1) + , callbacks = this._callbacks[event]; + + if (callbacks) { + callbacks = callbacks.slice(0); + for (var i = 0, len = callbacks.length; i < len; ++i) { + callbacks[i].apply(this, args); + } + } + + return this; +}; + +/** + * Return array of callbacks for `event`. + * + * @param {String} event + * @return {Array} + * @api public + */ + +Emitter.prototype.listeners = function(event){ + this._callbacks = this._callbacks || {}; + return this._callbacks[event] || []; +}; + +/** + * Check if this emitter has `event` handlers. + * + * @param {String} event + * @return {Boolean} + * @api public + */ + +Emitter.prototype.hasListeners = function(event){ + return !! this.listeners(event).length; +}; + +}); +require.register("vue/src/main.js", function(exports, require, module){ +var config = require('./config'), + ViewModel = require('./viewmodel'), + directives = require('./directives'), + filters = require('./filters'), + utils = require('./utils') + +/** + * Set config options + */ +ViewModel.config = function (opts, val) { + if (typeof opts === 'string') { + if (val === undefined) { + return config[opts] + } else { + config[opts] = val + } + } else { + utils.extend(config, opts) + } + return this +} + +/** + * Allows user to register/retrieve a directive definition + */ +ViewModel.directive = function (id, fn) { + if (!fn) return directives[id] + directives[id] = fn + return this +} + +/** + * Allows user to register/retrieve a filter function + */ +ViewModel.filter = function (id, fn) { + if (!fn) return filters[id] + filters[id] = fn + return this +} + +/** + * Allows user to register/retrieve a ViewModel constructor + */ +ViewModel.component = function (id, Ctor) { + if (!Ctor) return utils.components[id] + utils.components[id] = utils.toConstructor(Ctor) + return this +} + +/** + * Allows user to register/retrieve a template partial + */ +ViewModel.partial = function (id, partial) { + if (!partial) return utils.partials[id] + utils.partials[id] = utils.toFragment(partial) + return this +} + +/** + * Allows user to register/retrieve a transition definition object + */ +ViewModel.transition = function (id, transition) { + if (!transition) return utils.transitions[id] + utils.transitions[id] = transition + return this +} + +ViewModel.extend = extend +ViewModel.nextTick = utils.nextTick + +/** + * Expose the main ViewModel class + * and add extend method + */ +function extend (options) { + + var ParentVM = this + + // inherit options + options = inheritOptions(options, ParentVM.options, true) + utils.processOptions(options) + + var ExtendedVM = function (opts, asParent) { + if (!asParent) { + opts = inheritOptions(opts, options, true) + } + ParentVM.call(this, opts, true) + } + + // inherit prototype props + var proto = ExtendedVM.prototype = Object.create(ParentVM.prototype) + utils.defProtected(proto, 'constructor', ExtendedVM) + + // copy prototype props + var methods = options.methods + if (methods) { + for (var key in methods) { + if ( + !(key in ViewModel.prototype) && + typeof methods[key] === 'function' + ) { + proto[key] = methods[key] + } + } + } + + // allow extended VM to be further extended + ExtendedVM.extend = extend + ExtendedVM.super = ParentVM + ExtendedVM.options = options + return ExtendedVM +} + +/** + * Inherit options + * + * For options such as `data`, `vms`, `directives`, 'partials', + * they should be further extended. However extending should only + * be done at top level. + * + * `proto` is an exception because it's handled directly on the + * prototype. + * + * `el` is an exception because it's not allowed as an + * extension option, but only as an instance option. + */ +function inheritOptions (child, parent, topLevel) { + child = child || utils.hash() + if (!parent) return child + for (var key in parent) { + if (key === 'el' || key === 'methods') continue + var val = child[key], + parentVal = parent[key], + type = utils.typeOf(val) + if (topLevel && type === 'Function' && parentVal) { + // merge hook functions + child[key] = mergeHook(val, parentVal) + } else if (topLevel && type === 'Object') { + // merge toplevel object options + inheritOptions(val, parentVal) + } else if (val === undefined) { + // inherit if child doesn't override + child[key] = parentVal + } + } + return child +} + +/** + * Merge hook functions + * so parent hooks also get called + */ +function mergeHook (fn, parentFn) { + return function (opts) { + parentFn.call(this, opts) + fn.call(this, opts) + } +} + +module.exports = ViewModel +}); +require.register("vue/src/emitter.js", function(exports, require, module){ +// shiv to make this work for Component, Browserify and Node at the same time. +var Emitter, + componentEmitter = 'emitter' + +try { + // Requiring without a string literal will make browserify + // unable to parse the dependency, thus preventing it from + // stopping the compilation after a failed lookup. + Emitter = require(componentEmitter) +} catch (e) { + Emitter = require('events').EventEmitter + Emitter.prototype.off = function () { + var method = arguments.length > 1 + ? this.removeListener + : this.removeAllListeners + return method.apply(this, arguments) + } +} + +module.exports = Emitter +}); +require.register("vue/src/config.js", function(exports, require, module){ +var prefix = 'v', + specialAttributes = [ + 'pre', + 'text', + 'repeat', + 'partial', + 'with', + 'component', + 'component-id', + 'transition' + ], + config = module.exports = { + + debug : false, + silent : false, + enterClass : 'v-enter', + leaveClass : 'v-leave', + attrs : {}, + + get prefix () { + return prefix + }, + set prefix (val) { + prefix = val + updatePrefix() + } + + } + +function updatePrefix () { + specialAttributes.forEach(function (attr) { + config.attrs[attr] = prefix + '-' + attr + }) +} + +updatePrefix() +}); +require.register("vue/src/utils.js", function(exports, require, module){ +var config = require('./config'), + attrs = config.attrs, + toString = Object.prototype.toString, + join = Array.prototype.join, + console = window.console, + ViewModel // late def + +var defer = + window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.setTimeout + +/** + * Create a prototype-less object + * which is a better hash/map + */ +function makeHash () { + return Object.create(null) +} + +var utils = module.exports = { + + hash: makeHash, + + // global storage for user-registered + // vms, partials and transitions + components : makeHash(), + partials : makeHash(), + transitions : makeHash(), + + /** + * get an attribute and remove it. + */ + attr: function (el, type, noRemove) { + var attr = attrs[type], + val = el.getAttribute(attr) + if (!noRemove && val !== null) el.removeAttribute(attr) + return val + }, + + /** + * Define an ienumerable property + * This avoids it being included in JSON.stringify + * or for...in loops. + */ + defProtected: function (obj, key, val, enumerable, configurable) { + if (obj.hasOwnProperty(key)) return + Object.defineProperty(obj, key, { + value : val, + enumerable : !!enumerable, + configurable : !!configurable + }) + }, + + /** + * Accurate type check + * internal use only, so no need to check for NaN + */ + typeOf: function (obj) { + return toString.call(obj).slice(8, -1) + }, + + /** + * Most simple bind + * enough for the usecase and fast than native bind() + */ + bind: function (fn, ctx) { + return function (arg) { + return fn.call(ctx, arg) + } + }, + + /** + * Make sure only strings and numbers are output to html + * output empty string is value is not string or number + */ + toText: function (value) { + /* jshint eqeqeq: false */ + return (typeof value === 'string' || + typeof value === 'boolean' || + (typeof value === 'number' && value == value)) // deal with NaN + ? value + : '' + }, + + /** + * simple extend + */ + extend: function (obj, ext, protective) { + for (var key in ext) { + if (protective && obj[key]) continue + obj[key] = ext[key] + } + }, + + /** + * filter an array with duplicates into uniques + */ + unique: function (arr) { + var hash = utils.hash(), + i = arr.length, + key, res = [] + while (i--) { + key = arr[i] + if (hash[key]) continue + hash[key] = 1 + res.push(key) + } + return res + }, + + /** + * Convert a string template to a dom fragment + */ + toFragment: function (template) { + if (typeof template !== 'string') { + return template + } + if (template.charAt(0) === '#') { + var templateNode = document.getElementById(template.slice(1)) + if (!templateNode) return + template = templateNode.innerHTML + } + var node = document.createElement('div'), + frag = document.createDocumentFragment(), + child + node.innerHTML = template.trim() + /* jshint boss: true */ + while (child = node.firstChild) { + frag.appendChild(child) + } + return frag + }, + + /** + * Convert the object to a ViewModel constructor + * if it is not already one + */ + toConstructor: function (obj) { + ViewModel = ViewModel || require('./viewmodel') + return utils.typeOf(obj) === 'Object' + ? ViewModel.extend(obj) + : typeof obj === 'function' + ? obj + : null + }, + + /** + * convert certain option values to the desired format. + */ + processOptions: function (options) { + var components = options.components, + partials = options.partials, + template = options.template, + key + if (components) { + for (key in components) { + components[key] = utils.toConstructor(components[key]) + } + } + if (partials) { + for (key in partials) { + partials[key] = utils.toFragment(partials[key]) + } + } + if (template) { + options.template = utils.toFragment(template) + } + }, + + /** + * log for debugging + */ + log: function () { + if (config.debug && console) { + console.log(join.call(arguments, ' ')) + } + }, + + /** + * warnings, traces by default + * can be suppressed by `silent` option. + */ + warn: function() { + if (!config.silent && console) { + console.warn(join.call(arguments, ' ')) + if (config.debug) { + console.trace() + } + } + }, + + /** + * used to defer batch updates + */ + nextTick: function (cb) { + defer(cb, 0) + } +} +}); +require.register("vue/src/compiler.js", function(exports, require, module){ +var Emitter = require('./emitter'), + Observer = require('./observer'), + config = require('./config'), + utils = require('./utils'), + Binding = require('./binding'), + Directive = require('./directive'), + TextParser = require('./text-parser'), + DepsParser = require('./deps-parser'), + ExpParser = require('./exp-parser'), + + // cache methods + slice = Array.prototype.slice, + log = utils.log, + makeHash = utils.hash, + extend = utils.extend, + def = utils.defProtected, + hasOwn = Object.prototype.hasOwnProperty + +/** + * The DOM compiler + * scans a DOM node and compile bindings for a ViewModel + */ +function Compiler (vm, options) { + + var compiler = this + // indicate that we are intiating this instance + // so we should not run any transitions + compiler.init = true + + // process and extend options + options = compiler.options = options || makeHash() + utils.processOptions(options) + + // copy data, methods & compiler options + var data = compiler.data = options.data || {} + extend(vm, data, true) + extend(vm, options.methods, true) + extend(compiler, options.compilerOptions) + + // initialize element + var el = compiler.setupElement(options) + log('\nnew VM instance:', el.tagName, '\n') + + // set compiler properties + compiler.vm = vm + compiler.bindings = makeHash() + compiler.dirs = [] + compiler.exps = [] + compiler.computed = [] + compiler.childCompilers = [] + compiler.emitter = new Emitter() + + // set inenumerable VM properties + def(vm, '$', makeHash()) + def(vm, '$el', el) + def(vm, '$compiler', compiler) + def(vm, '$root', getRoot(compiler).vm) + + // set parent VM + // and register child id on parent + var parent = compiler.parentCompiler, + childId = utils.attr(el, 'component-id') + if (parent) { + parent.childCompilers.push(compiler) + def(vm, '$parent', parent.vm) + if (childId) { + compiler.childId = childId + parent.vm.$[childId] = vm + } + } + + // setup observer + compiler.setupObserver() + + // create bindings for computed properties + var computed = options.computed + if (computed) { + for (var key in computed) { + compiler.createBinding(key) + } + } + + // beforeCompile hook + compiler.execHook('beforeCompile', 'created') + + // the user might have set some props on the vm + // so copy it back to the data... + extend(data, vm) + + // observe the data + Observer.observe(data, '', compiler.observer) + + // for repeated items, create an index binding + // which should be inenumerable but configurable + if (compiler.repeat) { + //data.$index = compiler.repeatIndex + def(data, '$index', compiler.repeatIndex, false, true) + compiler.createBinding('$index') + } + + // allow the $data object to be swapped + Object.defineProperty(vm, '$data', { + enumerable: false, + get: function () { + return compiler.data + }, + set: function (newData) { + var oldData = compiler.data + Observer.unobserve(oldData, '', compiler.observer) + compiler.data = newData + Observer.copyPaths(newData, oldData) + Observer.observe(newData, '', compiler.observer) + } + }) + + // now parse the DOM, during which we will create necessary bindings + // and bind the parsed directives + compiler.compile(el, true) + + // extract dependencies for computed properties + if (compiler.computed.length) { + DepsParser.parse(compiler.computed) + } + + // done! + compiler.init = false + + // post compile / ready hook + compiler.execHook('afterCompile', 'ready') +} + +var CompilerProto = Compiler.prototype + +/** + * Initialize the VM/Compiler's element. + * Fill it in with the template if necessary. + */ +CompilerProto.setupElement = function (options) { + // create the node first + var el = this.el = typeof options.el === 'string' + ? document.querySelector(options.el) + : options.el || document.createElement(options.tagName || 'div') + + var template = options.template + if (template) { + // replace option: use the first node in + // the template directly + if (options.replace && template.childNodes.length === 1) { + var replacer = template.childNodes[0].cloneNode(true) + if (el.parentNode) { + el.parentNode.insertBefore(replacer, el) + el.parentNode.removeChild(el) + } + el = replacer + } else { + el.innerHTML = '' + el.appendChild(template.cloneNode(true)) + } + } + + // apply element options + if (options.id) el.id = options.id + if (options.className) el.className = options.className + var attrs = options.attributes + if (attrs) { + for (var attr in attrs) { + el.setAttribute(attr, attrs[attr]) + } + } + + return el +} + +/** + * Setup observer. + * The observer listens for get/set/mutate events on all VM + * values/objects and trigger corresponding binding updates. + */ +CompilerProto.setupObserver = function () { + + var compiler = this, + bindings = compiler.bindings, + observer = compiler.observer = new Emitter() + + // a hash to hold event proxies for each root level key + // so they can be referenced and removed later + observer.proxies = makeHash() + + // add own listeners which trigger binding updates + observer + .on('get', function (key) { + check(key) + DepsParser.catcher.emit('get', bindings[key]) + }) + .on('set', function (key, val) { + observer.emit('change:' + key, val) + check(key) + bindings[key].update(val) + }) + .on('mutate', function (key, val, mutation) { + observer.emit('change:' + key, val, mutation) + check(key) + bindings[key].pub() + }) + + function check (key) { + if (!bindings[key]) { + compiler.createBinding(key) + } + } +} + +/** + * Compile a DOM node (recursive) + */ +CompilerProto.compile = function (node, root) { + + var compiler = this, + nodeType = node.nodeType, + tagName = node.tagName + + if (nodeType === 1 && tagName !== 'SCRIPT') { // a normal node + + // skip anything with v-pre + if (utils.attr(node, 'pre') !== null) return + + // special attributes to check + var repeatExp, + withKey, + partialId, + directive, + componentId = utils.attr(node, 'component') || tagName.toLowerCase(), + componentCtor = compiler.getOption('components', componentId) + + // It is important that we access these attributes + // procedurally because the order matters. + // + // `utils.attr` removes the attribute once it gets the + // value, so we should not access them all at once. + + // v-repeat has the highest priority + // and we need to preserve all other attributes for it. + /* jshint boss: true */ + if (repeatExp = utils.attr(node, 'repeat')) { + + // repeat block cannot have v-id at the same time. + directive = Directive.parse('repeat', repeatExp, compiler, node) + if (directive) { + directive.Ctor = componentCtor + compiler.bindDirective(directive) + } + + // v-with has 2nd highest priority + } else if (!root && ((withKey = utils.attr(node, 'with')) || componentCtor)) { + + directive = Directive.parse('with', withKey || '', compiler, node) + if (directive) { + directive.Ctor = componentCtor + compiler.bindDirective(directive) + } + + } else { + + // check transition property + node.vue_trans = utils.attr(node, 'transition') + + // replace innerHTML with partial + partialId = utils.attr(node, 'partial') + if (partialId) { + var partial = compiler.getOption('partials', partialId) + if (partial) { + node.innerHTML = '' + node.appendChild(partial.cloneNode(true)) + } + } + + // finally, only normal directives left! + compiler.compileNode(node) + } + + } else if (nodeType === 3) { // text node + + compiler.compileTextNode(node) + + } + +} + +/** + * Compile a normal node + */ +CompilerProto.compileNode = function (node) { + var i, j, + attrs = node.attributes, + prefix = config.prefix + '-' + // parse if has attributes + if (attrs && attrs.length) { + var attr, isDirective, exps, exp, directive + // loop through all attributes + i = attrs.length + while (i--) { + attr = attrs[i] + isDirective = false + + if (attr.name.indexOf(prefix) === 0) { + // a directive - split, parse and bind it. + isDirective = true + exps = Directive.split(attr.value) + // loop through clauses (separated by ",") + // inside each attribute + j = exps.length + while (j--) { + exp = exps[j] + directive = Directive.parse(attr.name.slice(prefix.length), exp, this, node) + if (directive) { + this.bindDirective(directive) + } + } + } else { + // non directive attribute, check interpolation tags + exp = TextParser.parseAttr(attr.value) + if (exp) { + directive = Directive.parse('attr', attr.name + ':' + exp, this, node) + if (directive) { + this.bindDirective(directive) + } + } + } + + if (isDirective) node.removeAttribute(attr.name) + } + } + // recursively compile childNodes + if (node.childNodes.length) { + var nodes = slice.call(node.childNodes) + for (i = 0, j = nodes.length; i < j; i++) { + this.compile(nodes[i]) + } + } +} + +/** + * Compile a text node + */ +CompilerProto.compileTextNode = function (node) { + + var tokens = TextParser.parse(node.nodeValue) + if (!tokens) return + var el, token, directive, partial, partialId, partialNodes + + for (var i = 0, l = tokens.length; i < l; i++) { + token = tokens[i] + if (token.key) { // a binding + if (token.key.charAt(0) === '>') { // a partial + partialId = token.key.slice(1).trim() + partial = this.getOption('partials', partialId) + if (partial) { + el = partial.cloneNode(true) + // save an Array reference of the partial's nodes + // so we can compile them AFTER appending the fragment + partialNodes = slice.call(el.childNodes) + } + } else { // a real binding + el = document.createTextNode('') + directive = Directive.parse('text', token.key, this, el) + if (directive) { + this.bindDirective(directive) + } + } + } else { // a plain string + el = document.createTextNode(token) + } + + // insert node + node.parentNode.insertBefore(el, node) + + // compile partial after appending, because its children's parentNode + // will change from the fragment to the correct parentNode. + // This could affect directives that need access to its element's parentNode. + if (partialNodes) { + for (var j = 0, k = partialNodes.length; j < k; j++) { + this.compile(partialNodes[j]) + } + partialNodes = null + } + + } + node.parentNode.removeChild(node) +} + +/** + * Add a directive instance to the correct binding & viewmodel + */ +CompilerProto.bindDirective = function (directive) { + + // keep track of it so we can unbind() later + this.dirs.push(directive) + + // for a simple directive, simply call its bind() or _update() + // and we're done. + if (directive.isEmpty) { + if (directive.bind) directive.bind() + return + } + + // otherwise, we got more work to do... + var binding, + compiler = this, + key = directive.key + + if (directive.isExp) { + // expression bindings are always created on current compiler + binding = compiler.createBinding(key, true, directive.isFn) + } else { + // recursively locate which compiler owns the binding + while (compiler) { + if (compiler.hasKey(key)) { + break + } else { + compiler = compiler.parentCompiler + } + } + compiler = compiler || this + binding = compiler.bindings[key] || compiler.createBinding(key) + } + + binding.instances.push(directive) + directive.binding = binding + + // invoke bind hook if exists + if (directive.bind) { + directive.bind() + } + + // set initial value + directive.update(binding.val(), true) +} + +/** + * Create binding and attach getter/setter for a key to the viewmodel object + */ +CompilerProto.createBinding = function (key, isExp, isFn) { + + log(' created binding: ' + key) + + var compiler = this, + bindings = compiler.bindings, + computed = compiler.options.computed, + binding = new Binding(compiler, key, isExp, isFn) + + if (isExp) { + // expression bindings are anonymous + compiler.defineExp(key, binding) + } else { + bindings[key] = binding + if (binding.root) { + // this is a root level binding. we need to define getter/setters for it. + if (computed && computed[key]) { + // computed property + compiler.defineComputed(key, binding, computed[key]) + } else { + // normal property + compiler.defineProp(key, binding) + } + } else { + // ensure path in data so it can be observed + Observer.ensurePath(compiler.data, key) + var parentKey = key.slice(0, key.lastIndexOf('.')) + if (!bindings[parentKey]) { + // this is a nested value binding, but the binding for its parent + // has not been created yet. We better create that one too. + compiler.createBinding(parentKey) + } + } + } + return binding +} + +/** + * Define the getter/setter for a root-level property on the VM + * and observe the initial value + */ +CompilerProto.defineProp = function (key, binding) { + + var compiler = this, + data = compiler.data, + ob = data.__observer__ + + // make sure the key is present in data + // so it can be observed + if (!(key in data)) { + data[key] = undefined + } + + // if the data object is already observed, but the key + // is not observed, we need to add it to the observed keys. + if (ob && !(key in ob.values)) { + Observer.convert(data, key) + } + + binding.value = data[key] + + Object.defineProperty(compiler.vm, key, { + get: function () { + return compiler.data[key] + }, + set: function (val) { + compiler.data[key] = val + } + }) +} + +/** + * Define an expression binding, which is essentially + * an anonymous computed property + */ +CompilerProto.defineExp = function (key, binding) { + var getter = ExpParser.parse(key, this) + if (getter) { + this.markComputed(binding, getter) + this.exps.push(binding) + } +} + +/** + * Define a computed property on the VM + */ +CompilerProto.defineComputed = function (key, binding, value) { + this.markComputed(binding, value) + var def = { + get: binding.value.$get, + set: binding.value.$set + } + Object.defineProperty(this.vm, key, def) +} + +/** + * Process a computed property binding + * so its getter/setter are bound to proper context + */ +CompilerProto.markComputed = function (binding, value) { + binding.isComputed = true + // bind the accessors to the vm + if (binding.isFn) { + binding.value = value + } else { + if (typeof value === 'function') { + value = { $get: value } + } + binding.value = { + $get: utils.bind(value.$get, this.vm), + $set: value.$set + ? utils.bind(value.$set, this.vm) + : undefined + } + } + // keep track for dep parsing later + this.computed.push(binding) +} + +/** + * Retrive an option from the compiler + */ +CompilerProto.getOption = function (type, id) { + var opts = this.options, + parent = this.parentCompiler + return (opts[type] && opts[type][id]) || ( + parent + ? parent.getOption(type, id) + : utils[type] && utils[type][id] + ) +} + +/** + * Execute a user hook + */ +CompilerProto.execHook = function (id, alt) { + var opts = this.options, + hook = opts[id] || opts[alt] + if (hook) { + hook.call(this.vm, opts) + } +} + +/** + * Check if a compiler's data contains a keypath + */ +CompilerProto.hasKey = function (key) { + var baseKey = key.split('.')[0] + return hasOwn.call(this.data, baseKey) || + hasOwn.call(this.vm, baseKey) +} + +/** + * Unbind and remove element + */ +CompilerProto.destroy = function () { + + var compiler = this, + i, key, dir, instances, binding, + vm = compiler.vm, + el = compiler.el, + directives = compiler.dirs, + exps = compiler.exps, + bindings = compiler.bindings + + compiler.execHook('beforeDestroy') + + // unwatch + compiler.observer.off() + compiler.emitter.off() + + // unbind all direcitves + i = directives.length + while (i--) { + dir = directives[i] + // if this directive is an instance of an external binding + // e.g. a directive that refers to a variable on the parent VM + // we need to remove it from that binding's instances + if (!dir.isEmpty && dir.binding.compiler !== compiler) { + instances = dir.binding.instances + if (instances) instances.splice(instances.indexOf(dir), 1) + } + dir.unbind() + } + + // unbind all expressions (anonymous bindings) + i = exps.length + while (i--) { + exps[i].unbind() + } + + // unbind/unobserve all own bindings + for (key in bindings) { + binding = bindings[key] + if (binding) { + if (binding.root) { + Observer.unobserve(binding.value, binding.key, compiler.observer) + } + binding.unbind() + } + } + + // remove self from parentCompiler + var parent = compiler.parentCompiler, + childId = compiler.childId + if (parent) { + parent.childCompilers.splice(parent.childCompilers.indexOf(compiler), 1) + if (childId) { + delete parent.vm.$[childId] + } + } + + // finally remove dom element + if (el === document.body) { + el.innerHTML = '' + } else { + vm.$remove() + } + + compiler.execHook('afterDestroy') +} + +// Helpers -------------------------------------------------------------------- + +/** + * shorthand for getting root compiler + */ +function getRoot (compiler) { + while (compiler.parentCompiler) { + compiler = compiler.parentCompiler + } + return compiler +} + +module.exports = Compiler +}); +require.register("vue/src/viewmodel.js", function(exports, require, module){ +var Compiler = require('./compiler'), + utils = require('./utils'), + transition = require('./transition'), + def = utils.defProtected, + nextTick = utils.nextTick + +/** + * ViewModel exposed to the user that holds data, + * computed properties, event handlers + * and a few reserved methods + */ +function ViewModel (options) { + // just compile. options are passed directly to compiler + new Compiler(this, options) +} + +// All VM prototype methods are inenumerable +// so it can be stringified/looped through as raw data +var VMProto = ViewModel.prototype + +/** + * Convenience function to set an actual nested value + * from a flat key string. Used in directives. + */ +def(VMProto, '$set', function (key, value) { + var path = key.split('.'), + obj = getTargetVM(this, path) + if (!obj) return + for (var d = 0, l = path.length - 1; d < l; d++) { + obj = obj[path[d]] + } + obj[path[d]] = value +}) + +/** + * watch a key on the viewmodel for changes + * fire callback with new value + */ +def(VMProto, '$watch', function (key, callback) { + var self = this + function on () { + var args = arguments + utils.nextTick(function () { + callback.apply(self, args) + }) + } + callback._fn = on + self.$compiler.observer.on('change:' + key, on) +}) + +/** + * unwatch a key + */ +def(VMProto, '$unwatch', function (key, callback) { + // workaround here + // since the emitter module checks callback existence + // by checking the length of arguments + var args = ['change:' + key], + ob = this.$compiler.observer + if (callback) args.push(callback._fn) + ob.off.apply(ob, args) +}) + +/** + * unbind everything, remove everything + */ +def(VMProto, '$destroy', function () { + this.$compiler.destroy() +}) + +/** + * broadcast an event to all child VMs recursively. + */ +def(VMProto, '$broadcast', function () { + var children = this.$compiler.childCompilers, + i = children.length, + child + while (i--) { + child = children[i] + child.emitter.emit.apply(child.emitter, arguments) + child.vm.$broadcast.apply(child.vm, arguments) + } +}) + +/** + * emit an event that propagates all the way up to parent VMs. + */ +def(VMProto, '$dispatch', function () { + var compiler = this.$compiler, + emitter = compiler.emitter, + parent = compiler.parentCompiler + emitter.emit.apply(emitter, arguments) + if (parent) { + parent.vm.$dispatch.apply(parent.vm, arguments) + } +}) + +/** + * delegate on/off/once to the compiler's emitter + */ +;['emit', 'on', 'off', 'once'].forEach(function (method) { + def(VMProto, '$' + method, function () { + var emitter = this.$compiler.emitter + emitter[method].apply(emitter, arguments) + }) +}) + +// DOM convenience methods + +def(VMProto, '$appendTo', function (target, cb) { + target = query(target) + var el = this.$el + transition(el, 1, function () { + target.appendChild(el) + if (cb) nextTick(cb) + }, this.$compiler) +}) + +def(VMProto, '$remove', function (cb) { + var el = this.$el, + parent = el.parentNode + if (!parent) return + transition(el, -1, function () { + parent.removeChild(el) + if (cb) nextTick(cb) + }, this.$compiler) +}) + +def(VMProto, '$before', function (target, cb) { + target = query(target) + var el = this.$el, + parent = target.parentNode + if (!parent) return + transition(el, 1, function () { + parent.insertBefore(el, target) + if (cb) nextTick(cb) + }, this.$compiler) +}) + +def(VMProto, '$after', function (target, cb) { + target = query(target) + var el = this.$el, + parent = target.parentNode, + next = target.nextSibling + if (!parent) return + transition(el, 1, function () { + if (next) { + parent.insertBefore(el, next) + } else { + parent.appendChild(el) + } + if (cb) nextTick(cb) + }, this.$compiler) +}) + +function query (el) { + return typeof el === 'string' + ? document.querySelector(el) + : el +} + +/** + * If a VM doesn't contain a path, go up the prototype chain + * to locate the ancestor that has it. + */ +function getTargetVM (vm, path) { + var baseKey = path[0], + binding = vm.$compiler.bindings[baseKey] + return binding + ? binding.compiler.vm + : null +} + +module.exports = ViewModel +}); +require.register("vue/src/binding.js", function(exports, require, module){ +var batcher = require('./batcher'), + id = 0 + +/** + * Binding class. + * + * each property on the viewmodel has one corresponding Binding object + * which has multiple directive instances on the DOM + * and multiple computed property dependents + */ +function Binding (compiler, key, isExp, isFn) { + this.id = id++ + this.value = undefined + this.isExp = !!isExp + this.isFn = isFn + this.root = !this.isExp && key.indexOf('.') === -1 + this.compiler = compiler + this.key = key + this.instances = [] + this.subs = [] + this.deps = [] + this.unbound = false +} + +var BindingProto = Binding.prototype + +/** + * Update value and queue instance updates. + */ +BindingProto.update = function (value) { + if (!this.isComputed || this.isFn) { + this.value = value + } + batcher.queue(this) +} + +/** + * Actually update the instances. + */ +BindingProto._update = function () { + var i = this.instances.length, + value = this.val() + while (i--) { + this.instances[i].update(value) + } + this.pub() +} + +/** + * Return the valuated value regardless + * of whether it is computed or not + */ +BindingProto.val = function () { + return this.isComputed && !this.isFn + ? this.value.$get() + : this.value +} + +/** + * Notify computed properties that depend on this binding + * to update themselves + */ +BindingProto.pub = function () { + var i = this.subs.length + while (i--) { + this.subs[i].update() + } +} + +/** + * Unbind the binding, remove itself from all of its dependencies + */ +BindingProto.unbind = function () { + // Indicate this has been unbound. + // It's possible this binding will be in + // the batcher's flush queue when its owner + // compiler has already been destroyed. + this.unbound = true + var i = this.instances.length + while (i--) { + this.instances[i].unbind() + } + i = this.deps.length + var subs + while (i--) { + subs = this.deps[i].subs + subs.splice(subs.indexOf(this), 1) + } +} + +module.exports = Binding +}); +require.register("vue/src/observer.js", function(exports, require, module){ +/* jshint proto:true */ + +var Emitter = require('./emitter'), + utils = require('./utils'), + + // cache methods + typeOf = utils.typeOf, + def = utils.defProtected, + slice = Array.prototype.slice, + + // types + OBJECT = 'Object', + ARRAY = 'Array', + + // Array mutation methods to wrap + methods = ['push','pop','shift','unshift','splice','sort','reverse'], + + // fix for IE + __proto__ problem + // define methods as inenumerable if __proto__ is present, + // otherwise enumerable so we can loop through and manually + // attach to array instances + hasProto = ({}).__proto__, + + // lazy load + ViewModel + +// The proxy prototype to replace the __proto__ of +// an observed array +var ArrayProxy = Object.create(Array.prototype) + +// Define mutation interceptors so we can emit the mutation info +methods.forEach(function (method) { + def(ArrayProxy, method, function () { + var result = Array.prototype[method].apply(this, arguments) + this.__observer__.emit('mutate', this.__observer__.path, this, { + method: method, + args: slice.call(arguments), + result: result + }) + return result + }, !hasProto) +}) + +// Augment it with several convenience methods +var extensions = { + remove: function (index) { + if (typeof index === 'function') { + var i = this.length, + removed = [] + while (i--) { + if (index(this[i])) { + removed.push(this.splice(i, 1)[0]) + } + } + return removed.reverse() + } else { + if (typeof index !== 'number') { + index = this.indexOf(index) + } + if (index > -1) { + return this.splice(index, 1)[0] + } + } + }, + replace: function (index, data) { + if (typeof index === 'function') { + var i = this.length, + replaced = [], + replacer + while (i--) { + replacer = index(this[i]) + if (replacer !== undefined) { + replaced.push(this.splice(i, 1, replacer)[0]) + } + } + return replaced.reverse() + } else { + if (typeof index !== 'number') { + index = this.indexOf(index) + } + if (index > -1) { + return this.splice(index, 1, data)[0] + } + } + } +} + +for (var method in extensions) { + def(ArrayProxy, method, extensions[method], !hasProto) +} + +/** + * Watch an Object, recursive. + */ +function watchObject (obj) { + for (var key in obj) { + convert(obj, key) + } +} + +/** + * Watch an Array, overload mutation methods + * and add augmentations by intercepting the prototype chain + */ +function watchArray (arr, path) { + var observer = arr.__observer__ + if (!observer) { + observer = new Emitter() + def(arr, '__observer__', observer) + } + observer.path = path + if (hasProto) { + arr.__proto__ = ArrayProxy + } else { + for (var key in ArrayProxy) { + def(arr, key, ArrayProxy[key]) + } + } +} + +/** + * Define accessors for a property on an Object + * so it emits get/set events. + * Then watch the value itself. + */ +function convert (obj, key) { + var keyPrefix = key.charAt(0) + if ((keyPrefix === '$' || keyPrefix === '_') && key !== '$index') { + return + } + // emit set on bind + // this means when an object is observed it will emit + // a first batch of set events. + var observer = obj.__observer__, + values = observer.values, + val = values[key] = obj[key] + observer.emit('set', key, val) + if (Array.isArray(val)) { + observer.emit('set', key + '.length', val.length) + } + Object.defineProperty(obj, key, { + get: function () { + var value = values[key] + // only emit get on tip values + if (pub.shouldGet && typeOf(value) !== OBJECT) { + observer.emit('get', key) + } + return value + }, + set: function (newVal) { + var oldVal = values[key] + unobserve(oldVal, key, observer) + values[key] = newVal + copyPaths(newVal, oldVal) + observer.emit('set', key, newVal) + observe(newVal, key, observer) + } + }) + observe(val, key, observer) +} + +/** + * Check if a value is watchable + */ +function isWatchable (obj) { + ViewModel = ViewModel || require('./viewmodel') + var type = typeOf(obj) + return (type === OBJECT || type === ARRAY) && !(obj instanceof ViewModel) +} + +/** + * When a value that is already converted is + * observed again by another observer, we can skip + * the watch conversion and simply emit set event for + * all of its properties. + */ +function emitSet (obj) { + var type = typeOf(obj), + emitter = obj && obj.__observer__ + if (type === ARRAY) { + emitter.emit('set', 'length', obj.length) + } else if (type === OBJECT) { + var key, val + for (key in obj) { + val = obj[key] + emitter.emit('set', key, val) + emitSet(val) + } + } +} + +/** + * Make sure all the paths in an old object exists + * in a new object. + * So when an object changes, all missing keys will + * emit a set event with undefined value. + */ +function copyPaths (newObj, oldObj) { + if (typeOf(oldObj) !== OBJECT || typeOf(newObj) !== OBJECT) { + return + } + var path, type, oldVal, newVal + for (path in oldObj) { + if (!(path in newObj)) { + oldVal = oldObj[path] + type = typeOf(oldVal) + if (type === OBJECT) { + newVal = newObj[path] = {} + copyPaths(newVal, oldVal) + } else if (type === ARRAY) { + newObj[path] = [] + } else { + newObj[path] = undefined + } + } + } +} + +/** + * walk along a path and make sure it can be accessed + * and enumerated in that object + */ +function ensurePath (obj, key) { + var path = key.split('.'), sec + for (var i = 0, d = path.length - 1; i < d; i++) { + sec = path[i] + if (!obj[sec]) { + obj[sec] = {} + if (obj.__observer__) convert(obj, sec) + } + obj = obj[sec] + } + if (typeOf(obj) === OBJECT) { + sec = path[i] + if (!(sec in obj)) { + obj[sec] = undefined + if (obj.__observer__) convert(obj, sec) + } + } +} + +/** + * Observe an object with a given path, + * and proxy get/set/mutate events to the provided observer. + */ +function observe (obj, rawPath, observer) { + if (!isWatchable(obj)) return + var path = rawPath ? rawPath + '.' : '', + ob, alreadyConverted = !!obj.__observer__ + if (!alreadyConverted) { + def(obj, '__observer__', new Emitter()) + } + ob = obj.__observer__ + ob.values = ob.values || utils.hash() + observer.proxies = observer.proxies || {} + var proxies = observer.proxies[path] = { + get: function (key) { + observer.emit('get', path + key) + }, + set: function (key, val) { + observer.emit('set', path + key, val) + }, + mutate: function (key, val, mutation) { + // if the Array is a root value + // the key will be null + var fixedPath = key ? path + key : rawPath + observer.emit('mutate', fixedPath, val, mutation) + // also emit set for Array's length when it mutates + var m = mutation.method + if (m !== 'sort' && m !== 'reverse') { + observer.emit('set', fixedPath + '.length', val.length) + } + } + } + ob + .on('get', proxies.get) + .on('set', proxies.set) + .on('mutate', proxies.mutate) + if (alreadyConverted) { + emitSet(obj) + } else { + var type = typeOf(obj) + if (type === OBJECT) { + watchObject(obj) + } else if (type === ARRAY) { + watchArray(obj) + } + } +} + +/** + * Cancel observation, turn off the listeners. + */ +function unobserve (obj, path, observer) { + if (!obj || !obj.__observer__) return + path = path ? path + '.' : '' + var proxies = observer.proxies[path] + if (!proxies) return + obj.__observer__ + .off('get', proxies.get) + .off('set', proxies.set) + .off('mutate', proxies.mutate) + observer.proxies[path] = null +} + +var pub = module.exports = { + + // whether to emit get events + // only enabled during dependency parsing + shouldGet : false, + + observe : observe, + unobserve : unobserve, + ensurePath : ensurePath, + convert : convert, + copyPaths : copyPaths, + watchArray : watchArray +} +}); +require.register("vue/src/directive.js", function(exports, require, module){ +var utils = require('./utils'), + directives = require('./directives'), + filters = require('./filters'), + + // Regexes! + + // regex to split multiple directive expressions + // split by commas, but ignore commas within quotes, parens and escapes. + SPLIT_RE = /(?:['"](?:\\.|[^'"])*['"]|\((?:\\.|[^\)])*\)|\\.|[^,])+/g, + + // match up to the first single pipe, ignore those within quotes. + KEY_RE = /^(?:['"](?:\\.|[^'"])*['"]|\\.|[^\|]|\|\|)+/, + + ARG_RE = /^([\w- ]+):(.+)$/, + FILTERS_RE = /\|[^\|]+/g, + FILTER_TOKEN_RE = /[^\s']+|'[^']+'/g, + NESTING_RE = /^\$(parent|root)\./, + SINGLE_VAR_RE = /^[\w\.\$]+$/ + +/** + * Directive class + * represents a single directive instance in the DOM + */ +function Directive (definition, expression, rawKey, compiler, node) { + + this.compiler = compiler + this.vm = compiler.vm + this.el = node + + var isEmpty = expression === '' + + // mix in properties from the directive definition + if (typeof definition === 'function') { + this[isEmpty ? 'bind' : '_update'] = definition + } else { + for (var prop in definition) { + if (prop === 'unbind' || prop === 'update') { + this['_' + prop] = definition[prop] + } else { + this[prop] = definition[prop] + } + } + } + + // empty expression, we're done. + if (isEmpty) { + this.isEmpty = true + return + } + + this.expression = expression.trim() + this.rawKey = rawKey + + parseKey(this, rawKey) + + this.isExp = !SINGLE_VAR_RE.test(this.key) || NESTING_RE.test(this.key) + + var filterExps = this.expression.slice(rawKey.length).match(FILTERS_RE) + if (filterExps) { + this.filters = [] + var i = 0, l = filterExps.length, filter + for (; i < l; i++) { + filter = parseFilter(filterExps[i], this.compiler) + if (filter) this.filters.push(filter) + } + if (!this.filters.length) this.filters = null + } else { + this.filters = null + } +} + +var DirProto = Directive.prototype + +/** + * parse a key, extract argument and nesting/root info + */ +function parseKey (dir, rawKey) { + var key = rawKey + if (rawKey.indexOf(':') > -1) { + var argMatch = rawKey.match(ARG_RE) + key = argMatch + ? argMatch[2].trim() + : key + dir.arg = argMatch + ? argMatch[1].trim() + : null + } + dir.key = key +} + +/** + * parse a filter expression + */ +function parseFilter (filter, compiler) { + + var tokens = filter.slice(1).match(FILTER_TOKEN_RE) + if (!tokens) return + tokens = tokens.map(function (token) { + return token.replace(/'/g, '').trim() + }) + + var name = tokens[0], + apply = compiler.getOption('filters', name) || filters[name] + if (!apply) { + utils.warn('Unknown filter: ' + name) + return + } + + return { + name : name, + apply : apply, + args : tokens.length > 1 + ? tokens.slice(1) + : null + } +} + +/** + * called when a new value is set + * for computed properties, this will only be called once + * during initialization. + */ +DirProto.update = function (value, init) { + if (!init && value === this.value) return + this.value = value + if (this._update) { + this._update( + this.filters + ? this.applyFilters(value) + : value + ) + } +} + +/** + * pipe the value through filters + */ +DirProto.applyFilters = function (value) { + var filtered = value, filter + for (var i = 0, l = this.filters.length; i < l; i++) { + filter = this.filters[i] + filtered = filter.apply.call(this.vm, filtered, filter.args) + } + return filtered +} + +/** + * Unbind diretive + * @ param {Boolean} update + * Sometimes we call unbind before an update (i.e. not destroy) + * just to teardown previous stuff, in that case we do not want + * to null everything. + */ +DirProto.unbind = function (update) { + // this can be called before the el is even assigned... + if (!this.el) return + if (this._unbind) this._unbind(update) + if (!update) this.vm = this.el = this.binding = this.compiler = null +} + +// exposed methods ------------------------------------------------------------ + +/** + * split a unquoted-comma separated expression into + * multiple clauses + */ +Directive.split = function (exp) { + return exp.indexOf(',') > -1 + ? exp.match(SPLIT_RE) || [''] + : [exp] +} + +/** + * make sure the directive and expression is valid + * before we create an instance + */ +Directive.parse = function (dirname, expression, compiler, node) { + + var dir = compiler.getOption('directives', dirname) || directives[dirname] + if (!dir) return utils.warn('unknown directive: ' + dirname) + + var rawKey + if (expression.indexOf('|') > -1) { + var keyMatch = expression.match(KEY_RE) + if (keyMatch) { + rawKey = keyMatch[0].trim() + } + } else { + rawKey = expression.trim() + } + + // have a valid raw key, or be an empty directive + return (rawKey || expression === '') + ? new Directive(dir, expression, rawKey, compiler, node) + : utils.warn('invalid directive expression: ' + expression) +} + +module.exports = Directive +}); +require.register("vue/src/exp-parser.js", function(exports, require, module){ +var utils = require('./utils'), + stringSaveRE = /"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'/g, + stringRestoreRE = /"(\d+)"/g + +// Variable extraction scooped from https://github.com/RubyLouvre/avalon + +var KEYWORDS = + // keywords + 'break,case,catch,continue,debugger,default,delete,do,else,false' + + ',finally,for,function,if,in,instanceof,new,null,return,switch,this' + + ',throw,true,try,typeof,var,void,while,with,undefined' + + // reserved + ',abstract,boolean,byte,char,class,const,double,enum,export,extends' + + ',final,float,goto,implements,import,int,interface,long,native' + + ',package,private,protected,public,short,static,super,synchronized' + + ',throws,transient,volatile' + + // ECMA 5 - use strict + ',arguments,let,yield' + + // allow using Math in expressions + ',Math', + + KEYWORDS_RE = new RegExp(["\\b" + KEYWORDS.replace(/,/g, '\\b|\\b') + "\\b"].join('|'), 'g'), + REMOVE_RE = /\/\*(?:.|\n)*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|'[^']*'|"[^"]*"|[\s\t\n]*\.[\s\t\n]*[$\w\.]+/g, + SPLIT_RE = /[^\w$]+/g, + NUMBER_RE = /\b\d[^,]*/g, + BOUNDARY_RE = /^,+|,+$/g + +/** + * Strip top level variable names from a snippet of JS expression + */ +function getVariables (code) { + code = code + .replace(REMOVE_RE, '') + .replace(SPLIT_RE, ',') + .replace(KEYWORDS_RE, '') + .replace(NUMBER_RE, '') + .replace(BOUNDARY_RE, '') + return code + ? code.split(/,+/) + : [] +} + +/** + * A given path could potentially exist not on the + * current compiler, but up in the parent chain somewhere. + * This function generates an access relationship string + * that can be used in the getter function by walking up + * the parent chain to check for key existence. + * + * It stops at top parent if no vm in the chain has the + * key. It then creates any missing bindings on the + * final resolved vm. + */ +function getRel (path, compiler) { + var rel = '', + dist = 0, + self = compiler + while (compiler) { + if (compiler.hasKey(path)) { + break + } else { + compiler = compiler.parentCompiler + dist++ + } + } + if (compiler) { + while (dist--) { + rel += '$parent.' + } + if (!compiler.bindings[path] && path.charAt(0) !== '$') { + compiler.createBinding(path) + } + } else { + self.createBinding(path) + } + return rel +} + +/** + * Create a function from a string... + * this looks like evil magic but since all variables are limited + * to the VM's data it's actually properly sandboxed + */ +function makeGetter (exp, raw) { + /* jshint evil: true */ + var fn + try { + fn = new Function(exp) + } catch (e) { + utils.warn('Invalid expression: ' + raw) + } + return fn +} + +/** + * Escape a leading dollar sign for regex construction + */ +function escapeDollar (v) { + return v.charAt(0) === '$' + ? '\\' + v + : v +} + +module.exports = { + + /** + * Parse and return an anonymous computed property getter function + * from an arbitrary expression, together with a list of paths to be + * created as bindings. + */ + parse: function (exp, compiler) { + // extract variable names + var vars = getVariables(exp) + if (!vars.length) { + return makeGetter('return ' + exp, exp) + } + vars = utils.unique(vars) + var accessors = '', + has = utils.hash(), + strings = [], + // construct a regex to extract all valid variable paths + // ones that begin with "$" are particularly tricky + // because we can't use \b for them + pathRE = new RegExp( + "[^$\\w\\.](" + + vars.map(escapeDollar).join('|') + + ")[$\\w\\.]*\\b", 'g' + ), + body = ('return ' + exp) + .replace(stringSaveRE, saveStrings) + .replace(pathRE, replacePath) + .replace(stringRestoreRE, restoreStrings) + body = accessors + body + + function saveStrings (str) { + var i = strings.length + strings[i] = str + return '"' + i + '"' + } + + function replacePath (path) { + // keep track of the first char + var c = path.charAt(0) + path = path.slice(1) + var val = 'this.' + getRel(path, compiler) + path + if (!has[path]) { + accessors += val + ';' + has[path] = 1 + } + // don't forget to put that first char back + return c + val + } + + function restoreStrings (str, i) { + return strings[i] + } + + return makeGetter(body, exp) + } +} +}); +require.register("vue/src/text-parser.js", function(exports, require, module){ +var BINDING_RE = /\{\{(.+?)\}\}/ + +/** + * Parse a piece of text, return an array of tokens + */ +function parse (text) { + if (!BINDING_RE.test(text)) return null + var m, i, tokens = [] + /* jshint boss: true */ + while (m = text.match(BINDING_RE)) { + i = m.index + if (i > 0) tokens.push(text.slice(0, i)) + tokens.push({ key: m[1].trim() }) + text = text.slice(i + m[0].length) + } + if (text.length) tokens.push(text) + return tokens +} + +/** + * Parse an attribute value with possible interpolation tags + * return a Directive-friendly expression + */ +function parseAttr (attr) { + var tokens = parse(attr) + if (!tokens) return null + var res = [], token + for (var i = 0, l = tokens.length; i < l; i++) { + token = tokens[i] + res.push(token.key || ('"' + token + '"')) + } + return res.join('+') +} + +exports.parse = parse +exports.parseAttr = parseAttr +}); +require.register("vue/src/deps-parser.js", function(exports, require, module){ +var Emitter = require('./emitter'), + utils = require('./utils'), + Observer = require('./observer'), + catcher = new Emitter() + +/** + * Auto-extract the dependencies of a computed property + * by recording the getters triggered when evaluating it. + */ +function catchDeps (binding) { + if (binding.isFn) return + utils.log('\n- ' + binding.key) + var got = utils.hash() + catcher.on('get', function (dep) { + var has = got[dep.key] + if (has && has.compiler === dep.compiler) return + got[dep.key] = dep + utils.log(' - ' + dep.key) + binding.deps.push(dep) + dep.subs.push(binding) + }) + binding.value.$get() + catcher.off('get') +} + +module.exports = { + + /** + * the observer that catches events triggered by getters + */ + catcher: catcher, + + /** + * parse a list of computed property bindings + */ + parse: function (bindings) { + utils.log('\nparsing dependencies...') + Observer.shouldGet = true + bindings.forEach(catchDeps) + Observer.shouldGet = false + utils.log('\ndone.') + } + +} +}); +require.register("vue/src/filters.js", function(exports, require, module){ +var keyCodes = { + enter : 13, + tab : 9, + 'delete' : 46, + up : 38, + left : 37, + right : 39, + down : 40, + esc : 27 +} + +module.exports = { + + /** + * 'abc' => 'Abc' + */ + capitalize: function (value) { + if (!value && value !== 0) return '' + value = value.toString() + return value.charAt(0).toUpperCase() + value.slice(1) + }, + + /** + * 'abc' => 'ABC' + */ + uppercase: function (value) { + return (value || value === 0) + ? value.toString().toUpperCase() + : '' + }, + + /** + * 'AbC' => 'abc' + */ + lowercase: function (value) { + return (value || value === 0) + ? value.toString().toLowerCase() + : '' + }, + + /** + * 12345 => $12,345.00 + */ + currency: function (value, args) { + if (!value && value !== 0) return '' + var sign = (args && args[0]) || '$', + s = Math.floor(value).toString(), + i = s.length % 3, + h = i > 0 ? (s.slice(0, i) + (s.length > 3 ? ',' : '')) : '', + f = '.' + value.toFixed(2).slice(-2) + return sign + h + s.slice(i).replace(/(\d{3})(?=\d)/g, '$1,') + f + }, + + /** + * args: an array of strings corresponding to + * the single, double, triple ... forms of the word to + * be pluralized. When the number to be pluralized + * exceeds the length of the args, it will use the last + * entry in the array. + * + * e.g. ['single', 'double', 'triple', 'multiple'] + */ + pluralize: function (value, args) { + return args.length > 1 + ? (args[value - 1] || args[args.length - 1]) + : (args[value - 1] || args[0] + 's') + }, + + /** + * A special filter that takes a handler function, + * wraps it so it only gets triggered on specific keypresses. + */ + key: function (handler, args) { + if (!handler) return + var code = keyCodes[args[0]] + if (!code) { + code = parseInt(args[0], 10) + } + return function (e) { + if (e.keyCode === code) { + handler.call(this, e) + } + } + } +} +}); +require.register("vue/src/transition.js", function(exports, require, module){ +var endEvent = sniffTransitionEndEvent(), + config = require('./config'), + // exit codes for testing + codes = { + CSS_E : 1, + CSS_L : 2, + JS_E : 3, + JS_L : 4, + CSS_SKIP : -1, + JS_SKIP : -2, + JS_SKIP_E : -3, + JS_SKIP_L : -4, + INIT : -5, + SKIP : -6 + } + +/** + * stage: + * 1 = enter + * 2 = leave + */ +var transition = module.exports = function (el, stage, cb, compiler) { + + var changeState = function () { + cb() + compiler.execHook(stage > 0 ? 'enteredView' : 'leftView') + } + + if (compiler.init) { + changeState() + return codes.INIT + } + + var transitionId = el.vue_trans + + if (transitionId) { + return applyTransitionFunctions( + el, + stage, + changeState, + transitionId, + compiler + ) + } else if (transitionId === '') { + return applyTransitionClass( + el, + stage, + changeState + ) + } else { + changeState() + return codes.SKIP + } + +} + +transition.codes = codes + +/** + * Togggle a CSS class to trigger transition + */ +function applyTransitionClass (el, stage, changeState) { + + if (!endEvent) { + changeState() + return codes.CSS_SKIP + } + + var classList = el.classList, + lastLeaveCallback = el.vue_trans_cb + + if (stage > 0) { // enter + + // cancel unfinished leave transition + if (lastLeaveCallback) { + el.removeEventListener(endEvent, lastLeaveCallback) + el.vue_trans_cb = null + } + + // set to hidden state before appending + classList.add(config.enterClass) + // append + changeState() + // force a layout so transition can be triggered + /* jshint unused: false */ + var forceLayout = el.clientHeight + // trigger transition + classList.remove(config.enterClass) + return codes.CSS_E + + } else { // leave + + // trigger hide transition + classList.add(config.leaveClass) + var onEnd = function (e) { + if (e.target === el) { + el.removeEventListener(endEvent, onEnd) + el.vue_trans_cb = null + // actually remove node here + changeState() + classList.remove(config.leaveClass) + } + } + // attach transition end listener + el.addEventListener(endEvent, onEnd) + el.vue_trans_cb = onEnd + return codes.CSS_L + + } + +} + +function applyTransitionFunctions (el, stage, changeState, functionId, compiler) { + + var funcs = compiler.getOption('transitions', functionId) + if (!funcs) { + changeState() + return codes.JS_SKIP + } + + var enter = funcs.enter, + leave = funcs.leave + + if (stage > 0) { // enter + if (typeof enter !== 'function') { + changeState() + return codes.JS_SKIP_E + } + enter(el, changeState) + return codes.JS_E + } else { // leave + if (typeof leave !== 'function') { + changeState() + return codes.JS_SKIP_L + } + leave(el, changeState) + return codes.JS_L + } + +} + +/** + * Sniff proper transition end event name + */ +function sniffTransitionEndEvent () { + var el = document.createElement('vue'), + defaultEvent = 'transitionend', + events = { + 'transition' : defaultEvent, + 'mozTransition' : defaultEvent, + 'webkitTransition' : 'webkitTransitionEnd' + } + for (var name in events) { + if (el.style[name] !== undefined) { + return events[name] + } + } +} +}); +require.register("vue/src/batcher.js", function(exports, require, module){ +var utils = require('./utils'), + queue, has, waiting + +reset() + +exports.queue = function (binding) { + if (!has[binding.id]) { + queue.push(binding) + has[binding.id] = true + if (!waiting) { + waiting = true + utils.nextTick(flush) + } + } +} + +function flush () { + for (var i = 0; i < queue.length; i++) { + var b = queue[i] + if (b.unbound) continue + b._update() + has[b.id] = false + } + reset() +} + +function reset () { + queue = [] + has = utils.hash() + waiting = false +} +}); +require.register("vue/src/directives/index.js", function(exports, require, module){ +var utils = require('../utils'), + transition = require('../transition') + +module.exports = { + + on : require('./on'), + repeat : require('./repeat'), + model : require('./model'), + 'if' : require('./if'), + 'with' : require('./with'), + + attr: function (value) { + this.el.setAttribute(this.arg, value) + }, + + text: function (value) { + this.el.textContent = utils.toText(value) + }, + + html: function (value) { + this.el.innerHTML = utils.toText(value) + }, + + show: function (value) { + var el = this.el, + target = value ? '' : 'none', + change = function () { + el.style.display = target + } + transition(el, value ? 1 : -1, change, this.compiler) + }, + + 'class': function (value) { + if (this.arg) { + this.el.classList[value ? 'add' : 'remove'](this.arg) + } else { + if (this.lastVal) { + this.el.classList.remove(this.lastVal) + } + if (value) { + this.el.classList.add(value) + this.lastVal = value + } + } + } + +} +}); +require.register("vue/src/directives/if.js", function(exports, require, module){ +var config = require('../config'), + transition = require('../transition') + +module.exports = { + + bind: function () { + this.parent = this.el.parentNode + this.ref = document.createComment(config.prefix + '-if-' + this.key) + this.el.vue_ref = this.ref + }, + + update: function (value) { + + var el = this.el + + if (!this.parent) { // the node was detached when bound + if (!el.parentNode) { + return + } else { + this.parent = el.parentNode + } + } + + // should always have this.parent if we reach here + var parent = this.parent, + ref = this.ref, + compiler = this.compiler + + if (!value) { + transition(el, -1, remove, compiler) + } else { + transition(el, 1, insert, compiler) + } + + function remove () { + if (!el.parentNode) return + // insert the reference node + var next = el.nextSibling + if (next) { + parent.insertBefore(ref, next) + } else { + parent.appendChild(ref) + } + parent.removeChild(el) + } + + function insert () { + if (el.parentNode) return + parent.insertBefore(el, ref) + parent.removeChild(ref) + } + }, + + unbind: function () { + this.el.vue_ref = null + } +} +}); +require.register("vue/src/directives/repeat.js", function(exports, require, module){ +var Observer = require('../observer'), + Emitter = require('../emitter'), + utils = require('../utils'), + config = require('../config'), + transition = require('../transition'), + ViewModel // lazy def to avoid circular dependency + +/** + * Mathods that perform precise DOM manipulation + * based on mutator method triggered + */ +var mutationHandlers = { + + push: function (m) { + var i, l = m.args.length, + base = this.collection.length - l + for (i = 0; i < l; i++) { + this.buildItem(m.args[i], base + i) + } + }, + + pop: function () { + var vm = this.vms.pop() + if (vm) vm.$destroy() + }, + + unshift: function (m) { + var i, l = m.args.length + for (i = 0; i < l; i++) { + this.buildItem(m.args[i], i) + } + }, + + shift: function () { + var vm = this.vms.shift() + if (vm) vm.$destroy() + }, + + splice: function (m) { + var i, l, + index = m.args[0], + removed = m.args[1], + added = m.args.length - 2, + removedVMs = this.vms.splice(index, removed) + for (i = 0, l = removedVMs.length; i < l; i++) { + removedVMs[i].$destroy() + } + for (i = 0; i < added; i++) { + this.buildItem(m.args[i + 2], index + i) + } + }, + + sort: function () { + var vms = this.vms, + col = this.collection, + l = col.length, + sorted = new Array(l), + i, j, vm, data + for (i = 0; i < l; i++) { + data = col[i] + for (j = 0; j < l; j++) { + vm = vms[j] + if (vm.$data === data) { + sorted[i] = vm + break + } + } + } + for (i = 0; i < l; i++) { + this.container.insertBefore(sorted[i].$el, this.ref) + } + this.vms = sorted + }, + + reverse: function () { + var vms = this.vms + vms.reverse() + for (var i = 0, l = vms.length; i < l; i++) { + this.container.insertBefore(vms[i].$el, this.ref) + } + } +} + +module.exports = { + + bind: function () { + + var self = this, + el = self.el, + ctn = self.container = el.parentNode + + // extract child VM information, if any + ViewModel = ViewModel || require('../viewmodel') + self.Ctor = self.Ctor || ViewModel + + // extract transition information + self.hasTrans = el.hasAttribute(config.attrs.transition) + + // create a comment node as a reference node for DOM insertions + self.ref = document.createComment(config.prefix + '-repeat-' + self.key) + ctn.insertBefore(self.ref, el) + ctn.removeChild(el) + + self.initiated = false + self.collection = null + self.vms = null + self.mutationListener = function (path, arr, mutation) { + var method = mutation.method + mutationHandlers[method].call(self, mutation) + if (method !== 'push' && method !== 'pop') { + self.updateIndexes() + } + } + + }, + + update: function (collection) { + + this.unbind(true) + // attach an object to container to hold handlers + this.container.vue_dHandlers = utils.hash() + // if initiating with an empty collection, we need to + // force a compile so that we get all the bindings for + // dependency extraction. + if (!this.initiated && (!collection || !collection.length)) { + this.buildItem() + this.initiated = true + } + collection = this.collection = collection || [] + this.vms = [] + + // listen for collection mutation events + // the collection has been augmented during Binding.set() + if (!collection.__observer__) Observer.watchArray(collection, null, new Emitter()) + collection.__observer__.on('mutate', this.mutationListener) + + // create child-vms and append to DOM + if (collection.length) { + for (var i = 0, l = collection.length; i < l; i++) { + this.buildItem(collection[i], i) + } + } + }, + + /** + * Create a new child VM from a data object + * passing along compiler options indicating this + * is a v-repeat item. + */ + buildItem: function (data, index) { + + var node = this.el.cloneNode(true), + ctn = this.container, + ref, item + + // append node into DOM first + // so v-if can get access to parentNode + if (data) { + ref = this.vms.length > index + ? this.vms[index].$el + : this.ref + // make sure it works with v-if + if (!ref.parentNode) ref = ref.vue_ref + // process transition info before appending + node.vue_trans = utils.attr(node, 'transition', true) + transition(node, 1, function () { + ctn.insertBefore(node, ref) + }, this.compiler) + } + + item = new this.Ctor({ + el: node, + data: data, + compilerOptions: { + repeat: true, + repeatIndex: index, + repeatCollection: this.collection, + parentCompiler: this.compiler, + delegator: ctn + } + }) + + if (!data) { + // this is a forced compile for an empty collection. + // let's remove it... + item.$destroy() + } else { + this.vms.splice(index, 0, item) + } + }, + + /** + * Update index of each item after a mutation + */ + updateIndexes: function () { + var i = this.vms.length + while (i--) { + this.vms[i].$data.$index = i + } + }, + + unbind: function () { + if (this.collection) { + this.collection.__observer__.off('mutate', this.mutationListener) + var i = this.vms.length + while (i--) { + this.vms[i].$destroy() + } + } + var ctn = this.container, + handlers = ctn.vue_dHandlers + for (var key in handlers) { + ctn.removeEventListener(handlers[key].event, handlers[key]) + } + ctn.vue_dHandlers = null + } +} +}); +require.register("vue/src/directives/on.js", function(exports, require, module){ +var utils = require('../utils') + +function delegateCheck (el, root, identifier) { + while (el && el !== root) { + if (el[identifier]) return el + el = el.parentNode + } +} + +module.exports = { + + isFn: true, + + bind: function () { + if (this.compiler.repeat) { + // attach an identifier to the el + // so it can be matched during event delegation + this.el[this.expression] = true + // attach the owner viewmodel of this directive + this.el.vue_viewmodel = this.vm + } + }, + + update: function (handler) { + this.unbind(true) + if (typeof handler !== 'function') { + return utils.warn('Directive "on" expects a function value.') + } + + var compiler = this.compiler, + event = this.arg, + isExp = this.binding.isExp, + ownerVM = this.binding.compiler.vm + + if (compiler.repeat && + // do not delegate if the repeat is combined with an extended VM + !this.vm.constructor.super && + // blur and focus events do not bubble + event !== 'blur' && event !== 'focus') { + + // for each blocks, delegate for better performance + // focus and blur events dont bubble so exclude them + var delegator = compiler.delegator, + identifier = this.expression, + dHandler = delegator.vue_dHandlers[identifier] + + if (dHandler) return + + // the following only gets run once for the entire each block + dHandler = delegator.vue_dHandlers[identifier] = function (e) { + var target = delegateCheck(e.target, delegator, identifier) + if (target) { + e.el = target + e.targetVM = target.vue_viewmodel + handler.call(isExp ? e.targetVM : ownerVM, e) + } + } + dHandler.event = event + delegator.addEventListener(event, dHandler) + + } else { + + // a normal, single element handler + var vm = this.vm + this.handler = function (e) { + e.el = e.currentTarget + e.targetVM = vm + handler.call(ownerVM, e) + } + this.el.addEventListener(event, this.handler) + + } + }, + + unbind: function (update) { + this.el.removeEventListener(this.arg, this.handler) + this.handler = null + if (!update) this.el.vue_viewmodel = null + } +} +}); +require.register("vue/src/directives/model.js", function(exports, require, module){ +var utils = require('../utils'), + isIE9 = navigator.userAgent.indexOf('MSIE 9.0') > 0 + +module.exports = { + + bind: function () { + + var self = this, + el = self.el, + type = el.type, + tag = el.tagName + + self.lock = false + + // determine what event to listen to + self.event = + (self.compiler.options.lazy || + tag === 'SELECT' || + type === 'checkbox' || type === 'radio') + ? 'change' + : 'input' + + // determine the attribute to change when updating + var attr = self.attr = type === 'checkbox' + ? 'checked' + : (tag === 'INPUT' || tag === 'SELECT' || tag === 'TEXTAREA') + ? 'value' + : 'innerHTML' + + var compositionLock = false + this.cLock = function () { + compositionLock = true + } + this.cUnlock = function () { + compositionLock = false + } + el.addEventListener('compositionstart', this.cLock) + el.addEventListener('compositionend', this.cUnlock) + + // attach listener + self.set = self.filters + ? function () { + if (compositionLock) return + // if this directive has filters + // we need to let the vm.$set trigger + // update() so filters are applied. + // therefore we have to record cursor position + // so that after vm.$set changes the input + // value we can put the cursor back at where it is + var cursorPos + try { + cursorPos = el.selectionStart + } catch (e) {} + self.vm.$set(self.key, el[attr]) + // since updates are async + // we need to reset cursor position async too + utils.nextTick(function () { + if (cursorPos !== undefined) { + el.setSelectionRange(cursorPos, cursorPos) + } + }) + } + : function () { + if (compositionLock) return + // no filters, don't let it trigger update() + self.lock = true + self.vm.$set(self.key, el[attr]) + utils.nextTick(function () { + self.lock = false + }) + } + el.addEventListener(self.event, self.set) + + // fix shit for IE9 + // since it doesn't fire input on backspace / del / cut + if (isIE9) { + self.onCut = function () { + // cut event fires before the value actually changes + utils.nextTick(function () { + self.set() + }) + } + self.onDel = function (e) { + if (e.keyCode === 46 || e.keyCode === 8) { + self.set() + } + } + el.addEventListener('cut', self.onCut) + el.addEventListener('keyup', self.onDel) + } + }, + + update: function (value) { + if (this.lock) return + /* jshint eqeqeq: false */ + var self = this, + el = self.el + if (el.tagName === 'SELECT') { // select dropdown + // setting