diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index f649df9aecf..a167e76dbd1 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -22,7 +22,7 @@ Hi! I’m really excited that you are interested in contributing to Vue.js. Befo - It is **required** that you clearly describe the steps necessary to reproduce the issue you are running into. Issues with no clear repro steps will not be triaged. If an issue labeled "need repro" receives no further input from the issue author for more than 5 days, it will be closed. -- It is recommended that you make a JSFiddle/JSBin/Codepen to demonstrate your issue. You could start with [this template](http://jsfiddle.net/5sH6A/) that already includes the latest version of Vue. +- It is recommended that you make a JSFiddle/JSBin/Codepen to demonstrate your issue. You could start with [this template](http://jsfiddle.net/df4Lnuw6/) that already includes the latest version of Vue. - For bugs that involves build setups, you can create a reproduction repository with steps in the README. @@ -45,6 +45,7 @@ Hi! I’m really excited that you are interested in contributing to Vue.js. Befo - Provide convincing reason to add this feature. Ideally you should open a suggestion issue first and have it greenlighted before working on it. - If fixing a bug: + - If you are resolving a special issue, add `(fix #xxxx[,#xxx])` (#xxxx is the issue id) in your PR title for a better release log, e.g. `update entities encoding/decoding (fix #3899)`. - Provide detailed description of the bug in the PR. Live demo preferred. - Add appropriate test coverage if applicable. diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index c12caedd647..8026bb63f0f 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -35,10 +35,11 @@ Remove the template from below and provide thoughtful commentary *and code sampl ### Vue.js version -2.0.0-rc.1 +2.0.2 ### Reproduction Link + ### Steps to reproduce diff --git a/build/config.js b/build/config.js index ffbd44fec0f..27d422bcfb5 100644 --- a/build/config.js +++ b/build/config.js @@ -30,7 +30,7 @@ const builds = { env: 'production', banner }, - // Runtime+compiler standalone developement build. + // Runtime+compiler standalone development build. 'web-standalone-dev': { entry: path.resolve(__dirname, '../src/entries/web-runtime-with-compiler.js'), dest: path.resolve(__dirname, '../dist/vue.js'), @@ -38,7 +38,7 @@ const builds = { env: 'development', banner, alias: { - entities: './entity-decoder' + he: './entity-decoder' } }, // Runtime+compiler standalone production build. @@ -49,7 +49,7 @@ const builds = { env: 'production', banner, alias: { - entities: './entity-decoder' + he: './entity-decoder' } }, // Web compiler (CommonJS). @@ -57,14 +57,14 @@ const builds = { entry: path.resolve(__dirname, '../src/entries/web-compiler.js'), dest: path.resolve(__dirname, '../packages/vue-template-compiler/build.js'), format: 'cjs', - external: ['entities', 'de-indent'] + external: ['he', 'de-indent'] }, // Web server renderer (CommonJS). 'web-server-renderer': { entry: path.resolve(__dirname, '../src/entries/web-server-renderer.js'), dest: path.resolve(__dirname, '../packages/vue-server-renderer/build.js'), format: 'cjs', - external: ['stream', 'module', 'vm', 'entities', 'de-indent'] + external: ['stream', 'module', 'vm', 'he', 'de-indent'] } } diff --git a/dist/vue.common.js b/dist/vue.common.js index 9d3f3710827..07b55fec6c4 100644 --- a/dist/vue.common.js +++ b/dist/vue.common.js @@ -1,5 +1,5 @@ /*! - * Vue.js v2.0.2 + * Vue.js v2.0.3 * (c) 2014-2016 Evan You * Released under the MIT License. */ @@ -1481,85 +1481,25 @@ function cloneVNodes (vnodes) { /* */ -function normalizeChildren ( - children, - ns, - nestedIndex -) { - if (isPrimitive(children)) { - return [createTextVNode(children)] - } - if (Array.isArray(children)) { - var res = []; - for (var i = 0, l = children.length; i < l; i++) { - var c = children[i]; - var last = res[res.length - 1]; - // nested - if (Array.isArray(c)) { - res.push.apply(res, normalizeChildren(c, ns, i)); - } else if (isPrimitive(c)) { - if (last && last.text) { - last.text += String(c); - } else if (c !== '') { - // convert primitive to vnode - res.push(createTextVNode(c)); - } - } else if (c instanceof VNode) { - if (c.text && last && last.text) { - last.text += c.text; - } else { - // inherit parent namespace - if (ns) { - applyNS(c, ns); - } - // default key for nested array children (likely generated by v-for) - if (c.tag && c.key == null && nestedIndex != null) { - c.key = "__vlist_" + nestedIndex + "_" + i + "__"; - } - res.push(c); - } - } - } - return res - } -} - -function createTextVNode (val) { - return new VNode(undefined, undefined, undefined, String(val)) -} - -function applyNS (vnode, ns) { - if (vnode.tag && !vnode.ns) { - vnode.ns = ns; - if (vnode.children) { - for (var i = 0, l = vnode.children.length; i < l; i++) { - applyNS(vnode.children[i], ns); - } - } - } -} - -function getFirstComponentChild (children) { - return children && children.filter(function (c) { return c && c.componentOptions; })[0] -} - -function mergeVNodeHook (def$$1, hookKey, hook, key) { +function mergeVNodeHook (def, hookKey, hook, key) { key = key + hookKey; - var injectedHash = def$$1.__injected || (def$$1.__injected = {}); + var injectedHash = def.__injected || (def.__injected = {}); if (!injectedHash[key]) { injectedHash[key] = true; - var oldHook = def$$1[hookKey]; + var oldHook = def[hookKey]; if (oldHook) { - def$$1[hookKey] = function () { + def[hookKey] = function () { oldHook.apply(this, arguments); hook.apply(this, arguments); }; } else { - def$$1[hookKey] = hook; + def[hookKey] = hook; } } } +/* */ + function updateListeners ( on, oldOn, @@ -1629,6 +1569,72 @@ function fnInvoker (o) { /* */ +function normalizeChildren ( + children, + ns, + nestedIndex +) { + if (isPrimitive(children)) { + return [createTextVNode(children)] + } + if (Array.isArray(children)) { + var res = []; + for (var i = 0, l = children.length; i < l; i++) { + var c = children[i]; + var last = res[res.length - 1]; + // nested + if (Array.isArray(c)) { + res.push.apply(res, normalizeChildren(c, ns, ((nestedIndex || '') + "_" + i))); + } else if (isPrimitive(c)) { + if (last && last.text) { + last.text += String(c); + } else if (c !== '') { + // convert primitive to vnode + res.push(createTextVNode(c)); + } + } else if (c instanceof VNode) { + if (c.text && last && last.text) { + last.text += c.text; + } else { + // inherit parent namespace + if (ns) { + applyNS(c, ns); + } + // default key for nested array children (likely generated by v-for) + if (c.tag && c.key == null && nestedIndex != null) { + c.key = "__vlist" + nestedIndex + "_" + i + "__"; + } + res.push(c); + } + } + } + return res + } +} + +function createTextVNode (val) { + return new VNode(undefined, undefined, undefined, String(val)) +} + +function applyNS (vnode, ns) { + if (vnode.tag && !vnode.ns) { + vnode.ns = ns; + if (vnode.children) { + for (var i = 0, l = vnode.children.length; i < l; i++) { + applyNS(vnode.children[i], ns); + } + } + } +} + +/* */ + +function getFirstComponentChild (children) { + return children && children.filter(function (c) { return c && c.componentOptions; })[0] +} + +/* */ + var activeInstance = null; function initLifecycle (vm) { @@ -1810,6 +1816,8 @@ function lifecycleMixin (Vue) { if (vm.$el) { vm.$el.__vue__ = null; } + // invoke destroy hooks on current rendered tree + vm.__patch__(vm._vnode, null); }; } @@ -1930,9 +1938,11 @@ function createFunctionalComponent ( slots: function () { return resolveSlots(children, context); } } ); - vnode.functionalContext = context; - if (data.slot) { - (vnode.data || (vnode.data = {})).slot = data.slot; + if (vnode instanceof VNode) { + vnode.functionalContext = context; + if (data.slot) { + (vnode.data || (vnode.data = {})).slot = data.slot; + } } return vnode } @@ -3370,7 +3380,7 @@ Object.defineProperty(Vue$2.prototype, '$isServer', { get: function () { return config._isServer; } }); -Vue$2.version = '2.0.2'; +Vue$2.version = '2.0.3'; /* */ @@ -3928,12 +3938,6 @@ function createPatchFunction (backend) { if (isDef(i = data.hook) && isDef(i = i.destroy)) { i(vnode); } for (i = 0; i < cbs.destroy.length; ++i) { cbs.destroy[i](vnode); } } - if (isDef(i = vnode.child) && ( - !data.keepAlive || - vnode.context._isBeingDestroyed - )) { - invokeDestroyHook(i._vnode); - } if (isDef(i = vnode.children)) { for (j = 0; j < vnode.children.length; ++j) { invokeDestroyHook(vnode.children[j]); @@ -4185,6 +4189,11 @@ function createPatchFunction (backend) { } return function patch (oldVnode, vnode, hydrating, removeOnly) { + if (!vnode) { + if (oldVnode) { invokeDestroyHook(oldVnode); } + return + } + var elm, parent; var isInitialPatch = false; var insertedVnodeQueue = []; @@ -4342,23 +4351,17 @@ function normalizeDirectives$1 ( var i, dir; for (i = 0; i < dirs.length; i++) { dir = dirs[i]; - res[getRawDirName(dir)] = dir; if (!dir.modifiers) { dir.modifiers = emptyModifiers; } + res[getRawDirName(dir)] = dir; dir.def = resolveAsset(vm.$options, 'directives', dir.name, true); } return res } function getRawDirName (dir) { - return dir.rawName || ( - dir.name + ( - dir.modifiers - ? '.' + Object.keys(dir.modifiers).join('.') - : '' - ) - ) + return dir.rawName || ((dir.name) + "." + (Object.keys(dir.modifiers || {}).join('.'))) } function callHook$1 (dir, hook, vnode, oldVnode) { @@ -5098,7 +5101,10 @@ var model = { if (isIE || isEdge) { setTimeout(cb, 0); } - } else if (vnode.tag === 'textarea' || el.type === 'text') { + } else if ( + (vnode.tag === 'textarea' || el.type === 'text') && + !binding.modifiers.lazy + ) { if (!isAndroid) { el.addEventListener('compositionstart', onCompositionStart); el.addEventListener('compositionend', onCompositionEnd); @@ -5118,7 +5124,7 @@ var model = { // option in the DOM. var needReset = el.multiple ? binding.value.some(function (v) { return hasNoMatchingOption(v, el.options); }) - : hasNoMatchingOption(binding.value, el.options); + : binding.value !== binding.oldValue && hasNoMatchingOption(binding.value, el.options); if (needReset) { trigger(el, 'change'); } diff --git a/dist/vue.js b/dist/vue.js index 51ba21370b1..ea15bfac416 100644 --- a/dist/vue.js +++ b/dist/vue.js @@ -1,5 +1,5 @@ /*! - * Vue.js v2.0.2 + * Vue.js v2.0.3 * (c) 2014-2016 Evan You * Released under the MIT License. */ @@ -1483,85 +1483,25 @@ function cloneVNodes (vnodes) { /* */ -function normalizeChildren ( - children, - ns, - nestedIndex -) { - if (isPrimitive(children)) { - return [createTextVNode(children)] - } - if (Array.isArray(children)) { - var res = []; - for (var i = 0, l = children.length; i < l; i++) { - var c = children[i]; - var last = res[res.length - 1]; - // nested - if (Array.isArray(c)) { - res.push.apply(res, normalizeChildren(c, ns, i)); - } else if (isPrimitive(c)) { - if (last && last.text) { - last.text += String(c); - } else if (c !== '') { - // convert primitive to vnode - res.push(createTextVNode(c)); - } - } else if (c instanceof VNode) { - if (c.text && last && last.text) { - last.text += c.text; - } else { - // inherit parent namespace - if (ns) { - applyNS(c, ns); - } - // default key for nested array children (likely generated by v-for) - if (c.tag && c.key == null && nestedIndex != null) { - c.key = "__vlist_" + nestedIndex + "_" + i + "__"; - } - res.push(c); - } - } - } - return res - } -} - -function createTextVNode (val) { - return new VNode(undefined, undefined, undefined, String(val)) -} - -function applyNS (vnode, ns) { - if (vnode.tag && !vnode.ns) { - vnode.ns = ns; - if (vnode.children) { - for (var i = 0, l = vnode.children.length; i < l; i++) { - applyNS(vnode.children[i], ns); - } - } - } -} - -function getFirstComponentChild (children) { - return children && children.filter(function (c) { return c && c.componentOptions; })[0] -} - -function mergeVNodeHook (def$$1, hookKey, hook, key) { +function mergeVNodeHook (def, hookKey, hook, key) { key = key + hookKey; - var injectedHash = def$$1.__injected || (def$$1.__injected = {}); + var injectedHash = def.__injected || (def.__injected = {}); if (!injectedHash[key]) { injectedHash[key] = true; - var oldHook = def$$1[hookKey]; + var oldHook = def[hookKey]; if (oldHook) { - def$$1[hookKey] = function () { + def[hookKey] = function () { oldHook.apply(this, arguments); hook.apply(this, arguments); }; } else { - def$$1[hookKey] = hook; + def[hookKey] = hook; } } } +/* */ + function updateListeners ( on, oldOn, @@ -1631,6 +1571,72 @@ function fnInvoker (o) { /* */ +function normalizeChildren ( + children, + ns, + nestedIndex +) { + if (isPrimitive(children)) { + return [createTextVNode(children)] + } + if (Array.isArray(children)) { + var res = []; + for (var i = 0, l = children.length; i < l; i++) { + var c = children[i]; + var last = res[res.length - 1]; + // nested + if (Array.isArray(c)) { + res.push.apply(res, normalizeChildren(c, ns, ((nestedIndex || '') + "_" + i))); + } else if (isPrimitive(c)) { + if (last && last.text) { + last.text += String(c); + } else if (c !== '') { + // convert primitive to vnode + res.push(createTextVNode(c)); + } + } else if (c instanceof VNode) { + if (c.text && last && last.text) { + last.text += c.text; + } else { + // inherit parent namespace + if (ns) { + applyNS(c, ns); + } + // default key for nested array children (likely generated by v-for) + if (c.tag && c.key == null && nestedIndex != null) { + c.key = "__vlist" + nestedIndex + "_" + i + "__"; + } + res.push(c); + } + } + } + return res + } +} + +function createTextVNode (val) { + return new VNode(undefined, undefined, undefined, String(val)) +} + +function applyNS (vnode, ns) { + if (vnode.tag && !vnode.ns) { + vnode.ns = ns; + if (vnode.children) { + for (var i = 0, l = vnode.children.length; i < l; i++) { + applyNS(vnode.children[i], ns); + } + } + } +} + +/* */ + +function getFirstComponentChild (children) { + return children && children.filter(function (c) { return c && c.componentOptions; })[0] +} + +/* */ + var activeInstance = null; function initLifecycle (vm) { @@ -1812,6 +1818,8 @@ function lifecycleMixin (Vue) { if (vm.$el) { vm.$el.__vue__ = null; } + // invoke destroy hooks on current rendered tree + vm.__patch__(vm._vnode, null); }; } @@ -1932,9 +1940,11 @@ function createFunctionalComponent ( slots: function () { return resolveSlots(children, context); } } ); - vnode.functionalContext = context; - if (data.slot) { - (vnode.data || (vnode.data = {})).slot = data.slot; + if (vnode instanceof VNode) { + vnode.functionalContext = context; + if (data.slot) { + (vnode.data || (vnode.data = {})).slot = data.slot; + } } return vnode } @@ -3370,7 +3380,7 @@ Object.defineProperty(Vue$3.prototype, '$isServer', { get: function () { return config._isServer; } }); -Vue$3.version = '2.0.2'; +Vue$3.version = '2.0.3'; /* */ @@ -3928,12 +3938,6 @@ function createPatchFunction (backend) { if (isDef(i = data.hook) && isDef(i = i.destroy)) { i(vnode); } for (i = 0; i < cbs.destroy.length; ++i) { cbs.destroy[i](vnode); } } - if (isDef(i = vnode.child) && ( - !data.keepAlive || - vnode.context._isBeingDestroyed - )) { - invokeDestroyHook(i._vnode); - } if (isDef(i = vnode.children)) { for (j = 0; j < vnode.children.length; ++j) { invokeDestroyHook(vnode.children[j]); @@ -4185,6 +4189,11 @@ function createPatchFunction (backend) { } return function patch (oldVnode, vnode, hydrating, removeOnly) { + if (!vnode) { + if (oldVnode) { invokeDestroyHook(oldVnode); } + return + } + var elm, parent; var isInitialPatch = false; var insertedVnodeQueue = []; @@ -4342,23 +4351,17 @@ function normalizeDirectives$1 ( var i, dir; for (i = 0; i < dirs.length; i++) { dir = dirs[i]; - res[getRawDirName(dir)] = dir; if (!dir.modifiers) { dir.modifiers = emptyModifiers; } + res[getRawDirName(dir)] = dir; dir.def = resolveAsset(vm.$options, 'directives', dir.name, true); } return res } function getRawDirName (dir) { - return dir.rawName || ( - dir.name + ( - dir.modifiers - ? '.' + Object.keys(dir.modifiers).join('.') - : '' - ) - ) + return dir.rawName || ((dir.name) + "." + (Object.keys(dir.modifiers || {}).join('.'))) } function callHook$1 (dir, hook, vnode, oldVnode) { @@ -5098,7 +5101,10 @@ var model = { if (isIE || isEdge) { setTimeout(cb, 0); } - } else if (vnode.tag === 'textarea' || el.type === 'text') { + } else if ( + (vnode.tag === 'textarea' || el.type === 'text') && + !binding.modifiers.lazy + ) { if (!isAndroid) { el.addEventListener('compositionstart', onCompositionStart); el.addEventListener('compositionend', onCompositionEnd); @@ -5118,7 +5124,7 @@ var model = { // option in the DOM. var needReset = el.multiple ? binding.value.some(function (v) { return hasNoMatchingOption(v, el.options); }) - : hasNoMatchingOption(binding.value, el.options); + : binding.value !== binding.oldValue && hasNoMatchingOption(binding.value, el.options); if (needReset) { trigger(el, 'change'); } @@ -5613,13 +5619,6 @@ function shouldDecode (content, encoded) { return div.innerHTML.indexOf(encoded) > 0 } -// According to -// https://w3c.github.io/DOM-Parsing/#dfn-serializing-an-attribute-value -// when serializing innerHTML, <, >, ", & should be encoded as entities. -// However, only some browsers, e.g. PhantomJS, encodes < and >. -// this causes problems with the in-browser parser. -var shouldDecodeTags = inBrowser ? shouldDecode('>', '>') : false; - // #3663 // IE encodes newlines inside attribute values while other browsers don't var shouldDecodeNewlines = inBrowser ? shouldDecode('\n', ' ') : false; @@ -5628,7 +5627,7 @@ var shouldDecodeNewlines = inBrowser ? shouldDecode('\n', ' ') : false; var decoder = document.createElement('div'); -function decodeHTML (html) { +function decode (html) { decoder.innerHTML = html; return decoder.textContent } @@ -5686,21 +5685,21 @@ var nlRE = / /g; var ampRE = /&/g; var quoteRE = /"/g; -function decodeAttr (value, shouldDecodeTags, shouldDecodeNewlines) { - if (shouldDecodeTags) { - value = value.replace(ltRE, '<').replace(gtRE, '>'); - } +function decodeAttr (value, shouldDecodeNewlines) { if (shouldDecodeNewlines) { value = value.replace(nlRE, '\n'); } - return value.replace(ampRE, '&').replace(quoteRE, '"') + return value + .replace(ltRE, '<') + .replace(gtRE, '>') + .replace(ampRE, '&') + .replace(quoteRE, '"') } function parseHTML (html, options) { var stack = []; var expectHTML = options.expectHTML; var isUnaryTag$$1 = options.isUnaryTag || no; - var isFromDOM = options.isFromDOM; var index = 0; var last, lastTag; while (html) { @@ -5850,11 +5849,10 @@ function parseHTML (html, options) { var value = args[3] || args[4] || args[5] || ''; attrs[i] = { name: args[1], - value: isFromDOM ? decodeAttr( + value: decodeAttr( value, - options.shouldDecodeTags, options.shouldDecodeNewlines - ) : value + ) }; } @@ -6139,7 +6137,7 @@ var argRE = /:(.*)$/; var modifierRE = /\.[^\.]+/g; var specialNewlineRE = /\u2028|\u2029/g; -var decodeHTMLCached = cached(decodeHTML); +var decodeHTMLCached = cached(decode); // configurable state var warn$1; @@ -6176,8 +6174,6 @@ function parse ( parseHTML(template, { expectHTML: options.expectHTML, isUnaryTag: options.isUnaryTag, - isFromDOM: options.isFromDOM, - shouldDecodeTags: options.shouldDecodeTags, shouldDecodeNewlines: options.shouldDecodeNewlines, start: function start (tag, attrs, unary) { // check namespace. @@ -6194,7 +6190,7 @@ function parse ( type: 1, tag: tag, attrsList: attrs, - attrsMap: makeAttrsMap(attrs), + attrsMap: makeAttrsMap(attrs, options.isIE), parent: currentParent, children: [] }; @@ -6544,10 +6540,10 @@ function parseModifiers (name) { } } -function makeAttrsMap (attrs) { +function makeAttrsMap (attrs, isIE) { var map = {}; for (var i = 0, l = attrs.length; i < l; i++) { - if ("development" !== 'production' && map[attrs[i].name]) { + if ("development" !== 'production' && map[attrs[i].name] && !isIE) { warn$1('duplicate attribute: ' + attrs[i].name); } map[attrs[i].name] = attrs[i].value; @@ -6661,7 +6657,7 @@ function markStaticRoots (node, isInFor) { } if (node.children) { for (var i = 0, l = node.children.length; i < l; i++) { - markStaticRoots(node.children[i], !!node.for); + markStaticRoots(node.children[i], isInFor || !!node.for); } } } @@ -6679,10 +6675,24 @@ function isStatic (node) { !node.if && !node.for && // not v-if or v-for or v-else !isBuiltInTag(node.tag) && // not a built-in isPlatformReservedTag(node.tag) && // not a component + !isDirectChildOfTemplateFor(node) && Object.keys(node).every(isStaticKey) )) } +function isDirectChildOfTemplateFor (node) { + while (node.parent) { + node = node.parent; + if (node.tag !== 'template') { + return false + } + if (node.for) { + return true + } + } + return false +} + /* */ var simplePathRE = /^\s*[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\]|\[\d+\]|\[[A-Za-z_$][\w$]*\])*\s*$/; @@ -6988,7 +6998,7 @@ function genSlot (el) { } function genComponent (el) { - var children = genChildren(el); + var children = el.inlineTemplate ? null : genChildren(el); return ("_h(" + (el.component) + "," + (genData(el)) + (children ? ("," + children) : '') + ")") } @@ -7185,14 +7195,16 @@ function model$1 ( } } if (tag === 'select') { - return genSelect(el, value) + genSelect(el, value); } else if (tag === 'input' && type === 'checkbox') { genCheckboxModel(el, value); } else if (tag === 'input' && type === 'radio') { genRadioModel(el, value); } else { - return genDefaultModel(el, value, modifiers) + genDefaultModel(el, value, modifiers); } + // ensure runtime directive metadata + return true } function genCheckboxModel (el, value) { @@ -7291,10 +7303,6 @@ function genDefaultModel ( } addProp(el, 'value', isNative ? ("_s(" + value + ")") : ("(" + value + ")")); addHandler(el, event, code, null, true); - if (needCompositionGuard) { - // need runtime directive code to help with composition events - return true - } } function genSelect (el, value) { @@ -7306,8 +7314,6 @@ function genSelect (el, value) { ".map(function(o){return \"_value\" in o ? o._value : o.value})" + (el.attrsMap.multiple == null ? '[0]' : ''); addHandler(el, 'change', code, null, true); - // need runtime to help with possible dynamically generated options - return true } function checkOptionWarning (option) { @@ -7457,15 +7463,12 @@ Vue$3.prototype.$mount = function ( // resolve template/el and convert to render function if (!options.render) { var template = options.template; - var isFromDOM = false; if (template) { if (typeof template === 'string') { if (template.charAt(0) === '#') { - isFromDOM = true; template = idToTemplate(template); } } else if (template.nodeType) { - isFromDOM = true; template = template.innerHTML; } else { { @@ -7474,14 +7477,11 @@ Vue$3.prototype.$mount = function ( return this } } else if (el) { - isFromDOM = true; template = getOuterHTML(el); } if (template) { var ref = compileToFunctions(template, { warn: warn, - isFromDOM: isFromDOM, - shouldDecodeTags: shouldDecodeTags, shouldDecodeNewlines: shouldDecodeNewlines, delimiters: options.delimiters }, this); diff --git a/dist/vue.min.js b/dist/vue.min.js index a1c31957bae..f86786dd454 100644 --- a/dist/vue.min.js +++ b/dist/vue.min.js @@ -1,7 +1,7 @@ /*! - * Vue.js v2.0.2 + * Vue.js v2.0.3 * (c) 2014-2016 Evan You * Released under the MIT License. */ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.Vue=t()}(this,function(){"use strict";function e(e){return null==e?"":"object"==typeof e?JSON.stringify(e,null,2):String(e)}function t(e){var t=parseFloat(e,10);return t||0===t?t:e}function n(e,t){for(var n=Object.create(null),r=e.split(","),i=0;i-1)return e.splice(n,1)}}function i(e,t){return yr.call(e,t)}function o(e){return"string"==typeof e||"number"==typeof e}function a(e){var t=Object.create(null);return function(n){var r=t[n];return r||(t[n]=e(n))}}function s(e,t){function n(n){var r=arguments.length;return r?r>1?e.apply(t,arguments):e.call(t,n):e.call(t)}return n._length=e.length,n}function c(e,t){t=t||0;for(var n=e.length-t,r=new Array(n);n--;)r[n]=e[n+t];return r}function u(e,t){for(var n in t)e[n]=t[n];return e}function l(e){return null!==e&&"object"==typeof e}function f(e){return xr.call(e)===kr}function d(e){for(var t={},n=0;n=0&&Ur[n].id>e.id;)n--;Ur.splice(Math.max(n,qr)+1,0,e)}else Ur.push(e);Vr||(Vr=!0,Ir(x))}}function A(e,t){var n,r;t||(t=Zr,t.clear());var i=Array.isArray(e),o=l(e);if((i||o)&&Object.isExtensible(e)){if(e.__ob__){var a=e.__ob__.dep.id;if(t.has(a))return;t.add(a)}if(i)for(n=e.length;n--;)A(e[n],t);else if(o)for(r=Object.keys(e),n=r.length;n--;)A(e[r[n]],t)}}function O(e,t){e.__proto__=t}function T(e,t,n){for(var r=0,i=n.length;r1?c(n):n;for(var r=c(arguments,1),i=0,o=n.length;i-1?ji[e]=t.constructor===window.HTMLUnknownElement||t.constructor===window.HTMLElement:ji[e]=/HTMLUnknownElement/.test(t.toString())}function We(e){if("string"==typeof e){if(e=document.querySelector(e),!e)return document.createElement("div")}return e}function Ze(e,t){var n=document.createElement(e);return"select"!==e?n:(t.data&&t.data.attrs&&"multiple"in t.data.attrs&&n.setAttribute("multiple","multiple"),n)}function Ge(e,t){return document.createElementNS(Ci[e],t)}function Ye(e){return document.createTextNode(e)}function Qe(e){return document.createComment(e)}function Xe(e,t,n){e.insertBefore(t,n)}function et(e,t){e.removeChild(t)}function tt(e,t){e.appendChild(t)}function nt(e){return e.parentNode}function rt(e){return e.nextSibling}function it(e){return e.tagName}function ot(e,t){e.textContent=t}function at(e){return e.childNodes}function st(e,t,n){e.setAttribute(t,n)}function ct(e,t){var n=e.data.ref;if(n){var i=e.context,o=e.child||e.elm,a=i.$refs;t?Array.isArray(a[n])?r(a[n],o):a[n]===o&&(a[n]=void 0):e.data.refInFor?Array.isArray(a[n])?a[n].push(o):a[n]=[o]:a[n]=o}}function ut(e){return null==e}function lt(e){return null!=e}function ft(e,t){return e.key===t.key&&e.tag===t.tag&&e.isComment===t.isComment&&!e.data==!t.data}function dt(e,t,n){var r,i,o={};for(r=t;r<=n;++r)i=e[r].key,lt(i)&&(o[i]=r);return o}function pt(e){function t(e){return new ni(C.tagName(e).toLowerCase(),{},[],void 0,e)}function n(e,t){function n(){0===--n.listeners&&r(e)}return n.listeners=t,n}function r(e){var t=C.parentNode(e);C.removeChild(t,e)}function i(e,t,n){var r,i=e.data;if(e.isRootInsert=!n,lt(i)&&(lt(r=i.hook)&<(r=r.init)&&r(e),lt(r=e.child)))return u(e,t),e.elm;var o=e.children,s=e.tag;return lt(s)?(e.elm=e.ns?C.createElementNS(e.ns,s):C.createElement(s,e),l(e),a(e,o,t),lt(i)&&c(e,t)):e.isComment?e.elm=C.createComment(e.text):e.elm=C.createTextNode(e.text),e.elm}function a(e,t,n){if(Array.isArray(t))for(var r=0;rv?(u=ut(n[y+1])?null:n[y+1].elm,f(e,u,n,d,y,r)):d>y&&p(e,t,l,v)}function m(e,t,n,r){if(e!==t){if(t.isStatic&&e.isStatic&&t.key===e.key&&t.isCloned)return void(t.elm=e.elm);var i,o=t.data,a=lt(o);a&<(i=o.hook)&<(i=i.prepatch)&&i(e,t);var c=t.elm=e.elm,u=e.children,l=t.children;if(a&&s(t)){for(i=0;i<$.update.length;++i)$.update[i](e,t);lt(i=o.hook)&<(i=i.update)&&i(e,t)}ut(t.text)?lt(u)&<(l)?u!==l&&h(c,u,l,n,r):lt(l)?(lt(e.text)&&C.setTextContent(c,""),f(c,null,l,0,l.length-1,n)):lt(u)?p(c,u,0,u.length-1):lt(e.text)&&C.setTextContent(c,""):e.text!==t.text&&C.setTextContent(c,t.text),a&<(i=o.hook)&<(i=i.postpatch)&&i(e,t)}}function g(e,t,n){if(n&&e.parent)e.parent.data.pendingInsert=t;else for(var r=0;r-1?t.split(/\s+/).forEach(function(t){return e.classList.add(t)}):e.classList.add(t);else{var n=" "+e.getAttribute("class")+" ";n.indexOf(" "+t+" ")<0&&e.setAttribute("class",(n+t).trim())}}function kt(e,t){if(e.classList)t.indexOf(" ")>-1?t.split(/\s+/).forEach(function(t){return e.classList.remove(t)}):e.classList.remove(t);else{for(var n=" "+e.getAttribute("class")+" ",r=" "+t+" ";n.indexOf(r)>=0;)n=n.replace(r," ");e.setAttribute("class",n.trim())}}function At(e){Xi(function(){Xi(e)})}function Ot(e,t){(e._transitionClasses||(e._transitionClasses=[])).push(t),xt(e,t)}function Tt(e,t){e._transitionClasses&&r(e._transitionClasses,t),kt(e,t)}function St(e,t,n){var r=Et(e,t),i=r.type,o=r.timeout,a=r.propCount;if(!i)return n();var s=i===Ki?Gi:Qi,c=0,u=function(){e.removeEventListener(s,l),n()},l=function(t){t.target===e&&++c>=a&&u()};setTimeout(function(){c0&&(n=Ki,l=a,f=o.length):t===Wi?u>0&&(n=Wi,l=u,f=c.length):(l=Math.max(a,u),n=l>0?a>u?Ki:Wi:null,f=n?n===Ki?o.length:c.length:0);var d=n===Ki&&eo.test(r[Zi+"Property"]);return{type:n,timeout:l,propCount:f,hasTransform:d}}function jt(e,t){return Math.max.apply(null,t.map(function(t,n){return Lt(t)+Lt(e[n])}))}function Lt(e){return 1e3*Number(e.slice(0,-1))}function Nt(e){var t=e.elm;t._leaveCb&&(t._leaveCb.cancelled=!0,t._leaveCb());var n=Mt(e.data.transition);if(n&&!t._enterCb&&1===t.nodeType){var r=n.css,i=n.type,o=n.enterClass,a=n.enterActiveClass,s=n.appearClass,c=n.appearActiveClass,u=n.beforeEnter,l=n.enter,f=n.afterEnter,d=n.enterCancelled,p=n.beforeAppear,v=n.appear,h=n.afterAppear,m=n.appearCancelled,g=ii.$vnode,y=g&&g.parent?g.parent.context:ii,_=!y._isMounted||!e.isRootInsert;if(!_||v||""===v){var b=_?s:o,$=_?c:a,w=_?p||u:u,C=_&&"function"==typeof v?v:l,x=_?h||f:f,k=_?m||d:d,A=r!==!1&&!Nr,O=C&&(C._length||C.length)>1,T=t._enterCb=Pt(function(){A&&Tt(t,$),T.cancelled?(A&&Tt(t,b),k&&k(t)):x&&x(t),t._enterCb=null});e.data.show||G(e.data.hook||(e.data.hook={}),"insert",function(){var n=t.parentNode,r=n&&n._pending&&n._pending[e.key];r&&r.tag===e.tag&&r.elm._leaveCb&&r.elm._leaveCb(),C&&C(t,T)},"transition-insert"),w&&w(t),A&&(Ot(t,b),Ot(t,$),At(function(){Tt(t,b),T.cancelled||O||St(t,i,T)})),e.data.show&&C&&C(t,T),A||O||T()}}}function Dt(e,t){function n(){m.cancelled||(e.data.show||((r.parentNode._pending||(r.parentNode._pending={}))[e.key]=e),u&&u(r),v&&(Ot(r,s),Ot(r,c),At(function(){Tt(r,s),m.cancelled||h||St(r,a,m)})),l&&l(r,m),v||h||m())}var r=e.elm;r._enterCb&&(r._enterCb.cancelled=!0,r._enterCb());var i=Mt(e.data.transition);if(!i)return t();if(!r._leaveCb&&1===r.nodeType){var o=i.css,a=i.type,s=i.leaveClass,c=i.leaveActiveClass,u=i.beforeLeave,l=i.leave,f=i.afterLeave,d=i.leaveCancelled,p=i.delayLeave,v=o!==!1&&!Nr,h=l&&(l._length||l.length)>1,m=r._leaveCb=Pt(function(){r.parentNode&&r.parentNode._pending&&(r.parentNode._pending[e.key]=null),v&&Tt(r,c),m.cancelled?(v&&Tt(r,s),d&&d(r)):(t(),f&&f(r)),r._leaveCb=null});p?p(n):n()}}function Mt(e){if(e){if("object"==typeof e){var t={};return e.css!==!1&&u(t,to(e.name||"v")),u(t,e),t}return"string"==typeof e?to(e):void 0}}function Pt(e){var t=!1;return function(){t||(t=!0,e())}}function Rt(e,t,n){var r=t.value,i=e.multiple;if(!i||Array.isArray(r)){for(var o,a,s=0,c=e.options.length;s-1,a.selected!==o&&(a.selected=o);else if(h(Bt(a),r))return void(e.selectedIndex!==s&&(e.selectedIndex=s));i||(e.selectedIndex=-1)}}function It(e,t){for(var n=0,r=t.length;n',n.innerHTML.indexOf(t)>0}function Qt(e){return go.innerHTML=e,go.textContent}function Xt(e,t,n){return t&&(e=e.replace(Wo,"<").replace(Zo,">")),n&&(e=e.replace(Go,"\n")),e.replace(Yo,"&").replace(Qo,'"')}function en(e,t){function n(t){d+=t,e=e.substring(t)}function r(){var t=e.match(xo);if(t){var r={tagName:t[1],attrs:[],start:d};n(t[0].length);for(var i,o;!(i=e.match(ko))&&(o=e.match($o));)n(o[0].length),r.attrs.push(o);if(i)return r.unarySlash=i[1],n(i[0].length),r.end=d,r}}function i(e){var n=e.tagName,r=e.unarySlash;u&&("p"===s&&Oi(n)&&o("",s),Ai(n)&&s===n&&o("",n));for(var i=l(n)||"html"===n&&"head"===s||!!r,a=e.attrs.length,d=new Array(a),p=0;p=0&&c[o].tag.toLowerCase()!==a;o--);}else o=0;if(o>=0){for(var u=c.length-1;u>=o;u--)t.end&&t.end(c[u].tag,r,i);c.length=o,s=o&&c[o-1].tag}else"br"===n.toLowerCase()?t.start&&t.start(n,[],!0,r,i):"p"===n.toLowerCase()&&(t.start&&t.start(n,[],!1,r,i),t.end&&t.end(n,r,i))}for(var a,s,c=[],u=t.expectHTML,l=t.isUnaryTag||Ar,f=t.isFromDOM,d=0;e;){if(a=e,s&&qo(s)){var p=s.toLowerCase(),v=Ko[p]||(Ko[p]=new RegExp("([\\s\\S]*?)(]*>)","i")),h=0,m=e.replace(v,function(e,n,r){return h=r.length,"script"!==p&&"style"!==p&&"noscript"!==p&&(n=n.replace(//g,"$1").replace(//g,"$1")),t.chars&&t.chars(n),""});d+=e.length-m.length,e=m,o("",p,d-h,d)}else{var g=e.indexOf("<");if(0===g){if(/^");if(y>=0){n(y+3);continue}}if(/^");if(_>=0){n(_+2);continue}}var b=e.match(Oo);if(b){n(b[0].length);continue}var $=e.match(Ao);if($){var w=d;n($[0].length),o($[0],$[1],w,d);continue}var C=r();if(C){i(C);continue}}var x=void 0;g>=0?(x=e.substring(0,g),n(g)):(x=e,e=""),t.chars&&t.chars(x)}if(e===a)throw new Error("Error parsing template:\n\n"+e)}o()}function tn(e){function t(){(a||(a=[])).push(e.slice(d,i).trim()),d=i+1}var n,r,i,o,a,s=!1,c=!1,u=0,l=0,f=0,d=0;for(i=0;ia&&o.push(JSON.stringify(e.slice(a,i)));var s=tn(r[1].trim());o.push("_s("+s+")"),a=i+r[0].length}return a-1:_q("+t+","+r+")"),ln(e,"change","var $$a="+t+",$$el=$event.target,$$c=$$el.checked?("+r+"):("+i+");if(Array.isArray($$a)){var $$v="+n+",$$i=_i($$a,$$v);if($$c){$$i<0&&("+t+"=$$a.concat($$v))}else{$$i>-1&&("+t+"=$$a.slice(0,$$i).concat($$a.slice($$i+1)))}}else{"+t+"=$$c}",null,!0)}function sr(e,t){var n=fn(e,"value")||"null";sn(e,"checked","_q("+t+","+n+")"),ln(e,"change",t+"="+n,null,!0)}function cr(e,t,n){var r=e.attrsMap.type,i=n||{},o=i.lazy,a=i.number,s=i.trim,c=o||Lr&&"range"===r?"change":"input",u=!o&&"range"!==r,l="input"===e.tag||"textarea"===e.tag,f=l?"$event.target.value"+(s?".trim()":""):"$event",d=a||"number"===r?t+"=_n("+f+")":t+"="+f;if(l&&u&&(d="if($event.target.composing)return;"+d),sn(e,"value",l?"_s("+t+")":"("+t+")"),ln(e,c,d,null,!0),u)return!0}function ur(e,t){var n=t+'=Array.prototype.filter.call($event.target.options,function(o){return o.selected}).map(function(o){return "_value" in o ? o._value : o.value})'+(null==e.attrsMap.multiple?"[0]":"");return ln(e,"change",n,null,!0),!0}function lr(e,t){t.value&&sn(e,"textContent","_s("+t.value+")")}function fr(e,t){t.value&&sn(e,"innerHTML","_s("+t.value+")")}function dr(e,t){return t=t?u(u({},Ca),t):Ca,er(e,t)}function pr(e,t,n){var r=(t&&t.warn||ui,t&&t.delimiters?String(t.delimiters)+e:e);if(wa[r])return wa[r];var i={},o=dr(e,t);i.render=vr(o.render);var a=o.staticRenderFns.length;i.staticRenderFns=new Array(a);for(var s=0;s0,Dr=jr&&jr.indexOf("edge/")>0,Mr=jr&&jr.indexOf("android")>0,Pr=jr&&/iphone|ipad|ipod|ios/.test(jr),Rr=Er&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__,Ir=function(){function e(){r=!1;var e=n.slice(0);n.length=0;for(var t=0;t",">"),mo=!!Er&&Yt("\n"," "),go=document.createElement("div"),yo=/([^\s"'<>\/=]+)/,_o=/(?:=)/,bo=[/"([^"]*)"+/.source,/'([^']*)'+/.source,/([^\s"'=<>`]+)/.source],$o=new RegExp("^\\s*"+yo.source+"(?:\\s*("+_o.source+")\\s*(?:"+bo.join("|")+"))?"),wo="[a-zA-Z_][\\w\\-\\.]*",Co="((?:"+wo+"\\:)?"+wo+")",xo=new RegExp("^<"+Co),ko=/^\s*(\/?)>/,Ao=new RegExp("^<\\/"+Co+"[^>]*>"),Oo=/^]+>/i,To=!1;"x".replace(/x(.)?/g,function(e,t){To=""===t});var So,Eo,jo,Lo,No,Do,Mo,Po,Ro,Io,Bo,Fo,Ho,Uo,zo,Vo,Jo,qo=n("script,style",!0),Ko={},Wo=/</g,Zo=/>/g,Go=/ /g,Yo=/&/g,Qo=/"/g,Xo=/\{\{((?:.|\n)+?)\}\}/g,ea=/[-.*+?^${}()|[\]\/\\]/g,ta=a(function(e){var t=e[0].replace(ea,"\\$&"),n=e[1].replace(ea,"\\$&");return new RegExp(t+"((?:.|\\n)+?)"+n,"g")}),na=/^v-|^@|^:/,ra=/(.*?)\s+(?:in|of)\s+(.*)/,ia=/\(([^,]*),([^,]*)(?:,([^,]*))?\)/,oa=/^:|^v-bind:/,aa=/^@|^v-on:/,sa=/:(.*)$/,ca=/\.[^\.]+/g,ua=/\u2028|\u2029/g,la=a(Qt),fa=/^xmlns:NS\d+/,da=/^NS\d+:/,pa=a(Ln),va=/^\s*[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\]|\[\d+\]|\[[A-Za-z_$][\w$]*\])*\s*$/,ha={esc:27,tab:9,enter:13,space:32,up:38,left:37,right:39,down:40,delete:[8,46]},ma={stop:"$event.stopPropagation();",prevent:"$event.preventDefault();",self:"if($event.target !== $event.currentTarget)return;"},ga={bind:Fn,cloak:p},ya=(new RegExp("\\b"+"do,if,for,let,new,try,var,case,else,with,await,break,catch,class,const,super,throw,while,yield,delete,export,import,return,switch,default,extends,finally,continue,debugger,function,arguments".split(",").join("\\b|\\b")+"\\b"),{staticKeys:["staticClass"],transformNode:tr,genData:nr}),_a={transformNode:rr,genData:ir},ba=[ya,_a],$a={model:or,text:lr,html:fr},wa=Object.create(null),Ca={isIE:Lr,expectHTML:!0,modules:ba,staticKeys:v(ba),directives:$a,isReservedTag:Ei,isUnaryTag:ki,mustUseProp:mi,getTagNamespace:qe,isPreTag:Si},xa=a(function(e){var t=We(e);return t&&t.innerHTML}),ka=Ce.prototype.$mount;return Ce.prototype.$mount=function(e,t){if(e=e&&We(e),e===document.body||e===document.documentElement)return this;var n=this.$options;if(!n.render){var r=n.template,i=!1;if(r)if("string"==typeof r)"#"===r.charAt(0)&&(i=!0,r=xa(r));else{if(!r.nodeType)return this;i=!0,r=r.innerHTML}else e&&(i=!0,r=hr(e));if(r){var o=pr(r,{warn:ui,isFromDOM:i,shouldDecodeTags:ho,shouldDecodeNewlines:mo,delimiters:n.delimiters},this),a=o.render,s=o.staticRenderFns;n.render=a,n.staticRenderFns=s}}return ka.call(this,e,t)},Ce.compile=pr,Ce}); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.Vue=t()}(this,function(){"use strict";function e(e){return null==e?"":"object"==typeof e?JSON.stringify(e,null,2):String(e)}function t(e){var t=parseFloat(e,10);return t||0===t?t:e}function n(e,t){for(var n=Object.create(null),r=e.split(","),i=0;i-1)return e.splice(n,1)}}function i(e,t){return _r.call(e,t)}function a(e){return"string"==typeof e||"number"==typeof e}function o(e){var t=Object.create(null);return function(n){var r=t[n];return r||(t[n]=e(n))}}function s(e,t){function n(n){var r=arguments.length;return r?r>1?e.apply(t,arguments):e.call(t,n):e.call(t)}return n._length=e.length,n}function c(e,t){t=t||0;for(var n=e.length-t,r=new Array(n);n--;)r[n]=e[n+t];return r}function u(e,t){for(var n in t)e[n]=t[n];return e}function l(e){return null!==e&&"object"==typeof e}function f(e){return kr.call(e)===Ar}function d(e){for(var t={},n=0;n=0&&zr[n].id>e.id;)n--;zr.splice(Math.max(n,Kr)+1,0,e)}else zr.push(e);Jr||(Jr=!0,Br(x))}}function A(e,t){var n,r;t||(t=Gr,t.clear());var i=Array.isArray(e),a=l(e);if((i||a)&&Object.isExtensible(e)){if(e.__ob__){var o=e.__ob__.dep.id;if(t.has(o))return;t.add(o)}if(i)for(n=e.length;n--;)A(e[n],t);else if(a)for(r=Object.keys(e),n=r.length;n--;)A(e[r[n]],t)}}function O(e,t){e.__proto__=t}function T(e,t,n){for(var r=0,i=n.length;r1?c(n):n;for(var r=c(arguments,1),i=0,a=n.length;i-1?Li[e]=t.constructor===window.HTMLUnknownElement||t.constructor===window.HTMLElement:Li[e]=/HTMLUnknownElement/.test(t.toString())}function We(e){if("string"==typeof e){if(e=document.querySelector(e),!e)return document.createElement("div")}return e}function Ze(e,t){var n=document.createElement(e);return"select"!==e?n:(t.data&&t.data.attrs&&"multiple"in t.data.attrs&&n.setAttribute("multiple","multiple"),n)}function Ge(e,t){return document.createElementNS(xi[e],t)}function Ye(e){return document.createTextNode(e)}function Qe(e){return document.createComment(e)}function Xe(e,t,n){e.insertBefore(t,n)}function et(e,t){e.removeChild(t)}function tt(e,t){e.appendChild(t)}function nt(e){return e.parentNode}function rt(e){return e.nextSibling}function it(e){return e.tagName}function at(e,t){e.textContent=t}function ot(e){return e.childNodes}function st(e,t,n){e.setAttribute(t,n)}function ct(e,t){var n=e.data.ref;if(n){var i=e.context,a=e.child||e.elm,o=i.$refs;t?Array.isArray(o[n])?r(o[n],a):o[n]===a&&(o[n]=void 0):e.data.refInFor?Array.isArray(o[n])?o[n].push(a):o[n]=[a]:o[n]=a}}function ut(e){return null==e}function lt(e){return null!=e}function ft(e,t){return e.key===t.key&&e.tag===t.tag&&e.isComment===t.isComment&&!e.data==!t.data}function dt(e,t,n){var r,i,a={};for(r=t;r<=n;++r)i=e[r].key,lt(i)&&(a[i]=r);return a}function pt(e){function t(e){return new ri(C.tagName(e).toLowerCase(),{},[],void 0,e)}function n(e,t){function n(){0===--n.listeners&&r(e)}return n.listeners=t,n}function r(e){var t=C.parentNode(e);C.removeChild(t,e)}function i(e,t,n){var r,i=e.data;if(e.isRootInsert=!n,lt(i)&&(lt(r=i.hook)&<(r=r.init)&&r(e),lt(r=e.child)))return u(e,t),e.elm;var a=e.children,s=e.tag;return lt(s)?(e.elm=e.ns?C.createElementNS(e.ns,s):C.createElement(s,e),l(e),o(e,a,t),lt(i)&&c(e,t)):e.isComment?e.elm=C.createComment(e.text):e.elm=C.createTextNode(e.text),e.elm}function o(e,t,n){if(Array.isArray(t))for(var r=0;rv?(u=ut(n[y+1])?null:n[y+1].elm,f(e,u,n,d,y,r)):d>y&&p(e,t,l,v)}function m(e,t,n,r){if(e!==t){if(t.isStatic&&e.isStatic&&t.key===e.key&&t.isCloned)return void(t.elm=e.elm);var i,a=t.data,o=lt(a);o&<(i=a.hook)&<(i=i.prepatch)&&i(e,t);var c=t.elm=e.elm,u=e.children,l=t.children;if(o&&s(t)){for(i=0;i<$.update.length;++i)$.update[i](e,t);lt(i=a.hook)&<(i=i.update)&&i(e,t)}ut(t.text)?lt(u)&<(l)?u!==l&&h(c,u,l,n,r):lt(l)?(lt(e.text)&&C.setTextContent(c,""),f(c,null,l,0,l.length-1,n)):lt(u)?p(c,u,0,u.length-1):lt(e.text)&&C.setTextContent(c,""):e.text!==t.text&&C.setTextContent(c,t.text),o&<(i=a.hook)&<(i=i.postpatch)&&i(e,t)}}function g(e,t,n){if(n&&e.parent)e.parent.data.pendingInsert=t;else for(var r=0;r-1?t.split(/\s+/).forEach(function(t){return e.classList.add(t)}):e.classList.add(t);else{var n=" "+e.getAttribute("class")+" ";n.indexOf(" "+t+" ")<0&&e.setAttribute("class",(n+t).trim())}}function kt(e,t){if(e.classList)t.indexOf(" ")>-1?t.split(/\s+/).forEach(function(t){return e.classList.remove(t)}):e.classList.remove(t);else{for(var n=" "+e.getAttribute("class")+" ",r=" "+t+" ";n.indexOf(r)>=0;)n=n.replace(r," ");e.setAttribute("class",n.trim())}}function At(e){ea(function(){ea(e)})}function Ot(e,t){(e._transitionClasses||(e._transitionClasses=[])).push(t),xt(e,t)}function Tt(e,t){e._transitionClasses&&r(e._transitionClasses,t),kt(e,t)}function St(e,t,n){var r=Et(e,t),i=r.type,a=r.timeout,o=r.propCount;if(!i)return n();var s=i===Wi?Yi:Xi,c=0,u=function(){e.removeEventListener(s,l),n()},l=function(t){t.target===e&&++c>=o&&u()};setTimeout(function(){c0&&(n=Wi,l=o,f=a.length):t===Zi?u>0&&(n=Zi,l=u,f=c.length):(l=Math.max(o,u),n=l>0?o>u?Wi:Zi:null,f=n?n===Wi?a.length:c.length:0);var d=n===Wi&&ta.test(r[Gi+"Property"]);return{type:n,timeout:l,propCount:f,hasTransform:d}}function jt(e,t){return Math.max.apply(null,t.map(function(t,n){return Lt(t)+Lt(e[n])}))}function Lt(e){return 1e3*Number(e.slice(0,-1))}function Nt(e){var t=e.elm;t._leaveCb&&(t._leaveCb.cancelled=!0,t._leaveCb());var n=Mt(e.data.transition);if(n&&!t._enterCb&&1===t.nodeType){var r=n.css,i=n.type,a=n.enterClass,o=n.enterActiveClass,s=n.appearClass,c=n.appearActiveClass,u=n.beforeEnter,l=n.enter,f=n.afterEnter,d=n.enterCancelled,p=n.beforeAppear,v=n.appear,h=n.afterAppear,m=n.appearCancelled,g=ai.$vnode,y=g&&g.parent?g.parent.context:ai,_=!y._isMounted||!e.isRootInsert;if(!_||v||""===v){var b=_?s:a,$=_?c:o,w=_?p||u:u,C=_&&"function"==typeof v?v:l,x=_?h||f:f,k=_?m||d:d,A=r!==!1&&!Dr,O=C&&(C._length||C.length)>1,T=t._enterCb=Pt(function(){A&&Tt(t,$),T.cancelled?(A&&Tt(t,b),k&&k(t)):x&&x(t),t._enterCb=null});e.data.show||q(e.data.hook||(e.data.hook={}),"insert",function(){var n=t.parentNode,r=n&&n._pending&&n._pending[e.key];r&&r.tag===e.tag&&r.elm._leaveCb&&r.elm._leaveCb(),C&&C(t,T)},"transition-insert"),w&&w(t),A&&(Ot(t,b),Ot(t,$),At(function(){Tt(t,b),T.cancelled||O||St(t,i,T)})),e.data.show&&C&&C(t,T),A||O||T()}}}function Dt(e,t){function n(){m.cancelled||(e.data.show||((r.parentNode._pending||(r.parentNode._pending={}))[e.key]=e),u&&u(r),v&&(Ot(r,s),Ot(r,c),At(function(){Tt(r,s),m.cancelled||h||St(r,o,m)})),l&&l(r,m),v||h||m())}var r=e.elm;r._enterCb&&(r._enterCb.cancelled=!0,r._enterCb());var i=Mt(e.data.transition);if(!i)return t();if(!r._leaveCb&&1===r.nodeType){var a=i.css,o=i.type,s=i.leaveClass,c=i.leaveActiveClass,u=i.beforeLeave,l=i.leave,f=i.afterLeave,d=i.leaveCancelled,p=i.delayLeave,v=a!==!1&&!Dr,h=l&&(l._length||l.length)>1,m=r._leaveCb=Pt(function(){r.parentNode&&r.parentNode._pending&&(r.parentNode._pending[e.key]=null),v&&Tt(r,c),m.cancelled?(v&&Tt(r,s),d&&d(r)):(t(),f&&f(r)),r._leaveCb=null});p?p(n):n()}}function Mt(e){if(e){if("object"==typeof e){var t={};return e.css!==!1&&u(t,na(e.name||"v")),u(t,e),t}return"string"==typeof e?na(e):void 0}}function Pt(e){var t=!1;return function(){t||(t=!0,e())}}function Rt(e,t,n){var r=t.value,i=e.multiple;if(!i||Array.isArray(r)){for(var a,o,s=0,c=e.options.length;s-1,o.selected!==a&&(o.selected=a);else if(h(Bt(o),r))return void(e.selectedIndex!==s&&(e.selectedIndex=s));i||(e.selectedIndex=-1)}}function It(e,t){for(var n=0,r=t.length;n',n.innerHTML.indexOf(t)>0}function Qt(e){return ma.innerHTML=e,ma.textContent}function Xt(e,t){return t&&(e=e.replace(Za,"\n")),e.replace(Ka,"<").replace(Wa,">").replace(Ga,"&").replace(Ya,'"')}function en(e,t){function n(t){f+=t,e=e.substring(t)}function r(){var t=e.match(Ca);if(t){var r={tagName:t[1],attrs:[],start:f};n(t[0].length);for(var i,a;!(i=e.match(xa))&&(a=e.match(ba));)n(a[0].length),r.attrs.push(a);if(i)return r.unarySlash=i[1],n(i[0].length),r.end=f,r}}function i(e){var n=e.tagName,r=e.unarySlash;u&&("p"===s&&Ti(n)&&a("",s),Oi(n)&&s===n&&a("",n));for(var i=l(n)||"html"===n&&"head"===s||!!r,o=e.attrs.length,f=new Array(o),d=0;d=0&&c[a].tag.toLowerCase()!==o;a--);}else a=0;if(a>=0){for(var u=c.length-1;u>=a;u--)t.end&&t.end(c[u].tag,r,i);c.length=a,s=a&&c[a-1].tag}else"br"===n.toLowerCase()?t.start&&t.start(n,[],!0,r,i):"p"===n.toLowerCase()&&(t.start&&t.start(n,[],!1,r,i),t.end&&t.end(n,r,i))}for(var o,s,c=[],u=t.expectHTML,l=t.isUnaryTag||Or,f=0;e;){if(o=e,s&&Ja(s)){var d=s.toLowerCase(),p=qa[d]||(qa[d]=new RegExp("([\\s\\S]*?)(]*>)","i")),v=0,h=e.replace(p,function(e,n,r){return v=r.length,"script"!==d&&"style"!==d&&"noscript"!==d&&(n=n.replace(//g,"$1").replace(//g,"$1")),t.chars&&t.chars(n),""});f+=e.length-h.length,e=h,a("",d,f-v,f)}else{var m=e.indexOf("<");if(0===m){if(/^");if(g>=0){n(g+3);continue}}if(/^");if(y>=0){n(y+2);continue}}var _=e.match(Aa);if(_){n(_[0].length);continue}var b=e.match(ka);if(b){var $=f;n(b[0].length),a(b[0],b[1],$,f);continue}var w=r();if(w){i(w);continue}}var C=void 0;m>=0?(C=e.substring(0,m),n(m)):(C=e,e=""),t.chars&&t.chars(C)}if(e===o)throw new Error("Error parsing template:\n\n"+e)}a()}function tn(e){function t(){(o||(o=[])).push(e.slice(d,i).trim()),d=i+1}var n,r,i,a,o,s=!1,c=!1,u=0,l=0,f=0,d=0;for(i=0;io&&a.push(JSON.stringify(e.slice(o,i)));var s=tn(r[1].trim());a.push("_s("+s+")"),o=i+r[0].length}return o-1:_q("+t+","+r+")"),ln(e,"change","var $$a="+t+",$$el=$event.target,$$c=$$el.checked?("+r+"):("+i+");if(Array.isArray($$a)){var $$v="+n+",$$i=_i($$a,$$v);if($$c){$$i<0&&("+t+"=$$a.concat($$v))}else{$$i>-1&&("+t+"=$$a.slice(0,$$i).concat($$a.slice($$i+1)))}}else{"+t+"=$$c}",null,!0)}function cr(e,t){var n=fn(e,"value")||"null";sn(e,"checked","_q("+t+","+n+")"),ln(e,"change",t+"="+n,null,!0)}function ur(e,t,n){var r=e.attrsMap.type,i=n||{},a=i.lazy,o=i.number,s=i.trim,c=a||Nr&&"range"===r?"change":"input",u=!a&&"range"!==r,l="input"===e.tag||"textarea"===e.tag,f=l?"$event.target.value"+(s?".trim()":""):"$event",d=o||"number"===r?t+"=_n("+f+")":t+"="+f;l&&u&&(d="if($event.target.composing)return;"+d),sn(e,"value",l?"_s("+t+")":"("+t+")"),ln(e,c,d,null,!0)}function lr(e,t){var n=t+'=Array.prototype.filter.call($event.target.options,function(o){return o.selected}).map(function(o){return "_value" in o ? o._value : o.value})'+(null==e.attrsMap.multiple?"[0]":"");ln(e,"change",n,null,!0)}function fr(e,t){t.value&&sn(e,"textContent","_s("+t.value+")")}function dr(e,t){t.value&&sn(e,"innerHTML","_s("+t.value+")")}function pr(e,t){return t=t?u(u({},Co),t):Co,tr(e,t)}function vr(e,t,n){var r=(t&&t.warn||li,t&&t.delimiters?String(t.delimiters)+e:e);if(wo[r])return wo[r];var i={},a=pr(e,t);i.render=hr(a.render);var o=a.staticRenderFns.length;i.staticRenderFns=new Array(o);for(var s=0;s0,Mr=Lr&&Lr.indexOf("edge/")>0,Pr=Lr&&Lr.indexOf("android")>0,Rr=Lr&&/iphone|ipad|ipod|ios/.test(Lr),Ir=jr&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__,Br=function(){function e(){r=!1;var e=n.slice(0);n.length=0;for(var t=0;t\/=]+)/,ya=/(?:=)/,_a=[/"([^"]*)"+/.source,/'([^']*)'+/.source,/([^\s"'=<>`]+)/.source],ba=new RegExp("^\\s*"+ga.source+"(?:\\s*("+ya.source+")\\s*(?:"+_a.join("|")+"))?"),$a="[a-zA-Z_][\\w\\-\\.]*",wa="((?:"+$a+"\\:)?"+$a+")",Ca=new RegExp("^<"+wa),xa=/^\s*(\/?)>/,ka=new RegExp("^<\\/"+wa+"[^>]*>"),Aa=/^]+>/i,Oa=!1;"x".replace(/x(.)?/g,function(e,t){Oa=""===t});var Ta,Sa,Ea,ja,La,Na,Da,Ma,Pa,Ra,Ia,Ba,Fa,Ha,Ua,za,Va,Ja=n("script,style",!0),qa={},Ka=/</g,Wa=/>/g,Za=/ /g,Ga=/&/g,Ya=/"/g,Qa=/\{\{((?:.|\n)+?)\}\}/g,Xa=/[-.*+?^${}()|[\]\/\\]/g,eo=o(function(e){var t=e[0].replace(Xa,"\\$&"),n=e[1].replace(Xa,"\\$&");return new RegExp(t+"((?:.|\\n)+?)"+n,"g")}),to=/^v-|^@|^:/,no=/(.*?)\s+(?:in|of)\s+(.*)/,ro=/\(([^,]*),([^,]*)(?:,([^,]*))?\)/,io=/^:|^v-bind:/,ao=/^@|^v-on:/,oo=/:(.*)$/,so=/\.[^\.]+/g,co=/\u2028|\u2029/g,uo=o(Qt),lo=/^xmlns:NS\d+/,fo=/^NS\d+:/,po=o(Ln),vo=/^\s*[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\]|\[\d+\]|\[[A-Za-z_$][\w$]*\])*\s*$/,ho={esc:27,tab:9,enter:13,space:32,up:38,left:37,right:39,down:40,delete:[8,46]},mo={stop:"$event.stopPropagation();",prevent:"$event.preventDefault();",self:"if($event.target !== $event.currentTarget)return;"},go={bind:Hn,cloak:p},yo=(new RegExp("\\b"+"do,if,for,let,new,try,var,case,else,with,await,break,catch,class,const,super,throw,while,yield,delete,export,import,return,switch,default,extends,finally,continue,debugger,function,arguments".split(",").join("\\b|\\b")+"\\b"),{staticKeys:["staticClass"],transformNode:nr,genData:rr}),_o={transformNode:ir,genData:ar},bo=[yo,_o],$o={model:or,text:fr,html:dr},wo=Object.create(null),Co={isIE:Nr,expectHTML:!0,modules:bo,staticKeys:v(bo),directives:$o,isReservedTag:ji,isUnaryTag:Ai,mustUseProp:gi,getTagNamespace:qe,isPreTag:Ei},xo=o(function(e){var t=We(e);return t&&t.innerHTML}),ko=Ce.prototype.$mount;return Ce.prototype.$mount=function(e,t){if(e=e&&We(e),e===document.body||e===document.documentElement)return this;var n=this.$options;if(!n.render){var r=n.template;if(r)if("string"==typeof r)"#"===r.charAt(0)&&(r=xo(r));else{if(!r.nodeType)return this;r=r.innerHTML}else e&&(r=mr(e));if(r){var i=vr(r,{warn:li,shouldDecodeNewlines:ha,delimiters:n.delimiters},this),a=i.render,o=i.staticRenderFns;n.render=a,n.staticRenderFns=o}}return ko.call(this,e,t)},Ce.compile=vr,Ce}); \ No newline at end of file diff --git a/examples/commits/index.html b/examples/commits/index.html index a80eaa4604e..116fb86f159 100644 --- a/examples/commits/index.html +++ b/examples/commits/index.html @@ -18,7 +18,8 @@ font-weight: bold; } - + +
diff --git a/examples/elastic-header/index.html b/examples/elastic-header/index.html index 63f75fa0246..81df1c9404e 100644 --- a/examples/elastic-header/index.html +++ b/examples/elastic-header/index.html @@ -4,7 +4,8 @@ - + + diff --git a/examples/firebase/index.html b/examples/firebase/index.html index e8c54bd5a85..eee783ac0df 100644 --- a/examples/firebase/index.html +++ b/examples/firebase/index.html @@ -5,7 +5,8 @@ - + + diff --git a/examples/grid/index.html b/examples/grid/index.html index c9d58fd4f69..d668cd76cc5 100644 --- a/examples/grid/index.html +++ b/examples/grid/index.html @@ -4,13 +4,14 @@ Vue.js grid component example - + + diff --git a/examples/markdown/index.html b/examples/markdown/index.html index 42f228fa7a8..9ca987466ba 100644 --- a/examples/markdown/index.html +++ b/examples/markdown/index.html @@ -6,7 +6,8 @@ - + + diff --git a/examples/modal/index.html b/examples/modal/index.html index 5f530ab924b..302e947023d 100644 --- a/examples/modal/index.html +++ b/examples/modal/index.html @@ -3,7 +3,8 @@ Vue.js Modal Example - + + diff --git a/examples/move-animations/index.html b/examples/move-animations/index.html index dc0f80e0c28..ae246607b63 100644 --- a/examples/move-animations/index.html +++ b/examples/move-animations/index.html @@ -29,7 +29,8 @@ } - + +
diff --git a/examples/select2/index.html b/examples/select2/index.html index f625c8a5b13..b2344c6e69b 100644 --- a/examples/select2/index.html +++ b/examples/select2/index.html @@ -3,7 +3,8 @@ Vue.js custom directive integration example (select2) - + + diff --git a/examples/svg/index.html b/examples/svg/index.html index 7b4ca5dbc8e..faf731dfd71 100644 --- a/examples/svg/index.html +++ b/examples/svg/index.html @@ -4,7 +4,8 @@ Vue.js SVG example - + + diff --git a/examples/todomvc/index.html b/examples/todomvc/index.html index 063229bc3fe..0477f0d014f 100644 --- a/examples/todomvc/index.html +++ b/examples/todomvc/index.html @@ -1,68 +1,69 @@ - - - Vue.js • TodoMVC - - - - - -
-
-

todos

- -
-
- -
    -
  • -
    - - - -
    - -
  • -
-
-
- - {{ remaining }} {{ remaining | pluralize }} left - - - -
-
- + + + Vue.js • TodoMVC + + + + + +
+
+

todos

+ +
+
+ +
    +
  • +
    + + + +
    + +
  • +
+
+
+ + {{ remaining }} {{ remaining | pluralize }} left + + + +
+
+ - - - - + + + + + diff --git a/examples/tree/index.html b/examples/tree/index.html index 1bb8611ccc3..05df32066a9 100644 --- a/examples/tree/index.html +++ b/examples/tree/index.html @@ -20,7 +20,8 @@ list-style-type: dot; } - + + diff --git a/flow/modules.js b/flow/modules.js index 829c77156d7..5ea7f71a10f 100644 --- a/flow/modules.js +++ b/flow/modules.js @@ -1,6 +1,6 @@ -declare module 'entities' { - declare function encodeHTML(html: string): string; - declare function decodeHTML(html: string): string; +declare module 'he' { + declare function escape(html: string): string; + declare function decode(html: string): string; } declare module 'source-map' { diff --git a/package.json b/package.json index 323f6778b73..794bcaa4b03 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vue", - "version": "2.0.2", + "version": "2.0.3", "description": "Reactive, component-oriented view layer for modern web interfaces.", "main": "dist/vue.common.js", "typings": "types/index.d.ts", @@ -26,7 +26,7 @@ "test": "npm run lint && flow check && npm run test:types && npm run test:cover && npm run test:e2e -- --env phantomjs && npm run test:ssr", "test:unit": "karma start build/karma.unit.config.js", "test:cover": "karma start build/karma.cover.config.js", - "test:e2e": "npm run build -- vue.js && node test/e2e/runner.js", + "test:e2e": "npm run build -- vue.min.js && node test/e2e/runner.js", "test:ssr": "npm run build:ssr && VUE_ENV=server jasmine JASMINE_CONFIG_PATH=test/ssr/jasmine.json", "test:sauce": "npm run sauce -- 0 && npm run sauce -- 1 && npm run sauce -- 2", "test:types": "tsc -p ./types/test/tsconfig.json", @@ -61,7 +61,6 @@ "codecov.io": "^0.1.6", "cross-spawn": "^4.0.0", "de-indent": "^1.0.2", - "entities": "^1.1.1", "es6-promise": "^3.2.1", "eslint": "^3.4.0", "eslint-config-vue": "^1.1.0", @@ -69,6 +68,7 @@ "eslint-plugin-flowtype": "^2.16.0", "eslint-plugin-html": "^1.5.2", "flow-bin": "^0.32.0", + "he": "^1.1.0", "http-server": "^0.9.0", "jasmine": "2.4.x", "jasmine-core": "2.4.x", diff --git a/packages/vue-server-renderer/build.js b/packages/vue-server-renderer/build.js index 89347f6857f..c0d2e719b07 100644 --- a/packages/vue-server-renderer/build.js +++ b/packages/vue-server-renderer/build.js @@ -6,7 +6,7 @@ function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'defau var stream = require('stream'); var stream__default = _interopDefault(stream); -var entities = require('entities'); +var he = require('he'); var NativeModule = _interopDefault(require('module')); var vm = _interopDefault(require('vm')); @@ -1644,67 +1644,7 @@ function cloneVNodes (vnodes) { /* */ -function normalizeChildren ( - children, - ns, - nestedIndex -) { - if (isPrimitive(children)) { - return [createTextVNode(children)] - } - if (Array.isArray(children)) { - var res = []; - for (var i = 0, l = children.length; i < l; i++) { - var c = children[i]; - var last = res[res.length - 1]; - // nested - if (Array.isArray(c)) { - res.push.apply(res, normalizeChildren(c, ns, i)); - } else if (isPrimitive(c)) { - if (last && last.text) { - last.text += String(c); - } else if (c !== '') { - // convert primitive to vnode - res.push(createTextVNode(c)); - } - } else if (c instanceof VNode) { - if (c.text && last && last.text) { - last.text += c.text; - } else { - // inherit parent namespace - if (ns) { - applyNS(c, ns); - } - // default key for nested array children (likely generated by v-for) - if (c.tag && c.key == null && nestedIndex != null) { - c.key = "__vlist_" + nestedIndex + "_" + i + "__"; - } - res.push(c); - } - } - } - return res - } -} - -function createTextVNode (val) { - return new VNode(undefined, undefined, undefined, String(val)) -} - -function applyNS (vnode, ns) { - if (vnode.tag && !vnode.ns) { - vnode.ns = ns; - if (vnode.children) { - for (var i = 0, l = vnode.children.length; i < l; i++) { - applyNS(vnode.children[i], ns); - } - } - } -} - - - - +/* */ function updateListeners ( on, @@ -1775,6 +1715,68 @@ function fnInvoker (o) { /* */ +function normalizeChildren ( + children, + ns, + nestedIndex +) { + if (isPrimitive(children)) { + return [createTextVNode(children)] + } + if (Array.isArray(children)) { + var res = []; + for (var i = 0, l = children.length; i < l; i++) { + var c = children[i]; + var last = res[res.length - 1]; + // nested + if (Array.isArray(c)) { + res.push.apply(res, normalizeChildren(c, ns, ((nestedIndex || '') + "_" + i))); + } else if (isPrimitive(c)) { + if (last && last.text) { + last.text += String(c); + } else if (c !== '') { + // convert primitive to vnode + res.push(createTextVNode(c)); + } + } else if (c instanceof VNode) { + if (c.text && last && last.text) { + last.text += c.text; + } else { + // inherit parent namespace + if (ns) { + applyNS(c, ns); + } + // default key for nested array children (likely generated by v-for) + if (c.tag && c.key == null && nestedIndex != null) { + c.key = "__vlist" + nestedIndex + "_" + i + "__"; + } + res.push(c); + } + } + } + return res + } +} + +function createTextVNode (val) { + return new VNode(undefined, undefined, undefined, String(val)) +} + +function applyNS (vnode, ns) { + if (vnode.tag && !vnode.ns) { + vnode.ns = ns; + if (vnode.children) { + for (var i = 0, l = vnode.children.length; i < l; i++) { + applyNS(vnode.children[i], ns); + } + } + } +} + +/* */ + +/* */ + var activeInstance = null; function initLifecycle (vm$$1) { @@ -1956,6 +1958,8 @@ function lifecycleMixin (Vue) { if (vm$$1.$el) { vm$$1.$el.__vue__ = null; } + // invoke destroy hooks on current rendered tree + vm$$1.__patch__(vm$$1._vnode, null); }; } @@ -2076,9 +2080,11 @@ function createFunctionalComponent ( slots: function () { return resolveSlots(children, context); } } ); - vnode.functionalContext = context; - if (data.slot) { - (vnode.data || (vnode.data = {})).slot = data.slot; + if (vnode instanceof VNode) { + vnode.functionalContext = context; + if (data.slot) { + (vnode.data || (vnode.data = {})).slot = data.slot; + } } return vnode } @@ -3485,21 +3491,21 @@ var nlRE = / /g; var ampRE = /&/g; var quoteRE = /"/g; -function decodeAttr (value, shouldDecodeTags, shouldDecodeNewlines) { - if (shouldDecodeTags) { - value = value.replace(ltRE, '<').replace(gtRE, '>'); - } +function decodeAttr (value, shouldDecodeNewlines) { if (shouldDecodeNewlines) { value = value.replace(nlRE, '\n'); } - return value.replace(ampRE, '&').replace(quoteRE, '"') + return value + .replace(ltRE, '<') + .replace(gtRE, '>') + .replace(ampRE, '&') + .replace(quoteRE, '"') } function parseHTML (html, options) { var stack = []; var expectHTML = options.expectHTML; var isUnaryTag$$1 = options.isUnaryTag || no; - var isFromDOM = options.isFromDOM; var index = 0; var last, lastTag; while (html) { @@ -3649,11 +3655,10 @@ function parseHTML (html, options) { var value = args[3] || args[4] || args[5] || ''; attrs[i] = { name: args[1], - value: isFromDOM ? decodeAttr( + value: decodeAttr( value, - options.shouldDecodeTags, options.shouldDecodeNewlines - ) : value + ) }; } @@ -3938,7 +3943,7 @@ var argRE = /:(.*)$/; var modifierRE = /\.[^\.]+/g; var specialNewlineRE = /\u2028|\u2029/g; -var decodeHTMLCached = cached(entities.decodeHTML); +var decodeHTMLCached = cached(he.decode); // configurable state var warn$1; @@ -3975,8 +3980,6 @@ function parse ( parseHTML(template, { expectHTML: options.expectHTML, isUnaryTag: options.isUnaryTag, - isFromDOM: options.isFromDOM, - shouldDecodeTags: options.shouldDecodeTags, shouldDecodeNewlines: options.shouldDecodeNewlines, start: function start (tag, attrs, unary) { // check namespace. @@ -3993,7 +3996,7 @@ function parse ( type: 1, tag: tag, attrsList: attrs, - attrsMap: makeAttrsMap(attrs), + attrsMap: makeAttrsMap(attrs, options.isIE), parent: currentParent, children: [] }; @@ -4343,10 +4346,10 @@ function parseModifiers (name) { } } -function makeAttrsMap (attrs) { +function makeAttrsMap (attrs, isIE) { var map = {}; for (var i = 0, l = attrs.length; i < l; i++) { - if (process.env.NODE_ENV !== 'production' && map[attrs[i].name]) { + if (process.env.NODE_ENV !== 'production' && map[attrs[i].name] && !isIE) { warn$1('duplicate attribute: ' + attrs[i].name); } map[attrs[i].name] = attrs[i].value; @@ -4460,7 +4463,7 @@ function markStaticRoots (node, isInFor) { } if (node.children) { for (var i = 0, l = node.children.length; i < l; i++) { - markStaticRoots(node.children[i], !!node.for); + markStaticRoots(node.children[i], isInFor || !!node.for); } } } @@ -4478,10 +4481,24 @@ function isStatic (node) { !node.if && !node.for && // not v-if or v-for or v-else !isBuiltInTag(node.tag) && // not a built-in isPlatformReservedTag(node.tag) && // not a component + !isDirectChildOfTemplateFor(node) && Object.keys(node).every(isStaticKey) )) } +function isDirectChildOfTemplateFor (node) { + while (node.parent) { + node = node.parent; + if (node.tag !== 'template') { + return false + } + if (node.for) { + return true + } + } + return false +} + /* */ var simplePathRE = /^\s*[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\]|\[\d+\]|\[[A-Za-z_$][\w$]*\])*\s*$/; @@ -4787,7 +4804,7 @@ function genSlot (el) { } function genComponent (el) { - var children = genChildren(el); + var children = el.inlineTemplate ? null : genChildren(el); return ("_h(" + (el.component) + "," + (genData(el)) + (children ? ("," + children) : '') + ")") } @@ -4984,14 +5001,16 @@ function model ( } } if (tag === 'select') { - return genSelect(el, value) + genSelect(el, value); } else if (tag === 'input' && type === 'checkbox') { genCheckboxModel(el, value); } else if (tag === 'input' && type === 'radio') { genRadioModel(el, value); } else { - return genDefaultModel(el, value, modifiers) + genDefaultModel(el, value, modifiers); } + // ensure runtime directive metadata + return true } function genCheckboxModel (el, value) { @@ -5090,10 +5109,6 @@ function genDefaultModel ( } addProp(el, 'value', isNative ? ("_s(" + value + ")") : ("(" + value + ")")); addHandler(el, event, code, null, true); - if (needCompositionGuard) { - // need runtime directive code to help with composition events - return true - } } function genSelect (el, value) { @@ -5105,8 +5120,6 @@ function genSelect (el, value) { ".map(function(o){return \"_value\" in o ? o._value : o.value})" + (el.attrsMap.multiple == null ? '[0]' : ''); addHandler(el, 'change', code, null, true); - // need runtime to help with possible dynamically generated options - return true } function checkOptionWarning (option) { @@ -5338,7 +5351,7 @@ function createRenderFunction ( } else if (node.isComment) { write((""), next); } else { - write(node.raw ? node.text : entities.encodeHTML(String(node.text)), next); + write(node.raw ? node.text : he.escape(String(node.text)), next); } } } diff --git a/packages/vue-server-renderer/package.json b/packages/vue-server-renderer/package.json index 2e381b5504b..f14fb94cd09 100644 --- a/packages/vue-server-renderer/package.json +++ b/packages/vue-server-renderer/package.json @@ -1,6 +1,6 @@ { "name": "vue-server-renderer", - "version": "2.0.2", + "version": "2.0.3", "description": "server renderer for Vue 2.0", "main": "index.js", "repository": { @@ -18,7 +18,7 @@ "url": "https://github.com/vuejs/vue/issues" }, "dependencies": { - "entities": "^1.1.1", + "he": "^1.1.0", "de-indent": "^1.0.2" }, "homepage": "https://github.com/vuejs/vue#readme" diff --git a/packages/vue-template-compiler/README.md b/packages/vue-template-compiler/README.md index 4ffd726583d..98d0cceca5b 100644 --- a/packages/vue-template-compiler/README.md +++ b/packages/vue-template-compiler/README.md @@ -38,7 +38,7 @@ The optional `options` object can contain the following: - `modules` - An array of compiler modules. For details on compiler modules, refer to its [type definition](https://github.com/vuejs/vue/blob/dev/flow/compiler.js#L31) and the [built-in modules](https://github.com/vuejs/vue/tree/dev/src/platforms/web/compiler/modules). + An array of compiler modules. For details on compiler modules, refer to its [type definition](https://github.com/vuejs/vue/blob/dev/flow/compiler.js#L35) and the [built-in modules](https://github.com/vuejs/vue/tree/dev/src/platforms/web/compiler/modules). - `directives` @@ -55,7 +55,11 @@ The optional `options` object can contain the following: By default, a compile-time directive will extract the directive and the directive will not be present at runtime. If you want the directive to also be handled by a runtime definition, return `true` in the transform function. - Refer to the implementation of some [built-in compile-time directives](https://github.com/vuejs/vue/tree/next/src/platforms/web/compiler/directives). + Refer to the implementation of some [built-in compile-time directives](https://github.com/vuejs/vue/tree/dev/src/platforms/web/compiler/directives). + +- `preserveWhitespace` + + Defaults to `true`. This means the compiled render function respects all the whitespaces between HTML tags. If set to `false`, all whitespaces between tags will be ignored. This can result in slightly better performance but may affect layout for inline elements. --- @@ -76,7 +80,7 @@ This is only useful at runtime with pre-configured builds, so it doesn't accept ### compiler.parseComponent(file, [options]) -Parse a SFC (single-file component, or `*.vue` file) into a [descriptor](https://github.com/vuejs/vue/blob/dev/flow/compiler.js#L131). This is used in SFC build tools like `vue-loader` and `vueify`. +Parse a SFC (single-file component, or `*.vue` file) into a [descriptor](https://github.com/vuejs/vue/blob/dev/flow/compiler.js#L137). This is used in SFC build tools like `vue-loader` and `vueify`. #### Options diff --git a/packages/vue-template-compiler/build.js b/packages/vue-template-compiler/build.js index 0f7a1d1200b..2545652cf16 100644 --- a/packages/vue-template-compiler/build.js +++ b/packages/vue-template-compiler/build.js @@ -4,7 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } -var entities = require('entities'); +var he = require('he'); var deindent = _interopDefault(require('de-indent')); /* */ @@ -1518,67 +1518,7 @@ function cloneVNodes (vnodes) { /* */ -function normalizeChildren ( - children, - ns, - nestedIndex -) { - if (isPrimitive(children)) { - return [createTextVNode(children)] - } - if (Array.isArray(children)) { - var res = []; - for (var i = 0, l = children.length; i < l; i++) { - var c = children[i]; - var last = res[res.length - 1]; - // nested - if (Array.isArray(c)) { - res.push.apply(res, normalizeChildren(c, ns, i)); - } else if (isPrimitive(c)) { - if (last && last.text) { - last.text += String(c); - } else if (c !== '') { - // convert primitive to vnode - res.push(createTextVNode(c)); - } - } else if (c instanceof VNode) { - if (c.text && last && last.text) { - last.text += c.text; - } else { - // inherit parent namespace - if (ns) { - applyNS(c, ns); - } - // default key for nested array children (likely generated by v-for) - if (c.tag && c.key == null && nestedIndex != null) { - c.key = "__vlist_" + nestedIndex + "_" + i + "__"; - } - res.push(c); - } - } - } - return res - } -} - -function createTextVNode (val) { - return new VNode(undefined, undefined, undefined, String(val)) -} - -function applyNS (vnode, ns) { - if (vnode.tag && !vnode.ns) { - vnode.ns = ns; - if (vnode.children) { - for (var i = 0, l = vnode.children.length; i < l; i++) { - applyNS(vnode.children[i], ns); - } - } - } -} - - - - +/* */ function updateListeners ( on, @@ -1649,6 +1589,68 @@ function fnInvoker (o) { /* */ +function normalizeChildren ( + children, + ns, + nestedIndex +) { + if (isPrimitive(children)) { + return [createTextVNode(children)] + } + if (Array.isArray(children)) { + var res = []; + for (var i = 0, l = children.length; i < l; i++) { + var c = children[i]; + var last = res[res.length - 1]; + // nested + if (Array.isArray(c)) { + res.push.apply(res, normalizeChildren(c, ns, ((nestedIndex || '') + "_" + i))); + } else if (isPrimitive(c)) { + if (last && last.text) { + last.text += String(c); + } else if (c !== '') { + // convert primitive to vnode + res.push(createTextVNode(c)); + } + } else if (c instanceof VNode) { + if (c.text && last && last.text) { + last.text += c.text; + } else { + // inherit parent namespace + if (ns) { + applyNS(c, ns); + } + // default key for nested array children (likely generated by v-for) + if (c.tag && c.key == null && nestedIndex != null) { + c.key = "__vlist" + nestedIndex + "_" + i + "__"; + } + res.push(c); + } + } + } + return res + } +} + +function createTextVNode (val) { + return new VNode(undefined, undefined, undefined, String(val)) +} + +function applyNS (vnode, ns) { + if (vnode.tag && !vnode.ns) { + vnode.ns = ns; + if (vnode.children) { + for (var i = 0, l = vnode.children.length; i < l; i++) { + applyNS(vnode.children[i], ns); + } + } + } +} + +/* */ + +/* */ + var activeInstance = null; function initLifecycle (vm) { @@ -1830,6 +1832,8 @@ function lifecycleMixin (Vue) { if (vm.$el) { vm.$el.__vue__ = null; } + // invoke destroy hooks on current rendered tree + vm.__patch__(vm._vnode, null); }; } @@ -1950,9 +1954,11 @@ function createFunctionalComponent ( slots: function () { return resolveSlots(children, context); } } ); - vnode.functionalContext = context; - if (data.slot) { - (vnode.data || (vnode.data = {})).slot = data.slot; + if (vnode instanceof VNode) { + vnode.functionalContext = context; + if (data.slot) { + (vnode.data || (vnode.data = {})).slot = data.slot; + } } return vnode } @@ -3324,21 +3330,21 @@ var nlRE = / /g; var ampRE = /&/g; var quoteRE = /"/g; -function decodeAttr (value, shouldDecodeTags, shouldDecodeNewlines) { - if (shouldDecodeTags) { - value = value.replace(ltRE, '<').replace(gtRE, '>'); - } +function decodeAttr (value, shouldDecodeNewlines) { if (shouldDecodeNewlines) { value = value.replace(nlRE, '\n'); } - return value.replace(ampRE, '&').replace(quoteRE, '"') + return value + .replace(ltRE, '<') + .replace(gtRE, '>') + .replace(ampRE, '&') + .replace(quoteRE, '"') } function parseHTML (html, options) { var stack = []; var expectHTML = options.expectHTML; var isUnaryTag$$1 = options.isUnaryTag || no; - var isFromDOM = options.isFromDOM; var index = 0; var last, lastTag; while (html) { @@ -3488,11 +3494,10 @@ function parseHTML (html, options) { var value = args[3] || args[4] || args[5] || ''; attrs[i] = { name: args[1], - value: isFromDOM ? decodeAttr( + value: decodeAttr( value, - options.shouldDecodeTags, options.shouldDecodeNewlines - ) : value + ) }; } @@ -3777,7 +3782,7 @@ var argRE = /:(.*)$/; var modifierRE = /\.[^\.]+/g; var specialNewlineRE = /\u2028|\u2029/g; -var decodeHTMLCached = cached(entities.decodeHTML); +var decodeHTMLCached = cached(he.decode); // configurable state var warn$1; @@ -3814,8 +3819,6 @@ function parse ( parseHTML(template, { expectHTML: options.expectHTML, isUnaryTag: options.isUnaryTag, - isFromDOM: options.isFromDOM, - shouldDecodeTags: options.shouldDecodeTags, shouldDecodeNewlines: options.shouldDecodeNewlines, start: function start (tag, attrs, unary) { // check namespace. @@ -3832,7 +3835,7 @@ function parse ( type: 1, tag: tag, attrsList: attrs, - attrsMap: makeAttrsMap(attrs), + attrsMap: makeAttrsMap(attrs, options.isIE), parent: currentParent, children: [] }; @@ -4182,10 +4185,10 @@ function parseModifiers (name) { } } -function makeAttrsMap (attrs) { +function makeAttrsMap (attrs, isIE) { var map = {}; for (var i = 0, l = attrs.length; i < l; i++) { - if (process.env.NODE_ENV !== 'production' && map[attrs[i].name]) { + if (process.env.NODE_ENV !== 'production' && map[attrs[i].name] && !isIE) { warn$1('duplicate attribute: ' + attrs[i].name); } map[attrs[i].name] = attrs[i].value; @@ -4299,7 +4302,7 @@ function markStaticRoots (node, isInFor) { } if (node.children) { for (var i = 0, l = node.children.length; i < l; i++) { - markStaticRoots(node.children[i], !!node.for); + markStaticRoots(node.children[i], isInFor || !!node.for); } } } @@ -4317,10 +4320,24 @@ function isStatic (node) { !node.if && !node.for && // not v-if or v-for or v-else !isBuiltInTag(node.tag) && // not a built-in isPlatformReservedTag(node.tag) && // not a component + !isDirectChildOfTemplateFor(node) && Object.keys(node).every(isStaticKey) )) } +function isDirectChildOfTemplateFor (node) { + while (node.parent) { + node = node.parent; + if (node.tag !== 'template') { + return false + } + if (node.for) { + return true + } + } + return false +} + /* */ var simplePathRE = /^\s*[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\]|\[\d+\]|\[[A-Za-z_$][\w$]*\])*\s*$/; @@ -4626,7 +4643,7 @@ function genSlot (el) { } function genComponent (el) { - var children = genChildren(el); + var children = el.inlineTemplate ? null : genChildren(el); return ("_h(" + (el.component) + "," + (genData(el)) + (children ? ("," + children) : '') + ")") } @@ -4823,14 +4840,16 @@ function model ( } } if (tag === 'select') { - return genSelect(el, value) + genSelect(el, value); } else if (tag === 'input' && type === 'checkbox') { genCheckboxModel(el, value); } else if (tag === 'input' && type === 'radio') { genRadioModel(el, value); } else { - return genDefaultModel(el, value, modifiers) + genDefaultModel(el, value, modifiers); } + // ensure runtime directive metadata + return true } function genCheckboxModel (el, value) { @@ -4929,10 +4948,6 @@ function genDefaultModel ( } addProp(el, 'value', isNative ? ("_s(" + value + ")") : ("(" + value + ")")); addHandler(el, event, code, null, true); - if (needCompositionGuard) { - // need runtime directive code to help with composition events - return true - } } function genSelect (el, value) { @@ -4944,8 +4959,6 @@ function genSelect (el, value) { ".map(function(o){return \"_value\" in o ? o._value : o.value})" + (el.attrsMap.multiple == null ? '[0]' : ''); addHandler(el, 'change', code, null, true); - // need runtime to help with possible dynamically generated options - return true } function checkOptionWarning (option) { @@ -5183,6 +5196,7 @@ function compile$$1 ( var compiled = compile$1(template, { modules: modules, directives: directives, + preserveWhitespace: options.preserveWhitespace, warn: function (msg) { errors.push(msg); } diff --git a/packages/vue-template-compiler/package.json b/packages/vue-template-compiler/package.json index a44f6a787b7..001b220896b 100644 --- a/packages/vue-template-compiler/package.json +++ b/packages/vue-template-compiler/package.json @@ -1,6 +1,6 @@ { "name": "vue-template-compiler", - "version": "2.0.2", + "version": "2.0.3", "description": "template compiler for Vue 2.0", "main": "index.js", "repository": { @@ -18,7 +18,7 @@ }, "homepage": "https://github.com/vuejs/vue#readme", "dependencies": { - "de-indent": "^1.0.2", - "entities": "^1.1.1" + "he": "^1.1.0", + "de-indent": "^1.0.2" } } diff --git a/src/compiler/codegen/index.js b/src/compiler/codegen/index.js index d11fc7e3b65..fb8f9ef6ac0 100644 --- a/src/compiler/codegen/index.js +++ b/src/compiler/codegen/index.js @@ -230,7 +230,7 @@ function genSlot (el: ASTElement): string { } function genComponent (el: any): string { - const children = genChildren(el) + const children = el.inlineTemplate ? null : genChildren(el) return `_h(${el.component},${genData(el)}${ children ? `,${children}` : '' })` diff --git a/src/compiler/optimizer.js b/src/compiler/optimizer.js index 42e2421527b..03855d6f3e5 100644 --- a/src/compiler/optimizer.js +++ b/src/compiler/optimizer.js @@ -8,7 +8,7 @@ let isPlatformReservedTag const genStaticKeysCached = cached(genStaticKeys) /** - * Goal of the optimizier: walk the generated template AST tree + * Goal of the optimizer: walk the generated template AST tree * and detect sub-trees that are purely static, i.e. parts of * the DOM that never needs to change. * @@ -57,7 +57,7 @@ function markStaticRoots (node: ASTNode, isInFor: boolean) { } if (node.children) { for (let i = 0, l = node.children.length; i < l; i++) { - markStaticRoots(node.children[i], !!node.for) + markStaticRoots(node.children[i], isInFor || !!node.for) } } } @@ -75,6 +75,20 @@ function isStatic (node: ASTNode): boolean { !node.if && !node.for && // not v-if or v-for or v-else !isBuiltInTag(node.tag) && // not a built-in isPlatformReservedTag(node.tag) && // not a component + !isDirectChildOfTemplateFor(node) && Object.keys(node).every(isStaticKey) )) } + +function isDirectChildOfTemplateFor (node: ASTElement): boolean { + while (node.parent) { + node = node.parent + if (node.tag !== 'template') { + return false + } + if (node.for) { + return true + } + } + return false +} diff --git a/src/compiler/parser/entity-decoder.js b/src/compiler/parser/entity-decoder.js index 387cc6ee3bd..66b27f6abdb 100644 --- a/src/compiler/parser/entity-decoder.js +++ b/src/compiler/parser/entity-decoder.js @@ -2,7 +2,7 @@ const decoder = document.createElement('div') -export function decodeHTML (html: string): string { +export function decode (html: string): string { decoder.innerHTML = html return decoder.textContent } diff --git a/src/compiler/parser/html-parser.js b/src/compiler/parser/html-parser.js index f50c89e9cb3..930817173f8 100644 --- a/src/compiler/parser/html-parser.js +++ b/src/compiler/parser/html-parser.js @@ -44,7 +44,23 @@ let IS_REGEX_CAPTURING_BROKEN = false }) // Special Elements (can contain anything) -const isSpecialTag = makeMap('script,style', true) +const isScriptOrStyle = makeMap('script,style', true) +const hasLang = attr => attr.name === 'lang' && attr.value !== 'html' +const isSpecialTag = (tag, isSFC, stack) => { + if (isScriptOrStyle(tag)) { + return true + } + // top-level template that has a pre-processor + if ( + isSFC && + tag === 'template' && + stack.length === 1 && + stack[0].attrs.some(hasLang) + ) { + return true + } + return false +} const reCache = {} @@ -54,27 +70,27 @@ const nlRE = / /g const ampRE = /&/g const quoteRE = /"/g -function decodeAttr (value, shouldDecodeTags, shouldDecodeNewlines) { - if (shouldDecodeTags) { - value = value.replace(ltRE, '<').replace(gtRE, '>') - } +function decodeAttr (value, shouldDecodeNewlines) { if (shouldDecodeNewlines) { value = value.replace(nlRE, '\n') } - return value.replace(ampRE, '&').replace(quoteRE, '"') + return value + .replace(ltRE, '<') + .replace(gtRE, '>') + .replace(ampRE, '&') + .replace(quoteRE, '"') } export function parseHTML (html, options) { const stack = [] const expectHTML = options.expectHTML const isUnaryTag = options.isUnaryTag || no - const isFromDOM = options.isFromDOM let index = 0 let last, lastTag while (html) { last = html // Make sure we're not in a script or style element - if (!lastTag || !isSpecialTag(lastTag)) { + if (!lastTag || !isSpecialTag(lastTag, options.sfc, stack)) { const textEnd = html.indexOf('<') if (textEnd === 0) { // Comment: @@ -218,11 +234,10 @@ export function parseHTML (html, options) { const value = args[3] || args[4] || args[5] || '' attrs[i] = { name: args[1], - value: isFromDOM ? decodeAttr( + value: decodeAttr( value, - options.shouldDecodeTags, options.shouldDecodeNewlines - ) : value + ) } } diff --git a/src/compiler/parser/index.js b/src/compiler/parser/index.js index b41fdf4c236..45a235f576f 100644 --- a/src/compiler/parser/index.js +++ b/src/compiler/parser/index.js @@ -1,6 +1,6 @@ /* @flow */ -import { decodeHTML } from 'entities' +import { decode } from 'he' import { parseHTML } from './html-parser' import { parseText } from './text-parser' import { cached, no, camelize } from 'shared/util' @@ -24,7 +24,7 @@ const argRE = /:(.*)$/ const modifierRE = /\.[^\.]+/g const specialNewlineRE = /\u2028|\u2029/g -const decodeHTMLCached = cached(decodeHTML) +const decodeHTMLCached = cached(decode) // configurable state let warn @@ -61,8 +61,6 @@ export function parse ( parseHTML(template, { expectHTML: options.expectHTML, isUnaryTag: options.isUnaryTag, - isFromDOM: options.isFromDOM, - shouldDecodeTags: options.shouldDecodeTags, shouldDecodeNewlines: options.shouldDecodeNewlines, start (tag, attrs, unary) { // check namespace. @@ -79,7 +77,7 @@ export function parse ( type: 1, tag, attrsList: attrs, - attrsMap: makeAttrsMap(attrs), + attrsMap: makeAttrsMap(attrs, options.isIE), parent: currentParent, children: [] } @@ -132,14 +130,16 @@ export function parse ( } function checkRootConstraints (el) { - if (process.env.NODE_ENV !== 'production') { + if (process.env.NODE_ENV !== 'production' && !warned) { if (el.tag === 'slot' || el.tag === 'template') { + warned = true warn( `Cannot use <${el.tag}> as component root element because it may ` + 'contain multiple nodes:\n' + template ) } if (el.attrsMap.hasOwnProperty('v-for')) { + warned = true warn( 'Cannot use v-for on stateful component root element because ' + 'it renders multiple elements:\n' + template @@ -152,12 +152,12 @@ export function parse ( if (!root) { root = element checkRootConstraints(root) - } else if (process.env.NODE_ENV !== 'production' && !stack.length && !warned) { + } else if (!stack.length) { // allow 2 root elements with v-if and v-else if (root.if && element.else) { checkRootConstraints(element) root.elseBlock = element - } else { + } else if (process.env.NODE_ENV !== 'production' && !warned) { warned = true warn( `Component template should contain exactly one root element:\n\n${template}` @@ -400,7 +400,8 @@ function processAttrs (el) { warn( `${name}="${value}": ` + 'Interpolation inside attributes has been deprecated. ' + - 'Use v-bind or the colon shorthand instead.' + 'Use v-bind or the colon shorthand instead. For example, ' + + 'instead of
, use
.' ) } } @@ -429,10 +430,10 @@ function parseModifiers (name: string): Object | void { } } -function makeAttrsMap (attrs: Array): Object { +function makeAttrsMap (attrs: Array, isIE: ?boolean): Object { const map = {} for (let i = 0, l = attrs.length; i < l; i++) { - if (process.env.NODE_ENV !== 'production' && map[attrs[i].name]) { + if (process.env.NODE_ENV !== 'production' && map[attrs[i].name] && !isIE) { warn('duplicate attribute: ' + attrs[i].name) } map[attrs[i].name] = attrs[i].value diff --git a/src/core/components/keep-alive.js b/src/core/components/keep-alive.js index 0348bc8c717..8268c78d1d1 100644 --- a/src/core/components/keep-alive.js +++ b/src/core/components/keep-alive.js @@ -1,5 +1,5 @@ import { callHook } from 'core/instance/lifecycle' -import { getFirstComponentChild } from 'core/vdom/helpers' +import { getFirstComponentChild } from 'core/vdom/helpers/index' export default { name: 'keep-alive', diff --git a/src/core/index.js b/src/core/index.js index a7a54af2b77..9f945d1996d 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -8,6 +8,6 @@ Object.defineProperty(Vue.prototype, '$isServer', { get: () => config._isServer }) -Vue.version = '2.0.2' +Vue.version = '2.0.3' export default Vue diff --git a/src/core/instance/events.js b/src/core/instance/events.js index 5c664d44ea5..1058f7c64b5 100644 --- a/src/core/instance/events.js +++ b/src/core/instance/events.js @@ -1,7 +1,7 @@ /* @flow */ import { bind, toArray } from '../util/index' -import { updateListeners } from '../vdom/helpers' +import { updateListeners } from '../vdom/helpers/index' export function initEvents (vm: Component) { vm._events = Object.create(null) diff --git a/src/core/instance/lifecycle.js b/src/core/instance/lifecycle.js index f77008927b1..ae20c9c43f4 100644 --- a/src/core/instance/lifecycle.js +++ b/src/core/instance/lifecycle.js @@ -187,6 +187,8 @@ export function lifecycleMixin (Vue: Class) { if (vm.$el) { vm.$el.__vue__ = null } + // invoke destroy hooks on current rendered tree + vm.__patch__(vm._vnode, null) } } diff --git a/src/core/instance/render.js b/src/core/instance/render.js index 86fd6f165a2..48f990b5c8e 100644 --- a/src/core/instance/render.js +++ b/src/core/instance/render.js @@ -2,7 +2,7 @@ import config from '../config' import VNode, { emptyVNode, cloneVNode, cloneVNodes } from '../vdom/vnode' -import { normalizeChildren } from '../vdom/helpers' +import { normalizeChildren } from '../vdom/helpers/index' import { warn, formatComponentName, bind, isObject, toObject, nextTick, resolveAsset, _toString, toNumber, looseEqual, looseIndexOf diff --git a/src/core/observer/index.js b/src/core/observer/index.js index cadabb7ee5f..24d2f9ceb45 100644 --- a/src/core/observer/index.js +++ b/src/core/observer/index.js @@ -186,6 +186,7 @@ export function defineReactive ( */ export function set (obj: Array | Object, key: any, val: any) { if (Array.isArray(obj)) { + obj.length = Math.max(obj.length, key) obj.splice(key, 1, val) return val } diff --git a/src/core/observer/watcher.js b/src/core/observer/watcher.js index f4b69549879..f3aa240e5d3 100644 --- a/src/core/observer/watcher.js +++ b/src/core/observer/watcher.js @@ -204,7 +204,7 @@ export default class Watcher { } /** - * Remove self from all dependencies' subcriber list. + * Remove self from all dependencies' subscriber list. */ teardown () { if (this.active) { diff --git a/src/core/vdom/create-component.js b/src/core/vdom/create-component.js index 0a2721cb1f6..c8f0ba11499 100644 --- a/src/core/vdom/create-component.js +++ b/src/core/vdom/create-component.js @@ -2,7 +2,7 @@ import Vue from '../instance/index' import VNode from './vnode' -import { normalizeChildren } from './helpers' +import { normalizeChildren } from './helpers/index' import { activeInstance, callHook } from '../instance/lifecycle' import { resolveSlots } from '../instance/render' import { createElement } from './create-element' @@ -113,9 +113,11 @@ function createFunctionalComponent ( slots: () => resolveSlots(children, context) } ) - vnode.functionalContext = context - if (data.slot) { - (vnode.data || (vnode.data = {})).slot = data.slot + if (vnode instanceof VNode) { + vnode.functionalContext = context + if (data.slot) { + (vnode.data || (vnode.data = {})).slot = data.slot + } } return vnode } @@ -234,7 +236,7 @@ function resolveAsyncComponent ( } function extractProps (data: VNodeData, Ctor: Class): ?Object { - // we are only extrating raw values here. + // we are only extracting raw values here. // validation and default values are handled in the child // component itself. const propOptions = Ctor.options.props diff --git a/src/core/vdom/create-element.js b/src/core/vdom/create-element.js index 268f88f7a91..f6d47a26ae6 100644 --- a/src/core/vdom/create-element.js +++ b/src/core/vdom/create-element.js @@ -3,7 +3,7 @@ import VNode, { emptyVNode } from './vnode' import config from '../config' import { createComponent } from './create-component' -import { normalizeChildren } from './helpers' +import { normalizeChildren } from './helpers/index' import { warn, resolveAsset } from '../util/index' // wrapper function for providing a more flexible interface diff --git a/src/core/vdom/helpers.js b/src/core/vdom/helpers.js deleted file mode 100644 index f1f014cea1d..00000000000 --- a/src/core/vdom/helpers.js +++ /dev/null @@ -1,148 +0,0 @@ -/* @flow */ - -import { isPrimitive, warn } from '../util/index' -import VNode from './vnode' - -export function normalizeChildren ( - children: any, - ns: string | void, - nestedIndex: number | void -): Array | void { - if (isPrimitive(children)) { - return [createTextVNode(children)] - } - if (Array.isArray(children)) { - const res = [] - for (let i = 0, l = children.length; i < l; i++) { - const c = children[i] - const last = res[res.length - 1] - // nested - if (Array.isArray(c)) { - res.push.apply(res, normalizeChildren(c, ns, i)) - } else if (isPrimitive(c)) { - if (last && last.text) { - last.text += String(c) - } else if (c !== '') { - // convert primitive to vnode - res.push(createTextVNode(c)) - } - } else if (c instanceof VNode) { - if (c.text && last && last.text) { - last.text += c.text - } else { - // inherit parent namespace - if (ns) { - applyNS(c, ns) - } - // default key for nested array children (likely generated by v-for) - if (c.tag && c.key == null && nestedIndex != null) { - c.key = `__vlist_${nestedIndex}_${i}__` - } - res.push(c) - } - } - } - return res - } -} - -function createTextVNode (val) { - return new VNode(undefined, undefined, undefined, String(val)) -} - -function applyNS (vnode, ns) { - if (vnode.tag && !vnode.ns) { - vnode.ns = ns - if (vnode.children) { - for (let i = 0, l = vnode.children.length; i < l; i++) { - applyNS(vnode.children[i], ns) - } - } - } -} - -export function getFirstComponentChild (children: ?Array) { - return children && children.filter(c => c && c.componentOptions)[0] -} - -export function mergeVNodeHook (def: Object, hookKey: string, hook: Function, key: string) { - key = key + hookKey - const injectedHash = def.__injected || (def.__injected = {}) - if (!injectedHash[key]) { - injectedHash[key] = true - const oldHook = def[hookKey] - if (oldHook) { - def[hookKey] = function () { - oldHook.apply(this, arguments) - hook.apply(this, arguments) - } - } else { - def[hookKey] = hook - } - } -} - -export function updateListeners ( - on: Object, - oldOn: Object, - add: Function, - remove: Function, - vm: Component -) { - let name, cur, old, fn, event, capture - for (name in on) { - cur = on[name] - old = oldOn[name] - if (!cur) { - process.env.NODE_ENV !== 'production' && warn( - `Invalid handler for event "${name}": got ` + String(cur), - vm - ) - } else if (!old) { - capture = name.charAt(0) === '!' - event = capture ? name.slice(1) : name - if (Array.isArray(cur)) { - add(event, (cur.invoker = arrInvoker(cur)), capture) - } else { - if (!cur.invoker) { - fn = cur - cur = on[name] = {} - cur.fn = fn - cur.invoker = fnInvoker(cur) - } - add(event, cur.invoker, capture) - } - } else if (cur !== old) { - if (Array.isArray(old)) { - old.length = cur.length - for (let i = 0; i < old.length; i++) old[i] = cur[i] - on[name] = old - } else { - old.fn = cur - on[name] = old - } - } - } - for (name in oldOn) { - if (!on[name]) { - event = name.charAt(0) === '!' ? name.slice(1) : name - remove(event, oldOn[name].invoker) - } - } -} - -function arrInvoker (arr: Array): Function { - return function (ev) { - const single = arguments.length === 1 - for (let i = 0; i < arr.length; i++) { - single ? arr[i](ev) : arr[i].apply(null, arguments) - } - } -} - -function fnInvoker (o: { fn: Function }): Function { - return function (ev) { - const single = arguments.length === 1 - single ? o.fn(ev) : o.fn.apply(null, arguments) - } -} diff --git a/src/core/vdom/helpers/index.js b/src/core/vdom/helpers/index.js new file mode 100644 index 00000000000..e5087409573 --- /dev/null +++ b/src/core/vdom/helpers/index.js @@ -0,0 +1,9 @@ +/* @flow */ + +export * from './merge-hook' +export * from './update-listeners' +export * from './normalize-children' + +export function getFirstComponentChild (children: ?Array): ?VNodeWithData { + return children && children.filter(c => c && c.componentOptions)[0] +} diff --git a/src/core/vdom/helpers/merge-hook.js b/src/core/vdom/helpers/merge-hook.js new file mode 100644 index 00000000000..b23a4d9841c --- /dev/null +++ b/src/core/vdom/helpers/merge-hook.js @@ -0,0 +1,18 @@ +/* @flow */ + +export function mergeVNodeHook (def: Object, hookKey: string, hook: Function, key: string) { + key = key + hookKey + const injectedHash = def.__injected || (def.__injected = {}) + if (!injectedHash[key]) { + injectedHash[key] = true + const oldHook = def[hookKey] + if (oldHook) { + def[hookKey] = function () { + oldHook.apply(this, arguments) + hook.apply(this, arguments) + } + } else { + def[hookKey] = hook + } + } +} diff --git a/src/core/vdom/helpers/normalize-children.js b/src/core/vdom/helpers/normalize-children.js new file mode 100644 index 00000000000..207ddbfdb67 --- /dev/null +++ b/src/core/vdom/helpers/normalize-children.js @@ -0,0 +1,62 @@ +/* @flow */ + +import { isPrimitive } from 'core/util/index' +import VNode from 'core/vdom/vnode' + +export function normalizeChildren ( + children: any, + ns: string | void, + nestedIndex: string | void +): Array | void { + if (isPrimitive(children)) { + return [createTextVNode(children)] + } + if (Array.isArray(children)) { + const res = [] + for (let i = 0, l = children.length; i < l; i++) { + const c = children[i] + const last = res[res.length - 1] + // nested + if (Array.isArray(c)) { + res.push.apply(res, normalizeChildren(c, ns, `${nestedIndex || ''}_${i}`)) + } else if (isPrimitive(c)) { + if (last && last.text) { + last.text += String(c) + } else if (c !== '') { + // convert primitive to vnode + res.push(createTextVNode(c)) + } + } else if (c instanceof VNode) { + if (c.text && last && last.text) { + last.text += c.text + } else { + // inherit parent namespace + if (ns) { + applyNS(c, ns) + } + // default key for nested array children (likely generated by v-for) + if (c.tag && c.key == null && nestedIndex != null) { + c.key = `__vlist${nestedIndex}_${i}__` + } + res.push(c) + } + } + } + return res + } +} + +function createTextVNode (val) { + return new VNode(undefined, undefined, undefined, String(val)) +} + +function applyNS (vnode, ns) { + if (vnode.tag && !vnode.ns) { + vnode.ns = ns + if (vnode.children) { + for (let i = 0, l = vnode.children.length; i < l; i++) { + applyNS(vnode.children[i], ns) + } + } + } +} diff --git a/src/core/vdom/helpers/update-listeners.js b/src/core/vdom/helpers/update-listeners.js new file mode 100644 index 00000000000..3feef8cbe39 --- /dev/null +++ b/src/core/vdom/helpers/update-listeners.js @@ -0,0 +1,68 @@ +/* @flow */ + +import { warn } from 'core/util/index' + +export function updateListeners ( + on: Object, + oldOn: Object, + add: Function, + remove: Function, + vm: Component +) { + let name, cur, old, fn, event, capture + for (name in on) { + cur = on[name] + old = oldOn[name] + if (!cur) { + process.env.NODE_ENV !== 'production' && warn( + `Invalid handler for event "${name}": got ` + String(cur), + vm + ) + } else if (!old) { + capture = name.charAt(0) === '!' + event = capture ? name.slice(1) : name + if (Array.isArray(cur)) { + add(event, (cur.invoker = arrInvoker(cur)), capture) + } else { + if (!cur.invoker) { + fn = cur + cur = on[name] = {} + cur.fn = fn + cur.invoker = fnInvoker(cur) + } + add(event, cur.invoker, capture) + } + } else if (cur !== old) { + if (Array.isArray(old)) { + old.length = cur.length + for (let i = 0; i < old.length; i++) old[i] = cur[i] + on[name] = old + } else { + old.fn = cur + on[name] = old + } + } + } + for (name in oldOn) { + if (!on[name]) { + event = name.charAt(0) === '!' ? name.slice(1) : name + remove(event, oldOn[name].invoker) + } + } +} + +function arrInvoker (arr: Array): Function { + return function (ev) { + const single = arguments.length === 1 + for (let i = 0; i < arr.length; i++) { + single ? arr[i](ev) : arr[i].apply(null, arguments) + } + } +} + +function fnInvoker (o: { fn: Function }): Function { + return function (ev) { + const single = arguments.length === 1 + single ? o.fn(ev) : o.fn.apply(null, arguments) + } +} diff --git a/src/core/vdom/modules/directives.js b/src/core/vdom/modules/directives.js index 513afe51ebc..230bbebab4b 100644 --- a/src/core/vdom/modules/directives.js +++ b/src/core/vdom/modules/directives.js @@ -1,7 +1,7 @@ /* @flow */ import { resolveAsset } from 'core/util/options' -import { mergeVNodeHook } from 'core/vdom/helpers' +import { mergeVNodeHook } from 'core/vdom/helpers/index' import { emptyNode } from 'core/vdom/patch' export default { @@ -90,23 +90,17 @@ function normalizeDirectives ( let i, dir for (i = 0; i < dirs.length; i++) { dir = dirs[i] - res[getRawDirName(dir)] = dir if (!dir.modifiers) { dir.modifiers = emptyModifiers } + res[getRawDirName(dir)] = dir dir.def = resolveAsset(vm.$options, 'directives', dir.name, true) } return res } function getRawDirName (dir: VNodeDirective): string { - return dir.rawName || ( - dir.name + ( - dir.modifiers - ? '.' + Object.keys(dir.modifiers).join('.') - : '' - ) - ) + return dir.rawName || `${dir.name}.${Object.keys(dir.modifiers || {}).join('.')}` } function callHook (dir, hook, vnode, oldVnode) { diff --git a/src/core/vdom/patch.js b/src/core/vdom/patch.js index 6d6444b354e..fc4065d8228 100644 --- a/src/core/vdom/patch.js +++ b/src/core/vdom/patch.js @@ -202,12 +202,6 @@ export function createPatchFunction (backend) { if (isDef(i = data.hook) && isDef(i = i.destroy)) i(vnode) for (i = 0; i < cbs.destroy.length; ++i) cbs.destroy[i](vnode) } - if (isDef(i = vnode.child) && ( - !data.keepAlive || - vnode.context._isBeingDestroyed - )) { - invokeDestroyHook(i._vnode) - } if (isDef(i = vnode.children)) { for (j = 0; j < vnode.children.length; ++j) { invokeDestroyHook(vnode.children[j]) @@ -457,6 +451,11 @@ export function createPatchFunction (backend) { } return function patch (oldVnode, vnode, hydrating, removeOnly) { + if (!vnode) { + if (oldVnode) invokeDestroyHook(oldVnode) + return + } + let elm, parent let isInitialPatch = false const insertedVnodeQueue = [] diff --git a/src/core/vdom/vnode.js b/src/core/vdom/vnode.js index c7ef80bd71d..f228857e1c8 100644 --- a/src/core/vdom/vnode.js +++ b/src/core/vdom/vnode.js @@ -12,7 +12,7 @@ export default class VNode { key: string | number | void; componentOptions: VNodeComponentOptions | void; child: Component | void; // component instance - parent: VNode | void; // compoennt placeholder node + parent: VNode | void; // component placeholder node raw: boolean; // contains raw HTML? (server only) isStatic: boolean; // hoisted static node isRootInsert: boolean; // necessary for enter transition check diff --git a/src/entries/web-compiler.js b/src/entries/web-compiler.js index 432ee4beaa2..bf7a2eba0f3 100644 --- a/src/entries/web-compiler.js +++ b/src/entries/web-compiler.js @@ -24,6 +24,7 @@ export function compile ( const compiled = baseCompile(template, { modules, directives, + preserveWhitespace: options.preserveWhitespace, warn: msg => { errors.push(msg) } diff --git a/src/entries/web-runtime-with-compiler.js b/src/entries/web-runtime-with-compiler.js index cf8eb69dff8..55e28c2efd5 100644 --- a/src/entries/web-runtime-with-compiler.js +++ b/src/entries/web-runtime-with-compiler.js @@ -3,7 +3,7 @@ import Vue from './web-runtime' import { warn, cached } from 'core/util/index' import { query } from 'web/util/index' -import { shouldDecodeTags, shouldDecodeNewlines } from 'web/util/compat' +import { shouldDecodeNewlines } from 'web/util/compat' import { compileToFunctions } from 'web/compiler/index' const idToTemplate = cached(id => { @@ -30,15 +30,12 @@ Vue.prototype.$mount = function ( // resolve template/el and convert to render function if (!options.render) { let template = options.template - let isFromDOM = false if (template) { if (typeof template === 'string') { if (template.charAt(0) === '#') { - isFromDOM = true template = idToTemplate(template) } } else if (template.nodeType) { - isFromDOM = true template = template.innerHTML } else { if (process.env.NODE_ENV !== 'production') { @@ -47,14 +44,11 @@ Vue.prototype.$mount = function ( return this } } else if (el) { - isFromDOM = true template = getOuterHTML(el) } if (template) { const { render, staticRenderFns } = compileToFunctions(template, { warn, - isFromDOM, - shouldDecodeTags, shouldDecodeNewlines, delimiters: options.delimiters }, this) diff --git a/src/platforms/web/compiler/directives/model.js b/src/platforms/web/compiler/directives/model.js index a59752e6b10..3dd2c45ea05 100644 --- a/src/platforms/web/compiler/directives/model.js +++ b/src/platforms/web/compiler/directives/model.js @@ -2,6 +2,7 @@ import { isIE } from 'core/util/env' import { addHandler, addProp, getBindingAttr } from 'compiler/helpers' +import parseModel from 'web/util/model' let warn @@ -25,14 +26,16 @@ export default function model ( } } if (tag === 'select') { - return genSelect(el, value) + genSelect(el, value) } else if (tag === 'input' && type === 'checkbox') { genCheckboxModel(el, value) } else if (tag === 'input' && type === 'radio') { genRadioModel(el, value) } else { - return genDefaultModel(el, value, modifiers) + genDefaultModel(el, value, modifiers) } + // ensure runtime directive metadata + return true } function genCheckboxModel (el: ASTElement, value: string) { @@ -77,7 +80,7 @@ function genRadioModel (el: ASTElement, value: string) { } const valueBinding = getBindingAttr(el, 'value') || 'null' addProp(el, 'checked', `_q(${value},${valueBinding})`) - addHandler(el, 'change', `${value}=${valueBinding}`, null, true) + addHandler(el, 'change', genAssignmentCode(value, valueBinding), null, true) } function genDefaultModel ( @@ -112,8 +115,8 @@ function genDefaultModel ( ? `$event.target.value${trim ? '.trim()' : ''}` : `$event` let code = number || type === 'number' - ? `${value}=_n(${valueExpression})` - : `${value}=${valueExpression}` + ? genAssignmentCode(value, `_n(${valueExpression})`) + : genAssignmentCode(value, valueExpression) if (isNative && needCompositionGuard) { code = `if($event.target.composing)return;${code}` } @@ -128,23 +131,20 @@ function genDefaultModel ( } addProp(el, 'value', isNative ? `_s(${value})` : `(${value})`) addHandler(el, event, code, null, true) - if (needCompositionGuard) { - // need runtime directive code to help with composition events - return true - } } function genSelect (el: ASTElement, value: string) { if (process.env.NODE_ENV !== 'production') { el.children.some(checkOptionWarning) } - const code = `${value}=Array.prototype.filter` + + + const assignment = `Array.prototype.filter` + `.call($event.target.options,function(o){return o.selected})` + `.map(function(o){return "_value" in o ? o._value : o.value})` + (el.attrsMap.multiple == null ? '[0]' : '') + + const code = genAssignmentCode(value, assignment) addHandler(el, 'change', code, null, true) - // need runtime to help with possible dynamically generated options - return true } function checkOptionWarning (option: any): boolean { @@ -160,3 +160,15 @@ function checkOptionWarning (option: any): boolean { } return false } + +function genAssignmentCode (value: string, assignment: string): string { + const modelRs = parseModel(value) + if (modelRs.idx === null) { + return `${value}=${assignment}` + } else { + return `var $$exp = ${modelRs.exp}, $$idx = ${modelRs.idx};` + + `if (!Array.isArray($$exp)){` + + `${value}=${assignment}}` + + `else{$$exp.splice($$idx, 1, ${assignment})}` + } +} diff --git a/src/platforms/web/runtime/components/transition.js b/src/platforms/web/runtime/components/transition.js index 321ef4038d7..93c5daadf06 100644 --- a/src/platforms/web/runtime/components/transition.js +++ b/src/platforms/web/runtime/components/transition.js @@ -5,7 +5,7 @@ import { warn } from 'core/util/index' import { camelize, extend } from 'shared/util' -import { mergeVNodeHook, getFirstComponentChild } from 'core/vdom/helpers' +import { mergeVNodeHook, getFirstComponentChild } from 'core/vdom/helpers/index' export const transitionProps = { name: String, @@ -22,7 +22,7 @@ export const transitionProps = { } // in case the child is also an abstract component, e.g. -// we want to recrusively retrieve the real component to be rendered +// we want to recursively retrieve the real component to be rendered function getRealChild (vnode: ?VNode): ?VNode { const compOptions = vnode && vnode.componentOptions if (compOptions && compOptions.Ctor.options.abstract) { diff --git a/src/platforms/web/runtime/directives/model.js b/src/platforms/web/runtime/directives/model.js index 0c67c9abf46..239f0b06a0b 100644 --- a/src/platforms/web/runtime/directives/model.js +++ b/src/platforms/web/runtime/directives/model.js @@ -40,7 +40,10 @@ export default { if (isIE || isEdge) { setTimeout(cb, 0) } - } else if (vnode.tag === 'textarea' || el.type === 'text') { + } else if ( + (vnode.tag === 'textarea' || el.type === 'text') && + !binding.modifiers.lazy + ) { if (!isAndroid) { el.addEventListener('compositionstart', onCompositionStart) el.addEventListener('compositionend', onCompositionEnd) @@ -56,11 +59,11 @@ export default { setSelected(el, binding, vnode.context) // in case the options rendered by v-for have changed, // it's possible that the value is out-of-sync with the rendered options. - // detect such cases and filter out values that no longer has a matchig + // detect such cases and filter out values that no longer has a matching // option in the DOM. const needReset = el.multiple ? binding.value.some(v => hasNoMatchingOption(v, el.options)) - : hasNoMatchingOption(binding.value, el.options) + : binding.value !== binding.oldValue && hasNoMatchingOption(binding.value, el.options) if (needReset) { trigger(el, 'change') } diff --git a/src/platforms/web/runtime/modules/events.js b/src/platforms/web/runtime/modules/events.js index 40c15530ec0..cf0c5441d99 100644 --- a/src/platforms/web/runtime/modules/events.js +++ b/src/platforms/web/runtime/modules/events.js @@ -1,7 +1,7 @@ // skip type checking this file because we need to attach private properties // to elements -import { updateListeners } from 'core/vdom/helpers' +import { updateListeners } from 'core/vdom/helpers/index' function updateDOMListeners (oldVnode, vnode) { if (!oldVnode.data.on && !vnode.data.on) { diff --git a/src/platforms/web/runtime/modules/transition.js b/src/platforms/web/runtime/modules/transition.js index cb5ceb8a458..79bc5fc280d 100644 --- a/src/platforms/web/runtime/modules/transition.js +++ b/src/platforms/web/runtime/modules/transition.js @@ -2,7 +2,7 @@ import { inBrowser, isIE9 } from 'core/util/index' import { cached, extend } from 'shared/util' -import { mergeVNodeHook } from 'core/vdom/helpers' +import { mergeVNodeHook } from 'core/vdom/helpers/index' import { activeInstance } from 'core/instance/lifecycle' import { nextFrame, diff --git a/src/platforms/web/runtime/transition-util.js b/src/platforms/web/runtime/transition-util.js index 4883cd6fc8c..416d72cfbc0 100644 --- a/src/platforms/web/runtime/transition-util.js +++ b/src/platforms/web/runtime/transition-util.js @@ -131,6 +131,10 @@ export function getTransitionInfo (el: Element, expectedType?: ?string): { } function getTimeout (delays: Array, durations: Array): number { + while (delays.length < durations.length) { + delays = delays.concat(delays) + } + return Math.max.apply(null, durations.map((d, i) => { return toMs(d) + toMs(delays[i]) })) diff --git a/src/platforms/web/util/compat.js b/src/platforms/web/util/compat.js index 1978a892965..3ee0019e622 100644 --- a/src/platforms/web/util/compat.js +++ b/src/platforms/web/util/compat.js @@ -9,13 +9,6 @@ function shouldDecode (content: string, encoded: string): boolean { return div.innerHTML.indexOf(encoded) > 0 } -// According to -// https://w3c.github.io/DOM-Parsing/#dfn-serializing-an-attribute-value -// when serializing innerHTML, <, >, ", & should be encoded as entities. -// However, only some browsers, e.g. PhantomJS, encodes < and >. -// this causes problems with the in-browser parser. -export const shouldDecodeTags = inBrowser ? shouldDecode('>', '>') : false - // #3663 // IE encodes newlines inside attribute values while other browsers don't export const shouldDecodeNewlines = inBrowser ? shouldDecode('\n', ' ') : false diff --git a/src/platforms/web/util/model.js b/src/platforms/web/util/model.js new file mode 100644 index 00000000000..fdf6a5ac174 --- /dev/null +++ b/src/platforms/web/util/model.js @@ -0,0 +1,84 @@ +/* @flow */ + +let len, str, chr, index, expressionPos, expressionEndPos + +/** + * parse directive model to do the array update transform. a[idx] = val => $$a.splice($$idx, 1, val) + * + * for loop possible cases: + * + * - test + * - test[idx] + * - test[test1[idx]] + * - test["a"][idx] + * - xxx.test[a[a].test1[idx]] + * - test.xxx.a["asa"][test1[idx]] + * + */ + +export default function parseModel (val: string): Object { + str = val + len = str.length + index = expressionPos = expressionEndPos = 0 + + if (val.indexOf('[') < 0) { + return { + exp: val, + idx: null + } + } + + while (!eof()) { + chr = next() + if (isStringStart(chr)) { + parseString(chr) + } else if (chr === 0x5B) { + parseBracket(chr) + } + } + + return { + exp: val.substring(0, expressionPos), + idx: val.substring(expressionPos + 1, expressionEndPos) + } +} + +function next (): number { + return str.charCodeAt(++index) +} + +function eof (): boolean { + return index >= len +} + +function isStringStart (chr: number): boolean { + return chr === 0x22 || chr === 0x27 +} + +function parseBracket (chr: number): void { + let inBracket = 1 + expressionPos = index + while (!eof()) { + chr = next() + if (isStringStart(chr)) { + parseString(chr) + continue + } + if (chr === 0x5B) inBracket++ + if (chr === 0x5D) inBracket-- + if (inBracket === 0) { + expressionEndPos = index + break + } + } +} + +function parseString (chr: number): void { + const stringQuote = chr + while (!eof()) { + chr = next() + if (chr === stringQuote) { + break + } + } +} diff --git a/src/server/create-renderer.js b/src/server/create-renderer.js index 7a7e2c8e3ab..ae0e9e4475c 100644 --- a/src/server/create-renderer.js +++ b/src/server/create-renderer.js @@ -21,7 +21,7 @@ export function createRenderer ({ } { if (process.env.VUE_ENV !== 'server') { warn( - 'You are using createRenderer without setting VUE_ENV enviroment variable to "server". ' + + 'You are using createRenderer without setting VUE_ENV environment variable to "server". ' + 'It is recommended to set VUE_ENV=server this will help rendering performance, ' + 'by turning data observation off.' ) diff --git a/src/server/render-stream.js b/src/server/render-stream.js index 939c36a58f0..3531f6d0a32 100644 --- a/src/server/render-stream.js +++ b/src/server/render-stream.js @@ -1,7 +1,7 @@ /* @flow */ /** - * Original RenderStream implmentation by Sasha Aickin (@aickin) + * Original RenderStream implementation by Sasha Aickin (@aickin) * Licensed under the Apache License, Version 2.0 * http://www.apache.org/licenses/LICENSE-2.0 * diff --git a/src/server/render.js b/src/server/render.js index 660b97799b5..8b755da0743 100644 --- a/src/server/render.js +++ b/src/server/render.js @@ -1,6 +1,6 @@ /* @flow */ -import { encodeHTML } from 'entities' +import { escape } from 'he' import { compileToFunctions } from 'web/compiler/index' import { createComponentInstanceForVnode } from 'core/vdom/create-component' @@ -112,7 +112,7 @@ export function createRenderFunction ( } else if (node.isComment) { write(``, next) } else { - write(node.raw ? node.text : encodeHTML(String(node.text)), next) + write(node.raw ? node.text : escape(String(node.text)), next) } } } diff --git a/src/sfc/parser.js b/src/sfc/parser.js index 3cb962b551e..6b8530a8283 100644 --- a/src/sfc/parser.js +++ b/src/sfc/parser.js @@ -92,7 +92,8 @@ export function parseComponent ( parseHTML(content, { start, - end + end, + sfc: true }) return sfc diff --git a/test/e2e/specs/grid.js b/test/e2e/specs/grid.js index ad47c8ff893..7c273359e1b 100644 --- a/test/e2e/specs/grid.js +++ b/test/e2e/specs/grid.js @@ -82,6 +82,12 @@ module.exports = { { name: 'Chuck Norris', power: Infinity } ]) + browser + .clearValue('input[name="query"]') + .assert.count('p', 0) + .setValue('input[name="query"]', 'stringthatdoesnotexistanywhere') + .assert.count('p', 1) + browser.end() function assertTable (data) { diff --git a/test/ssr/ssr-bundle-render.spec.js b/test/ssr/ssr-bundle-render.spec.js index f35ca7901a2..c28ce636e29 100644 --- a/test/ssr/ssr-bundle-render.spec.js +++ b/test/ssr/ssr-bundle-render.spec.js @@ -37,7 +37,7 @@ describe('SSR: bundle renderer', () => { const context = { url: '/test' } renderer.renderToString(context, (err, res) => { expect(err).toBeNull() - expect(res).toBe('
/test
') + expect(res).toBe('
/test
') expect(context.msg).toBe('hello') done() }) @@ -53,7 +53,7 @@ describe('SSR: bundle renderer', () => { res += chunk.toString() }) stream.on('end', () => { - expect(res).toBe('
/test
') + expect(res).toBe('
/test
') expect(context.msg).toBe('hello') done() }) @@ -99,7 +99,7 @@ describe('SSR: bundle renderer', () => { } } createRenderer('cache.js', renderer => { - const expected = '
/test
' + const expected = '
/test
' const key = 'app::1' renderer.renderToString((err, res) => { expect(err).toBeNull() @@ -142,7 +142,7 @@ describe('SSR: bundle renderer', () => { } } createRenderer('cache.js', renderer => { - const expected = '
/test
' + const expected = '
/test
' const key = 'app::1' renderer.renderToString((err, res) => { expect(err).toBeNull() diff --git a/test/ssr/ssr-env.spec.js b/test/ssr/ssr-env.spec.js index a16b975c165..5cc27724951 100644 --- a/test/ssr/ssr-env.spec.js +++ b/test/ssr/ssr-env.spec.js @@ -39,7 +39,7 @@ describe('SSR: VUE_ENV=server', () => { it('should warn when not set', () => { process.env.VUE_ENV = '' createRenderer() - expect('You are using createRenderer without setting VUE_ENV enviroment').toHaveBeenWarned() + expect('You are using createRenderer without setting VUE_ENV environment').toHaveBeenWarned() process.env.VUE_ENV = 'server' }) }) diff --git a/test/ssr/ssr-string.spec.js b/test/ssr/ssr-string.spec.js index cee8ee3866c..c9d7965f4cd 100644 --- a/test/ssr/ssr-string.spec.js +++ b/test/ssr/ssr-string.spec.js @@ -94,7 +94,7 @@ describe('SSR: renderToString', () => { bar: 'rendering' } }, result => { - expect(result).toContain('
server side <span>rendering</span>
') + expect(result).toContain('
server side <span>rendering</span>
') done() }) }) @@ -118,7 +118,7 @@ describe('SSR: renderToString', () => { text: 'foo' } }, result => { - expect(result).toContain('
<span>foo</span>
') + expect(result).toContain('
<span>foo</span>
') done() }) }) diff --git a/test/unit/features/directives/model-component.spec.js b/test/unit/features/directives/model-component.spec.js index 1739e7803b2..622deed74f4 100644 --- a/test/unit/features/directives/model-component.spec.js +++ b/test/unit/features/directives/model-component.spec.js @@ -2,14 +2,18 @@ import Vue from 'vue' describe('Directive v-model component', () => { it('should work', done => { + const spy = jasmine.createSpy() const vm = new Vue({ data: { - msg: 'hello' + msg: ['hello'] + }, + watch: { + msg: spy }, template: `

{{ msg }}

- +
@@ -40,7 +44,8 @@ describe('Directive v-model component', () => { input.value = 'world' triggerEvent(input, 'input') }).then(() => { - expect(vm.msg).toBe('world') + expect(vm.msg).toEqual(['world']) + expect(spy).toHaveBeenCalled() }).then(() => { document.body.removeChild(vm.$el) vm.$destroy() diff --git a/test/unit/features/directives/model-radio.spec.js b/test/unit/features/directives/model-radio.spec.js index 175f0cc87a3..b52456d4e6b 100644 --- a/test/unit/features/directives/model-radio.spec.js +++ b/test/unit/features/directives/model-radio.spec.js @@ -85,6 +85,46 @@ describe('Directive v-model radio', () => { }).then(done) }) + it('multiple radios ', (done) => { + const spy = jasmine.createSpy() + const vm = new Vue({ + data: { + selections: ['a', '1'], + radioList: [ + { + name: 'questionA', + data: ['a', 'b', 'c'] + }, + { + name: 'questionB', + data: ['1', '2'] + } + ] + }, + watch: { + selections: spy + }, + template: + '
' + + '
' + + '
' + + '' + + '' + + '' + + '' + + '
' + + '
' + + '
' + }).$mount() + document.body.appendChild(vm.$el) + var inputs = vm.$el.getElementsByTagName('input') + inputs[1].click() + waitForUpdate(() => { + expect(vm.selections).toEqual(['b', '1']) + expect(spy).toHaveBeenCalled() + }).then(done) + }) + it('warn inline checked', () => { const vm = new Vue({ template: ``, diff --git a/test/unit/features/directives/model-select.spec.js b/test/unit/features/directives/model-select.spec.js index 9b6092f26e1..7de1f0d3fd2 100644 --- a/test/unit/features/directives/model-select.spec.js +++ b/test/unit/features/directives/model-select.spec.js @@ -161,6 +161,32 @@ describe('Directive v-model select', () => { }).then(done) }) + it('should work with select which has no default selected options', (done) => { + const spy = jasmine.createSpy() + const vm = new Vue({ + data: { + id: 4, + list: [1, 2, 3], + testChange: 5 + }, + template: + '
' + + '' + + '{{testChange}}' + + '
', + methods: { + test: spy + } + }).$mount() + document.body.appendChild(vm.$el) + vm.testChange = 10 + waitForUpdate(() => { + expect(spy.calls.count()).toBe(0) + }).then(done) + }) + it('multiple', done => { const vm = new Vue({ data: { @@ -237,6 +263,44 @@ describe('Directive v-model select', () => { }).then(done) }) + it('multiple selects', (done) => { + const spy = jasmine.createSpy() + const vm = new Vue({ + data: { + selections: ['', ''], + selectBoxes: [ + [ + { value: 'foo', text: 'foo' }, + { value: 'bar', text: 'bar' } + ], + [ + { value: 'day', text: 'day' }, + { value: 'night', text: 'night' } + ] + ] + }, + watch: { + selections: spy + }, + template: + '
' + + '' + + '{{selections}}' + + '
' + }).$mount() + document.body.appendChild(vm.$el) + var selects = vm.$el.getElementsByTagName('select') + var select0 = selects[0] + select0.options[0].selected = true + triggerEvent(select0, 'change') + waitForUpdate(() => { + expect(spy).toHaveBeenCalled() + expect(vm.selections).toEqual(['foo', '']) + }).then(done) + }) + it('should warn inline selected', () => { const vm = new Vue({ data: { diff --git a/test/unit/features/directives/model-text.spec.js b/test/unit/features/directives/model-text.spec.js index 23ccb30e097..f4ce9e451a7 100644 --- a/test/unit/features/directives/model-text.spec.js +++ b/test/unit/features/directives/model-text.spec.js @@ -64,6 +64,47 @@ describe('Directive v-model text', () => { expect(vm.test).toBe('what') }) + it('multiple inputs', (done) => { + const spy = jasmine.createSpy() + const vm = new Vue({ + data: { + selections: [[1, 2, 3], [4, 5]], + inputList: [ + { + name: 'questionA', + data: ['a', 'b', 'c'] + }, + { + name: 'questionB', + data: ['1', '2'] + } + ] + }, + watch: { + selections: spy + }, + template: + '
' + + '
' + + '
' + + '' + + '' + + '' + + '' + + '
' + + '
' + + '{{selections}}' + + '
' + }).$mount() + var inputs = vm.$el.getElementsByTagName('input') + inputs[1].value = 'test' + triggerEvent(inputs[1], 'input') + waitForUpdate(() => { + expect(spy).toHaveBeenCalled() + expect(vm.selections).toEqual([[1, 'test', 3], [4, 5]]) + }).then(done) + }) + if (isIE9) { it('IE9 selectionchange', done => { const vm = new Vue({ diff --git a/test/unit/modules/compiler/parser.spec.js b/test/unit/modules/compiler/parser.spec.js index 1ca9b3796c8..4d78bfe5014 100644 --- a/test/unit/modules/compiler/parser.spec.js +++ b/test/unit/modules/compiler/parser.spec.js @@ -1,6 +1,7 @@ import { parse } from 'compiler/parser/index' import { extend } from 'shared/util' import { baseOptions } from 'web/compiler/index' +import { isIE } from 'core/util/env' describe('parser', () => { it('simple element', () => { @@ -320,10 +321,12 @@ describe('parser', () => { expect('Interpolation inside attributes has been deprecated').toHaveBeenWarned() }) - it('duplicate attribute', () => { - parse('

hello world

', baseOptions) - expect('duplicate attribute').toHaveBeenWarned() - }) + if (!isIE) { + it('duplicate attribute', () => { + parse('

hello world

', baseOptions) + expect('duplicate attribute').toHaveBeenWarned() + }) + } it('custom delimiter', () => { const ast = parse('

{msg}

', extend({ delimiters: ['{', '}'] }, baseOptions)) diff --git a/test/unit/modules/sfc/sfc-parser.spec.js b/test/unit/modules/sfc/sfc-parser.spec.js index 79b891fa8dd..e98230dfa1c 100644 --- a/test/unit/modules/sfc/sfc-parser.spec.js +++ b/test/unit/modules/sfc/sfc-parser.spec.js @@ -63,4 +63,14 @@ describe('Single File Component parser', () => { expect(res.script.content).toBe(Array(3 + 1).join('//\n') + '\nexport default {}\n') expect(res.styles[0].content).toBe(Array(6 + 1).join('\n') + '\nh1 { color: red }\n') }) + + it('should handle template blocks with lang as special text', () => { + const res = parseComponent(` + + `) + expect(res.template.content.trim()).toBe(`div\n h1(v-if='1 < 2') hello`) + }) }) diff --git a/test/unit/modules/vdom/modules/class.spec.js b/test/unit/modules/vdom/modules/class.spec.js index e380d46114d..174e934d4ac 100644 --- a/test/unit/modules/vdom/modules/class.spec.js +++ b/test/unit/modules/vdom/modules/class.spec.js @@ -2,7 +2,7 @@ import { patch } from 'web/runtime/patch' import VNode from 'core/vdom/vnode' describe('vdom class module', () => { - it('shuold create an element with staticClass', () => { + it('should create an element with staticClass', () => { const vnode = new VNode('p', { staticClass: 'class1' }) const elm = patch(null, vnode) expect(elm).toHaveClass('class1')