From 0fb4ba3740fd7d2a2c1a3ab3eab5ae5a909c6afc Mon Sep 17 00:00:00 2001 From: JianMiau Date: Tue, 5 Apr 2022 18:40:31 +0800 Subject: [PATCH] =?UTF-8?q?[add]=20Vue=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/vue.js | 10073 +++++++++++++++++++++++ main.js | 108 +- package.json | 38 +- panel/index.js | 96 +- static/style/default/bootstrap.min.css | 7 + static/style/default/index.css | 8 + static/template/default/index.html | 6 + static/template/vue/counter.html | 18 + static/template/vue/counter.js | 36 + 9 files changed, 10263 insertions(+), 127 deletions(-) create mode 100644 lib/vue.js create mode 100644 static/style/default/bootstrap.min.css create mode 100644 static/style/default/index.css create mode 100644 static/template/default/index.html create mode 100644 static/template/vue/counter.html create mode 100644 static/template/vue/counter.js diff --git a/lib/vue.js b/lib/vue.js new file mode 100644 index 0000000..7ae9589 --- /dev/null +++ b/lib/vue.js @@ -0,0 +1,10073 @@ +/*! + * Vue.js v1.0.26 + * (c) 2016 Evan You + * Released under the MIT License. + */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.Vue = factory()); +}(this, function () { 'use strict'; + + function set(obj, key, val) { + if (hasOwn(obj, key)) { + obj[key] = val; + return; + } + if (obj._isVue) { + set(obj._data, key, val); + return; + } + var ob = obj.__ob__; + if (!ob) { + obj[key] = val; + return; + } + ob.convert(key, val); + ob.dep.notify(); + if (ob.vms) { + var i = ob.vms.length; + while (i--) { + var vm = ob.vms[i]; + vm._proxy(key); + vm._digest(); + } + } + return val; + } + + /** + * Delete a property and trigger change if necessary. + * + * @param {Object} obj + * @param {String} key + */ + + function del(obj, key) { + if (!hasOwn(obj, key)) { + return; + } + delete obj[key]; + var ob = obj.__ob__; + if (!ob) { + if (obj._isVue) { + delete obj._data[key]; + obj._digest(); + } + return; + } + ob.dep.notify(); + if (ob.vms) { + var i = ob.vms.length; + while (i--) { + var vm = ob.vms[i]; + vm._unproxy(key); + vm._digest(); + } + } + } + + var hasOwnProperty = Object.prototype.hasOwnProperty; + /** + * Check whether the object has the property. + * + * @param {Object} obj + * @param {String} key + * @return {Boolean} + */ + + function hasOwn(obj, key) { + return hasOwnProperty.call(obj, key); + } + + /** + * Check if an expression is a literal value. + * + * @param {String} exp + * @return {Boolean} + */ + + var literalValueRE = /^\s?(true|false|-?[\d\.]+|'[^']*'|"[^"]*")\s?$/; + + function isLiteral(exp) { + return literalValueRE.test(exp); + } + + /** + * Check if a string starts with $ or _ + * + * @param {String} str + * @return {Boolean} + */ + + function isReserved(str) { + var c = (str + '').charCodeAt(0); + return c === 0x24 || c === 0x5F; + } + + /** + * Guard text output, make sure undefined outputs + * empty string + * + * @param {*} value + * @return {String} + */ + + function _toString(value) { + return value == null ? '' : value.toString(); + } + + /** + * Check and convert possible numeric strings to numbers + * before setting back to data + * + * @param {*} value + * @return {*|Number} + */ + + function toNumber(value) { + if (typeof value !== 'string') { + return value; + } else { + var parsed = Number(value); + return isNaN(parsed) ? value : parsed; + } + } + + /** + * Convert string boolean literals into real booleans. + * + * @param {*} value + * @return {*|Boolean} + */ + + function toBoolean(value) { + return value === 'true' ? true : value === 'false' ? false : value; + } + + /** + * Strip quotes from a string + * + * @param {String} str + * @return {String | false} + */ + + function stripQuotes(str) { + var a = str.charCodeAt(0); + var b = str.charCodeAt(str.length - 1); + return a === b && (a === 0x22 || a === 0x27) ? str.slice(1, -1) : str; + } + + /** + * Camelize a hyphen-delmited string. + * + * @param {String} str + * @return {String} + */ + + var camelizeRE = /-(\w)/g; + + function camelize(str) { + return str.replace(camelizeRE, toUpper); + } + + function toUpper(_, c) { + return c ? c.toUpperCase() : ''; + } + + /** + * Hyphenate a camelCase string. + * + * @param {String} str + * @return {String} + */ + + var hyphenateRE = /([a-z\d])([A-Z])/g; + + function hyphenate(str) { + return str.replace(hyphenateRE, '$1-$2').toLowerCase(); + } + + /** + * 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; + + function classify(str) { + return str.replace(classifyRE, toUpper); + } + + /** + * Simple bind, faster than native + * + * @param {Function} fn + * @param {Object} ctx + * @return {Function} + */ + + function bind(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} + */ + + function toArray(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 + */ + + function extend(to, from) { + var keys = Object.keys(from); + var i = keys.length; + while (i--) { + to[keys[i]] = from[keys[i]]; + } + 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} + */ + + function isObject(obj) { + return obj !== null && typeof obj === 'object'; + } + + /** + * Strict object type check. Only returns true + * for plain JavaScript objects. + * + * @param {*} obj + * @return {Boolean} + */ + + var toString = Object.prototype.toString; + var OBJECT_STRING = '[object Object]'; + + function isPlainObject(obj) { + return toString.call(obj) === OBJECT_STRING; + } + + /** + * Array type check. + * + * @param {*} obj + * @return {Boolean} + */ + + var isArray = Array.isArray; + + /** + * Define a property. + * + * @param {Object} obj + * @param {String} key + * @param {*} val + * @param {Boolean} [enumerable] + */ + + function def(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 + */ + + function _debounce(func, wait) { + var timeout, args, context, timestamp, result; + var later = function later() { + 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 + */ + + function indexOf(arr, obj) { + var i = arr.length; + while (i--) { + if (arr[i] === obj) return i; + } + return -1; + } + + /** + * Make a cancellable version of an async callback. + * + * @param {Function} fn + * @return {Function} + */ + + function cancellable(fn) { + var cb = function cb() { + if (!cb.cancelled) { + return fn.apply(this, arguments); + } + }; + cb.cancel = function () { + cb.cancelled = true; + }; + return cb; + } + + /** + * Check if two values are loosely equal - that is, + * if they are plain objects, do they have the same shape? + * + * @param {*} a + * @param {*} b + * @return {Boolean} + */ + + function looseEqual(a, b) { + /* eslint-disable eqeqeq */ + return a == b || (isObject(a) && isObject(b) ? JSON.stringify(a) === JSON.stringify(b) : false); + /* eslint-enable eqeqeq */ + } + + var hasProto = ('__proto__' in {}); + + // Browser environment sniffing + var inBrowser = typeof window !== 'undefined' && Object.prototype.toString.call(window) !== '[object Object]'; + + // detect devtools + var devtools = inBrowser && window.__VUE_DEVTOOLS_GLOBAL_HOOK__; + + // UA sniffing for working around browser-specific quirks + var UA = inBrowser && window.navigator.userAgent.toLowerCase(); + var isIE = UA && UA.indexOf('trident') > 0; + var isIE9 = UA && UA.indexOf('msie 9.0') > 0; + var isAndroid = UA && UA.indexOf('android') > 0; + var isIos = UA && /(iphone|ipad|ipod|ios)/i.test(UA); + var iosVersionMatch = isIos && UA.match(/os ([\d_]+)/); + var iosVersion = iosVersionMatch && iosVersionMatch[1].split('_'); + + // detecting iOS UIWebView by indexedDB + var hasMutationObserverBug = iosVersion && Number(iosVersion[0]) >= 9 && Number(iosVersion[1]) >= 3 && !window.indexedDB; + + var transitionProp = undefined; + var transitionEndEvent = undefined; + var animationProp = undefined; + var animationEndEvent = undefined; + + // Transition property/event sniffing + if (inBrowser && !isIE9) { + var isWebkitTrans = window.ontransitionend === undefined && window.onwebkittransitionend !== undefined; + var isWebkitAnim = window.onanimationend === undefined && window.onwebkitanimationend !== undefined; + transitionProp = isWebkitTrans ? 'WebkitTransition' : 'transition'; + transitionEndEvent = isWebkitTrans ? 'webkitTransitionEnd' : 'transitionend'; + animationProp = isWebkitAnim ? 'WebkitAnimation' : 'animation'; + animationEndEvent = isWebkitAnim ? 'webkitAnimationEnd' : 'animationend'; + } + + /** + * 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 {Function} cb + * @param {Object} ctx + */ + + var nextTick = (function () { + var callbacks = []; + var pending = false; + var timerFunc; + function nextTickHandler() { + pending = false; + var copies = callbacks.slice(0); + callbacks = []; + for (var i = 0; i < copies.length; i++) { + copies[i](); + } + } + + /* istanbul ignore if */ + if (typeof MutationObserver !== 'undefined' && !hasMutationObserverBug) { + var counter = 1; + var observer = new MutationObserver(nextTickHandler); + var textNode = document.createTextNode(counter); + observer.observe(textNode, { + characterData: true + }); + timerFunc = function () { + counter = (counter + 1) % 2; + textNode.data = counter; + }; + } else { + // webpack attempts to inject a shim for setImmediate + // if it is used as a global, so we have to work around that to + // avoid bundling unnecessary code. + var context = inBrowser ? window : typeof global !== 'undefined' ? global : {}; + timerFunc = context.setImmediate || setTimeout; + } + return function (cb, ctx) { + var func = ctx ? function () { + cb.call(ctx); + } : cb; + callbacks.push(func); + if (pending) return; + pending = true; + timerFunc(nextTickHandler, 0); + }; + })(); + + var _Set = undefined; + /* istanbul ignore if */ + if (typeof Set !== 'undefined' && Set.toString().match(/native code/)) { + // use native Set when available. + _Set = Set; + } else { + // a non-standard Set polyfill that only works with primitive keys. + _Set = function () { + this.set = Object.create(null); + }; + _Set.prototype.has = function (key) { + return this.set[key] !== undefined; + }; + _Set.prototype.add = function (key) { + this.set[key] = 1; + }; + _Set.prototype.clear = function () { + this.set = Object.create(null); + }; + } + + function Cache(limit) { + this.size = 0; + this.limit = limit; + this.head = this.tail = undefined; + this._keymap = Object.create(null); + } + + 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 removed; + + var entry = this.get(key, true); + if (!entry) { + if (this.size === this.limit) { + removed = this.shift(); + } + entry = { + key: key + }; + this._keymap[key] = entry; + if (this.tail) { + this.tail.newer = entry; + entry.older = this.tail; + } else { + this.head = entry; + } + this.tail = entry; + this.size++; + } + entry.value = value; + + return removed; + }; + + /** + * 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; + this.size--; + } + 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; + }; + + var cache$1 = new Cache(1000); + var filterTokenRE = /[^\s'"]+|'[^']*'|"[^"]*"/g; + var reservedArgRE = /^in$|^-?\d+/; + + /** + * Parser state + */ + + var str; + var dir; + var c; + var prev; + var i; + var l; + var lastFilterIndex; + var inSingle; + var inDouble; + var curly; + var square; + var paren; + /** + * Push a filter to the current directive object + */ + + function pushFilter() { + var exp = str.slice(lastFilterIndex, i).trim(); + var filter; + if (exp) { + filter = {}; + var tokens = exp.match(filterTokenRE); + filter.name = tokens[0]; + if (tokens.length > 1) { + filter.args = tokens.slice(1).map(processFilterArg); + } + } + if (filter) { + (dir.filters = dir.filters || []).push(filter); + } + lastFilterIndex = i + 1; + } + + /** + * Check if an argument is dynamic and strip quotes. + * + * @param {String} arg + * @return {Object} + */ + + function processFilterArg(arg) { + if (reservedArgRE.test(arg)) { + return { + value: toNumber(arg), + dynamic: false + }; + } else { + var stripped = stripQuotes(arg); + var dynamic = stripped === arg; + return { + value: dynamic ? arg : stripped, + dynamic: dynamic + }; + } + } + + /** + * Parse a directive value and extract the expression + * and its filters into a descriptor. + * + * Example: + * + * "a + 1 | uppercase" will yield: + * { + * expression: 'a + 1', + * filters: [ + * { name: 'uppercase', args: null } + * ] + * } + * + * @param {String} s + * @return {Object} + */ + + function parseDirective(s) { + var hit = cache$1.get(s); + if (hit) { + return hit; + } + + // reset parser state + str = s; + inSingle = inDouble = false; + curly = square = paren = 0; + lastFilterIndex = 0; + dir = {}; + + for (i = 0, l = str.length; i < l; i++) { + prev = c; + c = str.charCodeAt(i); + if (inSingle) { + // check single quote + if (c === 0x27 && prev !== 0x5C) inSingle = !inSingle; + } else if (inDouble) { + // check double quote + if (c === 0x22 && prev !== 0x5C) inDouble = !inDouble; + } else if (c === 0x7C && // pipe + str.charCodeAt(i + 1) !== 0x7C && str.charCodeAt(i - 1) !== 0x7C) { + if (dir.expression == null) { + // first filter, end of expression + lastFilterIndex = i + 1; + dir.expression = str.slice(0, i).trim(); + } else { + // already has filter + pushFilter(); + } + } else { + switch (c) { + case 0x22: + inDouble = true;break; // " + case 0x27: + inSingle = true;break; // ' + case 0x28: + paren++;break; // ( + case 0x29: + paren--;break; // ) + case 0x5B: + square++;break; // [ + case 0x5D: + square--;break; // ] + case 0x7B: + curly++;break; // { + case 0x7D: + curly--;break; // } + } + } + } + + if (dir.expression == null) { + dir.expression = str.slice(0, i).trim(); + } else if (lastFilterIndex !== 0) { + pushFilter(); + } + + cache$1.put(s, dir); + return dir; + } + +var directive = Object.freeze({ + parseDirective: parseDirective + }); + + var regexEscapeRE = /[-.*+?^${}()|[\]\/\\]/g; + var cache = undefined; + var tagRE = undefined; + var htmlRE = undefined; + /** + * Escape a string so it can be used in a RegExp + * constructor. + * + * @param {String} str + */ + + function escapeRegex(str) { + return str.replace(regexEscapeRE, '\\$&'); + } + + function compileRegex() { + var open = escapeRegex(config.delimiters[0]); + var close = escapeRegex(config.delimiters[1]); + var unsafeOpen = escapeRegex(config.unsafeDelimiters[0]); + var unsafeClose = escapeRegex(config.unsafeDelimiters[1]); + tagRE = new RegExp(unsafeOpen + '((?:.|\\n)+?)' + unsafeClose + '|' + open + '((?:.|\\n)+?)' + close, 'g'); + htmlRE = new RegExp('^' + unsafeOpen + '((?:.|\\n)+?)' + unsafeClose + '$'); + // reset cache + cache = new Cache(1000); + } + + /** + * Parse a template text string into an array of tokens. + * + * @param {String} text + * @return {Array | null} + * - {String} type + * - {String} value + * - {Boolean} [html] + * - {Boolean} [oneTime] + */ + + function parseText(text) { + if (!cache) { + compileRegex(); + } + var hit = cache.get(text); + if (hit) { + return hit; + } + if (!tagRE.test(text)) { + return null; + } + var tokens = []; + var lastIndex = tagRE.lastIndex = 0; + var match, index, html, value, first, oneTime; + /* eslint-disable no-cond-assign */ + while (match = tagRE.exec(text)) { + /* eslint-enable no-cond-assign */ + index = match.index; + // push text token + if (index > lastIndex) { + tokens.push({ + value: text.slice(lastIndex, index) + }); + } + // tag token + html = htmlRE.test(match[0]); + value = html ? match[1] : match[2]; + first = value.charCodeAt(0); + oneTime = first === 42; // * + value = oneTime ? value.slice(1) : value; + tokens.push({ + tag: true, + value: value.trim(), + html: html, + oneTime: oneTime + }); + lastIndex = index + match[0].length; + } + if (lastIndex < text.length) { + tokens.push({ + value: text.slice(lastIndex) + }); + } + 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 + * into one single expression as '"a " + b + " c"'. + * + * @param {Array} tokens + * @param {Vue} [vm] + * @return {String} + */ + + function tokensToExp(tokens, vm) { + if (tokens.length > 1) { + return tokens.map(function (token) { + return formatToken(token, vm); + }).join('+'); + } else { + return formatToken(tokens[0], vm, true); + } + } + + /** + * Format a single token. + * + * @param {Object} token + * @param {Vue} [vm] + * @param {Boolean} [single] + * @return {String} + */ + + function formatToken(token, vm, single) { + return token.tag ? token.oneTime && vm ? '"' + vm.$eval(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 + * the whole thing into a single watchable expression, we + * have to inline those filters. This function does exactly + * that. This is a bit hacky but it avoids heavy changes + * to directive parser and watcher mechanism. + * + * @param {String} exp + * @param {Boolean} single + * @return {String} + */ + + var filterRE = /[^|]\|[^|]/; + function inlineFilters(exp, single) { + if (!filterRE.test(exp)) { + return single ? exp : '(' + exp + ')'; + } else { + var dir = parseDirective(exp); + if (!dir.filters) { + return '(' + exp + ')'; + } else { + return 'this._applyFilters(' + dir.expression + // value + ',null,' + // oldValue (null for read) + JSON.stringify(dir.filters) + // filter descriptors + ',false)'; // write? + } + } + } + +var text = Object.freeze({ + compileRegex: compileRegex, + parseText: parseText, + tokensToExp: tokensToExp + }); + + var delimiters = ['{{', '}}']; + var unsafeDelimiters = ['{{{', '}}}']; + + var config = Object.defineProperties({ + + /** + * Whether to print debug messages. + * Also enables stack trace for warnings. + * + * @type {Boolean} + */ + + debug: false, + + /** + * Whether to suppress warnings. + * + * @type {Boolean} + */ + + silent: false, + + /** + * Whether to use async rendering. + */ + + async: true, + + /** + * Whether to warn against errors caught when evaluating + * expressions. + */ + + warnExpressionErrors: true, + + /** + * Whether to allow devtools inspection. + * Disabled by default in production builds. + */ + + devtools: 'development' !== 'production', + + /** + * 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: ['component', 'directive', 'elementDirective', 'filter', 'transition', 'partial'], + + /** + * prop binding modes + */ + + _propBindingModes: { + ONE_WAY: 0, + TWO_WAY: 1, + ONE_TIME: 2 + }, + + /** + * Max circular updates allowed in a batcher flush cycle. + */ + + _maxUpdateCount: 100 + + }, { + delimiters: { /** + * Interpolation delimiters. Changing these would trigger + * the text parser to re-compile the regular expressions. + * + * @type {Array} + */ + + get: function get() { + return delimiters; + }, + set: function set(val) { + delimiters = val; + compileRegex(); + }, + configurable: true, + enumerable: true + }, + unsafeDelimiters: { + get: function get() { + return unsafeDelimiters; + }, + set: function set(val) { + unsafeDelimiters = val; + compileRegex(); + }, + configurable: true, + enumerable: true + } + }); + + var warn = undefined; + var formatComponentName = undefined; + + if ('development' !== 'production') { + (function () { + var hasConsole = typeof console !== 'undefined'; + + warn = function (msg, vm) { + if (hasConsole && !config.silent) { + console.error('[Vue warn]: ' + msg + (vm ? formatComponentName(vm) : '')); + } + }; + + formatComponentName = function (vm) { + var name = vm._isVue ? vm.$options.name : vm.name; + return name ? ' (found in component: <' + hyphenate(name) + '>)' : ''; + }; + })(); + } + + /** + * Append with transition. + * + * @param {Element} el + * @param {Element} target + * @param {Vue} vm + * @param {Function} [cb] + */ + + function appendWithTransition(el, target, vm, cb) { + applyTransition(el, 1, function () { + target.appendChild(el); + }, vm, cb); + } + + /** + * InsertBefore with transition. + * + * @param {Element} el + * @param {Element} target + * @param {Vue} vm + * @param {Function} [cb] + */ + + function beforeWithTransition(el, target, vm, cb) { + applyTransition(el, 1, function () { + before(el, target); + }, vm, cb); + } + + /** + * Remove with transition. + * + * @param {Element} el + * @param {Vue} vm + * @param {Function} [cb] + */ + + function removeWithTransition(el, vm, cb) { + applyTransition(el, -1, function () { + remove(el); + }, vm, cb); + } + + /** + * Apply transitions with an operation callback. + * + * @param {Element} el + * @param {Number} direction + * 1: enter + * -1: leave + * @param {Function} op - the actual DOM operation + * @param {Vue} vm + * @param {Function} [cb] + */ + + function applyTransition(el, direction, op, vm, cb) { + var transition = el.__v_trans; + if (!transition || + // skip if there are no js hooks and CSS transition is + // not supported + !transition.hooks && !transitionEndEvent || + // skip transitions for initial compile + !vm._isCompiled || + // if the vm is being manipulated by a parent directive + // during the parent's compilation phase, skip the + // animation. + vm.$parent && !vm.$parent._isCompiled) { + op(); + if (cb) cb(); + return; + } + var action = direction > 0 ? 'enter' : 'leave'; + transition[action](op, cb); + } + +var transition = Object.freeze({ + appendWithTransition: appendWithTransition, + beforeWithTransition: beforeWithTransition, + removeWithTransition: removeWithTransition, + applyTransition: applyTransition + }); + + /** + * Query an element selector if it's not an element already. + * + * @param {String|Element} el + * @return {Element} + */ + + function query(el) { + if (typeof el === 'string') { + var selector = el; + el = document.querySelector(el); + if (!el) { + 'development' !== 'production' && warn('Cannot find element: ' + selector); + } + } + return el; + } + + /** + * 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 by doing the + * contains() check on the node's parentNode instead of + * the node itself. + * + * @param {Node} node + * @return {Boolean} + */ + + function inDoc(node) { + if (!node) return false; + var doc = node.ownerDocument.documentElement; + var parent = node.parentNode; + return doc === node || doc === parent || !!(parent && parent.nodeType === 1 && doc.contains(parent)); + } + + /** + * Get and remove an attribute from a node. + * + * @param {Node} node + * @param {String} _attr + */ + + function getAttr(node, _attr) { + var val = node.getAttribute(_attr); + if (val !== null) { + node.removeAttribute(_attr); + } + return val; + } + + /** + * Get an attribute with colon or v-bind: prefix. + * + * @param {Node} node + * @param {String} name + * @return {String|null} + */ + + function getBindAttr(node, name) { + var val = getAttr(node, ':' + name); + if (val === null) { + val = getAttr(node, 'v-bind:' + name); + } + return val; + } + + /** + * Check the presence of a bind attribute. + * + * @param {Node} node + * @param {String} name + * @return {Boolean} + */ + + function hasBindAttr(node, name) { + return node.hasAttribute(name) || node.hasAttribute(':' + name) || node.hasAttribute('v-bind:' + name); + } + + /** + * Insert el before target + * + * @param {Element} el + * @param {Element} target + */ + + function before(el, target) { + target.parentNode.insertBefore(el, target); + } + + /** + * Insert el after target + * + * @param {Element} el + * @param {Element} target + */ + + function after(el, target) { + if (target.nextSibling) { + before(el, target.nextSibling); + } else { + target.parentNode.appendChild(el); + } + } + + /** + * Remove el from DOM + * + * @param {Element} el + */ + + function remove(el) { + el.parentNode.removeChild(el); + } + + /** + * Prepend el to target + * + * @param {Element} el + * @param {Element} target + */ + + function prepend(el, target) { + if (target.firstChild) { + before(el, target.firstChild); + } else { + target.appendChild(el); + } + } + + /** + * Replace target with el + * + * @param {Element} target + * @param {Element} el + */ + + function replace(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 + * @param {Boolean} [useCapture] + */ + + function on(el, event, cb, useCapture) { + el.addEventListener(event, cb, useCapture); + } + + /** + * Remove event listener shorthand. + * + * @param {Element} el + * @param {String} event + * @param {Function} cb + */ + + function off(el, event, cb) { + el.removeEventListener(event, cb); + } + + /** + * For IE9 compat: when both class and :class are present + * getAttribute('class') returns wrong value... + * + * @param {Element} el + * @return {String} + */ + + function getClass(el) { + var classname = el.className; + if (typeof classname === 'object') { + classname = classname.baseVal || ''; + } + return classname; + } + + /** + * In IE9, setAttribute('class') will result in empty class + * if the element also has the :class attribute; However in + * PhantomJS, setting `className` does not work on SVG elements... + * So we have to do a conditional check here. + * + * @param {Element} el + * @param {String} cls + */ + + function setClass(el, cls) { + /* istanbul ignore if */ + if (isIE9 && !/svg$/.test(el.namespaceURI)) { + el.className = cls; + } else { + el.setAttribute('class', cls); + } + } + + /** + * Add class with compatibility for IE & SVG + * + * @param {Element} el + * @param {String} cls + */ + + function addClass(el, cls) { + if (el.classList) { + el.classList.add(cls); + } else { + var cur = ' ' + getClass(el) + ' '; + if (cur.indexOf(' ' + cls + ' ') < 0) { + setClass(el, (cur + cls).trim()); + } + } + } + + /** + * Remove class with compatibility for IE & SVG + * + * @param {Element} el + * @param {String} cls + */ + + function removeClass(el, cls) { + if (el.classList) { + el.classList.remove(cls); + } else { + var cur = ' ' + getClass(el) + ' '; + var tar = ' ' + cls + ' '; + while (cur.indexOf(tar) >= 0) { + cur = cur.replace(tar, ' '); + } + setClass(el, cur.trim()); + } + if (!el.className) { + el.removeAttribute('class'); + } + } + + /** + * Extract raw content inside an element into a temporary + * container div + * + * @param {Element} el + * @param {Boolean} asFragment + * @return {Element|DocumentFragment} + */ + + function extractContent(el, asFragment) { + var child; + var rawContent; + /* istanbul ignore if */ + if (isTemplate(el) && isFragment(el.content)) { + el = el.content; + } + if (el.hasChildNodes()) { + trimNode(el); + rawContent = asFragment ? document.createDocumentFragment() : document.createElement('div'); + /* eslint-disable no-cond-assign */ + while (child = el.firstChild) { + /* eslint-enable no-cond-assign */ + rawContent.appendChild(child); + } + } + return rawContent; + } + + /** + * Trim possible empty head/tail text and comment + * nodes inside a parent. + * + * @param {Node} node + */ + + function trimNode(node) { + var child; + /* eslint-disable no-sequences */ + while ((child = node.firstChild, isTrimmable(child))) { + node.removeChild(child); + } + while ((child = node.lastChild, isTrimmable(child))) { + node.removeChild(child); + } + /* eslint-enable no-sequences */ + } + + function isTrimmable(node) { + return node && (node.nodeType === 3 && !node.data.trim() || node.nodeType === 8); + } + + /** + * Check if an element is a template tag. + * Note if the template appears inside an SVG its tagName + * will be in lowercase. + * + * @param {Element} el + */ + + function isTemplate(el) { + return el.tagName && el.tagName.toLowerCase() === 'template'; + } + + /** + * Create an "anchor" for performing dom insertion/removals. + * This is used in a number of scenarios: + * - fragment instance + * - v-html + * - v-if + * - v-for + * - component + * + * @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} + */ + + function createAnchor(content, persist) { + var anchor = config.debug ? document.createComment(content) : document.createTextNode(persist ? ' ' : ''); + anchor.__v_anchor = true; + return anchor; + } + + /** + * Find a component ref attribute that starts with $. + * + * @param {Element} node + * @return {String|undefined} + */ + + var refRE = /^v-ref:/; + + function findRef(node) { + if (node.hasAttributes()) { + var attrs = node.attributes; + for (var i = 0, l = attrs.length; i < l; i++) { + var name = attrs[i].name; + if (refRE.test(name)) { + return camelize(name.replace(refRE, '')); + } + } + } + } + + /** + * Map a function to a range of nodes . + * + * @param {Node} node + * @param {Node} end + * @param {Function} op + */ + + function mapNodeRange(node, end, op) { + var next; + while (node !== end) { + next = node.nextSibling; + op(node); + node = next; + } + op(end); + } + + /** + * Remove a range of nodes with transition, store + * the nodes in a fragment with correct ordering, + * and call callback when done. + * + * @param {Node} start + * @param {Node} end + * @param {Vue} vm + * @param {DocumentFragment} frag + * @param {Function} cb + */ + + function removeNodeRange(start, end, vm, frag, cb) { + var done = false; + var removed = 0; + var nodes = []; + mapNodeRange(start, end, function (node) { + if (node === end) done = true; + nodes.push(node); + removeWithTransition(node, vm, onRemoved); + }); + function onRemoved() { + removed++; + if (done && removed >= nodes.length) { + for (var i = 0; i < nodes.length; i++) { + frag.appendChild(nodes[i]); + } + cb && cb(); + } + } + } + + /** + * Check if a node is a DocumentFragment. + * + * @param {Node} node + * @return {Boolean} + */ + + function isFragment(node) { + return node && node.nodeType === 11; + } + + /** + * Get outerHTML of elements, taking care + * of SVG elements in IE as well. + * + * @param {Element} el + * @return {String} + */ + + function getOuterHTML(el) { + if (el.outerHTML) { + return el.outerHTML; + } else { + var container = document.createElement('div'); + container.appendChild(el.cloneNode(true)); + return container.innerHTML; + } + } + + var commonTagRE = /^(div|p|span|img|a|b|i|br|ul|ol|li|h1|h2|h3|h4|h5|h6|code|pre|table|th|td|tr|form|label|input|select|option|nav|article|section|header|footer)$/i; + var reservedTagRE = /^(slot|partial|component)$/i; + + var isUnknownElement = undefined; + if ('development' !== 'production') { + isUnknownElement = function (el, tag) { + if (tag.indexOf('-') > -1) { + // http://stackoverflow.com/a/28210364/1070244 + return el.constructor === window.HTMLUnknownElement || el.constructor === window.HTMLElement; + } else { + return (/HTMLUnknownElement/.test(el.toString()) && + // Chrome returns unknown for several HTML5 elements. + // https://code.google.com/p/chromium/issues/detail?id=540526 + // Firefox returns unknown for some "Interactive elements." + !/^(data|time|rtc|rb|details|dialog|summary)$/.test(tag) + ); + } + }; + } + + /** + * Check if an element is a component, if yes return its + * component id. + * + * @param {Element} el + * @param {Object} options + * @return {Object|undefined} + */ + + function checkComponentAttr(el, options) { + var tag = el.tagName.toLowerCase(); + var hasAttrs = el.hasAttributes(); + if (!commonTagRE.test(tag) && !reservedTagRE.test(tag)) { + if (resolveAsset(options, 'components', tag)) { + return { id: tag }; + } else { + var is = hasAttrs && getIsBinding(el, options); + if (is) { + return is; + } else if ('development' !== 'production') { + var expectedTag = options._componentNameMap && options._componentNameMap[tag]; + if (expectedTag) { + warn('Unknown custom element: <' + tag + '> - ' + 'did you mean <' + expectedTag + '>? ' + 'HTML is case-insensitive, remember to use kebab-case in templates.'); + } else if (isUnknownElement(el, tag)) { + warn('Unknown custom element: <' + tag + '> - did you ' + 'register the component correctly? For recursive components, ' + 'make sure to provide the "name" option.'); + } + } + } + } else if (hasAttrs) { + return getIsBinding(el, options); + } + } + + /** + * Get "is" binding from an element. + * + * @param {Element} el + * @param {Object} options + * @return {Object|undefined} + */ + + function getIsBinding(el, options) { + // dynamic syntax + var exp = el.getAttribute('is'); + if (exp != null) { + if (resolveAsset(options, 'components', exp)) { + el.removeAttribute('is'); + return { id: exp }; + } + } else { + exp = getBindAttr(el, 'is'); + if (exp != null) { + return { id: exp, dynamic: true }; + } + } + } + + /** + * Option overwriting strategies are functions that handle + * how to merge a parent option value and a child option + * value into the final value. + * + * All strategy functions follow the same signature: + * + * @param {*} parentVal + * @param {*} childVal + * @param {Vue} [vm] + */ + + var strats = config.optionMergeStrategies = Object.create(null); + + /** + * Helper that recursively merges two data objects together. + */ + + function mergeData(to, from) { + var key, toVal, fromVal; + for (key in from) { + toVal = to[key]; + fromVal = from[key]; + if (!hasOwn(to, key)) { + set(to, key, fromVal); + } else if (isObject(toVal) && isObject(fromVal)) { + mergeData(toVal, fromVal); + } + } + return to; + } + + /** + * Data + */ + + strats.data = function (parentVal, childVal, vm) { + if (!vm) { + // in a Vue.extend merge, both should be functions + if (!childVal) { + return parentVal; + } + if (typeof childVal !== 'function') { + 'development' !== 'production' && warn('The "data" option should be a function ' + 'that returns a per-instance value in component ' + 'definitions.', vm); + return parentVal; + } + if (!parentVal) { + return childVal; + } + // when parentVal & childVal are both present, + // we need to return a function that returns the + // merged result of both functions... no need to + // check if parentVal is a function here because + // it has to be a function to pass previous merges. + return function mergedDataFn() { + return mergeData(childVal.call(this), parentVal.call(this)); + }; + } else if (parentVal || childVal) { + return function mergedInstanceDataFn() { + // instance merge + var instanceData = typeof childVal === 'function' ? childVal.call(vm) : childVal; + var defaultData = typeof parentVal === 'function' ? parentVal.call(vm) : undefined; + if (instanceData) { + return mergeData(instanceData, defaultData); + } else { + return defaultData; + } + }; + } + }; + + /** + * El + */ + + strats.el = function (parentVal, childVal, vm) { + if (!vm && childVal && typeof childVal !== 'function') { + 'development' !== 'production' && warn('The "el" option should be a function ' + 'that returns a per-instance value in component ' + 'definitions.', vm); + return; + } + var ret = childVal || parentVal; + // invoke the element factory if this is instance merge + return vm && typeof ret === 'function' ? ret.call(vm) : ret; + }; + + /** + * Hooks and param attributes are merged as arrays. + */ + + strats.init = strats.created = strats.ready = strats.attached = strats.detached = strats.beforeCompile = strats.compiled = strats.beforeDestroy = strats.destroyed = strats.activate = function (parentVal, childVal) { + return childVal ? parentVal ? parentVal.concat(childVal) : isArray(childVal) ? childVal : [childVal] : parentVal; + }; + + /** + * Assets + * + * When a vm is present (instance creation), we need to do + * a three-way merge between constructor options, instance + * options and parent options. + */ + + function mergeAssets(parentVal, childVal) { + var res = Object.create(parentVal || null); + return childVal ? extend(res, guardArrayAssets(childVal)) : res; + } + + config._assetTypes.forEach(function (type) { + strats[type + 's'] = mergeAssets; + }); + + /** + * 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; + if (!parentVal) return childVal; + var ret = {}; + extend(ret, parentVal); + for (var key in childVal) { + var parent = ret[key]; + var child = childVal[key]; + if (parent && !isArray(parent)) { + parent = [parent]; + } + ret[key] = parent ? parent.concat(child) : [child]; + } + return ret; + }; + + /** + * Other object hashes. + */ + + strats.props = strats.methods = strats.computed = function (parentVal, childVal) { + if (!childVal) return parentVal; + if (!parentVal) return childVal; + var ret = Object.create(null); + extend(ret, parentVal); + extend(ret, childVal); + return ret; + }; + + /** + * Default strategy. + */ + + var defaultStrat = function defaultStrat(parentVal, childVal) { + return childVal === undefined ? parentVal : childVal; + }; + + /** + * Make sure component options get converted to actual + * constructors. + * + * @param {Object} options + */ + + function guardComponents(options) { + if (options.components) { + var components = options.components = guardArrayAssets(options.components); + var ids = Object.keys(components); + var def; + if ('development' !== 'production') { + var map = options._componentNameMap = {}; + } + for (var i = 0, l = ids.length; i < l; i++) { + var key = ids[i]; + if (commonTagRE.test(key) || reservedTagRE.test(key)) { + 'development' !== 'production' && warn('Do not use built-in or reserved HTML elements as component ' + 'id: ' + key); + continue; + } + // record a all lowercase <-> kebab-case mapping for + // possible custom element case error warning + if ('development' !== 'production') { + map[key.replace(/-/g, '').toLowerCase()] = hyphenate(key); + } + def = components[key]; + if (isPlainObject(def)) { + components[key] = Vue.extend(def); + } + } + } + } + + /** + * Ensure all props option syntax are normalized into the + * Object-based format. + * + * @param {Object} options + */ + + function guardProps(options) { + var props = options.props; + var i, val; + if (isArray(props)) { + options.props = {}; + i = props.length; + while (i--) { + val = props[i]; + if (typeof val === 'string') { + options.props[val] = null; + } else if (val.name) { + options.props[val.name] = val; + } + } + } else if (isPlainObject(props)) { + var keys = Object.keys(props); + i = keys.length; + while (i--) { + val = props[keys[i]]; + if (typeof val === 'function') { + props[keys[i]] = { type: val }; + } + } + } + } + + /** + * Guard an Array-format assets option and converted it + * into the key-value Object format. + * + * @param {Object|Array} assets + * @return {Object} + */ + + function guardArrayAssets(assets) { + if (isArray(assets)) { + var res = {}; + var i = assets.length; + var asset; + while (i--) { + asset = assets[i]; + var id = typeof asset === 'function' ? asset.options && asset.options.name || asset.id : asset.name || asset.id; + if (!id) { + 'development' !== 'production' && warn('Array-syntax assets must provide a "name" or "id" field.'); + } else { + res[id] = asset; + } + } + return res; + } + return assets; + } + + /** + * Merge two option objects into a new one. + * Core utility used in both instantiation and inheritance. + * + * @param {Object} parent + * @param {Object} child + * @param {Vue} [vm] - if vm is present, indicates this is + * an instantiation merge. + */ + + function mergeOptions(parent, child, vm) { + guardComponents(child); + guardProps(child); + if ('development' !== 'production') { + if (child.propsData && !vm) { + warn('propsData can only be used as an instantiation option.'); + } + } + var options = {}; + var key; + if (child['extends']) { + parent = typeof child['extends'] === 'function' ? mergeOptions(parent, child['extends'].options, vm) : mergeOptions(parent, child['extends'], vm); + } + if (child.mixins) { + for (var i = 0, l = child.mixins.length; i < l; i++) { + var mixin = child.mixins[i]; + var mixinOptions = mixin.prototype instanceof Vue ? mixin.options : mixin; + parent = mergeOptions(parent, mixinOptions, vm); + } + } + for (key in parent) { + mergeField(key); + } + for (key in child) { + if (!hasOwn(parent, key)) { + mergeField(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 + * @param {Boolean} warnMissing + * @return {Object|Function} + */ + + function resolveAsset(options, type, id, warnMissing) { + /* istanbul ignore if */ + if (typeof id !== 'string') { + return; + } + var assets = options[type]; + var camelizedId; + var res = assets[id] || + // camelCase ID + assets[camelizedId = camelize(id)] || + // Pascal Case ID + assets[camelizedId.charAt(0).toUpperCase() + camelizedId.slice(1)]; + if ('development' !== 'production' && warnMissing && !res) { + warn('Failed to resolve ' + type.slice(0, -1) + ': ' + id, options); + } + return res; + } + + var uid$1 = 0; + + /** + * A dep is an observable that can have multiple + * directives subscribing to it. + * + * @constructor + */ + function Dep() { + this.id = uid$1++; + this.subs = []; + } + + // the current target watcher being evaluated. + // this is globally unique because there could be only one + // watcher being evaluated at any time. + Dep.target = null; + + /** + * Add a directive subscriber. + * + * @param {Directive} sub + */ + + Dep.prototype.addSub = function (sub) { + this.subs.push(sub); + }; + + /** + * Remove a directive subscriber. + * + * @param {Directive} sub + */ + + Dep.prototype.removeSub = function (sub) { + this.subs.$remove(sub); + }; + + /** + * Add self as a dependency to the target watcher. + */ + + Dep.prototype.depend = function () { + Dep.target.addDep(this); + }; + + /** + * Notify all subscribers of a new value. + */ + + Dep.prototype.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(); + } + }; + + 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]; + def(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.dep.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 + */ + + def(arrayProto, '$set', function $set(index, val) { + if (index >= this.length) { + this.length = Number(index) + 1; + } + return this.splice(index, 1, val)[0]; + }); + + /** + * Convenience method to remove the element at given index or target element reference. + * + * @param {*} item + */ + + def(arrayProto, '$remove', function $remove(item) { + /* istanbul ignore if */ + if (!this.length) return; + var index = indexOf(this, item); + if (index > -1) { + return this.splice(index, 1); + } + }); + + var arrayKeys = Object.getOwnPropertyNames(arrayMethods); + + /** + * By default, when a reactive property is set, the new value is + * also converted to become reactive. However in certain cases, e.g. + * v-for scope alias and props, we don't want to force conversion + * because the value may be a nested value under a frozen data structure. + * + * So whenever we want to set a reactive property without forcing + * conversion on the new value, we wrap that call inside this function. + */ + + var shouldConvert = true; + + function withoutConversion(fn) { + shouldConvert = false; + fn(); + shouldConvert = true; + } + + /** + * 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 + * @constructor + */ + + function Observer(value) { + this.value = value; + this.dep = new Dep(); + def(value, '__ob__', this); + if (isArray(value)) { + var augment = hasProto ? protoAugment : copyAugment; + augment(value, arrayMethods, arrayKeys); + this.observeArray(value); + } else { + this.walk(value); + } + } + + // Instance methods + + /** + * Walk through each property and convert them into + * getter/setters. This method should only be called when + * value type is Object. + * + * @param {Object} obj + */ + + Observer.prototype.walk = function (obj) { + var keys = Object.keys(obj); + for (var i = 0, l = keys.length; i < l; i++) { + this.convert(keys[i], obj[keys[i]]); + } + }; + + /** + * Observe a list of Array items. + * + * @param {Array} items + */ + + Observer.prototype.observeArray = function (items) { + for (var i = 0, l = items.length; i < l; i++) { + 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 + */ + + Observer.prototype.convert = function (key, val) { + defineReactive(this.value, key, val); + }; + + /** + * Add an owner vm, so that when $set/$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 + */ + + Observer.prototype.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 + */ + + Observer.prototype.removeVm = function (vm) { + this.vms.$remove(vm); + }; + + // helpers + + /** + * Augment an target Object or Array by intercepting + * the prototype chain using __proto__ + * + * @param {Object|Array} target + * @param {Object} src + */ + + function protoAugment(target, src) { + /* eslint-disable no-proto */ + target.__proto__ = src; + /* eslint-enable no-proto */ + } + + /** + * Augment an target Object or Array by defining + * hidden properties. + * + * @param {Object|Array} target + * @param {Object} proto + */ + + function copyAugment(target, src, keys) { + for (var i = 0, l = keys.length; i < l; i++) { + var key = keys[i]; + def(target, key, src[key]); + } + } + + /** + * 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 + * @param {Vue} [vm] + * @return {Observer|undefined} + * @static + */ + + function observe(value, vm) { + if (!value || typeof value !== 'object') { + return; + } + var ob; + if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { + ob = value.__ob__; + } else if (shouldConvert && (isArray(value) || isPlainObject(value)) && Object.isExtensible(value) && !value._isVue) { + ob = new Observer(value); + } + if (ob && vm) { + ob.addVm(vm); + } + return ob; + } + + /** + * Define a reactive property on an Object. + * + * @param {Object} obj + * @param {String} key + * @param {*} val + */ + + function defineReactive(obj, key, val) { + var dep = new Dep(); + + var property = Object.getOwnPropertyDescriptor(obj, key); + if (property && property.configurable === false) { + return; + } + + // cater for pre-defined getter/setters + var getter = property && property.get; + var setter = property && property.set; + + var childOb = observe(val); + Object.defineProperty(obj, key, { + enumerable: true, + configurable: true, + get: function reactiveGetter() { + var value = getter ? getter.call(obj) : val; + if (Dep.target) { + dep.depend(); + if (childOb) { + childOb.dep.depend(); + } + if (isArray(value)) { + for (var e, i = 0, l = value.length; i < l; i++) { + e = value[i]; + e && e.__ob__ && e.__ob__.dep.depend(); + } + } + } + return value; + }, + set: function reactiveSetter(newVal) { + var value = getter ? getter.call(obj) : val; + if (newVal === value) { + return; + } + if (setter) { + setter.call(obj, newVal); + } else { + val = newVal; + } + childOb = observe(newVal); + dep.notify(); + } + }); + } + + + + var util = Object.freeze({ + defineReactive: defineReactive, + set: set, + del: del, + hasOwn: hasOwn, + isLiteral: isLiteral, + isReserved: isReserved, + _toString: _toString, + toNumber: toNumber, + toBoolean: toBoolean, + stripQuotes: stripQuotes, + camelize: camelize, + hyphenate: hyphenate, + classify: classify, + bind: bind, + toArray: toArray, + extend: extend, + isObject: isObject, + isPlainObject: isPlainObject, + def: def, + debounce: _debounce, + indexOf: indexOf, + cancellable: cancellable, + looseEqual: looseEqual, + isArray: isArray, + hasProto: hasProto, + inBrowser: inBrowser, + devtools: devtools, + isIE: isIE, + isIE9: isIE9, + isAndroid: isAndroid, + isIos: isIos, + iosVersionMatch: iosVersionMatch, + iosVersion: iosVersion, + hasMutationObserverBug: hasMutationObserverBug, + get transitionProp () { return transitionProp; }, + get transitionEndEvent () { return transitionEndEvent; }, + get animationProp () { return animationProp; }, + get animationEndEvent () { return animationEndEvent; }, + nextTick: nextTick, + get _Set () { return _Set; }, + query: query, + inDoc: inDoc, + getAttr: getAttr, + getBindAttr: getBindAttr, + hasBindAttr: hasBindAttr, + before: before, + after: after, + remove: remove, + prepend: prepend, + replace: replace, + on: on, + off: off, + setClass: setClass, + addClass: addClass, + removeClass: removeClass, + extractContent: extractContent, + trimNode: trimNode, + isTemplate: isTemplate, + createAnchor: createAnchor, + findRef: findRef, + mapNodeRange: mapNodeRange, + removeNodeRange: removeNodeRange, + isFragment: isFragment, + getOuterHTML: getOuterHTML, + mergeOptions: mergeOptions, + resolveAsset: resolveAsset, + checkComponentAttr: checkComponentAttr, + commonTagRE: commonTagRE, + reservedTagRE: reservedTagRE, + get warn () { return warn; } + }); + + var uid = 0; + + function initMixin (Vue) { + /** + * 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. + */ + + Vue.prototype._init = function (options) { + options = options || {}; + + this.$el = null; + this.$parent = options.parent; + this.$root = this.$parent ? this.$parent.$root : this; + this.$children = []; + this.$refs = {}; // child vm references + this.$els = {}; // element references + this._watchers = []; // all watchers as an array + this._directives = []; // all directives + + // a uid + this._uid = uid++; + + // a flag to avoid this being observed + this._isVue = true; + + // events bookkeeping + this._events = {}; // registered callbacks + this._eventsCount = {}; // for $broadcast optimization + + // fragment instance properties + this._isFragment = false; + this._fragment = // @type {DocumentFragment} + this._fragmentStart = // @type {Text|Comment} + this._fragmentEnd = null; // @type {Text|Comment} + + // lifecycle state + this._isCompiled = this._isDestroyed = this._isReady = this._isAttached = this._isBeingDestroyed = this._vForRemoving = false; + this._unlinkFn = null; + + // context: + // if this is a transcluded component, context + // will be the common parent vm of this instance + // and its host. + this._context = options._context || this.$parent; + + // scope: + // if this is inside an inline v-for, the scope + // will be the intermediate scope created for this + // repeat fragment. this is used for linking props + // and container directives. + this._scope = options._scope; + + // fragment: + // if this instance is compiled inside a Fragment, it + // needs to reigster itself as a child of that fragment + // for attach/detach to work properly. + this._frag = options._frag; + if (this._frag) { + this._frag.children.push(this); + } + + // push self into parent / transclusion host + if (this.$parent) { + this.$parent.$children.push(this); + } + + // merge options. + options = this.$options = mergeOptions(this.constructor.options, options, this); + + // set ref + this._updateRef(); + + // initialize data as empty object. + // it will be filled up in _initData(). + this._data = {}; + + // call init hook + this._callHook('init'); + + // initialize data observation and scope inheritance. + this._initState(); + + // 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); + } + }; + } + + var pathCache = new Cache(1000); + + // actions + var APPEND = 0; + var PUSH = 1; + var INC_SUB_PATH_DEPTH = 2; + var PUSH_SUB_PATH = 3; + + // states + var BEFORE_PATH = 0; + var IN_PATH = 1; + var BEFORE_IDENT = 2; + var IN_IDENT = 3; + var IN_SUB_PATH = 4; + var IN_SINGLE_QUOTE = 5; + var IN_DOUBLE_QUOTE = 6; + var AFTER_PATH = 7; + var ERROR = 8; + + var pathStateMachine = []; + + pathStateMachine[BEFORE_PATH] = { + 'ws': [BEFORE_PATH], + 'ident': [IN_IDENT, APPEND], + '[': [IN_SUB_PATH], + 'eof': [AFTER_PATH] + }; + + pathStateMachine[IN_PATH] = { + 'ws': [IN_PATH], + '.': [BEFORE_IDENT], + '[': [IN_SUB_PATH], + 'eof': [AFTER_PATH] + }; + + pathStateMachine[BEFORE_IDENT] = { + 'ws': [BEFORE_IDENT], + 'ident': [IN_IDENT, APPEND] + }; + + pathStateMachine[IN_IDENT] = { + 'ident': [IN_IDENT, APPEND], + '0': [IN_IDENT, APPEND], + 'number': [IN_IDENT, APPEND], + 'ws': [IN_PATH, PUSH], + '.': [BEFORE_IDENT, PUSH], + '[': [IN_SUB_PATH, PUSH], + 'eof': [AFTER_PATH, PUSH] + }; + + pathStateMachine[IN_SUB_PATH] = { + "'": [IN_SINGLE_QUOTE, APPEND], + '"': [IN_DOUBLE_QUOTE, APPEND], + '[': [IN_SUB_PATH, INC_SUB_PATH_DEPTH], + ']': [IN_PATH, PUSH_SUB_PATH], + 'eof': ERROR, + 'else': [IN_SUB_PATH, APPEND] + }; + + pathStateMachine[IN_SINGLE_QUOTE] = { + "'": [IN_SUB_PATH, APPEND], + 'eof': ERROR, + 'else': [IN_SINGLE_QUOTE, APPEND] + }; + + pathStateMachine[IN_DOUBLE_QUOTE] = { + '"': [IN_SUB_PATH, APPEND], + 'eof': ERROR, + 'else': [IN_DOUBLE_QUOTE, APPEND] + }; + + /** + * Determine the type of a character in a keypath. + * + * @param {Char} ch + * @return {String} type + */ + + function getPathCharType(ch) { + if (ch === undefined) { + return 'eof'; + } + + var code = ch.charCodeAt(0); + + switch (code) { + case 0x5B: // [ + case 0x5D: // ] + case 0x2E: // . + case 0x22: // " + case 0x27: // ' + case 0x30: + // 0 + return ch; + + case 0x5F: // _ + case 0x24: + // $ + return 'ident'; + + case 0x20: // Space + case 0x09: // Tab + case 0x0A: // Newline + case 0x0D: // Return + case 0xA0: // No-break space + case 0xFEFF: // Byte Order Mark + case 0x2028: // Line Separator + case 0x2029: + // Paragraph Separator + return 'ws'; + } + + // a-z, A-Z + if (code >= 0x61 && code <= 0x7A || code >= 0x41 && code <= 0x5A) { + return 'ident'; + } + + // 1-9 + if (code >= 0x31 && code <= 0x39) { + return 'number'; + } + + return 'else'; + } + + /** + * Format a subPath, return its plain form if it is + * a literal string or number. Otherwise prepend the + * dynamic indicator (*). + * + * @param {String} path + * @return {String} + */ + + function formatSubPath(path) { + var trimmed = path.trim(); + // invalid leading 0 + if (path.charAt(0) === '0' && isNaN(path)) { + return false; + } + return isLiteral(trimmed) ? stripQuotes(trimmed) : '*' + trimmed; + } + + /** + * Parse a string path into an array of segments + * + * @param {String} path + * @return {Array|undefined} + */ + + function parse(path) { + var keys = []; + var index = -1; + var mode = BEFORE_PATH; + var subPathDepth = 0; + var c, newChar, key, type, transition, action, typeMap; + + var actions = []; + + actions[PUSH] = function () { + if (key !== undefined) { + keys.push(key); + key = undefined; + } + }; + + actions[APPEND] = function () { + if (key === undefined) { + key = newChar; + } else { + key += newChar; + } + }; + + actions[INC_SUB_PATH_DEPTH] = function () { + actions[APPEND](); + subPathDepth++; + }; + + actions[PUSH_SUB_PATH] = function () { + if (subPathDepth > 0) { + subPathDepth--; + mode = IN_SUB_PATH; + actions[APPEND](); + } else { + subPathDepth = 0; + key = formatSubPath(key); + if (key === false) { + return false; + } else { + actions[PUSH](); + } + } + }; + + function maybeUnescapeQuote() { + var nextChar = path[index + 1]; + if (mode === IN_SINGLE_QUOTE && nextChar === "'" || mode === IN_DOUBLE_QUOTE && nextChar === '"') { + index++; + newChar = '\\' + nextChar; + actions[APPEND](); + return true; + } + } + + while (mode != null) { + 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]]; + if (action) { + newChar = transition[2]; + newChar = newChar === undefined ? c : newChar; + if (action() === false) { + return; + } + } + + if (mode === AFTER_PATH) { + keys.raw = path; + return keys; + } + } + } + + /** + * External parse that check for a cache hit first + * + * @param {String} path + * @return {Array|undefined} + */ + + function parsePath(path) { + var hit = pathCache.get(path); + if (!hit) { + hit = parse(path); + if (hit) { + pathCache.put(path, hit); + } + } + return hit; + } + + /** + * Get from an object from a path string + * + * @param {Object} obj + * @param {String} path + */ + + function getPath(obj, path) { + return parseExpression(path).get(obj); + } + + /** + * Warn against setting non-existent root path on a vm. + */ + + var warnNonExistent; + if ('development' !== 'production') { + warnNonExistent = function (path, vm) { + 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.', vm); + }; + } + + /** + * Set on an object from a path + * + * @param {Object} obj + * @param {String | Array} path + * @param {*} val + */ + + function setPath(obj, path, val) { + var original = obj; + if (typeof path === 'string') { + path = parse(path); + } + if (!path || !isObject(obj)) { + return false; + } + var last, key; + for (var i = 0, l = path.length; i < l; i++) { + last = obj; + key = path[i]; + if (key.charAt(0) === '*') { + key = parseExpression(key.slice(1)).get.call(original, original); + } + if (i < l - 1) { + obj = obj[key]; + if (!isObject(obj)) { + obj = {}; + if ('development' !== 'production' && last._isVue) { + warnNonExistent(path, last); + } + set(last, key, obj); + } + } else { + if (isArray(obj)) { + obj.$set(key, val); + } else if (key in obj) { + obj[key] = val; + } else { + if ('development' !== 'production' && obj._isVue) { + warnNonExistent(path, obj); + } + set(obj, key, val); + } + } + } + return true; + } + +var path = Object.freeze({ + parsePath: parsePath, + getPath: getPath, + setPath: setPath + }); + + 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,' + 'protected,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 identRE = /[^\w$\.](?:[A-Za-z_$][\w$]*)/g; + var literalValueRE$1 = /^(?:true|false|null|undefined|Infinity|NaN)$/; + + function noop() {} + + /** + * Save / Rewrite / Restore + * + * 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 + * @return {Function} + */ + + function compileGetter(exp) { + if (improperKeywordsRE.test(exp)) { + 'development' !== 'production' && warn('Avoid using reserved keywords in expression: ' + exp); + } + // 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 because the regex matches 1 extra char + body = (' ' + body).replace(identRE, rewrite).replace(restoreRE, restore); + return makeGetterFn(body); + } + + /** + * Build a getter function. Requires eval. + * + * We isolate the try/catch so it doesn't affect the + * optimization of the parse function when it is not called. + * + * @param {String} body + * @return {Function|undefined} + */ + + function makeGetterFn(body) { + try { + /* eslint-disable no-new-func */ + return new Function('scope', 'return ' + body + ';'); + /* eslint-enable no-new-func */ + } catch (e) { + if ('development' !== 'production') { + /* istanbul ignore if */ + if (e.toString().match(/unsafe-eval|CSP/)) { + warn('It seems you are using the default build of Vue.js in an environment ' + 'with Content Security Policy that prohibits unsafe-eval. ' + 'Use the CSP-compliant build instead: ' + 'http://vuejs.org/guide/installation.html#CSP-compliant-build'); + } else { + warn('Invalid expression. ' + 'Generated function body: ' + body); + } + } + return noop; + } + } + + /** + * Compile a setter function for the expression. + * + * @param {String} exp + * @return {Function|undefined} + */ + + function compileSetter(exp) { + var path = parsePath(exp); + if (path) { + return function (scope, val) { + setPath(scope, path, val); + }; + } else { + 'development' !== 'production' && warn('Invalid setter expression: ' + exp); + } + } + + /** + * Parse an expression into re-written getter/setters. + * + * @param {String} exp + * @param {Boolean} needSet + * @return {Function} + */ + + function parseExpression(exp, needSet) { + exp = exp.trim(); + // try cache + var hit = expressionCache.get(exp); + if (hit) { + if (needSet && !hit.set) { + hit.set = compileSetter(hit.exp); + } + return hit; + } + var res = { exp: exp }; + res.get = isSimplePath(exp) && exp.indexOf('[') < 0 + // optimized super simple getter + ? makeGetterFn('scope.' + exp) + // dynamic getter + : compileGetter(exp); + if (needSet) { + res.set = compileSetter(exp); + } + expressionCache.put(exp, res); + return res; + } + + /** + * Check if an expression is a simple path. + * + * @param {String} exp + * @return {Boolean} + */ + + function isSimplePath(exp) { + return pathTestRE.test(exp) && + // don't treat literal values as paths + !literalValueRE$1.test(exp) && + // Math constants e.g. Math.PI, Math.E etc. + exp.slice(0, 5) !== 'Math.'; + } + +var expression = Object.freeze({ + parseExpression: parseExpression, + isSimplePath: isSimplePath + }); + + // 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 circular = {}; + var waiting = false; + + /** + * Reset the batcher's state. + */ + + function resetBatcherState() { + queue.length = 0; + userQueue.length = 0; + has = {}; + circular = {}; + waiting = false; + } + + /** + * Flush both queues and run the watchers. + */ + + function flushBatcherQueue() { + var _again = true; + + _function: while (_again) { + _again = false; + + runBatcherQueue(queue); + runBatcherQueue(userQueue); + // user watchers triggered more watchers, + // keep flushing until it depletes + if (queue.length) { + _again = true; + continue _function; + } + // dev tool hook + /* istanbul ignore if */ + if (devtools && config.devtools) { + devtools.emit('flush'); + } + resetBatcherState(); + } + } + + /** + * Run the watchers in a single queue. + * + * @param {Array} queue + */ + + function runBatcherQueue(queue) { + // do not cache length because more watchers might be pushed + // as we run existing watchers + for (var i = 0; i < queue.length; i++) { + var watcher = queue[i]; + var id = watcher.id; + has[id] = null; + watcher.run(); + // in dev build, check and stop circular updates. + if ('development' !== 'production' && has[id] != null) { + circular[id] = (circular[id] || 0) + 1; + if (circular[id] > config._maxUpdateCount) { + warn('You may have an infinite update loop for watcher ' + 'with expression "' + watcher.expression + '"', watcher.vm); + break; + } + } + } + queue.length = 0; + } + + /** + * Push a watcher into the watcher queue. + * Jobs with duplicate IDs will be skipped unless it's + * pushed when the queue is being flushed. + * + * @param {Watcher} watcher + * properties: + * - {Number} id + * - {Function} run + */ + + function pushWatcher(watcher) { + var id = watcher.id; + if (has[id] == null) { + // push watcher into appropriate queue + var q = watcher.user ? userQueue : queue; + has[id] = q.length; + q.push(watcher); + // queue the flush + if (!waiting) { + waiting = true; + nextTick(flushBatcherQueue); + } + } + } + + var uid$2 = 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|Function} expOrFn + * @param {Function} cb + * @param {Object} options + * - {Array} filters + * - {Boolean} twoWay + * - {Boolean} deep + * - {Boolean} user + * - {Boolean} sync + * - {Boolean} lazy + * - {Function} [preProcess] + * - {Function} [postProcess] + * @constructor + */ + function Watcher(vm, expOrFn, cb, options) { + // mix in options + if (options) { + extend(this, options); + } + var isFn = typeof expOrFn === 'function'; + this.vm = vm; + vm._watchers.push(this); + this.expression = expOrFn; + this.cb = cb; + this.id = ++uid$2; // uid for batching + this.active = true; + this.dirty = this.lazy; // for lazy watchers + this.deps = []; + this.newDeps = []; + this.depIds = new _Set(); + this.newDepIds = new _Set(); + this.prevError = null; // for async error stacks + // parse expression for getter/setter + if (isFn) { + this.getter = expOrFn; + this.setter = undefined; + } else { + var res = parseExpression(expOrFn, this.twoWay); + this.getter = res.get; + this.setter = res.set; + } + this.value = this.lazy ? undefined : this.get(); + // state for avoiding false triggers for deep and Array + // watchers during vm._digest() + this.queued = this.shallow = false; + } + + /** + * Evaluate the getter, and re-collect dependencies. + */ + + Watcher.prototype.get = function () { + this.beforeGet(); + var scope = this.scope || this.vm; + var value; + try { + value = this.getter.call(scope, scope); + } catch (e) { + if ('development' !== 'production' && config.warnExpressionErrors) { + warn('Error when evaluating expression ' + '"' + this.expression + '": ' + e.toString(), this.vm); + } + } + // "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 = scope._applyFilters(value, null, this.filters, false); + } + if (this.postProcess) { + value = this.postProcess(value); + } + this.afterGet(); + return value; + }; + + /** + * Set the corresponding value with the setter. + * + * @param {*} value + */ + + Watcher.prototype.set = function (value) { + var scope = this.scope || this.vm; + if (this.filters) { + value = scope._applyFilters(value, this.value, this.filters, true); + } + try { + this.setter.call(scope, scope, value); + } catch (e) { + if ('development' !== 'production' && config.warnExpressionErrors) { + warn('Error when evaluating setter ' + '"' + this.expression + '": ' + e.toString(), this.vm); + } + } + // two-way sync for v-for alias + var forContext = scope.$forContext; + if (forContext && forContext.alias === this.expression) { + if (forContext.filters) { + 'development' !== 'production' && warn('It seems you are using two-way binding on ' + 'a v-for alias (' + this.expression + '), and the ' + 'v-for has filters. This will not work properly. ' + 'Either remove the filters or use an array of ' + 'objects and bind to object properties instead.', this.vm); + return; + } + forContext._withLock(function () { + if (scope.$key) { + // original is an object + forContext.rawValue[scope.$key] = value; + } else { + forContext.rawValue.$set(scope.$index, value); + } + }); + } + }; + + /** + * Prepare for dependency collection. + */ + + Watcher.prototype.beforeGet = function () { + Dep.target = this; + }; + + /** + * Add a dependency to this directive. + * + * @param {Dep} dep + */ + + Watcher.prototype.addDep = function (dep) { + var id = dep.id; + if (!this.newDepIds.has(id)) { + this.newDepIds.add(id); + this.newDeps.push(dep); + if (!this.depIds.has(id)) { + dep.addSub(this); + } + } + }; + + /** + * Clean up for dependency collection. + */ + + Watcher.prototype.afterGet = function () { + Dep.target = null; + var i = this.deps.length; + while (i--) { + var dep = this.deps[i]; + if (!this.newDepIds.has(dep.id)) { + dep.removeSub(this); + } + } + var tmp = this.depIds; + this.depIds = this.newDepIds; + this.newDepIds = tmp; + this.newDepIds.clear(); + tmp = this.deps; + this.deps = this.newDeps; + this.newDeps = tmp; + this.newDeps.length = 0; + }; + + /** + * Subscriber interface. + * Will be called when a dependency changes. + * + * @param {Boolean} shallow + */ + + Watcher.prototype.update = function (shallow) { + if (this.lazy) { + this.dirty = true; + } else if (this.sync || !config.async) { + this.run(); + } else { + // if queued, only overwrite shallow with non-shallow, + // but not the other way around. + this.shallow = this.queued ? shallow ? this.shallow : false : !!shallow; + this.queued = true; + // record before-push error stack in debug mode + /* istanbul ignore if */ + if ('development' !== 'production' && config.debug) { + this.prevError = new Error('[vue] async stack trace'); + } + pushWatcher(this); + } + }; + + /** + * Batcher job interface. + * Will be called by the batcher. + */ + + Watcher.prototype.run = function () { + if (this.active) { + var value = this.get(); + if (value !== this.value || + // Deep watchers and watchers on Object/Arrays should fire even + // when the value is the same, because the value may + // have mutated; but only do so if this is a + // non-shallow update (caused by a vm digest). + (isObject(value) || this.deep) && !this.shallow) { + // set new value + var oldValue = this.value; + this.value = value; + // in debug + async mode, when a watcher callbacks + // throws, we also throw the saved before-push error + // so the full cross-tick stack trace is available. + var prevError = this.prevError; + /* istanbul ignore if */ + if ('development' !== 'production' && config.debug && prevError) { + this.prevError = null; + try { + this.cb.call(this.vm, value, oldValue); + } catch (e) { + nextTick(function () { + throw prevError; + }, 0); + throw e; + } + } else { + this.cb.call(this.vm, value, oldValue); + } + } + this.queued = this.shallow = false; + } + }; + + /** + * Evaluate the value of the watcher. + * This only gets called for lazy watchers. + */ + + Watcher.prototype.evaluate = function () { + // avoid overwriting another watcher that is being + // collected. + var current = Dep.target; + this.value = this.get(); + this.dirty = false; + Dep.target = current; + }; + + /** + * Depend on all deps collected by this watcher. + */ + + Watcher.prototype.depend = function () { + var i = this.deps.length; + while (i--) { + this.deps[i].depend(); + } + }; + + /** + * Remove self from all dependencies' subcriber list. + */ + + Watcher.prototype.teardown = function () { + if (this.active) { + // remove self from vm's watcher list + // this is a somewhat expensive operation so we skip it + // if the vm is being destroyed or is performing a v-for + // re-render (the watcher list is then filtered by v-for). + if (!this.vm._isBeingDestroyed && !this.vm._vForRemoving) { + 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 {*} val + */ + + var seenObjects = new _Set(); + function traverse(val, seen) { + var i = undefined, + keys = undefined; + if (!seen) { + seen = seenObjects; + seen.clear(); + } + var isA = isArray(val); + var isO = isObject(val); + if ((isA || isO) && Object.isExtensible(val)) { + if (val.__ob__) { + var depId = val.__ob__.dep.id; + if (seen.has(depId)) { + return; + } else { + seen.add(depId); + } + } + if (isA) { + i = val.length; + while (i--) traverse(val[i], seen); + } else if (isO) { + keys = Object.keys(val); + i = keys.length; + while (i--) traverse(val[keys[i]], seen); + } + } + } + + var text$1 = { + + bind: function bind() { + this.attr = this.el.nodeType === 3 ? 'data' : 'textContent'; + }, + + update: function update(value) { + this.el[this.attr] = _toString(value); + } + }; + + var templateCache = new Cache(1000); + var idSelectorCache = new Cache(1000); + + var map = { + efault: [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, '', '']; + + /** + * Check if a node is a supported template node with a + * DocumentFragment content. + * + * @param {Node} node + * @return {Boolean} + */ + + function isRealTemplate(node) { + return isTemplate(node) && isFragment(node.content); + } + + var tagRE$1 = /<([\w:-]+)/; + var entityRE = /&#?\w+?;/; + var commentRE = /