From 61eaa271c0694cc4cf7296637b55b5481dbd3f98 Mon Sep 17 00:00:00 2001 From: Evan You Date: Mon, 1 Jun 2015 16:56:45 -0400 Subject: [PATCH] [release] 0.12.0-rc --- bower.json | 2 +- component.json | 2 +- dist/vue.js | 13038 ++++++++++++++++++++++++---------------------- dist/vue.min.js | 7 +- package.json | 2 +- 5 files changed, 6683 insertions(+), 6368 deletions(-) diff --git a/bower.json b/bower.json index 2b782a58..9adb07cf 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "vue", - "version": "0.12.0-beta5", + "version": "0.12.0-rc", "main": "dist/vue.js", "description": "Simple, Fast & Composable MVVM for building interative interfaces", "authors": ["Evan You "], diff --git a/component.json b/component.json index bb3ba4e5..f416457b 100644 --- a/component.json +++ b/component.json @@ -1,6 +1,6 @@ { "name": "vue", - "version": "0.12.0-beta5", + "version": "0.12.0-rc", "main": "src/vue.js", "author": "Evan You ", "description": "Simple, Fast & Composable MVVM for building interative interfaces", diff --git a/dist/vue.js b/dist/vue.js index 1c646ba4..a85048b2 100644 --- a/dist/vue.js +++ b/dist/vue.js @@ -1,3 +1,9 @@ +/** + * Vue.js v0.12.0-rc + * (c) 2015 Evan You + * Released under the MIT License. + */ + (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); @@ -11,41 +17,41 @@ return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; -/******/ + /******/ // The require function /******/ function __webpack_require__(moduleId) { -/******/ + /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) /******/ return installedModules[moduleId].exports; -/******/ + /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ exports: {}, /******/ id: moduleId, /******/ loaded: false /******/ }; -/******/ + /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ + /******/ // Flag the module as loaded /******/ module.loaded = true; -/******/ + /******/ // Return the exports of the module /******/ return module.exports; /******/ } -/******/ -/******/ + + /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; -/******/ + /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; -/******/ + /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; -/******/ + /******/ // Load entry module and return exports /******/ return __webpack_require__(0); /******/ }) @@ -54,9 +60,9 @@ return /******/ (function(modules) { // webpackBootstrap /* 0 */ /***/ function(module, exports, __webpack_require__) { - var _ = __webpack_require__(11) + var _ = __webpack_require__(2) var extend = _.extend - + /** * The exposed Vue constructor. * @@ -70,17 +76,17 @@ return /******/ (function(modules) { // webpackBootstrap * @param {Object} [options] * @public */ - + function Vue (options) { this._init(options) } - + /** * Mixin global API */ - - extend(Vue, __webpack_require__(1)) - + + extend(Vue, __webpack_require__(27)) + /** * Vue and every constructor that extends Vue has an * associated options object, which can be accessed during @@ -89,693 +95,68 @@ return /******/ (function(modules) { // webpackBootstrap * These can be seen as the default options of every * Vue instance. */ - + Vue.options = { - directives : __webpack_require__(12), - filters : __webpack_require__(13), - partials : {}, + directives : __webpack_require__(28), + filters : __webpack_require__(51), transitions : {}, - components : {} + components : {}, + elementDirectives: {} } - + /** * Build up the prototype */ - + var p = Vue.prototype - + /** * $data has a setter which does a bunch of * teardown/setup work */ - + Object.defineProperty(p, '$data', { get: function () { return this._data }, set: function (newData) { - this._setData(newData) + if (newData !== this._data) { + this._setData(newData) + } } }) - + /** * Mixin internal instance methods */ - - extend(p, __webpack_require__(2)) - extend(p, __webpack_require__(3)) - extend(p, __webpack_require__(4)) - extend(p, __webpack_require__(5)) - extend(p, __webpack_require__(62)) - + + extend(p, __webpack_require__(53)) + extend(p, __webpack_require__(54)) + extend(p, __webpack_require__(55)) + extend(p, __webpack_require__(1)) + extend(p, __webpack_require__(56)) + /** * Mixin public API methods */ - - extend(p, __webpack_require__(6)) - extend(p, __webpack_require__(7)) - extend(p, __webpack_require__(8)) - extend(p, __webpack_require__(9)) - extend(p, __webpack_require__(10)) - + + extend(p, __webpack_require__(57)) + extend(p, __webpack_require__(58)) + extend(p, __webpack_require__(59)) + extend(p, __webpack_require__(60)) + extend(p, __webpack_require__(61)) + module.exports = _.Vue = Vue /***/ }, /* 1 */ /***/ function(module, exports, __webpack_require__) { - var _ = __webpack_require__(11) - var mergeOptions = __webpack_require__(14) - - /** - * Expose useful internals - */ - - exports.util = _ - exports.nextTick = _.nextTick - exports.config = __webpack_require__(15) - - exports.compiler = { - compile: __webpack_require__(16), - transclude: __webpack_require__(17) - } - - exports.parsers = { - path: __webpack_require__(18), - text: __webpack_require__(19), - template: __webpack_require__(20), - directive: __webpack_require__(21), - expression: __webpack_require__(22) - } - - /** - * Each instance constructor, including Vue, has a unique - * cid. This enables us to create wrapped "child - * constructors" for prototypal inheritance and cache them. - */ - - exports.cid = 0 - var cid = 1 - - /** - * Class inehritance - * - * @param {Object} extendOptions - */ - - exports.extend = function (extendOptions) { - extendOptions = extendOptions || {} - var Super = this - var Sub = createClass( - extendOptions.name || - Super.options.name || - 'VueComponent' - ) - Sub.prototype = Object.create(Super.prototype) - Sub.prototype.constructor = Sub - Sub.cid = cid++ - Sub.options = mergeOptions( - Super.options, - extendOptions - ) - Sub['super'] = Super - // allow further extension - Sub.extend = Super.extend - // create asset registers, so extended classes - // can have their private assets too. - createAssetRegisters(Sub) - return Sub - } - - /** - * A function that returns a sub-class constructor with the - * given name. This gives us much nicer output when - * logging instances in the console. - * - * @param {String} name - * @return {Function} - */ - - function createClass (name) { - return new Function( - 'return function ' + _.classify(name) + - ' (options) { this._init(options) }' - )() - } - - /** - * Plugin system - * - * @param {Object} plugin - */ - - exports.use = function (plugin) { - // additional parameters - var args = _.toArray(arguments, 1) - args.unshift(this) - if (typeof plugin.install === 'function') { - plugin.install.apply(plugin, args) - } else { - plugin.apply(null, args) - } - return this - } - - /** - * Define asset registration methods on a constructor. - * - * @param {Function} Constructor - */ - - var assetTypes = [ - 'directive', - 'filter', - 'partial', - 'transition' - ] - - function createAssetRegisters (Constructor) { - - /* Asset registration methods share the same signature: - * - * @param {String} id - * @param {*} definition - */ - - assetTypes.forEach(function (type) { - Constructor[type] = function (id, definition) { - if (!definition) { - return this.options[type + 's'][id] - } else { - this.options[type + 's'][id] = definition - } - } - }) - - /** - * Component registration needs to automatically invoke - * Vue.extend on object values. - * - * @param {String} id - * @param {Object|Function} definition - */ - - Constructor.component = function (id, definition) { - if (!definition) { - return this.options.components[id] - } else { - if (_.isPlainObject(definition)) { - definition.name = id - definition = _.Vue.extend(definition) - } - this.options.components[id] = definition - } - } - } - - createAssetRegisters(exports) + var _ = __webpack_require__(2) + var Directive = __webpack_require__(10) + var compile = __webpack_require__(22) + var transclude = __webpack_require__(26) -/***/ }, -/* 2 */ -/***/ function(module, exports, __webpack_require__) { - - var mergeOptions = __webpack_require__(14) - - /** - * The main init sequence. This is called for every - * instance, including ones that are created from extended - * constructors. - * - * @param {Object} options - this options object should be - * the result of merging class - * options and the options passed - * in to the constructor. - */ - - exports._init = function (options) { - - options = options || {} - - this.$el = null - this.$parent = options._parent - this.$root = options._root || this - this.$ = {} // child vm references - this.$$ = {} // element references - this._watcherList = [] // all watchers as an array - this._watchers = {} // internal watchers as a hash - this._userWatchers = {} // user watchers as a hash - this._directives = [] // all directives - - // a flag to avoid this being observed - this._isVue = true - - // events bookkeeping - this._events = {} // registered callbacks - this._eventsCount = {} // for $broadcast optimization - this._eventCancelled = false // for event cancellation - - // block instance properties - this._isBlock = false - this._blockStart = // @type {CommentNode} - this._blockEnd = null // @type {CommentNode} - - // lifecycle state - this._isCompiled = - this._isDestroyed = - this._isReady = - this._isAttached = - this._isBeingDestroyed = false - this._unlinkFn = null - - // children - this._children = [] - this._childCtors = {} - - // transcluded components that belong to the parent. - // need to keep track of them so that we can call - // attached/detached hooks on them. - this._transCpnts = [] - this._host = options._host - - // push self into parent / transclusion host - if (this.$parent) { - this.$parent._children.push(this) - } - if (this._host) { - this._host._transCpnts.push(this) - } - - // props used in v-repeat diffing - this._new = true - this._reused = false - - // merge options. - options = this.$options = mergeOptions( - this.constructor.options, - options, - this - ) - - // set data after merge. - this._data = options.data || {} - - // initialize data observation and scope inheritance. - this._initScope() - - // setup event system and option events. - this._initEvents() - - // call created hook - this._callHook('created') - - // if `el` option is passed, start compilation. - if (options.el) { - this.$mount(options.el) - } - } - -/***/ }, -/* 3 */ -/***/ function(module, exports, __webpack_require__) { - - var _ = __webpack_require__(11) - var inDoc = _.inDoc - - /** - * Setup the instance's option events & watchers. - * If the value is a string, we pull it from the - * instance's methods by name. - */ - - exports._initEvents = function () { - var options = this.$options - registerCallbacks(this, '$on', options.events) - registerCallbacks(this, '$watch', options.watch) - } - - /** - * Register callbacks for option events and watchers. - * - * @param {Vue} vm - * @param {String} action - * @param {Object} hash - */ - - function registerCallbacks (vm, action, hash) { - if (!hash) return - var handlers, key, i, j - for (key in hash) { - handlers = hash[key] - if (_.isArray(handlers)) { - for (i = 0, j = handlers.length; i < j; i++) { - register(vm, action, key, handlers[i]) - } - } else { - register(vm, action, key, handlers) - } - } - } - - /** - * Helper to register an event/watch callback. - * - * @param {Vue} vm - * @param {String} action - * @param {String} key - * @param {*} handler - */ - - function register (vm, action, key, handler) { - var type = typeof handler - if (type === 'function') { - vm[action](key, handler) - } else if (type === 'string') { - var methods = vm.$options.methods - var method = methods && methods[handler] - if (method) { - vm[action](key, method) - } else { - _.warn( - 'Unknown method: "' + handler + '" when ' + - 'registering callback for ' + action + - ': "' + key + '".' - ) - } - } - } - - /** - * Setup recursive attached/detached calls - */ - - exports._initDOMHooks = function () { - this.$on('hook:attached', onAttached) - this.$on('hook:detached', onDetached) - } - - /** - * Callback to recursively call attached hook on children - */ - - function onAttached () { - this._isAttached = true - this._children.forEach(callAttach) - if (this._transCpnts.length) { - this._transCpnts.forEach(callAttach) - } - } - - /** - * Iterator to call attached hook - * - * @param {Vue} child - */ - - function callAttach (child) { - if (!child._isAttached && inDoc(child.$el)) { - child._callHook('attached') - } - } - - /** - * Callback to recursively call detached hook on children - */ - - function onDetached () { - this._isAttached = false - this._children.forEach(callDetach) - if (this._transCpnts.length) { - this._transCpnts.forEach(callDetach) - } - } - - /** - * Iterator to call detached hook - * - * @param {Vue} child - */ - - function callDetach (child) { - if (child._isAttached && !inDoc(child.$el)) { - child._callHook('detached') - } - } - - /** - * Trigger all handlers for a hook - * - * @param {String} hook - */ - - exports._callHook = function (hook) { - var handlers = this.$options[hook] - if (handlers) { - for (var i = 0, j = handlers.length; i < j; i++) { - handlers[i].call(this) - } - } - this.$emit('hook:' + hook) - } - -/***/ }, -/* 4 */ -/***/ function(module, exports, __webpack_require__) { - - var _ = __webpack_require__(11) - var Observer = __webpack_require__(26) - var Dep = __webpack_require__(23) - - /** - * Setup the scope of an instance, which contains: - * - observed data - * - computed properties - * - user methods - * - meta properties - */ - - exports._initScope = function () { - this._initData() - this._initComputed() - this._initMethods() - this._initMeta() - } - - /** - * Initialize the data. - */ - - exports._initData = function () { - // proxy data on instance - var data = this._data - var i, key - // make sure all paramAttributes properties are observed - var params = this.$options.paramAttributes - if (params) { - i = params.length - while (i--) { - key = _.camelize(params[i]) - if (!(key in data)) { - data[key] = null - } - } - } - var keys = Object.keys(data) - i = keys.length - while (i--) { - key = keys[i] - if (!_.isReserved(key)) { - this._proxy(key) - } - } - // observe data - Observer.create(data).addVm(this) - } - - /** - * Swap the isntance's $data. Called in $data's setter. - * - * @param {Object} newData - */ - - exports._setData = function (newData) { - newData = newData || {} - var oldData = this._data - this._data = newData - var keys, key, i - // unproxy keys not present in new data - keys = Object.keys(oldData) - i = keys.length - while (i--) { - key = keys[i] - if (!_.isReserved(key) && !(key in newData)) { - this._unproxy(key) - } - } - // proxy keys not already proxied, - // and trigger change for changed values - keys = Object.keys(newData) - i = keys.length - while (i--) { - key = keys[i] - if (!this.hasOwnProperty(key) && !_.isReserved(key)) { - // new property - this._proxy(key) - } - } - oldData.__ob__.removeVm(this) - Observer.create(newData).addVm(this) - this._digest() - } - - /** - * Proxy a property, so that - * vm.prop === vm._data.prop - * - * @param {String} key - */ - - exports._proxy = function (key) { - // need to store ref to self here - // because these getter/setters might - // be called by child instances! - var self = this - Object.defineProperty(self, key, { - configurable: true, - enumerable: true, - get: function proxyGetter () { - return self._data[key] - }, - set: function proxySetter (val) { - self._data[key] = val - } - }) - } - - /** - * Unproxy a property. - * - * @param {String} key - */ - - exports._unproxy = function (key) { - delete this[key] - } - - /** - * Force update on every watcher in scope. - */ - - exports._digest = function () { - var i = this._watcherList.length - while (i--) { - this._watcherList[i].update() - } - var children = this._children - i = children.length - while (i--) { - var child = children[i] - if (child.$options.inherit) { - child._digest() - } - } - } - - /** - * Setup computed properties. They are essentially - * special getter/setters - */ - - function noop () {} - exports._initComputed = function () { - var computed = this.$options.computed - if (computed) { - for (var key in computed) { - var userDef = computed[key] - var def = { - enumerable: true, - configurable: true - } - if (typeof userDef === 'function') { - def.get = _.bind(userDef, this) - def.set = noop - } else { - def.get = userDef.get - ? _.bind(userDef.get, this) - : noop - def.set = userDef.set - ? _.bind(userDef.set, this) - : noop - } - Object.defineProperty(this, key, def) - } - } - } - - /** - * Setup instance methods. Methods must be bound to the - * instance since they might be called by children - * inheriting them. - */ - - exports._initMethods = function () { - var methods = this.$options.methods - if (methods) { - for (var key in methods) { - this[key] = _.bind(methods[key], this) - } - } - } - - /** - * Initialize meta information like $index, $key & $value. - */ - - exports._initMeta = function () { - var metas = this.$options._meta - if (metas) { - for (var key in metas) { - this._defineMeta(key, metas[key]) - } - } - } - - /** - * Define a meta property, e.g $index, $key, $value - * which only exists on the vm instance but not in $data. - * - * @param {String} key - * @param {*} value - */ - - exports._defineMeta = function (key, value) { - var dep = new Dep() - Object.defineProperty(this, key, { - enumerable: true, - configurable: true, - get: function metaGetter () { - if (Observer.target) { - Observer.target.addDep(dep) - } - return value - }, - set: function metaSetter (val) { - if (val !== value) { - value = val - dep.notify() - } - } - }) - } - -/***/ }, -/* 5 */ -/***/ function(module, exports, __webpack_require__) { - - var _ = __webpack_require__(11) - var Directive = __webpack_require__(24) - var compile = __webpack_require__(16) - var transclude = __webpack_require__(17) - /** * Transclude, compile and link element. * @@ -788,7 +169,7 @@ return /******/ (function(modules) { // webpackBootstrap * @param {Element} el * @return {Element} */ - + exports._compile = function (el) { var options = this.$options if (options._linkFn) { @@ -811,19 +192,23 @@ return /******/ (function(modules) { // webpackBootstrap } return el } - + /** * Initialize instance element. Called in the public * $mount() method. * * @param {Element} el */ - + exports._initElement = function (el) { if (el instanceof DocumentFragment) { this._isBlock = true this.$el = this._blockStart = el.firstChild this._blockEnd = el.lastChild + // set persisted text anchors to empty + if (this._blockStart.nodeType === 3) { + this._blockStart.data = this._blockEnd.data = '' + } this._blockFragment = el } else { this.$el = el @@ -831,7 +216,7 @@ return /******/ (function(modules) { // webpackBootstrap this.$el.__vue__ = this this._callHook('beforeCompile') } - + /** * Create and bind a directive to an element. * @@ -841,13 +226,13 @@ return /******/ (function(modules) { // webpackBootstrap * @param {Object} def - directive definition object * @param {Vue|undefined} host - transclusion host component */ - + exports._bindDir = function (name, node, desc, def, host) { this._directives.push( new Directive(name, node, this, desc, def, host) ) } - + /** * Teardown an instance, unobserves the data, unbind all the * directives, turn off all the event listeners, etc. @@ -856,7 +241,7 @@ return /******/ (function(modules) { // webpackBootstrap * @param {Boolean} deferCleanup - if true, defer cleanup to * be called later */ - + exports._destroy = function (remove, deferCleanup) { if (this._isBeingDestroyed) { return @@ -887,13 +272,9 @@ return /******/ (function(modules) { // webpackBootstrap // splicing the directives this._unlinkFn(true) } - // teardown all user watchers. - var watcher - for (i in this._userWatchers) { - watcher = this._userWatchers[i] - if (watcher) { - watcher.teardown() - } + i = this._watchers.length + while (i--) { + this._watchers[i].teardown() } // remove reference to self on $el if (this.$el) { @@ -909,20 +290,18 @@ return /******/ (function(modules) { // webpackBootstrap this._cleanup() } } - + /** * Clean up to ensure garbage collection. * This is called after the leave transition if there * is any. */ - + exports._cleanup = function () { // remove reference from data ob this._data.__ob__.removeVm(this) this._data = this._watchers = - this._userWatchers = - this._watcherList = this.$el = this.$parent = this.$root = @@ -936,567 +315,820 @@ return /******/ (function(modules) { // webpackBootstrap this.$off() } +/***/ }, +/* 2 */ +/***/ function(module, exports, __webpack_require__) { + + var lang = __webpack_require__(5) + var extend = lang.extend + + extend(exports, lang) + extend(exports, __webpack_require__(6)) + extend(exports, __webpack_require__(7)) + extend(exports, __webpack_require__(3)) + extend(exports, __webpack_require__(8)) + extend(exports, __webpack_require__(9)) + +/***/ }, +/* 3 */ +/***/ function(module, exports, __webpack_require__) { + + var _ = __webpack_require__(2) + var config = __webpack_require__(4) + var commonTagRE = /^(div|p|span|img|a|br|ul|ol|li|h1|h2|h3|h4|h5|table|tbody|tr|td|pre)$/ + + /** + * Check if an element is a component, if yes return its + * component id. + * + * @param {Element} el + * @param {Object} options + * @return {String|undefined} + */ + + exports.checkComponent = function (el, options) { + var tag = el.tagName.toLowerCase() + if (tag === 'component') { + // dynamic syntax + var exp = el.getAttribute('is') + el.removeAttribute('is') + return exp + } else if ( + !commonTagRE.test(tag) && + _.resolveAsset(options, 'components', tag) + ) { + return tag + } + } + + /** + * Create an "anchor" for performing dom insertion/removals. + * This is used in a number of scenarios: + * - block instance + * - v-html + * - v-if + * - component + * - repeat + * + * @param {String} content + * @param {Boolean} persist - IE trashes empty textNodes on + * cloneNode(true), so in certain + * cases the anchor needs to be + * non-empty to be persisted in + * templates. + * @return {Comment|Text} + */ + + exports.createAnchor = function (content, persist) { + return config.debug + ? document.createComment(content) + : document.createTextNode(persist ? ' ' : '') + } + +/***/ }, +/* 4 */ +/***/ function(module, exports, __webpack_require__) { + + module.exports = { + + /** + * The prefix to look for when parsing directives. + * + * @type {String} + */ + + prefix: 'v-', + + /** + * Whether to print debug messages. + * Also enables stack trace for warnings. + * + * @type {Boolean} + */ + + debug: false, + + /** + * Whether to suppress warnings. + * + * @type {Boolean} + */ + + silent: false, + + /** + * Whether allow observer to alter data objects' + * __proto__. + * + * @type {Boolean} + */ + + proto: true, + + /** + * Whether to parse mustache tags in templates. + * + * @type {Boolean} + */ + + interpolate: true, + + /** + * Whether to use async rendering. + */ + + async: true, + + /** + * Whether to warn against errors caught when evaluating + * expressions. + */ + + warnExpressionErrors: true, + + /** + * Internal flag to indicate the delimiters have been + * changed. + * + * @type {Boolean} + */ + + _delimitersChanged: true, + + /** + * List of asset types that a component can own. + * + * @type {Array} + */ + + _assetTypes: [ + 'directive', + 'elementDirective', + 'filter', + 'transition' + ] + + } + + /** + * Interpolation delimiters. + * We need to mark the changed flag so that the text parser + * knows it needs to recompile the regex. + * + * @type {Array} + */ + + var delimiters = ['{{', '}}'] + Object.defineProperty(module.exports, 'delimiters', { + get: function () { + return delimiters + }, + set: function (val) { + delimiters = val + this._delimitersChanged = true + } + }) + +/***/ }, +/* 5 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Check is a string starts with $ or _ + * + * @param {String} str + * @return {Boolean} + */ + + exports.isReserved = function (str) { + var c = (str + '').charCodeAt(0) + return c === 0x24 || c === 0x5F + } + + /** + * Guard text output, make sure undefined outputs + * empty string + * + * @param {*} value + * @return {String} + */ + + exports.toString = function (value) { + return value == null + ? '' + : value.toString() + } + + /** + * Check and convert possible numeric numbers before + * setting back to data + * + * @param {*} value + * @return {*|Number} + */ + + exports.toNumber = function (value) { + return ( + isNaN(value) || + value === null || + typeof value === 'boolean' + ) ? value + : Number(value) + } + + /** + * Strip quotes from a string + * + * @param {String} str + * @return {String | false} + */ + + exports.stripQuotes = function (str) { + var a = str.charCodeAt(0) + var b = str.charCodeAt(str.length - 1) + return a === b && (a === 0x22 || a === 0x27) + ? str.slice(1, -1) + : false + } + + /** + * Replace helper + * + * @param {String} _ - matched delimiter + * @param {String} c - matched char + * @return {String} + */ + function toUpper (_, c) { + return c ? c.toUpperCase () : '' + } + + /** + * Camelize a hyphen-delmited string. + * + * @param {String} str + * @return {String} + */ + + var camelRE = /-(\w)/g + exports.camelize = function (str) { + return str.replace(camelRE, toUpper) + } + + /** + * Converts hyphen/underscore/slash delimitered names into + * camelized classNames. + * + * e.g. my-component => MyComponent + * some_else => SomeElse + * some/comp => SomeComp + * + * @param {String} str + * @return {String} + */ + + var classifyRE = /(?:^|[-_\/])(\w)/g + exports.classify = function (str) { + return str.replace(classifyRE, toUpper) + } + + /** + * Simple bind, faster than native + * + * @param {Function} fn + * @param {Object} ctx + * @return {Function} + */ + + exports.bind = function (fn, ctx) { + return function (a) { + var l = arguments.length + return l + ? l > 1 + ? fn.apply(ctx, arguments) + : fn.call(ctx, a) + : fn.call(ctx) + } + } + + /** + * Convert an Array-like object to a real Array. + * + * @param {Array-like} list + * @param {Number} [start] - start index + * @return {Array} + */ + + exports.toArray = function (list, start) { + start = start || 0 + var i = list.length - start + var ret = new Array(i) + while (i--) { + ret[i] = list[i + start] + } + return ret + } + + /** + * Mix properties into target object. + * + * @param {Object} to + * @param {Object} from + */ + + exports.extend = function (to, from) { + for (var key in from) { + to[key] = from[key] + } + return to + } + + /** + * Quick object check - this is primarily used to tell + * Objects from primitive values when we know the value + * is a JSON-compliant type. + * + * @param {*} obj + * @return {Boolean} + */ + + exports.isObject = function (obj) { + return obj && typeof obj === 'object' + } + + /** + * Strict object type check. Only returns true + * for plain JavaScript objects. + * + * @param {*} obj + * @return {Boolean} + */ + + var toString = Object.prototype.toString + exports.isPlainObject = function (obj) { + return toString.call(obj) === '[object Object]' + } + + /** + * Array type check. + * + * @param {*} obj + * @return {Boolean} + */ + + exports.isArray = function (obj) { + return Array.isArray(obj) + } + + /** + * Define a non-enumerable property + * + * @param {Object} obj + * @param {String} key + * @param {*} val + * @param {Boolean} [enumerable] + */ + + exports.define = function (obj, key, val, enumerable) { + Object.defineProperty(obj, key, { + value : val, + enumerable : !!enumerable, + writable : true, + configurable : true + }) + } + + /** + * Debounce a function so it only gets called after the + * input stops arriving after the given wait period. + * + * @param {Function} func + * @param {Number} wait + * @return {Function} - the debounced function + */ + + exports.debounce = function(func, wait) { + var timeout, args, context, timestamp, result + var later = function() { + var last = Date.now() - timestamp + if (last < wait && last >= 0) { + timeout = setTimeout(later, wait - last) + } else { + timeout = null + result = func.apply(context, args) + if (!timeout) context = args = null + } + } + return function() { + context = this + args = arguments + timestamp = Date.now() + if (!timeout) { + timeout = setTimeout(later, wait) + } + return result + } + } + + /** + * Manual indexOf because it's slightly faster than + * native. + * + * @param {Array} arr + * @param {*} obj + */ + + exports.indexOf = function (arr, obj) { + for (var i = 0, l = arr.length; i < l; i++) { + if (arr[i] === obj) return i + } + return -1 + } + + /** + * Make a cancellable version of an async callback. + * + * @param {Function} fn + * @return {Function} + */ + + exports.cancellable = function (fn) { + var cb = function () { + if (!cb.cancelled) { + return fn.apply(this, arguments) + } + } + cb.cancel = function () { + cb.cancelled = true + } + return cb + } + /***/ }, /* 6 */ /***/ function(module, exports, __webpack_require__) { - var _ = __webpack_require__(11) - var Watcher = __webpack_require__(25) - var Path = __webpack_require__(18) - var textParser = __webpack_require__(19) - var dirParser = __webpack_require__(21) - var expParser = __webpack_require__(22) - 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) - } + // can we use __proto__? + exports.hasProto = '__proto__' in {} + + // Browser environment sniffing + var inBrowser = exports.inBrowser = + typeof window !== 'undefined' && + Object.prototype.toString.call(window) !== '[object Object]' + + exports.isIE9 = + inBrowser && + navigator.userAgent.toLowerCase().indexOf('msie 9.0') > 0 + + exports.isAndroid = + inBrowser && + navigator.userAgent.toLowerCase().indexOf('android') > 0 + + // Transition property/event sniffing + if (inBrowser && !exports.isIE9) { + var isWebkitTrans = + window.ontransitionend === undefined && + window.onwebkittransitionend !== undefined + var isWebkitAnim = + window.onanimationend === undefined && + window.onwebkitanimationend !== undefined + exports.transitionProp = isWebkitTrans + ? 'WebkitTransition' + : 'transition' + exports.transitionEndEvent = isWebkitTrans + ? 'webkitTransitionEnd' + : 'transitionend' + exports.animationProp = isWebkitAnim + ? 'WebkitAnimation' + : 'animation' + exports.animationEndEvent = isWebkitAnim + ? 'webkitAnimationEnd' + : 'animationend' } - + /** - * Set the value from an expression on this vm. - * The expression must be a valid left-hand - * expression in an assignment. + * Defer a task to execute it asynchronously. Ideally this + * should be executed as a microtask, so we leverage + * MutationObserver if it's available, and fallback to + * setTimeout(0). * - * @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 + * @param {Object} ctx */ - - 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, { - deep: deep, - user: true - }) - } else { - watcher.addCb(wrappedCb) - } - if (immediate) { - wrappedCb(watcher.value) - } - return function unwatchFn () { - watcher.removeCb(wrappedCb) - if (!watcher.active) { - vm._userWatchers[key] = null + + exports.nextTick = (function () { + var callbacks = [] + var pending = false + var timerFunc + function handle () { + pending = false + var copies = callbacks.slice(0) + callbacks = [] + for (var i = 0; i < copies.length; i++) { + copies[i]() } } - } - - /** - * 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) + /* istanbul ignore if */ + if (typeof MutationObserver !== 'undefined') { + var counter = 1 + var observer = new MutationObserver(handle) + var textNode = document.createTextNode(counter) + observer.observe(textNode, { + characterData: true + }) + timerFunc = function () { + counter = (counter + 1) % 2 + textNode.data = counter + } } else { - // no filter - return this.$get(text) + timerFunc = setTimeout } - } - - /** - * 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 + return function (cb, ctx) { + var func = ctx + ? function () { cb.call(ctx) } + : cb + callbacks.push(func) + if (pending) return + pending = true + timerFunc(handle, 0) } - } - - /** - * 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) - } + })() /***/ }, /* 7 */ /***/ function(module, exports, __webpack_require__) { - var _ = __webpack_require__(11) - var transition = __webpack_require__(49) - + var config = __webpack_require__(4) + /** - * Append instance to target + * Check if a node is in the document. + * Note: document.documentElement.contains should work here + * but always returns false for comment nodes in phantomjs, + * making unit tests difficult. This is fixed byy doing the + * contains() check on the node's parentNode instead of + * the node itself. * - * @param {Node} target - * @param {Function} [cb] - * @param {Boolean} [withTransition] - defaults to true + * @param {Node} node + * @return {Boolean} */ - - exports.$appendTo = function (target, cb, withTransition) { - return insert( - this, target, cb, withTransition, - append, transition.append - ) + + var doc = + typeof document !== 'undefined' && + document.documentElement + + exports.inDoc = function (node) { + var parent = node && node.parentNode + return doc === node || + doc === parent || + !!(parent && parent.nodeType === 1 && (doc.contains(parent))) } - + /** - * Prepend instance to target + * Extract an attribute from a node. * - * @param {Node} target - * @param {Function} [cb] - * @param {Boolean} [withTransition] - defaults to true + * @param {Node} node + * @param {String} attr */ - - exports.$prependTo = function (target, cb, withTransition) { - target = query(target) - if (target.hasChildNodes()) { - this.$before(target.firstChild, cb, withTransition) - } else { - this.$appendTo(target, cb, withTransition) + + exports.attr = function (node, attr) { + attr = config.prefix + attr + var val = node.getAttribute(attr) + if (val !== null) { + node.removeAttribute(attr) } - return this + return val } - + /** - * Insert instance before target + * Insert el before target * - * @param {Node} target - * @param {Function} [cb] - * @param {Boolean} [withTransition] - defaults to true - */ - - exports.$before = function (target, cb, withTransition) { - return insert( - this, target, cb, withTransition, - before, transition.before - ) - } - - /** - * Insert instance after target - * - * @param {Node} target - * @param {Function} [cb] - * @param {Boolean} [withTransition] - defaults to true - */ - - exports.$after = function (target, cb, withTransition) { - target = query(target) - if (target.nextSibling) { - this.$before(target.nextSibling, cb, withTransition) - } else { - this.$appendTo(target.parentNode, cb, withTransition) - } - return this - } - - /** - * Remove instance from DOM - * - * @param {Function} [cb] - * @param {Boolean} [withTransition] - defaults to true - */ - - exports.$remove = function (cb, withTransition) { - var inDoc = this._isAttached && _.inDoc(this.$el) - // if we are not in document, no need to check - // for transitions - if (!inDoc) withTransition = false - var op - var self = this - var realCb = function () { - if (inDoc) self._callHook('detached') - if (cb) cb() - } - if ( - this._isBlock && - !this._blockFragment.hasChildNodes() - ) { - op = withTransition === false - ? append - : transition.removeThenAppend - blockOp(this, this._blockFragment, op, realCb) - } else { - op = withTransition === false - ? remove - : transition.remove - op(this.$el, this, realCb) - } - return this - } - - /** - * Shared DOM insertion function. - * - * @param {Vue} vm + * @param {Element} el * @param {Element} target - * @param {Function} [cb] - * @param {Boolean} [withTransition] - * @param {Function} op1 - op for non-transition insert - * @param {Function} op2 - op for transition insert - * @return vm */ - - function insert (vm, target, cb, withTransition, op1, op2) { - target = query(target) - var targetIsDetached = !_.inDoc(target) - var op = withTransition === false || targetIsDetached - ? op1 - : op2 - var shouldCallHook = - !targetIsDetached && - !vm._isAttached && - !_.inDoc(vm.$el) - if (vm._isBlock) { - blockOp(vm, target, op, cb) - } else { - op(vm.$el, target, vm, cb) - } - if (shouldCallHook) { - vm._callHook('attached') - } - return vm + + exports.before = function (el, target) { + target.parentNode.insertBefore(el, target) } - + /** - * Execute a transition operation on a block instance, - * iterating through all its block nodes. + * Insert el after target * - * @param {Vue} vm - * @param {Node} target - * @param {Function} op + * @param {Element} el + * @param {Element} target + */ + + exports.after = function (el, target) { + if (target.nextSibling) { + exports.before(el, target.nextSibling) + } else { + target.parentNode.appendChild(el) + } + } + + /** + * Remove el from DOM + * + * @param {Element} el + */ + + exports.remove = function (el) { + el.parentNode.removeChild(el) + } + + /** + * Prepend el to target + * + * @param {Element} el + * @param {Element} target + */ + + exports.prepend = function (el, target) { + if (target.firstChild) { + exports.before(el, target.firstChild) + } else { + target.appendChild(el) + } + } + + /** + * Replace target with el + * + * @param {Element} target + * @param {Element} el + */ + + exports.replace = function (target, el) { + var parent = target.parentNode + if (parent) { + parent.replaceChild(el, target) + } + } + + /** + * Add event listener shorthand. + * + * @param {Element} el + * @param {String} event * @param {Function} cb */ - - function blockOp (vm, target, op, cb) { - var current = vm._blockStart - var end = vm._blockEnd - var next - while (next !== end) { - next = current.nextSibling - op(current, target, vm) - current = next + + exports.on = function (el, event, cb) { + el.addEventListener(event, cb) + } + + /** + * Remove event listener shorthand. + * + * @param {Element} el + * @param {String} event + * @param {Function} cb + */ + + exports.off = function (el, event, cb) { + el.removeEventListener(event, cb) + } + + /** + * Add class with compatibility for IE & SVG + * + * @param {Element} el + * @param {Strong} cls + */ + + exports.addClass = function (el, cls) { + if (el.classList) { + el.classList.add(cls) + } else { + var cur = ' ' + (el.getAttribute('class') || '') + ' ' + if (cur.indexOf(' ' + cls + ' ') < 0) { + el.setAttribute('class', (cur + cls).trim()) + } } - op(end, target, vm, cb) } - + /** - * Check for selectors + * Remove class with compatibility for IE & SVG * - * @param {String|Element} el + * @param {Element} el + * @param {Strong} cls */ - - function query (el) { - return typeof el === 'string' - ? document.querySelector(el) - : el + + exports.removeClass = function (el, cls) { + if (el.classList) { + el.classList.remove(cls) + } else { + var cur = ' ' + (el.getAttribute('class') || '') + ' ' + var tar = ' ' + cls + ' ' + while (cur.indexOf(tar) >= 0) { + cur = cur.replace(tar, ' ') + } + el.setAttribute('class', cur.trim()) + } } - + /** - * Append operation that takes a callback. + * Extract raw content inside an element into a temporary + * container div * - * @param {Node} el - * @param {Node} target - * @param {Vue} vm - unused - * @param {Function} [cb] + * @param {Element} el + * @param {Boolean} asFragment + * @return {Element} */ - - function append (el, target, vm, cb) { - target.appendChild(el) - if (cb) cb() - } - - /** - * InsertBefore operation that takes a callback. - * - * @param {Node} el - * @param {Node} target - * @param {Vue} vm - unused - * @param {Function} [cb] - */ - - function before (el, target, vm, cb) { - _.before(el, target) - if (cb) cb() - } - - /** - * Remove operation that takes a callback. - * - * @param {Node} el - * @param {Vue} vm - unused - * @param {Function} [cb] - */ - - function remove (el, vm, cb) { - _.remove(el) - if (cb) cb() + + exports.extractContent = function (el, asFragment) { + var child + var rawContent + /* istanbul ignore if */ + if ( + el.tagName === 'TEMPLATE' && + el.content instanceof DocumentFragment + ) { + el = el.content + } + if (el.hasChildNodes()) { + rawContent = asFragment + ? document.createDocumentFragment() + : document.createElement('div') + /* jshint boss:true */ + while (child = el.firstChild) { + rawContent.appendChild(child) + } + } + return rawContent } + /***/ }, /* 8 */ /***/ function(module, exports, __webpack_require__) { - var _ = __webpack_require__(11) - + var config = __webpack_require__(4) + /** - * Listen on the given `event` with `fn`. - * - * @param {String} event - * @param {Function} fn + * Enable debug utilities. The enableDebug() function and + * all _.log() & _.warn() calls will be dropped in the + * minified production build. */ - - exports.$on = function (event, fn) { - (this._events[event] || (this._events[event] = [])) - .push(fn) - modifyListenerCount(this, event, 1) - return this - } - - /** - * Adds an `event` listener that will be invoked a single - * time then automatically removed. - * - * @param {String} event - * @param {Function} fn - */ - - exports.$once = function (event, fn) { - var self = this - 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 - */ - - exports.$off = function (event, fn) { - var cbs - // all - if (!arguments.length) { - if (this.$parent) { - for (event in this._events) { - cbs = this._events[event] - if (cbs) { - modifyListenerCount(this, event, -cbs.length) - } - } - } - this._events = {} - return this - } - // specific event - cbs = this._events[event] - if (!cbs) { - return this - } - if (arguments.length === 1) { - modifyListenerCount(this, event, -cbs.length) - this._events[event] = null - return this - } - // specific handler - var cb - var i = cbs.length - while (i--) { - cb = cbs[i] - if (cb === fn || cb.fn === fn) { - modifyListenerCount(this, event, -1) - cbs.splice(i, 1) - break + + enableDebug() + + function enableDebug () { + + var hasConsole = typeof console !== 'undefined' + + /** + * Log a message. + * + * @param {String} msg + */ + + exports.log = function (msg) { + if (hasConsole && config.debug) { + console.log('[Vue info]: ' + msg) } } - return this - } - - /** - * Trigger an event on self. - * - * @param {String} event - */ - - exports.$emit = function (event) { - this._eventCancelled = false - var cbs = this._events[event] - if (cbs) { - // avoid leaking arguments: - // http://jsperf.com/closure-with-arguments - var i = arguments.length - 1 - var args = new Array(i) - while (i--) { - args[i] = arguments[i + 1] - } - i = 0 - cbs = cbs.length > 1 - ? _.toArray(cbs) - : cbs - for (var l = cbs.length; i < l; i++) { - if (cbs[i].apply(this, args) === false) { - this._eventCancelled = true + + /** + * We've got a problem here. + * + * @param {String} msg + */ + + exports.warn = function (msg) { + if (hasConsole && (!config.silent || config.debug)) { + console.warn('[Vue warn]: ' + msg) + /* istanbul ignore if */ + if (config.debug) { + /* jshint debug: true */ + debugger } } } - return this - } - - /** - * Recursively broadcast an event to all children instances. - * - * @param {String} event - * @param {...*} additional arguments - */ - - exports.$broadcast = function (event) { - // if no child has registered for this event, - // then there's no need to broadcast. - if (!this._eventsCount[event]) return - var children = this._children - for (var i = 0, l = children.length; i < l; i++) { - var child = children[i] - child.$emit.apply(child, arguments) - if (!child._eventCancelled) { - child.$broadcast.apply(child, arguments) + + /** + * Assert asset exists + */ + + exports.assertAsset = function (val, type, id) { + /* istanbul ignore if */ + if (type === 'directive') { + if (id === 'component') { + exports.warn( + 'v-component has been deprecated in 0.12. ' + + 'Use custom element syntax instead.' + ) + return + } + if (id === 'with') { + exports.warn( + 'v-with has been deprecated in 0.12. ' + + 'Use props instead.' + ) + return + } + } + if (!val) { + exports.warn('Failed to resolve ' + type + ': ' + id) } - } - return this - } - - /** - * Recursively propagate an event up the parent chain. - * - * @param {String} event - * @param {...*} additional arguments - */ - - exports.$dispatch = function () { - var parent = this.$parent - while (parent) { - parent.$emit.apply(parent, arguments) - parent = parent._eventCancelled - ? null - : parent.$parent - } - return this - } - - /** - * Modify the listener counts on all parents. - * This bookkeeping allows $broadcast to return early when - * no child has listened to a certain event. - * - * @param {Vue} vm - * @param {String} event - * @param {Number} count - */ - - var hookRE = /^hook:/ - function modifyListenerCount (vm, event, count) { - var parent = vm.$parent - // hooks do not get broadcasted so no need - // to do bookkeeping for them - if (!parent || !count || hookRE.test(event)) return - while (parent) { - parent._eventsCount[event] = - (parent._eventsCount[event] || 0) + count - parent = parent.$parent } } @@ -1504,322 +1136,9 @@ return /******/ (function(modules) { // webpackBootstrap /* 9 */ /***/ function(module, exports, __webpack_require__) { - var _ = __webpack_require__(11) - - /** - * Create a child instance that prototypally inehrits - * data on parent. To achieve that we create an intermediate - * constructor with its prototype pointing to parent. - * - * @param {Object} opts - * @param {Function} [BaseCtor] - * @return {Vue} - * @public - */ - - exports.$addChild = function (opts, BaseCtor) { - BaseCtor = BaseCtor || _.Vue - opts = opts || {} - var parent = this - var ChildVue - var inherit = opts.inherit !== undefined - ? opts.inherit - : BaseCtor.options.inherit - if (inherit) { - var ctors = parent._childCtors - ChildVue = ctors[BaseCtor.cid] - if (!ChildVue) { - var optionName = BaseCtor.options.name - var className = optionName - ? _.classify(optionName) - : 'VueComponent' - ChildVue = new Function( - 'return function ' + className + ' (options) {' + - 'this.constructor = ' + className + ';' + - 'this._init(options) }' - )() - ChildVue.options = BaseCtor.options - ChildVue.prototype = this - ctors[BaseCtor.cid] = ChildVue - } - } else { - ChildVue = BaseCtor - } - opts._parent = parent - opts._root = parent.$root - var child = new ChildVue(opts) - return child - } - -/***/ }, -/* 10 */ -/***/ function(module, exports, __webpack_require__) { - - var _ = __webpack_require__(11) - var compile = __webpack_require__(16) - - /** - * Set instance target element and kick off the compilation - * process. The passed in `el` can be a selector string, an - * existing Element, or a DocumentFragment (for block - * instances). - * - * @param {Element|DocumentFragment|string} el - * @public - */ - - exports.$mount = function (el) { - if (this._isCompiled) { - _.warn('$mount() should be called only once.') - return - } - if (!el) { - el = document.createElement('div') - } else if (typeof el === 'string') { - var selector = el - el = document.querySelector(el) - if (!el) { - _.warn('Cannot find element: ' + selector) - return - } - } - this._compile(el) - this._isCompiled = true - this._callHook('compiled') - if (_.inDoc(this.$el)) { - this._callHook('attached') - this._initDOMHooks() - ready.call(this) - } else { - this._initDOMHooks() - this.$once('hook:attached', ready) - } - return this - } - - /** - * Mark an instance as ready. - */ - - function ready () { - this._isAttached = true - this._isReady = true - this._callHook('ready') - } - - /** - * Teardown the instance, simply delegate to the internal - * _destroy. - */ - - exports.$destroy = function (remove, deferCleanup) { - this._destroy(remove, deferCleanup) - } - - /** - * Partially compile a piece of DOM and return a - * decompile function. - * - * @param {Element|DocumentFragment} el - * @return {Function} - */ - - exports.$compile = function (el) { - return compile(el, this.$options, true)(this, el) - } - -/***/ }, -/* 11 */ -/***/ function(module, exports, __webpack_require__) { - - var lang = __webpack_require__(27) - var extend = lang.extend - - extend(exports, lang) - extend(exports, __webpack_require__(28)) - extend(exports, __webpack_require__(29)) - extend(exports, __webpack_require__(30)) - extend(exports, __webpack_require__(31)) - -/***/ }, -/* 12 */ -/***/ function(module, exports, __webpack_require__) { - - // manipulation directives - exports.text = __webpack_require__(32) - exports.html = __webpack_require__(33) - exports.attr = __webpack_require__(34) - exports.show = __webpack_require__(35) - exports['class'] = __webpack_require__(36) - exports.el = __webpack_require__(37) - exports.ref = __webpack_require__(38) - exports.cloak = __webpack_require__(39) - exports.style = __webpack_require__(40) - exports.partial = __webpack_require__(41) - exports.transition = __webpack_require__(42) - - // event listener directives - exports.on = __webpack_require__(43) - exports.model = __webpack_require__(51) - - // child vm directives - exports.component = __webpack_require__(44) - exports.repeat = __webpack_require__(45) - exports['if'] = __webpack_require__(46) - - // child vm communication directives - exports['with'] = __webpack_require__(47) - exports.events = __webpack_require__(48) - -/***/ }, -/* 13 */ -/***/ function(module, exports, __webpack_require__) { - - var _ = __webpack_require__(11) - - /** - * Stringify value. - * - * @param {Number} indent - */ - - exports.json = { - read: function (value, indent) { - return typeof value === 'string' - ? value - : JSON.stringify(value, null, Number(indent) || 2) - }, - write: function (value) { - try { - return JSON.parse(value) - } catch (e) { - return value - } - } - } - - /** - * 'abc' => 'Abc' - */ - - exports.capitalize = function (value) { - if (!value && value !== 0) return '' - value = value.toString() - return value.charAt(0).toUpperCase() + value.slice(1) - } - - /** - * 'abc' => 'ABC' - */ - - exports.uppercase = function (value) { - return (value || value === 0) - ? value.toString().toUpperCase() - : '' - } - - /** - * 'AbC' => 'abc' - */ - - exports.lowercase = function (value) { - return (value || value === 0) - ? value.toString().toLowerCase() - : '' - } - - /** - * 12345 => $12,345.00 - * - * @param {String} sign - */ - - var digitsRE = /(\d{3})(?=\d)/g - - exports.currency = function (value, sign) { - value = parseFloat(value) - if (!isFinite(value) || (!value && value !== 0)) return '' - sign = sign || '$' - var s = Math.floor(Math.abs(value)).toString(), - i = s.length % 3, - h = i > 0 - ? (s.slice(0, i) + (s.length > 3 ? ',' : '')) - : '', - v = Math.abs(parseInt((value * 100) % 100, 10)), - f = '.' + (v < 10 ? ('0' + v) : v) - return (value < 0 ? '-' : '') + - sign + h + s.slice(i).replace(digitsRE, '$1,') + f - } - - /** - * 'item' => 'items' - * - * @params - * 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'] - */ - - exports.pluralize = function (value) { - var args = _.toArray(arguments, 1) - return args.length > 1 - ? (args[value % 10 - 1] || args[args.length - 1]) - : (args[0] + (value === 1 ? '' : 's')) - } - - /** - * A special filter that takes a handler function, - * wraps it so it only gets triggered on specific - * keypresses. v-on only. - * - * @param {String} key - */ - - var keyCodes = { - enter : 13, - tab : 9, - 'delete' : 46, - up : 38, - left : 37, - right : 39, - down : 40, - esc : 27 - } - - exports.key = function (handler, key) { - if (!handler) return - var code = keyCodes[key] - if (!code) { - code = parseInt(key, 10) - } - return function (e) { - if (e.keyCode === code) { - return handler.call(this, e) - } - } - } - - // expose keycode hash - exports.key.keyCodes = keyCodes - - /** - * Install special array filters - */ - - _.extend(exports, __webpack_require__(50)) - - -/***/ }, -/* 14 */ -/***/ function(module, exports, __webpack_require__) { - - var _ = __webpack_require__(11) + var _ = __webpack_require__(2) var extend = _.extend - + /** * Option overwriting strategies are functions that handle * how to merge a parent option value and a child option @@ -1831,13 +1150,13 @@ return /******/ (function(modules) { // webpackBootstrap * @param {*} childVal * @param {Vue} [vm] */ - + var strats = Object.create(null) - + /** * Helper that recursively merges two data objects together. */ - + function mergeData (to, from) { var key, toVal, fromVal for (key in from) { @@ -1851,11 +1170,11 @@ return /******/ (function(modules) { // webpackBootstrap } return to } - + /** * Data */ - + strats.data = function (parentVal, childVal, vm) { if (!vm) { // in a Vue.extend merge, both should be functions @@ -1899,11 +1218,11 @@ return /******/ (function(modules) { // webpackBootstrap } } } - + /** * El */ - + strats.el = function (parentVal, childVal, vm) { if (!vm && childVal && typeof childVal !== 'function') { _.warn( @@ -1919,11 +1238,11 @@ return /******/ (function(modules) { // webpackBootstrap ? ret.call(vm) : ret } - + /** * Hooks and param attributes are merged as arrays. */ - + strats.created = strats.ready = strats.attached = @@ -1932,7 +1251,7 @@ return /******/ (function(modules) { // webpackBootstrap strats.compiled = strats.beforeDestroy = strats.destroyed = - strats.paramAttributes = function (parentVal, childVal) { + strats.props = function (parentVal, childVal) { return childVal ? parentVal ? parentVal.concat(childVal) @@ -1941,7 +1260,19 @@ return /******/ (function(modules) { // webpackBootstrap : [childVal] : parentVal } - + + /** + * 0.11 deprecation warning + */ + + strats.paramAttributes = function () { + /* istanbul ignore next */ + _.warn( + '"paramAttributes" option has been deprecated in 0.12. ' + + 'Use "props" instead.' + ) + } + /** * Assets * @@ -1949,37 +1280,25 @@ return /******/ (function(modules) { // webpackBootstrap * a three-way merge between constructor options, instance * options and parent options. */ - + strats.directives = strats.filters = - strats.partials = strats.transitions = - strats.components = function (parentVal, childVal, vm, key) { - var ret = Object.create( - vm && vm.$parent - ? vm.$parent.$options[key] - : _.Vue.options[key] - ) - if (parentVal) { - var keys = Object.keys(parentVal) - var i = keys.length - var field - while (i--) { - field = keys[i] - ret[field] = parentVal[field] - } - } - if (childVal) extend(ret, childVal) - return ret + strats.components = + strats.elementDirectives = function (parentVal, childVal) { + var res = Object.create(parentVal) + return childVal + ? extend(res, childVal) + : res } - + /** * Events & Watchers. * * Events & watchers hashes should not overwrite one * another, so we merge them as arrays. */ - + strats.watch = strats.events = function (parentVal, childVal) { if (!childVal) return parentVal @@ -1998,11 +1317,11 @@ return /******/ (function(modules) { // webpackBootstrap } return ret } - + /** * Other object hashes. */ - + strats.methods = strats.computed = function (parentVal, childVal) { if (!childVal) return parentVal @@ -2011,24 +1330,24 @@ return /******/ (function(modules) { // webpackBootstrap extend(ret, childVal) return ret } - + /** * Default strategy. */ - + var defaultStrat = function (parentVal, childVal) { return childVal === undefined ? parentVal : childVal } - + /** * Make sure component options get converted to actual * constructors. * * @param {Object} components */ - + function guardComponents (components) { if (components) { var def @@ -2041,7 +1360,7 @@ return /******/ (function(modules) { // webpackBootstrap } } } - + /** * Merge two option objects into a new one. * Core utility used in both instantiation and inheritance. @@ -2051,1065 +1370,1266 @@ return /******/ (function(modules) { // webpackBootstrap * @param {Vue} [vm] - if vm is present, indicates this is * an instantiation merge. */ - - module.exports = function mergeOptions (parent, child, vm) { + + exports.mergeOptions = function merge (parent, child, vm) { guardComponents(child.components) var options = {} var key if (child.mixins) { for (var i = 0, l = child.mixins.length; i < l; i++) { - parent = mergeOptions(parent, child.mixins[i], vm) + parent = merge(parent, child.mixins[i], vm) } } for (key in parent) { - merge(key) + mergeField(key) } for (key in child) { if (!(parent.hasOwnProperty(key))) { - merge(key) + mergeField(key) } } - function merge (key) { + function mergeField (key) { var strat = strats[key] || defaultStrat options[key] = strat(parent[key], child[key], vm, key) } return options } + /** + * Resolve an asset. + * This function is used because child instances need access + * to assets defined in its ancestor chain. + * + * @param {Object} options + * @param {String} type + * @param {String} id + * @return {Object|Function} + */ + + exports.resolveAsset = function resolve (options, type, id) { + var asset = options[type][id] + while (!asset && options._parent) { + options = options._parent.$options + asset = options[type][id] + } + return asset + } + +/***/ }, +/* 10 */ +/***/ function(module, exports, __webpack_require__) { + + var _ = __webpack_require__(2) + var config = __webpack_require__(4) + var Watcher = __webpack_require__(11) + var textParser = __webpack_require__(20) + var expParser = __webpack_require__(16) + + /** + * 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 {String} name + * @param {Node} el + * @param {Vue} vm + * @param {Object} descriptor + * - {String} expression + * - {String} [arg] + * - {Array} [filters] + * @param {Object} def - directive definition object + * @param {Vue|undefined} host - transclusion host target + * @constructor + */ + + function Directive (name, el, vm, descriptor, def, host) { + // public + this.name = name + this.el = el + this.vm = vm + // copy descriptor props + this.raw = descriptor.raw + this.expression = descriptor.expression + this.arg = descriptor.arg + this.filters = descriptor.filters + // private + this._descriptor = descriptor + this._host = host + this._locked = false + this._bound = false + // init + this._bind(def) + } + + var p = Directive.prototype + + /** + * Initialize the directive, mixin definition properties, + * setup the watcher, call definition bind() and update() + * if present. + * + * @param {Object} def + */ + + p._bind = function (def) { + if (this.name !== 'cloak' && this.el && this.el.removeAttribute) { + this.el.removeAttribute(config.prefix + this.name) + } + if (typeof def === 'function') { + this.update = def + } else { + _.extend(this, def) + } + this._watcherExp = this.expression + this._checkDynamicLiteral() + if (this.bind) { + this.bind() + } + if (this._watcherExp && + (this.update || this.twoWay) && + (!this.isLiteral || this._isDynamicLiteral) && + !this._checkStatement()) { + // wrapped updater for context + var dir = this + var update = this._update = this.update + ? function (val, oldVal) { + if (!dir._locked) { + dir.update(val, oldVal) + } + } + : function () {} // noop if no update is provided + // pre-process hook called before the value is piped + // through the filters. used in v-repeat. + var preProcess = this._preProcess + ? _.bind(this._preProcess, this) + : null + var watcher = this._watcher = new Watcher( + this.vm, + this._watcherExp, + update, // callback + { + filters: this.filters, + twoWay: this.twoWay, + deep: this.deep, + preProcess: preProcess + } + ) + if (this._initValue != null) { + watcher.set(this._initValue) + } else if (this.update) { + this.update(watcher.value) + } + } + this._bound = true + } + + /** + * check if this is a dynamic literal binding. + * + * e.g. v-component="{{currentView}}" + */ + + p._checkDynamicLiteral = function () { + var expression = this.expression + if (expression && this.isLiteral) { + var tokens = textParser.parse(expression) + if (tokens) { + var exp = textParser.tokensToExp(tokens) + this.expression = this.vm.$get(exp) + this._watcherExp = exp + this._isDynamicLiteral = true + } + } + } + + /** + * 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. v-on="click: a++" + * + * @return {Boolean} + */ + + p._checkStatement = function () { + var expression = this.expression + if ( + expression && this.acceptStatement && + !expParser.isSimplePath(expression) + ) { + var fn = expParser.parse(expression).get + var vm = this.vm + var handler = function () { + fn.call(vm, vm) + } + if (this.filters) { + handler = vm._applyFilters(handler, null, this.filters) + } + this.update(handler) + return true + } + } + + /** + * Check for an attribute directive param, e.g. lazy + * + * @param {String} name + * @return {String} + */ + + p._checkParam = function (name) { + var param = this.el.getAttribute(name) + if (param !== null) { + this.el.removeAttribute(name) + } + return param + } + + /** + * Teardown the watcher and call unbind. + */ + + p._teardown = function () { + if (this._bound) { + this._bound = false + if (this.unbind) { + this.unbind() + } + if (this._watcher) { + this._watcher.teardown() + } + this.vm = this.el = this._watcher = null + } + } + + /** + * Set the corresponding value with the setter. + * This should only be used in two-way directives + * e.g. v-model. + * + * @param {*} value + * @public + */ + + p.set = function (value) { + if (this.twoWay) { + this._withLock(function () { + this._watcher.set(value) + }) + } + } + + /** + * Execute a function while preventing that function from + * triggering updates on this directive instance. + * + * @param {Function} fn + */ + + p._withLock = function (fn) { + var self = this + self._locked = true + fn.call(self) + _.nextTick(function () { + self._locked = false + }) + } + + module.exports = Directive + +/***/ }, +/* 11 */ +/***/ function(module, exports, __webpack_require__) { + + var _ = __webpack_require__(2) + var config = __webpack_require__(4) + var Observer = __webpack_require__(12) + var expParser = __webpack_require__(16) + var batcher = __webpack_require__(19) + var uid = 0 + + /** + * A watcher parses an expression, collects dependencies, + * and fires callback when the expression value changes. + * This is used for both the $watch() api and directives. + * + * @param {Vue} vm + * @param {String} expression + * @param {Function} cb + * @param {Object} options + * - {Array} filters + * - {Boolean} twoWay + * - {Boolean} deep + * - {Boolean} user + * - {Function} [preProcess] + * @constructor + */ + + function Watcher (vm, expression, cb, options) { + this.vm = vm + vm._watchers.push(this) + this.expression = expression + this.cb = cb + this.id = ++uid // uid for batching + this.active = true + options = options || {} + this.deep = !!options.deep + this.user = !!options.user + this.twoWay = !!options.twoWay + this.filters = options.filters + this.preProcess = options.preProcess + this.deps = [] + this.newDeps = [] + // parse expression for getter/setter + var res = expParser.parse(expression, options.twoWay) + this.getter = res.get + this.setter = res.set + this.value = this.get() + } + + var p = Watcher.prototype + + /** + * Add a dependency to this directive. + * + * @param {Dep} dep + */ + + p.addDep = function (dep) { + var newDeps = this.newDeps + var old = this.deps + if (_.indexOf(newDeps, dep) < 0) { + newDeps.push(dep) + var i = _.indexOf(old, dep) + if (i < 0) { + dep.addSub(this) + } else { + old[i] = null + } + } + } + + /** + * Evaluate the getter, and re-collect dependencies. + */ + + p.get = function () { + this.beforeGet() + var vm = this.vm + var value + try { + value = this.getter.call(vm, vm) + } catch (e) { + if (config.warnExpressionErrors) { + _.warn( + 'Error when evaluating expression "' + + this.expression + '":\n ' + e + ) + } + } + // "touch" every property so they are all tracked as + // dependencies for deep watching + if (this.deep) { + traverse(value) + } + if (this.preProcess) { + value = this.preProcess(value) + } + if (this.filters) { + value = vm._applyFilters(value, null, this.filters, false) + } + this.afterGet() + return value + } + + /** + * Set the corresponding value with the setter. + * + * @param {*} value + */ + + p.set = function (value) { + var vm = this.vm + if (this.filters) { + value = vm._applyFilters( + value, this.value, this.filters, true) + } + try { + this.setter.call(vm, vm, value) + } catch (e) { + if (config.warnExpressionErrors) { + _.warn( + 'Error when evaluating setter "' + + this.expression + '":\n ' + e + ) + } + } + } + + /** + * Prepare for dependency collection. + */ + + p.beforeGet = function () { + Observer.target = this + } + + /** + * Clean up for dependency collection. + */ + + p.afterGet = function () { + Observer.target = null + var i = this.deps.length + while (i--) { + var dep = this.deps[i] + if (dep) { + dep.removeSub(this) + } + } + this.deps = this.newDeps + this.newDeps = [] + } + + /** + * Subscriber interface. + * Will be called when a dependency changes. + */ + + p.update = function () { + if (!config.async || config.debug) { + this.run() + } else { + batcher.push(this) + } + } + + /** + * Batcher job interface. + * Will be called by the batcher. + */ + + p.run = function () { + if (this.active) { + var value = this.get() + if ( + value !== this.value || + Array.isArray(value) || + this.deep + ) { + var oldValue = this.value + this.value = value + this.cb(value, oldValue) + } + } + } + + /** + * Remove self from all dependencies' subcriber list. + */ + + p.teardown = function () { + if (this.active) { + // remove self from vm's watcher list + // we can skip this if the vm if being destroyed + // which can improve teardown performance. + if (!this.vm._isBeingDestroyed) { + this.vm._watchers.$remove(this) + } + var i = this.deps.length + while (i--) { + this.deps[i].removeSub(this) + } + this.active = false + this.vm = this.cb = this.value = null + } + } + + + /** + * Recrusively traverse an object to evoke all converted + * getters, so that every nested property inside the object + * is collected as a "deep" dependency. + * + * @param {Object} obj + */ + + function traverse (obj) { + var key, val, i + for (key in obj) { + val = obj[key] + if (_.isArray(val)) { + i = val.length + while (i--) traverse(val[i]) + } else if (_.isObject(val)) { + traverse(val) + } + } + } + + module.exports = Watcher + +/***/ }, +/* 12 */ +/***/ function(module, exports, __webpack_require__) { + + var _ = __webpack_require__(2) + var config = __webpack_require__(4) + var Dep = __webpack_require__(13) + var arrayMethods = __webpack_require__(14) + var arrayKeys = Object.getOwnPropertyNames(arrayMethods) + __webpack_require__(15) + + var uid = 0 + + /** + * Type enums + */ + + var ARRAY = 0 + var OBJECT = 1 + + /** + * Augment an target Object or Array by intercepting + * the prototype chain using __proto__ + * + * @param {Object|Array} target + * @param {Object} proto + */ + + function protoAugment (target, src) { + target.__proto__ = src + } + + /** + * Augment an target Object or Array by defining + * hidden properties. + * + * @param {Object|Array} target + * @param {Object} proto + */ + + function copyAugment (target, src, keys) { + var i = keys.length + var key + while (i--) { + key = keys[i] + _.define(target, key, src[key]) + } + } + + /** + * Observer class that are attached to each observed + * object. Once attached, the observer converts target + * object's property keys into getter/setters that + * collect dependencies and dispatches updates. + * + * @param {Array|Object} value + * @param {Number} type + * @constructor + */ + + function Observer (value, type) { + this.id = ++uid + this.value = value + this.active = true + this.deps = [] + _.define(value, '__ob__', this) + if (type === ARRAY) { + var augment = config.proto && _.hasProto + ? protoAugment + : copyAugment + augment(value, arrayMethods, arrayKeys) + this.observeArray(value) + } else if (type === OBJECT) { + this.walk(value) + } + } + + Observer.target = null + + var p = Observer.prototype + + /** + * Attempt to create an observer instance for a value, + * returns the new observer if successfully observed, + * or the existing observer if the value already has one. + * + * @param {*} value + * @return {Observer|undefined} + * @static + */ + + Observer.create = function (value) { + if ( + value && + value.hasOwnProperty('__ob__') && + value.__ob__ instanceof Observer + ) { + return value.__ob__ + } else if (_.isArray(value)) { + return new Observer(value, ARRAY) + } else if ( + _.isPlainObject(value) && + !value._isVue // avoid Vue instance + ) { + return new Observer(value, OBJECT) + } + } + + /** + * Walk through each property and convert them into + * getter/setters. This method should only be called when + * value type is Object. Properties prefixed with `$` or `_` + * and accessor properties are ignored. + * + * @param {Object} obj + */ + + p.walk = function (obj) { + var keys = Object.keys(obj) + var i = keys.length + var key, prefix + while (i--) { + key = keys[i] + prefix = key.charCodeAt(0) + if (prefix !== 0x24 && prefix !== 0x5F) { // skip $ or _ + this.convert(key, obj[key]) + } + } + } + + /** + * Try to carete an observer for a child value, + * and if value is array, link dep to the array. + * + * @param {*} val + * @return {Dep|undefined} + */ + + p.observe = function (val) { + return Observer.create(val) + } + + /** + * Observe a list of Array items. + * + * @param {Array} items + */ + + p.observeArray = function (items) { + var i = items.length + while (i--) { + this.observe(items[i]) + } + } + + /** + * Convert a property into getter/setter so we can emit + * the events when the property is accessed/changed. + * + * @param {String} key + * @param {*} val + */ + + p.convert = function (key, val) { + var ob = this + var childOb = ob.observe(val) + var dep = new Dep() + if (childOb) { + childOb.deps.push(dep) + } + Object.defineProperty(ob.value, key, { + enumerable: true, + configurable: true, + get: function () { + // Observer.target is a watcher whose getter is + // currently being evaluated. + if (ob.active && Observer.target) { + Observer.target.addDep(dep) + } + return val + }, + set: function (newVal) { + if (newVal === val) return + // remove dep from old value + var oldChildOb = val && val.__ob__ + if (oldChildOb) { + oldChildOb.deps.$remove(dep) + } + val = newVal + // add dep to new value + var newChildOb = ob.observe(newVal) + if (newChildOb) { + newChildOb.deps.push(dep) + } + dep.notify() + } + }) + } + + /** + * Notify change on all self deps on an observer. + * This is called when a mutable value mutates. e.g. + * when an Array's mutating methods are called, or an + * Object's $add/$delete are called. + */ + + p.notify = function () { + var deps = this.deps + for (var i = 0, l = deps.length; i < l; i++) { + deps[i].notify() + } + } + + /** + * Add an owner vm, so that when $add/$delete mutations + * happen we can notify owner vms to proxy the keys and + * digest the watchers. This is only called when the object + * is observed as an instance's root $data. + * + * @param {Vue} vm + */ + + p.addVm = function (vm) { + (this.vms = this.vms || []).push(vm) + } + + /** + * Remove an owner vm. This is called when the object is + * swapped out as an instance's $data object. + * + * @param {Vue} vm + */ + + p.removeVm = function (vm) { + this.vms.$remove(vm) + } + + module.exports = Observer + + +/***/ }, +/* 13 */ +/***/ function(module, exports, __webpack_require__) { + + var _ = __webpack_require__(2) + + /** + * A dep is an observable that can have multiple + * directives subscribing to it. + * + * @constructor + */ + + function Dep () { + this.subs = [] + } + + var p = Dep.prototype + + /** + * Add a directive subscriber. + * + * @param {Directive} sub + */ + + p.addSub = function (sub) { + this.subs.push(sub) + } + + /** + * Remove a directive subscriber. + * + * @param {Directive} sub + */ + + p.removeSub = function (sub) { + this.subs.$remove(sub) + } + + /** + * Notify all subscribers of a new value. + */ + + p.notify = function () { + // stablize the subscriber list first + var subs = _.toArray(this.subs) + for (var i = 0, l = subs.length; i < l; i++) { + subs[i].update() + } + } + + module.exports = Dep + +/***/ }, +/* 14 */ +/***/ function(module, exports, __webpack_require__) { + + var _ = __webpack_require__(2) + var arrayProto = Array.prototype + var arrayMethods = Object.create(arrayProto) + + /** + * Intercept mutating methods and emit events + */ + + ;[ + 'push', + 'pop', + 'shift', + 'unshift', + 'splice', + 'sort', + 'reverse' + ] + .forEach(function (method) { + // cache original method + var original = arrayProto[method] + _.define(arrayMethods, method, function mutator () { + // avoid leaking arguments: + // http://jsperf.com/closure-with-arguments + var i = arguments.length + var args = new Array(i) + while (i--) { + args[i] = arguments[i] + } + var result = original.apply(this, args) + var ob = this.__ob__ + var inserted + switch (method) { + case 'push': + inserted = args + break + case 'unshift': + inserted = args + break + case 'splice': + inserted = args.slice(2) + break + } + if (inserted) ob.observeArray(inserted) + // notify change + ob.notify() + return result + }) + }) + + /** + * Swap the element at the given index with a new value + * and emits corresponding event. + * + * @param {Number} index + * @param {*} val + * @return {*} - replaced element + */ + + _.define( + arrayProto, + '$set', + function $set (index, val) { + if (index >= this.length) { + this.length = index + 1 + } + return this.splice(index, 1, val)[0] + } + ) + + /** + * Convenience method to remove the element at given index. + * + * @param {Number} index + * @param {*} val + */ + + _.define( + arrayProto, + '$remove', + function $remove (index) { + /* istanbul ignore if */ + if (!this.length) return + if (typeof index !== 'number') { + index = _.indexOf(this, index) + } + if (index > -1) { + this.splice(index, 1) + } + } + ) + + module.exports = arrayMethods + /***/ }, /* 15 */ /***/ function(module, exports, __webpack_require__) { - module.exports = { - - /** - * The prefix to look for when parsing directives. - * - * @type {String} - */ - - prefix: 'v-', - - /** - * Whether to print debug messages. - * Also enables stack trace for warnings. - * - * @type {Boolean} - */ - - debug: false, - - /** - * Whether to suppress warnings. - * - * @type {Boolean} - */ - - silent: false, - - /** - * Whether allow observer to alter data objects' - * __proto__. - * - * @type {Boolean} - */ - - proto: true, - - /** - * Whether to parse mustache tags in templates. - * - * @type {Boolean} - */ - - interpolate: true, - - /** - * Whether to use async rendering. - */ - - async: true, - - /** - * Whether to warn against errors caught when evaluating - * expressions. - */ - - warnExpressionErrors: true, - - /** - * Internal flag to indicate the delimiters have been - * changed. - * - * @type {Boolean} - */ - - _delimitersChanged: true, - - /** - * List of directives that are "terminal", i.e. handles - * the compilation of its own content - */ - - _terminalDirectives: [ - 'repeat', - 'if', - 'component' - ] - - } - + var _ = __webpack_require__(2) + var objProto = Object.prototype + /** - * Interpolation delimiters. - * We need to mark the changed flag so that the text parser - * knows it needs to recompile the regex. + * Add a new property to an observed object + * and emits corresponding event * - * @type {Array} + * @param {String} key + * @param {*} val + * @public */ - - var delimiters = ['{{', '}}'] - Object.defineProperty(module.exports, 'delimiters', { - get: function () { - return delimiters - }, - set: function (val) { - delimiters = val - this._delimitersChanged = true + + _.define( + objProto, + '$add', + function $add (key, val) { + if (this.hasOwnProperty(key)) return + var ob = this.__ob__ + if (!ob || _.isReserved(key)) { + this[key] = val + return + } + ob.convert(key, val) + ob.notify() + if (ob.vms) { + var i = ob.vms.length + while (i--) { + var vm = ob.vms[i] + vm._proxy(key) + vm._digest() + } + } } - }) + ) + + /** + * Set a property on an observed object, calling add to + * ensure the property is observed. + * + * @param {String} key + * @param {*} val + * @public + */ + + _.define( + objProto, + '$set', + function $set (key, val) { + this.$add(key, val) + this[key] = val + } + ) + + /** + * Deletes a property from an observed object + * and emits corresponding event + * + * @param {String} key + * @public + */ + + _.define( + objProto, + '$delete', + function $delete (key) { + if (!this.hasOwnProperty(key)) return + delete this[key] + var ob = this.__ob__ + if (!ob || _.isReserved(key)) { + return + } + ob.notify() + if (ob.vms) { + var i = ob.vms.length + while (i--) { + var vm = ob.vms[i] + vm._unproxy(key) + vm._digest() + } + } + } + ) /***/ }, /* 16 */ /***/ function(module, exports, __webpack_require__) { - var _ = __webpack_require__(11) - var config = __webpack_require__(15) - var textParser = __webpack_require__(19) - var dirParser = __webpack_require__(21) - var templateParser = __webpack_require__(20) - - module.exports = compile - + var _ = __webpack_require__(2) + var Path = __webpack_require__(17) + var Cache = __webpack_require__(18) + var expressionCache = new Cache(1000) + + var allowedKeywords = + 'Math,Date,this,true,false,null,undefined,Infinity,NaN,' + + 'isNaN,isFinite,decodeURI,decodeURIComponent,encodeURI,' + + 'encodeURIComponent,parseInt,parseFloat' + var allowedKeywordsRE = + new RegExp('^(' + allowedKeywords.replace(/,/g, '\\b|') + '\\b)') + + // keywords that don't make sense inside expressions + var improperKeywords = + 'break,case,class,catch,const,continue,debugger,default,' + + 'delete,do,else,export,extends,finally,for,function,if,' + + 'import,in,instanceof,let,return,super,switch,throw,try,' + + 'var,while,with,yield,enum,await,implements,package,' + + 'proctected,static,interface,private,public' + var improperKeywordsRE = + new RegExp('^(' + improperKeywords.replace(/,/g, '\\b|') + '\\b)') + + var wsRE = /\s/g + var newlineRE = /\n/g + var saveRE = /[\{,]\s*[\w\$_]+\s*:|('[^']*'|"[^"]*")|new |typeof |void /g + var restoreRE = /"(\d+)"/g + var pathTestRE = /^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\]|\[\d+\]|\[[A-Za-z_$][\w$]*\])*$/ + var pathReplaceRE = /[^\w$\.]([A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\])*)/g + var booleanLiteralRE = /^(true|false)$/ + /** - * Compile a template and return a reusable composite link - * function, which recursively contains more link functions - * inside. This top level compile function should only be - * called on instance root nodes. + * Save / Rewrite / Restore * - * @param {Element|DocumentFragment} el - * @param {Object} options - * @param {Boolean} partial - * @param {Boolean} transcluded + * When rewriting paths found in an expression, it is + * possible for the same letter sequences to be found in + * strings and Object literal property keys. Therefore we + * remove and store these parts in a temporary array, and + * restore them after the path rewrite. + */ + + var saved = [] + + /** + * Save replacer + * + * The save regex can match two possible cases: + * 1. An opening object literal + * 2. A string + * If matched as a plain string, we need to escape its + * newlines, since the string needs to be preserved when + * generating the function body. + * + * @param {String} str + * @param {String} isString - str if matched as a string + * @return {String} - placeholder with index + */ + + function save (str, isString) { + var i = saved.length + saved[i] = isString + ? str.replace(newlineRE, '\\n') + : str + return '"' + i + '"' + } + + /** + * Path rewrite replacer + * + * @param {String} raw + * @return {String} + */ + + function rewrite (raw) { + var c = raw.charAt(0) + var path = raw.slice(1) + if (allowedKeywordsRE.test(path)) { + return raw + } else { + path = path.indexOf('"') > -1 + ? path.replace(restoreRE, restore) + : path + return c + 'scope.' + path + } + } + + /** + * Restore replacer + * + * @param {String} str + * @param {String} i - matched save index + * @return {String} + */ + + function restore (str, i) { + return saved[i] + } + + /** + * Rewrite an expression, prefixing all path accessors with + * `scope.` and generate getter/setter functions. + * + * @param {String} exp + * @param {Boolean} needSet * @return {Function} */ - - function compile (el, options, partial, transcluded) { - // link function for the node itself. - var nodeLinkFn = options._asComponent && !partial - ? compileRoot(el, options) - : compileNode(el, options) - // link function for the childNodes - var childLinkFn = - !(nodeLinkFn && nodeLinkFn.terminal) && - el.tagName !== 'SCRIPT' && - el.hasChildNodes() - ? compileNodeList(el.childNodes, options) - : null - - /** - * A composite linker function to be called on a already - * compiled piece of DOM, which instantiates all directive - * instances. - * - * @param {Vue} vm - * @param {Element|DocumentFragment} el - * @return {Function|undefined} - */ - - function compositeLinkFn (vm, el) { - // save original directive count before linking - // so we can capture the directives created during a - // partial compilation. - var originalDirCount = vm._directives.length - var parentOriginalDirCount = - vm.$parent && vm.$parent._directives.length - // cache childNodes before linking parent, fix #657 - var childNodes = _.toArray(el.childNodes) - // if this is a transcluded compile, linkers need to be - // called in source scope, and the host needs to be - // passed down. - var source = transcluded ? vm.$parent : vm - var host = transcluded ? vm : undefined - // link - if (nodeLinkFn) nodeLinkFn(source, el, host) - if (childLinkFn) childLinkFn(source, childNodes, host) - - var selfDirs = vm._directives.slice(originalDirCount) - var parentDirs = vm.$parent && - vm.$parent._directives.slice(parentOriginalDirCount) - - /** - * The linker function returns an unlink function that - * tearsdown all directives instances generated during - * the process. - * - * @param {Boolean} destroying - */ - return function unlink (destroying) { - teardownDirs(vm, selfDirs, destroying) - if (parentDirs) { - teardownDirs(vm.$parent, parentDirs) - } - } + + function compileExpFns (exp, needSet) { + if (improperKeywordsRE.test(exp)) { + _.warn( + 'Avoid using reserved keywords in expression: ' + + exp + ) } - - // transcluded linkFns are terminal, because it takes - // over the entire sub-tree. - if (transcluded) { - compositeLinkFn.terminal = true - } - - return compositeLinkFn - } - - /** - * Teardown a subset of directives on a vm. - * - * @param {Vue} vm - * @param {Array} dirs - * @param {Boolean} destroying - */ - - function teardownDirs (vm, dirs, destroying) { - var i = dirs.length - while (i--) { - dirs[i]._teardown() - if (!destroying) { - vm._directives.$remove(dirs[i]) + // reset state + saved.length = 0 + // save strings and object literal keys + var body = exp + .replace(saveRE, save) + .replace(wsRE, '') + // rewrite all paths + // pad 1 space here becaue the regex matches 1 extra char + body = (' ' + body) + .replace(pathReplaceRE, rewrite) + .replace(restoreRE, restore) + var getter = makeGetter(body) + if (getter) { + return { + get: getter, + body: body, + set: needSet + ? makeSetter(body) + : null } } } - + /** - * Compile the root element of a component. There are - * 4 types of things to process here: - * - * 1. paramAttributes on parent container (child scope) - * 2. v-with on parent container (child scope) - * 3. other attrs on parent container (parent scope) - * 4. attrs on the component template root node, if - * replace:true (child scope) + * Compile getter setters for a simple path. * - * Also, if this is a block instance, we only need to - * compile 1 & 2 here. - * - * @param {Element} el - * @param {Object} options + * @param {String} exp * @return {Function} */ - - function compileRoot (el, options) { - var isBlock = el.nodeType === 11 // DocumentFragment - var containerAttrs = options._containerAttrs - var replacerAttrs = options._replacerAttrs - var params = options.paramAttributes - var paramsLinkFn, withLinkFn, parentLinkFn, replacerLinkFn - // 1. paramAttributes - paramsLinkFn = params - ? compileParamAttributes(el, containerAttrs, params, options) - : null - // 2. v-with - var withName = config.prefix + 'with' - var withVal = containerAttrs && containerAttrs[withName] - if (withVal) { - containerAttrs[withName] = null - withLinkFn = makeNodeLinkFn([{ - name: 'with', - descriptors: dirParser.parse(withVal), - def: options.directives['with'] - }]) - } - if (!isBlock) { - // 3. container attributes - if (containerAttrs) { - parentLinkFn = compileDirectives(containerAttrs, options) - } - if (replacerAttrs) { - // 4. replacer attributes - replacerLinkFn = compileDirectives(replacerAttrs, options) - } - } - return function rootLinkFn (vm, el, host) { - // explicitly passing null to paramAttributes and v-with - // linkers because they don't need a real element - if (paramsLinkFn) paramsLinkFn(vm, null) - if (withLinkFn) withLinkFn(vm, null) - if (parentLinkFn) parentLinkFn(vm.$parent, el, host) - if (replacerLinkFn) replacerLinkFn(vm, el, host) - } - } - - /** - * Compile a node and return a nodeLinkFn based on the - * node type. - * - * @param {Node} node - * @param {Object} options - * @return {Function|null} - */ - - function compileNode (node, options) { - var type = node.nodeType - if (type === 1 && node.tagName !== 'SCRIPT') { - return compileElement(node, options) - } else if (type === 3 && config.interpolate && node.data.trim()) { - return compileTextNode(node, options) + + function compilePathFns (exp) { + var getter, path + if (exp.indexOf('[') < 0) { + // really simple path + path = exp.split('.') + path.raw = exp + getter = Path.compileGetter(path) } else { - return null + // do the real parsing + path = Path.parse(exp) + getter = path.get + } + return { + get: getter, + // always generate setter for simple paths + set: function (obj, val) { + Path.set(obj, path, val) + } } } - + /** - * Compile an element and return a nodeLinkFn. + * Build a getter function. Requires eval. * - * @param {Element} el - * @param {Object} options - * @return {Function|null} - */ - - function compileElement (el, options) { - if (checkTransclusion(el)) { - // unwrap textNode - if (el.hasAttribute('__vue__wrap')) { - el = el.firstChild - } - return compile(el, options._parent.$options, true, true) - } - var linkFn, tag, component - // check custom element component, but only on non-root - if (!el.__vue__) { - tag = el.tagName.toLowerCase() - component = - tag.indexOf('-') > 0 && - options.components[tag] - if (component) { - el.setAttribute(config.prefix + 'component', tag) - } - } - if (component || el.hasAttributes()) { - // check terminal direcitves - linkFn = checkTerminalDirectives(el, options) - // if not terminal, build normal link function - if (!linkFn) { - linkFn = compileDirectives(el, options) - } - } - // if the element is a textarea, we need to interpolate - // its content on initial render. - if (el.tagName === 'TEXTAREA') { - var realLinkFn = linkFn - linkFn = function (vm, el) { - el.value = vm.$interpolate(el.value) - if (realLinkFn) realLinkFn(vm, el) - } - linkFn.terminal = true - } - return linkFn - } - - /** - * Compile a textNode and return a nodeLinkFn. + * We isolate the try/catch so it doesn't affect the + * optimization of the parse function when it is not called. * - * @param {TextNode} node - * @param {Object} options - * @return {Function|null} textNodeLinkFn - */ - - function compileTextNode (node, options) { - var tokens = textParser.parse(node.data) - if (!tokens) { - return null - } - var frag = document.createDocumentFragment() - var el, token - for (var i = 0, l = tokens.length; i < l; i++) { - token = tokens[i] - el = token.tag - ? processTextToken(token, options) - : document.createTextNode(token.value) - frag.appendChild(el) - } - return makeTextNodeLinkFn(tokens, frag, options) - } - - /** - * Process a single text token. - * - * @param {Object} token - * @param {Object} options - * @return {Node} - */ - - function processTextToken (token, options) { - var el - if (token.oneTime) { - el = document.createTextNode(token.value) - } else { - if (token.html) { - el = document.createComment('v-html') - setTokenType('html') - } else if (token.partial) { - el = document.createComment('v-partial') - setTokenType('partial') - } else { - // IE will clean up empty textNodes during - // frag.cloneNode(true), so we have to give it - // something here... - el = document.createTextNode(' ') - setTokenType('text') - } - } - function setTokenType (type) { - token.type = type - token.def = options.directives[type] - token.descriptor = dirParser.parse(token.value)[0] - } - return el - } - - /** - * Build a function that processes a textNode. - * - * @param {Array} tokens - * @param {DocumentFragment} frag - */ - - function makeTextNodeLinkFn (tokens, frag) { - return function textNodeLinkFn (vm, el) { - var fragClone = frag.cloneNode(true) - var childNodes = _.toArray(fragClone.childNodes) - var token, value, node - for (var i = 0, l = tokens.length; i < l; i++) { - token = tokens[i] - value = token.value - if (token.tag) { - node = childNodes[i] - if (token.oneTime) { - value = vm.$eval(value) - if (token.html) { - _.replace(node, templateParser.parse(value, true)) - } else { - node.data = value - } - } else { - vm._bindDir(token.type, node, - token.descriptor, token.def) - } - } - } - _.replace(el, fragClone) - } - } - - /** - * Compile a node list and return a childLinkFn. - * - * @param {NodeList} nodeList - * @param {Object} options + * @param {String} body * @return {Function|undefined} */ - - function compileNodeList (nodeList, options) { - var linkFns = [] - var nodeLinkFn, childLinkFn, node - for (var i = 0, l = nodeList.length; i < l; i++) { - node = nodeList[i] - nodeLinkFn = compileNode(node, options) - childLinkFn = - !(nodeLinkFn && nodeLinkFn.terminal) && - node.tagName !== 'SCRIPT' && - node.hasChildNodes() - ? compileNodeList(node.childNodes, options) - : null - linkFns.push(nodeLinkFn, childLinkFn) + + function makeGetter (body) { + try { + return new Function('scope', 'return ' + body + ';') + } catch (e) { + _.warn( + 'Invalid expression. ' + + 'Generated function body: ' + body + ) } - return linkFns.length - ? makeChildLinkFn(linkFns) - : null } - + /** - * Make a child link function for a node's childNodes. + * Build a setter function. * - * @param {Array} linkFns - * @return {Function} childLinkFn + * This is only needed in rare situations like "a[b]" where + * a settable path requires dynamic evaluation. + * + * This setter function may throw error when called if the + * expression body is not a valid left-hand expression in + * assignment. + * + * @param {String} body + * @return {Function|undefined} */ - - function makeChildLinkFn (linkFns) { - return function childLinkFn (vm, nodes, host) { - var node, nodeLinkFn, childrenLinkFn - for (var i = 0, n = 0, l = linkFns.length; i < l; n++) { - node = nodes[n] - nodeLinkFn = linkFns[i++] - childrenLinkFn = linkFns[i++] - // cache childNodes before linking parent, fix #657 - var childNodes = _.toArray(node.childNodes) - if (nodeLinkFn) { - nodeLinkFn(vm, node, host) - } - if (childrenLinkFn) { - childrenLinkFn(vm, childNodes, host) - } - } + + function makeSetter (body) { + try { + return new Function('scope', 'value', body + '=value;') + } catch (e) { + _.warn('Invalid setter function body: ' + body) } } - + /** - * Compile param attributes on a root element and return - * a paramAttributes link function. + * Check for setter existence on a cache hit. * - * @param {Element|DocumentFragment} el - * @param {Object} attrs - * @param {Array} paramNames - * @param {Object} options - * @return {Function} paramsLinkFn + * @param {Function} hit */ - - function compileParamAttributes (el, attrs, paramNames, options) { - var params = [] - var i = paramNames.length - var name, value, param - while (i--) { - name = paramNames[i] - if (/[A-Z]/.test(name)) { - _.warn( - 'You seem to be using camelCase for a paramAttribute, ' + - 'but HTML doesn\'t differentiate between upper and ' + - 'lower case. You should use hyphen-delimited ' + - 'attribute names. For more info see ' + - 'http://vuejs.org/api/options.html#paramAttributes' - ) - } - value = attrs[name] - if (value !== null) { - param = { - name: name, - value: value - } - var tokens = textParser.parse(value) - if (tokens) { - if (el && el.nodeType === 1) { - el.removeAttribute(name) - } - attrs[name] = null - if (tokens.length > 1) { - _.warn( - 'Invalid param attribute binding: "' + - name + '="' + value + '"' + - '\nDon\'t mix binding tags with plain text ' + - 'in param attribute bindings.' - ) - continue - } else { - param.dynamic = true - param.value = tokens[0].value - } - } - params.push(param) - } - } - return makeParamsLinkFn(params, options) - } - - /** - * Build a function that applies param attributes to a vm. - * - * @param {Array} params - * @param {Object} options - * @return {Function} paramsLinkFn - */ - - var dataAttrRE = /^data-/ - - function makeParamsLinkFn (params, options) { - var def = options.directives['with'] - return function paramsLinkFn (vm, el) { - var i = params.length - var param, path - while (i--) { - param = params[i] - // params could contain dashes, which will be - // interpreted as minus calculations by the parser - // so we need to wrap the path here - path = _.camelize(param.name.replace(dataAttrRE, '')) - if (param.dynamic) { - // dynamic param attribtues are bound as v-with. - // we can directly duck the descriptor here beacuse - // param attributes cannot use expressions or - // filters. - vm._bindDir('with', el, { - arg: path, - expression: param.value - }, def) - } else { - // just set once - vm.$set(path, param.value) - } - } + + function checkSetter (hit) { + if (!hit.set) { + hit.set = makeSetter(hit.body) } } - + /** - * Check an element for terminal directives in fixed order. - * If it finds one, return a terminal link function. + * Parse an expression into re-written getter/setters. * - * @param {Element} el - * @param {Object} options - * @return {Function} terminalLinkFn - */ - - function checkTerminalDirectives (el, options) { - if (_.attr(el, 'pre') !== null) { - return skip - } - var value, dirName - var dirs = config._terminalDirectives - /* jshint boss: true */ - for (var i = 0, l = dirs.length; i < l; i++) { - dirName = dirs[i] - if ((value = _.attr(el, dirName)) !== null) { - return makeTerminalNodeLinkFn(el, dirName, value, options) - } - } - } - - function skip () {} - skip.terminal = true - - /** - * Build a node link function for a terminal directive. - * A terminal link function terminates the current - * compilation recursion and handles compilation of the - * subtree in the directive. - * - * @param {Element} el - * @param {String} dirName - * @param {String} value - * @param {Object} options - * @return {Function} terminalLinkFn - */ - - function makeTerminalNodeLinkFn (el, dirName, value, options) { - var descriptor = dirParser.parse(value)[0] - var def = options.directives[dirName] - var fn = function terminalNodeLinkFn (vm, el, host) { - vm._bindDir(dirName, el, descriptor, def, host) - } - fn.terminal = true - return fn - } - - /** - * Compile the directives on an element and return a linker. - * - * @param {Element|Object} elOrAttrs - * - could be an object of already-extracted - * container attributes. - * @param {Object} options + * @param {String} exp + * @param {Boolean} needSet * @return {Function} */ - - function compileDirectives (elOrAttrs, options) { - var attrs = _.isPlainObject(elOrAttrs) - ? mapToList(elOrAttrs) - : elOrAttrs.attributes - var i = attrs.length - var dirs = [] - var attr, name, value, dir, dirName, dirDef - while (i--) { - attr = attrs[i] - name = attr.name - value = attr.value - if (value === null) continue - if (name.indexOf(config.prefix) === 0) { - dirName = name.slice(config.prefix.length) - dirDef = options.directives[dirName] - _.assertAsset(dirDef, 'directive', dirName) - if (dirDef) { - dirs.push({ - name: dirName, - descriptors: dirParser.parse(value), - def: dirDef - }) - } - } else if (config.interpolate) { - dir = collectAttrDirective(name, value, options) - if (dir) { - dirs.push(dir) - } + + exports.parse = function (exp, needSet) { + exp = exp.trim() + // try cache + var hit = expressionCache.get(exp) + if (hit) { + if (needSet) { + checkSetter(hit) } + return hit } - // sort by priority, LOW to HIGH - if (dirs.length) { - dirs.sort(directiveComparator) - return makeNodeLinkFn(dirs) - } + // we do a simple path check to optimize for them. + // the check fails valid paths with unusal whitespaces, + // but that's too rare and we don't care. + // also skip boolean literals and paths that start with + // global "Math" + var res = exports.isSimplePath(exp) + ? compilePathFns(exp) + : compileExpFns(exp, needSet) + expressionCache.put(exp, res) + return res } - + /** - * Convert a map (Object) of attributes to an Array. + * Check if an expression is a simple path. * - * @param {Object} map - * @return {Array} - */ - - function mapToList (map) { - var list = [] - for (var key in map) { - list.push({ - name: key, - value: map[key] - }) - } - return list - } - - /** - * Build a link function for all directives on a single node. - * - * @param {Array} directives - * @return {Function} directivesLinkFn - */ - - function makeNodeLinkFn (directives) { - return function nodeLinkFn (vm, el, host) { - // reverse apply because it's sorted low to high - var i = directives.length - var dir, j, k - while (i--) { - dir = directives[i] - if (dir._link) { - // custom link fn - dir._link(vm, el) - } else { - k = dir.descriptors.length - for (j = 0; j < k; j++) { - vm._bindDir(dir.name, el, - dir.descriptors[j], dir.def, host) - } - } - } - } - } - - /** - * Check an attribute for potential dynamic bindings, - * and return a directive object. - * - * @param {String} name - * @param {String} value - * @param {Object} options - * @return {Object} - */ - - function collectAttrDirective (name, value, options) { - var tokens = textParser.parse(value) - if (tokens) { - var def = options.directives.attr - var i = tokens.length - var allOneTime = true - while (i--) { - var token = tokens[i] - if (token.tag && !token.oneTime) { - allOneTime = false - } - } - return { - def: def, - _link: allOneTime - ? function (vm, el) { - el.setAttribute(name, vm.$interpolate(value)) - } - : function (vm, el) { - var value = textParser.tokensToExp(tokens, vm) - var desc = dirParser.parse(name + ':' + value)[0] - vm._bindDir('attr', el, desc, def) - } - } - } - } - - /** - * Directive priority sort comparator - * - * @param {Object} a - * @param {Object} b - */ - - function directiveComparator (a, b) { - a = a.def.priority || 0 - b = b.def.priority || 0 - return a > b ? 1 : -1 - } - - /** - * Check whether an element is transcluded - * - * @param {Element} el + * @param {String} exp * @return {Boolean} */ - - var transcludedFlagAttr = '__vue__transcluded' - function checkTransclusion (el) { - if (el.nodeType === 1 && el.hasAttribute(transcludedFlagAttr)) { - el.removeAttribute(transcludedFlagAttr) - return true - } + + exports.isSimplePath = function (exp) { + return pathTestRE.test(exp) && + // don't treat true/false as paths + !booleanLiteralRE.test(exp) && + // Math constants e.g. Math.PI, Math.E etc. + exp.slice(0, 5) !== 'Math.' } /***/ }, /* 17 */ /***/ function(module, exports, __webpack_require__) { - var _ = __webpack_require__(11) - var templateParser = __webpack_require__(20) - var transcludedFlagAttr = '__vue__transcluded' - - /** - * Process an element or a DocumentFragment based on a - * instance option object. This allows us to transclude - * a template node/fragment before the instance is created, - * so the processed fragment can then be cloned and reused - * in v-repeat. - * - * @param {Element} el - * @param {Object} options - * @return {Element|DocumentFragment} - */ - - module.exports = function transclude (el, options) { - if (options && options._asComponent) { - // extract container attributes to pass them down - // to compiler, because they need to be compiled in - // parent scope. we are mutating the options object here - // assuming the same object will be used for compile - // right after this. - options._containerAttrs = extractAttrs(el) - // Mark content nodes and attrs so that the compiler - // knows they should be compiled in parent scope. - var i = el.childNodes.length - while (i--) { - var node = el.childNodes[i] - if (node.nodeType === 1) { - node.setAttribute(transcludedFlagAttr, '') - } else if (node.nodeType === 3 && node.data.trim()) { - // wrap transcluded textNodes in spans, because - // raw textNodes can't be persisted through clones - // by attaching attributes. - var wrapper = document.createElement('span') - wrapper.textContent = node.data - wrapper.setAttribute('__vue__wrap', '') - wrapper.setAttribute(transcludedFlagAttr, '') - el.replaceChild(wrapper, node) - } - } - } - // for template tags, what we want is its content as - // a documentFragment (for block instances) - if (el.tagName === 'TEMPLATE') { - el = templateParser.parse(el) - } - if (options && options.template) { - el = transcludeTemplate(el, options) - } - if (el instanceof DocumentFragment) { - _.prepend(document.createComment('v-start'), el) - el.appendChild(document.createComment('v-end')) - } - return el - } - - /** - * Process the template option. - * If the replace option is true this will swap the $el. - * - * @param {Element} el - * @param {Object} options - * @return {Element|DocumentFragment} - */ - - function transcludeTemplate (el, options) { - var template = options.template - var frag = templateParser.parse(template, true) - if (!frag) { - _.warn('Invalid template option: ' + template) - } else { - var rawContent = options._content || _.extractContent(el) - if (options.replace) { - if (frag.childNodes.length > 1) { - transcludeContent(frag, rawContent) - return frag - } else { - var replacer = frag.firstChild - options._replacerAttrs = extractAttrs(replacer) - mergeAttrs(el, replacer) - transcludeContent(replacer, rawContent) - return replacer - } - } else { - el.appendChild(frag) - transcludeContent(el, rawContent) - return el - } - } - } - - /** - * Resolve insertion points mimicking the behavior - * of the Shadow DOM spec: - * - * http://w3c.github.io/webcomponents/spec/shadow/#insertion-points - * - * @param {Element|DocumentFragment} el - * @param {Element} raw - */ - - function transcludeContent (el, raw) { - var outlets = getOutlets(el) - var i = outlets.length - if (!i) return - var outlet, select, selected, j, main - - function isDirectChild (node) { - return node.parentNode === raw - } - - // first pass, collect corresponding content - // for each outlet. - while (i--) { - outlet = outlets[i] - if (raw) { - select = outlet.getAttribute('select') - if (select) { // select content - selected = raw.querySelectorAll(select) - if (selected.length) { - // according to Shadow DOM spec, `select` can - // only select direct children of the host node. - // enforcing this also fixes #786. - selected = [].filter.call(selected, isDirectChild) - } - outlet.content = selected.length - ? selected - : _.toArray(outlet.childNodes) - } else { // default content - main = outlet - } - } else { // fallback content - outlet.content = _.toArray(outlet.childNodes) - } - } - // second pass, actually insert the contents - for (i = 0, j = outlets.length; i < j; i++) { - outlet = outlets[i] - if (outlet !== main) { - insertContentAt(outlet, outlet.content) - } - } - // finally insert the main content - if (main) { - insertContentAt(main, _.toArray(raw.childNodes)) - } - } - - /** - * Get outlets from the element/list - * - * @param {Element|Array} el - * @return {Array} - */ - - var concat = [].concat - function getOutlets (el) { - return _.isArray(el) - ? concat.apply([], el.map(getOutlets)) - : el.querySelectorAll - ? _.toArray(el.querySelectorAll('content')) - : [] - } - - /** - * Insert an array of nodes at outlet, - * then remove the outlet. - * - * @param {Element} outlet - * @param {Array} contents - */ - - function insertContentAt (outlet, contents) { - // not using util DOM methods here because - // parentNode can be cached - var parent = outlet.parentNode - for (var i = 0, j = contents.length; i < j; i++) { - parent.insertBefore(contents[i], outlet) - } - parent.removeChild(outlet) - } - - /** - * Helper to extract a component container's attribute names - * into a map. The resulting map will be used in compiler to - * determine whether an attribute is transcluded. - * - * @param {Element} el - */ - - function extractAttrs (el) { - var attrs = el.attributes - if (!attrs) return - var res = {} - var i = attrs.length - while (i--) { - res[attrs[i].name] = attrs[i].value - } - return res - } - - /** - * Merge the attributes of two elements, and make sure - * the class names are merged properly. - * - * @param {Element} from - * @param {Element} to - */ - - function mergeAttrs (from, to) { - var attrs = from.attributes - var i = attrs.length - var name, value - while (i--) { - name = attrs[i].name - value = attrs[i].value - if (!to.hasAttribute(name)) { - to.setAttribute(name, value) - } else if (name === 'class') { - to.className = to.className + ' ' + value - } - } - } - -/***/ }, -/* 18 */ -/***/ function(module, exports, __webpack_require__) { - - var _ = __webpack_require__(11) - var Cache = __webpack_require__(52) + var _ = __webpack_require__(2) + var Cache = __webpack_require__(18) var pathCache = new Cache(1000) - var identRE = /^[$_a-zA-Z]+[\w$]*$/ - + var identRE = exports.identRE = /^[$_a-zA-Z]+[\w$]*$/ + /** * Path-parsing algorithm scooped from Polymer/observe-js */ - + var pathStateMachine = { 'beforePath': { 'ws': ['beforePath'], @@ -3117,19 +2637,19 @@ return /******/ (function(modules) { // webpackBootstrap '[': ['beforeElement'], 'eof': ['afterPath'] }, - + 'inPath': { 'ws': ['inPath'], '.': ['beforeIdent'], '[': ['beforeElement'], 'eof': ['afterPath'] }, - + 'beforeIdent': { 'ws': ['beforeIdent'], 'ident': ['inIdent', 'append'] }, - + 'inIdent': { 'ident': ['inIdent', 'append'], '0': ['inIdent', 'append'], @@ -3137,63 +2657,65 @@ return /******/ (function(modules) { // webpackBootstrap 'ws': ['inPath', 'push'], '.': ['beforeIdent', 'push'], '[': ['beforeElement', 'push'], - 'eof': ['afterPath', 'push'] + 'eof': ['afterPath', 'push'], + ']': ['inPath', 'push'] }, - + 'beforeElement': { 'ws': ['beforeElement'], '0': ['afterZero', 'append'], 'number': ['inIndex', 'append'], "'": ['inSingleQuote', 'append', ''], - '"': ['inDoubleQuote', 'append', ''] + '"': ['inDoubleQuote', 'append', ''], + "ident": ['inIdent', 'append', '*'] }, - + 'afterZero': { 'ws': ['afterElement', 'push'], ']': ['inPath', 'push'] }, - + 'inIndex': { '0': ['inIndex', 'append'], 'number': ['inIndex', 'append'], 'ws': ['afterElement'], ']': ['inPath', 'push'] }, - + 'inSingleQuote': { "'": ['afterElement'], 'eof': 'error', 'else': ['inSingleQuote', 'append'] }, - + 'inDoubleQuote': { '"': ['afterElement'], 'eof': 'error', 'else': ['inDoubleQuote', 'append'] }, - + 'afterElement': { 'ws': ['afterElement'], ']': ['inPath', 'push'] } } - + function noop () {} - + /** * Determine the type of a character in a keypath. * * @param {Char} char * @return {String} type */ - + function getPathCharType (char) { if (char === undefined) { return 'eof' } - + var code = char.charCodeAt(0) - + switch(code) { case 0x5B: // [ case 0x5D: // ] @@ -3202,11 +2724,11 @@ return /******/ (function(modules) { // webpackBootstrap case 0x27: // ' case 0x30: // 0 return char - + case 0x5F: // _ case 0x24: // $ return 'ident' - + case 0x20: // Space case 0x09: // Tab case 0x0A: // Newline @@ -3217,21 +2739,21 @@ return /******/ (function(modules) { // webpackBootstrap case 0x2029: // Paragraph Separator return 'ws' } - + // a-z, A-Z if ((0x61 <= code && code <= 0x7A) || (0x41 <= code && code <= 0x5A)) { return 'ident' } - + // 1-9 if (0x31 <= code && code <= 0x39) { return 'number' } - + return 'else' } - + /** * Parse a string path into an array of segments * Todo implement cache @@ -3239,13 +2761,13 @@ return /******/ (function(modules) { // webpackBootstrap * @param {String} path * @return {Array|undefined} */ - + function parsePath (path) { var keys = [] var index = -1 var mode = 'beforePath' var c, newChar, key, type, transition, action, typeMap - + var actions = { push: function() { if (key === undefined) { @@ -3262,7 +2784,7 @@ return /******/ (function(modules) { // webpackBootstrap } } } - + function maybeUnescapeQuote () { var nextChar = path[index + 1] if ((mode === 'inSingleQuote' && nextChar === "'") || @@ -3273,53 +2795,59 @@ return /******/ (function(modules) { // webpackBootstrap return true } } - + while (mode) { index++ c = path[index] - + if (c === '\\' && maybeUnescapeQuote()) { continue } - + type = getPathCharType(c) typeMap = pathStateMachine[mode] transition = typeMap[type] || typeMap['else'] || 'error' - + if (transition === 'error') { return // parse error } - + mode = transition[0] action = actions[transition[1]] || noop - newChar = transition[2] === undefined + newChar = transition[2] + newChar = newChar === undefined ? c - : transition[2] + : newChar === '*' + ? newChar + c + : newChar action() - + if (mode === 'afterPath') { + keys.raw = path return keys } } } - + /** * Format a accessor segment based on its type. * * @param {String} key * @return {Boolean} */ - - function formatAccessor(key) { + + function formatAccessor (key) { if (identRE.test(key)) { // identifier return '.' + key } else if (+key === key >>> 0) { // bracket index return '[' + key + ']' + } else if (key.charAt(0) === '*') { + return '[o' + formatAccessor(key.slice(1)) + ']' } else { // bracket string return '["' + key.replace(/"/g, '\\"') + '"]' } } - + /** * Compiles a getter function with a fixed path. * The fixed path getter supresses errors. @@ -3327,19 +2855,19 @@ return /******/ (function(modules) { // webpackBootstrap * @param {Array} path * @return {Function} */ - + exports.compileGetter = function (path) { var body = 'return o' + path.map(formatAccessor).join('') return new Function('o', 'try {' + body + '} catch (e) {}') } - + /** * External parse that check for a cache hit first * * @param {String} path * @return {Array|undefined} */ - + exports.parse = function (path) { var hit = pathCache.get(path) if (!hit) { @@ -3351,21 +2879,21 @@ return /******/ (function(modules) { // webpackBootstrap } return hit } - + /** * Get from an object from a path string * * @param {Object} obj * @param {String} path */ - + exports.get = function (obj, path) { path = exports.parse(path) if (path) { return path.get(obj) } } - + /** * Set on an object from a path * @@ -3373,8 +2901,9 @@ return /******/ (function(modules) { // webpackBootstrap * @param {String | Array} path * @param {*} val */ - + exports.set = function (obj, path, val) { + var original = obj if (typeof path === 'string') { path = exports.parse(path) } @@ -3382,51 +2911,283 @@ return /******/ (function(modules) { // webpackBootstrap return false } var last, key - for (var i = 0, l = path.length - 1; i < l; i++) { + for (var i = 0, l = path.length; i < l; i++) { last = obj key = path[i] - obj = obj[key] - if (!_.isObject(obj)) { - obj = {} - last.$add(key, obj) + if (key.charAt(0) === '*') { + key = original[key.slice(1)] + } + if (i < l - 1) { + obj = obj[key] + if (!_.isObject(obj)) { + obj = {} + last.$add(key, obj) + warnNonExistent(path) + } + } else { + if (key in obj) { + obj[key] = val + } else { + obj.$add(key, val) + warnNonExistent(path) + } } - } - key = path[i] - if (key in obj) { - obj[key] = val - } else { - obj.$add(key, val) } return true } + function warnNonExistent (path) { + _.warn( + 'You are setting a non-existent path "' + path.raw + '" ' + + 'on a vm instance. Consider pre-initializing the property ' + + 'with the "data" option for more reliable reactivity ' + + 'and better performance.' + ) + } + +/***/ }, +/* 18 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * A doubly linked list-based Least Recently Used (LRU) + * cache. Will keep most recently used items while + * discarding least recently used items when its limit is + * reached. This is a bare-bone version of + * Rasmus Andersson's js-lru: + * + * https://github.com/rsms/js-lru + * + * @param {Number} limit + * @constructor + */ + + function Cache (limit) { + this.size = 0 + this.limit = limit + this.head = this.tail = undefined + this._keymap = {} + } + + var p = Cache.prototype + + /** + * Put into the cache associated with . + * Returns the entry which was removed to make room for + * the new entry. Otherwise undefined is returned. + * (i.e. if there was enough room already). + * + * @param {String} key + * @param {*} value + * @return {Entry|undefined} + */ + + p.put = function (key, value) { + var entry = { + key:key, + value:value + } + this._keymap[key] = entry + if (this.tail) { + this.tail.newer = entry + entry.older = this.tail + } else { + this.head = entry + } + this.tail = entry + if (this.size === this.limit) { + return this.shift() + } else { + this.size++ + } + } + + /** + * Purge the least recently used (oldest) entry from the + * cache. Returns the removed entry or undefined if the + * cache was empty. + */ + + p.shift = function () { + var entry = this.head + if (entry) { + this.head = this.head.newer + this.head.older = undefined + entry.newer = entry.older = undefined + this._keymap[entry.key] = undefined + } + return entry + } + + /** + * Get and register recent use of . Returns the value + * associated with or undefined if not in cache. + * + * @param {String} key + * @param {Boolean} returnEntry + * @return {Entry|*} + */ + + p.get = function (key, returnEntry) { + var entry = this._keymap[key] + if (entry === undefined) return + if (entry === this.tail) { + return returnEntry + ? entry + : entry.value + } + // HEAD--------------TAIL + // <.older .newer> + // <--- add direction -- + // A B C E + if (entry.newer) { + if (entry === this.head) { + this.head = entry.newer + } + entry.newer.older = entry.older // C <-- E. + } + if (entry.older) { + entry.older.newer = entry.newer // C. --> E + } + entry.newer = undefined // D --x + entry.older = this.tail // D. --> E + if (this.tail) { + this.tail.newer = entry // E. <-- D + } + this.tail = entry + return returnEntry + ? entry + : entry.value + } + + module.exports = Cache + /***/ }, /* 19 */ /***/ function(module, exports, __webpack_require__) { - var Cache = __webpack_require__(52) - var config = __webpack_require__(15) + var _ = __webpack_require__(2) + var MAX_UPDATE_COUNT = 10 + + // we have two separate queues: one for directive updates + // and one for user watcher registered via $watch(). + // we want to guarantee directive updates to be called + // before user watchers so that when user watchers are + // triggered, the DOM would have already been in updated + // state. + var queue = [] + var userQueue = [] + var has = {} + var waiting = false + var flushing = false + + /** + * Reset the batcher's state. + */ + + function reset () { + queue = [] + userQueue = [] + has = {} + waiting = false + flushing = false + } + + /** + * Flush both queues and run the jobs. + */ + + function flush () { + flushing = true + run(queue) + run(userQueue) + reset() + } + + /** + * Run the jobs in a single queue. + * + * @param {Array} queue + */ + + function run (queue) { + // do not cache length because more jobs might be pushed + // as we run existing jobs + for (var i = 0; i < queue.length; i++) { + queue[i].run() + } + } + + /** + * Push a job into the job queue. + * Jobs with duplicate IDs will be skipped unless it's + * pushed when the queue is being flushed. + * + * @param {Object} job + * properties: + * - {String|Number} id + * - {Function} run + */ + + exports.push = function (job) { + var id = job.id + if (!id || !has[id] || flushing) { + if (!has[id]) { + has[id] = 1 + } else { + has[id]++ + // detect possible infinite update loops + if (has[id] > MAX_UPDATE_COUNT) { + _.warn( + 'You may have an infinite update loop for the ' + + 'watcher with expression: "' + job.expression + '".' + ) + return + } + } + // A user watcher callback could trigger another + // directive update during the flushing; at that time + // the directive queue would already have been run, so + // we call that update immediately as it is pushed. + if (flushing && !job.user) { + job.run() + return + } + ;(job.user ? userQueue : queue).push(job) + if (!waiting) { + waiting = true + _.nextTick(flush) + } + } + } + +/***/ }, +/* 20 */ +/***/ function(module, exports, __webpack_require__) { + + var Cache = __webpack_require__(18) + var config = __webpack_require__(4) var dirParser = __webpack_require__(21) var regexEscapeRE = /[-.*+?^${}()|[\]\/\\]/g var cache, tagRE, htmlRE, firstChar, lastChar - + /** * Escape a string so it can be used in a RegExp * constructor. * * @param {String} str */ - + function escapeRegex (str) { return str.replace(regexEscapeRE, '\\$&') } - + /** * Compile the interpolation tag regex. * * @return {RegExp} */ - + function compileRegex () { config._delimitersChanged = false var open = config.delimiters[0] @@ -3451,7 +3212,7 @@ return /******/ (function(modules) { // webpackBootstrap // reset cache cache = new Cache(1000) } - + /** * Parse a template text string into an array of tokens. * @@ -3462,7 +3223,7 @@ return /******/ (function(modules) { // webpackBootstrap * - {Boolean} [html] * - {Boolean} [oneTime] */ - + exports.parse = function (text) { if (config._delimitersChanged) { compileRegex() @@ -3476,7 +3237,7 @@ return /******/ (function(modules) { // webpackBootstrap } var tokens = [] var lastIndex = tagRE.lastIndex = 0 - var match, index, value, first, oneTime, partial + var match, index, value, first, oneTime /* jshint boss:true */ while (match = tagRE.exec(text)) { index = match.index @@ -3489,16 +3250,14 @@ return /******/ (function(modules) { // webpackBootstrap // tag token first = match[1].charCodeAt(0) oneTime = first === 0x2A // * - partial = first === 0x3E // > - value = (oneTime || partial) + value = oneTime ? match[1].slice(1) : match[1] tokens.push({ tag: true, value: value.trim(), html: htmlRE.test(match[0]), - oneTime: oneTime, - partial: partial + oneTime: oneTime }) lastIndex = index + match[0].length } @@ -3510,7 +3269,7 @@ return /******/ (function(modules) { // webpackBootstrap cache.put(text, tokens) return tokens } - + /** * Format a list of tokens into an expression. * e.g. tokens parsed from 'a {{b}} c' can be serialized @@ -3520,7 +3279,7 @@ return /******/ (function(modules) { // webpackBootstrap * @param {Vue} [vm] * @return {String} */ - + exports.tokensToExp = function (tokens, vm) { return tokens.length > 1 ? tokens.map(function (token) { @@ -3528,7 +3287,7 @@ return /******/ (function(modules) { // webpackBootstrap }).join('+') : formatToken(tokens[0], vm, true) } - + /** * Format a single token. * @@ -3537,17 +3296,15 @@ return /******/ (function(modules) { // webpackBootstrap * @param {Boolean} single * @return {String} */ - + function formatToken (token, vm, single) { return token.tag ? vm && token.oneTime ? '"' + vm.$eval(token.value) + '"' - : single - ? token.value - : inlineFilters(token.value) + : inlineFilters(token.value, single) : '"' + token.value + '"' } - + /** * For an attribute with multiple interpolation tags, * e.g. attr="some-{{thing | filter}}", in order to combine @@ -3557,312 +3314,45 @@ return /******/ (function(modules) { // webpackBootstrap * to directive parser and watcher mechanism. * * @param {String} exp + * @param {Boolean} single * @return {String} */ - + var filterRE = /[^|]\|[^|]/ - function inlineFilters (exp) { + function inlineFilters (exp, single) { if (!filterRE.test(exp)) { - return '(' + exp + ')' + return single + ? exp + : '(' + exp + ')' } else { var dir = dirParser.parse(exp)[0] if (!dir.filters) { return '(' + exp + ')' } else { - exp = dir.expression - for (var i = 0, l = dir.filters.length; i < l; i++) { - var filter = dir.filters[i] - var args = filter.args - ? ',"' + filter.args.join('","') + '"' - : '' - filter = 'this.$options.filters["' + filter.name + '"]' - exp = '(' + filter + '.read||' + filter + ')' + - '.apply(this,[' + exp + args + '])' - } - return exp + return 'this._applyFilters(' + + dir.expression + // value + ',null,' + // oldValue (null for read) + JSON.stringify(dir.filters) + // filter descriptors + ',false)' // write? } } } -/***/ }, -/* 20 */ -/***/ function(module, exports, __webpack_require__) { - - var _ = __webpack_require__(11) - var Cache = __webpack_require__(52) - var templateCache = new Cache(1000) - var idSelectorCache = new Cache(1000) - - var map = { - _default : [0, '', ''], - legend : [1, '
', '
'], - tr : [2, '', '
'], - col : [ - 2, - '', - '
' - ] - } - - map.td = - map.th = [ - 3, - '', - '
' - ] - - map.option = - map.optgroup = [ - 1, - '' - ] - - map.thead = - map.tbody = - map.colgroup = - map.caption = - map.tfoot = [1, '', '
'] - - map.g = - map.defs = - map.symbol = - map.use = - map.image = - map.text = - map.circle = - map.ellipse = - map.line = - map.path = - map.polygon = - map.polyline = - map.rect = [ - 1, - '', - '' - ] - - var tagRE = /<([\w:]+)/ - var entityRE = /&\w+;/ - - /** - * Convert a string template to a DocumentFragment. - * Determines correct wrapping by tag types. Wrapping - * strategy found in jQuery & component/domify. - * - * @param {String} templateString - * @return {DocumentFragment} - */ - - function stringToFragment (templateString) { - // try a cache hit first - var hit = templateCache.get(templateString) - if (hit) { - return hit - } - - var frag = document.createDocumentFragment() - var tagMatch = templateString.match(tagRE) - var entityMatch = entityRE.test(templateString) - - if (!tagMatch && !entityMatch) { - // text only, return a single text node. - frag.appendChild( - document.createTextNode(templateString) - ) - } else { - - var tag = tagMatch && tagMatch[1] - var wrap = map[tag] || map._default - var depth = wrap[0] - var prefix = wrap[1] - var suffix = wrap[2] - var node = document.createElement('div') - - node.innerHTML = prefix + templateString.trim() + suffix - while (depth--) { - node = node.lastChild - } - - var child - /* jshint boss:true */ - while (child = node.firstChild) { - frag.appendChild(child) - } - } - - templateCache.put(templateString, frag) - return frag - } - - /** - * Convert a template node to a DocumentFragment. - * - * @param {Node} node - * @return {DocumentFragment} - */ - - function nodeToFragment (node) { - var tag = node.tagName - // if its a template tag and the browser supports it, - // its content is already a document fragment. - if ( - tag === 'TEMPLATE' && - node.content instanceof DocumentFragment - ) { - return node.content - } - // script template - if (tag === 'SCRIPT') { - return stringToFragment(node.textContent) - } - // normal node, clone it to avoid mutating the original - var clone = exports.clone(node) - var frag = document.createDocumentFragment() - var child - /* jshint boss:true */ - while (child = clone.firstChild) { - frag.appendChild(child) - } - return frag - } - - // Test for the presence of the Safari template cloning bug - // https://bugs.webkit.org/show_bug.cgi?id=137755 - var hasBrokenTemplate = _.inBrowser - ? (function () { - var a = document.createElement('div') - a.innerHTML = '' - return !a.cloneNode(true).firstChild.innerHTML - })() - : false - - // Test for IE10/11 textarea placeholder clone bug - var hasTextareaCloneBug = _.inBrowser - ? (function () { - var t = document.createElement('textarea') - t.placeholder = 't' - return t.cloneNode(true).value === 't' - })() - : false - - /** - * 1. Deal with Safari cloning nested