diff --git a/src/images/devtools-storage-chrome.png b/src/images/devtools-storage-chrome.png new file mode 100644 index 0000000000..9271dd57e5 Binary files /dev/null and b/src/images/devtools-storage-chrome.png differ diff --git a/src/images/devtools-storage-edge.png b/src/images/devtools-storage-edge.png new file mode 100644 index 0000000000..d05024b643 Binary files /dev/null and b/src/images/devtools-storage-edge.png differ diff --git a/src/images/devtools-storage.png b/src/images/devtools-storage.png new file mode 100644 index 0000000000..44e2998185 Binary files /dev/null and b/src/images/devtools-storage.png differ diff --git a/src/v2/api/index.md b/src/v2/api/index.md index 21b337ea90..f855cdbe40 100644 --- a/src/v2/api/index.md +++ b/src/v2/api/index.md @@ -1590,14 +1590,139 @@ type: api - Si l'évènement et la fonction de rappel sont fournis, supprime l'écouteur uniquement pour cet événément et cette fonction de rappel spécifique. -### vm.$emit( event, [...args] ) +### vm.$emit( eventName, [...args] ) - **Arguments :** - - `{string} évènement` + - `{string} nom d'évènement` - `[...arguments]` Déclenche un évènement sur l'instance actuelle. Tous les arguments additionnels sont passés à la fonction de rappel de l'écouteur. +- **Exemples:** + + Utiliser `$emit` avec un nom d'évènement : + + ```js + Vue.component('welcome-button', { + template: ` + + ` + }) + ``` + ```html +
Cette page est en cours de traduction. Pour nous aider, vous pouvez participer sur le dépôt GitHub dédié de Vuejs-FR.
If you are developing applications with Vue, then you need to watch out for memory leaks. This issue is especially important in Single Page Applications (SPAs) because by design, users should not have to refresh their browser when using an SPA, so it is up to the JavaScript application to clean up components and make sure that garbage collection takes place as expected.
Memory leaks in Vue applications do not typically come from Vue itself, rather they can happen when incorporating other libraries into an application. @@ -166,4 +166,4 @@ deactivated: function () { ## Wrapping Up -Vue makes it very easy to develop amazing, reactive Javascript applications, but you still need to be careful about memory leaks. These leaks will often occur when using additional 3rd Party libraries that manipulate the DOM outside of Vue. Make sure to test your application for memory leaks and take appropriate steps to clean up components where necessary. \ No newline at end of file +Vue makes it very easy to develop amazing, reactive JavaScript applications, but you still need to be careful about memory leaks. These leaks will often occur when using additional 3rd Party libraries that manipulate the DOM outside of Vue. Make sure to test your application for memory leaks and take appropriate steps to clean up components where necessary. \ No newline at end of file diff --git a/src/v2/cookbook/client-side-storage.md b/src/v2/cookbook/client-side-storage.md new file mode 100644 index 0000000000..646edd808f --- /dev/null +++ b/src/v2/cookbook/client-side-storage.md @@ -0,0 +1,176 @@ +--- +title: Client-Side Storage (EN) +type: cookbook +order: 11 +--- + +## Base Example + +Cette page est en cours de traduction. Pour nous aider, vous pouvez participer sur le dépôt GitHub dédié de Vuejs-FR.
Client-side storage is an excellent way to quickly add performance gains to an application. By storing data on the browser itself, you can skip fetching information from the server every time the user needs it. While especially useful when offline, even online users will benefit from using data locally versus a remote server. Client-side storage can be done with [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies), [Local Storage](https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API) (technically "Web Storage"), [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API), and [WebSQL](https://www.w3.org/TR/webdatabase/) (a deprecated method that should not be used in new projects).
+ +In this cookbook entry we'll focus on Local Storage, the simplest of the storage mechanisms. Local Storage uses a key/value system for storing data. It is limited to storing only simple values but complex data can be stored if you are willing to encode and decode the values with JSON. In general, Local Storage is appropriate for smaller sets of data you would want to persist, things like user preferences or form data. Larger data with more complex storage needs would be better stored typically in IndexedDB. + +Let's begin with a simple form based example: + +``` html +See the Pen testing localstorage by Raymond Camden (@cfjedimaster) on CodePen.
+ + +Type something in the form and then reload this page. You'll note that the value you typed previously will show up automatically. Don't forget that your browser provides excellent developer tools for inspecting client-side storage. Here's an example in Firefox: + + + +And here it is in Chrome: + + + +And then finally, an example in Microsoft Edge. Note that you can find application storage values under the Debugger tab. + + + +As a quick aside, these dev tools also offer you a way to remove storage values. This can be very useful when testing.
+ +Immediately writing the value may not advisable. Let's consider a slightly more advanced example. First, the updated form. + +``` html +See the Pen testing localstorage 2 by Raymond Camden (@cfjedimaster) on CodePen.
+ + +## Working with Complex Values + +As mentioned above, Local Storage only works with simple values. To store more complex values, like objects or arrays, you must serialize and deserialize the values with JSON. Here is a more advanced example that persists an array of cats (the best kind of array possible). + +``` html ++ {{cat}} +
++ + +
+ +See the Pen localstorage, complex by Raymond Camden (@cfjedimaster) on CodePen.
+ + +## Alternative Patterns + +While the Local Storage API is relatively simple, it is missing some basic features that would be useful in many applications. The following plugins wrap Local Storage access and make it easier to use, while also adding functionality like default values. + +* [vue-local-storage](https://github.com/pinguinjkeke/vue-local-storage) +* [vue-reactive-storage](https://github.com/ropbla9/vue-reactive-storage) + +## Wrapping Up + +While the browser will never replace a server persistence system, having multiple ways to cache data locally can be a huge performance boost for your application, and working with it in Vue.js makes it even more powerful. diff --git a/src/v2/cookbook/creating-custom-scroll-directives.md b/src/v2/cookbook/creating-custom-scroll-directives.md index fb9eb351b9..99ca0c7a49 100644 --- a/src/v2/cookbook/creating-custom-scroll-directives.md +++ b/src/v2/cookbook/creating-custom-scroll-directives.md @@ -50,7 +50,7 @@ new Vue({ We'd also need a style property that will transition the intermediary values here, in this case: -``` +```css .box { transition: 1.5s all cubic-bezier(0.39, 0.575, 0.565, 1); } diff --git a/src/v2/cookbook/packaging-sfc-for-npm.md b/src/v2/cookbook/packaging-sfc-for-npm.md new file mode 100644 index 0000000000..418aa2e864 --- /dev/null +++ b/src/v2/cookbook/packaging-sfc-for-npm.md @@ -0,0 +1,216 @@ +--- +title: Packaging Vue Components for npm (EN) +type: cookbook +order: 12 +--- + +## Base Example + +Cette page est en cours de traduction. Pour nous aider, vous pouvez participer sur le dépôt GitHub dédié de Vuejs-FR.
Vue components by nature are meant to be re-used. This is easy when the component is only used within a single application. But how can you write a component once and use it in multiple sites/applications? Perhaps the easiest solution is via npm.
+ +By packaging your component to be shared via npm, it can be imported/required into a build process for use in full-fledged web applications: + +```js +import MyComponent from 'my-component'; + +export default { + components: { + MyComponent, + }, + // rest of the component +} +``` + +Or even used via ` + + ... +L'exemple ci-dessus et plusieurs exemples par la suite utilisent une chaîne de caractères JavaScript appelée [modèles de libellés](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) (« template string ») permettant des templates multilignes plus lisibles. Ceux-ci ne sont pas supportés dans Internet Explorer (IE), aussi, si vous souhaitez supporter IE sans utiliser de transpilateur (p. ex. Babel ou TypeScript), [ajoutez un caractère d'échappement à chaque nouvelle ligne](https://css-tricks.com/snippets/javascript/multiline-string-variables-in-javascript) à la place.
+ +Maintenant, chaque fois qu'une nouvelle propriété sera ajoutée à l'objet `post`, elle sera automatiquement disponible dans `L'exemple ci-dessus et plusieurs exemples futurs utilisent une chaine de caractère JavaScript appelée [modèles de libellés](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) permettant des templates multilignes plus lisibles. Ceux-ci ne sont pas supportés dans Internet Explorer (IE), aussi, si vous souhaitez supporter IE sans utiliser de transpilleur (p. ex. Babel ou TypeScript), [échappez le caractère de nouvelle ligne](https://css-tricks.com/snippets/javascript/multiline-string-variables-in-javascript) à la place.
- Le problème est que le bouton ne fait rien du tout : ```html @@ -438,7 +475,7 @@ Exactement comme les éléments HTML, il est souvent utile de passer du contenu ``` html
+<%_ for (const sponsor of theme.silver_sponsors) {_%>
+
+
+
+<%_ } _%>
+
Si vous êtes une entreprise et que vous utilisez Vue pour des produits générant du revenu, cela fait sens d'être sponsor du développement de Vue : cela assure que le projet sur lequel repose votre produit reste sain et activement maintenu. Cela améliore également votre visibilité auprès de la communauté Vue et vous rend plus attractif pour les développeurs Vue.
diff --git a/themes/vue/source/css/_sponsors-page.styl b/themes/vue/source/css/_sponsors-page.styl index 77b397e982..2052feda2b 100644 --- a/themes/vue/source/css/_sponsors-page.styl +++ b/themes/vue/source/css/_sponsors-page.styl @@ -23,8 +23,10 @@ .open-collective-sponsors img - max-height 80px - margin-right 20px + max-width 140px + max-height 60px + margin-right 30px + margin-bottom 20px #one-time-donations a, svg diff --git a/themes/vue/source/images/dopamine.png b/themes/vue/source/images/dopamine.png new file mode 100644 index 0000000000..3d688c7a55 Binary files /dev/null and b/themes/vue/source/images/dopamine.png differ diff --git a/themes/vue/source/js/vue.js b/themes/vue/source/js/vue.js index 9d84c53b4b..657cb37eaa 100644 --- a/themes/vue/source/js/vue.js +++ b/themes/vue/source/js/vue.js @@ -1,6 +1,6 @@ /*! - * Vue.js v2.5.13 - * (c) 2014-2017 Evan You + * Vue.js v2.5.16 + * (c) 2014-2018 Evan You * Released under the MIT License. */ (function (global, factory) { @@ -185,9 +185,15 @@ var hyphenate = cached(function (str) { }); /** - * Simple bind, faster than native + * Simple bind polyfill for environments that do not support it... e.g. + * PhantomJS 1.x. Technically we don't need this anymore since native bind is + * now more performant in most browsers, but removing it would be breaking for + * code that was able to run in PhantomJS 1.x, so this must be kept for + * backwards compatibility. */ -function bind (fn, ctx) { + +/* istanbul ignore next */ +function polyfillBind (fn, ctx) { function boundFn (a) { var l = arguments.length; return l @@ -196,11 +202,19 @@ function bind (fn, ctx) { : fn.call(ctx, a) : fn.call(ctx) } - // record original fn length + boundFn._length = fn.length; return boundFn } +function nativeBind (fn, ctx) { + return fn.bind(ctx) +} + +var bind = Function.prototype.bind + ? nativeBind + : polyfillBind; + /** * Convert an Array-like object to a real Array. */ @@ -430,7 +444,7 @@ var config = ({ * Exposed for legacy reasons */ _lifecycleHooks: LIFECYCLE_HOOKS -}); +}) /* */ @@ -474,7 +488,6 @@ function parsePath (path) { /* */ - // can we use __proto__? var hasProto = '__proto__' in {}; @@ -513,7 +526,7 @@ var _isServer; var isServerRendering = function () { if (_isServer === undefined) { /* istanbul ignore if */ - if (!inBrowser && typeof global !== 'undefined') { + if (!inBrowser && !inWeex && typeof global !== 'undefined') { // detect presence of vue-server-renderer and avoid // Webpack shimming the process _isServer = global['process'].env.VUE_ENV === 'server'; @@ -770,8 +783,7 @@ function createTextVNode (val) { // used for static nodes and slot nodes because they may be reused across // multiple renders, cloning them avoids errors when DOM manipulations rely // on their elm reference. -function cloneVNode (vnode, deep) { - var componentOptions = vnode.componentOptions; +function cloneVNode (vnode) { var cloned = new VNode( vnode.tag, vnode.data, @@ -779,7 +791,7 @@ function cloneVNode (vnode, deep) { vnode.text, vnode.elm, vnode.context, - componentOptions, + vnode.componentOptions, vnode.asyncFactory ); cloned.ns = vnode.ns; @@ -790,33 +802,18 @@ function cloneVNode (vnode, deep) { cloned.fnOptions = vnode.fnOptions; cloned.fnScopeId = vnode.fnScopeId; cloned.isCloned = true; - if (deep) { - if (vnode.children) { - cloned.children = cloneVNodes(vnode.children, true); - } - if (componentOptions && componentOptions.children) { - componentOptions.children = cloneVNodes(componentOptions.children, true); - } - } return cloned } -function cloneVNodes (vnodes, deep) { - var len = vnodes.length; - var res = new Array(len); - for (var i = 0; i < len; i++) { - res[i] = cloneVNode(vnodes[i], deep); - } - return res -} - /* * not type checking this file because flow doesn't play well with * dynamically accessing methods on Array prototype */ var arrayProto = Array.prototype; -var arrayMethods = Object.create(arrayProto);[ +var arrayMethods = Object.create(arrayProto); + +var methodsToPatch = [ 'push', 'pop', 'shift', @@ -824,7 +821,12 @@ var arrayMethods = Object.create(arrayProto);[ 'splice', 'sort', 'reverse' -].forEach(function (method) { +]; + +/** + * Intercept mutating methods and emit events + */ +methodsToPatch.forEach(function (method) { // cache original method var original = arrayProto[method]; def(arrayMethods, method, function mutator () { @@ -855,20 +857,20 @@ var arrayMethods = Object.create(arrayProto);[ var arrayKeys = Object.getOwnPropertyNames(arrayMethods); /** - * By default, when a reactive property is set, the new value is - * also converted to become reactive. However when passing down props, - * we don't want to force conversion because the value may be a nested value - * under a frozen data structure. Converting it would defeat the optimization. + * In some cases we may want to disable observation inside a component's + * update computation. */ -var observerState = { - shouldConvert: true -}; +var shouldObserve = true; + +function toggleObserving (value) { + shouldObserve = value; +} /** - * Observer class that are attached to each observed - * object. Once attached, the observer converts target + * Observer class that is attached to each observed + * object. Once attached, the observer converts the target * object's property keys into getter/setters that - * collect dependencies and dispatches updates. + * collect dependencies and dispatch updates. */ var Observer = function Observer (value) { this.value = value; @@ -894,7 +896,7 @@ var Observer = function Observer (value) { Observer.prototype.walk = function walk (obj) { var keys = Object.keys(obj); for (var i = 0; i < keys.length; i++) { - defineReactive(obj, keys[i], obj[keys[i]]); + defineReactive(obj, keys[i]); } }; @@ -944,7 +946,7 @@ function observe (value, asRootData) { if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { ob = value.__ob__; } else if ( - observerState.shouldConvert && + shouldObserve && !isServerRendering() && (Array.isArray(value) || isPlainObject(value)) && Object.isExtensible(value) && @@ -977,6 +979,9 @@ function defineReactive ( // cater for pre-defined getter/setters var getter = property && property.get; + if (!getter && arguments.length === 2) { + val = obj[key]; + } var setter = property && property.set; var childOb = !shallow && observe(val); @@ -1023,6 +1028,11 @@ function defineReactive ( * already exist. */ function set (target, key, val) { + if ("development" !== 'production' && + (isUndef(target) || isPrimitive(target)) + ) { + warn(("Cannot set reactive property on undefined, null, or primitive value: " + ((target)))); + } if (Array.isArray(target) && isValidArrayIndex(key)) { target.length = Math.max(target.length, key); target.splice(key, 1, val); @@ -1053,6 +1063,11 @@ function set (target, key, val) { * Delete a property and trigger change if necessary. */ function del (target, key) { + if ("development" !== 'production' && + (isUndef(target) || isPrimitive(target)) + ) { + warn(("Cannot delete reactive property on undefined, null, or primitive value: " + ((target)))); + } if (Array.isArray(target) && isValidArrayIndex(key)) { target.splice(key, 1); return @@ -1519,12 +1534,18 @@ function validateProp ( var prop = propOptions[key]; var absent = !hasOwn(propsData, key); var value = propsData[key]; - // handle boolean props - if (isType(Boolean, prop.type)) { + // boolean casting + var booleanIndex = getTypeIndex(Boolean, prop.type); + if (booleanIndex > -1) { if (absent && !hasOwn(prop, 'default')) { value = false; - } else if (!isType(String, prop.type) && (value === '' || value === hyphenate(key))) { - value = true; + } else if (value === '' || value === hyphenate(key)) { + // only cast empty string / same name to boolean if + // boolean has higher priority + var stringIndex = getTypeIndex(String, prop.type); + if (stringIndex < 0 || booleanIndex < stringIndex) { + value = true; + } } } // check default value @@ -1532,10 +1553,10 @@ function validateProp ( value = getPropDefaultValue(vm, prop, key); // since the default value is a fresh copy, // make sure to observe it. - var prevShouldConvert = observerState.shouldConvert; - observerState.shouldConvert = true; + var prevShouldObserve = shouldObserve; + toggleObserving(true); observe(value); - observerState.shouldConvert = prevShouldConvert; + toggleObserving(prevShouldObserve); } { assertProp(prop, key, value, vm, absent); @@ -1664,17 +1685,20 @@ function getType (fn) { return match ? match[1] : '' } -function isType (type, fn) { - if (!Array.isArray(fn)) { - return getType(fn) === getType(type) +function isSameType (a, b) { + return getType(a) === getType(b) +} + +function getTypeIndex (type, expectedTypes) { + if (!Array.isArray(expectedTypes)) { + return isSameType(expectedTypes, type) ? 0 : -1 } - for (var i = 0, len = fn.length; i < len; i++) { - if (getType(fn[i]) === getType(type)) { - return true + for (var i = 0, len = expectedTypes.length; i < len; i++) { + if (isSameType(expectedTypes[i], type)) { + return i } } - /* istanbul ignore next */ - return false + return -1 } /* */ @@ -1737,19 +1761,19 @@ function flushCallbacks () { } } -// Here we have async deferring wrappers using both micro and macro tasks. -// In < 2.4 we used micro tasks everywhere, but there are some scenarios where -// micro tasks have too high a priority and fires in between supposedly +// Here we have async deferring wrappers using both microtasks and (macro) tasks. +// In < 2.4 we used microtasks everywhere, but there are some scenarios where +// microtasks have too high a priority and fire in between supposedly // sequential events (e.g. #4521, #6690) or even between bubbling of the same -// event (#6566). However, using macro tasks everywhere also has subtle problems +// event (#6566). However, using (macro) tasks everywhere also has subtle problems // when state is changed right before repaint (e.g. #6813, out-in transitions). -// Here we use micro task by default, but expose a way to force macro task when +// Here we use microtask by default, but expose a way to force (macro) task when // needed (e.g. in event handlers attached by v-on). var microTimerFunc; var macroTimerFunc; var useMacroTask = false; -// Determine (macro) Task defer implementation. +// Determine (macro) task defer implementation. // Technically setImmediate should be the ideal choice, but it's only available // in IE. The only polyfill that consistently queues the callback after all DOM // events triggered in the same loop is by using MessageChannel. @@ -1776,7 +1800,7 @@ if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) { }; } -// Determine MicroTask defer implementation. +// Determine microtask defer implementation. /* istanbul ignore next, $flow-disable-line */ if (typeof Promise !== 'undefined' && isNative(Promise)) { var p = Promise.resolve(); @@ -1796,7 +1820,7 @@ if (typeof Promise !== 'undefined' && isNative(Promise)) { /** * Wrap a function so that if any code inside triggers state change, - * the changes are queued using a Task instead of a MicroTask. + * the changes are queued using a (macro) task instead of a microtask. */ function withMacroTask (fn) { return fn._withTask || (fn._withTask = function () { @@ -1885,8 +1909,7 @@ var initProxy; }; var hasProxy = - typeof Proxy !== 'undefined' && - Proxy.toString().match(/native code/); + typeof Proxy !== 'undefined' && isNative(Proxy); if (hasProxy) { var isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta,exact'); @@ -1954,7 +1977,7 @@ function traverse (val) { function _traverse (val, seen) { var i, keys; var isA = Array.isArray(val); - if ((!isA && !isObject(val)) || Object.isFrozen(val)) { + if ((!isA && !isObject(val)) || Object.isFrozen(val) || val instanceof VNode) { return } if (val.__ob__) { @@ -2812,29 +2835,30 @@ function updateChildComponent ( // update $attrs and $listeners hash // these are also reactive so they may trigger child update if the child // used them during render - vm.$attrs = (parentVnode.data && parentVnode.data.attrs) || emptyObject; + vm.$attrs = parentVnode.data.attrs || emptyObject; vm.$listeners = listeners || emptyObject; // update props if (propsData && vm.$options.props) { - observerState.shouldConvert = false; + toggleObserving(false); var props = vm._props; var propKeys = vm.$options._propKeys || []; for (var i = 0; i < propKeys.length; i++) { var key = propKeys[i]; - props[key] = validateProp(key, vm.$options.props, propsData, vm); + var propOptions = vm.$options.props; // wtf flow? + props[key] = validateProp(key, propOptions, propsData, vm); } - observerState.shouldConvert = true; + toggleObserving(true); // keep a copy of raw propsData vm.$options.propsData = propsData; } // update listeners - if (listeners) { - var oldListeners = vm.$options._parentListeners; - vm.$options._parentListeners = listeners; - updateComponentListeners(vm, listeners, oldListeners); - } + listeners = listeners || emptyObject; + var oldListeners = vm.$options._parentListeners; + vm.$options._parentListeners = listeners; + updateComponentListeners(vm, listeners, oldListeners); + // resolve slots + force update if has children if (hasChildren) { vm.$slots = resolveSlots(renderChildren, parentVnode.context); @@ -2888,6 +2912,8 @@ function deactivateChildComponent (vm, direct) { } function callHook (vm, hook) { + // #7573 disable dep collection when invoking lifecycle hooks + pushTarget(); var handlers = vm.$options[hook]; if (handlers) { for (var i = 0, j = handlers.length; i < j; i++) { @@ -2901,6 +2927,7 @@ function callHook (vm, hook) { if (vm._hasHookEvent) { vm.$emit('hook:' + hook); } + popTarget(); } /* */ @@ -3045,7 +3072,7 @@ function queueWatcher (watcher) { /* */ -var uid$2 = 0; +var uid$1 = 0; /** * A watcher parses an expression, collects dependencies, @@ -3074,7 +3101,7 @@ var Watcher = function Watcher ( this.deep = this.user = this.lazy = this.sync = false; } this.cb = cb; - this.id = ++uid$2; // uid for batching + this.id = ++uid$1; // uid for batching this.active = true; this.dirty = this.lazy; // for lazy watchers this.deps = []; @@ -3297,7 +3324,9 @@ function initProps (vm, propsOptions) { var keys = vm.$options._propKeys = []; var isRoot = !vm.$parent; // root instance props should be converted - observerState.shouldConvert = isRoot; + if (!isRoot) { + toggleObserving(false); + } var loop = function ( key ) { keys.push(key); var value = validateProp(key, propsOptions, propsData, vm); @@ -3332,7 +3361,7 @@ function initProps (vm, propsOptions) { }; for (var key in propsOptions) loop( key ); - observerState.shouldConvert = true; + toggleObserving(true); } function initData (vm) { @@ -3378,11 +3407,15 @@ function initData (vm) { } function getData (data, vm) { + // #7573 disable dep collection when invoking data getters + pushTarget(); try { return data.call(vm, vm) } catch (e) { handleError(e, vm, "data()"); return {} + } finally { + popTarget(); } } @@ -3520,7 +3553,7 @@ function initWatch (vm, watch) { function createWatcher ( vm, - keyOrFn, + expOrFn, handler, options ) { @@ -3531,7 +3564,7 @@ function createWatcher ( if (typeof handler === 'string') { handler = vm[handler]; } - return vm.$watch(keyOrFn, handler, options) + return vm.$watch(expOrFn, handler, options) } function stateMixin (Vue) { @@ -3595,7 +3628,7 @@ function initProvide (vm) { function initInjections (vm) { var result = resolveInject(vm.$options.inject, vm); if (result) { - observerState.shouldConvert = false; + toggleObserving(false); Object.keys(result).forEach(function (key) { /* istanbul ignore else */ { @@ -3609,7 +3642,7 @@ function initInjections (vm) { }); } }); - observerState.shouldConvert = true; + toggleObserving(true); } } @@ -3629,7 +3662,7 @@ function resolveInject (inject, vm) { var provideKey = inject[key].from; var source = vm; while (source) { - if (source._provided && provideKey in source._provided) { + if (source._provided && hasOwn(source._provided, provideKey)) { result[key] = source._provided[provideKey]; break } @@ -3744,6 +3777,14 @@ function resolveFilter (id) { /* */ +function isKeyNotMatch (expect, actual) { + if (Array.isArray(expect)) { + return expect.indexOf(actual) === -1 + } else { + return expect !== actual + } +} + /** * Runtime helper for checking keyCodes from config. * exposed as Vue.prototype._k @@ -3752,16 +3793,15 @@ function resolveFilter (id) { function checkKeyCodes ( eventKeyCode, key, - builtInAlias, - eventKeyName + builtInKeyCode, + eventKeyName, + builtInKeyName ) { - var keyCodes = config.keyCodes[key] || builtInAlias; - if (keyCodes) { - if (Array.isArray(keyCodes)) { - return keyCodes.indexOf(eventKeyCode) === -1 - } else { - return keyCodes !== eventKeyCode - } + var mappedKeyCode = config.keyCodes[key] || builtInKeyCode; + if (builtInKeyName && eventKeyName && !config.keyCodes[key]) { + return isKeyNotMatch(builtInKeyName, eventKeyName) + } else if (mappedKeyCode) { + return isKeyNotMatch(mappedKeyCode, eventKeyCode) } else if (eventKeyName) { return hyphenate(eventKeyName) !== key } @@ -3833,11 +3873,9 @@ function renderStatic ( var cached = this._staticTrees || (this._staticTrees = []); var tree = cached[index]; // if has already-rendered static tree and not inside v-for, - // we can reuse the same tree by doing a shallow clone. + // we can reuse the same tree. if (tree && !isInFor) { - return Array.isArray(tree) - ? cloneVNodes(tree) - : cloneVNode(tree) + return tree } // otherwise, render a fresh tree. tree = cached[index] = this.$options.staticRenderFns[index].call( @@ -3935,6 +3973,24 @@ function FunctionalRenderContext ( Ctor ) { var options = Ctor.options; + // ensure the createElement function in functional components + // gets a unique context - this is necessary for correct named slot check + var contextVm; + if (hasOwn(parent, '_uid')) { + contextVm = Object.create(parent); + // $flow-disable-line + contextVm._original = parent; + } else { + // the context vm passed in is a functional context as well. + // in this case we want to make sure we are able to get a hold to the + // real context instance. + contextVm = parent; + // $flow-disable-line + parent = parent._original; + } + var isCompiled = isTrue(options._compiled); + var needNormalization = !isCompiled; + this.data = data; this.props = props; this.children = children; @@ -3943,12 +3999,6 @@ function FunctionalRenderContext ( this.injections = resolveInject(options.inject, parent); this.slots = function () { return resolveSlots(children, parent); }; - // ensure the createElement function in functional components - // gets a unique context - this is necessary for correct named slot check - var contextVm = Object.create(parent); - var isCompiled = isTrue(options._compiled); - var needNormalization = !isCompiled; - // support for compiled functional template if (isCompiled) { // exposing $options for renderStatic() @@ -3961,7 +4011,7 @@ function FunctionalRenderContext ( if (options._scopeId) { this._c = function (a, b, c, d) { var vnode = createElement(contextVm, a, b, c, d, needNormalization); - if (vnode) { + if (vnode && !Array.isArray(vnode)) { vnode.fnScopeId = options._scopeId; vnode.fnContext = parent; } @@ -4004,14 +4054,28 @@ function createFunctionalComponent ( var vnode = options.render.call(null, renderContext._c, renderContext); if (vnode instanceof VNode) { - vnode.fnContext = contextVm; - vnode.fnOptions = options; - if (data.slot) { - (vnode.data || (vnode.data = {})).slot = data.slot; + return cloneAndMarkFunctionalResult(vnode, data, renderContext.parent, options) + } else if (Array.isArray(vnode)) { + var vnodes = normalizeChildren(vnode) || []; + var res = new Array(vnodes.length); + for (var i = 0; i < vnodes.length; i++) { + res[i] = cloneAndMarkFunctionalResult(vnodes[i], data, renderContext.parent, options); } + return res } +} - return vnode +function cloneAndMarkFunctionalResult (vnode, data, contextVm, options) { + // #7817 clone node before setting fnContext, otherwise if the node is reused + // (e.g. it was from a cached normal slot) the fnContext causes named slots + // that should not be matched to match. + var clone = cloneVNode(vnode); + clone.fnContext = contextVm; + clone.fnOptions = options; + if (data.slot) { + (clone.data || (clone.data = {})).slot = data.slot; + } + return clone } function mergeProps (to, from) { @@ -4041,7 +4105,7 @@ function mergeProps (to, from) { /* */ -// hooks to be invoked on component VNodes during patch +// inline hooks to be invoked on component VNodes during patch var componentVNodeHooks = { init: function init ( vnode, @@ -4049,7 +4113,15 @@ var componentVNodeHooks = { parentElm, refElm ) { - if (!vnode.componentInstance || vnode.componentInstance._isDestroyed) { + if ( + vnode.componentInstance && + !vnode.componentInstance._isDestroyed && + vnode.data.keepAlive + ) { + // kept-alive components, treat as a patch + var mountedNode = vnode; // work around flow + componentVNodeHooks.prepatch(mountedNode, mountedNode); + } else { var child = vnode.componentInstance = createComponentInstanceForVnode( vnode, activeInstance, @@ -4057,10 +4129,6 @@ var componentVNodeHooks = { refElm ); child.$mount(hydrating ? vnode.elm : undefined, hydrating); - } else if (vnode.data.keepAlive) { - // kept-alive components, treat as a patch - var mountedNode = vnode; // work around flow - componentVNodeHooks.prepatch(mountedNode, mountedNode); } }, @@ -4195,8 +4263,8 @@ function createComponent ( } } - // merge component management hooks onto the placeholder node - mergeHooks(data); + // install component management hooks onto the placeholder node + installComponentHooks(data); // return a placeholder vnode var name = Ctor.options.name || tag; @@ -4236,22 +4304,11 @@ function createComponentInstanceForVnode ( return new vnode.componentOptions.Ctor(options) } -function mergeHooks (data) { - if (!data.hook) { - data.hook = {}; - } +function installComponentHooks (data) { + var hooks = data.hook || (data.hook = {}); for (var i = 0; i < hooksToMerge.length; i++) { var key = hooksToMerge[i]; - var fromParent = data.hook[key]; - var ours = componentVNodeHooks[key]; - data.hook[key] = fromParent ? mergeHook$1(ours, fromParent) : ours; - } -} - -function mergeHook$1 (one, two) { - return function (a, b, c, d) { - one(a, b, c, d); - two(a, b, c, d); + hooks[key] = componentVNodeHooks[key]; } } @@ -4368,8 +4425,11 @@ function _createElement ( // direct component options / constructor vnode = createComponent(tag, data, context, children); } - if (isDef(vnode)) { - if (ns) { applyNS(vnode, ns); } + if (Array.isArray(vnode)) { + return vnode + } else if (isDef(vnode)) { + if (isDef(ns)) { applyNS(vnode, ns); } + if (isDef(data)) { registerDeepBindings(data); } return vnode } else { return createEmptyVNode() @@ -4386,13 +4446,26 @@ function applyNS (vnode, ns, force) { if (isDef(vnode.children)) { for (var i = 0, l = vnode.children.length; i < l; i++) { var child = vnode.children[i]; - if (isDef(child.tag) && (isUndef(child.ns) || isTrue(force))) { + if (isDef(child.tag) && ( + isUndef(child.ns) || (isTrue(force) && child.tag !== 'svg'))) { applyNS(child, ns, force); } } } } +// ref #5318 +// necessary to ensure parent re-render when deep bindings like :style and +// :class are used on slot nodes +function registerDeepBindings (data) { + if (isObject(data.style)) { + traverse(data.style); + } + if (isObject(data.class)) { + traverse(data.class); + } +} + /* */ function initRender (vm) { @@ -4441,20 +4514,17 @@ function renderMixin (Vue) { var render = ref.render; var _parentVnode = ref._parentVnode; - if (vm._isMounted) { - // if the parent didn't update, the slot nodes will be the ones from - // last render. They need to be cloned to ensure "freshness" for this render. + // reset _rendered flag on slots for duplicate slot check + { for (var key in vm.$slots) { - var slot = vm.$slots[key]; - // _rendered is a flag added by renderSlot, but may not be present - // if the slot is passed from manually written render functions - if (slot._rendered || (slot[0] && slot[0].elm)) { - vm.$slots[key] = cloneVNodes(slot, true /* deep */); - } + // $flow-disable-line + vm.$slots[key]._rendered = false; } } - vm.$scopedSlots = (_parentVnode && _parentVnode.data.scopedSlots) || emptyObject; + if (_parentVnode) { + vm.$scopedSlots = _parentVnode.data.scopedSlots || emptyObject; + } // set parent vnode. this allows render functions to have access // to the data on the placeholder node. @@ -4500,13 +4570,13 @@ function renderMixin (Vue) { /* */ -var uid$1 = 0; +var uid$3 = 0; function initMixin (Vue) { Vue.prototype._init = function (options) { var vm = this; // a uid - vm._uid = uid$1++; + vm._uid = uid$3++; var startTag, endTag; /* istanbul ignore if */ @@ -4637,20 +4707,20 @@ function dedupe (latest, extended, sealed) { } } -function Vue$3 (options) { +function Vue (options) { if ("development" !== 'production' && - !(this instanceof Vue$3) + !(this instanceof Vue) ) { warn('Vue is a constructor and should be called with the `new` keyword'); } this._init(options); } -initMixin(Vue$3); -stateMixin(Vue$3); -eventsMixin(Vue$3); -lifecycleMixin(Vue$3); -renderMixin(Vue$3); +initMixin(Vue); +stateMixin(Vue); +eventsMixin(Vue); +lifecycleMixin(Vue); +renderMixin(Vue); /* */ @@ -4879,13 +4949,15 @@ var KeepAlive = { } }, - watch: { - include: function include (val) { - pruneCache(this, function (name) { return matches(val, name); }); - }, - exclude: function exclude (val) { - pruneCache(this, function (name) { return !matches(val, name); }); - } + mounted: function mounted () { + var this$1 = this; + + this.$watch('include', function (val) { + pruneCache(this$1, function (name) { return matches(val, name); }); + }); + this.$watch('exclude', function (val) { + pruneCache(this$1, function (name) { return !matches(val, name); }); + }); }, render: function render () { @@ -4933,11 +5005,11 @@ var KeepAlive = { } return vnode || (slot && slot[0]) } -}; +} var builtInComponents = { KeepAlive: KeepAlive -}; +} /* */ @@ -4985,20 +5057,25 @@ function initGlobalAPI (Vue) { initAssetRegisters(Vue); } -initGlobalAPI(Vue$3); +initGlobalAPI(Vue); -Object.defineProperty(Vue$3.prototype, '$isServer', { +Object.defineProperty(Vue.prototype, '$isServer', { get: isServerRendering }); -Object.defineProperty(Vue$3.prototype, '$ssrContext', { +Object.defineProperty(Vue.prototype, '$ssrContext', { get: function get () { /* istanbul ignore next */ return this.$vnode && this.$vnode.ssrContext } }); -Vue$3.version = '2.5.13'; +// expose FunctionalRenderContext for ssr runtime helper installation +Object.defineProperty(Vue, 'FunctionalRenderContext', { + value: FunctionalRenderContext +}); + +Vue.version = '2.5.16'; /* */ @@ -5272,8 +5349,8 @@ function setTextContent (node, text) { node.textContent = text; } -function setAttribute (node, key, val) { - node.setAttribute(key, val); +function setStyleScope (node, scopeId) { + node.setAttribute(scopeId, ''); } @@ -5289,7 +5366,7 @@ var nodeOps = Object.freeze({ nextSibling: nextSibling, tagName: tagName, setTextContent: setTextContent, - setAttribute: setAttribute + setStyleScope: setStyleScope }); /* */ @@ -5307,11 +5384,11 @@ var ref = { destroy: function destroy (vnode) { registerRef(vnode, true); } -}; +} function registerRef (vnode, isRemoval) { var key = vnode.data.ref; - if (!key) { return } + if (!isDef(key)) { return } var vm = vnode.context; var ref = vnode.componentInstance || vnode.elm; @@ -5442,7 +5519,25 @@ function createPatchFunction (backend) { } var creatingElmInVPre = 0; - function createElm (vnode, insertedVnodeQueue, parentElm, refElm, nested) { + + function createElm ( + vnode, + insertedVnodeQueue, + parentElm, + refElm, + nested, + ownerArray, + index + ) { + if (isDef(vnode.elm) && isDef(ownerArray)) { + // This vnode was used in a previous render! + // now it's used as a new node, overwriting its elm would cause + // potential patch errors down the road when it's used as an insertion + // reference node. Instead, we clone the node on-demand before creating + // associated DOM element for it. + vnode = ownerArray[index] = cloneVNode(vnode); + } + vnode.isRootInsert = !nested; // for transition enter check if (createComponent(vnode, insertedVnodeQueue, parentElm, refElm)) { return @@ -5465,6 +5560,7 @@ function createPatchFunction (backend) { ); } } + vnode.elm = vnode.ns ? nodeOps.createElementNS(vnode.ns, tag) : nodeOps.createElement(tag, vnode); @@ -5570,7 +5666,7 @@ function createPatchFunction (backend) { checkDuplicateKeys(children); } for (var i = 0; i < children.length; ++i) { - createElm(children[i], insertedVnodeQueue, vnode.elm, null, true); + createElm(children[i], insertedVnodeQueue, vnode.elm, null, true, children, i); } } else if (isPrimitive(vnode.text)) { nodeOps.appendChild(vnode.elm, nodeOps.createTextNode(String(vnode.text))); @@ -5601,12 +5697,12 @@ function createPatchFunction (backend) { function setScope (vnode) { var i; if (isDef(i = vnode.fnScopeId)) { - nodeOps.setAttribute(vnode.elm, i, ''); + nodeOps.setStyleScope(vnode.elm, i); } else { var ancestor = vnode; while (ancestor) { if (isDef(i = ancestor.context) && isDef(i = i.$options._scopeId)) { - nodeOps.setAttribute(vnode.elm, i, ''); + nodeOps.setStyleScope(vnode.elm, i); } ancestor = ancestor.parent; } @@ -5617,13 +5713,13 @@ function createPatchFunction (backend) { i !== vnode.fnContext && isDef(i = i.$options._scopeId) ) { - nodeOps.setAttribute(vnode.elm, i, ''); + nodeOps.setStyleScope(vnode.elm, i); } } function addVnodes (parentElm, refElm, vnodes, startIdx, endIdx, insertedVnodeQueue) { for (; startIdx <= endIdx; ++startIdx) { - createElm(vnodes[startIdx], insertedVnodeQueue, parentElm, refElm); + createElm(vnodes[startIdx], insertedVnodeQueue, parentElm, refElm, false, vnodes, startIdx); } } @@ -5733,7 +5829,7 @@ function createPatchFunction (backend) { ? oldKeyToIdx[newStartVnode.key] : findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx); if (isUndef(idxInOld)) { // New element - createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm); + createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx); } else { vnodeToMove = oldCh[idxInOld]; if (sameVnode(vnodeToMove, newStartVnode)) { @@ -5742,7 +5838,7 @@ function createPatchFunction (backend) { canMove && nodeOps.insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm); } else { // same key but different element. treat as new element - createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm); + createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx); } } newStartVnode = newCh[++newStartIdx]; @@ -6080,7 +6176,7 @@ var directives = { destroy: function unbindDirectives (vnode) { updateDirectives(vnode, emptyNode); } -}; +} function updateDirectives (oldVnode, vnode) { if (oldVnode.data.directives || vnode.data.directives) { @@ -6191,7 +6287,7 @@ function callHook$1 (dir, hook, vnode, oldVnode, isDestroy) { var baseModules = [ ref, directives -]; +] /* */ @@ -6237,7 +6333,9 @@ function updateAttrs (oldVnode, vnode) { } function setAttr (el, key, value) { - if (isBooleanAttr(key)) { + if (el.tagName.indexOf('-') > -1) { + baseSetAttr(el, key, value); + } else if (isBooleanAttr(key)) { // set attribute for blank value // e.g. if (isFalsyAttrValue(value)) { @@ -6259,35 +6357,39 @@ function setAttr (el, key, value) { el.setAttributeNS(xlinkNS, key, value); } } else { - if (isFalsyAttrValue(value)) { - el.removeAttribute(key); - } else { - // #7138: IE10 & 11 fires input event when setting placeholder on - //