diff --git a/build/release-weex.sh b/build/release-weex.sh index 77ce1d0abf6..3bb5412dd4f 100644 --- a/build/release-weex.sh +++ b/build/release-weex.sh @@ -31,7 +31,6 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then cd - # commit - git add src/entries/weex* git add packages/weex* git commit -m "[release] weex-vue-framework@$NEXT_VERSION" fi diff --git a/packages/weex-template-compiler/build.js b/packages/weex-template-compiler/build.js index 9f3fc688040..e590d002c7d 100644 --- a/packages/weex-template-compiler/build.js +++ b/packages/weex-template-compiler/build.js @@ -2,7 +2,9 @@ Object.defineProperty(exports, '__esModule', { value: true }); -var he = require('he'); +function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } + +var he = _interopDefault(require('he')); /* */ @@ -14,6 +16,8 @@ var he = require('he'); + + /** * Check if value is primitive */ @@ -24,15 +28,29 @@ var he = require('he'); * Objects from primitive values when we know the value * is a JSON-compliant type. */ +function isObject (obj) { + return obj !== null && typeof obj === 'object' +} +var _toString = Object.prototype.toString; /** * Strict object type check. Only returns true * for plain JavaScript objects. */ +function isPlainObject (obj) { + return _toString.call(obj) === '[object Object]' +} +/** + * Check if val is a valid array index. + */ +function isValidArrayIndex (val) { + var n = parseFloat(val); + return n >= 0 && Math.floor(n) === n && isFinite(val) +} /** * Convert a value to a string that is actually rendered. @@ -69,11 +87,29 @@ function makeMap ( var isBuiltInTag = makeMap('slot,component', true); /** - * Remove an item from an array + * Check if a attribute is a reserved attribute. */ +var isReservedAttribute = makeMap('key,ref,slot,is'); +/** + * Remove an item from an array + */ +function remove (arr, item) { + if (arr.length) { + var index = arr.indexOf(item); + if (index > -1) { + return arr.splice(index, 1) + } + } +} - +/** + * Check whether the object has the property. + */ +var hasOwnProperty = Object.prototype.hasOwnProperty; +function hasOwn (obj, key) { + return hasOwnProperty.call(obj, key) +} /** * Create a cached version of a pure function. @@ -128,13 +164,15 @@ function extend (to, _from) { /** * Perform no operation. + * Stubbing args to make Flow happy without leaving useless transpiled code + * with ...rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/) */ -function noop () {} +function noop (a, b, c) {} /** * Always return false. */ -var no = function () { return false; }; +var no = function (a, b, c) { return false; }; /** * Return same value @@ -243,6 +281,10 @@ var decodingMap = { var encodedAttr = /&(?:lt|gt|quot|amp);/g; var encodedAttrWithNewLines = /&(?:lt|gt|quot|amp|#10);/g; +// #5992 +var isIgnoreNewlineTag = makeMap('pre,textarea', true); +var shouldIgnoreFirstNewline = function (tag, html) { return tag && isIgnoreNewlineTag(tag) && html[0] === '\n'; }; + function decodeAttr (value, shouldDecodeNewlines) { var re = shouldDecodeNewlines ? encodedAttrWithNewLines : encodedAttr; return value.replace(re, function (match) { return decodingMap[match]; }) @@ -266,6 +308,9 @@ function parseHTML (html, options) { var commentEnd = html.indexOf('-->'); if (commentEnd >= 0) { + if (options.shouldKeepComment) { + options.comment(html.substring(4, commentEnd)); + } advance(commentEnd + 3); continue } @@ -301,24 +346,27 @@ function parseHTML (html, options) { var startTagMatch = parseStartTag(); if (startTagMatch) { handleStartTag(startTagMatch); + if (shouldIgnoreFirstNewline(lastTag, html)) { + advance(1); + } continue } } - var text = (void 0), rest$1 = (void 0), next = (void 0); + var text = (void 0), rest = (void 0), next = (void 0); if (textEnd >= 0) { - rest$1 = html.slice(textEnd); + rest = html.slice(textEnd); while ( - !endTag.test(rest$1) && - !startTagOpen.test(rest$1) && - !comment.test(rest$1) && - !conditionalComment.test(rest$1) + !endTag.test(rest) && + !startTagOpen.test(rest) && + !comment.test(rest) && + !conditionalComment.test(rest) ) { // < in plain text, be forgiving and treat it as text - next = rest$1.indexOf('<', 1); + next = rest.indexOf('<', 1); if (next < 0) { break } textEnd += next; - rest$1 = html.slice(textEnd); + rest = html.slice(textEnd); } text = html.substring(0, textEnd); advance(textEnd); @@ -333,23 +381,26 @@ function parseHTML (html, options) { options.chars(text); } } else { + var endTagLength = 0; var stackedTag = lastTag.toLowerCase(); var reStackedTag = reCache[stackedTag] || (reCache[stackedTag] = new RegExp('([\\s\\S]*?)(]*>)', 'i')); - var endTagLength = 0; - var rest = html.replace(reStackedTag, function (all, text, endTag) { + var rest$1 = html.replace(reStackedTag, function (all, text, endTag) { endTagLength = endTag.length; if (!isPlainTextElement(stackedTag) && stackedTag !== 'noscript') { text = text .replace(//g, '$1') .replace(//g, '$1'); } + if (shouldIgnoreFirstNewline(stackedTag, text)) { + text = text.slice(1); + } if (options.chars) { options.chars(text); } return '' }); - index += html.length - rest.length; - html = rest; + index += html.length - rest$1.length; + html = rest$1; parseEndTag(stackedTag, index - endTagLength, index); } @@ -406,7 +457,7 @@ function parseHTML (html, options) { } } - var unary = isUnaryTag$$1(tagName) || tagName === 'html' && lastTag === 'head' || !!unarySlash; + var unary = isUnaryTag$$1(tagName) || !!unarySlash; var l = match.attrs.length; var attrs = new Array(l); @@ -463,8 +514,9 @@ function parseHTML (html, options) { // Close all the open elements, up the stack for (var i = stack.length - 1; i >= pos; i--) { if (process.env.NODE_ENV !== 'production' && - (i > pos || !tagName) && - options.warn) { + (i > pos || !tagName) && + options.warn + ) { options.warn( ("tag <" + (stack[i].tag) + "> has no matching end tag.") ); @@ -674,10 +726,7 @@ function genAssignmentCode ( 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 + ")}" + return ("$set(" + (modelRs.exp) + ", " + (modelRs.idx) + ", " + assignment + ")") } } @@ -770,6 +819,12 @@ function parseString (chr) { } } +var ASSET_TYPES = [ + 'component', + 'directive', + 'filter' +]; + var LIFECYCLE_HOOKS = [ 'beforeCreate', 'created', @@ -816,6 +871,11 @@ var config = ({ */ errorHandler: null, + /** + * Warn handler for watcher warns + */ + warnHandler: null, + /** * Ignore certain custom elements */ @@ -866,9 +926,11 @@ var config = ({ _lifecycleHooks: LIFECYCLE_HOOKS }); +/* */ + var warn$1 = noop; var tip = noop; -var formatComponentName; +var formatComponentName = (null); // work around flow check if (process.env.NODE_ENV !== 'production') { var hasConsole = typeof console !== 'undefined'; @@ -878,10 +940,12 @@ if (process.env.NODE_ENV !== 'production') { .replace(/[-_]/g, ''); }; warn$1 = function (msg, vm) { - if (hasConsole && (!config.silent)) { - console.error("[Vue warn]: " + msg + ( - vm ? generateComponentTrace(vm) : '' - )); + var trace = vm ? generateComponentTrace(vm) : ''; + + if (config.warnHandler) { + config.warnHandler.call(null, msg, vm, trace); + } else if (hasConsole && (!config.silent)) { + console.error(("[Vue warn]: " + msg + trace)); } }; @@ -957,6 +1021,8 @@ if (process.env.NODE_ENV !== 'production') { }; } +/* */ + function handleError (err, vm, info) { if (config.errorHandler) { config.errorHandler.call(null, err, vm, info); @@ -977,7 +1043,7 @@ function handleError (err, vm, info) { /* globals MutationObserver */ // can we use __proto__? - +var hasProto = '__proto__' in {}; // Browser environment sniffing var inBrowser = typeof window !== 'undefined'; @@ -989,6 +1055,9 @@ var isAndroid = UA && UA.indexOf('android') > 0; var isIOS = UA && /iphone|ipad|ipod|ios/.test(UA); var isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge; +// Firefix has a "watch" function on Object.prototype... +var nativeWatch = ({}).watch; + var supportsPassive = false; if (inBrowser) { try { @@ -998,7 +1067,7 @@ if (inBrowser) { /* istanbul ignore next */ supportsPassive = true; } - } )); // https://github.com/facebook/flow/issues/285 + })); // https://github.com/facebook/flow/issues/285 window.addEventListener('test-passive', null, opts); } catch (e) {} } @@ -1292,12 +1361,15 @@ function parse ( options ) { warn = options.warn || baseWarn; - platformGetTagNamespace = options.getTagNamespace || no; - platformMustUseProp = options.mustUseProp || no; + platformIsPreTag = options.isPreTag || no; - preTransforms = pluckModuleFunction(options.modules, 'preTransformNode'); + platformMustUseProp = options.mustUseProp || no; + platformGetTagNamespace = options.getTagNamespace || no; + transforms = pluckModuleFunction(options.modules, 'transformNode'); + preTransforms = pluckModuleFunction(options.modules, 'preTransformNode'); postTransforms = pluckModuleFunction(options.modules, 'postTransformNode'); + delimiters = options.delimiters; var stack = []; @@ -1331,6 +1403,7 @@ function parse ( isUnaryTag: options.isUnaryTag, canBeLeftOpenTag: options.canBeLeftOpenTag, shouldDecodeNewlines: options.shouldDecodeNewlines, + shouldKeepComment: options.comments, start: function start (tag, attrs, unary) { // check namespace. // inherit parent ns if there is one @@ -1489,8 +1562,9 @@ function parse ( // IE textarea placeholder bug /* istanbul ignore if */ if (isIE && - currentParent.tag === 'textarea' && - currentParent.attrsMap.placeholder === text) { + currentParent.tag === 'textarea' && + currentParent.attrsMap.placeholder === text + ) { return } var children = currentParent.children; @@ -1513,6 +1587,13 @@ function parse ( }); } } + }, + comment: function comment (text) { + currentParent.children.push({ + type: 3, + text: text, + isComment: true + }); } }); return root @@ -1714,7 +1795,9 @@ function processAttrs (el) { ); } } - if (isProp || platformMustUseProp(el.tag, el.attrsMap.type, name)) { + if (isProp || ( + !el.component && platformMustUseProp(el.tag, el.attrsMap.type, name) + )) { addProp(el, name, value); } else { addAttr(el, name, value); @@ -1889,6 +1972,15 @@ function markStatic (node) { node.static = false; } } + if (node.ifConditions) { + for (var i$1 = 1, l$1 = node.ifConditions.length; i$1 < l$1; i$1++) { + var block = node.ifConditions[i$1].block; + markStatic(block); + if (!block.static) { + node.static = false; + } + } + } } } @@ -1915,17 +2007,13 @@ function markStaticRoots (node, isInFor) { } } if (node.ifConditions) { - walkThroughConditionsBlocks(node.ifConditions, isInFor); + for (var i$1 = 1, l$1 = node.ifConditions.length; i$1 < l$1; i$1++) { + markStaticRoots(node.ifConditions[i$1].block, isInFor); + } } } } -function walkThroughConditionsBlocks (conditionBlocks, isInFor) { - for (var i = 1, len = conditionBlocks.length; i < len; i++) { - markStaticRoots(conditionBlocks[i].block, isInFor); - } -} - function isStatic (node) { if (node.type === 2) { // expression return false @@ -1994,17 +2082,17 @@ var modifierCode = { function genHandlers ( events, - native, + isNative, warn ) { - var res = native ? 'nativeOn:{' : 'on:{'; + var res = isNative ? 'nativeOn:{' : 'on:{'; for (var name in events) { var handler = events[name]; // #5330: warn click.right, since right clicks do not actually fire click events. if (process.env.NODE_ENV !== 'production' && - name === 'click' && - handler && handler.modifiers && handler.modifiers.right - ) { + name === 'click' && + handler && handler.modifiers && handler.modifiers.right + ) { warn( "Use \"contextmenu\" instead of \"click.right\" since right clicks " + "do not actually fire \"click\" events." @@ -2080,99 +2168,639 @@ function genFilterCode (key) { /* */ +var emptyObject = Object.freeze({}); + +/** + * Check if a string starts with $ or _ + */ + + +/** + * Define a property. + */ +function def (obj, key, val, enumerable) { + Object.defineProperty(obj, key, { + value: val, + enumerable: !!enumerable, + writable: true, + configurable: true + }); +} + +/* */ + + +var uid = 0; + +/** + * A dep is an observable that can have multiple + * directives subscribing to it. + */ +var Dep = function Dep () { + this.id = uid++; + this.subs = []; +}; + +Dep.prototype.addSub = function addSub (sub) { + this.subs.push(sub); +}; + +Dep.prototype.removeSub = function removeSub (sub) { + remove(this.subs, sub); +}; + +Dep.prototype.depend = function depend () { + if (Dep.target) { + Dep.target.addDep(this); + } +}; + +Dep.prototype.notify = function notify () { + // stabilize the subscriber list first + var subs = this.subs.slice(); + for (var i = 0, l = subs.length; i < l; i++) { + subs[i].update(); + } +}; + +// the current target watcher being evaluated. +// this is globally unique because there could be only one +// watcher being evaluated at any time. +Dep.target = null; + +/* + * 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);[ + 'push', + 'pop', + 'shift', + 'unshift', + 'splice', + 'sort', + 'reverse' +] +.forEach(function (method) { + // cache original method + var original = arrayProto[method]; + def(arrayMethods, method, function mutator () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + var result = original.apply(this, args); + var ob = this.__ob__; + var inserted; + switch (method) { + case 'push': + case 'unshift': + inserted = args; + break + case 'splice': + inserted = args.slice(2); + break + } + if (inserted) { ob.observeArray(inserted); } + // notify change + ob.dep.notify(); + return result + }); +}); + +/* */ + +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. + */ +var observerState = { + shouldConvert: true +}; + +/** + * Observer class that are attached to each observed + * object. Once attached, the observer converts target + * object's property keys into getter/setters that + * collect dependencies and dispatches updates. + */ +var Observer = function Observer (value) { + this.value = value; + this.dep = new Dep(); + this.vmCount = 0; + def(value, '__ob__', this); + if (Array.isArray(value)) { + var augment = hasProto + ? protoAugment + : copyAugment; + augment(value, arrayMethods, arrayKeys); + this.observeArray(value); + } else { + this.walk(value); + } +}; + +/** + * Walk through each property and convert them into + * getter/setters. This method should only be called when + * value type is Object. + */ +Observer.prototype.walk = function walk (obj) { + var keys = Object.keys(obj); + for (var i = 0; i < keys.length; i++) { + defineReactive$$1(obj, keys[i], obj[keys[i]]); + } +}; + +/** + * Observe a list of Array items. + */ +Observer.prototype.observeArray = function observeArray (items) { + for (var i = 0, l = items.length; i < l; i++) { + observe(items[i]); + } +}; + +// helpers + +/** + * Augment an target Object or Array by intercepting + * the prototype chain using __proto__ + */ +function protoAugment (target, src, keys) { + /* eslint-disable no-proto */ + target.__proto__ = src; + /* eslint-enable no-proto */ +} + +/** + * Augment an target Object or Array by defining + * hidden properties. + */ +/* istanbul ignore next */ +function copyAugment (target, src, keys) { + for (var i = 0, l = keys.length; i < l; i++) { + var key = keys[i]; + def(target, key, src[key]); + } +} + +/** + * Attempt to create an observer instance for a value, + * returns the new observer if successfully observed, + * or the existing observer if the value already has one. + */ +function observe (value, asRootData) { + if (!isObject(value)) { + return + } + var ob; + if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { + ob = value.__ob__; + } else if ( + observerState.shouldConvert && + !isServerRendering() && + (Array.isArray(value) || isPlainObject(value)) && + Object.isExtensible(value) && + !value._isVue + ) { + ob = new Observer(value); + } + if (asRootData && ob) { + ob.vmCount++; + } + return ob +} + +/** + * Define a reactive property on an Object. + */ +function defineReactive$$1 ( + obj, + key, + val, + customSetter, + shallow +) { + var dep = new Dep(); + + var property = Object.getOwnPropertyDescriptor(obj, key); + if (property && property.configurable === false) { + return + } + + // cater for pre-defined getter/setters + var getter = property && property.get; + var setter = property && property.set; + + var childOb = !shallow && observe(val); + Object.defineProperty(obj, key, { + enumerable: true, + configurable: true, + get: function reactiveGetter () { + var value = getter ? getter.call(obj) : val; + if (Dep.target) { + dep.depend(); + if (childOb) { + childOb.dep.depend(); + } + if (Array.isArray(value)) { + dependArray(value); + } + } + return value + }, + set: function reactiveSetter (newVal) { + var value = getter ? getter.call(obj) : val; + /* eslint-disable no-self-compare */ + if (newVal === value || (newVal !== newVal && value !== value)) { + return + } + /* eslint-enable no-self-compare */ + if (process.env.NODE_ENV !== 'production' && customSetter) { + customSetter(); + } + if (setter) { + setter.call(obj, newVal); + } else { + val = newVal; + } + childOb = !shallow && observe(newVal); + dep.notify(); + } + }); +} + +/** + * Set a property on an object. Adds the new property and + * triggers change notification if the property doesn't + * already exist. + */ +function set (target, key, val) { + if (Array.isArray(target) && isValidArrayIndex(key)) { + target.length = Math.max(target.length, key); + target.splice(key, 1, val); + return val + } + if (hasOwn(target, key)) { + target[key] = val; + return val + } + var ob = (target).__ob__; + if (target._isVue || (ob && ob.vmCount)) { + process.env.NODE_ENV !== 'production' && warn$1( + 'Avoid adding reactive properties to a Vue instance or its root $data ' + + 'at runtime - declare it upfront in the data option.' + ); + return val + } + if (!ob) { + target[key] = val; + return val + } + defineReactive$$1(ob.value, key, val); + ob.dep.notify(); + return val +} + +/** + * Delete a property and trigger change if necessary. + */ + + +/** + * Collect dependencies on array elements when the array is touched, since + * we cannot intercept array element access like property getters. + */ +function dependArray (value) { + for (var e = (void 0), i = 0, l = value.length; i < l; i++) { + e = value[i]; + e && e.__ob__ && e.__ob__.dep.depend(); + if (Array.isArray(e)) { + dependArray(e); + } + } +} + +/* */ + +/** + * Option overwriting strategies are functions that handle + * how to merge a parent option value and a child option + * value into the final value. + */ +var strats = config.optionMergeStrategies; + +/** + * Options with restrictions + */ +if (process.env.NODE_ENV !== 'production') { + strats.el = strats.propsData = function (parent, child, vm, key) { + if (!vm) { + warn$1( + "option \"" + key + "\" can only be used during instance " + + 'creation with the `new` keyword.' + ); + } + return defaultStrat(parent, child) + }; +} + +/** + * Helper that recursively merges two data objects together. + */ +function mergeData (to, from) { + if (!from) { return to } + var key, toVal, fromVal; + var keys = Object.keys(from); + for (var i = 0; i < keys.length; i++) { + key = keys[i]; + toVal = to[key]; + fromVal = from[key]; + if (!hasOwn(to, key)) { + set(to, key, fromVal); + } else if (isPlainObject(toVal) && isPlainObject(fromVal)) { + mergeData(toVal, fromVal); + } + } + return to +} + +/** + * Data + */ +function mergeDataOrFn ( + parentVal, + childVal, + vm +) { + if (!vm) { + // in a Vue.extend merge, both should be functions + if (!childVal) { + return parentVal + } + if (!parentVal) { + return childVal + } + // when parentVal & childVal are both present, + // we need to return a function that returns the + // merged result of both functions... no need to + // check if parentVal is a function here because + // it has to be a function to pass previous merges. + return function mergedDataFn () { + return mergeData( + typeof childVal === 'function' ? childVal.call(this) : childVal, + typeof parentVal === 'function' ? parentVal.call(this) : parentVal + ) + } + } else if (parentVal || childVal) { + return function mergedInstanceDataFn () { + // instance merge + var instanceData = typeof childVal === 'function' + ? childVal.call(vm) + : childVal; + var defaultData = typeof parentVal === 'function' + ? parentVal.call(vm) + : undefined; + if (instanceData) { + return mergeData(instanceData, defaultData) + } else { + return defaultData + } + } + } +} + +strats.data = function ( + parentVal, + childVal, + vm +) { + if (!vm) { + if (childVal && typeof childVal !== 'function') { + process.env.NODE_ENV !== 'production' && warn$1( + 'The "data" option should be a function ' + + 'that returns a per-instance value in component ' + + 'definitions.', + vm + ); + + return parentVal + } + return mergeDataOrFn.call(this, parentVal, childVal) + } + + return mergeDataOrFn(parentVal, childVal, vm) +}; + +/** + * Hooks and props are merged as arrays. + */ +function mergeHook ( + parentVal, + childVal +) { + return childVal + ? parentVal + ? parentVal.concat(childVal) + : Array.isArray(childVal) + ? childVal + : [childVal] + : parentVal +} + +LIFECYCLE_HOOKS.forEach(function (hook) { + strats[hook] = mergeHook; +}); + +/** + * Assets + * + * When a vm is present (instance creation), we need to do + * a three-way merge between constructor options, instance + * options and parent options. + */ +function mergeAssets (parentVal, childVal) { + var res = Object.create(parentVal || null); + return childVal + ? extend(res, childVal) + : res +} + +ASSET_TYPES.forEach(function (type) { + strats[type + 's'] = mergeAssets; +}); + +/** + * Watchers. + * + * Watchers hashes should not overwrite one + * another, so we merge them as arrays. + */ +strats.watch = function (parentVal, childVal) { + // work around Firefox's Object.prototype.watch... + if (parentVal === nativeWatch) { parentVal = undefined; } + if (childVal === nativeWatch) { childVal = undefined; } + /* istanbul ignore if */ + if (!childVal) { return Object.create(parentVal || null) } + if (!parentVal) { return childVal } + var ret = {}; + extend(ret, parentVal); + for (var key in childVal) { + var parent = ret[key]; + var child = childVal[key]; + if (parent && !Array.isArray(parent)) { + parent = [parent]; + } + ret[key] = parent + ? parent.concat(child) + : Array.isArray(child) ? child : [child]; + } + return ret +}; + +/** + * Other object hashes. + */ +strats.props = +strats.methods = +strats.inject = +strats.computed = function (parentVal, childVal) { + if (!parentVal) { return childVal } + var ret = Object.create(null); + extend(ret, parentVal); + if (childVal) { extend(ret, childVal); } + return ret +}; +strats.provide = mergeDataOrFn; + +/** + * Default strategy. + */ +var defaultStrat = function (parentVal, childVal) { + return childVal === undefined + ? parentVal + : childVal +}; + +/** + * Merge two option objects into a new one. + * Core utility used in both instantiation and inheritance. + */ + + +/** + * Resolve an asset. + * This function is used because child instances need access + * to assets defined in its ancestor chain. + */ + +/* */ + +/* */ + +/* */ + +function on (el, dir) { + if (process.env.NODE_ENV !== 'production' && dir.modifiers) { + warn$1("v-on without argument does not support modifiers."); + } + el.wrapListeners = function (code) { return ("_g(" + code + "," + (dir.value) + ")"); }; +} + +/* */ + function bind$1 (el, dir) { el.wrapData = function (code) { - return ("_b(" + code + ",'" + (el.tag) + "'," + (dir.value) + (dir.modifiers && dir.modifiers.prop ? ',true' : '') + ")") + return ("_b(" + code + ",'" + (el.tag) + "'," + (dir.value) + "," + (dir.modifiers && dir.modifiers.prop ? 'true' : 'false') + (dir.modifiers && dir.modifiers.sync ? ',true' : '') + ")") }; } /* */ var baseDirectives = { + on: on, bind: bind$1, cloak: noop }; /* */ -// configurable state -var warn$2; -var transforms$1; -var dataGenFns; -var platformDirectives; -var isPlatformReservedTag$1; -var staticRenderFns; -var onceCount; -var currentOptions; +var CodegenState = function CodegenState (options) { + this.options = options; + this.warn = options.warn || baseWarn; + this.transforms = pluckModuleFunction(options.modules, 'transformCode'); + this.dataGenFns = pluckModuleFunction(options.modules, 'genData'); + this.directives = extend(extend({}, baseDirectives), options.directives); + var isReservedTag = options.isReservedTag || no; + this.maybeComponent = function (el) { return !isReservedTag(el.tag); }; + this.onceId = 0; + this.staticRenderFns = []; +}; + + function generate ( ast, options ) { - // save previous staticRenderFns so generate calls can be nested - var prevStaticRenderFns = staticRenderFns; - var currentStaticRenderFns = staticRenderFns = []; - var prevOnceCount = onceCount; - onceCount = 0; - currentOptions = options; - warn$2 = options.warn || baseWarn; - transforms$1 = pluckModuleFunction(options.modules, 'transformCode'); - dataGenFns = pluckModuleFunction(options.modules, 'genData'); - platformDirectives = options.directives || {}; - isPlatformReservedTag$1 = options.isReservedTag || no; - var code = ast ? genElement(ast) : '_c("div")'; - staticRenderFns = prevStaticRenderFns; - onceCount = prevOnceCount; + var state = new CodegenState(options); + var code = ast ? genElement(ast, state) : '_c("div")'; return { render: ("with(this){return " + code + "}"), - staticRenderFns: currentStaticRenderFns + staticRenderFns: state.staticRenderFns } } -function genElement (el) { +function genElement (el, state) { if (el.staticRoot && !el.staticProcessed) { - return genStatic(el) + return genStatic(el, state) } else if (el.once && !el.onceProcessed) { - return genOnce(el) + return genOnce(el, state) } else if (el.for && !el.forProcessed) { - return genFor(el) + return genFor(el, state) } else if (el.if && !el.ifProcessed) { - return genIf(el) + return genIf(el, state) } else if (el.tag === 'template' && !el.slotTarget) { - return genChildren(el) || 'void 0' + return genChildren(el, state) || 'void 0' } else if (el.tag === 'slot') { - return genSlot(el) + return genSlot(el, state) } else { // component or element var code; if (el.component) { - code = genComponent(el.component, el); + code = genComponent(el.component, el, state); } else { - var data = el.plain ? undefined : genData(el); + var data = el.plain ? undefined : genData(el, state); - var children = el.inlineTemplate ? null : genChildren(el, true); + var children = el.inlineTemplate ? null : genChildren(el, state, true); code = "_c('" + (el.tag) + "'" + (data ? ("," + data) : '') + (children ? ("," + children) : '') + ")"; } // module transforms - for (var i = 0; i < transforms$1.length; i++) { - code = transforms$1[i](el, code); + for (var i = 0; i < state.transforms.length; i++) { + code = state.transforms[i](el, code); } return code } } // hoist static sub-trees out -function genStatic (el) { +function genStatic (el, state) { el.staticProcessed = true; - staticRenderFns.push(("with(this){return " + (genElement(el)) + "}")); - return ("_m(" + (staticRenderFns.length - 1) + (el.staticInFor ? ',true' : '') + ")") + state.staticRenderFns.push(("with(this){return " + (genElement(el, state)) + "}")); + return ("_m(" + (state.staticRenderFns.length - 1) + (el.staticInFor ? ',true' : '') + ")") } // v-once -function genOnce (el) { +function genOnce (el, state) { el.onceProcessed = true; if (el.if && !el.ifProcessed) { - return genIf(el) + return genIf(el, state) } else if (el.staticInFor) { var key = ''; var parent = el.parent; @@ -2184,51 +2812,72 @@ function genOnce (el) { parent = parent.parent; } if (!key) { - process.env.NODE_ENV !== 'production' && warn$2( + process.env.NODE_ENV !== 'production' && state.warn( "v-once can only be used inside v-for that is keyed. " ); - return genElement(el) + return genElement(el, state) } - return ("_o(" + (genElement(el)) + "," + (onceCount++) + (key ? ("," + key) : "") + ")") + return ("_o(" + (genElement(el, state)) + "," + (state.onceId++) + (key ? ("," + key) : "") + ")") } else { - return genStatic(el) + return genStatic(el, state) } } -function genIf (el) { +function genIf ( + el, + state, + altGen, + altEmpty +) { el.ifProcessed = true; // avoid recursion - return genIfConditions(el.ifConditions.slice()) + return genIfConditions(el.ifConditions.slice(), state, altGen, altEmpty) } -function genIfConditions (conditions) { +function genIfConditions ( + conditions, + state, + altGen, + altEmpty +) { if (!conditions.length) { - return '_e()' + return altEmpty || '_e()' } var condition = conditions.shift(); if (condition.exp) { - return ("(" + (condition.exp) + ")?" + (genTernaryExp(condition.block)) + ":" + (genIfConditions(conditions))) + return ("(" + (condition.exp) + ")?" + (genTernaryExp(condition.block)) + ":" + (genIfConditions(conditions, state, altGen, altEmpty))) } else { return ("" + (genTernaryExp(condition.block))) } // v-if with v-once should generate code like (a)?_m(0):_m(1) function genTernaryExp (el) { - return el.once ? genOnce(el) : genElement(el) + return altGen + ? altGen(el, state) + : el.once + ? genOnce(el, state) + : genElement(el, state) } } -function genFor (el) { +function genFor ( + el, + state, + altGen, + altHelper +) { var exp = el.for; var alias = el.alias; var iterator1 = el.iterator1 ? ("," + (el.iterator1)) : ''; var iterator2 = el.iterator2 ? ("," + (el.iterator2)) : ''; - if ( - process.env.NODE_ENV !== 'production' && - maybeComponent(el) && el.tag !== 'slot' && el.tag !== 'template' && !el.key + if (process.env.NODE_ENV !== 'production' && + state.maybeComponent(el) && + el.tag !== 'slot' && + el.tag !== 'template' && + !el.key ) { - warn$2( + state.warn( "<" + (el.tag) + " v-for=\"" + alias + " in " + exp + "\">: component lists rendered with " + "v-for should have explicit keys. " + "See https://vuejs.org/guide/list.html#key for more info.", @@ -2237,18 +2886,18 @@ function genFor (el) { } el.forProcessed = true; // avoid recursion - return "_l((" + exp + ")," + + return (altHelper || '_l') + "((" + exp + ")," + "function(" + alias + iterator1 + iterator2 + "){" + - "return " + (genElement(el)) + + "return " + ((altGen || genElement)(el, state)) + '})' } -function genData (el) { +function genData (el, state) { var data = '{'; // directives first. // directives may mutate the el's other properties before they are generated. - var dirs = genDirectives(el); + var dirs = genDirectives(el, state); if (dirs) { data += dirs + ','; } // key @@ -2271,8 +2920,8 @@ function genData (el) { data += "tag:\"" + (el.tag) + "\","; } // module data generation functions - for (var i = 0; i < dataGenFns.length; i++) { - data += dataGenFns[i](el); + for (var i = 0; i < state.dataGenFns.length; i++) { + data += state.dataGenFns[i](el); } // attributes if (el.attrs) { @@ -2284,10 +2933,10 @@ function genData (el) { } // event handlers if (el.events) { - data += (genHandlers(el.events, false, warn$2)) + ","; + data += (genHandlers(el.events, false, state.warn)) + ","; } if (el.nativeEvents) { - data += (genHandlers(el.nativeEvents, true, warn$2)) + ","; + data += (genHandlers(el.nativeEvents, true, state.warn)) + ","; } // slot target if (el.slotTarget) { @@ -2295,7 +2944,7 @@ function genData (el) { } // scoped slots if (el.scopedSlots) { - data += (genScopedSlots(el.scopedSlots)) + ","; + data += (genScopedSlots(el.scopedSlots, state)) + ","; } // component v-model if (el.model) { @@ -2303,7 +2952,7 @@ function genData (el) { } // inline-template if (el.inlineTemplate) { - var inlineTemplate = genInlineTemplate(el); + var inlineTemplate = genInlineTemplate(el, state); if (inlineTemplate) { data += inlineTemplate + ","; } @@ -2313,10 +2962,14 @@ function genData (el) { if (el.wrapData) { data = el.wrapData(data); } + // v-on data wrap + if (el.wrapListeners) { + data = el.wrapListeners(data); + } return data } -function genDirectives (el) { +function genDirectives (el, state) { var dirs = el.directives; if (!dirs) { return } var res = 'directives:['; @@ -2325,11 +2978,11 @@ function genDirectives (el) { for (i = 0, l = dirs.length; i < l; i++) { dir = dirs[i]; needRuntime = true; - var gen = platformDirectives[dir.name] || baseDirectives[dir.name]; + var gen = state.directives[dir.name]; if (gen) { // compile-time directive that manipulates AST. // returns true if it also needs a runtime counterpart. - needRuntime = !!gen(el, dir, warn$2); + needRuntime = !!gen(el, dir, state.warn); } if (needRuntime) { hasRuntime = true; @@ -2341,43 +2994,81 @@ function genDirectives (el) { } } -function genInlineTemplate (el) { +function genInlineTemplate (el, state) { var ast = el.children[0]; if (process.env.NODE_ENV !== 'production' && ( el.children.length > 1 || ast.type !== 1 )) { - warn$2('Inline-template components must have exactly one child element.'); + state.warn('Inline-template components must have exactly one child element.'); } if (ast.type === 1) { - var inlineRenderFns = generate(ast, currentOptions); + var inlineRenderFns = generate(ast, state.options); return ("inlineTemplate:{render:function(){" + (inlineRenderFns.render) + "},staticRenderFns:[" + (inlineRenderFns.staticRenderFns.map(function (code) { return ("function(){" + code + "}"); }).join(',')) + "]}") } } -function genScopedSlots (slots) { - return ("scopedSlots:_u([" + (Object.keys(slots).map(function (key) { return genScopedSlot(key, slots[key]); }).join(',')) + "])") +function genScopedSlots ( + slots, + state +) { + return ("scopedSlots:_u([" + (Object.keys(slots).map(function (key) { + return genScopedSlot(key, slots[key], state) + }).join(',')) + "])") } -function genScopedSlot (key, el) { - return "[" + key + ",function(" + (String(el.attrsMap.scope)) + "){" + +function genScopedSlot ( + key, + el, + state +) { + if (el.for && !el.forProcessed) { + return genForScopedSlot(key, el, state) + } + return "{key:" + key + ",fn:function(" + (String(el.attrsMap.scope)) + "){" + "return " + (el.tag === 'template' - ? genChildren(el) || 'void 0' - : genElement(el)) + "}]" + ? genChildren(el, state) || 'void 0' + : genElement(el, state)) + "}}" } -function genChildren (el, checkSkip) { +function genForScopedSlot ( + key, + el, + state +) { + var exp = el.for; + var alias = el.alias; + var iterator1 = el.iterator1 ? ("," + (el.iterator1)) : ''; + var iterator2 = el.iterator2 ? ("," + (el.iterator2)) : ''; + el.forProcessed = true; // avoid recursion + return "_l((" + exp + ")," + + "function(" + alias + iterator1 + iterator2 + "){" + + "return " + (genScopedSlot(key, el, state)) + + '})' +} + +function genChildren ( + el, + state, + checkSkip, + altGenElement, + altGenNode +) { var children = el.children; if (children.length) { var el$1 = children[0]; // optimize single v-for if (children.length === 1 && - el$1.for && - el$1.tag !== 'template' && - el$1.tag !== 'slot') { - return genElement(el$1) + el$1.for && + el$1.tag !== 'template' && + el$1.tag !== 'slot' + ) { + return (altGenElement || genElement)(el$1, state) } - var normalizationType = checkSkip ? getNormalizationType(children) : 0; - return ("[" + (children.map(genNode).join(',')) + "]" + (normalizationType ? ("," + normalizationType) : '')) + var normalizationType = checkSkip + ? getNormalizationType(children, state.maybeComponent) + : 0; + var gen = altGenNode || genNode; + return ("[" + (children.map(function (c) { return gen(c, state); }).join(',')) + "]" + (normalizationType ? ("," + normalizationType) : '')) } } @@ -2385,7 +3076,10 @@ function genChildren (el, checkSkip) { // 0: no normalization needed // 1: simple normalization needed (possible 1-level deep nested array) // 2: full normalization needed -function getNormalizationType (children) { +function getNormalizationType ( + children, + maybeComponent +) { var res = 0; for (var i = 0; i < children.length; i++) { var el = children[i]; @@ -2409,13 +3103,11 @@ function needsNormalization (el) { return el.for !== undefined || el.tag === 'template' || el.tag === 'slot' } -function maybeComponent (el) { - return !isPlatformReservedTag$1(el.tag) -} - -function genNode (node) { +function genNode (node, state) { if (node.type === 1) { - return genElement(node) + return genElement(node, state) + } if (node.type === 3 && node.isComment) { + return genComment(node) } else { return genText(node) } @@ -2427,9 +3119,13 @@ function genText (text) { : transformSpecialNewlines(JSON.stringify(text.text))) + ")") } -function genSlot (el) { +function genComment (comment) { + return ("_e(" + (JSON.stringify(comment.text)) + ")") +} + +function genSlot (el, state) { var slotName = el.slotName || '"default"'; - var children = genChildren(el); + var children = genChildren(el, state); var res = "_t(" + slotName + (children ? ("," + children) : ''); var attrs = el.attrs && ("{" + (el.attrs.map(function (a) { return ((camelize(a.name)) + ":" + (a.value)); }).join(',')) + "}"); var bind$$1 = el.attrsMap['v-bind']; @@ -2446,9 +3142,13 @@ function genSlot (el) { } // componentName is el.component, take it as argument to shun flow's pessimistic refinement -function genComponent (componentName, el) { - var children = el.inlineTemplate ? null : genChildren(el, true); - return ("_c(" + componentName + "," + (genData(el)) + (children ? ("," + children) : '') + ")") +function genComponent ( + componentName, + el, + state +) { + var children = el.inlineTemplate ? null : genChildren(el, state, true); + return ("_c(" + componentName + "," + (genData(el, state)) + (children ? ("," + children) : '') + ")") } function genProps (props) { @@ -2566,21 +3266,7 @@ function checkExpression (exp, text, errors) { /* */ -function baseCompile ( - template, - options -) { - var ast = parse(template.trim(), options); - optimize(ast, options); - var code = generate(ast, options); - return { - ast: ast, - render: code.render, - staticRenderFns: code.staticRenderFns - } -} - -function makeFunction (code, errors) { +function createFunction (code, errors) { try { return new Function(code) } catch (err) { @@ -2589,50 +3275,10 @@ function makeFunction (code, errors) { } } -function createCompiler (baseOptions) { - var functionCompileCache = Object.create(null); - - function compile ( - template, - options - ) { - var finalOptions = Object.create(baseOptions); - var errors = []; - var tips = []; - finalOptions.warn = function (msg, tip$$1) { - (tip$$1 ? tips : errors).push(msg); - }; - - if (options) { - // merge custom modules - if (options.modules) { - finalOptions.modules = (baseOptions.modules || []).concat(options.modules); - } - // merge custom directives - if (options.directives) { - finalOptions.directives = extend( - Object.create(baseOptions.directives), - options.directives - ); - } - // copy other options - for (var key in options) { - if (key !== 'modules' && key !== 'directives') { - finalOptions[key] = options[key]; - } - } - } - - var compiled = baseCompile(template, finalOptions); - if (process.env.NODE_ENV !== 'production') { - errors.push.apply(errors, detectErrors(compiled.ast)); - } - compiled.errors = errors; - compiled.tips = tips; - return compiled - } +function createCompileToFunctionFn (compile) { + var cache = Object.create(null); - function compileToFunctions ( + return function compileToFunctions ( template, options, vm @@ -2661,8 +3307,8 @@ function createCompiler (baseOptions) { var key = options.delimiters ? String(options.delimiters) + template : template; - if (functionCompileCache[key]) { - return functionCompileCache[key] + if (cache[key]) { + return cache[key] } // compile @@ -2685,12 +3331,10 @@ function createCompiler (baseOptions) { // turn code into functions var res = {}; var fnGenErrors = []; - res.render = makeFunction(compiled.render, fnGenErrors); - var l = compiled.staticRenderFns.length; - res.staticRenderFns = new Array(l); - for (var i = 0; i < l; i++) { - res.staticRenderFns[i] = makeFunction(compiled.staticRenderFns[i], fnGenErrors); - } + res.render = createFunction(compiled.render, fnGenErrors); + res.staticRenderFns = compiled.staticRenderFns.map(function (code) { + return createFunction(code, fnGenErrors) + }); // check function generation errors. // this should only happen if there is a bug in the compiler itself. @@ -2711,17 +3355,83 @@ function createCompiler (baseOptions) { } } - return (functionCompileCache[key] = res) + return (cache[key] = res) } +} - return { - compile: compile, - compileToFunctions: compileToFunctions +/* */ + +function createCompilerCreator (baseCompile) { + return function createCompiler (baseOptions) { + function compile ( + template, + options + ) { + var finalOptions = Object.create(baseOptions); + var errors = []; + var tips = []; + finalOptions.warn = function (msg, tip) { + (tip ? tips : errors).push(msg); + }; + + if (options) { + // merge custom modules + if (options.modules) { + finalOptions.modules = + (baseOptions.modules || []).concat(options.modules); + } + // merge custom directives + if (options.directives) { + finalOptions.directives = extend( + Object.create(baseOptions.directives), + options.directives + ); + } + // copy other options + for (var key in options) { + if (key !== 'modules' && key !== 'directives') { + finalOptions[key] = options[key]; + } + } + } + + var compiled = baseCompile(template, finalOptions); + if (process.env.NODE_ENV !== 'production') { + errors.push.apply(errors, detectErrors(compiled.ast)); + } + compiled.errors = errors; + compiled.tips = tips; + return compiled + } + + return { + compile: compile, + compileToFunctions: createCompileToFunctionFn(compile) + } } } /* */ +// `createCompilerCreator` allows creating compilers that use alternative +// parser/optimizer/codegen, e.g the SSR optimizing compiler. +// Here we just export a default compiler using the default parts. +var createCompiler = createCompilerCreator(function baseCompile ( + template, + options +) { + var ast = parse(template.trim(), options); + optimize(ast, options); + var code = generate(ast, options); + return { + ast: ast, + render: code.render, + staticRenderFns: code.staticRenderFns + } +}); + +/* */ + function transformNode (el, options) { var warn = options.warn || baseWarn; var staticClass = getAndRemoveAttr(el, 'class'); @@ -2860,7 +3570,7 @@ var style = { var normalize$1 = cached(camelize); -function normalizeKeyName (str) { +function normalizeKeyName (str) { if (str.match(/^v\-/)) { return str.replace(/(v-[a-z\-]+\:)([a-z\-]+)$/i, function ($, directive, prop) { return directive + normalize$1(prop) diff --git a/packages/weex-template-compiler/package.json b/packages/weex-template-compiler/package.json index 08693d4861e..19c493a216e 100644 --- a/packages/weex-template-compiler/package.json +++ b/packages/weex-template-compiler/package.json @@ -1,6 +1,6 @@ { "name": "weex-template-compiler", - "version": "2.1.9-weex.1", + "version": "2.4.2-weex.1", "description": "Weex template compiler for Vue 2.0", "main": "index.js", "repository": { diff --git a/packages/weex-vue-framework/factory.js b/packages/weex-vue-framework/factory.js index 70ed93943a6..155b38a2db4 100644 --- a/packages/weex-vue-framework/factory.js +++ b/packages/weex-vue-framework/factory.js @@ -18,11 +18,19 @@ function isTrue (v) { return v === true } +function isFalse (v) { + return v === false +} + /** * Check if value is primitive */ function isPrimitive (value) { - return typeof value === 'string' || typeof value === 'number' + return ( + typeof value === 'string' || + typeof value === 'number' || + typeof value === 'boolean' + ) } /** @@ -34,24 +42,32 @@ function isObject (obj) { return obj !== null && typeof obj === 'object' } -var toString = Object.prototype.toString; +var _toString = Object.prototype.toString; /** * Strict object type check. Only returns true * for plain JavaScript objects. */ function isPlainObject (obj) { - return toString.call(obj) === '[object Object]' + return _toString.call(obj) === '[object Object]' } function isRegExp (v) { - return toString.call(v) === '[object RegExp]' + return _toString.call(v) === '[object RegExp]' +} + +/** + * Check if val is a valid array index. + */ +function isValidArrayIndex (val) { + var n = parseFloat(val); + return n >= 0 && Math.floor(n) === n && isFinite(val) } /** * Convert a value to a string that is actually rendered. */ -function _toString (val) { +function toString (val) { return val == null ? '' : typeof val === 'object' @@ -91,6 +107,11 @@ function makeMap ( */ var isBuiltInTag = makeMap('slot,component', true); +/** + * Check if a attribute is a reserved attribute. + */ +var isReservedAttribute = makeMap('key,ref,slot,is'); + /** * Remove an item from an array */ @@ -203,13 +224,15 @@ function toObject (arr) { /** * Perform no operation. + * Stubbing args to make Flow happy without leaving useless transpiled code + * with ...rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/) */ -function noop () {} +function noop (a, b, c) {} /** * Always return false. */ -var no = function () { return false; }; +var no = function (a, b, c) { return false; }; /** * Return same value @@ -226,14 +249,30 @@ var identity = function (_) { return _; }; * if they are plain objects, do they have the same shape? */ function looseEqual (a, b) { + if (a === b) { return true } var isObjectA = isObject(a); var isObjectB = isObject(b); if (isObjectA && isObjectB) { try { - return JSON.stringify(a) === JSON.stringify(b) + var isArrayA = Array.isArray(a); + var isArrayB = Array.isArray(b); + if (isArrayA && isArrayB) { + return a.length === b.length && a.every(function (e, i) { + return looseEqual(e, b[i]) + }) + } else if (!isArrayA && !isArrayB) { + var keysA = Object.keys(a); + var keysB = Object.keys(b); + return keysA.length === keysB.length && keysA.every(function (key) { + return looseEqual(a[key], b[key]) + }) + } else { + /* istanbul ignore next */ + return false + } } catch (e) { - // possible circular reference - return a === b + /* istanbul ignore next */ + return false } } else if (!isObjectA && !isObjectB) { return String(a) === String(b) @@ -316,6 +355,11 @@ var config = ({ */ errorHandler: null, + /** + * Warn handler for watcher warns + */ + warnHandler: null, + /** * Ignore certain custom elements */ @@ -408,9 +452,11 @@ function parsePath (path) { } } +/* */ + var warn = noop; var tip = noop; -var formatComponentName; +var formatComponentName = (null); // work around flow check if (process.env.NODE_ENV !== 'production') { var hasConsole = typeof console !== 'undefined'; @@ -420,10 +466,12 @@ if (process.env.NODE_ENV !== 'production') { .replace(/[-_]/g, ''); }; warn = function (msg, vm) { - if (hasConsole && (!config.silent)) { - console.error("[Vue warn]: " + msg + ( - vm ? generateComponentTrace(vm) : '' - )); + var trace = vm ? generateComponentTrace(vm) : ''; + + if (config.warnHandler) { + config.warnHandler.call(null, msg, vm, trace); + } else if (hasConsole && (!config.silent)) { + console.error(("[Vue warn]: " + msg + trace)); } }; @@ -499,6 +547,8 @@ if (process.env.NODE_ENV !== 'production') { }; } +/* */ + function handleError (err, vm, info) { if (config.errorHandler) { config.errorHandler.call(null, err, vm, info); @@ -531,6 +581,9 @@ var isAndroid = UA && UA.indexOf('android') > 0; var isIOS = UA && /iphone|ipad|ipod|ios/.test(UA); var isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge; +// Firefix has a "watch" function on Object.prototype... +var nativeWatch = ({}).watch; + var supportsPassive = false; if (inBrowser) { try { @@ -540,7 +593,7 @@ if (inBrowser) { /* istanbul ignore next */ supportsPassive = true; } - } )); // https://github.com/facebook/flow/issues/285 + })); // https://github.com/facebook/flow/issues/285 window.addEventListener('test-passive', null, opts); } catch (e) {} } @@ -755,22 +808,14 @@ var arrayMethods = Object.create(arrayProto);[ // cache original method var original = arrayProto[method]; def(arrayMethods, method, function mutator () { - var arguments$1 = arguments; + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; - // avoid leaking arguments: - // http://jsperf.com/closure-with-arguments - var i = arguments.length; - var args = new Array(i); - while (i--) { - args[i] = arguments$1[i]; - } var result = original.apply(this, args); var ob = this.__ob__; var inserted; switch (method) { case 'push': - inserted = args; - break case 'unshift': inserted = args; break @@ -796,8 +841,7 @@ var arrayKeys = Object.getOwnPropertyNames(arrayMethods); * under a frozen data structure. Converting it would defeat the optimization. */ var observerState = { - shouldConvert: true, - isSettingProps: false + shouldConvert: true }; /** @@ -849,7 +893,7 @@ Observer.prototype.observeArray = function observeArray (items) { * Augment an target Object or Array by intercepting * the prototype chain using __proto__ */ -function protoAugment (target, src) { +function protoAugment (target, src, keys) { /* eslint-disable no-proto */ target.__proto__ = src; /* eslint-enable no-proto */ @@ -901,7 +945,8 @@ function defineReactive$$1 ( obj, key, val, - customSetter + customSetter, + shallow ) { var dep = new Dep(); @@ -914,7 +959,7 @@ function defineReactive$$1 ( var getter = property && property.get; var setter = property && property.set; - var childOb = observe(val); + var childOb = !shallow && observe(val); Object.defineProperty(obj, key, { enumerable: true, configurable: true, @@ -946,7 +991,7 @@ function defineReactive$$1 ( } else { val = newVal; } - childOb = observe(newVal); + childOb = !shallow && observe(newVal); dep.notify(); } }); @@ -958,7 +1003,7 @@ function defineReactive$$1 ( * already exist. */ function set (target, key, val) { - if (Array.isArray(target) && typeof key === 'number') { + if (Array.isArray(target) && isValidArrayIndex(key)) { target.length = Math.max(target.length, key); target.splice(key, 1, val); return val @@ -967,7 +1012,7 @@ function set (target, key, val) { target[key] = val; return val } - var ob = (target ).__ob__; + var ob = (target).__ob__; if (target._isVue || (ob && ob.vmCount)) { process.env.NODE_ENV !== 'production' && warn( 'Avoid adding reactive properties to a Vue instance or its root $data ' + @@ -988,11 +1033,11 @@ function set (target, key, val) { * Delete a property and trigger change if necessary. */ function del (target, key) { - if (Array.isArray(target) && typeof key === 'number') { + if (Array.isArray(target) && isValidArrayIndex(key)) { target.splice(key, 1); return } - var ob = (target ).__ob__; + var ob = (target).__ob__; if (target._isVue || (ob && ob.vmCount)) { process.env.NODE_ENV !== 'production' && warn( 'Avoid deleting properties on a Vue instance or its root $data ' + @@ -1071,7 +1116,7 @@ function mergeData (to, from) { /** * Data */ -strats.data = function ( +function mergeDataOrFn ( parentVal, childVal, vm @@ -1081,15 +1126,6 @@ strats.data = function ( if (!childVal) { return parentVal } - if (typeof childVal !== 'function') { - process.env.NODE_ENV !== 'production' && warn( - 'The "data" option should be a function ' + - 'that returns a per-instance value in component ' + - 'definitions.', - vm - ); - return parentVal - } if (!parentVal) { return childVal } @@ -1100,8 +1136,8 @@ strats.data = function ( // it has to be a function to pass previous merges. return function mergedDataFn () { return mergeData( - childVal.call(this), - parentVal.call(this) + typeof childVal === 'function' ? childVal.call(this) : childVal, + typeof parentVal === 'function' ? parentVal.call(this) : parentVal ) } } else if (parentVal || childVal) { @@ -1120,6 +1156,28 @@ strats.data = function ( } } } +} + +strats.data = function ( + parentVal, + childVal, + vm +) { + if (!vm) { + if (childVal && typeof childVal !== 'function') { + process.env.NODE_ENV !== 'production' && warn( + 'The "data" option should be a function ' + + 'that returns a per-instance value in component ' + + 'definitions.', + vm + ); + + return parentVal + } + return mergeDataOrFn.call(this, parentVal, childVal) + } + + return mergeDataOrFn(parentVal, childVal, vm) }; /** @@ -1167,6 +1225,9 @@ ASSET_TYPES.forEach(function (type) { * another, so we merge them as arrays. */ strats.watch = function (parentVal, childVal) { + // work around Firefox's Object.prototype.watch... + if (parentVal === nativeWatch) { parentVal = undefined; } + if (childVal === nativeWatch) { childVal = undefined; } /* istanbul ignore if */ if (!childVal) { return Object.create(parentVal || null) } if (!parentVal) { return childVal } @@ -1180,7 +1241,7 @@ strats.watch = function (parentVal, childVal) { } ret[key] = parent ? parent.concat(child) - : [child]; + : Array.isArray(child) ? child : [child]; } return ret }; @@ -1190,14 +1251,15 @@ strats.watch = function (parentVal, childVal) { */ strats.props = strats.methods = +strats.inject = strats.computed = function (parentVal, childVal) { - if (!childVal) { return Object.create(parentVal || null) } if (!parentVal) { return childVal } var ret = Object.create(null); extend(ret, parentVal); - extend(ret, childVal); + if (childVal) { extend(ret, childVal); } return ret }; +strats.provide = mergeDataOrFn; /** * Default strategy. @@ -1255,6 +1317,19 @@ function normalizeProps (options) { options.props = res; } +/** + * Normalize all injections into Object-based format + */ +function normalizeInject (options) { + var inject = options.inject; + if (Array.isArray(inject)) { + var normalized = options.inject = {}; + for (var i = 0; i < inject.length; i++) { + normalized[inject[i]] = inject[i]; + } + } +} + /** * Normalize raw function directives into object format. */ @@ -1288,6 +1363,7 @@ function mergeOptions ( } normalizeProps(child); + normalizeInject(child); normalizeDirectives(child); var extendsFrom = child.extends; if (extendsFrom) { @@ -1405,7 +1481,8 @@ function getPropDefaultValue (vm, prop, key) { // return previous default value to avoid unnecessary watcher trigger if (vm && vm.$options.propsData && vm.$options.propsData[key] === undefined && - vm._props[key] !== undefined) { + vm._props[key] !== undefined + ) { return vm._props[key] } // call factory function for non-Function types @@ -1511,6 +1588,8 @@ function isType (type, fn) { return false } +/* */ + /* not type checking this file because flow doesn't play well with Proxy */ var initProxy; @@ -1617,7 +1696,8 @@ var VNode = function VNode ( text, elm, context, - componentOptions + componentOptions, + asyncFactory ) { this.tag = tag; this.data = data; @@ -1637,6 +1717,9 @@ var VNode = function VNode ( this.isComment = false; this.isCloned = false; this.isOnce = false; + this.asyncFactory = asyncFactory; + this.asyncMeta = undefined; + this.isAsyncPlaceholder = false; }; var prototypeAccessors = { child: {} }; @@ -1649,9 +1732,11 @@ prototypeAccessors.child.get = function () { Object.defineProperties( VNode.prototype, prototypeAccessors ); -var createEmptyVNode = function () { +var createEmptyVNode = function (text) { + if ( text === void 0 ) text = ''; + var node = new VNode(); - node.text = ''; + node.text = text; node.isComment = true; return node }; @@ -1672,11 +1757,13 @@ function cloneVNode (vnode) { vnode.text, vnode.elm, vnode.context, - vnode.componentOptions + vnode.componentOptions, + vnode.asyncFactory ); cloned.ns = vnode.ns; cloned.isStatic = vnode.isStatic; cloned.key = vnode.key; + cloned.isComment = vnode.isComment; cloned.isCloned = true; return cloned } @@ -1713,8 +1800,9 @@ function createFnInvoker (fns) { var fns = invoker.fns; if (Array.isArray(fns)) { - for (var i = 0; i < fns.length; i++) { - fns[i].apply(null, arguments$1); + var cloned = fns.slice(); + for (var i = 0; i < cloned.length; i++) { + cloned[i].apply(null, arguments$1); } } else { // return handler return value for single handlers @@ -1895,6 +1983,10 @@ function normalizeChildren (children) { : undefined } +function isTextNode (node) { + return isDef(node) && isDef(node.text) && isFalse(node.isComment) +} + function normalizeArrayChildren (children, nestedIndex) { var res = []; var i, c, last; @@ -1906,19 +1998,26 @@ function normalizeArrayChildren (children, nestedIndex) { if (Array.isArray(c)) { res.push.apply(res, normalizeArrayChildren(c, ((nestedIndex || '') + "_" + i))); } else if (isPrimitive(c)) { - if (isDef(last) && isDef(last.text)) { + if (isTextNode(last)) { + // merge adjacent text nodes + // this is necessary for SSR hydration because text nodes are + // essentially merged when rendered to HTML strings (last).text += String(c); } else if (c !== '') { // convert primitive to vnode res.push(createTextVNode(c)); } } else { - if (isDef(c.text) && isDef(last) && isDef(last.text)) { + if (isTextNode(c) && isTextNode(last)) { + // merge adjacent text nodes res[res.length - 1] = createTextVNode(last.text + c.text); } else { // default key for nested array children (likely generated by v-for) - if (isDef(c.tag) && isUndef(c.key) && isDef(nestedIndex)) { - c.key = "__vlist" + ((nestedIndex)) + "_" + i + "__"; + if (isTrue(children._isVList) && + isDef(c.tag) && + isUndef(c.key) && + isDef(nestedIndex)) { + c.key = "__vlist" + nestedIndex + "_" + i + "__"; } res.push(c); } @@ -1930,11 +2029,27 @@ function normalizeArrayChildren (children, nestedIndex) { /* */ function ensureCtor (comp, base) { + if (comp.__esModule && comp.default) { + comp = comp.default; + } return isObject(comp) ? base.extend(comp) : comp } +function createAsyncPlaceholder ( + factory, + data, + context, + children, + tag +) { + var node = createEmptyVNode(); + node.asyncFactory = factory; + node.asyncMeta = { data: data, context: context, children: children, tag: tag }; + return node +} + function resolveAsyncComponent ( factory, baseCtor, @@ -2017,11 +2132,13 @@ function resolveAsyncComponent ( if (isDef(res.timeout)) { setTimeout(function () { - reject( - process.env.NODE_ENV !== 'production' - ? ("timeout (" + (res.timeout) + "ms)") - : null - ); + if (isUndef(factory.resolved)) { + reject( + process.env.NODE_ENV !== 'production' + ? ("timeout (" + (res.timeout) + "ms)") + : null + ); + } }, res.timeout); } } @@ -2174,7 +2291,11 @@ function eventsMixin (Vue) { cbs = cbs.length > 1 ? toArray(cbs) : cbs; var args = toArray(arguments, 1); for (var i = 0, l = cbs.length; i < l; i++) { - cbs[i].apply(vm, args); + try { + cbs[i].apply(vm, args); + } catch (e) { + handleError(e, vm, ("event handler for \"" + event + "\"")); + } } } return vm @@ -2200,7 +2321,8 @@ function resolveSlots ( // named slots should only be respected if the vnode was rendered in the // same context. if ((child.context === context || child.functionalContext === context) && - child.data && child.data.slot != null) { + child.data && child.data.slot != null + ) { var name = child.data.slot; var slot = (slots[name] || (slots[name] = [])); if (child.tag === 'template') { @@ -2224,11 +2346,16 @@ function isWhitespace (node) { } function resolveScopedSlots ( - fns + fns, // see flow/vnode + res ) { - var res = {}; + res = res || {}; for (var i = 0; i < fns.length; i++) { - res[fns[i][0]] = fns[i][1]; + if (Array.isArray(fns[i])) { + resolveScopedSlots(fns[i], res); + } else { + res[fns[i].key] = fns[i].fn; + } } return res } @@ -2236,6 +2363,7 @@ function resolveScopedSlots ( /* */ var activeInstance = null; +var isUpdatingChildComponent = false; function initLifecycle (vm) { var options = vm.$options; @@ -2283,6 +2411,9 @@ function lifecycleMixin (Vue) { vm.$options._parentElm, vm.$options._refElm ); + // no need for the ref nodes after initial patch + // this prevents keeping a detached DOM tree in memory (#5851) + vm.$options._parentElm = vm.$options._refElm = null; } else { // updates vm.$el = vm.__patch__(prevVnode, vnode); @@ -2347,8 +2478,6 @@ function lifecycleMixin (Vue) { if (vm.$el) { vm.$el.__vue__ = null; } - // remove reference to DOM nodes (prevents leak) - vm.$options._parentElm = vm.$options._refElm = null; }; } @@ -2424,6 +2553,10 @@ function updateChildComponent ( parentVnode, renderChildren ) { + if (process.env.NODE_ENV !== 'production') { + isUpdatingChildComponent = true; + } + // determine whether component has slot children // we need to do this before overwriting $options._renderChildren var hasChildren = !!( @@ -2435,17 +2568,21 @@ function updateChildComponent ( vm.$options._parentVnode = parentVnode; vm.$vnode = parentVnode; // update vm's placeholder node without re-render + if (vm._vnode) { // update child tree's parent vm._vnode.parent = parentVnode; } vm.$options._renderChildren = renderChildren; + // update $attrs and $listensers 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; + vm.$listeners = listeners; + // update props if (propsData && vm.$options.props) { observerState.shouldConvert = false; - if (process.env.NODE_ENV !== 'production') { - observerState.isSettingProps = true; - } var props = vm._props; var propKeys = vm.$options._propKeys || []; for (var i = 0; i < propKeys.length; i++) { @@ -2453,12 +2590,10 @@ function updateChildComponent ( props[key] = validateProp(key, vm.$options.props, propsData, vm); } observerState.shouldConvert = true; - if (process.env.NODE_ENV !== 'production') { - observerState.isSettingProps = false; - } // keep a copy of raw propsData vm.$options.propsData = propsData; } + // update listeners if (listeners) { var oldListeners = vm.$options._parentListeners; @@ -2470,6 +2605,10 @@ function updateChildComponent ( vm.$slots = resolveSlots(renderChildren, parentVnode.context); vm.$forceUpdate(); } + + if (process.env.NODE_ENV !== 'production') { + isUpdatingChildComponent = false; + } } function isInInactiveTree (vm) { @@ -2546,7 +2685,7 @@ var index = 0; * Reset the scheduler's state. */ function resetSchedulerState () { - queue.length = activatedChildren.length = 0; + index = queue.length = activatedChildren.length = 0; has = {}; if (process.env.NODE_ENV !== 'production') { circular = {}; @@ -2603,7 +2742,7 @@ function flushSchedulerQueue () { // call component updated and activated hooks callActivatedHooks(activatedQueue); - callUpdateHooks(updatedQueue); + callUpdatedHooks(updatedQueue); // devtool hook /* istanbul ignore if */ @@ -2612,7 +2751,7 @@ function flushSchedulerQueue () { } } -function callUpdateHooks (queue) { +function callUpdatedHooks (queue) { var i = queue.length; while (i--) { var watcher = queue[i]; @@ -2656,10 +2795,10 @@ function queueWatcher (watcher) { // if already flushing, splice the watcher based on its id // if already past its id, it will be run next immediately. var i = queue.length - 1; - while (i >= 0 && queue[i].id > watcher.id) { + while (i > index && queue[i].id > watcher.id) { i--; } - queue.splice(Math.max(i, index) + 1, 0, watcher); + queue.splice(i + 1, 0, watcher); } // queue the flush if (!waiting) { @@ -2733,22 +2872,23 @@ Watcher.prototype.get = function get () { pushTarget(this); var value; var vm = this.vm; - if (this.user) { - try { - value = this.getter.call(vm, vm); - } catch (e) { + try { + value = this.getter.call(vm, vm); + } catch (e) { + if (this.user) { handleError(e, vm, ("getter for watcher \"" + (this.expression) + "\"")); + } else { + throw e } - } else { - value = this.getter.call(vm, vm); - } - // "touch" every property so they are all tracked as - // dependencies for deep watching - if (this.deep) { - traverse(value); + } finally { + // "touch" every property so they are all tracked as + // dependencies for deep watching + if (this.deep) { + traverse(value); + } + popTarget(); + this.cleanupDeps(); } - popTarget(); - this.cleanupDeps(); return value }; @@ -2941,14 +3081,20 @@ function initState (vm) { observe(vm._data = {}, true /* asRootData */); } if (opts.computed) { initComputed(vm, opts.computed); } - if (opts.watch) { initWatch(vm, opts.watch); } + if (opts.watch && opts.watch !== nativeWatch) { + initWatch(vm, opts.watch); + } } -var isReservedProp = { - key: 1, - ref: 1, - slot: 1 -}; +function checkOptionType (vm, name) { + var option = vm.$options[name]; + if (!isPlainObject(option)) { + warn( + ("component option \"" + name + "\" should be an object."), + vm + ); + } +} function initProps (vm, propsOptions) { var propsData = vm.$options.propsData || {}; @@ -2964,14 +3110,14 @@ function initProps (vm, propsOptions) { var value = validateProp(key, propsOptions, propsData, vm); /* istanbul ignore else */ if (process.env.NODE_ENV !== 'production') { - if (isReservedProp[key] || config.isReservedAttr(key)) { + if (isReservedAttribute(key) || config.isReservedAttr(key)) { warn( ("\"" + key + "\" is a reserved attribute and cannot be used as component prop."), vm ); } defineReactive$$1(props, key, value, function () { - if (vm.$parent && !observerState.isSettingProps) { + if (vm.$parent && !isUpdatingChildComponent) { warn( "Avoid mutating a prop directly since the value will be " + "overwritten whenever the parent component re-renders. " + @@ -3012,16 +3158,26 @@ function initData (vm) { // proxy data on instance var keys = Object.keys(data); var props = vm.$options.props; + var methods = vm.$options.methods; var i = keys.length; while (i--) { - if (props && hasOwn(props, keys[i])) { + var key = keys[i]; + if (process.env.NODE_ENV !== 'production') { + if (methods && hasOwn(methods, key)) { + warn( + ("method \"" + key + "\" has already been defined as a data property."), + vm + ); + } + } + if (props && hasOwn(props, key)) { process.env.NODE_ENV !== 'production' && warn( - "The data property \"" + (keys[i]) + "\" is already declared as a prop. " + + "The data property \"" + key + "\" is already declared as a prop. " + "Use prop default value instead.", vm ); - } else if (!isReserved(keys[i])) { - proxy(vm, "_data", keys[i]); + } else if (!isReserved(key)) { + proxy(vm, "_data", key); } } // observe data @@ -3040,22 +3196,20 @@ function getData (data, vm) { var computedWatcherOptions = { lazy: true }; function initComputed (vm, computed) { + process.env.NODE_ENV !== 'production' && checkOptionType(vm, 'computed'); var watchers = vm._computedWatchers = Object.create(null); for (var key in computed) { var userDef = computed[key]; var getter = typeof userDef === 'function' ? userDef : userDef.get; - if (process.env.NODE_ENV !== 'production') { - if (getter === undefined) { - warn( - ("No getter function has been defined for computed property \"" + key + "\"."), - vm - ); - getter = noop; - } + if (process.env.NODE_ENV !== 'production' && getter == null) { + warn( + ("Getter is missing for computed property \"" + key + "\"."), + vm + ); } // create internal watcher for the computed property. - watchers[key] = new Watcher(vm, getter, noop, computedWatcherOptions); + watchers[key] = new Watcher(vm, getter || noop, noop, computedWatcherOptions); // component-defined computed properties are already defined on the // component prototype. We only need to define computed properties defined @@ -3086,6 +3240,15 @@ function defineComputed (target, key, userDef) { ? userDef.set : noop; } + if (process.env.NODE_ENV !== 'production' && + sharedPropertyDefinition.set === noop) { + sharedPropertyDefinition.set = function () { + warn( + ("Computed property \"" + key + "\" was assigned to but it has no setter."), + this + ); + }; + } Object.defineProperty(target, key, sharedPropertyDefinition); } @@ -3105,6 +3268,7 @@ function createComputedGetter (key) { } function initMethods (vm, methods) { + process.env.NODE_ENV !== 'production' && checkOptionType(vm, 'methods'); var props = vm.$options.props; for (var key in methods) { vm[key] = methods[key] == null ? noop : bind(methods[key], vm); @@ -3127,6 +3291,7 @@ function initMethods (vm, methods) { } function initWatch (vm, watch) { + process.env.NODE_ENV !== 'production' && checkOptionType(vm, 'watch'); for (var key in watch) { var handler = watch[key]; if (Array.isArray(handler)) { @@ -3139,8 +3304,12 @@ function initWatch (vm, watch) { } } -function createWatcher (vm, key, handler) { - var options; +function createWatcher ( + vm, + keyOrFn, + handler, + options +) { if (isPlainObject(handler)) { options = handler; handler = handler.handler; @@ -3148,7 +3317,7 @@ function createWatcher (vm, key, handler) { if (typeof handler === 'string') { handler = vm[handler]; } - vm.$watch(key, handler, options); + return vm.$watch(keyOrFn, handler, options) } function stateMixin (Vue) { @@ -3183,6 +3352,9 @@ function stateMixin (Vue) { options ) { var vm = this; + if (isPlainObject(cb)) { + return createWatcher(vm, expOrFn, cb, options) + } options = options || {}; options.user = true; var watcher = new Watcher(vm, expOrFn, cb, options); @@ -3209,6 +3381,7 @@ function initProvide (vm) { function initInjections (vm) { var result = resolveInject(vm.$options.inject, vm); if (result) { + observerState.shouldConvert = false; Object.keys(result).forEach(function (key) { /* istanbul ignore else */ if (process.env.NODE_ENV !== 'production') { @@ -3224,24 +3397,21 @@ function initInjections (vm) { defineReactive$$1(vm, key, result[key]); } }); + observerState.shouldConvert = true; } } function resolveInject (inject, vm) { if (inject) { // inject is :any because flow is not smart enough to figure out cached - // isArray here - var isArray = Array.isArray(inject); var result = Object.create(null); - var keys = isArray - ? inject - : hasSymbol + var keys = hasSymbol ? Reflect.ownKeys(inject) : Object.keys(inject); for (var i = 0; i < keys.length; i++) { var key = keys[i]; - var provideKey = isArray ? key : inject[key]; + var provideKey = inject[key]; var source = vm; while (source) { if (source._provided && provideKey in source._provided) { @@ -3250,6 +3420,9 @@ function resolveInject (inject, vm) { } source = source.$parent; } + if (process.env.NODE_ENV !== 'production' && !source) { + warn(("Injection \"" + key + "\" not found"), vm); + } } return result } @@ -3268,7 +3441,7 @@ function createFunctionalComponent ( var propOptions = Ctor.options.props; if (isDef(propOptions)) { for (var key in propOptions) { - props[key] = validateProp(key, propOptions, propsData); + props[key] = validateProp(key, propOptions, propsData || {}); } } else { if (isDef(data.attrs)) { mergeProps(props, data.attrs); } @@ -3289,6 +3462,7 @@ function createFunctionalComponent ( }); if (vnode instanceof VNode) { vnode.functionalContext = context; + vnode.functionalOptions = Ctor.options; if (data.slot) { (vnode.data || (vnode.data = {})).slot = data.slot; } @@ -3402,21 +3576,30 @@ function createComponent ( } // async component + var asyncFactory; if (isUndef(Ctor.cid)) { - Ctor = resolveAsyncComponent(Ctor, baseCtor, context); + asyncFactory = Ctor; + Ctor = resolveAsyncComponent(asyncFactory, baseCtor, context); if (Ctor === undefined) { - // return nothing if this is indeed an async component - // wait for the callback to trigger parent update. - return + // return a placeholder node for async component, which is rendered + // as a comment node but preserves all the raw information for the node. + // the information will be used for async server-rendering and hydration. + return createAsyncPlaceholder( + asyncFactory, + data, + context, + children, + tag + ) } } + data = data || {}; + // resolve constructor options in case global mixins are applied after // component constructor creation resolveConstructorOptions(Ctor); - data = data || {}; - // transform component v-model data into props & events if (isDef(data.model)) { transformModel(Ctor.options, data); @@ -3434,12 +3617,19 @@ function createComponent ( // child component listeners instead of DOM listeners var listeners = data.on; // replace with listeners with .native modifier + // so it gets processed during parent component patch. data.on = data.nativeOn; if (isTrue(Ctor.options.abstract)) { // abstract components do not keep anything - // other than props & listeners + // other than props & listeners & slot + + // work around flow + var slot = data.slot; data = {}; + if (slot) { + data.slot = slot; + } } // merge component management hooks onto the placeholder node @@ -3450,7 +3640,8 @@ function createComponent ( var vnode = new VNode( ("vue-component-" + (Ctor.cid) + (name ? ("-" + name) : '')), data, undefined, undefined, undefined, context, - { Ctor: Ctor, propsData: propsData, listeners: listeners, tag: tag, children: children } + { Ctor: Ctor, propsData: propsData, listeners: listeners, tag: tag, children: children }, + asyncFactory ); return vnode } @@ -3555,13 +3746,28 @@ function _createElement ( ); return createEmptyVNode() } + // object syntax in v-bind + if (isDef(data) && isDef(data.is)) { + tag = data.is; + } if (!tag) { // in case of component :is set to falsy value return createEmptyVNode() } + // warn against non-primitive key + if (process.env.NODE_ENV !== 'production' && + isDef(data) && isDef(data.key) && !isPrimitive(data.key) + ) { + warn( + 'Avoid using non-primitive value as key, ' + + 'use string/number value instead.', + context + ); + } // support single function children as default scoped slot if (Array.isArray(children) && - typeof children[0] === 'function') { + typeof children[0] === 'function' + ) { data = data || {}; data.scopedSlots = { default: children[0] }; children.length = 0; @@ -3597,7 +3803,7 @@ function _createElement ( // direct component options / constructor vnode = createComponent(tag, data, context, children); } - if (vnode !== undefined) { + if (isDef(vnode)) { if (ns) { applyNS(vnode, ns); } return vnode } else { @@ -3611,7 +3817,7 @@ function applyNS (vnode, ns) { // use default namespace inside foreignObject return } - if (Array.isArray(vnode.children)) { + 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)) { @@ -3649,6 +3855,9 @@ function renderList ( ret[i] = render(val[key], key, i); } } + if (isDef(ret)) { + (ret)._isVList = true; + } return ret } @@ -3667,7 +3876,7 @@ function renderSlot ( if (scopedSlotFn) { // scoped slot props = props || {}; if (bindObject) { - extend(props, bindObject); + props = extend(extend({}, bindObject), props); } return scopedSlotFn(props) || fallback } else { @@ -3721,7 +3930,8 @@ function bindObjectProps ( data, tag, value, - asProp + asProp, + isSync ) { if (value) { if (!isObject(value)) { @@ -3734,8 +3944,12 @@ function bindObjectProps ( value = toObject(value); } var hash; - for (var key in value) { - if (key === 'class' || key === 'style') { + var loop = function ( key ) { + if ( + key === 'class' || + key === 'style' || + isReservedAttribute(key) + ) { hash = data; } else { var type = data.attrs && data.attrs.type; @@ -3745,8 +3959,17 @@ function bindObjectProps ( } if (!(key in hash)) { hash[key] = value[key]; + + if (isSync) { + var on = data.on || (data.on = {}); + on[("update:" + key)] = function ($event) { + value[key] = $event; + }; + } } - } + }; + + for (var key in value) loop( key ); } } return data @@ -3813,6 +4036,27 @@ function markStaticNode (node, key, isOnce) { /* */ +function bindObjectListeners (data, value) { + if (value) { + if (!isPlainObject(value)) { + process.env.NODE_ENV !== 'production' && warn( + 'v-on without argument expects an Object value', + this + ); + } else { + var on = data.on = data.on ? extend({}, data.on) : {}; + for (var key in value) { + var existing = on[key]; + var ours = value[key]; + on[key] = existing ? [].concat(ours, existing) : ours; + } + } + } + return data +} + +/* */ + function initRender (vm) { vm._vnode = null; // the root of the child tree vm._staticTrees = null; @@ -3828,6 +4072,22 @@ function initRender (vm) { // normalization is always applied for the public version, used in // user-written render functions. vm.$createElement = function (a, b, c, d) { return createElement(vm, a, b, c, d, true); }; + + // $attrs & $listeners are exposed for easier HOC creation. + // they need to be reactive so that HOCs using them are always updated + var parentData = parentVnode && parentVnode.data; + /* istanbul ignore else */ + if (process.env.NODE_ENV !== 'production') { + defineReactive$$1(vm, '$attrs', parentData && parentData.attrs, function () { + !isUpdatingChildComponent && warn("$attrs is readonly.", vm); + }, true); + defineReactive$$1(vm, '$listeners', vm.$options._parentListeners, function () { + !isUpdatingChildComponent && warn("$listeners is readonly.", vm); + }, true); + } else { + defineReactive$$1(vm, '$attrs', parentData && parentData.attrs, null, true); + defineReactive$$1(vm, '$listeners', vm.$options._parentListeners, null, true); + } } function renderMixin (Vue) { @@ -3895,7 +4155,7 @@ function renderMixin (Vue) { // code size. Vue.prototype._o = markOnce; Vue.prototype._n = toNumber; - Vue.prototype._s = _toString; + Vue.prototype._s = toString; Vue.prototype._l = renderList; Vue.prototype._t = renderSlot; Vue.prototype._q = looseEqual; @@ -3907,6 +4167,7 @@ function renderMixin (Vue) { Vue.prototype._v = createTextVNode; Vue.prototype._e = createEmptyVNode; Vue.prototype._u = resolveScopedSlots; + Vue.prototype._g = bindObjectListeners; } /* */ @@ -4048,7 +4309,8 @@ function dedupe (latest, extended, sealed) { function Vue$2 (options) { if (process.env.NODE_ENV !== 'production' && - !(this instanceof Vue$2)) { + !(this instanceof Vue$2) + ) { warn('Vue is a constructor and should be called with the `new` keyword'); } this._init(options); @@ -4064,10 +4326,11 @@ renderMixin(Vue$2); function initUse (Vue) { Vue.use = function (plugin) { - /* istanbul ignore if */ - if (plugin.installed) { - return + var installedPlugins = (this._installedPlugins || (this._installedPlugins = [])); + if (installedPlugins.indexOf(plugin) > -1) { + return this } + // additional parameters var args = toArray(arguments, 1); args.unshift(this); @@ -4076,7 +4339,7 @@ function initUse (Vue) { } else if (typeof plugin === 'function') { plugin.apply(null, args); } - plugin.installed = true; + installedPlugins.push(plugin); return this }; } @@ -4086,6 +4349,7 @@ function initUse (Vue) { function initMixin$1 (Vue) { Vue.mixin = function (mixin) { this.options = mergeOptions(this.options, mixin); + return this }; } @@ -4226,14 +4490,16 @@ function initAssetRegisters (Vue) { /* */ -var patternTypes = [String, RegExp]; +var patternTypes = [String, RegExp, Array]; function getComponentName (opts) { return opts && (opts.Ctor.options.name || opts.tag) } function matches (pattern, name) { - if (typeof pattern === 'string') { + if (Array.isArray(pattern)) { + return pattern.indexOf(name) > -1 + } else if (typeof pattern === 'string') { return pattern.split(',').indexOf(name) > -1 } else if (isRegExp(pattern)) { return pattern.test(name) @@ -4377,7 +4643,14 @@ Object.defineProperty(Vue$2.prototype, '$isServer', { get: isServerRendering }); -Vue$2.version = '2.3.0-beta.1'; +Object.defineProperty(Vue$2.prototype, '$ssrContext', { + get: function get () { + /* istanbul ignore next */ + return this.$vnode && this.$vnode.ssrContext + } +}); + +Vue$2.version = '2.4.2'; /* globals renderer */ // renderer is injected by weex factory wrapper @@ -4508,10 +4781,11 @@ function registerRef (vnode, isRemoval) { } } else { if (vnode.data.refInFor) { - if (Array.isArray(refs[key]) && refs[key].indexOf(ref) < 0) { - refs[key].push(ref); - } else { + if (!Array.isArray(refs[key])) { refs[key] = [ref]; + } else if (refs[key].indexOf(ref) < 0) { + // $flow-disable-line + refs[key].push(ref); } } else { refs[key] = ref; @@ -4539,11 +4813,18 @@ var hooks = ['create', 'activate', 'update', 'remove', 'destroy']; function sameVnode (a, b) { return ( - a.key === b.key && - a.tag === b.tag && - a.isComment === b.isComment && - isDef(a.data) === isDef(b.data) && - sameInputType(a, b) + a.key === b.key && ( + ( + a.tag === b.tag && + a.isComment === b.isComment && + isDef(a.data) === isDef(b.data) && + sameInputType(a, b) + ) || ( + isTrue(a.isAsyncPlaceholder) && + a.asyncFactory === b.asyncFactory && + isUndef(b.asyncFactory.error) + ) + ) ) } @@ -4696,6 +4977,7 @@ function createPatchFunction (backend) { function initComponent (vnode, insertedVnodeQueue) { if (isDef(vnode.data.pendingInsert)) { insertedVnodeQueue.push.apply(insertedVnodeQueue, vnode.data.pendingInsert); + vnode.data.pendingInsert = null; } vnode.elm = vnode.componentInstance.$el; if (isPatchable(vnode)) { @@ -4732,11 +5014,11 @@ function createPatchFunction (backend) { insert(parentElm, vnode.elm, refElm); } - function insert (parent, elm, ref) { + function insert (parent, elm, ref$$1) { if (isDef(parent)) { - if (isDef(ref)) { - if (ref.parentNode === parent) { - nodeOps.insertBefore(parent, elm, ref); + if (isDef(ref$$1)) { + if (ref$$1.parentNode === parent) { + nodeOps.insertBefore(parent, elm, ref$$1); } } else { nodeOps.appendChild(parent, elm); @@ -4786,8 +5068,9 @@ function createPatchFunction (backend) { } // for slot content they should also get the scopeId from the host instance. if (isDef(i = activeInstance) && - i !== vnode.context && - isDef(i = i.$options._scopeId)) { + i !== vnode.context && + isDef(i = i.$options._scopeId) + ) { nodeOps.setAttribute(vnode.elm, i, ''); } } @@ -4912,7 +5195,7 @@ function createPatchFunction (backend) { if (sameVnode(elmToMove, newStartVnode)) { patchVnode(elmToMove, newStartVnode, insertedVnodeQueue); oldCh[idxInOld] = undefined; - canMove && nodeOps.insertBefore(parentElm, newStartVnode.elm, oldStartVnode.elm); + canMove && nodeOps.insertBefore(parentElm, elmToMove.elm, oldStartVnode.elm); newStartVnode = newCh[++newStartIdx]; } else { // same key but different element. treat as new element @@ -4934,24 +5217,37 @@ function createPatchFunction (backend) { if (oldVnode === vnode) { return } + + var elm = vnode.elm = oldVnode.elm; + + if (isTrue(oldVnode.isAsyncPlaceholder)) { + if (isDef(vnode.asyncFactory.resolved)) { + hydrate(oldVnode.elm, vnode, insertedVnodeQueue); + } else { + vnode.isAsyncPlaceholder = true; + } + return + } + // reuse element for static trees. // note we only do this if the vnode is cloned - // if the new node is not cloned it means the render functions have been // reset by the hot-reload-api and we need to do a proper re-render. if (isTrue(vnode.isStatic) && - isTrue(oldVnode.isStatic) && - vnode.key === oldVnode.key && - (isTrue(vnode.isCloned) || isTrue(vnode.isOnce))) { - vnode.elm = oldVnode.elm; + isTrue(oldVnode.isStatic) && + vnode.key === oldVnode.key && + (isTrue(vnode.isCloned) || isTrue(vnode.isOnce)) + ) { vnode.componentInstance = oldVnode.componentInstance; return } + var i; var data = vnode.data; if (isDef(data) && isDef(i = data.hook) && isDef(i = i.prepatch)) { i(oldVnode, vnode); } - var elm = vnode.elm = oldVnode.elm; + var oldCh = oldVnode.children; var ch = vnode.children; if (isDef(data) && isPatchable(vnode)) { @@ -4996,6 +5292,11 @@ function createPatchFunction (backend) { // Note: this is a browser-only function so we can assume elms are DOM nodes. function hydrate (elm, vnode, insertedVnodeQueue) { + if (isTrue(vnode.isComment) && isDef(vnode.asyncFactory)) { + vnode.elm = elm; + vnode.isAsyncPlaceholder = true; + return true + } if (process.env.NODE_ENV !== 'production') { if (!assertNodeMatch(elm, vnode)) { return false @@ -5032,8 +5333,9 @@ function createPatchFunction (backend) { // longer than the virtual children list. if (!childrenMatch || childNode) { if (process.env.NODE_ENV !== 'production' && - typeof console !== 'undefined' && - !bailed) { + typeof console !== 'undefined' && + !bailed + ) { bailed = true; console.warn('Parent: ', elm); console.warn('Mismatching childNodes vs. VNodes: ', elm.childNodes, children); @@ -5313,8 +5615,10 @@ function updateClass (oldVnode, vnode) { var data = vnode.data; var oldData = oldVnode.data; - if (!data.staticClass && !data.class && - (!oldData || (!oldData.staticClass && !oldData.class))) { + if (!data.staticClass && + !data.class && + (!oldData || (!oldData.staticClass && !oldData.class)) + ) { return } @@ -5632,9 +5936,10 @@ function enter (_, vnode) { var parent = el.parentNode; var pendingNode = parent && parent._pending && parent._pending[vnode.key]; if (pendingNode && - pendingNode.context === vnode.context && - pendingNode.tag === vnode.tag && - pendingNode.elm._leaveCb) { + pendingNode.context === vnode.context && + pendingNode.tag === vnode.tag && + pendingNode.elm._leaveCb + ) { pendingNode.elm._leaveCb(); } enterHook && enterHook(el, cb); @@ -5893,6 +6198,10 @@ function isSameChild (child, oldChild) { return oldChild.key === child.key && oldChild.tag === child.tag } +function isAsyncPlaceholder (node) { + return node.isComment && node.asyncFactory +} + var Transition$1 = { name: 'transition', props: transitionProps, @@ -5901,13 +6210,13 @@ var Transition$1 = { render: function render (h) { var this$1 = this; - var children = this.$slots.default; + var children = this.$options._renderChildren; if (!children) { return } // filter out text nodes (possible whitespaces) - children = children.filter(function (c) { return c.tag; }); + children = children.filter(function (c) { return c.tag || isAsyncPlaceholder(c); }); /* istanbul ignore if */ if (!children.length) { return @@ -5926,7 +6235,8 @@ var Transition$1 = { // warn invalid mode if (process.env.NODE_ENV !== 'production' && - mode && mode !== 'in-out' && mode !== 'out-in') { + mode && mode !== 'in-out' && mode !== 'out-in' + ) { warn( 'invalid mode: ' + mode, this.$parent @@ -5958,7 +6268,9 @@ var Transition$1 = { // during entering. var id = "__transition-" + (this._uid) + "-"; child.key = child.key == null - ? id + child.tag + ? child.isComment + ? id + 'comment' + : id + child.tag : isPrimitive(child.key) ? (String(child.key).indexOf(id) === 0 ? child.key : id + child.key) : child.key; @@ -5973,7 +6285,12 @@ var Transition$1 = { child.data.show = true; } - if (oldChild && oldChild.data && !isSameChild(child, oldChild)) { + if ( + oldChild && + oldChild.data && + !isSameChild(child, oldChild) && + !isAsyncPlaceholder(oldChild) + ) { // replace old child transition data with fresh one // important for dynamic transitions! var oldData = oldChild && (oldChild.data.transition = extend({}, data)); @@ -5987,6 +6304,9 @@ var Transition$1 = { }); return placeholder(h, rawChild) } else if (mode === 'in-out') { + if (isAsyncPlaceholder(child)) { + return oldRawChild + } var delayedLeave; var performLeave = function () { delayedLeave(); }; mergeVNodeHook(data, 'afterEnter', performLeave); diff --git a/packages/weex-vue-framework/index.js b/packages/weex-vue-framework/index.js index 70b16298f7f..a05c5f54084 100644 --- a/packages/weex-vue-framework/index.js +++ b/packages/weex-vue-framework/index.js @@ -34,7 +34,7 @@ function init (cfg) { renderer.Document = cfg.Document; renderer.Element = cfg.Element; renderer.Comment = cfg.Comment; - renderer.sendTasks = cfg.sendTasks; + renderer.compileBundle = cfg.compileBundle; } /** @@ -47,7 +47,7 @@ function reset () { delete renderer.Document; delete renderer.Element; delete renderer.Comment; - delete renderer.sendTasks; + delete renderer.compileBundle; } /** @@ -82,18 +82,9 @@ function createInstance ( // Virtual-DOM object. var document = new renderer.Document(instanceId, config.bundleUrl); - // All function/callback of parameters before sent to native - // will be converted as an id. So `callbacks` is used to store - // these real functions. When a callback invoked and won't be - // called again, it should be removed from here automatically. - var callbacks = []; - - // The latest callback id, incremental. - var callbackId = 1; - var instance = instances[instanceId] = { instanceId: instanceId, config: config, data: data, - document: document, callbacks: callbacks, callbackId: callbackId + document: document }; // Prepare native module getter and HTML5 Timer APIs. @@ -104,6 +95,7 @@ function createInstance ( var weexInstanceVar = { config: config, document: document, + supports: supports, requireModule: moduleGetter }; Object.freeze(weexInstanceVar); @@ -118,11 +110,16 @@ function createInstance ( weex: weexInstanceVar, // deprecated __weex_require_module__: weexInstanceVar.requireModule // eslint-disable-line - }, timerAPIs); - callFunction(instanceVars, appCode); + }, timerAPIs, env.services); + + if (!callFunctionNative(instanceVars, appCode)) { + // If failed to compile functionBody on native side, + // fallback to 'callFunction()'. + callFunction(instanceVars, appCode); + } // Send `createFinish` signal to native. - renderer.sendTasks(instanceId + '', [{ module: 'dom', method: 'createFinish', args: [] }], -1); + instance.document.taskCenter.send('dom', { action: 'createFinish' }, []); } /** @@ -133,6 +130,7 @@ function createInstance ( function destroyInstance (instanceId) { var instance = instances[instanceId]; if (instance && instance.app instanceof instance.Vue) { + instance.document.destroy(); instance.app.$destroy(); } delete instances[instanceId]; @@ -154,7 +152,7 @@ function refreshInstance (instanceId, data) { instance.Vue.set(instance.app, key, data[key]); } // Finally `refreshFinish` signal needed. - renderer.sendTasks(instanceId + '', [{ module: 'dom', method: 'refreshFinish', args: [] }], -1); + instance.document.taskCenter.send('dom', { action: 'refreshFinish' }, []); } /** @@ -169,49 +167,57 @@ function getRoot (instanceId) { return instance.app.$el.toJSON() } +var jsHandlers = { + fireEvent: function (id) { + var args = [], len = arguments.length - 1; + while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ]; + + return fireEvent.apply(void 0, [ instances[id] ].concat( args )) + }, + callback: function (id) { + var args = [], len = arguments.length - 1; + while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ]; + + return callback.apply(void 0, [ instances[id] ].concat( args )) + } +}; + +function fireEvent (instance, nodeId, type, e, domChanges) { + var el = instance.document.getRef(nodeId); + if (el) { + return instance.document.fireEvent(el, type, e, domChanges) + } + return new Error(("invalid element reference \"" + nodeId + "\"")) +} + +function callback (instance, callbackId, data, ifKeepAlive) { + var result = instance.document.taskCenter.callback(callbackId, data, ifKeepAlive); + instance.document.taskCenter.send('dom', { action: 'updateFinish' }, []); + return result +} + /** - * Receive tasks from native. Generally there are two types of tasks: - * 1. `fireEvent`: an device actions or user actions from native. - * 2. `callback`: invoke function which sent to native as a parameter before. - * @param {string} instanceId - * @param {array} tasks + * Accept calls from native (event or callback). + * + * @param {string} id + * @param {array} tasks list with `method` and `args` */ -function receiveTasks (instanceId, tasks) { - var instance = instances[instanceId]; - if (!instance || !(instance.app instanceof instance.Vue)) { - return new Error(("receiveTasks: instance " + instanceId + " not found!")) - } - var callbacks = instance.callbacks; - var document = instance.document; - tasks.forEach(function (task) { - // `fireEvent` case: find the event target and fire. - if (task.method === 'fireEvent') { - var ref = task.args; - var nodeId = ref[0]; - var type = ref[1]; - var e = ref[2]; - var domChanges = ref[3]; - var el = document.getRef(nodeId); - document.fireEvent(el, type, e, domChanges); - } - // `callback` case: find the callback by id and call it. - if (task.method === 'callback') { - var ref$1 = task.args; - var callbackId = ref$1[0]; - var data = ref$1[1]; - var ifKeepAlive = ref$1[2]; - var callback = callbacks[callbackId]; - if (typeof callback === 'function') { - callback(data); - // Remove the callback from `callbacks` if it won't called again. - if (typeof ifKeepAlive === 'undefined' || ifKeepAlive === false) { - callbacks[callbackId] = undefined; - } +function receiveTasks (id, tasks) { + var instance = instances[id]; + if (instance && Array.isArray(tasks)) { + var results = []; + tasks.forEach(function (task) { + var handler = jsHandlers[task.method]; + var args = [].concat( task.args ); + /* istanbul ignore else */ + if (typeof handler === 'function') { + args.unshift(id); + results.push(handler.apply(void 0, args)); } - } - }); - // Finally `updateFinish` signal needed. - renderer.sendTasks(instanceId + '', [{ module: 'dom', method: 'updateFinish', args: [] }], -1); + }); + return results + } + return new Error(("invalid instance id \"" + id + "\" or tasks")) } /** @@ -235,6 +241,18 @@ function registerModules (newModules) { for (var name in newModules) loop( name ); } +/** + * Check whether the module or the method has been registered. + * @param {String} module name + * @param {String} method name (optional) + */ +function isRegisteredModule (name, method) { + if (typeof method === 'string') { + return !!(modules[name] && modules[name][method]) + } + return !!modules[name] +} + /** * Register native components information. * @param {array} newComponents @@ -254,6 +272,35 @@ function registerComponents (newComponents) { } } +/** + * Check whether the component has been registered. + * @param {String} component name + */ +function isRegisteredComponent (name) { + return !!components[name] +} + +/** + * Detects whether Weex supports specific features. + * @param {String} condition + */ +function supports (condition) { + if (typeof condition !== 'string') { return null } + + var res = condition.match(/^@(\w+)\/(\w+)(\.(\w+))?$/i); + if (res) { + var type = res[1]; + var name = res[2]; + var method = res[4]; + switch (type) { + case 'module': return isRegisteredModule(name, method) + case 'component': return isRegisteredComponent(name) + } + } + + return null +} + /** * Create a fresh instance of Vue for each Weex instance. */ @@ -314,9 +361,7 @@ function createVueModuleInstance (instanceId, moduleGetter) { * Generate native module getter. Each native module has several * methods to call. And all the behaviors is instance-related. So * this getter will return a set of methods which additionally - * send current instance id to native when called. Also the args - * will be normalized into "safe" value. For example function arg - * will be converted into a callback id. + * send current instance id to native when called. * @param {string} instanceId * @return {function} */ @@ -326,15 +371,23 @@ function genModuleGetter (instanceId) { var nativeModule = modules[name] || []; var output = {}; var loop = function ( methodName ) { - output[methodName] = function () { - var args = [], len = arguments.length; - while ( len-- ) args[ len ] = arguments[ len ]; - - var finalArgs = args.map(function (value) { - return normalize(value, instance) - }); - renderer.sendTasks(instanceId + '', [{ module: name, method: methodName, args: finalArgs }], -1); - }; + Object.defineProperty(output, methodName, { + enumerable: true, + configurable: true, + get: function proxyGetter () { + return function () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + return instance.document.taskCenter.send('module', { module: name, method: methodName }, args) + } + }, + set: function proxySetter (val) { + if (typeof val === 'function') { + return instance.document.taskCenter.send('module', { module: name, method: methodName }, [val]) + } + } + }); }; for (var methodName in nativeModule) loop( methodName ); @@ -362,8 +415,9 @@ function getInstanceTimer (instanceId, moduleGetter) { var handler = function () { args[0].apply(args, args.slice(2)); }; + timer.setTimeout(handler, args[1]); - return instance.callbackId.toString() + return instance.document.taskCenter.callbackManager.lastCallbackId.toString() }, setInterval: function () { var args = [], len = arguments.length; @@ -372,8 +426,9 @@ function getInstanceTimer (instanceId, moduleGetter) { var handler = function () { args[0].apply(args, args.slice(2)); }; + timer.setInterval(handler, args[1]); - return instance.callbackId.toString() + return instance.document.taskCenter.callbackManager.lastCallbackId.toString() }, clearTimeout: function (n) { timer.clearTimeout(n); @@ -405,52 +460,55 @@ function callFunction (globalObjects, body) { } /** - * Convert all type of values into "safe" format to send to native. - * 1. A `function` will be converted into callback id. - * 2. An `Element` object will be converted into `ref`. - * The `instance` param is used to generate callback id and store - * function if necessary. - * @param {any} v - * @param {object} instance - * @return {any} + * Call a new function generated on the V8 native side. + * + * This function helps speed up bundle compiling. Normally, the V8 + * engine needs to download, parse, and compile a bundle on every + * visit. If 'compileBundle()' is available on native side, + * the downloding, parsing, and compiling steps would be skipped. + * @param {object} globalObjects + * @param {string} body + * @return {boolean} */ -function normalize (v, instance) { - var type = typof(v); - - switch (type) { - case 'undefined': - case 'null': - return '' - case 'regexp': - return v.toString() - case 'date': - return v.toISOString() - case 'number': - case 'string': - case 'boolean': - case 'array': - case 'object': - if (v instanceof renderer.Element) { - return v.ref - } - return v - case 'function': - instance.callbacks[++instance.callbackId] = v; - return instance.callbackId.toString() - default: - return JSON.stringify(v) +function callFunctionNative (globalObjects, body) { + if (typeof renderer.compileBundle !== 'function') { + return false } -} -/** - * Get the exact type of an object by `toString()`. For example call - * `toString()` on an array will be returned `[object Array]`. - * @param {any} v - * @return {string} - */ -function typof (v) { - var s = Object.prototype.toString.call(v); - return s.substring(8, s.length - 1).toLowerCase() + var fn = void 0; + var isNativeCompileOk = false; + var script = '(function ('; + var globalKeys = []; + var globalValues = []; + for (var key in globalObjects) { + globalKeys.push(key); + globalValues.push(globalObjects[key]); + } + for (var i = 0; i < globalKeys.length - 1; ++i) { + script += globalKeys[i]; + script += ','; + } + script += globalKeys[globalKeys.length - 1]; + script += ') {'; + script += body; + script += '} )'; + + try { + var weex = globalObjects.weex || {}; + var config = weex.config || {}; + fn = renderer.compileBundle(script, + config.bundleUrl, + config.bundleDigest, + config.codeCachePath); + if (fn && typeof fn === 'function') { + fn.apply(void 0, globalValues); + isNativeCompileOk = true; + } + } catch (e) { + console.error(e); + } + + return isNativeCompileOk } exports.init = init; @@ -461,4 +519,7 @@ exports.refreshInstance = refreshInstance; exports.getRoot = getRoot; exports.receiveTasks = receiveTasks; exports.registerModules = registerModules; +exports.isRegisteredModule = isRegisteredModule; exports.registerComponents = registerComponents; +exports.isRegisteredComponent = isRegisteredComponent; +exports.supports = supports; diff --git a/packages/weex-vue-framework/package.json b/packages/weex-vue-framework/package.json index ed5f69be00e..71bd1d65c88 100644 --- a/packages/weex-vue-framework/package.json +++ b/packages/weex-vue-framework/package.json @@ -1,6 +1,6 @@ { "name": "weex-vue-framework", - "version": "2.1.9-weex.1", + "version": "2.4.2-weex.1", "description": "Vue 2.0 Framework for Weex", "main": "index.js", "repository": { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy