diff --git a/dist/avalon.js b/dist/avalon.js index 2a8a2b291..71b7402a5 100644 --- a/dist/avalon.js +++ b/dist/avalon.js @@ -1,4 +1,4 @@ -/*! built in 2016-5-19:10 version 2.01 by 司徒正美 */ +/*! built in 2016-5-20:14 version 2.01 by 司徒正美 */ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); @@ -62,9 +62,9 @@ return /******/ (function(modules) { // webpackBootstrap __webpack_require__(15) __webpack_require__(19) __webpack_require__(35) - __webpack_require__(70) - __webpack_require__(74) + __webpack_require__(71) __webpack_require__(75) + __webpack_require__(76) module.exports = avalon @@ -848,7 +848,7 @@ return /******/ (function(modules) { // webpackBootstrap } kernel.plugins = plugins kernel.plugins['interpolate'](['{{', '}}']) - + //kernel.showDiff = true kernel.debug = true @@ -3168,28 +3168,28 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { __webpack_require__(36) - __webpack_require__(43) - //处理属性样式 __webpack_require__(44) - __webpack_require__(47) + //处理属性样式 + __webpack_require__(45) __webpack_require__(48) - //处理内容 __webpack_require__(49) + //处理内容 __webpack_require__(50) __webpack_require__(51) - //需要用到事件的 __webpack_require__(52) + //需要用到事件的 __webpack_require__(53) __webpack_require__(54) - __webpack_require__(61) + __webpack_require__(55) __webpack_require__(62) - - //处理逻辑 __webpack_require__(63) - __webpack_require__(65) + //处理逻辑 + __webpack_require__(64) __webpack_require__(66) - __webpack_require__(68) + + __webpack_require__(67) + __webpack_require__(69) //优先级 ms-important, ms-controller, ms-for, ms-widget, ms-effect, ms-if //....... //ms-duplex @@ -3199,6 +3199,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { var parseView = __webpack_require__(37) + var update = __webpack_require__(43) avalon.important = function (elem, vid) { //如果vmodel还不存在,直接返回 @@ -3241,10 +3242,7 @@ return /******/ (function(modules) { // webpackBootstrap }, diff: function (cur, pre, steps, name) { if (pre.props[name] !== cur.props[name]) { - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 - } + update(cur, this.update, steps, 'important' ) } }, update: function (node, vnode) { @@ -3783,7 +3781,23 @@ return /******/ (function(modules) { // webpackBootstrap /* 43 */ /***/ function(module, exports) { + module.exports = function (cur, update, steps, type, hookName) { + hookName = hookName || 'change' + var list = cur[hookName] || (cur[hookName] = []) + if (avalon.Array.ensure(list, update)) { + steps.count += 1 + avalon.config.showDiff && avalon.log(type+ ' change') + } + } + + +/***/ }, +/* 44 */ +/***/ function(module, exports, __webpack_require__) { + // 抽离出来公用 + var update = __webpack_require__(43) + avalon.skipController = function (fast, vm, iv) { if (fast) { var id = vm.$render ? vm.$render.$id : vm.$id @@ -3822,10 +3836,8 @@ return /******/ (function(modules) { // webpackBootstrap }, diff: function (cur, pre, steps, name) { if (pre.props[name] !== cur.props[name]) { - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 - } + console.log('controller',steps) + update(cur, this.update, steps, 'controller' ) } }, update: function (node, vnode) { @@ -3856,11 +3868,12 @@ return /******/ (function(modules) { // webpackBootstrap }) /***/ }, -/* 44 */ +/* 45 */ /***/ function(module, exports, __webpack_require__) { - var attrUpdate = __webpack_require__(45) + var attrUpdate = __webpack_require__(46) + var update = __webpack_require__(43) avalon.directive('attr', { parse: function (binding, num) { @@ -3889,11 +3902,8 @@ return /******/ (function(modules) { // webpackBootstrap cur.changeAttr = patch } } - if (cur.changeAttr) { - var list = cur.change || (cur.change = []) - if(avalon.Array.ensure(list, this.update)){ - steps.count += 1 - } + if (cur.changeAttr) { + update(cur, this.update, steps, 'attr' ) } } else { cur.props[name] = p @@ -3907,11 +3917,11 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 45 */ +/* 46 */ /***/ function(module, exports, __webpack_require__) { - var propMap = __webpack_require__(46) + var propMap = __webpack_require__(47) var isVML = __webpack_require__(29) var rsvg =/^\[object SVG\w*Element\]$/ var ramp = /&/g @@ -3975,7 +3985,7 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = attrUpdate /***/ }, -/* 46 */ +/* 47 */ /***/ function(module, exports) { var propMap = {//不规则的属性名映射 @@ -4019,10 +4029,11 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 47 */ -/***/ function(module, exports) { +/* 48 */ +/***/ function(module, exports, __webpack_require__) { + var update = __webpack_require__(43) avalon.directive('css', { parse: function (binding, num) { @@ -4031,7 +4042,7 @@ return /******/ (function(modules) { // webpackBootstrap diff: function (cur, pre, steps, name) { var a = cur.props[name] var p = pre.props[name] - if ( Object(a) === a) { + if (Object(a) === a) { if (Array.isArray(a)) { a = cur.props[name] = avalon.mix.apply({}, a) } @@ -4051,10 +4062,7 @@ return /******/ (function(modules) { // webpackBootstrap } } if (cur.changeStyle) { - var list = cur.change || (cur.change = []) - if(avalon.Array.ensure(list, this.update)){ - steps.count += 1 - } + update(cur, this.update, steps, 'css') } } else { cur.props[name] = p @@ -4072,10 +4080,11 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 48 */ -/***/ function(module, exports) { +/* 49 */ +/***/ function(module, exports, __webpack_require__) { + + var update = __webpack_require__(43) - var none = 'none' function parseDisplay(elem, val) { //用于取得此类标签的默认display值 @@ -4108,10 +4117,7 @@ return /******/ (function(modules) { // webpackBootstrap var c = cur.props[name] = !!cur.props[name] cur.displayValue = pre.displayValue if (c !== pre.props[name]) { - var list = cur.change || (cur.change = []) - if(avalon.Array.ensure(list, this.update)){ - steps.count += 1 - } + update(cur, this.update, steps, 'visible' ) } }, update: function (node, vnode) { @@ -4152,10 +4158,11 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 49 */ -/***/ function(module, exports) { +/* 50 */ +/***/ function(module, exports, __webpack_require__) { + + var update = __webpack_require__(43) - avalon.directive('expr', { parse: function () { }, @@ -4166,10 +4173,7 @@ return /******/ (function(modules) { // webpackBootstrap if (dom && avalon.contains(avalon.root,dom)) { this.update(dom, cur) } else { - var list = cur.change || (cur.change = []) - if(avalon.Array.ensure(list, this.update)){ - steps.count += 1 - } + update(cur, this.update, steps, 'expr' ) } } pre.dom = null @@ -4188,10 +4192,12 @@ return /******/ (function(modules) { // webpackBootstrap }) /***/ }, -/* 50 */ +/* 51 */ /***/ function(module, exports, __webpack_require__) { var rident = __webpack_require__(40).ident + var update = __webpack_require__(43) + avalon.directive('text', { parse: function (binding, num, vnode) { vnode.children = [{type: '#text', nodeType: 3, nodeValue: ''}] @@ -4210,10 +4216,7 @@ return /******/ (function(modules) { // webpackBootstrap if (dom) { this.update(dom, cur) } else { - var list = cur.change || (cur.change = []) - if(avalon.Array.ensure(list, this.update)){ - steps.count += 1 - } + update(cur, this.update, steps, 'text' ) } } pre.dom = null @@ -4231,8 +4234,10 @@ return /******/ (function(modules) { // webpackBootstrap }) /***/ }, -/* 51 */ -/***/ function(module, exports) { +/* 52 */ +/***/ function(module, exports, __webpack_require__) { + + var update = __webpack_require__(43) avalon.directive('html', { parse: function (binding, num,el) { @@ -4251,12 +4256,7 @@ return /******/ (function(modules) { // webpackBootstrap var preValue = pre.props[name] cur.isVoidTag = cur._isVoidTag if (curValue !== preValue) { - if (cur.props[name] !== preValue) { - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 - } - } + update(cur, this.update, steps, 'html' ) } }, update: function (node, vnode) { @@ -4275,12 +4275,13 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 52 */ +/* 53 */ /***/ function(module, exports, __webpack_require__) { //根据VM的属性值或表达式的值切换类名,ms-class='xxx yyy zzz:flag' //http://www.cnblogs.com/rubylouvre/archive/2012/12/17/2818540.html var markID = __webpack_require__(6).getLongID + var update = __webpack_require__(43) var directives = avalon.directives avalon.directive('class', { @@ -4328,15 +4329,15 @@ return /******/ (function(modules) { // webpackBootstrap return } className = cur.props[name] = className.trim().replace(/\s+/, ' ') - if (!preValue || preValue !== className) { + if (preValue !== className) { cur['change-' + type] = className - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 - } + update(cur, this.update, steps, type ) } }, update: function (node, vnode) { + + if(!node || node.nodeType !==1) + return var classEvent = vnode.classEvent if (classEvent) { for (var i in classEvent) { @@ -4355,7 +4356,7 @@ return /******/ (function(modules) { // webpackBootstrap if (value === void 0) return if (type === 'class') { - setClass(node, vnode) + node && setClass(node, vnode) } else { var oldType = node.getAttribute('change-'+type) if (oldType) { @@ -4410,13 +4411,14 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 53 */ +/* 54 */ /***/ function(module, exports, __webpack_require__) { var markID = __webpack_require__(6).getLongID var Cache = __webpack_require__(26) var eventCache = new Cache(128) var quote = avalon.quote + var update = __webpack_require__(43) //Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes // The assumption is that future DOM event attribute names will begin with @@ -4456,7 +4458,7 @@ return /******/ (function(modules) { // webpackBootstrap var fn0 = cur.props[name] var fn1 = (pre.props || {})[name] - if ( fn0 !== fn1 ) { + if ( fn0 +''!== fn1+'' ) { var match = name.match(revent) var type = match[1] var search = type + ':' + markID(fn0) @@ -4467,11 +4469,7 @@ return /******/ (function(modules) { // webpackBootstrap cur.removeEvents = cur.removeEvents || {} cur.removeEvents[type + ':' + fn1.uuid] = fn1 } - - var list = cur.change || (cur.change = []) - if(avalon.Array.ensure(list, this.update)){ - steps.count += 1 - } + update(cur, this.update, steps, 'on' ) } }, @@ -4502,16 +4500,17 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 54 */ +/* 55 */ /***/ function(module, exports, __webpack_require__) { - var valueHijack = __webpack_require__(55) + var valueHijack = __webpack_require__(56) - var newField = __webpack_require__(56) - var initField = __webpack_require__(57) - var updateField = __webpack_require__(59) - var addField = __webpack_require__(60) + var newField = __webpack_require__(57) + var initField = __webpack_require__(58) + var updateField = __webpack_require__(60) + var addField = __webpack_require__(61) + var update = __webpack_require__(43) var evaluatorPool = __webpack_require__(39) avalon.directive('duplex', { priority: 2000, @@ -4559,9 +4558,8 @@ return /******/ (function(modules) { // webpackBootstrap if (!isEqual) { field.modelValue = value - var afterChange = cur.afterChange || (cur.afterChange = []) - avalon.Array.ensure(afterChange, this.update) - steps.count += 1 + update(cur, this.update, steps, 'duplex', 'afterChange') + } }, update: function (node, vnode) { @@ -4635,7 +4633,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 55 */ +/* 56 */ /***/ function(module, exports) { var valueHijack = false @@ -4669,7 +4667,7 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = valueHijack /***/ }, -/* 56 */ +/* 57 */ /***/ function(module, exports) { var rchangeFilter = /\|\s*change\b/ @@ -4765,13 +4763,13 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 57 */ +/* 58 */ /***/ function(module, exports, __webpack_require__) { var msie = avalon.msie var window = avalon.window var document = avalon.document - var refreshModel = __webpack_require__(58) + var refreshModel = __webpack_require__(59) var markID = __webpack_require__(6).getShortID @@ -5008,7 +5006,7 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = initControl /***/ }, -/* 58 */ +/* 59 */ /***/ function(module, exports) { @@ -5102,7 +5100,7 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = refreshModel /***/ }, -/* 59 */ +/* 60 */ /***/ function(module, exports) { @@ -5155,7 +5153,7 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = updateField /***/ }, -/* 60 */ +/* 61 */ /***/ function(module, exports) { @@ -5180,8 +5178,10 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 61 */ -/***/ function(module, exports) { +/* 62 */ +/***/ function(module, exports, __webpack_require__) { + + var update = __webpack_require__(43) var dir = avalon.directive('validate', { //验证单个表单元素 @@ -5204,10 +5204,8 @@ return /******/ (function(modules) { // webpackBootstrap } } validator.fields = validator.fields || [] - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 - } + update(cur, this.update, steps, 'validate' ) + } }, update: function (node, vnode) { @@ -5356,7 +5354,7 @@ return /******/ (function(modules) { // webpackBootstrap } /***/ }, -/* 62 */ +/* 63 */ /***/ function(module, exports) { avalon.directive('rules', { @@ -5498,11 +5496,12 @@ return /******/ (function(modules) { // webpackBootstrap }) /***/ }, -/* 63 */ +/* 64 */ /***/ function(module, exports, __webpack_require__) { - var patch = __webpack_require__(64) - var uniqueID = 1 + var patch = __webpack_require__(65) + var update = __webpack_require__(43) + //ms-imporant ms-controller ms-for ms-widget ms-effect ms-if ... avalon.directive('if', { priority: 6, @@ -5521,11 +5520,8 @@ return /******/ (function(modules) { // webpackBootstrap diff: function (cur, pre, steps) { cur.dom = pre.dom if (cur.nodeType !== pre.nodeType) { - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 - cur.steps = steps - } + cur.steps = steps + update(cur, this.update, steps, 'if' ) } }, update: function (node, vnode, parent) { @@ -5577,7 +5573,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 64 */ +/* 65 */ /***/ function(module, exports) { /** @@ -5604,7 +5600,7 @@ return /******/ (function(modules) { // webpackBootstrap next = node.nextSibling } if (vnode.directive === 'for') { - if (vnode.change) { + if (vnode.hasChange) { if (!node) { return } @@ -5624,9 +5620,7 @@ return /******/ (function(modules) { // webpackBootstrap } next = vnode.endRepeat.nextSibling } - } - //ms-for, ms-if, ms-widget会返回false if (false === execHooks(node, vnode, parent, steps, 'change')) { if (vnode.repeatCount) { @@ -5687,24 +5681,30 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = patch /***/ }, -/* 65 */ +/* 66 */ /***/ function(module, exports, __webpack_require__) { - var patch = __webpack_require__(64) + var patch = __webpack_require__(65) var rforPrefix = /ms-for\:\s*/ var rforLeft = /^\s*\(\s*/ var rforRight = /\s*\)\s*$/ var rforSplit = /\s*,\s*/ var rforAs = /\s+as\s+([$\w]+)/ var rident = __webpack_require__(40).ident + var update = __webpack_require__(43) + var rinvalid = /^(null|undefined|NaN|window|this|\$index|\$id)$/ + function getTrackKey(item){ + var type = typeof item + return item && type === 'object' ? item.$hashcode : type + item + } + avalon._each = function (obj, fn) { if (Array.isArray(obj)) { for (var i = 0; i < obj.length; i++) { var item = obj[i] - var type = typeof item - var key = item && type === 'object' ? item.$hashcode : type + item - fn(i, obj[i], key) + var key = getTrackKey(item) + fn(i, item, key) } } else { for (var i in obj) { @@ -5714,7 +5714,36 @@ return /******/ (function(modules) { // webpackBootstrap } } } - var map = {} + var loopMap = {} + function getLoopValue(object){ + if(Array.isArray(object)){ + return object.length+"|"+object.map(getTrackKey).join(';;') + }else{ + var size = 0 + var arr = [] + for(var i in object){ + if(object.hasOwnProperty(i)){ + size++ + arr.push(i) + } + } + return size+"|"+arr.join(';;') + } + } + + avalon._checkLoopChange = function(key, obj){ + var cur = getLoopValue(obj) + if(!(key in loopMap)){ + loopMap[key] = cur + return true + } + if(cur !== loopMap[key]){ + loopMap[key] = cur + return true + } + return false + } + avalon.directive('for', { priority: 3, parse: function (el, num) { @@ -5727,15 +5756,18 @@ return /******/ (function(modules) { // webpackBootstrap } return '' }) + var arr = str.replace(rforPrefix, '').split(' in ') var assign = 'var loop' + num + ' = ' + avalon.parseExpr(arr[1]) + '\n' + var isChange = el.signature+'.hasChange = avalon._checkLoopChange("'+el.signature+'", loop' + num + ')\n' + var alias = aliasAs ? 'var ' + aliasAs + ' = loop' + num + '\n' : '' var kv = arr[0].replace(rforLeft, '').replace(rforRight, '').split(rforSplit) if (kv.length === 1) {//确保avalon._each的回调有三个参数 kv.unshift('$key') } //分别创建isArray, ____n, ___i, ___v, ___trackKey变量 - return assign + alias + 'avalon._each(loop' + num + ', function(' + kv + ', traceKey){\n' + return assign +isChange+ alias + 'avalon._each(loop' + num + ', function(' + kv + ', traceKey){\n' }, diff: function (current, previous, steps, __index__) { @@ -5819,10 +5851,8 @@ return /******/ (function(modules) { // webpackBootstrap pre.components.length = 0 //release memory delete pre.cache if (isChange) { - var list = cur.change || (cur.change = []) - avalon.Array.ensure(list, this.update) cur.steps = steps - steps.count += 1 + update(cur, this.update, steps, 'for') } return __index__ + nodes.length - 1 @@ -6057,11 +6087,12 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 66 */ +/* 67 */ /***/ function(module, exports, __webpack_require__) { - var disposeDetectStrategy = __webpack_require__(67) - var patch = __webpack_require__(64) + var disposeDetectStrategy = __webpack_require__(68) + var patch = __webpack_require__(65) + var update = __webpack_require__(43) //插入点机制,组件的模板中有一些slot元素,用于等待被外面的元素替代 var dir = avalon.directive('widget', { @@ -6102,10 +6133,8 @@ return /******/ (function(modules) { // webpackBootstrap cur.change = [this.replaceByComment] } else if (docker.renderCount && docker.renderCount < 2) { cur.steps = steps - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.replaceByComponent)) { - steps.count += 1 - } + update(cur, this.replaceByComponent, steps, 'widget' ) + function fireReady(dom, vnode) { cur.vmodel.$fire('onReady', { type: 'ready', @@ -6115,10 +6144,7 @@ return /******/ (function(modules) { // webpackBootstrap }) docker.renderCount = 2 } - list = cur.afterChange || (cur.afterChange = []) - if (avalon.Array.ensure(list, fireReady)) { - steps.count += 1 - } + update(cur, fireReady, steps, 'widget', 'afterChange' ) } else { var needUpdate = !cur.diff || cur.diff(cur, pre, steps) @@ -6190,7 +6216,7 @@ return /******/ (function(modules) { // webpackBootstrap // http://www.besteric.com/2014/11/16/build-blog-mirror-site-on-gitcafe/ /***/ }, -/* 67 */ +/* 68 */ /***/ function(module, exports) { //用于chrome, safari @@ -6333,11 +6359,12 @@ return /******/ (function(modules) { // webpackBootstrap } /***/ }, -/* 68 */ +/* 69 */ /***/ function(module, exports, __webpack_require__) { - var support = __webpack_require__(69) + var support = __webpack_require__(70) var Cache = __webpack_require__(26) + var update = __webpack_require__(43) avalon.directive('effect', { priority: 5, @@ -6361,10 +6388,8 @@ return /******/ (function(modules) { // webpackBootstrap if (Object(curObj) === curObj) { var preObj = pre.props[name] if ( Object(preObj) !== preObj || diffObj(curObj, preObj )) { - var list = cur.afterChange = cur.afterChange || [] - if(avalon.Array.ensure(list, this.update)){ - steps.count += 1 - } + update(cur, this.update, steps, 'effect', 'afterChange') + } } }, @@ -6586,7 +6611,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 69 */ +/* 70 */ /***/ function(module, exports) { /** @@ -6665,13 +6690,13 @@ return /******/ (function(modules) { // webpackBootstrap } /***/ }, -/* 70 */ +/* 71 */ /***/ function(module, exports, __webpack_require__) { - avalon.lexer = __webpack_require__(71) - avalon.diff = __webpack_require__(72) - avalon.batch = __webpack_require__(73) + avalon.lexer = __webpack_require__(72) + avalon.diff = __webpack_require__(73) + avalon.batch = __webpack_require__(74) // dispatch与patch 为内置模块 var parseView = __webpack_require__(37) @@ -6688,7 +6713,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 71 */ +/* 72 */ /***/ function(module, exports, __webpack_require__) { /** @@ -7061,7 +7086,7 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = lexer /***/ }, -/* 72 */ +/* 73 */ /***/ function(module, exports, __webpack_require__) { /** @@ -7093,9 +7118,14 @@ return /******/ (function(modules) { // webpackBootstrap } break case 8: - if (cur.directive === 'for') { - i = directives['for'].diff(current, previous, steps, i) - } else if (cur.directive) {//if widget + if (cur.directive === 'for' ) { + if(cur.hasChange){ + i = directives['for'].diff(current, previous, steps, i) + }else{ + avalon.shadowCopy(cur, previous[i]) + delete cur.hasChange + } + } else if (cur.directive ) {//if widget directives[cur.directive].diff(cur, pre, steps) } break @@ -7134,7 +7164,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 73 */ +/* 74 */ /***/ function(module, exports, __webpack_require__) { @@ -7144,7 +7174,7 @@ return /******/ (function(modules) { // webpackBootstrap * ------------------------------------------------------------ */ - var patch = __webpack_require__(64) + var patch = __webpack_require__(65) //如果正在更新一个子树,那么将它放到 @@ -7228,7 +7258,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 74 */ +/* 75 */ /***/ function(module, exports, __webpack_require__) { @@ -7505,7 +7535,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 75 */ +/* 76 */ /***/ function(module, exports, __webpack_require__) { /** @@ -7515,7 +7545,7 @@ return /******/ (function(modules) { // webpackBootstrap * ------------------------------------------------------------ */ - var share = __webpack_require__(76) + var share = __webpack_require__(77) var isSkip = share.isSkip var toJson = share.toJson @@ -7582,7 +7612,7 @@ return /******/ (function(modules) { // webpackBootstrap } $$midway.masterFactory = masterFactory - var addAccessors = __webpack_require__(81) + var addAccessors = __webpack_require__(82) var empty = {} function slaveFactory(before, after, heirloom, options) { var keys = {} @@ -7801,11 +7831,11 @@ return /******/ (function(modules) { // webpackBootstrap //使用这个AJAX库 https://github.com/matthew-andrews/isomorphic-fetch /***/ }, -/* 76 */ +/* 77 */ /***/ function(module, exports, __webpack_require__) { - var share = __webpack_require__(77) - var canHideProperty = __webpack_require__(80) + var share = __webpack_require__(78) + var canHideProperty = __webpack_require__(81) var makeFire = share.makeFire function toJson(val) { var xtype = avalon.type(val) @@ -7894,13 +7924,13 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 77 */ +/* 78 */ /***/ function(module, exports, __webpack_require__) { var $$midway = {} - var $$skipArray = __webpack_require__(78) - var dispatch = __webpack_require__(79) + var $$skipArray = __webpack_require__(79) + var dispatch = __webpack_require__(80) var $emit = dispatch.$emit var $watch = dispatch.$watch @@ -8166,7 +8196,7 @@ return /******/ (function(modules) { // webpackBootstrap } /***/ }, -/* 78 */ +/* 79 */ /***/ function(module, exports) { /** @@ -8182,7 +8212,7 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = avalon.oneObject('$id,$render,$track,$element,$watch,$fire,$events,$model,$skipArray,$accessors,$hashcode,__proxy__,__data__,__const__') /***/ }, -/* 79 */ +/* 80 */ /***/ function(module, exports) { @@ -8284,7 +8314,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 80 */ +/* 81 */ /***/ function(module, exports) { //如果浏览器不支持ecma262v5的Object.defineProperties或者存在BUG,比如IE8 @@ -8301,12 +8331,12 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = flag /***/ }, -/* 81 */ +/* 82 */ /***/ function(module, exports, __webpack_require__) { - var canHideProperty = __webpack_require__(80) - var $$skipArray = __webpack_require__(78) + var canHideProperty = __webpack_require__(81) + var $$skipArray = __webpack_require__(79) var defineProperties = Object.defineProperties diff --git a/dist/avalon.modern.js b/dist/avalon.modern.js index 68b1c5a2a..698383199 100644 --- a/dist/avalon.modern.js +++ b/dist/avalon.modern.js @@ -1,4 +1,4 @@ -/*! built in 2016-5-19:10 version 2.01 by 司徒正美 */ +/*! built in 2016-5-20:14 version 2.01 by 司徒正美 */ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); @@ -55,15 +55,15 @@ return /******/ (function(modules) { // webpackBootstrap /* 0 */ /***/ function(module, exports, __webpack_require__) { - var avalon = __webpack_require__(82) + var avalon = __webpack_require__(83) __webpack_require__(8) __webpack_require__(15) - __webpack_require__(84) - __webpack_require__(93) - __webpack_require__(70) - __webpack_require__(74) - __webpack_require__(100) + __webpack_require__(85) + __webpack_require__(94) + __webpack_require__(71) + __webpack_require__(75) + __webpack_require__(101) module.exports = avalon @@ -390,7 +390,7 @@ return /******/ (function(modules) { // webpackBootstrap } kernel.plugins = plugins kernel.plugins['interpolate'](['{{', '}}']) - + //kernel.showDiff = true kernel.debug = true @@ -1425,6 +1425,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { var parseView = __webpack_require__(37) + var update = __webpack_require__(43) avalon.important = function (elem, vid) { //如果vmodel还不存在,直接返回 @@ -1467,10 +1468,7 @@ return /******/ (function(modules) { // webpackBootstrap }, diff: function (cur, pre, steps, name) { if (pre.props[name] !== cur.props[name]) { - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 - } + update(cur, this.update, steps, 'important' ) } }, update: function (node, vnode) { @@ -2009,7 +2007,23 @@ return /******/ (function(modules) { // webpackBootstrap /* 43 */ /***/ function(module, exports) { + module.exports = function (cur, update, steps, type, hookName) { + hookName = hookName || 'change' + var list = cur[hookName] || (cur[hookName] = []) + if (avalon.Array.ensure(list, update)) { + steps.count += 1 + avalon.config.showDiff && avalon.log(type+ ' change') + } + } + + +/***/ }, +/* 44 */ +/***/ function(module, exports, __webpack_require__) { + // 抽离出来公用 + var update = __webpack_require__(43) + avalon.skipController = function (fast, vm, iv) { if (fast) { var id = vm.$render ? vm.$render.$id : vm.$id @@ -2048,10 +2062,8 @@ return /******/ (function(modules) { // webpackBootstrap }, diff: function (cur, pre, steps, name) { if (pre.props[name] !== cur.props[name]) { - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 - } + console.log('controller',steps) + update(cur, this.update, steps, 'controller' ) } }, update: function (node, vnode) { @@ -2082,9 +2094,9 @@ return /******/ (function(modules) { // webpackBootstrap }) /***/ }, -/* 44 */, /* 45 */, -/* 46 */ +/* 46 */, +/* 47 */ /***/ function(module, exports) { var propMap = {//不规则的属性名映射 @@ -2128,10 +2140,11 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 47 */ -/***/ function(module, exports) { +/* 48 */ +/***/ function(module, exports, __webpack_require__) { + var update = __webpack_require__(43) avalon.directive('css', { parse: function (binding, num) { @@ -2140,7 +2153,7 @@ return /******/ (function(modules) { // webpackBootstrap diff: function (cur, pre, steps, name) { var a = cur.props[name] var p = pre.props[name] - if ( Object(a) === a) { + if (Object(a) === a) { if (Array.isArray(a)) { a = cur.props[name] = avalon.mix.apply({}, a) } @@ -2160,10 +2173,7 @@ return /******/ (function(modules) { // webpackBootstrap } } if (cur.changeStyle) { - var list = cur.change || (cur.change = []) - if(avalon.Array.ensure(list, this.update)){ - steps.count += 1 - } + update(cur, this.update, steps, 'css') } } else { cur.props[name] = p @@ -2181,10 +2191,11 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 48 */ -/***/ function(module, exports) { +/* 49 */ +/***/ function(module, exports, __webpack_require__) { + + var update = __webpack_require__(43) - var none = 'none' function parseDisplay(elem, val) { //用于取得此类标签的默认display值 @@ -2217,10 +2228,7 @@ return /******/ (function(modules) { // webpackBootstrap var c = cur.props[name] = !!cur.props[name] cur.displayValue = pre.displayValue if (c !== pre.props[name]) { - var list = cur.change || (cur.change = []) - if(avalon.Array.ensure(list, this.update)){ - steps.count += 1 - } + update(cur, this.update, steps, 'visible' ) } }, update: function (node, vnode) { @@ -2261,11 +2269,13 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 49 */, -/* 50 */ +/* 50 */, +/* 51 */ /***/ function(module, exports, __webpack_require__) { var rident = __webpack_require__(40).ident + var update = __webpack_require__(43) + avalon.directive('text', { parse: function (binding, num, vnode) { vnode.children = [{type: '#text', nodeType: 3, nodeValue: ''}] @@ -2284,10 +2294,7 @@ return /******/ (function(modules) { // webpackBootstrap if (dom) { this.update(dom, cur) } else { - var list = cur.change || (cur.change = []) - if(avalon.Array.ensure(list, this.update)){ - steps.count += 1 - } + update(cur, this.update, steps, 'text' ) } } pre.dom = null @@ -2305,8 +2312,10 @@ return /******/ (function(modules) { // webpackBootstrap }) /***/ }, -/* 51 */ -/***/ function(module, exports) { +/* 52 */ +/***/ function(module, exports, __webpack_require__) { + + var update = __webpack_require__(43) avalon.directive('html', { parse: function (binding, num,el) { @@ -2325,12 +2334,7 @@ return /******/ (function(modules) { // webpackBootstrap var preValue = pre.props[name] cur.isVoidTag = cur._isVoidTag if (curValue !== preValue) { - if (cur.props[name] !== preValue) { - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 - } - } + update(cur, this.update, steps, 'html' ) } }, update: function (node, vnode) { @@ -2349,12 +2353,13 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 52 */ +/* 53 */ /***/ function(module, exports, __webpack_require__) { //根据VM的属性值或表达式的值切换类名,ms-class='xxx yyy zzz:flag' //http://www.cnblogs.com/rubylouvre/archive/2012/12/17/2818540.html var markID = __webpack_require__(6).getLongID + var update = __webpack_require__(43) var directives = avalon.directives avalon.directive('class', { @@ -2402,15 +2407,15 @@ return /******/ (function(modules) { // webpackBootstrap return } className = cur.props[name] = className.trim().replace(/\s+/, ' ') - if (!preValue || preValue !== className) { + if (preValue !== className) { cur['change-' + type] = className - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 - } + update(cur, this.update, steps, type ) } }, update: function (node, vnode) { + + if(!node || node.nodeType !==1) + return var classEvent = vnode.classEvent if (classEvent) { for (var i in classEvent) { @@ -2429,7 +2434,7 @@ return /******/ (function(modules) { // webpackBootstrap if (value === void 0) return if (type === 'class') { - setClass(node, vnode) + node && setClass(node, vnode) } else { var oldType = node.getAttribute('change-'+type) if (oldType) { @@ -2484,13 +2489,14 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 53 */ +/* 54 */ /***/ function(module, exports, __webpack_require__) { var markID = __webpack_require__(6).getLongID var Cache = __webpack_require__(26) var eventCache = new Cache(128) var quote = avalon.quote + var update = __webpack_require__(43) //Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes // The assumption is that future DOM event attribute names will begin with @@ -2530,7 +2536,7 @@ return /******/ (function(modules) { // webpackBootstrap var fn0 = cur.props[name] var fn1 = (pre.props || {})[name] - if ( fn0 !== fn1 ) { + if ( fn0 +''!== fn1+'' ) { var match = name.match(revent) var type = match[1] var search = type + ':' + markID(fn0) @@ -2541,11 +2547,7 @@ return /******/ (function(modules) { // webpackBootstrap cur.removeEvents = cur.removeEvents || {} cur.removeEvents[type + ':' + fn1.uuid] = fn1 } - - var list = cur.change || (cur.change = []) - if(avalon.Array.ensure(list, this.update)){ - steps.count += 1 - } + update(cur, this.update, steps, 'on' ) } }, @@ -2576,8 +2578,8 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 54 */, -/* 55 */ +/* 55 */, +/* 56 */ /***/ function(module, exports) { var valueHijack = false @@ -2611,7 +2613,7 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = valueHijack /***/ }, -/* 56 */ +/* 57 */ /***/ function(module, exports) { var rchangeFilter = /\|\s*change\b/ @@ -2707,8 +2709,8 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 57 */, -/* 58 */ +/* 58 */, +/* 59 */ /***/ function(module, exports) { @@ -2802,8 +2804,8 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = refreshModel /***/ }, -/* 59 */, -/* 60 */ +/* 60 */, +/* 61 */ /***/ function(module, exports) { @@ -2828,8 +2830,10 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 61 */ -/***/ function(module, exports) { +/* 62 */ +/***/ function(module, exports, __webpack_require__) { + + var update = __webpack_require__(43) var dir = avalon.directive('validate', { //验证单个表单元素 @@ -2852,10 +2856,8 @@ return /******/ (function(modules) { // webpackBootstrap } } validator.fields = validator.fields || [] - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 - } + update(cur, this.update, steps, 'validate' ) + } }, update: function (node, vnode) { @@ -3004,7 +3006,7 @@ return /******/ (function(modules) { // webpackBootstrap } /***/ }, -/* 62 */ +/* 63 */ /***/ function(module, exports) { avalon.directive('rules', { @@ -3146,11 +3148,12 @@ return /******/ (function(modules) { // webpackBootstrap }) /***/ }, -/* 63 */ +/* 64 */ /***/ function(module, exports, __webpack_require__) { - var patch = __webpack_require__(64) - var uniqueID = 1 + var patch = __webpack_require__(65) + var update = __webpack_require__(43) + //ms-imporant ms-controller ms-for ms-widget ms-effect ms-if ... avalon.directive('if', { priority: 6, @@ -3169,11 +3172,8 @@ return /******/ (function(modules) { // webpackBootstrap diff: function (cur, pre, steps) { cur.dom = pre.dom if (cur.nodeType !== pre.nodeType) { - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 - cur.steps = steps - } + cur.steps = steps + update(cur, this.update, steps, 'if' ) } }, update: function (node, vnode, parent) { @@ -3225,7 +3225,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 64 */ +/* 65 */ /***/ function(module, exports) { /** @@ -3252,7 +3252,7 @@ return /******/ (function(modules) { // webpackBootstrap next = node.nextSibling } if (vnode.directive === 'for') { - if (vnode.change) { + if (vnode.hasChange) { if (!node) { return } @@ -3272,9 +3272,7 @@ return /******/ (function(modules) { // webpackBootstrap } next = vnode.endRepeat.nextSibling } - } - //ms-for, ms-if, ms-widget会返回false if (false === execHooks(node, vnode, parent, steps, 'change')) { if (vnode.repeatCount) { @@ -3335,24 +3333,30 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = patch /***/ }, -/* 65 */ +/* 66 */ /***/ function(module, exports, __webpack_require__) { - var patch = __webpack_require__(64) + var patch = __webpack_require__(65) var rforPrefix = /ms-for\:\s*/ var rforLeft = /^\s*\(\s*/ var rforRight = /\s*\)\s*$/ var rforSplit = /\s*,\s*/ var rforAs = /\s+as\s+([$\w]+)/ var rident = __webpack_require__(40).ident + var update = __webpack_require__(43) + var rinvalid = /^(null|undefined|NaN|window|this|\$index|\$id)$/ + function getTrackKey(item){ + var type = typeof item + return item && type === 'object' ? item.$hashcode : type + item + } + avalon._each = function (obj, fn) { if (Array.isArray(obj)) { for (var i = 0; i < obj.length; i++) { var item = obj[i] - var type = typeof item - var key = item && type === 'object' ? item.$hashcode : type + item - fn(i, obj[i], key) + var key = getTrackKey(item) + fn(i, item, key) } } else { for (var i in obj) { @@ -3362,7 +3366,36 @@ return /******/ (function(modules) { // webpackBootstrap } } } - var map = {} + var loopMap = {} + function getLoopValue(object){ + if(Array.isArray(object)){ + return object.length+"|"+object.map(getTrackKey).join(';;') + }else{ + var size = 0 + var arr = [] + for(var i in object){ + if(object.hasOwnProperty(i)){ + size++ + arr.push(i) + } + } + return size+"|"+arr.join(';;') + } + } + + avalon._checkLoopChange = function(key, obj){ + var cur = getLoopValue(obj) + if(!(key in loopMap)){ + loopMap[key] = cur + return true + } + if(cur !== loopMap[key]){ + loopMap[key] = cur + return true + } + return false + } + avalon.directive('for', { priority: 3, parse: function (el, num) { @@ -3375,15 +3408,18 @@ return /******/ (function(modules) { // webpackBootstrap } return '' }) + var arr = str.replace(rforPrefix, '').split(' in ') var assign = 'var loop' + num + ' = ' + avalon.parseExpr(arr[1]) + '\n' + var isChange = el.signature+'.hasChange = avalon._checkLoopChange("'+el.signature+'", loop' + num + ')\n' + var alias = aliasAs ? 'var ' + aliasAs + ' = loop' + num + '\n' : '' var kv = arr[0].replace(rforLeft, '').replace(rforRight, '').split(rforSplit) if (kv.length === 1) {//确保avalon._each的回调有三个参数 kv.unshift('$key') } //分别创建isArray, ____n, ___i, ___v, ___trackKey变量 - return assign + alias + 'avalon._each(loop' + num + ', function(' + kv + ', traceKey){\n' + return assign +isChange+ alias + 'avalon._each(loop' + num + ', function(' + kv + ', traceKey){\n' }, diff: function (current, previous, steps, __index__) { @@ -3467,10 +3503,8 @@ return /******/ (function(modules) { // webpackBootstrap pre.components.length = 0 //release memory delete pre.cache if (isChange) { - var list = cur.change || (cur.change = []) - avalon.Array.ensure(list, this.update) cur.steps = steps - steps.count += 1 + update(cur, this.update, steps, 'for') } return __index__ + nodes.length - 1 @@ -3705,11 +3739,12 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 66 */ +/* 67 */ /***/ function(module, exports, __webpack_require__) { - var disposeDetectStrategy = __webpack_require__(67) - var patch = __webpack_require__(64) + var disposeDetectStrategy = __webpack_require__(68) + var patch = __webpack_require__(65) + var update = __webpack_require__(43) //插入点机制,组件的模板中有一些slot元素,用于等待被外面的元素替代 var dir = avalon.directive('widget', { @@ -3750,10 +3785,8 @@ return /******/ (function(modules) { // webpackBootstrap cur.change = [this.replaceByComment] } else if (docker.renderCount && docker.renderCount < 2) { cur.steps = steps - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.replaceByComponent)) { - steps.count += 1 - } + update(cur, this.replaceByComponent, steps, 'widget' ) + function fireReady(dom, vnode) { cur.vmodel.$fire('onReady', { type: 'ready', @@ -3763,10 +3796,7 @@ return /******/ (function(modules) { // webpackBootstrap }) docker.renderCount = 2 } - list = cur.afterChange || (cur.afterChange = []) - if (avalon.Array.ensure(list, fireReady)) { - steps.count += 1 - } + update(cur, fireReady, steps, 'widget', 'afterChange' ) } else { var needUpdate = !cur.diff || cur.diff(cur, pre, steps) @@ -3838,7 +3868,7 @@ return /******/ (function(modules) { // webpackBootstrap // http://www.besteric.com/2014/11/16/build-blog-mirror-site-on-gitcafe/ /***/ }, -/* 67 */ +/* 68 */ /***/ function(module, exports) { //用于chrome, safari @@ -3981,11 +4011,12 @@ return /******/ (function(modules) { // webpackBootstrap } /***/ }, -/* 68 */ +/* 69 */ /***/ function(module, exports, __webpack_require__) { - var support = __webpack_require__(69) + var support = __webpack_require__(70) var Cache = __webpack_require__(26) + var update = __webpack_require__(43) avalon.directive('effect', { priority: 5, @@ -4009,10 +4040,8 @@ return /******/ (function(modules) { // webpackBootstrap if (Object(curObj) === curObj) { var preObj = pre.props[name] if ( Object(preObj) !== preObj || diffObj(curObj, preObj )) { - var list = cur.afterChange = cur.afterChange || [] - if(avalon.Array.ensure(list, this.update)){ - steps.count += 1 - } + update(cur, this.update, steps, 'effect', 'afterChange') + } } }, @@ -4234,7 +4263,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 69 */ +/* 70 */ /***/ function(module, exports) { /** @@ -4313,13 +4342,13 @@ return /******/ (function(modules) { // webpackBootstrap } /***/ }, -/* 70 */ +/* 71 */ /***/ function(module, exports, __webpack_require__) { - avalon.lexer = __webpack_require__(71) - avalon.diff = __webpack_require__(72) - avalon.batch = __webpack_require__(73) + avalon.lexer = __webpack_require__(72) + avalon.diff = __webpack_require__(73) + avalon.batch = __webpack_require__(74) // dispatch与patch 为内置模块 var parseView = __webpack_require__(37) @@ -4336,7 +4365,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 71 */ +/* 72 */ /***/ function(module, exports, __webpack_require__) { /** @@ -4709,7 +4738,7 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = lexer /***/ }, -/* 72 */ +/* 73 */ /***/ function(module, exports, __webpack_require__) { /** @@ -4741,9 +4770,14 @@ return /******/ (function(modules) { // webpackBootstrap } break case 8: - if (cur.directive === 'for') { - i = directives['for'].diff(current, previous, steps, i) - } else if (cur.directive) {//if widget + if (cur.directive === 'for' ) { + if(cur.hasChange){ + i = directives['for'].diff(current, previous, steps, i) + }else{ + avalon.shadowCopy(cur, previous[i]) + delete cur.hasChange + } + } else if (cur.directive ) {//if widget directives[cur.directive].diff(cur, pre, steps) } break @@ -4782,7 +4816,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 73 */ +/* 74 */ /***/ function(module, exports, __webpack_require__) { @@ -4792,7 +4826,7 @@ return /******/ (function(modules) { // webpackBootstrap * ------------------------------------------------------------ */ - var patch = __webpack_require__(64) + var patch = __webpack_require__(65) //如果正在更新一个子树,那么将它放到 @@ -4876,7 +4910,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 74 */ +/* 75 */ /***/ function(module, exports, __webpack_require__) { @@ -5153,15 +5187,15 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 75 */, /* 76 */, -/* 77 */ +/* 77 */, +/* 78 */ /***/ function(module, exports, __webpack_require__) { var $$midway = {} - var $$skipArray = __webpack_require__(78) - var dispatch = __webpack_require__(79) + var $$skipArray = __webpack_require__(79) + var dispatch = __webpack_require__(80) var $emit = dispatch.$emit var $watch = dispatch.$watch @@ -5427,7 +5461,7 @@ return /******/ (function(modules) { // webpackBootstrap } /***/ }, -/* 78 */ +/* 79 */ /***/ function(module, exports) { /** @@ -5443,7 +5477,7 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = avalon.oneObject('$id,$render,$track,$element,$watch,$fire,$events,$model,$skipArray,$accessors,$hashcode,__proxy__,__data__,__const__') /***/ }, -/* 79 */ +/* 80 */ /***/ function(module, exports) { @@ -5545,9 +5579,9 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 80 */, /* 81 */, -/* 82 */ +/* 82 */, +/* 83 */ /***/ function(module, exports, __webpack_require__) { @@ -5556,14 +5590,14 @@ return /******/ (function(modules) { // webpackBootstrap avalon.shadowCopy(avalon, browser) - __webpack_require__(83) + __webpack_require__(84) __webpack_require__(6) __webpack_require__(7) module.exports = avalon /***/ }, -/* 83 */ +/* 84 */ /***/ function(module, exports) { //这里放置存在异议的方法 @@ -5710,7 +5744,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 84 */ +/* 85 */ /***/ function(module, exports, __webpack_require__) { @@ -5719,7 +5753,6 @@ return /******/ (function(modules) { // webpackBootstrap * shim,class,data,css,val,html,event,ready * **********************************************************************/ - __webpack_require__(85) __webpack_require__(86) __webpack_require__(87) __webpack_require__(88) @@ -5727,12 +5760,13 @@ return /******/ (function(modules) { // webpackBootstrap __webpack_require__(90) __webpack_require__(91) __webpack_require__(92) + __webpack_require__(93) module.exports = avalon /***/ }, -/* 85 */ +/* 86 */ /***/ function(module, exports) { //safari5+是把contains方法放在Element.prototype上而不是Node.prototype @@ -5823,7 +5857,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 86 */ +/* 87 */ /***/ function(module, exports) { var rnowhite = /\S+/g @@ -5862,7 +5896,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 87 */ +/* 88 */ /***/ function(module, exports) { @@ -5940,7 +5974,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 88 */ +/* 89 */ /***/ function(module, exports) { var root = avalon.root @@ -6190,7 +6224,7 @@ return /******/ (function(modules) { // webpackBootstrap } /***/ }, -/* 89 */ +/* 90 */ /***/ function(module, exports) { function getValType(elem) { @@ -6259,7 +6293,7 @@ return /******/ (function(modules) { // webpackBootstrap } /***/ }, -/* 90 */ +/* 91 */ /***/ function(module, exports, __webpack_require__) { var Cache = __webpack_require__(26) @@ -6355,7 +6389,7 @@ return /******/ (function(modules) { // webpackBootstrap } /***/ }, -/* 91 */ +/* 92 */ /***/ function(module, exports, __webpack_require__) { var document = avalon.document @@ -6639,7 +6673,7 @@ return /******/ (function(modules) { // webpackBootstrap } /***/ }, -/* 92 */ +/* 93 */ /***/ function(module, exports, __webpack_require__) { var scan = __webpack_require__(34) @@ -6677,39 +6711,40 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 93 */ +/* 94 */ /***/ function(module, exports, __webpack_require__) { __webpack_require__(36) - __webpack_require__(43) + __webpack_require__(44) //处理属性样式 - __webpack_require__(94) - __webpack_require__(47) + __webpack_require__(95) __webpack_require__(48) + __webpack_require__(49) //处理内容 - __webpack_require__(96) - __webpack_require__(50) + __webpack_require__(97) __webpack_require__(51) - //需要用到事件的 __webpack_require__(52) + //需要用到事件的 __webpack_require__(53) - __webpack_require__(97) - __webpack_require__(61) + __webpack_require__(54) + __webpack_require__(98) __webpack_require__(62) - - //处理逻辑 __webpack_require__(63) - __webpack_require__(65) + //处理逻辑 + __webpack_require__(64) __webpack_require__(66) - __webpack_require__(68) + + __webpack_require__(67) + __webpack_require__(69) /***/ }, -/* 94 */ +/* 95 */ /***/ function(module, exports, __webpack_require__) { - var attrUpdate = __webpack_require__(95) + var attrUpdate = __webpack_require__(96) + var update = __webpack_require__(43) avalon.directive('attr', { parse: function (binding, num) { @@ -6739,10 +6774,7 @@ return /******/ (function(modules) { // webpackBootstrap } } if (cur.changeAttr) { - var list = cur.change || (cur.change = []) - if(avalon.Array.ensure(list, this.update)){ - steps.count += 1 - } + update(cur, attrUpdate, steps, 'attr' ) } } else { cur.props[name] = p @@ -6755,10 +6787,10 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 95 */ +/* 96 */ /***/ function(module, exports, __webpack_require__) { - var propMap = __webpack_require__(46) + var propMap = __webpack_require__(47) var rsvg = /^\[object SVG\w*Element\]$/ function attrUpdate(node, vnode) { @@ -6805,19 +6837,17 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = attrUpdate /***/ }, -/* 96 */ -/***/ function(module, exports) { +/* 97 */ +/***/ function(module, exports, __webpack_require__) { + + var update = __webpack_require__(43) - avalon.directive('expr', { parse: function () { }, diff: function (cur, pre, steps) { if (cur.nodeValue !== pre.nodeValue) { - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 - } + update(cur, this.update, steps, 'expr' ) } }, update: function (node, vnode, parent) { @@ -6831,16 +6861,18 @@ return /******/ (function(modules) { // webpackBootstrap }) /***/ }, -/* 97 */ +/* 98 */ /***/ function(module, exports, __webpack_require__) { - var valueHijack = __webpack_require__(55) + var valueHijack = __webpack_require__(56) + + var newField = __webpack_require__(57) + var initField = __webpack_require__(99) + var updateField = __webpack_require__(100) + var addField = __webpack_require__(61) + var update = __webpack_require__(43) - var newField = __webpack_require__(56) - var initField = __webpack_require__(98) - var updateField = __webpack_require__(99) - var addField = __webpack_require__(60) var evaluatorPool = __webpack_require__(39) avalon.directive('duplex', { @@ -6888,9 +6920,7 @@ return /******/ (function(modules) { // webpackBootstrap if (!isEqual) { field.modelValue = value - var afterChange = cur.afterChange || (cur.afterChange = []) - avalon.Array.ensure(afterChange, this.update) - steps.count += 1 + update(cur, this.update, steps, 'duplex', 'afterChange') } }, update: function (node, vnode) { @@ -6964,12 +6994,12 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 98 */ +/* 99 */ /***/ function(module, exports, __webpack_require__) { var window = avalon.window - var refreshModel = __webpack_require__(58) + var refreshModel = __webpack_require__(59) var markID = __webpack_require__(6).getShortID function initControl(cur) { @@ -7115,7 +7145,7 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = initControl /***/ }, -/* 99 */ +/* 100 */ /***/ function(module, exports) { var updateField = { @@ -7156,7 +7186,7 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = updateField /***/ }, -/* 100 */ +/* 101 */ /***/ function(module, exports, __webpack_require__) { /** @@ -7165,7 +7195,7 @@ return /******/ (function(modules) { // webpackBootstrap * masterFactory,slaveFactory,mediatorFactory, ArrayFactory * ------------------------------------------------------------ */ - var share = __webpack_require__(101) + var share = __webpack_require__(102) var isSkip = share.isSkip var $$midway = share.$$midway var $$skipArray = share.$$skipArray @@ -7430,10 +7460,10 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 101 */ +/* 102 */ /***/ function(module, exports, __webpack_require__) { - var share = __webpack_require__(77) + var share = __webpack_require__(78) var makeFire = share.makeFire function toJson(val) { diff --git a/dist/avalon.next.js b/dist/avalon.next.js index 14ad942a4..54c7d7b17 100644 --- a/dist/avalon.next.js +++ b/dist/avalon.next.js @@ -1,4 +1,4 @@ -/*! built in 2016-5-19:10 version 2.01 by 司徒正美 */ +/*! built in 2016-5-20:14 version 2.01 by 司徒正美 */ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); @@ -55,15 +55,15 @@ return /******/ (function(modules) { // webpackBootstrap /* 0 */ /***/ function(module, exports, __webpack_require__) { - var avalon = __webpack_require__(82) + var avalon = __webpack_require__(83) __webpack_require__(8) __webpack_require__(15) - __webpack_require__(84) - __webpack_require__(93) - __webpack_require__(70) - __webpack_require__(74) - __webpack_require__(102) + __webpack_require__(85) + __webpack_require__(94) + __webpack_require__(71) + __webpack_require__(75) + __webpack_require__(103) module.exports = avalon @@ -391,7 +391,7 @@ return /******/ (function(modules) { // webpackBootstrap } kernel.plugins = plugins kernel.plugins['interpolate'](['{{', '}}']) - + //kernel.showDiff = true kernel.debug = true @@ -1426,6 +1426,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { var parseView = __webpack_require__(37) + var update = __webpack_require__(43) avalon.important = function (elem, vid) { //如果vmodel还不存在,直接返回 @@ -1468,10 +1469,7 @@ return /******/ (function(modules) { // webpackBootstrap }, diff: function (cur, pre, steps, name) { if (pre.props[name] !== cur.props[name]) { - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 - } + update(cur, this.update, steps, 'important' ) } }, update: function (node, vnode) { @@ -2010,7 +2008,23 @@ return /******/ (function(modules) { // webpackBootstrap /* 43 */ /***/ function(module, exports) { + module.exports = function (cur, update, steps, type, hookName) { + hookName = hookName || 'change' + var list = cur[hookName] || (cur[hookName] = []) + if (avalon.Array.ensure(list, update)) { + steps.count += 1 + avalon.config.showDiff && avalon.log(type+ ' change') + } + } + + +/***/ }, +/* 44 */ +/***/ function(module, exports, __webpack_require__) { + // 抽离出来公用 + var update = __webpack_require__(43) + avalon.skipController = function (fast, vm, iv) { if (fast) { var id = vm.$render ? vm.$render.$id : vm.$id @@ -2049,10 +2063,8 @@ return /******/ (function(modules) { // webpackBootstrap }, diff: function (cur, pre, steps, name) { if (pre.props[name] !== cur.props[name]) { - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 - } + console.log('controller',steps) + update(cur, this.update, steps, 'controller' ) } }, update: function (node, vnode) { @@ -2083,9 +2095,9 @@ return /******/ (function(modules) { // webpackBootstrap }) /***/ }, -/* 44 */, /* 45 */, -/* 46 */ +/* 46 */, +/* 47 */ /***/ function(module, exports) { var propMap = {//不规则的属性名映射 @@ -2129,10 +2141,11 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 47 */ -/***/ function(module, exports) { +/* 48 */ +/***/ function(module, exports, __webpack_require__) { + var update = __webpack_require__(43) avalon.directive('css', { parse: function (binding, num) { @@ -2141,7 +2154,7 @@ return /******/ (function(modules) { // webpackBootstrap diff: function (cur, pre, steps, name) { var a = cur.props[name] var p = pre.props[name] - if ( Object(a) === a) { + if (Object(a) === a) { if (Array.isArray(a)) { a = cur.props[name] = avalon.mix.apply({}, a) } @@ -2161,10 +2174,7 @@ return /******/ (function(modules) { // webpackBootstrap } } if (cur.changeStyle) { - var list = cur.change || (cur.change = []) - if(avalon.Array.ensure(list, this.update)){ - steps.count += 1 - } + update(cur, this.update, steps, 'css') } } else { cur.props[name] = p @@ -2182,10 +2192,11 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 48 */ -/***/ function(module, exports) { +/* 49 */ +/***/ function(module, exports, __webpack_require__) { + + var update = __webpack_require__(43) - var none = 'none' function parseDisplay(elem, val) { //用于取得此类标签的默认display值 @@ -2218,10 +2229,7 @@ return /******/ (function(modules) { // webpackBootstrap var c = cur.props[name] = !!cur.props[name] cur.displayValue = pre.displayValue if (c !== pre.props[name]) { - var list = cur.change || (cur.change = []) - if(avalon.Array.ensure(list, this.update)){ - steps.count += 1 - } + update(cur, this.update, steps, 'visible' ) } }, update: function (node, vnode) { @@ -2262,11 +2270,13 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 49 */, -/* 50 */ +/* 50 */, +/* 51 */ /***/ function(module, exports, __webpack_require__) { var rident = __webpack_require__(40).ident + var update = __webpack_require__(43) + avalon.directive('text', { parse: function (binding, num, vnode) { vnode.children = [{type: '#text', nodeType: 3, nodeValue: ''}] @@ -2285,10 +2295,7 @@ return /******/ (function(modules) { // webpackBootstrap if (dom) { this.update(dom, cur) } else { - var list = cur.change || (cur.change = []) - if(avalon.Array.ensure(list, this.update)){ - steps.count += 1 - } + update(cur, this.update, steps, 'text' ) } } pre.dom = null @@ -2306,8 +2313,10 @@ return /******/ (function(modules) { // webpackBootstrap }) /***/ }, -/* 51 */ -/***/ function(module, exports) { +/* 52 */ +/***/ function(module, exports, __webpack_require__) { + + var update = __webpack_require__(43) avalon.directive('html', { parse: function (binding, num,el) { @@ -2326,12 +2335,7 @@ return /******/ (function(modules) { // webpackBootstrap var preValue = pre.props[name] cur.isVoidTag = cur._isVoidTag if (curValue !== preValue) { - if (cur.props[name] !== preValue) { - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 - } - } + update(cur, this.update, steps, 'html' ) } }, update: function (node, vnode) { @@ -2350,12 +2354,13 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 52 */ +/* 53 */ /***/ function(module, exports, __webpack_require__) { //根据VM的属性值或表达式的值切换类名,ms-class='xxx yyy zzz:flag' //http://www.cnblogs.com/rubylouvre/archive/2012/12/17/2818540.html var markID = __webpack_require__(6).getLongID + var update = __webpack_require__(43) var directives = avalon.directives avalon.directive('class', { @@ -2403,15 +2408,15 @@ return /******/ (function(modules) { // webpackBootstrap return } className = cur.props[name] = className.trim().replace(/\s+/, ' ') - if (!preValue || preValue !== className) { + if (preValue !== className) { cur['change-' + type] = className - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 - } + update(cur, this.update, steps, type ) } }, update: function (node, vnode) { + + if(!node || node.nodeType !==1) + return var classEvent = vnode.classEvent if (classEvent) { for (var i in classEvent) { @@ -2430,7 +2435,7 @@ return /******/ (function(modules) { // webpackBootstrap if (value === void 0) return if (type === 'class') { - setClass(node, vnode) + node && setClass(node, vnode) } else { var oldType = node.getAttribute('change-'+type) if (oldType) { @@ -2485,13 +2490,14 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 53 */ +/* 54 */ /***/ function(module, exports, __webpack_require__) { var markID = __webpack_require__(6).getLongID var Cache = __webpack_require__(26) var eventCache = new Cache(128) var quote = avalon.quote + var update = __webpack_require__(43) //Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes // The assumption is that future DOM event attribute names will begin with @@ -2531,7 +2537,7 @@ return /******/ (function(modules) { // webpackBootstrap var fn0 = cur.props[name] var fn1 = (pre.props || {})[name] - if ( fn0 !== fn1 ) { + if ( fn0 +''!== fn1+'' ) { var match = name.match(revent) var type = match[1] var search = type + ':' + markID(fn0) @@ -2542,11 +2548,7 @@ return /******/ (function(modules) { // webpackBootstrap cur.removeEvents = cur.removeEvents || {} cur.removeEvents[type + ':' + fn1.uuid] = fn1 } - - var list = cur.change || (cur.change = []) - if(avalon.Array.ensure(list, this.update)){ - steps.count += 1 - } + update(cur, this.update, steps, 'on' ) } }, @@ -2577,8 +2579,8 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 54 */, -/* 55 */ +/* 55 */, +/* 56 */ /***/ function(module, exports) { var valueHijack = false @@ -2612,7 +2614,7 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = valueHijack /***/ }, -/* 56 */ +/* 57 */ /***/ function(module, exports) { var rchangeFilter = /\|\s*change\b/ @@ -2708,8 +2710,8 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 57 */, -/* 58 */ +/* 58 */, +/* 59 */ /***/ function(module, exports) { @@ -2803,8 +2805,8 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = refreshModel /***/ }, -/* 59 */, -/* 60 */ +/* 60 */, +/* 61 */ /***/ function(module, exports) { @@ -2829,8 +2831,10 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 61 */ -/***/ function(module, exports) { +/* 62 */ +/***/ function(module, exports, __webpack_require__) { + + var update = __webpack_require__(43) var dir = avalon.directive('validate', { //验证单个表单元素 @@ -2853,10 +2857,8 @@ return /******/ (function(modules) { // webpackBootstrap } } validator.fields = validator.fields || [] - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 - } + update(cur, this.update, steps, 'validate' ) + } }, update: function (node, vnode) { @@ -3005,7 +3007,7 @@ return /******/ (function(modules) { // webpackBootstrap } /***/ }, -/* 62 */ +/* 63 */ /***/ function(module, exports) { avalon.directive('rules', { @@ -3147,11 +3149,12 @@ return /******/ (function(modules) { // webpackBootstrap }) /***/ }, -/* 63 */ +/* 64 */ /***/ function(module, exports, __webpack_require__) { - var patch = __webpack_require__(64) - var uniqueID = 1 + var patch = __webpack_require__(65) + var update = __webpack_require__(43) + //ms-imporant ms-controller ms-for ms-widget ms-effect ms-if ... avalon.directive('if', { priority: 6, @@ -3170,11 +3173,8 @@ return /******/ (function(modules) { // webpackBootstrap diff: function (cur, pre, steps) { cur.dom = pre.dom if (cur.nodeType !== pre.nodeType) { - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 - cur.steps = steps - } + cur.steps = steps + update(cur, this.update, steps, 'if' ) } }, update: function (node, vnode, parent) { @@ -3226,7 +3226,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 64 */ +/* 65 */ /***/ function(module, exports) { /** @@ -3253,7 +3253,7 @@ return /******/ (function(modules) { // webpackBootstrap next = node.nextSibling } if (vnode.directive === 'for') { - if (vnode.change) { + if (vnode.hasChange) { if (!node) { return } @@ -3273,9 +3273,7 @@ return /******/ (function(modules) { // webpackBootstrap } next = vnode.endRepeat.nextSibling } - } - //ms-for, ms-if, ms-widget会返回false if (false === execHooks(node, vnode, parent, steps, 'change')) { if (vnode.repeatCount) { @@ -3336,24 +3334,30 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = patch /***/ }, -/* 65 */ +/* 66 */ /***/ function(module, exports, __webpack_require__) { - var patch = __webpack_require__(64) + var patch = __webpack_require__(65) var rforPrefix = /ms-for\:\s*/ var rforLeft = /^\s*\(\s*/ var rforRight = /\s*\)\s*$/ var rforSplit = /\s*,\s*/ var rforAs = /\s+as\s+([$\w]+)/ var rident = __webpack_require__(40).ident + var update = __webpack_require__(43) + var rinvalid = /^(null|undefined|NaN|window|this|\$index|\$id)$/ + function getTrackKey(item){ + var type = typeof item + return item && type === 'object' ? item.$hashcode : type + item + } + avalon._each = function (obj, fn) { if (Array.isArray(obj)) { for (var i = 0; i < obj.length; i++) { var item = obj[i] - var type = typeof item - var key = item && type === 'object' ? item.$hashcode : type + item - fn(i, obj[i], key) + var key = getTrackKey(item) + fn(i, item, key) } } else { for (var i in obj) { @@ -3363,7 +3367,36 @@ return /******/ (function(modules) { // webpackBootstrap } } } - var map = {} + var loopMap = {} + function getLoopValue(object){ + if(Array.isArray(object)){ + return object.length+"|"+object.map(getTrackKey).join(';;') + }else{ + var size = 0 + var arr = [] + for(var i in object){ + if(object.hasOwnProperty(i)){ + size++ + arr.push(i) + } + } + return size+"|"+arr.join(';;') + } + } + + avalon._checkLoopChange = function(key, obj){ + var cur = getLoopValue(obj) + if(!(key in loopMap)){ + loopMap[key] = cur + return true + } + if(cur !== loopMap[key]){ + loopMap[key] = cur + return true + } + return false + } + avalon.directive('for', { priority: 3, parse: function (el, num) { @@ -3376,15 +3409,18 @@ return /******/ (function(modules) { // webpackBootstrap } return '' }) + var arr = str.replace(rforPrefix, '').split(' in ') var assign = 'var loop' + num + ' = ' + avalon.parseExpr(arr[1]) + '\n' + var isChange = el.signature+'.hasChange = avalon._checkLoopChange("'+el.signature+'", loop' + num + ')\n' + var alias = aliasAs ? 'var ' + aliasAs + ' = loop' + num + '\n' : '' var kv = arr[0].replace(rforLeft, '').replace(rforRight, '').split(rforSplit) if (kv.length === 1) {//确保avalon._each的回调有三个参数 kv.unshift('$key') } //分别创建isArray, ____n, ___i, ___v, ___trackKey变量 - return assign + alias + 'avalon._each(loop' + num + ', function(' + kv + ', traceKey){\n' + return assign +isChange+ alias + 'avalon._each(loop' + num + ', function(' + kv + ', traceKey){\n' }, diff: function (current, previous, steps, __index__) { @@ -3468,10 +3504,8 @@ return /******/ (function(modules) { // webpackBootstrap pre.components.length = 0 //release memory delete pre.cache if (isChange) { - var list = cur.change || (cur.change = []) - avalon.Array.ensure(list, this.update) cur.steps = steps - steps.count += 1 + update(cur, this.update, steps, 'for') } return __index__ + nodes.length - 1 @@ -3706,11 +3740,12 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 66 */ +/* 67 */ /***/ function(module, exports, __webpack_require__) { - var disposeDetectStrategy = __webpack_require__(67) - var patch = __webpack_require__(64) + var disposeDetectStrategy = __webpack_require__(68) + var patch = __webpack_require__(65) + var update = __webpack_require__(43) //插入点机制,组件的模板中有一些slot元素,用于等待被外面的元素替代 var dir = avalon.directive('widget', { @@ -3751,10 +3786,8 @@ return /******/ (function(modules) { // webpackBootstrap cur.change = [this.replaceByComment] } else if (docker.renderCount && docker.renderCount < 2) { cur.steps = steps - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.replaceByComponent)) { - steps.count += 1 - } + update(cur, this.replaceByComponent, steps, 'widget' ) + function fireReady(dom, vnode) { cur.vmodel.$fire('onReady', { type: 'ready', @@ -3764,10 +3797,7 @@ return /******/ (function(modules) { // webpackBootstrap }) docker.renderCount = 2 } - list = cur.afterChange || (cur.afterChange = []) - if (avalon.Array.ensure(list, fireReady)) { - steps.count += 1 - } + update(cur, fireReady, steps, 'widget', 'afterChange' ) } else { var needUpdate = !cur.diff || cur.diff(cur, pre, steps) @@ -3839,7 +3869,7 @@ return /******/ (function(modules) { // webpackBootstrap // http://www.besteric.com/2014/11/16/build-blog-mirror-site-on-gitcafe/ /***/ }, -/* 67 */ +/* 68 */ /***/ function(module, exports) { //用于chrome, safari @@ -3982,11 +4012,12 @@ return /******/ (function(modules) { // webpackBootstrap } /***/ }, -/* 68 */ +/* 69 */ /***/ function(module, exports, __webpack_require__) { - var support = __webpack_require__(69) + var support = __webpack_require__(70) var Cache = __webpack_require__(26) + var update = __webpack_require__(43) avalon.directive('effect', { priority: 5, @@ -4010,10 +4041,8 @@ return /******/ (function(modules) { // webpackBootstrap if (Object(curObj) === curObj) { var preObj = pre.props[name] if ( Object(preObj) !== preObj || diffObj(curObj, preObj )) { - var list = cur.afterChange = cur.afterChange || [] - if(avalon.Array.ensure(list, this.update)){ - steps.count += 1 - } + update(cur, this.update, steps, 'effect', 'afterChange') + } } }, @@ -4235,7 +4264,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 69 */ +/* 70 */ /***/ function(module, exports) { /** @@ -4314,13 +4343,13 @@ return /******/ (function(modules) { // webpackBootstrap } /***/ }, -/* 70 */ +/* 71 */ /***/ function(module, exports, __webpack_require__) { - avalon.lexer = __webpack_require__(71) - avalon.diff = __webpack_require__(72) - avalon.batch = __webpack_require__(73) + avalon.lexer = __webpack_require__(72) + avalon.diff = __webpack_require__(73) + avalon.batch = __webpack_require__(74) // dispatch与patch 为内置模块 var parseView = __webpack_require__(37) @@ -4337,7 +4366,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 71 */ +/* 72 */ /***/ function(module, exports, __webpack_require__) { /** @@ -4710,7 +4739,7 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = lexer /***/ }, -/* 72 */ +/* 73 */ /***/ function(module, exports, __webpack_require__) { /** @@ -4742,9 +4771,14 @@ return /******/ (function(modules) { // webpackBootstrap } break case 8: - if (cur.directive === 'for') { - i = directives['for'].diff(current, previous, steps, i) - } else if (cur.directive) {//if widget + if (cur.directive === 'for' ) { + if(cur.hasChange){ + i = directives['for'].diff(current, previous, steps, i) + }else{ + avalon.shadowCopy(cur, previous[i]) + delete cur.hasChange + } + } else if (cur.directive ) {//if widget directives[cur.directive].diff(cur, pre, steps) } break @@ -4783,7 +4817,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 73 */ +/* 74 */ /***/ function(module, exports, __webpack_require__) { @@ -4793,7 +4827,7 @@ return /******/ (function(modules) { // webpackBootstrap * ------------------------------------------------------------ */ - var patch = __webpack_require__(64) + var patch = __webpack_require__(65) //如果正在更新一个子树,那么将它放到 @@ -4877,7 +4911,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 74 */ +/* 75 */ /***/ function(module, exports, __webpack_require__) { @@ -5154,15 +5188,15 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 75 */, /* 76 */, -/* 77 */ +/* 77 */, +/* 78 */ /***/ function(module, exports, __webpack_require__) { var $$midway = {} - var $$skipArray = __webpack_require__(78) - var dispatch = __webpack_require__(79) + var $$skipArray = __webpack_require__(79) + var dispatch = __webpack_require__(80) var $emit = dispatch.$emit var $watch = dispatch.$watch @@ -5428,7 +5462,7 @@ return /******/ (function(modules) { // webpackBootstrap } /***/ }, -/* 78 */ +/* 79 */ /***/ function(module, exports) { /** @@ -5444,7 +5478,7 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = avalon.oneObject('$id,$render,$track,$element,$watch,$fire,$events,$model,$skipArray,$accessors,$hashcode,__proxy__,__data__,__const__') /***/ }, -/* 79 */ +/* 80 */ /***/ function(module, exports) { @@ -5546,9 +5580,9 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 80 */, /* 81 */, -/* 82 */ +/* 82 */, +/* 83 */ /***/ function(module, exports, __webpack_require__) { @@ -5557,14 +5591,14 @@ return /******/ (function(modules) { // webpackBootstrap avalon.shadowCopy(avalon, browser) - __webpack_require__(83) + __webpack_require__(84) __webpack_require__(6) __webpack_require__(7) module.exports = avalon /***/ }, -/* 83 */ +/* 84 */ /***/ function(module, exports) { //这里放置存在异议的方法 @@ -5711,7 +5745,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 84 */ +/* 85 */ /***/ function(module, exports, __webpack_require__) { @@ -5720,7 +5754,6 @@ return /******/ (function(modules) { // webpackBootstrap * shim,class,data,css,val,html,event,ready * **********************************************************************/ - __webpack_require__(85) __webpack_require__(86) __webpack_require__(87) __webpack_require__(88) @@ -5728,12 +5761,13 @@ return /******/ (function(modules) { // webpackBootstrap __webpack_require__(90) __webpack_require__(91) __webpack_require__(92) + __webpack_require__(93) module.exports = avalon /***/ }, -/* 85 */ +/* 86 */ /***/ function(module, exports) { //safari5+是把contains方法放在Element.prototype上而不是Node.prototype @@ -5824,7 +5858,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 86 */ +/* 87 */ /***/ function(module, exports) { var rnowhite = /\S+/g @@ -5863,7 +5897,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 87 */ +/* 88 */ /***/ function(module, exports) { @@ -5941,7 +5975,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 88 */ +/* 89 */ /***/ function(module, exports) { var root = avalon.root @@ -6191,7 +6225,7 @@ return /******/ (function(modules) { // webpackBootstrap } /***/ }, -/* 89 */ +/* 90 */ /***/ function(module, exports) { function getValType(elem) { @@ -6260,7 +6294,7 @@ return /******/ (function(modules) { // webpackBootstrap } /***/ }, -/* 90 */ +/* 91 */ /***/ function(module, exports, __webpack_require__) { var Cache = __webpack_require__(26) @@ -6356,7 +6390,7 @@ return /******/ (function(modules) { // webpackBootstrap } /***/ }, -/* 91 */ +/* 92 */ /***/ function(module, exports, __webpack_require__) { var document = avalon.document @@ -6640,7 +6674,7 @@ return /******/ (function(modules) { // webpackBootstrap } /***/ }, -/* 92 */ +/* 93 */ /***/ function(module, exports, __webpack_require__) { var scan = __webpack_require__(34) @@ -6678,39 +6712,40 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 93 */ +/* 94 */ /***/ function(module, exports, __webpack_require__) { __webpack_require__(36) - __webpack_require__(43) + __webpack_require__(44) //处理属性样式 - __webpack_require__(94) - __webpack_require__(47) + __webpack_require__(95) __webpack_require__(48) + __webpack_require__(49) //处理内容 - __webpack_require__(96) - __webpack_require__(50) + __webpack_require__(97) __webpack_require__(51) - //需要用到事件的 __webpack_require__(52) + //需要用到事件的 __webpack_require__(53) - __webpack_require__(97) - __webpack_require__(61) + __webpack_require__(54) + __webpack_require__(98) __webpack_require__(62) - - //处理逻辑 __webpack_require__(63) - __webpack_require__(65) + //处理逻辑 + __webpack_require__(64) __webpack_require__(66) - __webpack_require__(68) + + __webpack_require__(67) + __webpack_require__(69) /***/ }, -/* 94 */ +/* 95 */ /***/ function(module, exports, __webpack_require__) { - var attrUpdate = __webpack_require__(95) + var attrUpdate = __webpack_require__(96) + var update = __webpack_require__(43) avalon.directive('attr', { parse: function (binding, num) { @@ -6740,10 +6775,7 @@ return /******/ (function(modules) { // webpackBootstrap } } if (cur.changeAttr) { - var list = cur.change || (cur.change = []) - if(avalon.Array.ensure(list, this.update)){ - steps.count += 1 - } + update(cur, attrUpdate, steps, 'attr' ) } } else { cur.props[name] = p @@ -6756,10 +6788,10 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 95 */ +/* 96 */ /***/ function(module, exports, __webpack_require__) { - var propMap = __webpack_require__(46) + var propMap = __webpack_require__(47) var rsvg = /^\[object SVG\w*Element\]$/ function attrUpdate(node, vnode) { @@ -6806,19 +6838,17 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = attrUpdate /***/ }, -/* 96 */ -/***/ function(module, exports) { +/* 97 */ +/***/ function(module, exports, __webpack_require__) { + + var update = __webpack_require__(43) - avalon.directive('expr', { parse: function () { }, diff: function (cur, pre, steps) { if (cur.nodeValue !== pre.nodeValue) { - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 - } + update(cur, this.update, steps, 'expr' ) } }, update: function (node, vnode, parent) { @@ -6832,16 +6862,18 @@ return /******/ (function(modules) { // webpackBootstrap }) /***/ }, -/* 97 */ +/* 98 */ /***/ function(module, exports, __webpack_require__) { - var valueHijack = __webpack_require__(55) + var valueHijack = __webpack_require__(56) + + var newField = __webpack_require__(57) + var initField = __webpack_require__(99) + var updateField = __webpack_require__(100) + var addField = __webpack_require__(61) + var update = __webpack_require__(43) - var newField = __webpack_require__(56) - var initField = __webpack_require__(98) - var updateField = __webpack_require__(99) - var addField = __webpack_require__(60) var evaluatorPool = __webpack_require__(39) avalon.directive('duplex', { @@ -6889,9 +6921,7 @@ return /******/ (function(modules) { // webpackBootstrap if (!isEqual) { field.modelValue = value - var afterChange = cur.afterChange || (cur.afterChange = []) - avalon.Array.ensure(afterChange, this.update) - steps.count += 1 + update(cur, this.update, steps, 'duplex', 'afterChange') } }, update: function (node, vnode) { @@ -6965,12 +6995,12 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 98 */ +/* 99 */ /***/ function(module, exports, __webpack_require__) { var window = avalon.window - var refreshModel = __webpack_require__(58) + var refreshModel = __webpack_require__(59) var markID = __webpack_require__(6).getShortID function initControl(cur) { @@ -7116,7 +7146,7 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = initControl /***/ }, -/* 99 */ +/* 100 */ /***/ function(module, exports) { var updateField = { @@ -7157,9 +7187,9 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = updateField /***/ }, -/* 100 */, /* 101 */, -/* 102 */ +/* 102 */, +/* 103 */ /***/ function(module, exports, __webpack_require__) { /** @@ -7169,7 +7199,7 @@ return /******/ (function(modules) { // webpackBootstrap * http://caniuse.com/#search=Proxy * ------------------------------------------------------------ */ - var share = __webpack_require__(77) + var share = __webpack_require__(78) var $$midway = share.$$midway var $$skipArray = share.$$skipArray $$skipArray.$compose = true @@ -7177,7 +7207,7 @@ return /******/ (function(modules) { // webpackBootstrap delete $$skipArray var modelAdaptor = share.modelAdaptor var makeHashCode = avalon.makeHashCode - var dispatch = __webpack_require__(79) + var dispatch = __webpack_require__(80) var $emit = dispatch.$emit var $watch = dispatch.$watch diff --git a/dist/avalon.test.js b/dist/avalon.test.js index a099b8a2a..902b39d1a 100644 --- a/dist/avalon.test.js +++ b/dist/avalon.test.js @@ -1,4 +1,4 @@ -/*! built in 2016-5-19:10 version 2.01 by 司徒正美 */ +/*! built in 2016-5-20:14 version 2.01 by 司徒正美 */ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); @@ -56,28 +56,253 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { - - var avalon = __webpack_require__(82) + // + //var avalon = require('./seed/modern') + // + //require('./filters/index') + //require('./vdom/index') + //require('./dom/modern') + //require('./directives/modern') + //require('./strategy/index') + //require('./component/index') + //require('./vmodel/modern') + + var avalon = __webpack_require__(1) //这个版本兼容IE6 __webpack_require__(8) __webpack_require__(15) - __webpack_require__(84) - __webpack_require__(93) - __webpack_require__(70) - __webpack_require__(74) - __webpack_require__(100) + __webpack_require__(19) + __webpack_require__(35) + __webpack_require__(71) + __webpack_require__(75) + __webpack_require__(76) - __webpack_require__(103) __webpack_require__(104) + __webpack_require__(105) + module.exports = avalon + + + + +/***/ }, +/* 1 */ +/***/ function(module, exports, __webpack_require__) { + + + __webpack_require__(2) + var avalon = __webpack_require__(3) + var browser = __webpack_require__(4) + + avalon.shadowCopy(avalon, browser) + + __webpack_require__(5) + __webpack_require__(6) + __webpack_require__(7) + module.exports = avalon +/***/ }, +/* 2 */ +/***/ function(module, exports) { + + + /** + * 此模块不依赖任何模块,用于修复语言的底层缺陷 + */ + + var ohasOwn = Object.prototype.hasOwnProperty + + if (!'司徒正美'.trim) { + var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g + String.prototype.trim = function () { + return this.replace(rtrim, '') + } + } + var hasDontEnumBug = !({ + 'toString': null + }).propertyIsEnumerable('toString'), + hasProtoEnumBug = (function () { + }).propertyIsEnumerable('prototype'), + dontEnums = [ + 'toString', + 'toLocaleString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'constructor' + ], + dontEnumsLength = dontEnums.length; + if (!Object.keys) { + Object.keys = function (object) { //ecma262v5 15.2.3.14 + var theKeys = [] + var skipProto = hasProtoEnumBug && typeof object === 'function' + if (typeof object === 'string' || (object && object.callee)) { + for (var i = 0; i < object.length; ++i) { + theKeys.push(String(i)) + } + } else { + for (var name in object) { + if (!(skipProto && name === 'prototype') && + ohasOwn.call(object, name)) { + theKeys.push(String(name)) + } + } + } + + if (hasDontEnumBug) { + var ctor = object.constructor, + skipConstructor = ctor && ctor.prototype === object + for (var j = 0; j < dontEnumsLength; j++) { + var dontEnum = dontEnums[j] + if (!(skipConstructor && dontEnum === 'constructor') && ohasOwn.call(object, dontEnum)) { + theKeys.push(dontEnum) + } + } + } + return theKeys + } + } + if (!Array.isArray) { + Array.isArray = function (a) { + return Object.prototype.toString.call(a) === '[object Array]' + } + } + + if (!Array.isArray.bind) { + Function.prototype.bind = function (scope) { + if (arguments.length < 2 && scope === void 0) + return this + var fn = this, + argv = arguments + return function () { + var args = [], + i + for (i = 1; i < argv.length; i++) + args.push(argv[i]) + for (i = 0; i < arguments.length; i++) + args.push(arguments[i]) + return fn.apply(scope, args) + } + } + } + //https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/slice + /** + * Shim for "fixing" IE's lack of support (IE < 9) for applying slice + * on host objects like NamedNodeMap, NodeList, and HTMLCollection + * (technically, since host objects have been implementation-dependent, + * at least before ES6, IE hasn't needed to work this way). + * Also works on strings, fixes IE < 9 to allow an explicit undefined + * for the 2nd argument (as in Firefox), and prevents errors when + * called on other DOM objects. + */ + + var _slice = Array.prototype.slice + try { + // Can't be used with DOM elements in IE < 9 + _slice.call(document.documentElement) + } catch (e) { // Fails in IE < 9 + // This will work for genuine arrays, array-like objects, + // NamedNodeMap (attributes, entities, notations), + // NodeList (e.g., getElementsByTagName), HTMLCollection (e.g., childNodes), + // and will not fail on other DOM objects (as do DOM elements in IE < 9) + Array.prototype.slice = function (begin, end) { + // IE < 9 gets unhappy with an undefined end argument + end = (typeof end !== 'undefined') ? end : this.length + + // For native Array objects, we use the native slice function + if (Array.isArray(this) ) { + return _slice.call(this, begin, end) + } + + // For array like object we handle it ourselves. + var i, cloned = [], + size, len = this.length + + // Handle negative value for "begin" + var start = begin || 0 + start = (start >= 0) ? start : len + start + + // Handle negative value for "end" + var upTo = (end) ? end : len + if (end < 0) { + upTo = len + end + } + + // Actual expected size of the slice + size = upTo - start + + if (size > 0) { + cloned = new Array(size) + if (this.charAt) { + for (i = 0; i < size; i++) { + cloned[i] = this.charAt(start + i) + } + } else { + for (i = 0; i < size; i++) { + cloned[i] = this[start + i] + } + } + } + + return cloned + } + } + + function iterator(vars, body, ret) { + var fun = 'for(var ' + vars + 'i=0,n = this.length; i < n; i++){' + + body.replace('_', '((i in this) && fn.call(scope,this[i],i,this))') + + '}' + ret + /* jshint ignore:start */ + return Function('fn,scope', fun) + /* jshint ignore:end */ + } + var ap = Array.prototype + if (!/\[native code\]/.test(ap.map)) { + var shim = { + //定位操作,返回数组中第一个等于给定参数的元素的索引值。 + indexOf: function (item, index) { + var n = this.length, + i = ~~index + if (i < 0) + i += n + for (; i < n; i++) + if (this[i] === item) + return i + return -1 + }, + //定位操作,同上,不过是从后遍历。 + lastIndexOf: function (item, index) { + var n = this.length, + i = index == null ? n - 1 : index + if (i < 0) + i = Math.max(0, n + i) + for (; i >= 0; i--) + if (this[i] === item) + return i + return -1 + }, + //迭代操作,将数组的元素挨个儿传入一个函数中执行。Prototype.js的对应名字为each。 + forEach: iterator('', '_', ''), + //迭代类 在数组中的每个项上运行一个函数,如果此函数的值为真,则此元素作为新数组的元素收集起来,并返回新数组 + filter: iterator('r=[],j=0,', 'if(_)r[j++]=this[i]', 'return r'), + //收集操作,将数组的元素挨个儿传入一个函数中执行,然后把它们的返回值组成一个新数组返回。Prototype.js的对应名字为collect。 + map: iterator('r=[],', 'r[i]=_', 'return r'), + //只要数组中有一个元素满足条件(放进给定函数返回true),那么它就返回true。Prototype.js的对应名字为any。 + some: iterator('', 'if(_)return true', 'return false'), + //只有数组中的元素都满足条件(放进给定函数返回true),它才返回true。Prototype.js的对应名字为all。 + every: iterator('', 'if(!_)return false', 'return true') + } + for (var i in shim) { + ap[i] = shim[i] + } + } + module.exports = {} /***/ }, -/* 1 */, -/* 2 */, /* 3 */ /***/ function(module, exports) { @@ -189,7 +414,247 @@ return /******/ (function(modules) { // webpackBootstrap /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) /***/ }, -/* 5 */, +/* 5 */ +/***/ function(module, exports) { + + //这里放置存在异议的方法 + + var serialize = avalon.inspect + var rwindow = /^\[object (?:Window|DOMWindow|global)\]$/ + var rnative = /\[native code\]/ //判定是否原生函数 + var rarraylike = /(Array|List|Collection|Map|Arguments)\]$/ + var ohasOwn = avalon.ohasOwn + // avalon.quote + //https://github.com/bestiejs/json3/blob/master/lib/json3.js + var Escapes = { + 92: "\\\\", + 34: '\\"', + 8: "\\b", + 12: "\\f", + 10: "\\n", + 13: "\\r", + 9: "\\t" + } + + // Internal: Converts `value` into a zero-padded string such that its + // length is at least equal to `width`. The `width` must be <= 6. + var leadingZeroes = "000000" + var toPaddedString = function (width, value) { + // The `|| 0` expression is necessary to work around a bug in + // Opera <= 7.54u2 where `0 == -0`, but `String(-0) !== "0"`. + return (leadingZeroes + (value || 0)).slice(-width) + }; + var unicodePrefix = "\\u00" + var escapeChar = function (character) { + var charCode = character.charCodeAt(0), escaped = Escapes[charCode] + if (escaped) { + return escaped + } + return unicodePrefix + toPaddedString(2, charCode.toString(16)) + }; + var reEscape = /[\x00-\x1f\x22\x5c]/g + function quote(value) { + reEscape.lastIndex = 0 + return '"' + ( reEscape.test(value)? String(value).replace(reEscape, escapeChar) : value ) + '"' + } + + avalon.quote = typeof JSON !== 'undefined' ? JSON.stringify : quote + + // avalon.type + var class2type = {} + 'Boolean Number String Function Array Date RegExp Object Error'.replace(avalon.rword, function (name) { + class2type['[object ' + name + ']'] = name.toLowerCase() + }) + + avalon.type = function (obj) { //取得目标的类型 + if (obj == null) { + return String(obj) + } + // 早期的webkit内核浏览器实现了已废弃的ecma262v4标准,可以将正则字面量当作函数使用,因此typeof在判定正则时会返回function + return typeof obj === 'object' || typeof obj === 'function' ? + class2type[serialize.call(obj)] || 'object' : + typeof obj + } + + var rfunction = /^\s*\bfunction\b/ + + avalon.isFunction = typeof alert === 'object' ? function (fn) { + try { + return rfunction.test(fn + '') + } catch (e) { + return false + } + } : function (fn) { + return serialize.call(fn) === '[object Function]' + } + + avalon.isWindow = function (obj) { + if (!obj) + return false + // 利用IE678 window == document为true,document == window竟然为false的神奇特性 + // 标准浏览器及IE9,IE10等使用 正则检测 + return obj == obj.document && obj.document != obj //jshint ignore:line + } + + + function isWindow(obj) { + return rwindow.test(serialize.call(obj)) + } + + if (isWindow(avalon.window)) { + avalon.isWindow = isWindow + } + + var enu, enumerateBUG + for (enu in avalon({})) { + break + } + enumerateBUG = enu !== '0' //IE6下为true, 其他为false + + /*判定是否是一个朴素的javascript对象(Object),不是DOM对象,不是BOM对象,不是自定义类的实例*/ + avalon.isPlainObject = function (obj, key) { + if (!obj || avalon.type(obj) !== 'object' || obj.nodeType || avalon.isWindow(obj)) { + return false + } + try { //IE内置对象没有constructor + if (obj.constructor && + !ohasOwn.call(obj, 'constructor') && + !ohasOwn.call(obj.constructor.prototype || {}, 'isPrototypeOf')) { + return false + } + } catch (e) { //IE8 9会在这里抛错 + return false + } + if (enumerateBUG) { + for (key in obj) { + return ohasOwn.call(obj, key) + } + } + for (key in obj) { + } + return key === void 0 || ohasOwn.call(obj, key) + } + + + if (rnative.test(Object.getPrototypeOf)) { + avalon.isPlainObject = function (obj) { + // 简单的 typeof obj === 'object'检测,会致使用isPlainObject(window)在opera下通不过 + return serialize.call(obj) === '[object Object]' && + Object.getPrototypeOf(obj) === Object.prototype + } + } + + //与jQuery.extend方法,可用于浅拷贝,深拷贝 + avalon.mix = avalon.fn.mix = function () { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false + + // 如果第一个参数为布尔,判定是否深拷贝 + if (typeof target === 'boolean') { + deep = target + target = arguments[1] || {} + i++ + } + + //确保接受方为一个复杂的数据类型 + if (typeof target !== 'object' && !avalon.isFunction(target)) { + target = {} + } + + //如果只有一个参数,那么新成员添加于mix所在的对象上 + if (i === length) { + target = this + i-- + } + + for (; i < length; i++) { + //只处理非空参数 + if ((options = arguments[i]) != null) { + for (name in options) { + try { + src = target[name] + copy = options[name] //当options为VBS对象时报错 + } catch (e) { + continue + } + + // 防止环引用 + if (target === copy) { + continue + } + if (deep && copy && (avalon.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) { + + if (copyIsArray) { + copyIsArray = false + clone = src && Array.isArray(src) ? src : [] + + } else { + clone = src && avalon.isPlainObject(src) ? src : {} + } + + target[name] = avalon.mix(deep, clone, copy) + } else if (copy !== void 0) { + target[name] = copy + } + } + } + } + return target + } + + /*判定是否类数组,如节点集合,纯数组,arguments与拥有非负整数的length属性的纯JS对象*/ + function isArrayLike(obj) { + if (!obj) + return false + var n = obj.length + if (n === (n >>> 0)) { //检测length属性是否为非负整数 + var type = serialize.call(obj).slice(8, -1) + if (rarraylike.test(type)) + return false + if (type === 'Array') + return true + try { + if ({}.propertyIsEnumerable.call(obj, 'length') === false) { //如果是原生对象 + return rfunction.test(obj.item || obj.callee) + } + return true + } catch (e) { //IE的NodeList直接抛错 + return !obj.window //IE6-8 window + } + } + return false + } + + + avalon.each = function (obj, fn) { + if (obj) { //排除null, undefined + var i = 0 + if (isArrayLike(obj)) { + for (var n = obj.length; i < n; i++) { + if (fn(i, obj[i]) === false) + break + } + } else { + for (i in obj) { + if (obj.hasOwnProperty(i) && fn(i, obj[i]) === false) { + break + } + } + } + } + } + + module.exports = { + avalon: avalon, + isArrayLike: isArrayLike + } + + + +/***/ }, /* 6 */ /***/ function(module, exports) { @@ -397,7 +862,7 @@ return /******/ (function(modules) { // webpackBootstrap } kernel.plugins = plugins kernel.plugins['interpolate'](['{{', '}}']) - + //kernel.showDiff = true kernel.debug = true @@ -1196,6331 +1661,6840 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = VElement /***/ }, -/* 19 */, -/* 20 */, -/* 21 */, -/* 22 */, -/* 23 */, -/* 24 */, -/* 25 */, -/* 26 */ +/* 19 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * ------------------------------------------------------------ + * DOM Api + * shim,class,data,css,val,html,event,ready + * ------------------------------------------------------------ + */ + __webpack_require__(20) + __webpack_require__(21) + __webpack_require__(22) + __webpack_require__(23) + __webpack_require__(24) + __webpack_require__(25) + __webpack_require__(31) + __webpack_require__(33) + + module.exports = avalon + +/***/ }, +/* 20 */ /***/ function(module, exports) { - // https://github.com/rsms/js-lru - function LRU(maxLength) { - this.size = 0 - this.limit = maxLength - this.head = this.tail = void 0 - this._keymap = {} + function fixContains(root, el) { + try { //IE6-8,游离于DOM树外的文本节点,访问parentNode有时会抛错 + while ((el = el.parentNode)) + if (el === root) + return true + return false + } catch (e) { + return false + } } - var p = LRU.prototype - - p.put = function (key, value) { - var entry = { - key: key, - value: value + avalon.contains = fixContains + //IE6-11的文档对象没有contains + if (!avalon.document.contains) { + avalon.document.contains = function (b) { + return fixContains(document, b) } - this._keymap[key] = entry - if (this.tail) { - this.tail.newer = entry - entry.older = this.tail - } else { - this.head = entry - } - this.tail = entry - if (this.size === this.limit) { - this.shift() - } else { - this.size++ - } - return value } - p.shift = function () { - var entry = this.head - if (entry) { - this.head = this.head.newer - this.head.older = - entry.newer = - entry.older = - this._keymap[entry.key] = void 0 - delete this._keymap[entry.key] //#1029 - } + function outerHTML() { + return new XMLSerializer().serializeToString(this) } - p.get = function (key) { - var entry = this._keymap[key] - if (entry === void 0) - return - if (entry === this.tail) { - return entry.value - } - // HEAD--------------TAIL - // <.older .newer> - // <--- add direction -- - // A B C E - if (entry.newer) { - if (entry === this.head) { - this.head = entry.newer + + if (avalon.window.SVGElement) { + //safari5+是把contains方法放在Element.prototype上而不是Node.prototype + if (!document.createTextNode('x').contains) { + Node.prototype.contains = function (arg) {//IE6-8没有Node对象 + return !!(this.compareDocumentPosition(arg) & 16) } - entry.newer.older = entry.older // C <-- E. - } - if (entry.older) { - entry.older.newer = entry.newer // C. --> E } - entry.newer = void 0 // D --x - entry.older = this.tail // D. --> E - if (this.tail) { - this.tail.newer = entry // E. <-- D + + var svgns = 'http://www.w3.org/2000/svg' + var svg = avalon.document.createElementNS(svgns, 'svg') + + svg.innerHTML = '' + //IE9-11,firefox,ios7,8的chrome不支持SVG元素的innerHTML,outerHTML属性 + if (!/^\[object SVG\w*Element\]$/.test(svg.firstChild)) { + function createSVG(node, parent) { + /* jshint ignore:start */ + if (node && node.childNodes) { + var nodes = node.childNodes + for (var i = 0, el; el = nodes[i++]; ) { + if (el.nodeType === 1) { + var svg = document.createElementNS(svgns, el.nodeName.toLowerCase()) + avalon.each(el.attributes, function (a, attr) { + svg.setAttribute(attr.name, attr.value) + }) + createSVG(el, svg) + parent.appendChild(svg) + } else { + parent.appendChild(el.cloneNode(true)) + } + } + } + /* jshint ignore:end */ + } + + Object.defineProperties(SVGElement.prototype, { + outerHTML: { + configurable: true, + get: outerHTML, + set: function (html) { + var tagName = this.tagName.toLowerCase() + var parent = this.parent + var parsed = avalon.parseHTML(html) + if (tagName === 'svg') { + parent.insertBefore(parsed, this) + } else { + var empty = document.createDocumentFragment() + createSVG(parsed, empty) + parent.insertBefore(empty, this) + } + parent.removeChild(this) + } + }, + innerHTML: { + configurable: true, + get: function () { + var s = this.outerHTML + var ropen = new RegExp('<' + this.nodeName + '\\b(?:(["\'])[^"]*?(\\1)|[^>])*>', 'i') + var rclose = new RegExp('<\/' + this.nodeName + '>$', 'i') + return s.replace(ropen, '').replace(rclose, '') + }, + set: function (html) { + if (avalon.clearHTML) { + avalon.clearHTML(this) + var frag = avalon.parseHTML(html) + createSVG(frag, this) + } + } + } + }) } - this.tail = entry - return entry.value + } + //firefox 到11时才有outerHTML + if (!avalon.root.outerHTML && window.HTMLElement) { + HTMLElement.prototype.__defineGetter__('outerHTML', outerHTML) } - module.exports = LRU + /***/ }, -/* 27 */ +/* 21 */ /***/ function(module, exports) { - - var scriptNode = avalon.document.createElement('script') - var scriptTypes = avalon.oneObject(['', 'text/javascript', 'text/ecmascript', - 'application/ecmascript', 'application/javascript']) + var rnowhite = /\S+/g + var fakeClassListMethods = { + _toString: function () { + var node = this.node + var cls = node.className + var str = typeof cls === 'string' ? cls : cls.baseVal + var match = str.match(rnowhite) + return match ? match.join(' ') : '' + }, + _contains: function (cls) { + return (' ' + this + ' ').indexOf(' ' + cls + ' ') > -1 + }, + _add: function (cls) { + if (!this.contains(cls)) { + this._set(this + ' ' + cls) + } + }, + _remove: function (cls) { + this._set((' ' + this + ' ').replace(' ' + cls + ' ', ' ')) + }, + __set: function (cls) { + cls = cls.trim() + var node = this.node + if (typeof node.className === 'object') { + //SVG元素的className是一个对象 SVGAnimatedString { baseVal='', animVal=''},只能通过set/getAttribute操作 + node.setAttribute('class', cls) + } else { + node.className = cls + } + } //toggle存在版本差异,因此不使用它 + } - function fixScript(wrapper) { - var els = typeof wrapper.querySelectorAll !== 'undefined'? - wrapper.querySelectorAll('script'): wrapper.getElementsByTagName('script') - if (els.length) { - for (var i = 0, el; el = els[i++]; ) { - if (scriptTypes[el.type]) { - //以偷龙转凤方式恢复执行脚本功能 - var neo = scriptNode.cloneNode(false) //FF不能省略参数 - Array.prototype.forEach.call(el.attributes, function (attr) { - if (attr && attr.specified) { - neo[attr.name] = attr.value //复制其属性 - neo.setAttribute(attr.name, attr.value) - } - }) // jshint ignore:line - neo.text = el.text - el.parentNode.replaceChild(neo, el) //替换节点 - } + function fakeClassList(node) { + if (!('classList' in node)) { + node.classList = { + node: node + } + for (var k in fakeClassListMethods) { + node.classList[k.slice(1)] = fakeClassListMethods[k] } } + return node.classList } - module.exports = fixScript + 'add,remove'.replace(avalon.rword, function (method) { + avalon.fn[method + 'Class'] = function (cls) { + var el = this[0] || {} + //https://developer.mozilla.org/zh-CN/docs/Mozilla/Firefox/Releases/26 + if (cls && typeof cls === 'string' && el.nodeType === 1) { + cls.replace(rnowhite, function (c) { + fakeClassList(el)[method](c) + }) + } + return this + } + }) + + avalon.fn.mix({ + hasClass: function (cls) { + var el = this[0] || {} + return el.nodeType === 1 && fakeClassList(el).contains(cls) + }, + toggleClass: function (value, stateVal) { + var isBool = typeof stateVal === 'boolean' + var me = this + String(value).replace(rnowhite, function (c) { + var state = isBool ? stateVal : !me.hasClass(c) + me[state ? 'addClass' : 'removeClass'](c) + }) + return this + } + }) -/***/ }, -/* 28 */, -/* 29 */, -/* 30 */, -/* 31 */, -/* 32 */ -/***/ function(module, exports) { - //http://www.feiesoft.com/html/events.html - //http://segmentfault.com/q/1010000000687977/a-1020000000688757 - module.exports = { - click: true, - dblclick: true, - keydown: true, - keypress: true, - keyup: true, - mousedown: true, - mousemove: true, - mouseup: true, - mouseover: true, - mouseout: true, - wheel: true, - mousewheel: true, - input: true, - change: true, - beforeinput: true, - compositionstart: true, - compositionupdate: true, - compositionend: true, - select: true, - //http://blog.csdn.net/lee_magnum/article/details/17761441 - cut: true, - copy: true, - paste: true, - beforecut: true, - beforecopy: true, - beforepaste: true, - focusin: true, - focusout: true, - DOMFocusIn: true, - DOMFocusOut: true, - DOMActivate: true, - dragend: true, - datasetchanged: true - } /***/ }, -/* 33 */, -/* 34 */ +/* 22 */ /***/ function(module, exports) { - var scanStatistics = 0 - function scan(nodes) { - for (var i = 0, elem; elem = nodes[i++]; ) { - if (elem.nodeType === 1) { - var $id = getController(elem) - if ($id) { - ++scanStatistics - } - var vm = avalon.vmodels[$id] - if (vm && !vm.$element) { - cleanWhitespace(elem)//减少虚拟DOM的规模及diff, patch的时间 - avalon(elem).removeClass('ms-controller') - vm.$element = elem - var now = new Date() - //IE6-8下元素的outerHTML前面会有空白 - elem.vtree = avalon.lexer(elem.outerHTML.trim()) - var now2 = new Date() - avalon.log('create primitive vtree', now2 - now) - vm.$render = avalon.render(elem.vtree) - var now3 = new Date() - avalon.log('create template Function ', now3 - now2) - avalon.rerenderStart = now3 - avalon.batch($id, true) + + var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/, + rvalidchars = /^[\],:{}\s]*$/, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, + rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g - } else if (!$id) { - scan(elem.childNodes) + avalon.parseJSON = avalon.window.JSON ? JSON.parse : function (data) { + if (typeof data === 'string') { + data = data.trim(); + if (data) { + if (rvalidchars.test(data.replace(rvalidescape, '@') + .replace(rvalidtokens, ']') + .replace(rvalidbraces, ''))) { + return (new Function('return ' + data))() // jshint ignore:line } } + avalon.error('Invalid JSON: ' + data) } + return data } - var notWhitespace = /\S/ - function cleanWhitespace(target) { - var keep - for (var i = 0; i < target.childNodes.length; i++) { - var node = target.childNodes[i] - if ((node.nodeType === 3) && (!notWhitespace.test(node.nodeValue))) { - keep = target.removeChild(node) - i-- - } else if (node.nodeType === 1) { - cleanWhitespace(node) - } - } - if (target.childNodes.length === 0 && keep) { - target.appendChild(keep) + + function parseData(data) { + try { + if (typeof data === 'object') + return data + data = data === 'true' ? true : + data === 'false' ? false : + data === 'null' ? null : +data + '' === data ? +data : + rbrace.test(data) ? avalon.parseJSON(data) : data + } catch (e) { } + return data } - module.exports = avalon.scan = function (a) { - if (!a || !a.nodeType) { - avalon.warn('[avalon.scan] first argument must be element , documentFragment, or document') - return + + avalon.fn.attr = function (name, value) { + if (arguments.length === 2) { + this[0].setAttribute(name, value) + return this + } else { + return this[0].getAttribute(name) } - scan([a]) - if (scanStatistics === 0) { - avalon.warn('[avalon.scan] your nodes must has "ms-controller" attribute') + } + + avalon.fn.data = function (name, value) { + name = 'data-' + avalon.hyphen(name || '') + switch (arguments.length) { + case 2: + this.attr(name, value) + return this + case 1: + var val = this.attr(name) + return parseData(val) + case 0: + var ret = {} + avalon.each(this[0].attributes, function (i, attr) { + if (attr) { + name = attr.name + if (!name.indexOf('data-')) { + name = avalon.camelize(name.slice(5)) + ret[name] = parseData(attr.value) + } + } + }) + return ret } - scanStatistics = 0 } - function getController(a) { - return a.getAttribute('ms-controller') - } + /***/ }, -/* 35 */, -/* 36 */ -/***/ function(module, exports, __webpack_require__) { +/* 23 */ +/***/ function(module, exports) { - var parseView = __webpack_require__(37) + var root = avalon.root + var window = avalon.window + var camelize = avalon.camelize + var cssHooks = avalon.cssHooks - avalon.important = function (elem, vid) { - //如果vmodel还不存在,直接返回 - var wid = elem.props.wid - var vm = avalon.vmodels[vid] - if(!vm){ - return elem - }else if (typeof avalon.caches[wid] === 'string') { - var body = avalon.caches[wid] - //生成模板函数,并进行相关缓存 - body = '__vmodel__ = avalon.vmodels[' + - avalon.quote(vid) + ']\n' + body - var render = Function('__vmodel__', body) - var child = render() - elem = avalon.caches[wid] = child[0] - elem.order = 'ms-important' - elem.skipAttrs = false - elem.props['ms-important'] = vid - elem.render = render - return elem + var prefixes = ['', '-webkit-', '-o-', '-moz-', '-ms-'] + var cssMap = { + 'float': window.Range ? 'cssFloat' : 'styleFloat' + } + avalon.cssNumber = avalon.oneObject('animationIterationCount,columnCount,order,flex,flexGrow,flexShrink,fillOpacity,fontWeight,lineHeight,opacity,orphans,widows,zIndex,zoom') + + avalon.cssName = function (name, host, camelCase) { + if (cssMap[name]) { + return cssMap[name] + } + host = host || root.style || {} + for (var i = 0, n = prefixes.length; i < n; i++) { + camelCase = camelize(prefixes[i] + name) + if (camelCase in host) { + return (cssMap[name] = camelCase) + } + } + return null + } + + + avalon.fn.css = function (name, value) { + if (avalon.isPlainObject(name)) { + for (var i in name) { + avalon.css(this, i, name[i]) + } } else { - elem = avalon.caches[wid] - elem.skipAttrs = elem.skipContent = true - return elem + var ret = avalon.css(this, name, value) } + return ret !== void 0 ? ret : this } - avalon.directive("important", { - priority: 1, - parse: function (binding, num, elem) { - delete elem.props['ms-important'] - var wid = elem.props.wid || (elem.props.wid = avalon.makeHashCode('w')) - var fn = parseView([elem], num) + '\n\nreturn vnodes' + num - //将渲染函数的某一部分存起来,渲在c方法中转换为函数 - avalon.caches[wid] = fn - elem.isVoidTag = true - return ['vnode' + num + '.props.wid = ' + avalon.quote(wid), - 'vnode' + num + ' = avalon.important(vnode' + num + ',' + - avalon.quote(binding.expr) + ')'].join('\n') + '\n' - }, - diff: function (cur, pre, steps, name) { - if (pre.props[name] !== cur.props[name]) { - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 + avalon.fn.position = function () { + var offsetParent, offset, + elem = this[0], + parentOffset = { + top: 0, + left: 0 } + if (!elem) { + return parentOffset + } + if (this.css('position') === 'fixed') { + offset = elem.getBoundingClientRect() + } else { + offsetParent = this.offsetParent() //得到真正的offsetParent + offset = this.offset() // 得到正确的offsetParent + if (offsetParent[0].tagName !== 'HTML') { + parentOffset = offsetParent.offset() } - }, - update: function (node, vnode) { - var vid = vnode.props['ms-important'] - var vm = avalon.vmodels[vid] - vm.$render = vnode.render - vm.$element = node + parentOffset.top += avalon.css(offsetParent[0], 'borderTopWidth', true) + parentOffset.left += avalon.css(offsetParent[0], 'borderLeftWidth', true) + + // Subtract offsetParent scroll positions + parentOffset.top -= offsetParent.scrollTop() + parentOffset.left -= offsetParent.scrollLeft() } - }) + return { + top: offset.top - parentOffset.top - avalon.css(elem, 'marginTop', true), + left: offset.left - parentOffset.left - avalon.css(elem, 'marginLeft', true) + } + } + avalon.fn.offsetParent = function () { + var offsetParent = this[0].offsetParent + while (offsetParent && avalon.css(offsetParent, 'position') === 'static') { + offsetParent = offsetParent.offsetParent; + } + return avalon(offsetParent || root) + } + cssHooks['@:set'] = function (node, name, value) { + try { + //node.style.width = NaN;node.style.width = 'xxxxxxx'; + //node.style.width = undefine 在旧式IE下会抛异常 + node.style[name] = value + } catch (e) { + } + } + if (window.getComputedStyle) { + cssHooks['@:get'] = function (node, name) { + if (!node || !node.style) { + throw new Error('getComputedStyle要求传入一个节点 ' + node) + } + var ret, styles = getComputedStyle(node, null) + if (styles) { + ret = name === 'filter' ? styles.getPropertyValue(name) : styles[name] + if (ret === '') { + ret = node.style[name] //其他浏览器需要我们手动取内联样式 + } + } + return ret + } + cssHooks['opacity:get'] = function (node) { + var ret = cssHooks['@:get'](node, 'opacity') + return ret === '' ? '1' : ret + } + } else { + var rnumnonpx = /^-?(?:\d*\.)?\d+(?!px)[^\d\s]+$/i + var rposition = /^(top|right|bottom|left)$/ + var ralpha = /alpha\([^)]*\)/i + var ie8 = !!window.XDomainRequest + var salpha = 'DXImageTransform.Microsoft.Alpha' + var border = { + thin: ie8 ? '1px' : '2px', + medium: ie8 ? '3px' : '4px', + thick: ie8 ? '5px' : '6px' + } + cssHooks['@:get'] = function (node, name) { + //取得精确值,不过它有可能是带em,pc,mm,pt,%等单位 + var currentStyle = node.currentStyle + var ret = currentStyle[name] + if ((rnumnonpx.test(ret) && !rposition.test(ret))) { + //①,保存原有的style.left, runtimeStyle.left, + var style = node.style, + left = style.left, + rsLeft = node.runtimeStyle.left + //②由于③处的style.left = xxx会影响到currentStyle.left, + //因此把它currentStyle.left放到runtimeStyle.left, + //runtimeStyle.left拥有最高优先级,不会style.left影响 + node.runtimeStyle.left = currentStyle.left + //③将精确值赋给到style.left,然后通过IE的另一个私有属性 style.pixelLeft + //得到单位为px的结果;fontSize的分支见http://bugs.jquery.com/ticket/760 + style.left = name === 'fontSize' ? '1em' : (ret || 0) + ret = style.pixelLeft + 'px' + //④还原 style.left,runtimeStyle.left + style.left = left + node.runtimeStyle.left = rsLeft + } + if (ret === 'medium') { + name = name.replace('Width', 'Style') + //border width 默认值为medium,即使其为0' + if (currentStyle[name] === 'none') { + ret = '0px' + } + } + return ret === '' ? 'auto' : border[ret] || ret + } + cssHooks['opacity:set'] = function (node, name, value) { + var style = node.style + var opacity = isFinite(value) && value <= 1 ? 'alpha(opacity=' + value * 100 + ')' : '' + var filter = style.filter || ''; + style.zoom = 1 + //不能使用以下方式设置透明度 + //node.filters.alpha.opacity = value * 100 + style.filter = (ralpha.test(filter) ? + filter.replace(ralpha, opacity) : + filter + ' ' + opacity).trim() + if (!style.filter) { + style.removeAttribute('filter') + } + } + cssHooks['opacity:get'] = function (node) { + //这是最快的获取IE透明值的方式,不需要动用正则了! + var alpha = node.filters.alpha || node.filters[salpha], + op = alpha && alpha.enabled ? alpha.opacity : 100 + return (op / 100) + '' //确保返回的是字符串 + } + } + + 'top,left'.replace(avalon.rword, function (name) { + cssHooks[name + ':get'] = function (node) { + var computed = cssHooks['@:get'](node, name) + return /px$/.test(computed) ? computed : + avalon(node).position()[name] + 'px' + } + }) -/***/ }, -/* 37 */ -/***/ function(module, exports, __webpack_require__) { + var cssShow = { + position: 'absolute', + visibility: 'hidden', + display: 'block' + } - - var parseExpr = __webpack_require__(38) - var parseBindings = __webpack_require__(41) - var parseDelimiter = __webpack_require__(42) - var rexpr = avalon.config.rexpr - var quote = avalon.quote - var makeHashCode = avalon.makeHashCode - var r = __webpack_require__(40) - var rident = r.ident - var rsp = r.sp - function wrapDelimiter(expr) { - return rident.test(expr) ? expr : parseExpr(expr, 'text') + var rdisplayswap = /^(none|table(?!-c[ea]).+)/ + + function showHidden(node, array) { + //http://www.cnblogs.com/rubylouvre/archive/2012/10/27/2742529.html + if (node.offsetWidth <= 0) { //opera.offsetWidth可能小于0 + if (rdisplayswap.test(cssHooks['@:get'](node, 'display'))) { + var obj = { + node: node + } + for (var name in cssShow) { + obj[name] = node.style[name] + node.style[name] = cssShow[name] + } + array.push(obj) + } + var parent = node.parentNode + if (parent && parent.nodeType === 1) { + showHidden(parent, array) + } + } } + avalon.each({ + Width: 'width', + Height: 'height' + }, function (name, method) { + var clientProp = 'client' + name, + scrollProp = 'scroll' + name, + offsetProp = 'offset' + name + cssHooks[method + ':get'] = function (node, which, override) { + var boxSizing = -4 + if (typeof override === 'number') { + boxSizing = override + } + which = name === 'Width' ? ['Left', 'Right'] : ['Top', 'Bottom'] + var ret = node[offsetProp] // border-box 0 + if (boxSizing === 2) { // margin-box 2 + return ret + avalon.css(node, 'margin' + which[0], true) + avalon.css(node, 'margin' + which[1], true) + } + if (boxSizing < 0) { // padding-box -2 + ret = ret - avalon.css(node, 'border' + which[0] + 'Width', true) - avalon.css(node, 'border' + which[1] + 'Width', true) + } + if (boxSizing === -4) { // content-box -4 + ret = ret - avalon.css(node, 'padding' + which[0], true) - avalon.css(node, 'padding' + which[1], true) + } + return ret + } + cssHooks[method + '&get'] = function (node) { + var hidden = []; + showHidden(node, hidden); + var val = cssHooks[method + ':get'](node) + for (var i = 0, obj; obj = hidden[i++]; ) { + node = obj.node + for (var n in obj) { + if (typeof obj[n] === 'string') { + node.style[n] = obj[n] + } + } + } + return val + } + avalon.fn[method] = function (value) { //会忽视其display + var node = this[0] + if (arguments.length === 0) { + if (node.setTimeout) { //取得窗口尺寸 + return node['inner' + name] || + node.document.documentElement[clientProp] || + node.document.body[clientProp] //IE6下前两个分别为undefined,0 + } + if (node.nodeType === 9) { //取得页面尺寸 + var doc = node.documentElement + //FF chrome html.scrollHeight< body.scrollHeight + //IE 标准模式 : html.scrollHeight> body.scrollHeight + //IE 怪异模式 : html.scrollHeight 最大等于可视窗口多一点? + return Math.max(node.body[scrollProp], doc[scrollProp], node.body[offsetProp], doc[offsetProp], doc[clientProp]) + } + return cssHooks[method + '&get'](node) + } else { + return this.css(method, value) + } + } + avalon.fn['inner' + name] = function () { + return cssHooks[method + ':get'](this[0], void 0, -2) + } + avalon.fn['outer' + name] = function (includeMargin) { + return cssHooks[method + ':get'](this[0], void 0, includeMargin === true ? 2 : 0) + } + }) - function wrap(a, num) { - return '(function(){\n\n' + a + '\n\nreturn vnodes' + num + '\n})();\n' + avalon.fn.offset = function () { //取得距离页面左右角的坐标 + var node = this[0], + box = { + left: 0, + top: 0 + } + if (!node || !node.tagName || !node.ownerDocument) { + return box + } + var doc = node.ownerDocument, + body = doc.body, + root = doc.documentElement, + win = doc.defaultView || doc.parentWindow + if (!avalon.contains(root, node)) { + return box + } + //http://hkom.blog1.fc2.com/?mode=m&no=750 body的偏移量是不包含margin的 + //我们可以通过getBoundingClientRect来获得元素相对于client的rect. + //http://msdn.microsoft.com/en-us/library/ms536433.aspx + if (node.getBoundingClientRect) { + box = node.getBoundingClientRect() // BlackBerry 5, iOS 3 (original iPhone) + } + //chrome/IE6: body.scrollTop, firefox/other: root.scrollTop + var clientTop = root.clientTop || body.clientTop, + clientLeft = root.clientLeft || body.clientLeft, + scrollTop = Math.max(win.pageYOffset || 0, root.scrollTop, body.scrollTop), + scrollLeft = Math.max(win.pageXOffset || 0, root.scrollLeft, body.scrollLeft) + // 把滚动距离加到left,top中去。 + // IE一些版本中会自动为HTML元素加上2px的border,我们需要去掉它 + // http://msdn.microsoft.com/en-us/library/ms533564(VS.85).aspx + return { + top: box.top + scrollTop - clientTop, + left: box.left + scrollLeft - clientLeft + } } - var rmsFor = /^\s*ms\-for:/ - var rmsForEnd = /^\s*ms\-for\-end:/ + //生成avalon.fn.scrollLeft, avalon.fn.scrollTop方法 + avalon.each({ + scrollLeft: 'pageXOffset', + scrollTop: 'pageYOffset' + }, function (method, prop) { + avalon.fn[method] = function (val) { + var node = this[0] || {}, + win = getWindow(node), + top = method === 'scrollTop' + if (!arguments.length) { + return win ? (prop in win) ? win[prop] : root[method] : node[method] + } else { + if (win) { + win.scrollTo(!top ? val : avalon(win).scrollLeft(), top ? val : avalon(win).scrollTop()) + } else { + node[method] = val + } + } + } + }) - function parseView(arr, num, scan) { - num = num || String(new Date - 0).slice(0, 5) + function getWindow(node) { + return node.window && node.document ? node : node.nodeType === 9 ? node.defaultView || node.parentWindow : false; + } - var forstack = [] - var hasIf = false - var children = 'vnodes' + num - var vnode = 'vnode' + num - var str = 'var ' + children + ' = []\n' - for (var i = 0; i < arr.length; i++) { - var el = arr[i] - if (el.nodeType === 3) { - str += 'var ' + vnode + ' = {type:"#text",nodeType:3,skipContent:true}\n' - var hasDelimiter = rexpr.test(el.nodeValue) +/***/ }, +/* 24 */ +/***/ function(module, exports) { - if (hasDelimiter) { - var array = parseDelimiter(el.nodeValue) - if (array.length === 1) { - var a = parseExpr(array[0].expr) - str += vnode + '.nodeValue = ' + wrapDelimiter(array[0].expr) + '\n' - } else { - a = array.map(function (el) { - return el.type ? wrapDelimiter(el.expr) : quote(el.expr) - }).join(' + ') - str += vnode + '.nodeValue = String(' + a + ')\n' - } - str += vnode + '.fixIESkip = true\n' - /* jshint ignore:start */ - str += vnode + '.skipContent = false\n' - } else { - if (rsp.test(el.nodeValue)) { - str += vnode + '.nodeValue = "\\n"\n' - } else { - str += vnode + '.nodeValue = ' + quote(el.nodeValue) + '\n' - } - } - str += children + '.push(' + vnode + ')\n' - continue - } else if (el.nodeType === 8) { - var nodeValue = el.nodeValue - if (rmsFor.test(nodeValue)) {// 处理ms-for指令 - if (nodeValue.indexOf('ms-for:') !== 0) { - avalon.error('ms-for指令前不能有空格') - } - var signature = el.signature - forstack.push(signature) - str += '\nvar ' + signature + ' = {' + - '\n\tnodeType:8,' + - '\n\ttype:"#comment",' + - '\n\tvmodel:__vmodel__,' + - '\n\tdirective:"for",' + - '\n\tskipContent:false,' + - '\n\tcid:' + quote(el.cid) + ',' + - '\n\tstart:' + children + '.length,' + - '\n\tsignature:' + quote(signature) + ',' + - '\n\ttemplate:' + quote(el.template) + ',' + - '\n\tnodeValue:' + quote(nodeValue) + - '\n}\n' - str += children + '.push(' + signature + ')\n' - - str += avalon.directives['for'].parse(el, num) - - } else if (rmsForEnd.test(nodeValue)) { - var signature = forstack[forstack.length - 1] - if (nodeValue.indexOf('ms-for-end:') !== 0) { - avalon.error('ms-for-end指令前不能有空格') - } - str += children + '.push({' + - '\n\tnodeType: 8,' + - '\n\ttype:"#comment",' + - '\n\tskipContent: true,' + - '\n\tnodeValue:' + quote(signature) + ',' + - '\n\tkey:traceKey\n})\n' - str += '\n})\n' //结束循环 - if (forstack.length) { - var signature = forstack[forstack.length - 1] - str += signature + '.end =' + children + '.push({' + - '\n\tnodeType: 8,' + - '\n\ttype:"#comment",' + - '\n\tskipContent: true,' + - '\n\tsignature: ' + quote(signature) + ',' + - '\n\tnodeValue: "ms-for-end:"' + - '\n})\n' - forstack.pop() - } - } else if (nodeValue.indexOf('ms-js:') === 0) {//插入普通JS代码 - str += parseExpr(nodeValue.replace('ms-js:', ''), 'js') + '\n' - } else { - str += children + '.push(' + quote(el) + ')\n\n\n' - } - continue - } else { //处理元素节点 - - str += 'var ' + vnode + ' = {' + - '\n\tnodeType:1,' + - '\n\ttype: ' + quote(el.type) + ',' + - '\n\tprops:{},' + - '\n\tchildren: [],' + - '\n\tisVoidTag: ' + !!el.isVoidTag + ',' + - '\n\ttemplate: ""}\n' - - var hasWidget = el.props['ms-widget'] - if (!hasWidget && el.type.indexOf('-') > 0 && !el.props.resolved) { - el.props['ms-widget'] = '@' + el.type.replace(/-/g, "_") - } - var hasBindings = '' - var vmID = el.props['ms-controller'] - - hasBindings = parseBindings(el.props, num, el) - if (hasBindings) { - str += hasBindings - } - if (!el.isVoidTag) { - if (el.children.length) { - var hasIf = el.props['ms-if'] - if (hasIf) { - str += 'if(' + vnode + '&&' + vnode + '.nodeType === 1 ){\n' - } - str += vnode + '.children = ' + wrap(parseView(el.children, num), num) + '\n' - if (hasIf) { - str += '}\n' - } - } else { - str += vnode + '.template = ' + quote(el.template) + '\n' + function getValType(elem) { + var ret = elem.tagName.toLowerCase() + return ret === 'input' && /checkbox|radio/.test(elem.type) ? 'checked' : ret + } + var roption = /^]+))?)*\s+value[\s=]/i + var valHooks = { + 'option:get': avalon.msie ? function (node) { + //在IE11及W3C,如果没有指定value,那么node.value默认为node.text(存在trim作),但IE9-10则是取innerHTML(没trim操作) + //specified并不可靠,因此通过分析outerHTML判定用户有没有显示定义value + return roption.test(node.outerHTML) ? node.value : node.text.trim() + } : function (node) { + return node.value + }, + 'select:get': function (node, value) { + var option, options = node.options, + index = node.selectedIndex, + getter = valHooks['option:get'], + one = node.type === 'select-one' || index < 0, + values = one ? null : [], + max = one ? index + 1 : options.length, + i = index < 0 ? max : one ? index : 0 + for (; i < max; i++) { + option = options[i] + //IE6-9在reset后不会改变selected,需要改用i === index判定 + //我们过滤所有disabled的option元素,但在safari5下, + //如果设置optgroup为disable,那么其所有孩子都disable + //因此当一个元素为disable,需要检测其是否显式设置了disable及其父节点的disable情况 + if ((option.selected || i === index) && !option.disabled && + (!option.parentNode.disabled || option.parentNode.tagName !== 'OPTGROUP') + ) { + value = getter(option) + if (one) { + return value } + //收集所有selected值组成数组返回 + values.push(value) } - str += children + '.push(' + vnode + ')\n' - if (vmID) {//闭合ms-controller指令中avalon.skipController分支 - str += '}' + } + return values + }, + 'select:set': function (node, values, optionSet) { + values = [].concat(values) //强制转换为数组 + var getter = valHooks['option:get'] + for (var i = 0, el; el = node.options[i++]; ) { + if ((el.selected = values.indexOf(getter(el)) > -1)) { + optionSet = true } } - + if (!optionSet) { + node.selectedIndex = -1 + } } - return str } - avalon.htmlFactory = function (str, num) { - var vtree = avalon.lexer(str + "") - avalon.__html = [] - var render = parseView(vtree, num) + '\nreturn (avalon.__html = vnodes' + num + ')' - return { - render: render + + avalon.fn.val = function (value) { + var node = this[0] + if (node && node.nodeType === 1) { + var get = arguments.length === 0 + var access = get ? ':get' : ':set' + var fn = valHooks[getValType(node) + access] + if (fn) { + var val = fn(node, value) + } else if (get) { + return (node.value || '').replace(/\r/g, '') + } else { + node.value = value + } } + return get ? val : this } - module.exports = parseView - /***/ }, -/* 38 */ +/* 25 */ /***/ function(module, exports, __webpack_require__) { - - - //缓存求值函数,以便多次利用 - var evaluatorPool = __webpack_require__(39) - - var rregexp = /(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\\\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/g - var rstring = __webpack_require__(40).string - var rfill = /\?\?\d+/g - var brackets = /\(([^)]*)\)/ - var rAt = /(^|[^\w\u00c0-\uFFFF_])(@|#)(?=\w)/g - var rhandleName = /^(?:\@|\#)[$\w]+$/ - var rshortCircuit = /\|\|/g - var rpipeline = /\|(?=\w)/ - var ruselessSp = /\s*(\.|\|)\s*/g - var wrapDuplex = function(arr){ - return '(function(){ return ' +arr.join('\n')+'})();\n' - } - function parseExpr(str, category) { + var Cache = __webpack_require__(26) + var fixScript = __webpack_require__(27) + var fixTbodyVML = __webpack_require__(28) + var fixCloneNode = __webpack_require__(30) + + var tagHooks = { + area: [1, '', ''], + param: [1, '', ''], + col: [2, '', '
'], + legend: [1, '
', '
'], + option: [1, ''], + thead: [1, '', '
'], + tr: [2, '', '
'], + td: [3, '', '
'], + g: [1, '', ''], + //IE6-8在用innerHTML生成节点时,不能直接创建no-scope元素与HTML5的新标签 + _default: avalon.modern ? [0, '', ''] : [1, 'X
', '
'] //div可以不用闭合 + } + tagHooks.th = tagHooks.td + tagHooks.optgroup = tagHooks.option + tagHooks.tbody = tagHooks.tfoot = tagHooks.colgroup = tagHooks.caption = tagHooks.thead + String('circle,defs,ellipse,image,line,path,polygon,polyline,rect,symbol,text,use').replace(avalon.rword, function (tag) { + tagHooks[tag] = tagHooks.g //处理SVG + }) - var binding = {} - category = category || 'other' - if (typeof str === 'object') { - category = str.type - binding = str - str = binding.expr + var rtagName = /<([\w:]+)/ //取得其tagName + var rxhtml = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig + var rcreate = avalon.modern ? /[^\d\D]/ : /(<(?:script|link|style|meta|noscript))/ig + var rnest = /<(?:tb|td|tf|th|tr|col|opt|leg|cap|area)/ //需要处理套嵌关系的标签 + var rhtml = /<|&#?\w+;/ + var htmlCache = new Cache(128) + avalon.parseHTML = function (html) { + var fragment = avalon.avalonFragment.cloneNode(false), firstChild + //处理非字符串 + if (typeof html !== 'string') { + return fragment + } + //处理非HTML字符串 + if (!rhtml.test(html)) { + fragment.appendChild(document.createTextNode(html)) + return fragment } - if (typeof str !== 'string') - return '' - var cacheID = str - var cacheStr = evaluatorPool.get(category + ':' + cacheID) - if (cacheStr) { - return cacheStr + html = html.replace(rxhtml, '<$1>').trim() + var hasCache = htmlCache.get(html) + if (hasCache) { + return fixCloneNode(hasCache) } - var number = 1 - //相同的表达式生成相同的函数 - var maps = {} - function dig(a) { - var key = '??' + number++ - maps[key] = a - return key + var tag = (rtagName.exec(html) || ['', ''])[1].toLowerCase() + var wrap = tagHooks[tag] || tagHooks._default + var wrapper = avalon.avalonDiv + + wrapper.innerHTML = wrap[1] + html + wrap[2] + + //使用innerHTML生成的script节点不会发出请求与执行text属性 + fixScript(wrapper) + + if (!avalon.modern) { //fix IE + fixTbodyVML(wrapper, wrap, tag) } - function fill(a) { - return maps[a] + //移除我们为了符合套嵌关系而添加的标签 + for (var i = wrap[0]; i--; wrapper = wrapper.lastChild) { + } + while (firstChild = wrapper.firstChild) { // 将wrapper上的节点转移到文档碎片上! + fragment.appendChild(firstChild) + } + if (html.length < 1024) { + htmlCache.put(html, fixCloneNode(fragment)) } + return fragment + } - var input = str.replace(rregexp, dig).//移除所有正则 - replace(rstring, dig).//移除所有字符串 - replace(rshortCircuit, dig).//移除所有短路或 - replace(ruselessSp, '$1').//移除. |两端空白 - split(rpipeline) //使用管道符分离所有过滤器及表达式的正体 - //还原body - var body = input.shift().replace(rfill, fill).trim() - if (category === 'on' && rhandleName.test(body)) { - body = body + '($event)' + avalon.innerHTML = function (node, html) { + if (!avalon.modern && (!rcreate.test(html) && !rnest.test(html))) { + try { + node.innerHTML = html + return + } catch (e) { + } } + var parsed = this.parseHTML(html) + this.clearHTML(node).appendChild(parsed) + } - body = body.replace(rAt, '$1__vmodel__.') - if (category === 'js') { - return evaluatorPool.put(category + ':' + cacheID, body) + avalon.clearHTML = function (node) { + avalon.$$unbind(node) + node.textContent = '' + while (node.lastChild) { + node.removeChild(node.lastChild) } + return node + } - //处理表达式的过滤器部分 - var filters = input.map(function (str) { - str = str.replace(rfill, fill).replace(rAt, '$1__vmodel__.') //还原 - var hasBracket = false - str = str.replace(brackets, function (a, b) { - hasBracket = true - return /\S/.test(b) ? - '(__value__,' + b + ');' : - '(__value__);' - }) - if (!hasBracket) { - str += '(__value__);' - } - str = str.replace(/(\w+)/, 'avalon.__format__("$1")') - return '__value__ = ' + str - }) - var ret = [] - if (category === 'on') { - filters = filters.map(function (el) { - return el.replace(/__value__/g, '$event') - }) - if (filters.length) { - filters.push('if($event.$return){\n\treturn;\n}') - } - if(!avalon.modern){ - body = body.replace(/__vmodel__\.([^(]+)\(([^)]*)\)/,function(a, b, c){ - return '__vmodel__.'+b+".call(__vmodel__"+ (/\S/.test(c) ? ','+c: "")+")" - }) - } - ret = ['function self($event){', - 'try{', - '\tvar __vmodel__ = this;', - '\t' + body, - '}catch(e){', - quoteError(str, category), - '}', - '}'] - filters.unshift(2, 0) - } else if (category === 'duplex') { +/***/ }, +/* 26 */ +/***/ function(module, exports) { - //从vm中得到当前属性的值 - var getterBody = [ - 'function (__vmodel__){', - 'try{', - 'return ' + body + '\n', - '}catch(e){', - quoteError(str, category), - '}', - '}'] - evaluatorPool.put('duplex:' + cacheID,wrapDuplex(getterBody)) - //给vm同步某个属性 - var setterBody = [ - 'function (__vmodel__,__value__){', - 'try{', - '\t' + body + ' = __value__', - '}catch(e){', - quoteError(str, category), - '}', - '}'] - evaluatorPool.put('duplex:set:' + cacheID, wrapDuplex(setterBody)) - //对某个值进行格式化 - if (input.length) { - var formatBody = [ - 'function (__vmodel__, __value__){', - 'try{', - filters.join('\n'), - 'return __value__\n', - '}catch(e){', - quoteError(str, category), - '}', - '}'] - evaluatorPool.put('duplex:format:' + cacheID, wrapDuplex(formatBody)) - } - return + // https://github.com/rsms/js-lru + function LRU(maxLength) { + this.size = 0 + this.limit = maxLength + this.head = this.tail = void 0 + this._keymap = {} + } + + var p = LRU.prototype + + p.put = function (key, value) { + var entry = { + key: key, + value: value + } + this._keymap[key] = entry + if (this.tail) { + this.tail.newer = entry + entry.older = this.tail } else { - ret = [ - '(function(){', - 'try{', - 'var __value__ = ' + body, - ( category === 'text'? - 'return __value__ == null ? "" :__value__': - 'return __value__'), - '}catch(e){', - quoteError(str, category), - '\treturn ""', - '}', - '})()' - ] - filters.unshift(3, 0) + this.head = entry } - ret.splice.apply(ret, filters) - cacheStr = ret.join('\n') - evaluatorPool.put(category + ':' + cacheID, cacheStr) - return cacheStr + this.tail = entry + if (this.size === this.limit) { + this.shift() + } else { + this.size++ + } + return value + } + p.shift = function () { + var entry = this.head + if (entry) { + this.head = this.head.newer + this.head.older = + entry.newer = + entry.older = + this._keymap[entry.key] = void 0 + delete this._keymap[entry.key] //#1029 + } + } + p.get = function (key) { + var entry = this._keymap[key] + if (entry === void 0) + return + if (entry === this.tail) { + return entry.value + } + // HEAD--------------TAIL + // <.older .newer> + // <--- add direction -- + // A B C E + if (entry.newer) { + if (entry === this.head) { + this.head = entry.newer + } + entry.newer.older = entry.older // C <-- E. + } + if (entry.older) { + entry.older.newer = entry.newer // C. --> E + } + entry.newer = void 0 // D --x + entry.older = this.tail // D. --> E + if (this.tail) { + this.tail.newer = entry // E. <-- D + } + this.tail = entry + return entry.value } - function quoteError(str, type) { - return '\tavalon.warn(e, ' + - avalon.quote('parse ' + type + ' binding【 ' + str + ' 】fail') - + ')' + module.exports = LRU + + +/***/ }, +/* 27 */ +/***/ function(module, exports) { + + + var scriptNode = avalon.document.createElement('script') + var scriptTypes = avalon.oneObject(['', 'text/javascript', 'text/ecmascript', + 'application/ecmascript', 'application/javascript']) + + function fixScript(wrapper) { + var els = typeof wrapper.querySelectorAll !== 'undefined'? + wrapper.querySelectorAll('script'): wrapper.getElementsByTagName('script') + if (els.length) { + for (var i = 0, el; el = els[i++]; ) { + if (scriptTypes[el.type]) { + //以偷龙转凤方式恢复执行脚本功能 + var neo = scriptNode.cloneNode(false) //FF不能省略参数 + Array.prototype.forEach.call(el.attributes, function (attr) { + if (attr && attr.specified) { + neo[attr.name] = attr.value //复制其属性 + neo.setAttribute(attr.name, attr.value) + } + }) // jshint ignore:line + neo.text = el.text + el.parentNode.replaceChild(neo, el) //替换节点 + } + } + } } - module.exports = avalon.parseExpr = parseExpr + module.exports = fixScript /***/ }, -/* 39 */ +/* 28 */ /***/ function(module, exports, __webpack_require__) { - - var Cache = __webpack_require__(26) - //缓存求值函数,以便多次利用 - module.exports = new Cache(512) + var isVML = __webpack_require__(29) + function fixTbody(wrapper, wrap, tag) { + var target = wrap[1] === 'X
' ? wrapper.lastChild.firstChild : wrapper.lastChild + if (target && target.tagName === 'TABLE' && tag !== 'tbody') { + //IE6-7处理 --> , + // --> , + // -->
+ for (var els = target.childNodes, i = 0, el; el = els[i++]; ) { + if (el.tagName === 'TBODY' && !el.innerHTML) { + target.removeChild(el) + break + } + } + } + + for (els = wrapper.all, i = 0; el = els[i++]; ) { //fix VML + if (isVML(el)) { + fixVML(el) + } + } + } + + function fixVML(node) { + if (node.currentStyle.behavior !== 'url(#default#VML)') { + node.style.behavior = 'url(#default#VML)' + node.style.display = 'inline-block' + node.style.zoom = 1 //hasLayout + } + } + + module.exports = fixTbody /***/ }, -/* 40 */ +/* 29 */ /***/ function(module, exports) { - module.exports = { - ident: /^[$a-zA-Z_][$a-zA-Z0-9_]*$/, - sp: /^\s+$/, //全部都是空白, - leftSp: /^\s+/, //左边空白 - rightSp: /s+$/, //右边空白, - binding: /^ms-(\w+)-?(.*)/, //绑定属性, - string: /(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/g + function isVML(src) { + var nodeName = src.nodeName + return nodeName.toLowerCase() === nodeName && src.scopeName && src.outerText === '' } + module.exports = isVML + /***/ }, -/* 41 */ +/* 30 */ +/***/ function(module, exports) { + + var rcheckedType = /radio|checkbox/ + + function fix(dest, src) { + if (dest.nodeType !== 1) { + return + } + var nodeName = dest.nodeName.toLowerCase() + if (nodeName === 'object') { + if (dest.parentNode) { + dest.outerHTML = src.outerHTML + } + + } else if (nodeName === 'input' && rcheckedType.test(src.type)) { + + dest.defaultChecked = dest.checked = src.checked + + if (dest.value !== src.value) { + dest.value = src.value + } + + } else if (nodeName === 'option') { + dest.defaultSelected = dest.selected = src.defaultSelected + } else if (nodeName === 'input' || nodeName === 'textarea') { + dest.defaultValue = src.defaultValue + } + } + + + function getAll(el) { + if (el.getElementsByTagName) { + return el.getElementsByTagName('*') + } else { + return el.querySelectorAll('*') + } + } + + function fixCloneNode(src) { + var target = src.cloneNode(true) + if(avalon.modern) + return target + var t = getAll(target) + var s = getAll(src) + avalon.each(s, function (i) { + fix(t[i], s[i]) + }) + return target + } + + module.exports = fixCloneNode + +/***/ }, +/* 31 */ /***/ function(module, exports, __webpack_require__) { - var rneedQuote = /[W-]/ - var quote = avalon.quote - var directives = avalon.directives - var rbinding = __webpack_require__(40).binding - var eventMap = avalon.oneObject('animationend,blur,change,input,click,dblclick,focus,keydown,keypress,keyup,mousedown,mouseenter,mouseleave,mousemove,mouseout,mouseover,mouseup,scan,scroll,submit') - var keyMap = avalon.oneObject("break,case,catch,continue,debugger,default,delete,do,else,false," + - "finally,for,function,if,in,instanceof,new,null,return,switch,this," + - "throw,true,try,typeof,var,void,while,with," + /* 关键字*/ - "abstract,boolean,byte,char,class,const,double,enum,export,extends," + - "final,float,goto,implements,import,int,interface,long,native," + - "package,private,protected,public,short,static,super,synchronized," + - "throws,transient,volatile") - function parseBindings(props, num, elem) { - var bindings = [] - var skip = 'ms-skip' in props - var ret = '' - var uniq = {} - for (var i in props) { - var value = props[i], match + var document = avalon.document + var window = avalon.window + var root = avalon.root + var W3C = avalon.modern - if (!skip && (match = i.match(rbinding))) { - var type = match[1] - var param = match[2] || '' - var name = i - if (eventMap[type]) { - var order = parseFloat(param) || 0 - param = type - type = 'on' - } - name = 'ms-' + type + (param ? '-' + param : '') - if (i !== name) { - delete props[i] - props[name] = value - } - if (directives[type]) { - var binding = { - type: type, - param: param, - name: name, - expr: value, - priority: directives[type].priority || type.charCodeAt(0) * 100 - } - if (type === 'on') { - order = order || 0 - binding.name += '-' + order - binding.priority += param.charCodeAt(0) * 100 + order - } - if(!uniq[binding.name]){ - uniq[binding.name] = 1 - bindings.push(binding) - } + var getShortID = __webpack_require__(6).getShortID + //http://www.feiesoft.com/html/events.html + //http://segmentfault.com/q/1010000000687977/a-1020000000688757 + var canBubbleUp = __webpack_require__(32) + + if (!W3C) { + delete canBubbleUp.change + delete canBubbleUp.select + } + + + var eventHooks = avalon.eventHooks + /*绑定事件*/ + avalon.bind = function (elem, type, fn) { + if (elem.nodeType === 1) { + var value = elem.getAttribute('avalon-events') || '' + //如果是使用ms-on-*绑定的回调,其uuid格式为e12122324, + //如果是使用bind方法绑定的回调,其uuid格式为_12 + var uuid = getShortID(fn) + var key = type + ':' + uuid + var hook = eventHooks[type] + if (hook) { + type = hook.type + if (hook.fix) { + fn = hook.fix(elem, fn) + fn.uuid = uuid + '0' } - } else { - //IE6-8下关键字不能直接当做对象的键名,需要用引号括起来 - if (rneedQuote.test(i) || keyMap[i]) {//收集非绑定属性 - ret += 'vnode' + num + '.props[' + quote(i) + '] = ' + quote(value) + '\n' + key = type + ':' + fn.uuid + } + avalon.eventListeners[fn.uuid] = fn + if (value.indexOf(type + ':') === -1) {//同一种事件只绑定一次 + if (canBubbleUp[type] || (avalon.modern && focusBlur[type])) { + delegateEvent(type) } else { - ret += 'vnode' + num + '.props.' + i + ' = ' + quote(value) + '\n' + nativeBind(elem, type, dispatch) } } - } - - if (!bindings.length) { - ret += '\tvnode' + num + '.skipAttrs = true\n' - } else { - bindings.sort(byPriority) - ret += ('vnode' + num + '.order = "'+ bindings.map(function(a){ - return a.name - }).join(';;')+'"\n') - //优化处理ms-widget - var first = bindings[0] - var isWidget = first && first.type === 'widget' - if (isWidget) { - bindings.shift() - bindings.forEach(function (binding) { - ret += 'vnode' + num + '.props[' + quote(binding.name) + '] = ' + quote(binding.expr) + '\n' - }) - ret += directives['widget'].parse(first, num, elem) - } else { - bindings.forEach(function (binding) { - ret += directives[binding.type].parse(binding, num, elem) - }) + var keys = value.split('??') + if (keys[0] === '') { + keys.shift() + } + if (keys.indexOf(key) === -1) { + keys.push(key) + elem.setAttribute('avalon-events', keys.join('??')) + //将令牌放进avalon-events属性中 } + } else { + nativeBind(elem, type, fn) } - return ret - + return fn //兼容之前的版本 } - function byPriority(a, b) { - return a.priority - b.priority + avalon.unbind = function (elem, type, fn) { + if (elem.nodeType === 1) { + var value = elem.getAttribute('avalon-events') || '' + switch (arguments.length) { + case 1: + nativeUnBind(elem, type, dispatch) + elem.removeAttribute('avalon-events') + break + case 2: + value = value.split('??').filter(function (str) { + return str.indexOf(type + ':') === -1 + }).join('??') + elem.setAttribute('avalon-events', value) + break + default: + var search = type + ':' + fn.uuid + value = value.split('??').filter(function (str) { + return str !== search + }).join('??') + elem.setAttribute('avalon-events', value) + delete avalon.eventListeners[fn.uuid] + break + } + } else { + nativeUnBind(elem, type, fn) + } } - module.exports = parseBindings - -/***/ }, -/* 42 */ -/***/ function(module, exports, __webpack_require__) { - - var rline = /\r?\n/g - var r = __webpack_require__(40) - - function parseDelimiter(str) { - var tokens = [], - value, start = 0, - stop - do { - stop = str.indexOf(avalon.config.openTag, start) - if (stop === -1) { - break - } - value = str.slice(start, stop) - if (start === 0) { - value = value.replace(r.leftSp, '') - } - if (value) { // {{ 左边的文本 - tokens.push({ - expr: value - }) - } - start = stop + avalon.config.openTag.length - stop = str.indexOf(avalon.config.closeTag, start) - if (stop === -1) { - break - } - value = str.slice(start, stop) - if (value) { //处理{{ }}插值表达式 - tokens.push({ - expr: value.replace(rline, ''), - type: '{{}}' + var reventNames = /[^\s\?]+/g + var last = +new Date() + var typeRegExp = {} + function collectHandlers(elem, type, handlers) { + var value = elem.getAttribute('avalon-events') + if (value && (elem.disabled !== true || type !== 'click')) { + var uuids = [] + var reg = typeRegExp[type] || (typeRegExp[type] = new RegExp(type + '\\:([^?\s]+)', 'g')) + value.replace(reg, function (a, b) { + uuids.push(b) + return a + }) + if (uuids.length) { + handlers.push({ + elem: elem, + uuids: uuids }) } - start = stop + avalon.config.closeTag.length - } while (1) - value = str.slice(start) + } + elem = elem.parentNode + if (elem && elem.getAttribute && canBubbleUp[type]) { + collectHandlers(elem, type, handlers) + } - var lastText = value.replace(r.rightSp, '') - if (lastText) { //}} 右边的文本 - tokens.push({ - expr: lastText - }) + } + var rhandleHasVm = /^e\d+/ + var rneedSmooth = /move|scroll/ + function dispatch(event) { + event = new avEvent(event) + var type = event.type + var elem = event.target + var handlers = [] + collectHandlers(elem, type, handlers) + var i = 0, j, uuid, handler + while ((handler = handlers[i++]) && !event.cancelBubble) { + event.currentTarget = handler.elem + j = 0 + while ((uuid = handler.uuids[ j++ ]) && + !event.isImmediatePropagationStopped) { + var fn = avalon.eventListeners[uuid] + if (fn) { + var vm = rhandleHasVm.test(uuid) ? handler.elem._ms_context_ : 0 + if (vm && vm.$hashcode === false) { + return avalon.unbind(elem, type, fn) + } + if (rneedSmooth.test(type)) { + var curr = +new Date() + if (curr - last > 16) { + fn.call(vm || elem, event) + last = curr + } + } else { + fn.call(vm || elem, event) + } + } + } } - return tokens } - module.exports = parseDelimiter + var focusBlur = { + focus: true, + blur: true + } + var nativeBind = W3C ? function (el, type, fn, capture) { + el.addEventListener(type, fn, capture) + } : function (el, type, fn) { + el.attachEvent('on' + type, fn) + } + var nativeUnBind = W3C ? function (el, type, fn) { + el.removeEventListener(type, fn) + } : function (el, type, fn) { + el.detachEvent('on' + type, fn) + } + function delegateEvent(type) { + var value = root.getAttribute('delegate-events') || '' + if (value.indexOf(type) === -1) { + var arr = value.match(reventNames) || [] + arr.push(type) + root.setAttribute('delegate-events', arr.join('??')) + nativeBind(root, type, dispatch, !!focusBlur[type]) + } + } -/***/ }, -/* 43 */ -/***/ function(module, exports) { + avalon.fireDom = function (elem, type, opts) { + if (document.createEvent) { + var hackEvent = document.createEvent('Events') + hackEvent.initEvent(type, true, true, opts) + avalon.shadowCopy(hackEvent, opts) - // 抽离出来公用 - avalon.skipController = function (fast, vm, iv) { - if (fast) { - var id = vm.$render ? vm.$render.$id : vm.$id - if (fast.length > id.length) { - return fast.indexOf(id + ';;') !== 0 - } - return id.indexOf(fast) !== 0 + elem.dispatchEvent(hackEvent) + } else if (root.contains(elem)) {//IE6-8触发事件必须保证在DOM树中,否则报'SCRIPT16389: 未指明的错误' + hackEvent = document.createEventObject() + avalon.shadowCopy(hackEvent, opts) + elem.fireEvent('on' + type, hackEvent) } - return false } - avalon.directive('controller', { - priority: 2, - parse: function (binding, num, elem) { - var id = avalon.quote(binding.expr) - delete elem.props['ms-controller'] - var vm = 'vm' + num - var ret = [ - 'if(!vnodes' + num + '.vm){ vnodes' + num + '.vm = __vmodel__}', - '__vmodel__ = vnodes' + num + '.vm || __vmodel__', - 'vnode' + num + '.props["ms-controller"] = ' + id + ';', - 'var ' + vm + ' = avalon.vmodels[' + id + ']', - 'if(!' + vm + '){return }', - 'vnode' + num + '.bottom = ' + vm, - 'if(__vmodel__){', - 'vnode' + num + '.top = __vmodel__', - 'var __id__ = __vmodel__.$id+ "_" + ' + id, - "__vmodel__ = avalon.caches[__id__] || (avalon.caches[__id__] = avalon.mediatorFactory(__vmodel__," + vm + '))', - 'vnode' + num + '.mediator = __vmodel__', - '}else{', - '__vmodel__ = ' + vm, - '}', - 'if(!avalon.skipController(__fast__, vnode' + num + '.bottom)){ ' - ] - return ret.join('\n') + '\n' + var rmouseEvent = /^(?:mouse|contextmenu|drag)|click/ + var rvendor = /^(?:ms|webkit|moz)/ + function avEvent(event) { + if (event.originalEvent) { + return this + } + for (var i in event) { + if (!rvendor.test(i) && typeof event[i] !== 'function') { + this[i] = event[i] + } + } + if (!this.target) { + this.target = event.srcElement + } + var target = this.target + if (event.type.indexOf('key') === 0) { + this.which = event.charCode != null ? event.charCode : event.keyCode + } else if (rmouseEvent.test(event.type) && !('pageX' in this)) { + var doc = target.ownerDocument || document + var box = doc.compatMode === 'BackCompat' ? doc.body : doc.documentElement + this.pageX = event.clientX + (box.scrollLeft >> 0) - (box.clientLeft >> 0) + this.pageY = event.clientY + (box.scrollTop >> 0) - (box.clientTop >> 0) + this.wheelDeltaY = this.wheelDelta + this.wheelDeltaX = 0 + } + this.timeStamp = new Date() - 0 + this.originalEvent = event + } + avEvent.prototype = { + preventDefault: function () { + var e = this.originalEvent; + this.returnValue = false + if (e) { + e.returnValue = false + if (e.preventDefault) { + e.preventDefault() + } + } }, - diff: function (cur, pre, steps, name) { - if (pre.props[name] !== cur.props[name]) { - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 + stopPropagation: function () { + var e = this.originalEvent + this.cancelBubble = true + if (e) { + e.cancelBubble = true + if (e.stopPropagation) { + e.stopPropagation() } } }, - update: function (node, vnode) { - var top = vnode.top //位于上方的顶层vm或mediator vm - var bottom = vnode.bottom //位于下方的顶层vm - var mediator = vnode.mediator //新合成的mediator vm - if(!(top && bottom)){ - return + stopImmediatePropagation: function () { + var e = this.originalEvent + this.isImmediatePropagationStopped = true + if (e.stopImmediatePropagation) { + e.stopImmediatePropagation() } - bottom.$element = (top && top.$element) || node - vnode.top = vnode.mediator = vnode.bottom = 0 - if (!bottom.$render) { - var topRender = top.$render - if (!topRender.$id) { - topRender.$id = top.$id + this.stopPropagation() + } + } + + //针对firefox, chrome修正mouseenter, mouseleave + if (!('onmouseenter' in root)) { + avalon.each({ + mouseenter: 'mouseover', + mouseleave: 'mouseout' + }, function (origType, fixType) { + eventHooks[origType] = { + type: fixType, + fix: function (elem, fn) { + return function (e) { + var t = e.relatedTarget + if (!t || (t !== elem && !(elem.compareDocumentPosition(t) & 16))) { + delete e.type + e.type = origType + return fn.apply(this, arguments) + } + } } - function bottomRender() { - return topRender(0, bottomRender.$id) + } + }) + } + //针对IE9+, w3c修正animationend + avalon.each({ + AnimationEvent: 'animationend', + WebKitAnimationEvent: 'webkitAnimationEnd' + }, function (construct, fixType) { + if (window[construct] && !eventHooks.animationend) { + eventHooks.animationend = { + type: fixType + } + } + }) + //针对IE6-8修正input + if (!('oninput' in document.createElement('input'))) { + eventHooks.input = { + type: 'propertychange', + fix: function (elem, fn) { + return function (e) { + if (e.propertyName === 'value') { + e.type = 'input' + return fn.apply(this, arguments) + } } - bottom.$render = bottomRender - bottomRender.dom = bottom.$element //方便以后更换扫描起点 - bottomRender.$id = topRender.$id + ';;' + bottom.$id - if(mediator){ - mediator.$render = bottomRender + } + } + } + if (document.onmousewheel === void 0) { + /* IE6-11 chrome mousewheel wheelDetla 下 -120 上 120 + firefox DOMMouseScroll detail 下3 上-3 + firefox wheel detlaY 下3 上-3 + IE9-11 wheel deltaY 下40 上-40 + chrome wheel deltaY 下100 上-100 */ + var fixWheelType = document.onwheel !== void 0 ? 'wheel' : 'DOMMouseScroll' + var fixWheelDelta = fixWheelType === 'wheel' ? 'deltaY' : 'detail' + eventHooks.mousewheel = { + type: fixWheelType, + fix: function (elem, fn) { + return function (e) { + var delta = e[fixWheelDelta] > 0 ? -120 : 120 + e.wheelDelta = ~~elem._ms_wheel_ + delta + elem._ms_wheel_ = e.wheelDeltaY = e.wheelDelta + + e.wheelDeltaX = 0 + if (Object.defineProperty) { + Object.defineProperty(e, 'type', { + value: 'mousewheel' + }) + } + return fn.apply(this, arguments) } } } - }) + } + + avalon.fn.bind = function (type, fn, phase) { + if (this[0]) { //此方法不会链 + return avalon.bind(this[0], type, fn, phase) + } + } + + avalon.fn.unbind = function (type, fn, phase) { + if (this[0]) { + avalon.unbind(this[0], type, fn, phase) + } + return this + } + avalon.$$unbind = function (node) { + var nodes = node.getElementsByTagName('*') + //IE6-7这样取所有子孙节点会混入注释节点 + avalon.each(nodes, function (i, el) { + if (el.nodeType === 1 && el.getAttribute('avalon-events')) { + avalon.unbind(el) + } + }) + } /***/ }, -/* 44 */, -/* 45 */, -/* 46 */ +/* 32 */ /***/ function(module, exports) { - var propMap = {//不规则的属性名映射 - 'accept-charset': 'acceptCharset', - 'char': 'ch', - charoff: 'chOff', - 'class': 'className', - 'for': 'htmlFor', - 'http-equiv': 'httpEquiv' + //http://www.feiesoft.com/html/events.html + //http://segmentfault.com/q/1010000000687977/a-1020000000688757 + module.exports = { + click: true, + dblclick: true, + keydown: true, + keypress: true, + keyup: true, + mousedown: true, + mousemove: true, + mouseup: true, + mouseover: true, + mouseout: true, + wheel: true, + mousewheel: true, + input: true, + change: true, + beforeinput: true, + compositionstart: true, + compositionupdate: true, + compositionend: true, + select: true, + //http://blog.csdn.net/lee_magnum/article/details/17761441 + cut: true, + copy: true, + paste: true, + beforecut: true, + beforecopy: true, + beforepaste: true, + focusin: true, + focusout: true, + DOMFocusIn: true, + DOMFocusOut: true, + DOMActivate: true, + dragend: true, + datasetchanged: true } - /* - contenteditable不是布尔属性 - http://www.zhangxinxu.com/wordpress/2016/01/contenteditable-plaintext-only/ - contenteditable='' - contenteditable='events' - contenteditable='caret' - contenteditable='plaintext-only' - contenteditable='true' - contenteditable='false' - */ - var bools = ['autofocus,autoplay,async,allowTransparency,checked,controls', - 'declare,disabled,defer,defaultChecked,defaultSelected,', - 'isMap,loop,multiple,noHref,noResize,noShade', - 'open,readOnly,selected' - ].join(',') - bools.replace(/\w+/g, function (name) { - propMap[name.toLowerCase()] = name - }) +/***/ }, +/* 33 */ +/***/ function(module, exports, __webpack_require__) { - var anomaly = ['accessKey,bgColor,cellPadding,cellSpacing,codeBase,codeType,colSpan', - 'dateTime,defaultValue,contentEditable,frameBorder,longDesc,maxLength,'+ - 'marginWidth,marginHeight,rowSpan,tabIndex,useMap,vSpace,valueType,vAlign' - ].join(',') + var scan = __webpack_require__(34) - anomaly.replace(/\w+/g, function (name) { - propMap[name.toLowerCase()] = name + var document = avalon.document + var window = avalon.window + var root = avalon.root + + var readyList = [], isReady + var fireReady = function (fn) { + isReady = true + + while (fn = readyList.shift()) { + fn(avalon) + } + } + + function doScrollCheck() { + try { //IE下通过doScrollCheck检测DOM树是否建完 + root.doScroll('left') + fireReady() + } catch (e) { + setTimeout(doScrollCheck) + } + } + + if (document.readyState === 'complete') { + setTimeout(fireReady) //如果在domReady之外加载 + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', fireReady) + } else if (document.attachEvent) { + document.attachEvent('onreadystatechange', function () { + if (document.readyState === 'complete') { + fireReady() + } + }) + try { + var isTop = window.frameElement === null + } catch (e) { + } + if (root.doScroll && isTop && window.external) {//fix IE iframe BUG + doScrollCheck() + } + } + if (window.document) { + avalon.bind(window, 'load', fireReady) + } + avalon.ready = function (fn) { + if (!isReady) { + readyList.push(fn) + } else { + fn(avalon) + } + } + + avalon.ready(function(){ + scan(document.body) }) - module.exports = propMap /***/ }, -/* 47 */ +/* 34 */ /***/ function(module, exports) { - - - avalon.directive('css', { - parse: function (binding, num) { - return 'vnode' + num + '.props["ms-css"] = ' + avalon.parseExpr(binding) + ';\n' - }, - diff: function (cur, pre, steps, name) { - var a = cur.props[name] - var p = pre.props[name] - if ( Object(a) === a) { - if (Array.isArray(a)) { - a = cur.props[name] = avalon.mix.apply({}, a) - } - if (typeof p !== 'object') { - cur.changeStyle = a - } else { - var patch = {} - var hasChange = false - for (var i in a) { - if (a[i] !== p[i]) { - hasChange = true - patch[i] = a[i] - } - } - if (hasChange) { - cur.changeStyle = patch - } + var scanStatistics = 0 + function scan(nodes) { + for (var i = 0, elem; elem = nodes[i++]; ) { + if (elem.nodeType === 1) { + var $id = getController(elem) + if ($id) { + ++scanStatistics } - if (cur.changeStyle) { - var list = cur.change || (cur.change = []) - if(avalon.Array.ensure(list, this.update)){ - steps.count += 1 - } + var vm = avalon.vmodels[$id] + if (vm && !vm.$element) { + cleanWhitespace(elem)//减少虚拟DOM的规模及diff, patch的时间 + avalon(elem).removeClass('ms-controller') + vm.$element = elem + var now = new Date() + //IE6-8下元素的outerHTML前面会有空白 + elem.vtree = avalon.lexer(elem.outerHTML.trim()) + var now2 = new Date() + avalon.log('create primitive vtree', now2 - now) + vm.$render = avalon.render(elem.vtree) + var now3 = new Date() + avalon.log('create template Function ', now3 - now2) + avalon.rerenderStart = now3 + avalon.batch($id, true) + + } else if (!$id) { + scan(elem.childNodes) } - } else { - cur.props[name] = p - } - }, - update: function (node, vnode) { - var change = vnode.changeStyle - var wrap = avalon(node) - for (var name in change) { - wrap.css(name, change[name]) } - delete vnode.changeStyle } - }) - - -/***/ }, -/* 48 */ -/***/ function(module, exports) { - - - var none = 'none' - function parseDisplay(elem, val) { - //用于取得此类标签的默认display值 - var doc = elem.ownerDocument - var nodeName = elem.nodeName - var key = '_' + nodeName - if (!parseDisplay[key]) { - var temp = doc.body.appendChild(doc.createElement(nodeName)) - if (avalon.modern) { - val = getComputedStyle(temp, null).display - } else { - val = temp.currentStyle.display - } - doc.body.removeChild(temp) - if (val === none) { - val = 'block' + } + var notWhitespace = /\S/ + function cleanWhitespace(target) { + var keep + for (var i = 0; i < target.childNodes.length; i++) { + var node = target.childNodes[i] + if ((node.nodeType === 3) && (!notWhitespace.test(node.nodeValue))) { + keep = target.removeChild(node) + i-- + } else if (node.nodeType === 1) { + cleanWhitespace(node) } - parseDisplay[key] = val } - return parseDisplay[key] + if (target.childNodes.length === 0 && keep) { + target.appendChild(keep) + } + } + module.exports = avalon.scan = function (a) { + if (!a || !a.nodeType) { + avalon.warn('[avalon.scan] first argument must be element , documentFragment, or document') + return + } + scan([a]) + if (scanStatistics === 0) { + avalon.warn('[avalon.scan] your nodes must has "ms-controller" attribute') + } + scanStatistics = 0 } - avalon.parseDisplay = parseDisplay + function getController(a) { + return a.getAttribute('ms-controller') + } - avalon.directive('visible', { - parse: function (binding, num) { - return 'vnode' + num + '.props["ms-visible"] = ' + avalon.parseExpr(binding) + ';\n' - }, - diff: function (cur, pre, steps, name) { - var c = cur.props[name] = !!cur.props[name] - cur.displayValue = pre.displayValue - if (c !== pre.props[name]) { - var list = cur.change || (cur.change = []) - if(avalon.Array.ensure(list, this.update)){ - steps.count += 1 - } - } - }, - update: function (node, vnode) { - var show = vnode.props['ms-visible'] - var display = node.style.display - var value - if (show) { - if (display === none) { - value = vnode.displayValue - if (!value) { - node.style.display = '' - } - } - if (node.style.display === '' && avalon(node).css('display') === none && - // fix firefox BUG,必须挂到页面上 - avalon.contains(node.ownerDocument, node)) { +/***/ }, +/* 35 */ +/***/ function(module, exports, __webpack_require__) { - value = parseDisplay(node) - } - } else { - if (display !== none) { - value = none - vnode.displayValue = display - } - } - function cb(){ - if (value !== void 0) { - node.style.display = value - } - } - avalon.applyEffect(node, vnode, { - hook: show ? 'onEnterDone': 'onLeaveDone', - cb: cb - }) - } - }) + __webpack_require__(36) + __webpack_require__(44) + //处理属性样式 + __webpack_require__(45) + __webpack_require__(48) + __webpack_require__(49) + //处理内容 + __webpack_require__(50) + __webpack_require__(51) + __webpack_require__(52) + //需要用到事件的 + __webpack_require__(53) + __webpack_require__(54) + __webpack_require__(55) + __webpack_require__(62) + __webpack_require__(63) + //处理逻辑 + __webpack_require__(64) + __webpack_require__(66) + __webpack_require__(67) + __webpack_require__(69) + //优先级 ms-important, ms-controller, ms-for, ms-widget, ms-effect, ms-if + //....... + //ms-duplex /***/ }, -/* 49 */, -/* 50 */ +/* 36 */ /***/ function(module, exports, __webpack_require__) { - var rident = __webpack_require__(40).ident - avalon.directive('text', { - parse: function (binding, num, vnode) { - vnode.children = [{type: '#text', nodeType: 3, nodeValue: ''}] - var val = rident.test(binding.expr) ? binding.expr : avalon.parseExpr(binding) - return 'vnode' + num + '.props["ms-text"] =' + val + '\n' + var parseView = __webpack_require__(37) + var update = __webpack_require__(43) + + avalon.important = function (elem, vid) { + //如果vmodel还不存在,直接返回 + var wid = elem.props.wid + var vm = avalon.vmodels[vid] + if(!vm){ + return elem + }else if (typeof avalon.caches[wid] === 'string') { + var body = avalon.caches[wid] + //生成模板函数,并进行相关缓存 + body = '__vmodel__ = avalon.vmodels[' + + avalon.quote(vid) + ']\n' + body + var render = Function('__vmodel__', body) + var child = render() + elem = avalon.caches[wid] = child[0] + elem.order = 'ms-important' + elem.skipAttrs = false + elem.props['ms-important'] = vid + elem.render = render + return elem + } else { + elem = avalon.caches[wid] + elem.skipAttrs = elem.skipContent = true + return elem + } + } + avalon.directive("important", { + priority: 1, + parse: function (binding, num, elem) { + delete elem.props['ms-important'] + var wid = elem.props.wid || (elem.props.wid = avalon.makeHashCode('w')) + var fn = parseView([elem], num) + '\n\nreturn vnodes' + num + //将渲染函数的某一部分存起来,渲在c方法中转换为函数 + avalon.caches[wid] = fn + elem.isVoidTag = true + return ['vnode' + num + '.props.wid = ' + avalon.quote(wid), + 'vnode' + num + ' = avalon.important(vnode' + num + ',' + + avalon.quote(binding.expr) + ')'].join('\n') + '\n' + }, diff: function (cur, pre, steps, name) { - var curValue = cur.props[name] - var preValue = pre.props[name] - cur.children = pre.children - cur.skipContent = true - var dom = cur.dom = pre.dom - if (curValue !== preValue) { - if (!cur.children[0]) cur.children[0] = {type:"#text",nodeType:3} - cur.children[0].nodeValue = curValue - if (dom) { - this.update(dom, cur) - } else { - var list = cur.change || (cur.change = []) - if(avalon.Array.ensure(list, this.update)){ - steps.count += 1 - } - } + if (pre.props[name] !== cur.props[name]) { + update(cur, this.update, steps, 'important' ) } - pre.dom = null - return false }, update: function (node, vnode) { - var nodeValue = vnode.props['ms-text'] - if ('textContent' in node) { - node.textContent = nodeValue + '' - } else { - node.innerText = nodeValue + '' - } - vnode.dom = node + var vid = vnode.props['ms-important'] + var vm = avalon.vmodels[vid] + vm.$render = vnode.render + vm.$element = node } }) + + /***/ }, -/* 51 */ -/***/ function(module, exports) { +/* 37 */ +/***/ function(module, exports, __webpack_require__) { - avalon.directive('html', { - parse: function (binding, num,el) { - var isVoidTag = !!el.isVoidTag - el.isVoidTag = false - var ret = ["var htmlId = " + avalon.parseExpr(binding), - 'vnode' + num + '.props["ms-html"] = htmlId;', - 'vnode' + num + '._isVoidTag = '+isVoidTag, - 'var obj = avalon.htmlFactory(htmlId,' + num + ');', - 'try{eval(" new function(){"+ obj.render +"}")}catch(e){};', - 'vnode' + num + '.children = avalon.__html;'] - return ret.join('\n')+'\n' - }, - diff: function (cur, pre, steps, name) { - var curValue = cur.props[name] - var preValue = pre.props[name] - cur.isVoidTag = cur._isVoidTag - if (curValue !== preValue) { - if (cur.props[name] !== preValue) { - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 + + var parseExpr = __webpack_require__(38) + var parseBindings = __webpack_require__(41) + var parseDelimiter = __webpack_require__(42) + var rexpr = avalon.config.rexpr + var quote = avalon.quote + var makeHashCode = avalon.makeHashCode + var r = __webpack_require__(40) + var rident = r.ident + var rsp = r.sp + function wrapDelimiter(expr) { + return rident.test(expr) ? expr : parseExpr(expr, 'text') + } + + function wrap(a, num) { + return '(function(){\n\n' + a + '\n\nreturn vnodes' + num + '\n})();\n' + } + + var rmsFor = /^\s*ms\-for:/ + var rmsForEnd = /^\s*ms\-for\-end:/ + + function parseView(arr, num, scan) { + num = num || String(new Date - 0).slice(0, 5) + + var forstack = [] + var hasIf = false + var children = 'vnodes' + num + var vnode = 'vnode' + num + var str = 'var ' + children + ' = []\n' + for (var i = 0; i < arr.length; i++) { + var el = arr[i] + if (el.nodeType === 3) { + str += 'var ' + vnode + ' = {type:"#text",nodeType:3,skipContent:true}\n' + var hasDelimiter = rexpr.test(el.nodeValue) + + if (hasDelimiter) { + var array = parseDelimiter(el.nodeValue) + if (array.length === 1) { + var a = parseExpr(array[0].expr) + str += vnode + '.nodeValue = ' + wrapDelimiter(array[0].expr) + '\n' + } else { + a = array.map(function (el) { + return el.type ? wrapDelimiter(el.expr) : quote(el.expr) + }).join(' + ') + str += vnode + '.nodeValue = String(' + a + ')\n' + } + str += vnode + '.fixIESkip = true\n' + /* jshint ignore:start */ + str += vnode + '.skipContent = false\n' + } else { + if (rsp.test(el.nodeValue)) { + str += vnode + '.nodeValue = "\\n"\n' + } else { + str += vnode + '.nodeValue = ' + quote(el.nodeValue) + '\n' } } - } - }, - update: function (node, vnode) { - if (node.nodeType !== 1) { - return - } - //添加节点 - avalon.clearHTML(node) - var fragment = document.createDocumentFragment() - vnode.children.forEach(function (c) { - c && fragment.appendChild(avalon.vdomAdaptor(c, 'toDOM')) - }) - node.appendChild(fragment) - } - }) + str += children + '.push(' + vnode + ')\n' + continue + } else if (el.nodeType === 8) { + var nodeValue = el.nodeValue + if (rmsFor.test(nodeValue)) {// 处理ms-for指令 + if (nodeValue.indexOf('ms-for:') !== 0) { + avalon.error('ms-for指令前不能有空格') + } + var signature = el.signature + forstack.push(signature) + str += '\nvar ' + signature + ' = {' + + '\n\tnodeType:8,' + + '\n\ttype:"#comment",' + + '\n\tvmodel:__vmodel__,' + + '\n\tdirective:"for",' + + '\n\tskipContent:false,' + + '\n\tcid:' + quote(el.cid) + ',' + + '\n\tstart:' + children + '.length,' + + '\n\tsignature:' + quote(signature) + ',' + + '\n\ttemplate:' + quote(el.template) + ',' + + '\n\tnodeValue:' + quote(nodeValue) + + '\n}\n' + str += children + '.push(' + signature + ')\n' + str += avalon.directives['for'].parse(el, num) -/***/ }, -/* 52 */ -/***/ function(module, exports, __webpack_require__) { + } else if (rmsForEnd.test(nodeValue)) { + var signature = forstack[forstack.length - 1] + if (nodeValue.indexOf('ms-for-end:') !== 0) { + avalon.error('ms-for-end指令前不能有空格') + } + str += children + '.push({' + + '\n\tnodeType: 8,' + + '\n\ttype:"#comment",' + + '\n\tskipContent: true,' + + '\n\tnodeValue:' + quote(signature) + ',' + + '\n\tkey:traceKey\n})\n' + str += '\n})\n' //结束循环 + if (forstack.length) { + var signature = forstack[forstack.length - 1] + str += signature + '.end =' + children + '.push({' + + '\n\tnodeType: 8,' + + '\n\ttype:"#comment",' + + '\n\tskipContent: true,' + + '\n\tsignature: ' + quote(signature) + ',' + + '\n\tnodeValue: "ms-for-end:"' + + '\n})\n' + forstack.pop() + } + } else if (nodeValue.indexOf('ms-js:') === 0) {//插入普通JS代码 + str += parseExpr(nodeValue.replace('ms-js:', ''), 'js') + '\n' + } else { + str += children + '.push(' + quote(el) + ')\n\n\n' + } + continue + } else { //处理元素节点 - //根据VM的属性值或表达式的值切换类名,ms-class='xxx yyy zzz:flag' - //http://www.cnblogs.com/rubylouvre/archive/2012/12/17/2818540.html - var markID = __webpack_require__(6).getLongID + str += 'var ' + vnode + ' = {' + + '\n\tnodeType:1,' + + '\n\ttype: ' + quote(el.type) + ',' + + '\n\tprops:{},' + + '\n\tchildren: [],' + + '\n\tisVoidTag: ' + !!el.isVoidTag + ',' + + '\n\ttemplate: ""}\n' - var directives = avalon.directives - avalon.directive('class', { - parse: function (binding, num) { - //必须是布尔对象或字符串数组 - return 'vnode' + num + '.props["' + binding.name + '"] = ' + avalon.parseExpr(binding) + ';\n' - }, - diff: function (cur, pre, steps, name) { - var type = name.slice(3) - var curValue = cur.props[name] - var preValue = pre.props[name] - if (!pre.classEvent) { - var classEvent = {} - if (type === 'hover') {//在移出移入时切换类名 - classEvent.mouseenter = activateClass - classEvent.mouseleave = abandonClass - } else if (type === 'active') {//在获得焦点时切换类名 - cur.props.tabindex = cur.props.tabindex || -1 - classEvent.tabIndex = cur.props.tabindex - classEvent.mousedown = activateClass - classEvent.mouseup = abandonClass - classEvent.mouseleave = abandonClass + var hasWidget = el.props['ms-widget'] + if (!hasWidget && el.type.indexOf('-') > 0 && !el.props.resolved) { + el.props['ms-widget'] = '@' + el.type.replace(/-/g, "_") } - cur.classEvent = classEvent - } else { - cur.classEvent = pre.classEvent - } - pre.classEvent = null + var hasBindings = '' + var vmID = el.props['ms-controller'] - var className = avalon.noop - if (Array.isArray(curValue)) { - //处理复杂的一维数组 - className = curValue.map(function(el){ - return el && typeof el === 'object' ? processBooleanObject(el) : - el ? el : '' - }).join(' ') - } else if (avalon.isObject(curValue)) { - //处理布尔对象 - className = processBooleanObject(curValue) - } else if (curValue) { - //处理其他真值,如字符串,数字 - className = String(curValue) - } - if(className === avalon.noop){ - return - } - className = cur.props[name] = className.trim().replace(/\s+/, ' ') - if (!preValue || preValue !== className) { - cur['change-' + type] = className - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 + hasBindings = parseBindings(el.props, num, el) + if (hasBindings) { + str += hasBindings } - } - }, - update: function (node, vnode) { - var classEvent = vnode.classEvent - if (classEvent) { - for (var i in classEvent) { - if (i === 'tabIndex') { - node[i] = classEvent[i] + if (!el.isVoidTag) { + if (el.children.length) { + var hasIf = el.props['ms-if'] + if (hasIf) { + str += 'if(' + vnode + '&&' + vnode + '.nodeType === 1 ){\n' + } + str += vnode + '.children = ' + wrap(parseView(el.children, num), num) + '\n' + if (hasIf) { + str += '}\n' + } } else { - avalon.bind(node, i, classEvent[i]) + str += vnode + '.template = ' + quote(el.template) + '\n' } } - vnode.classEvent = {} - } - var names = ['class', 'hover', 'active'] - names.forEach(function (type) { - var name = 'change-' + type - var value = vnode[ name ] - if (value === void 0) - return - if (type === 'class') { - setClass(node, vnode) - } else { - var oldType = node.getAttribute('change-'+type) - if (oldType) { - avalon(node).removeClass(oldType) - } - node.setAttribute(name, value) + str += children + '.push(' + vnode + ')\n' + if (vmID) {//闭合ms-controller指令中avalon.skipController分支 + str += '}' } - }) + } + } - }) + return str + } + avalon.htmlFactory = function (str, num) { + var vtree = avalon.lexer(str + "") + avalon.__html = [] + var render = parseView(vtree, num) + '\nreturn (avalon.__html = vnodes' + num + ')' + return { + render: render + } + } - directives.active = directives.hover = directives['class'] + module.exports = parseView - function processBooleanObject(obj) { - return Object.keys(obj).filter(function (name) { - return obj[name] - }).join(' ') - } +/***/ }, +/* 38 */ +/***/ function(module, exports, __webpack_require__) { - var classMap = { - mouseenter: 'change-hover', - mouseleave: 'change-hover', - mousedown: 'change-active', - mouseup: 'change-active' - } + - function activateClass(e) { - var elem = e.target - avalon(elem).addClass(elem.getAttribute(classMap[e.type]) || '') + //缓存求值函数,以便多次利用 + var evaluatorPool = __webpack_require__(39) + + var rregexp = /(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\\\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/g + var rstring = __webpack_require__(40).string + var rfill = /\?\?\d+/g + var brackets = /\(([^)]*)\)/ + var rAt = /(^|[^\w\u00c0-\uFFFF_])(@|#)(?=\w)/g + var rhandleName = /^(?:\@|\#)[$\w]+$/ + var rshortCircuit = /\|\|/g + var rpipeline = /\|(?=\w)/ + var ruselessSp = /\s*(\.|\|)\s*/g + var wrapDuplex = function(arr){ + return '(function(){ return ' +arr.join('\n')+'})();\n' } + function parseExpr(str, category) { - function abandonClass(e) { - var elem = e.target - var name = classMap[e.type] - avalon(elem).removeClass(elem.getAttribute(name) || '') - if (name !== 'change-active') { - avalon(elem).removeClass(elem.getAttribute('change-active') || '') + var binding = {} + category = category || 'other' + if (typeof str === 'object') { + category = str.type + binding = str + str = binding.expr } - } + if (typeof str !== 'string') + return '' + var cacheID = str + var cacheStr = evaluatorPool.get(category + ':' + cacheID) - function setClass(node, vnode) { - var old = node.getAttribute('old-change-class') || '' - var neo = vnode.props['ms-class'] - avalon(node).removeClass(old).addClass(neo) - node.setAttribute('old-change-class', neo) - } + if (cacheStr) { + return cacheStr + } - markID(activateClass) - markID(abandonClass) + var number = 1 + //相同的表达式生成相同的函数 + var maps = {} + function dig(a) { + var key = '??' + number++ + maps[key] = a + return key + } + function fill(a) { + return maps[a] + } + var input = str.replace(rregexp, dig).//移除所有正则 + replace(rstring, dig).//移除所有字符串 + replace(rshortCircuit, dig).//移除所有短路或 + replace(ruselessSp, '$1').//移除. |两端空白 + split(rpipeline) //使用管道符分离所有过滤器及表达式的正体 + //还原body + var body = input.shift().replace(rfill, fill).trim() + if (category === 'on' && rhandleName.test(body)) { + body = body + '($event)' + } -/***/ }, -/* 53 */ -/***/ function(module, exports, __webpack_require__) { + body = body.replace(rAt, '$1__vmodel__.') + if (category === 'js') { + return evaluatorPool.put(category + ':' + cacheID, body) + } - var markID = __webpack_require__(6).getLongID - var Cache = __webpack_require__(26) - var eventCache = new Cache(128) - var quote = avalon.quote + //处理表达式的过滤器部分 - //Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes - // The assumption is that future DOM event attribute names will begin with - // 'on' and be composed of only English letters. - var revent = /^ms-on-([a-z]+)/ - var rfilters = /\|.+/g - var rvar = /([@$]?\w+)/g - var rstring = __webpack_require__(40).string - //基于事件代理的高性能事件绑定 - avalon.directive('on', { - priority: 3000, - parse: function (binding, num) { - var vars = binding.expr.replace(rstring, ' ').replace(rfilters, '').match(rvar) - var canCache = vars.every(function (el) { - return el.charAt(0) === '@' || el.charAt(0) === '#' || el === '$event' + var filters = input.map(function (str) { + + str = str.replace(rfill, fill).replace(rAt, '$1__vmodel__.') //还原 + var hasBracket = false + str = str.replace(brackets, function (a, b) { + hasBracket = true + return /\S/.test(b) ? + '(__value__,' + b + ');' : + '(__value__);' }) - var vmDefine = 'vnode' + num + '.onVm = __vmodel__\n' - var pid = quote(binding.name) - - if (canCache) { - var key = binding.expr - var fn = eventCache.get(key) - if(!fn){ - var fn = Function('return ' + avalon.parseExpr(binding, 'on'))() - var uuid = markID(fn) - eventCache.put(key, fn) - } - avalon.eventListeners[uuid] = fn - return vmDefine + 'vnode' + num + '.props[' + pid + - '] = avalon.eventListeners.' + uuid + '\n' - } else {//如果闭包引用其他变量 - return vmDefine + 'vnode' + num + '.props[' + pid + - '] = ' + avalon.parseExpr(binding, 'on') + '\n' + if (!hasBracket) { + str += '(__value__);' } - }, - diff: function (cur, pre, steps, name) { - - var fn0 = cur.props[name] - var fn1 = (pre.props || {})[name] - if ( fn0 !== fn1 ) { - var match = name.match(revent) - var type = match[1] - var search = type + ':' + markID(fn0) - cur.addEvents = cur.addEvents || {} - cur.addEvents[search] = fn0 - - if (typeof fn1 === 'function') { - cur.removeEvents = cur.removeEvents || {} - cur.removeEvents[type + ':' + fn1.uuid] = fn1 - } - - var list = cur.change || (cur.change = []) - if(avalon.Array.ensure(list, this.update)){ - steps.count += 1 - } - + str = str.replace(/(\w+)/, 'avalon.__format__("$1")') + return '__value__ = ' + str + }) + var ret = [] + if (category === 'on') { + filters = filters.map(function (el) { + return el.replace(/__value__/g, '$event') + }) + if (filters.length) { + filters.push('if($event.$return){\n\treturn;\n}') } - }, - update: function (node, vnode) { - if(!node || node.nodeType > 1) //在循环绑定中,这里为null - return - var key, type, listener - node._ms_context_ = vnode.onVm - delete vnode.onVm - for (key in vnode.removeEvents) { - type = key.split(':').shift() - listener = vnode.removeEvents[key] - avalon.unbind(node, type, listener) + if(!avalon.modern){ + body = body.replace(/__vmodel__\.([^(]+)\(([^)]*)\)/,function(a, b, c){ + return '__vmodel__.'+b+".call(__vmodel__"+ (/\S/.test(c) ? ','+c: "")+")" + }) } - delete vnode.removeEvents - for (key in vnode.addEvents) { - type = key.split(':').shift() - listener = vnode.addEvents[key] - avalon.bind(node, type, listener) + ret = ['function self($event){', + 'try{', + '\tvar __vmodel__ = this;', + '\t' + body, + '}catch(e){', + quoteError(str, category), + '}', + '}'] + filters.unshift(2, 0) + } else if (category === 'duplex') { + + //从vm中得到当前属性的值 + var getterBody = [ + 'function (__vmodel__){', + 'try{', + 'return ' + body + '\n', + '}catch(e){', + quoteError(str, category), + '}', + '}'] + evaluatorPool.put('duplex:' + cacheID,wrapDuplex(getterBody)) + //给vm同步某个属性 + var setterBody = [ + 'function (__vmodel__,__value__){', + 'try{', + '\t' + body + ' = __value__', + '}catch(e){', + quoteError(str, category), + '}', + '}'] + evaluatorPool.put('duplex:set:' + cacheID, wrapDuplex(setterBody)) + //对某个值进行格式化 + if (input.length) { + var formatBody = [ + 'function (__vmodel__, __value__){', + 'try{', + filters.join('\n'), + 'return __value__\n', + '}catch(e){', + quoteError(str, category), + '}', + '}'] + evaluatorPool.put('duplex:format:' + cacheID, wrapDuplex(formatBody)) } - delete vnode.addEvents + return + } else { + ret = [ + '(function(){', + 'try{', + 'var __value__ = ' + body, + ( category === 'text'? + 'return __value__ == null ? "" :__value__': + 'return __value__'), + '}catch(e){', + quoteError(str, category), + '\treturn ""', + '}', + '})()' + ] + filters.unshift(3, 0) } - }) - + ret.splice.apply(ret, filters) + cacheStr = ret.join('\n') + evaluatorPool.put(category + ':' + cacheID, cacheStr) + return cacheStr + } + function quoteError(str, type) { + return '\tavalon.warn(e, ' + + avalon.quote('parse ' + type + ' binding【 ' + str + ' 】fail') + + ')' + } + module.exports = avalon.parseExpr = parseExpr /***/ }, -/* 54 */, -/* 55 */ -/***/ function(module, exports) { +/* 39 */ +/***/ function(module, exports, __webpack_require__) { - var valueHijack = false - try { //#272 IE9-IE11, firefox - var setters = {} - var aproto = HTMLInputElement.prototype - var bproto = HTMLTextAreaElement.prototype - function newSetter(value) { // jshint ignore:line - setters[this.tagName].call(this, value) - if (!this.caret && this._ms_field_) { - this._ms_field_.update.call(this) - } - } - var inputProto = HTMLInputElement.prototype - Object.getOwnPropertyNames(inputProto) //故意引发IE6-8等浏览器报错 - setters['INPUT'] = Object.getOwnPropertyDescriptor(aproto, 'value').set + + var Cache = __webpack_require__(26) + //缓存求值函数,以便多次利用 + module.exports = new Cache(512) - Object.defineProperty(aproto, 'value', { - set: newSetter - }) - setters['TEXTAREA'] = Object.getOwnPropertyDescriptor(bproto, 'value').set - Object.defineProperty(bproto, 'value', { - set: newSetter - }) - valueHijack = true - } catch (e) { - //在chrome 43中 ms-duplex终于不需要使用定时器实现双向绑定了 - // http://updates.html5rocks.com/2015/04/DOM-attributes-now-on-the-prototype - // https://docs.google.com/document/d/1jwA8mtClwxI-QJuHT7872Z0pxpZz8PBkf2bGAbsUtqs/edit?pli=1 - } - module.exports = valueHijack /***/ }, -/* 56 */ +/* 40 */ /***/ function(module, exports) { - var rchangeFilter = /\|\s*change\b/ - var rcheckedType = /^(?:checkbox|radio)$/ - var rdebounceFilter = /\|\s*debounce(?:\(([^)]+)\))?/ - var rnoduplexInput = /^(file|button|reset|submit|checkbox|radio|range)$/ + module.exports = { + ident: /^[$a-zA-Z_][$a-zA-Z0-9_]*$/, + sp: /^\s+$/, //全部都是空白, + leftSp: /^\s+/, //左边空白 + rightSp: /s+$/, //右边空白, + binding: /^ms-(\w+)-?(.*)/, //绑定属性, + string: /(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/g + } - function newField(binding, vnode) { - var expr = binding.expr - var etype = vnode.props.type - //处理数据转换器 - var ptype = binding.param - var isChecked = ptype === 'checked' +/***/ }, +/* 41 */ +/***/ function(module, exports, __webpack_require__) { - var field = vnode.field = { - parsers: [], - formatters: [], - modelValue: NaN, - viewValue: NaN, - validators: '', - parse: parse, - format: format - } - if (isChecked) { - if (rcheckedType.test(etype)) { - field.isChecked = true - field.type = 'radio' + var rneedQuote = /[W-]/ + var quote = avalon.quote + var directives = avalon.directives + var rbinding = __webpack_require__(40).binding + var eventMap = avalon.oneObject('animationend,blur,change,input,click,dblclick,focus,keydown,keypress,keyup,mousedown,mouseenter,mouseleave,mousemove,mouseout,mouseover,mouseup,scan,scroll,submit') + var keyMap = avalon.oneObject("break,case,catch,continue,debugger,default,delete,do,else,false," + + "finally,for,function,if,in,instanceof,new,null,return,switch,this," + + "throw,true,try,typeof,var,void,while,with," + /* 关键字*/ + "abstract,boolean,byte,char,class,const,double,enum,export,extends," + + "final,float,goto,implements,import,int,interface,long,native," + + "package,private,protected,public,short,static,super,synchronized," + + "throws,transient,volatile") + function parseBindings(props, num, elem) { + var bindings = [] + var skip = 'ms-skip' in props + var ret = '' + var uniq = {} + for (var i in props) { + var value = props[i], match + + if (!skip && (match = i.match(rbinding))) { + var type = match[1] + var param = match[2] || '' + var name = i + if (eventMap[type]) { + var order = parseFloat(param) || 0 + param = type + type = 'on' + } + name = 'ms-' + type + (param ? '-' + param : '') + if (i !== name) { + delete props[i] + props[name] = value + } + if (directives[type]) { + var binding = { + type: type, + param: param, + name: name, + expr: value, + priority: directives[type].priority || type.charCodeAt(0) * 100 + } + if (type === 'on') { + order = order || 0 + binding.name += '-' + order + binding.priority += param.charCodeAt(0) * 100 + order + } + if(!uniq[binding.name]){ + uniq[binding.name] = 1 + bindings.push(binding) + } + } } else { - ptype = null - } - } - var changed = vnode.props['data-duplex-changed'] - if (changed) { - var cid = changed+':cb' - if(!avalon.caches[cid]){ - var fn = Function('return '+ avalon.parseExpr(changed, 'on')) - avalon.caches[cid] = field.callback = fn() - }else{ - field.callback = avalon.caches[cid] + //IE6-8下关键字不能直接当做对象的键名,需要用引号括起来 + if (rneedQuote.test(i) || keyMap[i]) {//收集非绑定属性 + ret += 'vnode' + num + '.props[' + quote(i) + '] = ' + quote(value) + '\n' + } else { + ret += 'vnode' + num + '.props.' + i + ' = ' + quote(value) + '\n' + } } } - var parser = avalon.parsers[ptype] - if (parser) { - field.parsers.push(parser) - } - if (rchangeFilter.test(expr)) { - // expr = expr.replace(rchangeFilter, '') - if (rnoduplexInput.test(etype)) { - avalon.warn(etype + '不支持change过滤器') + + if (!bindings.length) { + ret += '\tvnode' + num + '.skipAttrs = true\n' + } else { + bindings.sort(byPriority) + ret += ('vnode' + num + '.order = "'+ bindings.map(function(a){ + return a.name + }).join(';;')+'"\n') + //优化处理ms-widget + var first = bindings[0] + var isWidget = first && first.type === 'widget' + if (isWidget) { + bindings.shift() + bindings.forEach(function (binding) { + ret += 'vnode' + num + '.props[' + quote(binding.name) + '] = ' + quote(binding.expr) + '\n' + }) + ret += directives['widget'].parse(first, num, elem) } else { - field.isChanged = true + bindings.forEach(function (binding) { + ret += directives[binding.type].parse(binding, num, elem) + }) } - } - var match = expr.match(rdebounceFilter) - if (match) { - // expr = expr.replace(rdebounceFilter, '') - if (!field.isChanged) { - field.debounceTime = parseInt(match[1], 10) || 300 - } - } - binding.expr = field.expr = expr.trim() - if (!/input|textarea|select/.test(vnode.type)) { - if ('contenteditable' in vnode.props) { - field.type = 'contenteditable' - } - } else if (!field.type) { - field.type = vnode.type === 'select' ? 'select' : - etype === 'checkbox' ? 'checkbox' : - etype === 'radio' ? 'radio' : - 'input' } - avalon.parseExpr(binding, 'duplex') - } + return ret - function parse(val) { - for (var i = 0, fn; fn = this.parsers[i++]; ) { - val = fn.call(this, val) - } - return val } - function format(val) { - var formatters = this.formatters - var index = formatters.length - while (index--) { - val = formatters[index](val) - } - return val + function byPriority(a, b) { + return a.priority - b.priority } - module.exports = newField - + module.exports = parseBindings /***/ }, -/* 57 */, -/* 58 */ -/***/ function(module, exports) { - - - /** - * ------------------------------------------------------------ - * refreshModel - * 在事件回调与value的setter中调用这些方法,来同步vm - * ------------------------------------------------------------ - */ - var refreshModel = { - input: function (prop) {//处理单个value值处理 - var field = this - prop = prop || 'value' - var viewValue = field.element[prop] - var rawValue = viewValue +/* 42 */ +/***/ function(module, exports, __webpack_require__) { - viewValue = field.format(viewValue) - //vm.aaa = '1234567890' - //处理 {{@aaa}} 这种格式化同步不一致的情况 - var val = field.parse(viewValue) - viewValue = val + '' + var rline = /\r?\n/g + var r = __webpack_require__(40) - if (val !== field.modelValue) { - field.set(field.vmodel, val) - callback(field) + function parseDelimiter(str) { + var tokens = [], + value, start = 0, + stop + do { + stop = str.indexOf(avalon.config.openTag, start) + if (stop === -1) { + break } - - if (rawValue !== viewValue) { - field.viewValue = viewValue - field.element[prop] = viewValue + value = str.slice(start, stop) + if (start === 0) { + value = value.replace(r.leftSp, '') } - - }, - radio: function () { - var field = this - if (field.isChecked) { - var val = field.modelValue = !field.modelValue - field.set(field.vmodel, val) - callback(field) - } else { - refreshModel.input.call(field) - } - }, - checkbox: function () { - var field = this - var array = field.modelValue - if (!Array.isArray(array)) { - avalon.warn('ms-duplex应用于checkbox上要对应一个数组') - array = [array] + if (value) { // {{ 左边的文本 + tokens.push({ + expr: value + }) } - var method = field.element.checked ? 'ensure' : 'remove' - if (array[method]) { - var val = field.parse(field.element.value) - array[method](val) - callback(field) + start = stop + avalon.config.openTag.length + stop = str.indexOf(avalon.config.closeTag, start) + if (stop === -1) { + break } - - }, - select: function () { - var field = this - var val = avalon(field.element).val() //字符串或字符串数组 - if (val + '' !== this.modelValue + '') { - if (Array.isArray(val)) { //转换布尔数组或其他 - val = val.map(function (v) { - return field.parse(v) - }) - } else { - val = field.parse(val) - } - field.modelValue = val - field.set(field.vmodel, val) - callback(field) + value = str.slice(start, stop) + if (value) { //处理{{ }}插值表达式 + tokens.push({ + expr: value.replace(rline, ''), + type: '{{}}' + }) } - }, - contenteditable: function () { - refreshModel.input.call(this, 'innerHTML') - } - } + start = stop + avalon.config.closeTag.length + } while (1) + value = str.slice(start) - function callback(field) { - if (field.validator) { - avalon.directives.validate.validate(field, false) - } - if (field.callback) { - field.callback.call(field.vmodel, { - type: 'changed', - target: field.element + var lastText = value.replace(r.rightSp, '') + if (lastText) { //}} 右边的文本 + tokens.push({ + expr: lastText }) } + return tokens } - module.exports = refreshModel + + module.exports = parseDelimiter + /***/ }, -/* 59 */, -/* 60 */ +/* 43 */ /***/ function(module, exports) { - - module.exports = function addField(node, vnode) { - var field = vnode.field - var rules = vnode.props['ms-rules'] - if (rules && !field.validator) { - while (node && node.nodeType === 1) { - var validator = node._ms_validator_ - if (validator) { - field.rules = rules - field.validator = validator - if(avalon.Array.ensure(validator.fields, field)){ - validator.addField(field) - } - break - } - node = node.parentNode - } + module.exports = function (cur, update, steps, type, hookName) { + hookName = hookName || 'change' + var list = cur[hookName] || (cur[hookName] = []) + if (avalon.Array.ensure(list, update)) { + steps.count += 1 + avalon.config.showDiff && avalon.log(type+ ' change') } } /***/ }, -/* 61 */ -/***/ function(module, exports) { +/* 44 */ +/***/ function(module, exports, __webpack_require__) { - var dir = avalon.directive('validate', { - //验证单个表单元素 - parse: function (binding, num) { - return 'vnode' + num + '.props["ms-validate"] = ' + avalon.parseExpr(binding) + ';\n' + // 抽离出来公用 + var update = __webpack_require__(43) + + avalon.skipController = function (fast, vm, iv) { + if (fast) { + var id = vm.$render ? vm.$render.$id : vm.$id + if (fast.length > id.length) { + return fast.indexOf(id + ';;') !== 0 + } + return id.indexOf(fast) !== 0 + } + return false + } + + avalon.directive('controller', { + priority: 2, + parse: function (binding, num, elem) { + var id = avalon.quote(binding.expr) + delete elem.props['ms-controller'] + var vm = 'vm' + num + var ret = [ + 'if(!vnodes' + num + '.vm){ vnodes' + num + '.vm = __vmodel__}', + '__vmodel__ = vnodes' + num + '.vm || __vmodel__', + 'vnode' + num + '.props["ms-controller"] = ' + id + ';', + 'var ' + vm + ' = avalon.vmodels[' + id + ']', + 'if(!' + vm + '){return }', + 'vnode' + num + '.bottom = ' + vm, + 'if(__vmodel__){', + 'vnode' + num + '.top = __vmodel__', + 'var __id__ = __vmodel__.$id+ "_" + ' + id, + "__vmodel__ = avalon.caches[__id__] || (avalon.caches[__id__] = avalon.mediatorFactory(__vmodel__," + vm + '))', + 'vnode' + num + '.mediator = __vmodel__', + '}else{', + '__vmodel__ = ' + vm, + '}', + 'if(!avalon.skipController(__fast__, vnode' + num + '.bottom)){ ' + ] + return ret.join('\n') + '\n' }, diff: function (cur, pre, steps, name) { - var validator = cur.props[name] - var p = pre.props[name] - if (p && p.onError && p.addField) { - cur.props[name] = p - } else if (Object(validator) === validator) { - if(validator.$id){//转换为普通对象 - validator = validator.$model - } - cur.props[name] = validator - for(var name in dir.defaults){ - if(!validator[name]){ - validator[name] = dir.defaults[name] - } - } - validator.fields = validator.fields || [] - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 - } + if (pre.props[name] !== cur.props[name]) { + console.log('controller',steps) + update(cur, this.update, steps, 'controller' ) } }, update: function (node, vnode) { - var validator = vnode.props['ms-validate'] - node._ms_validator_ = validator - validator.element = node - node.setAttribute("novalidate", "novalidate"); - if (validator.validateAllInSubmit) { - avalon.bind(node, "submit", function (e) { - e.preventDefault() - dir.validateAll.call(validator, validator.onValidateAll) - }) + var top = vnode.top //位于上方的顶层vm或mediator vm + var bottom = vnode.bottom //位于下方的顶层vm + var mediator = vnode.mediator //新合成的mediator vm + if(!(top && bottom)){ + return } - if (typeof validator.onInit === "function") { //vmodels是不包括vmodel的 - validator.onInit.call(node) + bottom.$element = (top && top.$element) || node + vnode.top = vnode.mediator = vnode.bottom = 0 + if (!bottom.$render) { + var topRender = top.$render + if (!topRender.$id) { + topRender.$id = top.$id + } + function bottomRender() { + return topRender(0, bottomRender.$id) + } + bottom.$render = bottomRender + bottomRender.dom = bottom.$element //方便以后更换扫描起点 + bottomRender.$id = topRender.$id + ';;' + bottom.$id + if(mediator){ + mediator.$render = bottomRender + } } + } + }) + +/***/ }, +/* 45 */ +/***/ function(module, exports, __webpack_require__) { + + + var attrUpdate = __webpack_require__(46) + var update = __webpack_require__(43) + + avalon.directive('attr', { + parse: function (binding, num) { + return 'vnode' + num + '.props["ms-attr"] = ' + avalon.parseExpr(binding) + ';\n' + }, - validateAll: function (callback) { - var validator = this - var fn = typeof callback === "function" ? callback : validator.onValidateAll - var promise = validator.fields.filter(function (field) { - var el = field.element - return el && !el.disabled && validator.element.contains(el) - }).map(function (field) { - return dir.validate(field, true) - }) - var reasons = [] - Promise.all(promise).then(function (array) { - for (var i = 0, el; el = array[i++]; ) { - reasons = reasons.concat(el) + diff: function (cur, pre, steps, name) { + var a = cur.props[name] + var p = pre.props[name] + if (a && typeof a === 'object') { + if (Array.isArray(a)) { + a = cur.props[name] = avalon.mix.apply({}, a) } - if (validator.deduplicateInValidateAll) { - var uniq = {} - reasons = reasons.filter(function (field) { - var el = field.element - var uuid = el.uniqueID || (el.uniqueID = setTimeout("1")) - if (uniq[uuid]) { - return false - } else { - uniq[uuid] = true - return true + if (typeof p !== 'object') { + cur.changeAttr = a + } else { + var patch = {} + var hasChange = false + for (var i in a) { + if (a[i] !== p[i]) { + hasChange = true + patch[i] = a[i] } - }) + } + if (hasChange) { + cur.changeAttr = patch + } } - fn.call(validator.element, reasons) //这里只放置未通过验证的组件 - }) - }, - addField: function (field) { - var validator = this - var node = field.element - if (validator.validateInKeyup && (!field.isChanged &&!field.debounceTime)) { - avalon.bind(node, 'keyup', function (e) { - dir.validate(field, 0, e) - }) - } - if (validator.validateInBlur) { - avalon.bind(node, 'blur', function (e) { - dir.validate(field, 0, e) - }) - } - if (validator.resetInFocus) { - avalon.bind(node, 'focus', function (e) { - validator.onReset.call(node, e, field) - }) + if (cur.changeAttr) { + update(cur, this.update, steps, 'attr' ) + } + } else { + cur.props[name] = p } + pre.changeAttr = null }, - validate: function (field, isValidateAll, event) { - var promises = [] - var value = field.get(field.vmodel) - var elem = field.element - var validator = field.validator - if (elem.disabled) - return - for (var ruleName in field.rules) { - var ruleValue = field.rules[ruleName] - if (ruleValue === false) - continue - var hook = avalon.validators[ruleName] - var resolve, reject - promises.push(new Promise(function (a, b) { - resolve = a - reject = b - })) - var next = function (a) { - if (field.norequired && value === "") { - a = true + //dom, vnode + update: attrUpdate + }) + + + +/***/ }, +/* 46 */ +/***/ function(module, exports, __webpack_require__) { + + + var propMap = __webpack_require__(47) + var isVML = __webpack_require__(29) + var rsvg =/^\[object SVG\w*Element\]$/ + var ramp = /&/g + + function attrUpdate(node, vnode) { + var attrs = vnode.changeAttr + if (!node || node.nodeType !== 1 ) { + return + } + if (attrs) { + for (var attrName in attrs) { + var val = attrs[attrName] + // 处理路径属性 + if (attrName === 'href' || attrName === 'src') { + if (!node.hasAttribute) { + val = String(val).replace(ramp, '&') //处理IE67自动转义的问题 } - if (a) { - resolve(true) - } else { - var reason = { - element: elem, - data: field.data, - message: elem.getAttribute("data-" + ruleName + "-message") || elem.getAttribute("data-message") || hook.message, - validateRule: ruleName, - getMessage: getMessage - } - resolve(reason) + node[attrName] = val + if (window.chrome && node.tagName === 'EMBED') { + var parent = node.parentNode //#525 chrome1-37下embed标签动态设置src不能发生请求 + var comment = document.createComment('ms-src') + parent.replaceChild(comment, node) + parent.replaceChild(node, comment) } - } - field.data = {} - field.data[ruleName] = ruleValue - hook.get(value, field, next) - } - var reasons = [] - //如果promises不为空,说明经过验证拦截器 - var lastPromise = Promise.all(promises).then(function (array) { - for (var i = 0, el; el = array[i++]; ) { - if (typeof el === "object") { - reasons.push(el) + //处理HTML5 data-*属性 + } else if (attrName.indexOf('data-') === 0) { + node.setAttribute(attrName, val) + + } else { + var propName = propMap[attrName] || attrName + if (typeof node[propName] === 'boolean') { + node[propName] = !!val + + //布尔属性必须使用el.xxx = true|false方式设值 + //如果为false, IE全系列下相当于setAttribute(xxx,''), + //会影响到样式,需要进一步处理 } - } - if (!isValidateAll) { - if (reasons.length) { - validator.onError.call(elem, reasons, event) + + if (val === false ) {//移除属性 + node.removeAttribute(propName) + continue + } + //SVG只能使用setAttribute(xxx, yyy), VML只能使用node.xxx = yyy , + //HTML的固有属性必须node.xxx = yyy + var isInnate = rsvg.test(node) ? false : + (document.namespaces && isVML(node)) ? true : + attrName in node.cloneNode(false) + if (isInnate) { + node[propName] = val + '' } else { - validator.onSuccess.call(elem, reasons, event) + node.setAttribute(attrName, val) } - validator.onComplete.call(elem, reasons, event) + } - return reasons - }) - return lastPromise + + } + vnode.changeAttr = null } - }) + } - var rformat = /\\?{{([^{}]+)\}}/gm + module.exports = attrUpdate - function getMessage() { - var data = this.data || {} - return this.message.replace(rformat, function (_, name) { - return data[name] == null ? "" : data[name] - }) - } - dir.defaults = { - addField: dir.addField, - onError: avalon.noop, - onSuccess: avalon.noop, - onComplete: avalon.noop, - onReset: avalon.noop, - validateInBlur: true, //@config {Boolean} true,在blur事件中进行验证,触发onSuccess, onError, onComplete回调 - validateInKeyup: true, //@config {Boolean} true,在keyup事件中进行验证,触发onSuccess, onError, onComplete回调 - validateAllInSubmit: true, //@config {Boolean} true,在submit事件中执行onValidateAll回调 - resetInFocus: true, //@config {Boolean} true,在focus事件中执行onReset回调, - deduplicateInValidateAll: false //@config {Boolean} false,在validateAll回调中对reason数组根据元素节点进行去重 +/***/ }, +/* 47 */ +/***/ function(module, exports) { + + var propMap = {//不规则的属性名映射 + 'accept-charset': 'acceptCharset', + 'char': 'ch', + charoff: 'chOff', + 'class': 'className', + 'for': 'htmlFor', + 'http-equiv': 'httpEquiv' } + /* + contenteditable不是布尔属性 + http://www.zhangxinxu.com/wordpress/2016/01/contenteditable-plaintext-only/ + contenteditable='' + contenteditable='events' + contenteditable='caret' + contenteditable='plaintext-only' + contenteditable='true' + contenteditable='false' + */ + var bools = ['autofocus,autoplay,async,allowTransparency,checked,controls', + 'declare,disabled,defer,defaultChecked,defaultSelected,', + 'isMap,loop,multiple,noHref,noResize,noShade', + 'open,readOnly,selected' + ].join(',') + + bools.replace(/\w+/g, function (name) { + propMap[name.toLowerCase()] = name + }) + + var anomaly = ['accessKey,bgColor,cellPadding,cellSpacing,codeBase,codeType,colSpan', + 'dateTime,defaultValue,contentEditable,frameBorder,longDesc,maxLength,'+ + 'marginWidth,marginHeight,rowSpan,tabIndex,useMap,vSpace,valueType,vAlign' + ].join(',') + + anomaly.replace(/\w+/g, function (name) { + propMap[name.toLowerCase()] = name + }) + + module.exports = propMap + /***/ }, -/* 62 */ -/***/ function(module, exports) { +/* 48 */ +/***/ function(module, exports, __webpack_require__) { - avalon.directive('rules', { + + var update = __webpack_require__(43) + + avalon.directive('css', { parse: function (binding, num) { - var rules = binding.expr - if (/{.+}/.test(rules)) { - return 'vnode' + num + '.props["ms-rules"] = ' + avalon.parseExpr(binding) + ';\n' + return 'vnode' + num + '.props["ms-css"] = ' + avalon.parseExpr(binding) + ';\n' + }, + diff: function (cur, pre, steps, name) { + var a = cur.props[name] + var p = pre.props[name] + if (Object(a) === a) { + if (Array.isArray(a)) { + a = cur.props[name] = avalon.mix.apply({}, a) + } + if (typeof p !== 'object') { + cur.changeStyle = a + } else { + var patch = {} + var hasChange = false + for (var i in a) { + if (a[i] !== p[i]) { + hasChange = true + patch[i] = a[i] + } + } + if (hasChange) { + cur.changeStyle = patch + } + } + if (cur.changeStyle) { + update(cur, this.update, steps, 'css') + } + } else { + cur.props[name] = p } }, - diff: avalon.noop + update: function (node, vnode) { + var change = vnode.changeStyle + var wrap = avalon(node) + for (var name in change) { + wrap.css(name, change[name]) + } + delete vnode.changeStyle + } }) - function isRegExp(value) { - return avalon.type(value) === 'regexp' - } - var rmail = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/i - var rurl = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/ - function isCorrectDate(value) { - if (typeof value === "string" && value) { //是字符串但不能是空字符 - var arr = value.split("-") //可以被-切成3份,并且第1个是4个字符 - if (arr.length === 3 && arr[0].length === 4) { - var year = ~~arr[0] //全部转换为非负整数 - var month = ~~arr[1] - 1 - var date = ~~arr[2] - var d = new Date(year, month, date) - return d.getFullYear() === year && d.getMonth() === month && d.getDate() === date + + +/***/ }, +/* 49 */ +/***/ function(module, exports, __webpack_require__) { + + var update = __webpack_require__(43) + + var none = 'none' + function parseDisplay(elem, val) { + //用于取得此类标签的默认display值 + var doc = elem.ownerDocument + var nodeName = elem.nodeName + var key = '_' + nodeName + if (!parseDisplay[key]) { + var temp = doc.body.appendChild(doc.createElement(nodeName)) + if (avalon.modern) { + val = getComputedStyle(temp, null).display + } else { + val = temp.currentStyle.display + } + doc.body.removeChild(temp) + if (val === none) { + val = 'block' } + parseDisplay[key] = val } - return false + return parseDisplay[key] } - avalon.shadowCopy(avalon.validators, { - pattern: { - message: '必须匹配{{pattern}}这样的格式', - get: function (value, field, next) { - var elem = field.element - var data = field.data - if (!isRegExp(data.pattern)) { - var h5pattern = elem.getAttribute("pattern") - data.pattern = new RegExp('^(?:' + h5pattern + ')$') - } - next(data.pattern.test(value)) - return value - } - }, - digits: { - message: '必须整数', - get: function (value, field, next) {//整数 - next(/^\-?\d+$/.test(value)) - return value - } + + avalon.parseDisplay = parseDisplay + + avalon.directive('visible', { + parse: function (binding, num) { + return 'vnode' + num + '.props["ms-visible"] = ' + avalon.parseExpr(binding) + ';\n' }, - number: { - message: '必须数字', - get: function (value, field, next) {//数值 - next(isFinite(value)) - return value + diff: function (cur, pre, steps, name) { + var c = cur.props[name] = !!cur.props[name] + cur.displayValue = pre.displayValue + if (c !== pre.props[name]) { + update(cur, this.update, steps, 'visible' ) } }, - required: { - message: '必须填写', - get: function (value, field, next) { - next(value !== "") - return value + update: function (node, vnode) { + var show = vnode.props['ms-visible'] + var display = node.style.display + var value + if (show) { + if (display === none) { + value = vnode.displayValue + if (!value) { + node.style.display = '' + } + } + if (node.style.display === '' && avalon(node).css('display') === none && + // fix firefox BUG,必须挂到页面上 + avalon.contains(node.ownerDocument, node)) { + + value = parseDisplay(node) + } + } else { + if (display !== none) { + value = none + vnode.displayValue = display + } } - }, - equalto: { - message: '密码输入不一致', - get: function (value, field, next) { - var id = String(field.data.equalto) - var other = avalon(document.getElementById(id)).val() || "" - next(value === other) - return value + function cb(){ + if (value !== void 0) { + node.style.display = value + } } + avalon.applyEffect(node, vnode, { + hook: show ? 'onEnterDone': 'onLeaveDone', + cb: cb + }) + } + }) + + + +/***/ }, +/* 50 */ +/***/ function(module, exports, __webpack_require__) { + + var update = __webpack_require__(43) + + avalon.directive('expr', { + parse: function () { }, - date: { - message: '日期格式不正确', - get: function (value, field, next) { - var data = field.data - if (avalon.type(data.date) === 'regexp') { - next(data.date.test(value)) + diff: function (cur, pre, steps) { + cur.fixIESkip = !avalon.modern + var dom = cur.dom = pre.dom + if (cur.nodeValue !== pre.nodeValue) { + if (dom && avalon.contains(avalon.root,dom)) { + this.update(dom, cur) } else { - next(isCorrectDate(value)) + update(cur, this.update, steps, 'expr' ) } - return value - } - }, - url: { - message: 'URL格式不正确', - get: function (value, field, next) { - next(rurl.test(value)) - return value - } - }, - email: { - message: 'email格式不正确', - get: function (value, field, next) { - next(rmail.test(value)) - return value - } - }, - minlength: { - message: '最少输入{{minlength}}个字', - get: function (value, field, next) { - var num = parseInt(field.data.minlength, 10) - next(value.length >= num) - return value - } - }, - maxlength: { - message: '最多输入{{maxlength}}个字', - get: function (value, field, next) { - var num = parseInt(field.data.maxlength, 10) - next(value.length <= num) - return value - } - }, - min: { - message: '输入值不能小于{{min}}', - get: function (value, field, next) { - var num = parseInt(field.data.min, 10) - next(parseFloat(value) >= num) - return value - } - }, - max: { - message: '输入值不能大于{{max}}', - get: function (value, field, next) { - var num = parseInt(field.data.max, 10) - next(parseFloat(value) <= num) - return value } + pre.dom = null }, - chs: { - message: '必须是中文字符', - get: function (value, field, next) { - next(/^[\u4e00-\u9fa5]+$/.test(value)) - return value + update: function (node, vnode, parent) { + if (node.nodeType !== 3) { + var textNode = document.createTextNode(vnode.nodeValue) + parent.replaceChild(textNode, node) + } else { + + node.nodeValue = vnode.nodeValue + textNode = node } + vnode.dom = textNode } }) /***/ }, -/* 63 */ +/* 51 */ /***/ function(module, exports, __webpack_require__) { - var patch = __webpack_require__(64) - var uniqueID = 1 - //ms-imporant ms-controller ms-for ms-widget ms-effect ms-if ... - avalon.directive('if', { - priority: 6, - parse: function (binding, num) { - var vnode = 'vnode' + num - var ret = [ - 'var ifVar = ' + avalon.parseExpr(binding, 'if'), - vnode + '.props["ms-if"] = ifVar;', - 'if(!ifVar){', - vnode + '.nodeType = 8;', - vnode + '.directive="if";', - vnode + '.nodeValue="ms-if"', '}' - ] - return ret.join('\n') + '\n' + var rident = __webpack_require__(40).ident + var update = __webpack_require__(43) + + avalon.directive('text', { + parse: function (binding, num, vnode) { + vnode.children = [{type: '#text', nodeType: 3, nodeValue: ''}] + var val = rident.test(binding.expr) ? binding.expr : avalon.parseExpr(binding) + return 'vnode' + num + '.props["ms-text"] =' + val + '\n' }, - diff: function (cur, pre, steps) { - cur.dom = pre.dom - if (cur.nodeType !== pre.nodeType) { - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 - cur.steps = steps + diff: function (cur, pre, steps, name) { + var curValue = cur.props[name] + var preValue = pre.props[name] + cur.children = pre.children + cur.skipContent = true + var dom = cur.dom = pre.dom + if (curValue !== preValue) { + if (!cur.children[0]) cur.children[0] = {type:"#text",nodeType:3} + cur.children[0].nodeValue = curValue + if (dom) { + this.update(dom, cur) + } else { + update(cur, this.update, steps, 'text' ) } } + pre.dom = null + return false }, - update: function (node, vnode, parent) { - var dtype = node.nodeType - var vtype = vnode.nodeType - if (dtype !== vtype) { - if (vtype === 1) { - //要插入元素节点,将原位置上的注释节点移除并cache - var element = vnode.dom - if (!element) { - element = avalon.vdomAdaptor(vnode, 'toDOM') - vnode.dom = element - var props = vnode.props - for (var prop in props) {//如果一开始是隐藏,那么事件会没有绑上 - if (prop.match(/ms\-on/g)) { - var fun = props[prop] - if (typeof fun === 'function') { - element._ms_context_ = vnode.onVm - avalon.bind(element, prop.split('-')[2], fun) - } - } - } - if (vnode.onVm) delete vnode.onVm - } - parent.replaceChild(element, node) - if (vnode.steps.count) { - patch([element], [vnode], parent, vnode.steps) - } - avalon.applyEffect(node, vnode, { - hook: 'onEnterDone' - }) - return (vnode.steps = false) - } else if (vtype === 8) { - //要移除元素节点,在对应位置上插入注释节点 - avalon.applyEffect(node, vnode, { - hook: 'onLeaveDone', - cb: function () { - var comment = node._ms_if_ || - (node._ms_if_ = document.createComment(vnode.nodeValue)) - - parent.replaceChild(comment, node) - } - }) - } + update: function (node, vnode) { + var nodeValue = vnode.props['ms-text'] + if ('textContent' in node) { + node.textContent = nodeValue + '' + } else { + node.innerText = nodeValue + '' } + vnode.dom = node } }) - - /***/ }, -/* 64 */ -/***/ function(module, exports) { +/* 52 */ +/***/ function(module, exports, __webpack_require__) { - /** - * ------------------------------------------------------------ - * patch 对某一个视图根据对应的虚拟DOM树进行全量更新 - * ------------------------------------------------------------ - */ - var sp = /^\s*$/ - function patch(nodes, vnodes, parent, steps) { - var next = nodes[0] - if ((!next && !parent) || !steps.count) { - return - } - parent = parent || next.parentNode - for (var i = 0, vn = vnodes.length; i < vn; i++) { - var vnode = vnodes[i] - var node = next - //IE6-8不会生成空白的文本节点,造成虚拟DOM与真实DOM的个数不一致,需要跳过,#1333 - if (avalon.msie < 9 && !vnode.fixIESkip && vnode.nodeType === 3 && sp.test(vnode.nodeValue) ) { - continue - } + var update = __webpack_require__(43) - if (node) { - next = node.nextSibling + avalon.directive('html', { + parse: function (binding, num,el) { + var isVoidTag = !!el.isVoidTag + el.isVoidTag = false + var ret = ["var htmlId = " + avalon.parseExpr(binding), + 'vnode' + num + '.props["ms-html"] = htmlId;', + 'vnode' + num + '._isVoidTag = '+isVoidTag, + 'var obj = avalon.htmlFactory(htmlId,' + num + ');', + 'try{eval(" new function(){"+ obj.render +"}")}catch(e){};', + 'vnode' + num + '.children = avalon.__html;'] + return ret.join('\n')+'\n' + }, + diff: function (cur, pre, steps, name) { + var curValue = cur.props[name] + var preValue = pre.props[name] + cur.isVoidTag = cur._isVoidTag + if (curValue !== preValue) { + update(cur, this.update, steps, 'html' ) } - if (vnode.directive === 'for') { - if (vnode.change) { - if (!node) { - return - } - if (node.nodeType === 1) { - var startRepeat = document.createComment(vnode.nodeValue) - parent.insertBefore(startRepeat, node) - vnode.endRepeat = document.createComment('ms-for-end:') - parent.insertBefore(vnode.endRepeat, node.nextSibling) - node = startRepeat - } else {//如果是注释节点 - if (!vnode.endRepeat) { - vnode.endRepeat = getEndRepeat(node) - } - } - if(node.nodeType !== 8){//fix IE6-8 - node = node.nextSibling - } - next = vnode.endRepeat.nextSibling - } - + }, + update: function (node, vnode) { + if (node.nodeType !== 1) { + return } + //添加节点 + avalon.clearHTML(node) + var fragment = document.createDocumentFragment() + vnode.children.forEach(function (c) { + c && fragment.appendChild(avalon.vdomAdaptor(c, 'toDOM')) + }) + node.appendChild(fragment) + } + }) - //ms-for, ms-if, ms-widget会返回false - if (false === execHooks(node, vnode, parent, steps, 'change')) { - if (vnode.repeatCount) { - i += vnode.repeatCount + 1 //修正索引值 + +/***/ }, +/* 53 */ +/***/ function(module, exports, __webpack_require__) { + + //根据VM的属性值或表达式的值切换类名,ms-class='xxx yyy zzz:flag' + //http://www.cnblogs.com/rubylouvre/archive/2012/12/17/2818540.html + var markID = __webpack_require__(6).getLongID + var update = __webpack_require__(43) + + var directives = avalon.directives + avalon.directive('class', { + parse: function (binding, num) { + //必须是布尔对象或字符串数组 + return 'vnode' + num + '.props["' + binding.name + '"] = ' + avalon.parseExpr(binding) + ';\n' + }, + diff: function (cur, pre, steps, name) { + var type = name.slice(3) + var curValue = cur.props[name] + var preValue = pre.props[name] + if (!pre.classEvent) { + var classEvent = {} + if (type === 'hover') {//在移出移入时切换类名 + classEvent.mouseenter = activateClass + classEvent.mouseleave = abandonClass + } else if (type === 'active') {//在获得焦点时切换类名 + cur.props.tabindex = cur.props.tabindex || -1 + classEvent.tabIndex = cur.props.tabindex + classEvent.mousedown = activateClass + classEvent.mouseup = abandonClass + classEvent.mouseleave = abandonClass } - execHooks(node, vnode, parent, steps, 'afterChange') - continue + cur.classEvent = classEvent + } else { + cur.classEvent = pre.classEvent } - if (!vnode.skipContent && vnode.children && node && node.nodeType === 1) { - //处理子节点 - patch(avalon.slice(node.childNodes), vnode.children, node, steps) + pre.classEvent = null + + var className = avalon.noop + if (Array.isArray(curValue)) { + //处理复杂的一维数组 + className = curValue.map(function(el){ + return el && typeof el === 'object' ? processBooleanObject(el) : + el ? el : '' + }).join(' ') + } else if (avalon.isObject(curValue)) { + //处理布尔对象 + className = processBooleanObject(curValue) + } else if (curValue) { + //处理其他真值,如字符串,数字 + className = String(curValue) } - // ms-if=false内的ms-controller无法正确的关联dom - var vmID = vnode.props && vnode.props['ms-controller'] - if (vmID && node) { - var vm = avalon.vmodels[vmID] - if (vm.$render) vm.$render.dom = node + if(className === avalon.noop){ + return } - //ms-duplex - execHooks(node, vnode, parent, steps, 'afterChange') - if (!steps.count) - break - } - } - - function getEndRepeat(node) { - var isBreak = 0, ret = [], node - while (node) { - if (node.nodeType === 8) { - if (node.nodeValue.indexOf('ms-for:') === 0) { - ++isBreak - } else if (node.nodeValue.indexOf('ms-for-end:') === 0) { - --isBreak - } + className = cur.props[name] = className.trim().replace(/\s+/, ' ') + if (preValue !== className) { + cur['change-' + type] = className + update(cur, this.update, steps, type ) } - ret.push(node) - node = node.nextSibling - if (isBreak === 0) { - break + }, + update: function (node, vnode) { + + if(!node || node.nodeType !==1) + return + var classEvent = vnode.classEvent + if (classEvent) { + for (var i in classEvent) { + if (i === 'tabIndex') { + node[i] = classEvent[i] + } else { + avalon.bind(node, i, classEvent[i]) + } + } + vnode.classEvent = {} } + var names = ['class', 'hover', 'active'] + names.forEach(function (type) { + var name = 'change-' + type + var value = vnode[ name ] + if (value === void 0) + return + if (type === 'class') { + node && setClass(node, vnode) + } else { + var oldType = node.getAttribute('change-'+type) + if (oldType) { + avalon(node).removeClass(oldType) + } + node.setAttribute(name, value) + } + }) } - return ret.pop() + }) + + directives.active = directives.hover = directives['class'] + + function processBooleanObject(obj) { + return Object.keys(obj).filter(function (name) { + return obj[name] + }).join(' ') } - function execHooks(node, vnode, parent, steps, hookName) { - var hooks = vnode[hookName] - if (hooks) { - for (var hook; hook = hooks.shift(); ) { - steps.count -= 1 - if (false === hook(node, vnode, parent)) { - return false - } - } - delete vnode[hookName] + var classMap = { + mouseenter: 'change-hover', + mouseleave: 'change-hover', + mousedown: 'change-active', + mouseup: 'change-active' + } + + function activateClass(e) { + var elem = e.target + avalon(elem).addClass(elem.getAttribute(classMap[e.type]) || '') + } + + function abandonClass(e) { + var elem = e.target + var name = classMap[e.type] + avalon(elem).removeClass(elem.getAttribute(name) || '') + if (name !== 'change-active') { + avalon(elem).removeClass(elem.getAttribute('change-active') || '') } } - module.exports = patch + function setClass(node, vnode) { + var old = node.getAttribute('old-change-class') || '' + var neo = vnode.props['ms-class'] + avalon(node).removeClass(old).addClass(neo) + node.setAttribute('old-change-class', neo) + } + + markID(activateClass) + markID(abandonClass) + + + /***/ }, -/* 65 */ +/* 54 */ /***/ function(module, exports, __webpack_require__) { - var patch = __webpack_require__(64) - var rforPrefix = /ms-for\:\s*/ - var rforLeft = /^\s*\(\s*/ - var rforRight = /\s*\)\s*$/ - var rforSplit = /\s*,\s*/ - var rforAs = /\s+as\s+([$\w]+)/ - var rident = __webpack_require__(40).ident - var rinvalid = /^(null|undefined|NaN|window|this|\$index|\$id)$/ - avalon._each = function (obj, fn) { - if (Array.isArray(obj)) { - for (var i = 0; i < obj.length; i++) { - var item = obj[i] - var type = typeof item - var key = item && type === 'object' ? item.$hashcode : type + item - fn(i, obj[i], key) - } - } else { - for (var i in obj) { - if (obj.hasOwnProperty(i)) { - fn(i, obj[i], i) - } - } - } - } - var map = {} - avalon.directive('for', { - priority: 3, - parse: function (el, num) { - var str = el.nodeValue, aliasAs - str = str.replace(rforAs, function (a, b) { - if (!rident.test(b) || rinvalid.test(b)) { - avalon.error('alias ' + b + ' is invalid --- must be a valid JS identifier which is not a reserved name.') - } else { - aliasAs = b - } - return '' + var markID = __webpack_require__(6).getLongID + var Cache = __webpack_require__(26) + var eventCache = new Cache(128) + var quote = avalon.quote + var update = __webpack_require__(43) + + //Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes + // The assumption is that future DOM event attribute names will begin with + // 'on' and be composed of only English letters. + var revent = /^ms-on-([a-z]+)/ + var rfilters = /\|.+/g + var rvar = /([@$]?\w+)/g + var rstring = __webpack_require__(40).string + //基于事件代理的高性能事件绑定 + avalon.directive('on', { + priority: 3000, + parse: function (binding, num) { + var vars = binding.expr.replace(rstring, ' ').replace(rfilters, '').match(rvar) + var canCache = vars.every(function (el) { + return el.charAt(0) === '@' || el.charAt(0) === '#' || el === '$event' }) - var arr = str.replace(rforPrefix, '').split(' in ') - var assign = 'var loop' + num + ' = ' + avalon.parseExpr(arr[1]) + '\n' - var alias = aliasAs ? 'var ' + aliasAs + ' = loop' + num + '\n' : '' - var kv = arr[0].replace(rforLeft, '').replace(rforRight, '').split(rforSplit) - if (kv.length === 1) {//确保avalon._each的回调有三个参数 - kv.unshift('$key') + var vmDefine = 'vnode' + num + '.onVm = __vmodel__\n' + var pid = quote(binding.name) + + if (canCache) { + var key = binding.expr + var fn = eventCache.get(key) + if(!fn){ + var fn = Function('return ' + avalon.parseExpr(binding, 'on'))() + var uuid = markID(fn) + eventCache.put(key, fn) + } + avalon.eventListeners[uuid] = fn + return vmDefine + 'vnode' + num + '.props[' + pid + + '] = avalon.eventListeners.' + uuid + '\n' + } else {//如果闭包引用其他变量 + return vmDefine + 'vnode' + num + '.props[' + pid + + '] = ' + avalon.parseExpr(binding, 'on') + '\n' } - //分别创建isArray, ____n, ___i, ___v, ___trackKey变量 - return assign + alias + 'avalon._each(loop' + num + ', function(' + kv + ', traceKey){\n' - }, - diff: function (current, previous, steps, __index__) { - var cur = current[__index__] - var pre = previous[__index__] || {} - - var isInit = !('directive' in pre) - var isChange = false, i, c, p - if (isInit) { - pre.components = [] - pre.repeatCount = 0 - } + diff: function (cur, pre, steps, name) { + + var fn0 = cur.props[name] + var fn1 = (pre.props || {})[name] + if ( fn0 +''!== fn1+'' ) { + var match = name.match(revent) + var type = match[1] + var search = type + ':' + markID(fn0) + cur.addEvents = cur.addEvents || {} + cur.addEvents[search] = fn0 - var quota = pre.components.length - var nodes = current.slice(cur.start, cur.end) - cur.endRepeat = pre.endRepeat - cur.components = getComponents(nodes.slice(1, -1), cur.signature) - var n = Math.max(nodes.length - 2, 0) - pre.repeatCount - if (n > 0) { - var spliceArgs = [__index__ + 1, 0] - for (var i = 0, n = n - 1; i < n; i++) { - spliceArgs.push(null) + if (typeof fn1 === 'function') { + cur.removeEvents = cur.removeEvents || {} + cur.removeEvents[type + ':' + fn1.uuid] = fn1 } - previous.splice.apply(previous, spliceArgs) - } else if (n < 0) { - previous.splice.apply(previous, [__index__, Math.abs(n)]) + update(cur, this.update, steps, 'on' ) + } - cur.action = isInit ? 'init' : 'update' - if (isInit) { - /* eslint-disable no-cond-assign */ - var oldCount = steps.count - var cache = cur.cache = {} - for (i = 0; c = cur.components[i++]; ) { - /* eslint-enable no-cond-assign */ - avalon.diff(c.children, [], steps) - saveInCache(cache, c) - } - cur.removedComponents = {} - //如果没有孩子也要处理一下 - isChange = cur.components.length === 0 || - steps.count !== oldCount + }, + update: function (node, vnode) { + if(!node || node.nodeType > 1) //在循环绑定中,这里为null + return + var key, type, listener + node._ms_context_ = vnode.onVm + delete vnode.onVm + for (key in vnode.removeEvents) { + type = key.split(':').shift() + listener = vnode.removeEvents[key] + avalon.unbind(node, type, listener) + } + delete vnode.removeEvents + for (key in vnode.addEvents) { + type = key.split(':').shift() + listener = vnode.addEvents[key] + avalon.bind(node, type, listener) + } + delete vnode.addEvents + } + }) - } else { - var cache = pre.cache - var newCache = cur.cache = {} - /* eslint-disable no-cond-assign */ - for (i = 0; c = cur.components[i++]; ) { - /* eslint-enable no-cond-assign */ - var p = isInCache(cache, c.key) - if (p) { - if (!isChange) {//如果位置发生了变化 - isChange = c.index !== p.index - } - quota-- - c.nodes = p.nodes - avalon.diff(c.children, p.children, steps) - } else if (quota) { - p = fuzzyMatchCache(cache, c.key) - if (p) { - quota-- - isChange = true //内容发生变化 - c.nodes = p.nodes - avalon.diff(c.children, p.children, steps) - } - } - if (!c.nodes) {//这是新添加的元素 - isChange = true - avalon.diff(c.children, [], steps) - } - saveInCache(newCache, c) - } - for (i in cache) { - cur.removedComponents = cache - isChange = true - break - } - } - pre.components.length = 0 //release memory - delete pre.cache - if (isChange) { - var list = cur.change || (cur.change = []) - avalon.Array.ensure(list, this.update) - cur.steps = steps - steps.count += 1 - } - return __index__ + nodes.length - 1 - }, - update: function (startRepeat, vnode, parent) { - var action = vnode.action - var endRepeat = vnode.endRepeat - var fragment = document.createDocumentFragment() - if (action === 'init') { - //在ms-widget中,这部分内容会先行被渲染出来 - var hasRender = false - var node = startRepeat.nextSibling - while (node && node !== endRepeat) { - if (node.nodeType === 8) { - hasRender = node.nodeValue === vnode.signature - if (hasRender) { - vnode.hasRender = true - break - } - } - node = node.nextSibling +/***/ }, +/* 55 */ +/***/ function(module, exports, __webpack_require__) { - } - if (!hasRender) { - node = startRepeat.nextSibling - while (node && node !== endRepeat) { - parent.removeChild(node) - node = startRepeat.nextSibling - } - } + + var valueHijack = __webpack_require__(56) + + var newField = __webpack_require__(57) + var initField = __webpack_require__(58) + var updateField = __webpack_require__(60) + var addField = __webpack_require__(61) + var update = __webpack_require__(43) + var evaluatorPool = __webpack_require__(39) + avalon.directive('duplex', { + priority: 2000, + parse: function (binding, num, vnode) { + var id = binding.expr + newField(binding, vnode) + avalon.caches[id] = vnode.field + var ret = 'vnode' + num + '.duplexVm = __vmodel__;\n' + + 'vnode' + num + '.props["ms-duplex"] = ' + avalon.quote(id) + ';\n' + + 'vnode' + num + '.props["data-duplex-get"] = ' + evaluatorPool.get('duplex:' + id) +'\n'+ + 'vnode' + num + '.props["data-duplex-set"] = ' + evaluatorPool.get('duplex:set:' + id)+'\n' + var format = evaluatorPool.get('duplex:format:' + id) + if (format) { + ret += 'vnode' + num + '.props["data-duplex-format"] = ' + format + } + return ret + }, + diff: function (cur, pre, steps) { + var duplexID = cur.props["ms-duplex"] + cur.field = pre.field || avalon.mix( {}, avalon.caches[duplexID]) + var field = cur.field + if (!field.set) { + initField(cur) } - var domTemplate = avalon.parseHTML(vnode.template) - - var key = vnode.signature - for (var i in vnode.removedComponents) { - var el = vnode.removedComponents[i] - if (el.nodes) { - el.nodes.forEach(function (n, k) { - if (n.parentNode) { - avalon.applyEffect(n, el.children[k], { - hook: 'onLeaveDone', - cb: function () { - n.parentNode.removeChild(n) - }, - staggerKey: key + 'leave' - }) - } - }) - el.nodes.length = el.children.length = 0 - } + cur.duplexVm = null + var value = cur.props.value = field.get(field.vmodel) + + if (cur.type === 'select' && !cur.children.length) { + avalon.Array.merge(cur.children, avalon.lexer(cur.template, 0, 2)) + fixVirtualOptionSelected(cur, value) } - delete vnode.removedComponents + if (!field.element) { + var isEqual = false + } else { + var preValue = pre.props.value - var insertPoint = startRepeat + if (Array.isArray(value)) { + isEqual = value + '' === preValue + '' + } else { + isEqual = value === preValue + } + } - for (var i = 0; i < vnode.components.length; i++) { - var com = vnode.components[i] - var cnodes = com.nodes - if (cnodes) { - if (insertPoint.nextSibling !== cnodes[0]) { - var moveFragment = fragment.cloneNode(false) - for (var k = 0, cc; cc = cnodes[k++]; ) { - moveFragment.appendChild(cc) - } - parent.insertBefore(moveFragment, insertPoint.nextSibling) - applyEffects(com.nodes, com.children, { - hook: 'onMoveDone', - staggerKey: key + 'move' - }) - } - } else if (vnode.hasRender) { - //添加nodes属性但不用插入节点 - var cnodes = com.nodes = [] - insertPoint = insertPoint.nextSibling - while (insertPoint && insertPoint !== vnode.endRepeat) { - cnodes.push(insertPoint) - if (insertPoint.nodeValue === vnode.signature) { - break - } - insertPoint = insertPoint.nextSibling - } - } else { - //添加nodes属性并插入节点 - var newFragment = domTemplate.cloneNode(true) - newFragment.appendChild(document.createComment(vnode.signature)) - cnodes = com.nodes = avalon.slice(newFragment.childNodes) - parent.insertBefore(newFragment, insertPoint.nextSibling) - applyEffects(com.nodes, com.children, { - hook: 'onEnterDone', - staggerKey: key + 'enter' - }) - } - insertPoint = cnodes[cnodes.length - 1] - if (!insertPoint) { - break + if (!isEqual) { + field.modelValue = value + update(cur, this.update, steps, 'duplex', 'afterChange') + + } + }, + update: function (node, vnode) { + var field = node._ms_field_ = vnode.field + if (!field.element) {//这是一次性绑定 + field.element = node //方便进行垃圾回收 + var events = field.events + for (var name in events) { + avalon.bind(node, name, events[name]) + delete events[name] } } - var entity = [], vnodes = [] - vnode.components.forEach(function (c) { - entity.push.apply(entity, c.nodes) - vnodes.push.apply(vnodes, c.children) - }) - vnode.repeatCount = vnodes.length - patch(entity, vnodes, parent, vnode.steps) - var cb = avalon.caches[vnode.cid] - if (cb) { - cb.call(vnode.vmodel, { - type: "rendered", - target: startRepeat, - endRepeat: endRepeat, - signature: vnode.signature - }) + addField(node, vnode) + if (!avalon.msie && valueHijack === false && !node.valueHijack) { + //chrome 42及以下版本需要这个hack + node.valueHijack = field.update + var intervalID = setInterval(function () { + if (!avalon.contains(avalon.root, node)) { + clearInterval(intervalID) + } else { + node.valueHijack() + } + }, 30) } - return false - } - - }) - - function getRepeatRange(nodes, i) { - var isBreak = 0, ret = [], node - while (node = nodes[i++]) { - if (node.type === '#comment') { - if (node.nodeValue.indexOf('ms-for:') === 0) { - isBreak++ - } else if (node.nodeValue.indexOf('ms-for-end:') === 0) { - isBreak-- + var viewValue = field.format(field.modelValue) + if (field.viewValue !== viewValue) { + field.viewValue = viewValue + updateField[field.type].call(field) + if (node.caret) { + var pos = field.caretPos + pos && field.updateCaret(node, pos.start, pos.end) + field.caretPos = null } } - ret.push(node) - if (isBreak === 0) { - break - } } - return ret - } + }) - //将要循环的节点根据锚点元素再分成一个个更大的单元,用于diff - function getComponents(nodes, signature) { - var components = [] - var com = { - children: [] - } - for (var i = 0, el; el = nodes[i]; i++) { - if (el.nodeType === 8 && el.nodeValue === signature) { - com.children.push(el) - com.key = el.key - com.index = components.length - components.push(com) - com = { - children: [] - } - } else { - com.children.push(el) + function fixVirtualOptionSelected(cur, curValue) { + var options = [] + cur.children.forEach(function (a) { + if (a.type === 'option') { + options.push(a) + } else if (a.type === 'optgroup') { + a.children.forEach(function (c) { + if (c.type === 'option') { + options.push(c) + } + }) } + }) + var multi = cur.props.multiple + var map = {} + var one = multi === null || multi === void 0 || multi === false + if (Array.isArray(curValue)) { + curValue.forEach(function (a) { + map[a] = 1 + }) + } else { + map[curValue] = 1 } - return components - } - - var rfuzzy = /^(string|number|boolean)/ - var rkfuzzy = /^_*(string|number|boolean)/ - function fuzzyMatchCache(cache, id) { - var m = id.match(rfuzzy) - if (m) { - var fid = m[1] - for (var i in cache) { - var n = i.match(rkfuzzy) - if (n && n[1] === fid) { - return isInCache(cache, i) - } + for (var i = 0, option; option = options[i++]; ) { + var v = 'value' in option.props ? option.props.value : + (option.children[0] || {nodeValue: ''}).nodeValue.trim() + option.props.selected = !!map[v] + if (map[v] && one) { + break } } } - // 新位置: 旧位置 - function isInCache(cache, id) { - var c = cache[id], cid = id - if (c) { - var ctack = cache["***" + id] - if (ctack) { - var a = ctack.pop() - delete cache[a.id] - if (ctack.length == 0) - delete cache["***" + id] - return a.c - } - var stack = [{id: id, c: c}] - while (1) { - id += '_' - if (cache[id]) { - stack.push({ - id: id, - c: cache[id] - }) - } else { - break - } - } - var a = stack.pop() - delete cache[a.id] - if (stack.length) { - cache['***' + cid] = stack - } - return a.c - } - return c - } - function saveInCache(cache, component) { - var trackId = component.key - if (!cache[trackId]) { - cache[trackId] = component - } else { - while (1) { - trackId += '_' - if (!cache[trackId]) { - cache[trackId] = component - break - } +/***/ }, +/* 56 */ +/***/ function(module, exports) { + + var valueHijack = false + try { //#272 IE9-IE11, firefox + var setters = {} + var aproto = HTMLInputElement.prototype + var bproto = HTMLTextAreaElement.prototype + function newSetter(value) { // jshint ignore:line + setters[this.tagName].call(this, value) + if (!this.caret && this._ms_field_) { + this._ms_field_.update.call(this) } } - } - var applyEffects = function (nodes, vnodes, opts) { - vnodes.forEach(function (el, i) { - avalon.applyEffect(nodes[i], vnodes[i], opts) + var inputProto = HTMLInputElement.prototype + Object.getOwnPropertyNames(inputProto) //故意引发IE6-8等浏览器报错 + setters['INPUT'] = Object.getOwnPropertyDescriptor(aproto, 'value').set + + Object.defineProperty(aproto, 'value', { + set: newSetter + }) + setters['TEXTAREA'] = Object.getOwnPropertyDescriptor(bproto, 'value').set + Object.defineProperty(bproto, 'value', { + set: newSetter }) + valueHijack = true + } catch (e) { + //在chrome 43中 ms-duplex终于不需要使用定时器实现双向绑定了 + // http://updates.html5rocks.com/2015/04/DOM-attributes-now-on-the-prototype + // https://docs.google.com/document/d/1jwA8mtClwxI-QJuHT7872Z0pxpZz8PBkf2bGAbsUtqs/edit?pli=1 } - - + module.exports = valueHijack /***/ }, -/* 66 */ -/***/ function(module, exports, __webpack_require__) { +/* 57 */ +/***/ function(module, exports) { - var disposeDetectStrategy = __webpack_require__(67) - var patch = __webpack_require__(64) + var rchangeFilter = /\|\s*change\b/ + var rcheckedType = /^(?:checkbox|radio)$/ + var rdebounceFilter = /\|\s*debounce(?:\(([^)]+)\))?/ + var rnoduplexInput = /^(file|button|reset|submit|checkbox|radio|range)$/ - //插入点机制,组件的模板中有一些slot元素,用于等待被外面的元素替代 - var dir = avalon.directive('widget', { - priority: 4, - parse: function (binding, num, elem) { - var isVoidTag = !!elem.isVoidTag - elem.isVoidTag = true - var wid = elem.props.wid || (elem.props.wid = avalon.makeHashCode('w')) - avalon.resolvedComponents[wid] = { - props: avalon.shadowCopy({}, elem.props), - template: elem.template - } - var ret = [ - 'vnode' + num + '._isVoidTag = ' + isVoidTag, - 'vnode' + num + '.props.wid = "' + wid + '"', - 'vnode' + num + '.template = ' + avalon.quote(elem.template), - 'vnode' + num + '.props["ms-widget"] = ' + avalon.parseExpr(binding, 'widget'), - 'vnode' + num + ' = avalon.component(vnode' + num + ', __vmodel__)', - 'if(typeof vnode' + num + '.render === "string"){', - 'avalon.__widget = [];', - 'var __backup__ = __vmodel__;', - '__vmodel__ = vnode' + num + '.vmodel;', - 'try{eval(" new function(){"+ vnode' + num + '.render +"}");', - '}catch(e){avalon.warn(e)', '}', - 'vnode' + num + ' = avalon.renderComponent(avalon.__widget[0])', '}', - '__vmodel__ = __backup__;'] - return ret.join('\n') + '\n' - }, - define: function () { - return avalon.mediatorFactory.apply(this, arguments) - }, - diff: function (cur, pre, steps) { - var coms = avalon.resolvedComponents - var wid = cur.props.wid - var docker = coms[wid] - if (!docker || !docker.renderCount) { - steps.count += 1 - cur.change = [this.replaceByComment] - } else if (docker.renderCount && docker.renderCount < 2) { - cur.steps = steps - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.replaceByComponent)) { - steps.count += 1 - } - function fireReady(dom, vnode) { - cur.vmodel.$fire('onReady', { - type: 'ready', - target: dom, - wid: wid, - vmodel: vnode.vmodel - }) - docker.renderCount = 2 - } - list = cur.afterChange || (cur.afterChange = []) - if (avalon.Array.ensure(list, fireReady)) { - steps.count += 1 - } + function newField(binding, vnode) { + var expr = binding.expr + var etype = vnode.props.type + //处理数据转换器 + var ptype = binding.param + var isChecked = ptype === 'checked' + var field = vnode.field = { + parsers: [], + formatters: [], + modelValue: NaN, + viewValue: NaN, + validators: '', + parse: parse, + format: format + } + if (isChecked) { + if (rcheckedType.test(etype)) { + field.isChecked = true + field.type = 'radio' } else { - var needUpdate = !cur.diff || cur.diff(cur, pre, steps) - cur.skipContent = !needUpdate - var viewChangeObservers = cur.vmodel.$events.onViewChange - if (viewChangeObservers && viewChangeObservers.length) { - steps.count += 1 - cur.afterChange = [function (dom, vnode) { - var preHTML = pre.outerHTML - var curHTML = cur.outerHTML || - (cur.outerHTML = avalon.vdomAdaptor(cur, 'toHTML')) - if (preHTML !== curHTML) { - cur.vmodel.$fire('onViewChange', { - type: 'viewchange', - target: dom, - wid: wid, - vmodel: vnode.vmodel - }) - } - docker.renderCount++ - }] - } - + ptype = null } - }, - addDisposeMonitor: function (dom) { - if (window.chrome && window.MutationEvent) { - disposeDetectStrategy.byMutationEvent(dom) - } else if (Object.defineProperty && window.Node) { - disposeDetectStrategy.byRewritePrototype(dom) - } else { - disposeDetectStrategy.byPolling(dom) + } + var changed = vnode.props['data-duplex-changed'] + if (changed) { + var cid = changed+':cb' + if(!avalon.caches[cid]){ + var fn = Function('return '+ avalon.parseExpr(changed, 'on')) + avalon.caches[cid] = field.callback = fn() + }else{ + field.callback = avalon.caches[cid] } - }, - replaceByComment: function (dom, node, parent) { - var comment = document.createComment(node.nodeValue) - if (dom) { - parent.replaceChild(comment, dom) + } + var parser = avalon.parsers[ptype] + if (parser) { + field.parsers.push(parser) + } + if (rchangeFilter.test(expr)) { + // expr = expr.replace(rchangeFilter, '') + if (rnoduplexInput.test(etype)) { + avalon.warn(etype + '不支持change过滤器') } else { - parent.appendChild(comment) - } - }, - replaceByComponent: function (dom, node, parent) { - var hasDdash = node.type.indexOf('-') > 0 - var hasDetect = false - if (hasDdash && document.registerElement) { - //必须在自定义标签实例化时,注册它 - disposeDetectStrategy.byCustomElement(node.type) - hasDetect = true + field.isChanged = true } - var com = avalon.vdomAdaptor(node, 'toDOM') - node.ouerHTML = avalon.vdomAdaptor(node, 'toHTML') - if (dom) { - parent.replaceChild(com, dom) - } else { - parent.appendChild(com) + } + + var match = expr.match(rdebounceFilter) + if (match) { + // expr = expr.replace(rdebounceFilter, '') + if (!field.isChanged) { + field.debounceTime = parseInt(match[1], 10) || 300 } - patch([com], [node], parent, node.steps) - if (!hasDetect) { - dir.addDisposeMonitor(com) + } + binding.expr = field.expr = expr.trim() + if (!/input|textarea|select/.test(vnode.type)) { + if ('contenteditable' in vnode.props) { + field.type = 'contenteditable' } - return false + } else if (!field.type) { + field.type = vnode.type === 'select' ? 'select' : + etype === 'checkbox' ? 'checkbox' : + etype === 'radio' ? 'radio' : + 'input' } - }) + avalon.parseExpr(binding, 'duplex') + } + function parse(val) { + for (var i = 0, fn; fn = this.parsers[i++]; ) { + val = fn.call(this, val) + } + return val + } + function format(val) { + var formatters = this.formatters + var index = formatters.length + while (index--) { + val = formatters[index](val) + } + return val + } + module.exports = newField - // http://www.besteric.com/2014/11/16/build-blog-mirror-site-on-gitcafe/ /***/ }, -/* 67 */ -/***/ function(module, exports) { +/* 58 */ +/***/ function(module, exports, __webpack_require__) { - //用于chrome, safari - var tags = {} - function byCustomElement(name) { - if (tags[name]) - return - tags[name] = true - var prototype = Object.create(HTMLElement.prototype) - prototype.detachedCallback = function () { - var dom = this - setTimeout(function () { - fireDisposeHook(dom) + var msie = avalon.msie + var window = avalon.window + var document = avalon.document + var refreshModel = __webpack_require__(59) + var markID = __webpack_require__(6).getShortID + + + function initControl(cur) { + + var field = cur.field + field.update = updateModel + field.updateCaret = setCaret + field.get = cur.props['data-duplex-get'] + field.set = cur.props['data-duplex-set'] + var format = cur.props['data-duplex-format'] + if (format) { + field.formatters.push(function (v) { + return format(field.vmodel, v) }) } - document.registerElement(name, prototype) - } + field.vmodel = cur.duplexVm - //http://stackoverflow.com/questions/11425209/are-dom-mutation-observers-slower-than-dom-mutation-events - //http://stackoverflow.com/questions/31798816/simple-mutationobserver-version-of-domnoderemovedfromdocument - function byMutationEvent(dom) { - dom.addEventListener("DOMNodeRemovedFromDocument", function () { - setTimeout(function () { - fireDisposeHook(dom) - }) - }) - } - //用于IE8+, firefox - function byRewritePrototype() { - if (byRewritePrototype.execute) { - return + var events = field.events = {} + //添加需要监听的事件 + switch (field.type) { + case 'radio': + if (cur.props.type === 'radio') { + events.click = updateModel + } else { + events[msie < 9 ? 'click' : 'change'] = updateModel + } + break + case 'checkbox': + case 'select': + events.change = updateModel + break + case 'contenteditable': + if (field.isChanged) { + events.blur = updateModel + } else { + if (avalon.modern) { + if (window.webkitURL) { + // http://code.metager.de/source/xref/WebKit/LayoutTests/fast/events/ + // https://bugs.webkit.org/show_bug.cgi?id=110742 + events.webkitEditableContentChanged = updateModel + } else if (window.MutationEvent) { + events.DOMCharacterDataModified = updateModel + } + events.input = updateModel + } else { + + events.keydown = updateModelKeyDown + events.paste = updateModelDelay + events.cut = updateModelDelay + events.focus = closeComposition + events.blur = openComposition + + } + + } + break + case 'input': + if (field.isChanged) { + events.change = updateModel + } else { + + //http://www.cnblogs.com/rubylouvre/archive/2013/02/17/2914604.html + //http://www.matts411.com/post/internet-explorer-9-oninput/ + if (avalon.msie < 10) { + // Internet Explorer <= 8 doesn't support the 'input' event, but does include 'propertychange' that fires whenever + // any property of an element changes. Unlike 'input', it also fires if a property is changed from JavaScript code, + // but that's an acceptable compromise for this binding. IE 9 does support 'input', but since it doesn't fire it + // when using autocomplete, we'll use 'propertychange' for it also. + events.propertychange = updateModelHack + if (msie > 7 ) { + // IE 8 has a bug where it fails to fire 'propertychange' on the first update following a value change from + // JavaScript code. It also doesn't fire if you clear the entire value. To fix this, we bind to the following + // events too. + events.keyup = updateModel // A single keystoke + events.keydown = updateModel // The first character when a key is held down + } + if (msie > 8) { + // Internet Explorer 9 doesn't fire the 'input' event when deleting text, including using + // the backspace, delete, or field-x keys, clicking the 'x' to clear the input, dragging text + // out of the field, and cutting or deleting text using the context menu. 'selectionchange' + // can detect all of those except dragging text out of the field, for which we use 'dragend'. + // These are also needed in IE8 because of the bug described above. + cur.valueHijack = updateModel // 'selectionchange' covers cut, paste, drop, delete, etc. + events.dragend = updateModelDelay + } + } else { + events.input = updateModel + //https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray + //如果当前浏览器支持Int8Array,那么我们就不需要以下这些事件来打补丁了 + if (!/\[native code\]/.test(window.Int8Array)) { + events.keydown = updateModelKeyDown //safari < 5 opera < 11 + events.paste = updateModelDelay//safari < 5 + events.cut = updateModelDelay//safari < 5 + if (window.netscape) { + // Firefox <= 3.6 doesn't fire the 'input' event when text is filled in through autocomplete + events.DOMAutoComplete = updateModel + } + } + events.compositionstart = openComposition + events.compositionend = closeComposition + + } + } + break } - byRewritePrototype.execute = true - var p = Node.prototype - var _removeChild = p.removeChild - p.removeChild = function (a, b) { - _removeChild.call(this, a, b) - if (a.nodeType === 1) { - setTimeout(function () { - fireDisposeHook(a) - }) - } - return a - } - var _replaceChild = p.replaceChild - p.replaceChild = function (a, b) { - _replaceChild.call(this, a, b) - if (a.nodeType === 1) { - setTimeout(function () { - fireDisposeHook(a) - }) - } - return a - } - var _innerHTML = p.innerHTML - p.innerHTML = function (html) { - var all = this.getElementsByTagName('*') - _innerHTML.call(this, html) - fireDisposedComponents(all) + if (/password|text/.test(cur.props.type)) { + events.focus = openCaret + events.blur = closeCaret } - var _appendChild = p.appendChild - p.appendChild = function (a) { - _appendChild.call(this, a) - if (a.nodeType === 1 && this.nodeType === 11) { - setTimeout(function () { - fireDisposeHook(a) - }) + } + + + function updateModel() { + var elem = this + + var field = this._ms_field_ + if (elem.composing) + return + if (elem.caret) { + try { + var pos = getCaret(elem) + if (pos.start === pos.end || pos.start + 1 === pos.end) { + field.caretPos = pos + } + } catch (e) { + avalon.warn('fixCaret error', e) } - return a } - var _insertBefore = p.insertBefore - p.insertBefore = function (a) { - _insertBefore.call(this, a) - if (a.nodeType === 1 && this.nodeType === 11) { - setTimeout(function () { - fireDisposeHook(a) - }) + if (field.debounceTime > 4) { + var timestamp = new Date() + var left = timestamp - field.time || 0 + field.time = timestamp + if (left >= field.debounceTime) { + refreshModel[field.type].call(field) + } else { + clearTimeout(field.debounceID) + field.debounceID = setTimeout(function () { + refreshModel[field.type].call(field) + }, left) } - return a + } else { + refreshModel[field.type].call(field) } } - //用于IE6,7 - var checkDisposeNodes = [] - var checkID = 0 - function byPolling(dom) { - avalon.Array.ensure(checkDisposeNodes, dom) - if (!checkID) { - checkID = setInterval(function () { - for (var i = 0, el; el = checkDisposeNodes[i++]; ) { - if (false === fireDisposeHook(el)) { - avalon.Array.removeAt(checkDisposeNodes, i) - --i - } - } - if (checkDisposeNodes.length == 0) { - clearInterval(checkID) - checkID = 0 - } - }, 1000) + function updateModelHack(e) { + if (e.propertyName === 'value') { + updateModel.call(this, e) } } - - module.exports = { - byPolling: byPolling, - byMutationEvent: byMutationEvent, - byCustomElement: byCustomElement, - byRewritePrototype: byRewritePrototype + function updateModelDelay(e) { + var elem = this + setTimeout(function () { + updateModel.call(elem, e) + }, 17) } - function fireDisposeHook(el) { - if (el.nodeType === 1 && el.getAttribute('wid') && !avalon.contains(avalon.root, el)) { - var wid = el.getAttribute('wid') - var docker = avalon.resolvedComponents[ wid ] - var vm = docker.vmodel - var cached = !!docker.cached - docker.vmodel.$fire("onDispose", { - type: 'dispose', - target: el, - vmodel: vm, - cached: cached - }) - if (docker && docker.vmodel && !cached) { - vm.$element = null - vm.$hashcode = false - delete docker.vmodel - delete avalon.resolvedComponents[ wid ] - } - return false - } + + function openCaret() { + this.caret = true } - function fireDisposedComponents(nodes) { - for (var i = 0, el; el = nodes[i++]; ) { - fireDisposeHook(el) - } + function closeCaret() { + this.caret = false + } + function openComposition() { + this.composing = true } -/***/ }, -/* 68 */ -/***/ function(module, exports, __webpack_require__) { + function closeComposition(e) { + this.composing = false + } + function updateModelKeyDown(e) { + var key = e.keyCode; + // ignore + // command modifiers arrows + if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) + return + updateModelDelay.call(this, e) + } - var support = __webpack_require__(69) - var Cache = __webpack_require__(26) + markID(openCaret) + markID(closeCaret) + markID(openComposition) + markID(closeComposition) + markID(updateModel) + markID(updateModelHack) + markID(updateModelDelay) + markID(updateModelKeyDown) - avalon.directive('effect', { - priority: 5, - parse: function (binding, num) { - return 'vnode' + num + '.props["ms-effect"] = ' + avalon.parseExpr(binding) + ';\n' - }, - diff: function (cur, pre, steps, name) { - var curObj = cur.props[name] - if(typeof curObj === 'string'){ - var is = curObj - curObj = cur.props[name] = { - is: is - } - - }else if (Array.isArray(curObj)) { - curObj = cur.props[name] = avalon.mix.apply({}, curObj) - } - - curObj.action = curObj.action || 'enter' - - if (Object(curObj) === curObj) { - var preObj = pre.props[name] - if ( Object(preObj) !== preObj || diffObj(curObj, preObj )) { - var list = cur.afterChange = cur.afterChange || [] - if(avalon.Array.ensure(list, this.update)){ - steps.count += 1 - } - } - } - }, - update: function (dom, vnode, parent, option) { - if(dom.animating ){ - return - } - dom.animating = true - var localeOption = vnode.props['ms-effect'] - var type = localeOption.is - option = option || {} - if(!type){//如果没有指定类型 - return avalon.warn('need is option') - } - - var effects = avalon.effects - if(support.css && !effects[type]){ - avalon.effect(type, {}) - } - var globalOption = effects[type] - if(!globalOption){//如果没有定义特效 - return avalon.warn(type+' effect is undefined') - } - var action = option.action || localeOption.action - var Effect = avalon.Effect - if (typeof Effect.prototype[action] !== 'function'){ - return avalon.warn(action+' action is undefined') - } - var effect = new Effect(dom) - var finalOption = avalon.mix(option, globalOption, localeOption) - if (finalOption.queue) { - animationQueue.push(function () { - effect[action](finalOption) - }) - callNextAnimation() - } else { - setTimeout(function(){ - effect[action](finalOption) - },4) + if (msie >= 8 && msie < 10) { + avalon.bind(document, 'selectionchange', function (e) { + var el = document.activeElement || {} + if (!el.caret && el.valueHijack) { + el.valueHijack() } + }) + } + + function getCaret(field) { + var start = NaN, end = NaN + if (field.setSelectionRange) { + start = field.selectionStart + end = field.selectionEnd + } else if (document.selection && document.selection.createRange) { + var range = document.selection.createRange() + start = 0 - range.duplicate().moveStart('character', -100000) + end = start + range.text.length } - }) - function diffObj(a, b){ - for(var i in a){ - if(a[i] !== b[i]) - return true + return { + start: start, + end: end } - return false } - var animationQueue = [] - function callNextAnimation() { - if (animationQueue.lock) + function setCaret(field, begin, end) { + if (!field.value || field.readOnly) return - var fn = animationQueue[0] - if (fn) { - callNextAnimation.lock = true - fn() + if (field.createTextRange) {//IE6-8 + var range = field.createTextRange() + range.collapse(true) + range.moveStart('character', begin) + range.select() + } else { + field.selectionStart = begin + field.selectionEnd = end } } - avalon.effects = {} - //这里定义CSS动画 + module.exports = initControl +/***/ }, +/* 59 */ +/***/ function(module, exports) { - avalon.effect = function (name, definition) { - avalon.effects[name] = definition || {} - if (support.css) { - if (!definition.enterClass) { - definition.enterClass = name + '-enter' - } - if (!definition.enterActiveClass) { - definition.enterActiveClass = definition.enterClass + '-active' - } - if (!definition.leaveClass) { - definition.leaveClass = name + '-leave' - } - if (!definition.leaveActiveClass) { - definition.leaveActiveClass = definition.leaveClass + '-active' - } - } - if (!definition.action) { - definition.action = 'enter' - } - } - + + /** + * ------------------------------------------------------------ + * refreshModel + * 在事件回调与value的setter中调用这些方法,来同步vm + * ------------------------------------------------------------ + */ + var refreshModel = { + input: function (prop) {//处理单个value值处理 + var field = this + prop = prop || 'value' + var viewValue = field.element[prop] + var rawValue = viewValue - var Effect = function (el) { - this.el = el - } - avalon.Effect = Effect - Effect.prototype = { - enter: createAction('Enter'), - leave: createAction('Leave'), - move: createAction('Move') - } + viewValue = field.format(viewValue) + //vm.aaa = '1234567890' + //处理 {{@aaa}} 这种格式化同步不一致的情况 + var val = field.parse(viewValue) + viewValue = val + '' - var rsecond = /\d+s$/ - function toMillisecond(str){ - var ratio = rsecond.test(str) ? 1000 : 1 - return parseFloat(str) * ratio - } + if (val !== field.modelValue) { + field.set(field.vmodel, val) + callback(field) + } - function execHooks(options, name, el) { - var list = options[name] - list = Array.isArray(list) ? list : typeof list === 'function' ? [list] : [] - list.forEach(function (fn) { - fn && fn(el) - }) - } - var staggerCache = new Cache(128) + if (rawValue !== viewValue) { + field.viewValue = viewValue + field.element[prop] = viewValue + } - function createAction(action) { - var lower = action.toLowerCase() - return function (option) { - var elem = this.el - var $el = avalon(elem) - var enterAnimateDone - var staggerTime = isFinite(option.stagger) ? option.stagger * 1000 : 0 - if(staggerTime){ - if(option.staggerKey){ - var stagger = staggerCache.get(option.staggerKey) || - staggerCache.put(option.staggerKey, { - count:0, - items:0 - }) - stagger.count++ - stagger.items++ - } + }, + radio: function () { + var field = this + if (field.isChecked) { + var val = field.modelValue = !field.modelValue + field.set(field.vmodel, val) + callback(field) + } else { + refreshModel.input.call(field) } - var staggerIndex = stagger && stagger.count || 0 - var animationDone = function(e) { - var isOk = e !== false - elem.animating = void 0 - enterAnimateDone = true - var dirWord = isOk ? 'Done' : 'Abort' - execHooks(option, 'on' + action + dirWord, elem) - avalon.unbind(elem,support.transitionEndEvent) - avalon.unbind(elem,support.animationEndEvent) - if(stagger){ - if(--stagger.items === 0){ - stagger.count = 0 - } - } - if(option.queue){ - animationQueue.lock = false - animationQueue.shift() - callNextAnimation() - } + }, + checkbox: function () { + var field = this + var array = field.modelValue + if (!Array.isArray(array)) { + avalon.warn('ms-duplex应用于checkbox上要对应一个数组') + array = [array] + } + var method = field.element.checked ? 'ensure' : 'remove' + if (array[method]) { + var val = field.parse(field.element.value) + array[method](val) + callback(field) } - execHooks(option, 'onBefore' + action, elem) - if (option[lower]) { - option[lower](elem, function (ok) { - animationDone(ok !== false) - }) - } else if (support.css) { - - $el.addClass(option[lower + 'Class']) - if(lower === 'leave'){ - $el.removeClass(option.enterClass+' '+option.enterActiveClass) - }else if(lower === 'enter'){ - $el.removeClass(option.leaveClass+' '+option.leaveActiveClass) + }, + select: function () { + var field = this + var val = avalon(field.element).val() //字符串或字符串数组 + if (val + '' !== this.modelValue + '') { + if (Array.isArray(val)) { //转换布尔数组或其他 + val = val.map(function (v) { + return field.parse(v) + }) + } else { + val = field.parse(val) } - - $el.bind(support.transitionEndEvent, animationDone) - $el.bind(support.animationEndEvent, animationDone) - setTimeout(function () { - enterAnimateDone = avalon.root.offsetWidth === NaN - $el.addClass(option[lower + 'ActiveClass']) - var computedStyles = window.getComputedStyle(elem) - var tranDuration = computedStyles[support.transitionDuration] - var animDuration = computedStyles[support.animationDuration] - var time = toMillisecond(tranDuration) || toMillisecond(animDuration) - if (!time === 0) { - animationDone(false) - }else if(!staggerTime ){ - setTimeout(function(){ - if(!enterAnimateDone){ - animationDone(false) - } - },time + 130 ) - } - }, 17+ staggerTime * staggerIndex)// = 1000/60 + field.modelValue = val + field.set(field.vmodel, val) + callback(field) } + }, + contenteditable: function () { + refreshModel.input.call(this, 'innerHTML') } } - avalon.applyEffect = function(node, vnode, opts){ - var cb = opts.cb - var hook = opts.hook - var curEffect = vnode.props && vnode.props['ms-effect'] - if(curEffect && !avalon.document.hidden ){ - var old = curEffect[hook] - if(cb){ - if(Array.isArray(old)){ - old.push(cb) - }else if(old){ - curEffect[hook] = [old, cb] - }else{ - curEffect[hook] = [cb] - } - } - getAction(opts) - node.animate = true - avalon.directives.effect.update(node,vnode, 0, avalon.shadowCopy({},opts) ) - - }else if(cb){ - cb() + function callback(field) { + if (field.validator) { + avalon.directives.validate.validate(field, false) + } + if (field.callback) { + field.callback.call(field.vmodel, { + type: 'changed', + target: field.element + }) } } + module.exports = refreshModel - function getAction(opts){ - if(!opts.acton){ - opts.action = opts.hook.replace(/^on/,'').replace(/Done$/,'').toLowerCase() +/***/ }, +/* 60 */ +/***/ function(module, exports) { + + + var updateField = { + input: function () {//处理单个value值处理 + this.element.value = this.viewValue + }, + radio: function () {//处理单个checked属性 + var checked + if (this.isChecked) { + checked = !!this.viewValue + } else { + checked = this.viewValue + '' === this.element.value + } + var element = this.element + if (avalon.msie === 6) { + setTimeout(function () { + //IE8 checkbox, radio是使用defaultChecked控制选中状态, + //并且要先设置defaultChecked后设置checked + //并且必须设置延迟 + element.defaultChecked = checked + element.checked = checked + }, 31) + } else { + element.checked = checked + } + }, + checkbox: function () {//处理多个checked属性 + var checked = false + var element = this.element + var value = element.value + for (var i = 0; i < this.modelValue.length; i++) { + var el = this.modelValue[i] + if (el + '' === value) { + checked = true + } + } + element.checked = checked + }, + select: function () {//处理子级的selected属性 + var a = Array.isArray(this.viewValue) ? this.viewValue.map(String): this.viewValue+'' + avalon(this.element).val(a) + }, + contenteditable: function () {//处理单个innerHTML + this.element.innerHTML = this.viewValue + this.update.call(this.element) } } - + module.exports = updateField /***/ }, -/* 69 */ +/* 61 */ /***/ function(module, exports) { - /** - * ------------------------------------------------------------ - * 检测浏览器对CSS动画的支持与API名 - * ------------------------------------------------------------ - */ - var supportTransition = false - var supportAnimation = false - var supportCSS = false - var transitionEndEvent - var animationEndEvent - var transitionDuration = avalon.cssName("transition-duration") - var animationDuration = avalon.cssName("animation-duration") - - var checker = { - 'TransitionEvent': 'transitionend', - 'WebKitTransitionEvent': 'webkitTransitionEnd', - 'OTransitionEvent': 'oTransitionEnd', - 'otransitionEvent': 'otransitionEnd' - } - var window = avalon.window - var tran - //有的浏览器同时支持私有实现与标准写法,比如webkit支持前两种,Opera支持1、3、4 - for (var name in checker) { - if (window[name]) { - tran = checker[name] - break - } - try { - var a = document.createEvent(name) - tran = checker[name] - break; - } catch (e) { - } - } - if (typeof tran === "string") { - supportTransition = true - supportCSS = true - transitionEndEvent = tran - } - - //animationend有两个可用形态 - //IE10+, Firefox 16+ & Opera 12.1+: animationend - //Chrome/Safari: webkitAnimationEnd - //http://blogs.msdn.com/b/davrous/archive/2011/12/06/introduction-to-css3-animat ions.aspx - //IE10也可以使用MSAnimationEnd监听,但是回调里的事件 type依然为animationend - // el.addEventListener("MSAnimationEnd", function(e) { - // alert(e.type)// animationend!!! - // }) - checker = { - 'AnimationEvent': 'animationend', - 'WebKitAnimationEvent': 'webkitAnimationEnd' - } - var ani - for (name in checker) { - if (window[name]) { - ani = checker[name]; - break; - } - } - if (typeof ani === "string") { - supportAnimation = true - supportCSS = true - animationEndEvent = ani - } - - module.exports = { - transition: supportTransition, - animation: supportAnimation, - css: supportCSS, - transitionEndEvent: transitionEndEvent, - animationEndEvent: animationEndEvent, - transitionDuration: transitionDuration, - animationDuration: animationDuration - } - -/***/ }, -/* 70 */ -/***/ function(module, exports, __webpack_require__) { - - - avalon.lexer = __webpack_require__(71) - avalon.diff = __webpack_require__(72) - avalon.batch = __webpack_require__(73) - // dispatch与patch 为内置模块 - - var parseView = __webpack_require__(37) - - function render(vtree, num, scan) { - var num = num || String(new Date - 0).slice(0, 6) - var body = parseView(vtree, num, scan) + '\n\nreturn vnodes' + num - var fn = Function('__vmodel__','__fast__', body) - return fn - } - avalon.render = render - - module.exports = avalon - - -/***/ }, -/* 71 */ -/***/ function(module, exports, __webpack_require__) { - - /** - * ------------------------------------------------------------ - * lexer 将字符串变成一个虚拟DOM树,方便以后进一步变成模板函数 - * 此阶段只会生成VElement,VText,VComment - * ------------------------------------------------------------ - */ - - var makeHashCode = avalon.makeHashCode - var vdom = __webpack_require__(15) - var VText = vdom.VText - var VComment = vdom.VComment - - - //匹配只有开标签的无内容元素(Void elements 或 self-contained tags) - //http://www.colorglare.com/2014/02/03/to-close-or-not-to-close.html - //http://blog.jobbole.com/61514/ - - var rfullTag = /^<([^\s>\/=.$<]+)(?:\s+[^=\s]+(?:=[^>\s]+)?)*\s*>(?:[\s\S]*)<\/\1>/ - var rvoidTag = /^<([^\s>\/=.$<]+)\s*([^>]*?)\/?>/ - - var rtext = /^[^<]+/ - var rcomment = /^/ - - var rnumber = /\d+/g - var rspAfterForStart = /^\s*ms-for\:/ - var rspBeforeForEnd = /^\s*ms-for-end\:/ - var r = __webpack_require__(40) - var rsp = r.sp - var rfill = /\?\?\d+/g - var rleftSp = r.leftSp - var rstring = r.string - - - var rbind = avalon.config.rbind - - - var maps = {} - var number = 1 - function dig(a) { - var key = '??' + number++ - maps[key] = a - return key - } - function fill(a) { - var val = maps[a] - return val - } - var rhasString = /=["']/ - var rlineSp = /\n\s*/g - function fixLongAttrValue(attr) { - return rhasString.test(attr) ? - attr.replace(rlineSp, '').replace(rstring, dig) : attr - } - function lexer(text, curDeep, maxDeep) { - var nodes = [] - maxDeep = maxDeep || 1 - if (typeof curDeep !== 'number') { - curDeep = 0 - } else { - curDeep = curDeep + 1 - } - if (curDeep >= maxDeep && !rbind.test(text)) { - return nodes - } - if (!curDeep) { - text = text.replace(rstring, dig) - } - do { - var outerHTML = '' - var node = false - var match = text.match(rtext) - if (match) {//尝试匹配文本 - outerHTML = match[0] - node = new VText(outerHTML.replace(rfill, fill)) - } - - if (!node) {//尝试匹配注释 - match = text.match(rcomment) - if (match) { - outerHTML = match[0] - node = new VComment(match[1].replace(rfill, fill)) - var nodeValue = node.nodeValue - if (rspBeforeForEnd.test(nodeValue)) { - var sp = nodes[nodes.length - 1] - //移除紧挨着前的空白节点 - if (sp && sp.nodeType === 3 && rsp.test(sp.nodeValue)) { - nodes.pop() - } - getForTemplate(nodes) - } - } - } - - - if (!node) {//尝试匹配拥有闭标签的元素节点 - match = text.match(rfullTag) - if (match) { - outerHTML = match[0]//贪婪匹配 outerHTML,可能匹配过多 - var type = match[1].toLowerCase()//nodeName - outerHTML = clipOuterHTML(outerHTML, type) - - match = outerHTML.match(rvoidTag) //抽取所有属性 - - var props = {} - if (match[2]) { - handleProps(fixLongAttrValue(match[2]), props) - } - - var innerHTML = outerHTML.slice(match[0].length, - (type.length + 3) * -1) //抽取innerHTML - - node = { - nodeType: 1, - type: type, - props: props, - template: innerHTML.replace(rfill, fill).trim(), - children: [] - } - node = modifyProps(node, innerHTML, nodes, curDeep, maxDeep) - } - } - - if (!node) { - match = text.match(rvoidTag) - if (match) {//尝试匹配自闭合标签 - outerHTML = match[0] - type = match[1].toLowerCase() - props = {} - if (match[2]) { - handleProps(fixLongAttrValue(match[2]), props) - } - node = { - nodeType: 1, - type: type, - props: props, - template: '', - children: [], - isVoidTag: true - } - modifyProps(node, '', nodes, curDeep, maxDeep) - } - } - - if (node) {//从text中移除被匹配的部分 - nodes.push(node) - text = text.slice(outerHTML.length) - if (node.nodeType === 8 && rspAfterForStart.test(node.nodeValue)) { - node.signature = makeHashCode('for') - //移除紧挨着后的空白节点 - text = text.replace(rleftSp, '') - } - } else { - break - } - } while (1); - if (!curDeep) { - maps = {} - } - return nodes - } - - function getForTemplate(nodes){ - var i = 1, el, k = nodes.length, ret = [] - while(el = nodes[--k]){ - if(el.nodeType === 8){ - if(rspAfterForStart.test(el.nodeValue)){ - i -= 1 - }else if(rspBeforeForEnd.test(el.nodeValue)){ - i += 1 - } - if(i === 0){ - break - } - } - ret.push(avalon.vdomAdaptor(el, 'toHTML')) - } - return el.template = ret.reverse().join('') - } - - //用于创建适配某一种标签的正则表达式 - var openStr = '(?:\\s+[^>=]*?(?:=[^>]+?)?)*>' - var tagCache = {}// 缓存所有匹配开标签闭标签的正则 - var rchar = /./g - var regArgs = avalon.msie < 9 ? 'ig' : 'g'//IE6-8,标签名都是大写 - function clipOuterHTML(matchText, type) { - var opens = [] - var closes = [] - var ropen = tagCache[type + 'open'] || - (tagCache[type + 'open'] = new RegExp('<' + type + openStr, regArgs)) - var rclose = tagCache[type + 'close'] || - (tagCache[type + 'close'] = new RegExp('<\/' + type + '>', regArgs)) - - /* jshint ignore:start */ - matchText.replace(ropen, function (_, b) { - //注意,页面有时很长,b的数值就很大,如 - //000000000<000000011>000000041<000000066>000000096<000000107> - opens.push(('0000000000' + b + '<').slice(-10))//取得所有开标签的位置 - return _.replace(rchar, '1') - }).replace(rclose, function (_, b) { - closes.push(('0000000000' + b + '>').slice(-10))//取得所有闭标签的位置 - }) - - /* jshint ignore:end */ - //
01
02
222
333
- //会变成000<005<012>018<025>031>037<045>051<059> - //再变成<<><>><><> - //最后获取正确的>的索引值,这里为<<><>>的最后一个字符, - var pos = opens.concat(closes).sort() - var gtlt = pos.join('').replace(rnumber, '') - var k = 0, last = 0 - - for (var i = 0, n = gtlt.length; i < n; i++) { - var c = gtlt.charAt(i) - if (c === '<') { - k += 1 - } else { - k -= 1 - } - if (k === 0) { - last = i - break - } - } - var findex = parseFloat(pos[last]) + type.length + 3 // (为三个字符) - return matchText.slice(0, findex) //取得正确的outerHTML - } - - - function modifyProps(node, innerHTML, nodes, curDeep, maxDeep) { - var type = node.type - if ('ms-skip' in node.props) { - node.skipContent = true - } else { - switch (type) { - case 'style': - case 'script': - case 'noscript': - case 'template': - case 'textarea': - node.skipContent = true - if (type === 'textarea') { - node.props.type = 'textarea' - } - break - case 'input': - if (!node.props.type) { - node.props.type = 'text' - } - case 'xmp': - node.children.push(new VText(node.template)) - break - case 'option': - node.children.push(new VText(trimHTML(node.template))) - break - default: - - if (!node.isVoidTag) { - var childs = lexer(innerHTML, curDeep, maxDeep) - node.children = childs - if (type === 'table') { - addTbody(node.children) - } - } - break - } - var forExpr = node.props['ms-for'] - if (forExpr) { - var cb = node.props['data-for-rendered'] - var cid = cb+':cb' - delete node.props['ms-for'] - nodes.push({ - nodeType: 8, - type: '#comment', - nodeValue: 'ms-for:' + forExpr, - signature: makeHashCode('for'), - cid: cid, - template: avalon.vdomAdaptor(node, 'toHTML') - }) - - if(cb && !avalon.caches[cid]){ - avalon.caches[cid] = Function('return '+ avalon.parseExpr(cb, 'on'))() - } - - nodes.push(node) - node = { - nodeType: 8, - skipContent: true, - type: '#comment', - nodeValue: 'ms-for-end:' - } - } - } - return node - } - //如果直接将tr元素写table下面,那么浏览器将将它们(相邻的那几个),放到一个动态创建的tbody底下 - function addTbody(nodes) { - var tbody, needAddTbody = false, count = 0, start = 0, n = nodes.length - for (var i = 0; i < n; i++) { - var node = nodes[i] - if (!tbody) { - if (node.type === 'tr') { - tbody = { - nodeType: 1, - type: 'tbody', - template: '', - children: [], - props: {} - } - tbody.children.push(node) - needAddTbody = true - if (start === 0) - start = i - nodes[i] = tbody - } - } else { - if (node.type !== 'tr' && node.nodeType === 1) { - tbody = false - } else { - tbody.children.push(node) - count++ - nodes[i] = 0 - } - } - } - - if (needAddTbody) { - for (i = start; i < n; i++) { - if (nodes[i] === 0) { - nodes.splice(i, 1) - i-- - count-- - if (count === 0) { - break + + module.exports = function addField(node, vnode) { + var field = vnode.field + var rules = vnode.props['ms-rules'] + if (rules && !field.validator) { + while (node && node.nodeType === 1) { + var validator = node._ms_validator_ + if (validator) { + field.rules = rules + field.validator = validator + if(avalon.Array.ensure(validator.fields, field)){ + validator.addField(field) } + break } + node = node.parentNode } } } - var ramp = /&/g - var rnowhite = /\S+/g - var rquote = /"/g - var rnogutter = /\s*=\s*/g - function handleProps(str, props) { - str.replace(rnogutter, '=').replace(rnowhite, function (el) { - var arr = el.split('='), value = arr[1] || '', - name = arr[0].toLowerCase() - if (arr.length === 2) { - if (value.indexOf('??') === 0) { - value = value.replace(rfill, fill). - slice(1, -1). - replace(ramp, '&'). - replace(rquote, '"') - } - } - props[name] = value - }) - } - - //form prototype.js - var rtrimHTML = /<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi - function trimHTML(v) { - return String(v).replace(rtrimHTML, '').trim() - } - - - module.exports = lexer - /***/ }, -/* 72 */ +/* 62 */ /***/ function(module, exports, __webpack_require__) { - /** - * ------------------------------------------------------------ - * diff 对比新旧两个虚拟DOM树,根据directive中的diff方法为新虚拟DOM树 - * 添加change, afterChange更新钩子 - * ------------------------------------------------------------ - */ - var emptyArr = [] - // 防止被引用 - var emptyObj = function() { - return { - children: [], props: {} - } - } - var directives = avalon.directives - var rbinding = __webpack_require__(40).binding + var update = __webpack_require__(43) - function diff(current, previous, steps) { - if (!current) - return - for (var i = 0; i < current.length; i++) { - var cur = current[i] - var pre = previous[i] || emptyObj() - switch (cur.nodeType) { - case 3: - if (!cur.skipContent) { - directives.expr.diff(cur, pre, steps) + var dir = avalon.directive('validate', { + //验证单个表单元素 + parse: function (binding, num) { + return 'vnode' + num + '.props["ms-validate"] = ' + avalon.parseExpr(binding) + ';\n' + }, + diff: function (cur, pre, steps, name) { + var validator = cur.props[name] + var p = pre.props[name] + if (p && p.onError && p.addField) { + cur.props[name] = p + } else if (Object(validator) === validator) { + if(validator.$id){//转换为普通对象 + validator = validator.$model + } + cur.props[name] = validator + for(var name in dir.defaults){ + if(!validator[name]){ + validator[name] = dir.defaults[name] } - break - case 8: - if (cur.directive === 'for') { - i = directives['for'].diff(current, previous, steps, i) - } else if (cur.directive) {//if widget - directives[cur.directive].diff(cur, pre, steps) + } + validator.fields = validator.fields || [] + update(cur, this.update, steps, 'validate' ) + + } + }, + update: function (node, vnode) { + var validator = vnode.props['ms-validate'] + node._ms_validator_ = validator + validator.element = node + node.setAttribute("novalidate", "novalidate"); + if (validator.validateAllInSubmit) { + avalon.bind(node, "submit", function (e) { + e.preventDefault() + dir.validateAll.call(validator, validator.onValidateAll) + }) + } + if (typeof validator.onInit === "function") { //vmodels是不包括vmodel的 + validator.onInit.call(node) + } + }, + validateAll: function (callback) { + var validator = this + var fn = typeof callback === "function" ? callback : validator.onValidateAll + var promise = validator.fields.filter(function (field) { + var el = field.element + return el && !el.disabled && validator.element.contains(el) + }).map(function (field) { + return dir.validate(field, true) + }) + var reasons = [] + Promise.all(promise).then(function (array) { + for (var i = 0, el; el = array[i++]; ) { + reasons = reasons.concat(el) + } + if (validator.deduplicateInValidateAll) { + var uniq = {} + reasons = reasons.filter(function (field) { + var el = field.element + var uuid = el.uniqueID || (el.uniqueID = setTimeout("1")) + if (uniq[uuid]) { + return false + } else { + uniq[uuid] = true + return true + } + }) + } + fn.call(validator.element, reasons) //这里只放置未通过验证的组件 + }) + }, + addField: function (field) { + var validator = this + var node = field.element + if (validator.validateInKeyup && (!field.isChanged &&!field.debounceTime)) { + avalon.bind(node, 'keyup', function (e) { + dir.validate(field, 0, e) + }) + } + if (validator.validateInBlur) { + avalon.bind(node, 'blur', function (e) { + dir.validate(field, 0, e) + }) + } + if (validator.resetInFocus) { + avalon.bind(node, 'focus', function (e) { + validator.onReset.call(node, e, field) + }) + } + }, + validate: function (field, isValidateAll, event) { + var promises = [] + var value = field.get(field.vmodel) + var elem = field.element + var validator = field.validator + if (elem.disabled) + return + for (var ruleName in field.rules) { + var ruleValue = field.rules[ruleName] + if (ruleValue === false) + continue + var hook = avalon.validators[ruleName] + var resolve, reject + promises.push(new Promise(function (a, b) { + resolve = a + reject = b + })) + var next = function (a) { + if (field.norequired && value === "") { + a = true } - break - default: - if (!cur.skipAttrs) { - diffProps(cur, pre, steps) + if (a) { + resolve(true) + } else { + var reason = { + element: elem, + data: field.data, + message: elem.getAttribute("data-" + ruleName + "-message") || elem.getAttribute("data-message") || hook.message, + validateRule: ruleName, + getMessage: getMessage + } + resolve(reason) + } + } + field.data = {} + field.data[ruleName] = ruleValue + hook.get(value, field, next) + } + var reasons = [] + //如果promises不为空,说明经过验证拦截器 + var lastPromise = Promise.all(promises).then(function (array) { + for (var i = 0, el; el = array[i++]; ) { + if (typeof el === "object") { + reasons.push(el) } - if (!cur.skipContent) { - diff(cur.children, pre.children || emptyArr, steps) + } + if (!isValidateAll) { + if (reasons.length) { + validator.onError.call(elem, reasons, event) + } else { + validator.onSuccess.call(elem, reasons, event) } - break - } + validator.onComplete.call(elem, reasons, event) + } + return reasons + }) + return lastPromise } - } + }) - function diffProps(current, previous, steps) { - if (current.order) { - try { - current.order.replace(/([^;]+)/g, function (name) { - var match = name.match(rbinding) - var type = match && match[1] - if (directives[type]) { - directives[type].diff(current, previous || emptyObj(), steps, name) - } - return name - }) - } catch (e) { - avalon.log(current, previous, e, 'diffProps error') - } - } - + var rformat = /\\?{{([^{}]+)\}}/gm + function getMessage() { + var data = this.data || {} + return this.message.replace(rformat, function (_, name) { + return data[name] == null ? "" : data[name] + }) + } + dir.defaults = { + addField: dir.addField, + onError: avalon.noop, + onSuccess: avalon.noop, + onComplete: avalon.noop, + onReset: avalon.noop, + validateInBlur: true, //@config {Boolean} true,在blur事件中进行验证,触发onSuccess, onError, onComplete回调 + validateInKeyup: true, //@config {Boolean} true,在keyup事件中进行验证,触发onSuccess, onError, onComplete回调 + validateAllInSubmit: true, //@config {Boolean} true,在submit事件中执行onValidateAll回调 + resetInFocus: true, //@config {Boolean} true,在focus事件中执行onReset回调, + deduplicateInValidateAll: false //@config {Boolean} false,在validateAll回调中对reason数组根据元素节点进行去重 } - avalon.diffProps = diffProps - module.exports = diff - /***/ }, -/* 73 */ -/***/ function(module, exports, __webpack_require__) { - - - /** - * ------------------------------------------------------------ - * batch 同时对N个视图进行全量更新 - * ------------------------------------------------------------ - */ - - var patch = __webpack_require__(64) - +/* 63 */ +/***/ function(module, exports) { - //如果正在更新一个子树,那么将它放到 - var dirtyTrees = {} - var needRenderIds = [] - avalon.suspendUpdate = 0 - var isBatchingUpdates = false - function batchUpdate(id, immediate) { - var vm = typeof id === 'string' ? avalon.vmodels[id] || {} : id - id = vm.$id - if (dirtyTrees[id]) { - avalon.Array.ensure(needRenderIds, id) - } else { - dirtyTrees[id] = true - } - - if ( typeof vm.$render !== 'function' || !vm.$element || isBatchingUpdates) { - return + avalon.directive('rules', { + parse: function (binding, num) { + var rules = binding.expr + if (/{.+}/.test(rules)) { + return 'vnode' + num + '.props["ms-rules"] = ' + avalon.parseExpr(binding) + ';\n' + } + }, + diff: avalon.noop + }) + function isRegExp(value) { + return avalon.type(value) === 'regexp' + } + var rmail = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/i + var rurl = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/ + function isCorrectDate(value) { + if (typeof value === "string" && value) { //是字符串但不能是空字符 + var arr = value.split("-") //可以被-切成3份,并且第1个是4个字符 + if (arr.length === 3 && arr[0].length === 4) { + var year = ~~arr[0] //全部转换为非负整数 + var month = ~~arr[1] - 1 + var date = ~~arr[2] + var d = new Date(year, month, date) + return d.getFullYear() === year && d.getMonth() === month && d.getDate() === date + } } - if (!document.nodeName)//如果是在mocha等测试环境中立即返回 - return - - - var dom = vm.$element - - flushUpdate(function () { - isBatchingUpdates = true - var vtree = vm.$render() || [] - var steps = {count: 0} - - if (vm.$render.dom) { - var _vtree = findVdom(vtree, vm.$id) - if(_vtree){ - dom = vm.$render.dom - vtree = [_vtree] + return false + } + avalon.shadowCopy(avalon.validators, { + pattern: { + message: '必须匹配{{pattern}}这样的格式', + get: function (value, field, next) { + var elem = field.element + var data = field.data + if (!isRegExp(data.pattern)) { + var h5pattern = elem.getAttribute("pattern") + data.pattern = new RegExp('^(?:' + h5pattern + ')$') } + next(data.pattern.test(value)) + return value } - avalon.diff(vtree, dom.vtree || [], steps) - patch([ dom], vtree, null, steps) - steps.count = 0 - dom.vtree = vtree - isBatchingUpdates = false - avalon.log('rerender', vm.$id, new Date - avalon.rerenderStart) - delete dirtyTrees[id] - for (var i in dirtyTrees) {//更新其他子树 - batchUpdate(i, true) - break + }, + digits: { + message: '必须整数', + get: function (value, field, next) {//整数 + next(/^\-?\d+$/.test(value)) + return value } - - }, immediate) - - - } - function findVdom(array, id) { - for (var i = 0, el; el = array[i++]; ) { - if (el.nodeType === 1) { - if (el.props['ms-controller'] === id) { - return el - } else if (el.children) { - var find = findVdom(el.children, id) - if(find){ - return find - } + }, + number: { + message: '必须数字', + get: function (value, field, next) {//数值 + next(isFinite(value)) + return value + } + }, + required: { + message: '必须填写', + get: function (value, field, next) { + next(value !== "") + return value + } + }, + equalto: { + message: '密码输入不一致', + get: function (value, field, next) { + var id = String(field.data.equalto) + var other = avalon(document.getElementById(id)).val() || "" + next(value === other) + return value + } + }, + date: { + message: '日期格式不正确', + get: function (value, field, next) { + var data = field.data + if (avalon.type(data.date) === 'regexp') { + next(data.date.test(value)) + } else { + next(isCorrectDate(value)) } + return value } - } - } - function flushUpdate(callback, immediate ) { - if (immediate) { - callback() - var id = needRenderIds.shift() - if (id) { - batchUpdate(id, true) + }, + url: { + message: 'URL格式不正确', + get: function (value, field, next) { + next(rurl.test(value)) + return value + } + }, + email: { + message: 'email格式不正确', + get: function (value, field, next) { + next(rmail.test(value)) + return value + } + }, + minlength: { + message: '最少输入{{minlength}}个字', + get: function (value, field, next) { + var num = parseInt(field.data.minlength, 10) + next(value.length >= num) + return value + } + }, + maxlength: { + message: '最多输入{{maxlength}}个字', + get: function (value, field, next) { + var num = parseInt(field.data.maxlength, 10) + next(value.length <= num) + return value + } + }, + min: { + message: '输入值不能小于{{min}}', + get: function (value, field, next) { + var num = parseInt(field.data.min, 10) + next(parseFloat(value) >= num) + return value + } + }, + max: { + message: '输入值不能大于{{max}}', + get: function (value, field, next) { + var num = parseInt(field.data.max, 10) + next(parseFloat(value) <= num) + return value + } + }, + chs: { + message: '必须是中文字符', + get: function (value, field, next) { + next(/^[\u4e00-\u9fa5]+$/.test(value)) + return value } - } else { - setTimeout(callback, 0) } - } - - module.exports = avalon.batch = batchUpdate - + }) /***/ }, -/* 74 */ +/* 64 */ /***/ function(module, exports, __webpack_require__) { - - var VText = __webpack_require__(16) - var parseView = __webpack_require__(37) - var resolvedComponents = avalon.resolvedComponents - var componentContainers = {wbr:1, xmp:1, template: 1} - var componentEvents = avalon.oneObject('onInit,onReady,onViewChange,onDispose') - - var needDel = avalon.mix({ - is: 1, - diff: 1, - define: 1, - cached: 1 - }, componentEvents) - avalon.document.createElement('slot') - - avalon.component = function (name, definition) { - //这是定义组件的分支,并将列队中的同类型对象移除 - if (typeof name === 'string') { - if (!avalon.components[name]) { - avalon.components[name] = definition - }//这里没有返回值 - } else { + var patch = __webpack_require__(65) + var update = __webpack_require__(43) - var node = name //node为页面上节点对应的虚拟DOM - var topVm = definition - var wid = node.props.wid - //处理ms-widget的参数 - var optionMixin = {} - function mixinHooks(option, index) { - for (var k in option) { - if(!option.hasOwnProperty(k)) - continue - var v = option[k] - if (componentEvents[k]) { - if (k in optionMixin) { - optionMixin[k].push(v) - } else { - optionMixin[k] = [option[k]] + //ms-imporant ms-controller ms-for ms-widget ms-effect ms-if ... + avalon.directive('if', { + priority: 6, + parse: function (binding, num) { + var vnode = 'vnode' + num + var ret = [ + 'var ifVar = ' + avalon.parseExpr(binding, 'if'), + vnode + '.props["ms-if"] = ifVar;', + 'if(!ifVar){', + vnode + '.nodeType = 8;', + vnode + '.directive="if";', + vnode + '.nodeValue="ms-if"', '}' + ] + return ret.join('\n') + '\n' + }, + diff: function (cur, pre, steps) { + cur.dom = pre.dom + if (cur.nodeType !== pre.nodeType) { + cur.steps = steps + update(cur, this.update, steps, 'if' ) + } + }, + update: function (node, vnode, parent) { + var dtype = node.nodeType + var vtype = vnode.nodeType + if (dtype !== vtype) { + if (vtype === 1) { + //要插入元素节点,将原位置上的注释节点移除并cache + var element = vnode.dom + if (!element) { + element = avalon.vdomAdaptor(vnode, 'toDOM') + vnode.dom = element + var props = vnode.props + for (var prop in props) {//如果一开始是隐藏,那么事件会没有绑上 + if (prop.match(/ms\-on/g)) { + var fun = props[prop] + if (typeof fun === 'function') { + element._ms_context_ = vnode.onVm + avalon.bind(element, prop.split('-')[2], fun) + } + } } - } else if (isFinite(index)) { - optionMixin[k] = v + if (vnode.onVm) delete vnode.onVm } + parent.replaceChild(element, node) + if (vnode.steps.count) { + patch([element], [vnode], parent, vnode.steps) + } + avalon.applyEffect(node, vnode, { + hook: 'onEnterDone' + }) + return (vnode.steps = false) + } else if (vtype === 8) { + //要移除元素节点,在对应位置上插入注释节点 + avalon.applyEffect(node, vnode, { + hook: 'onLeaveDone', + cb: function () { + var comment = node._ms_if_ || + (node._ms_if_ = document.createComment(vnode.nodeValue)) + + parent.replaceChild(comment, node) + } + }) } } - var options = node.props['ms-widget'] || {} - options = Array.isArray(options) ? options : [options] - options.forEach(mixinHooks) - if(optionMixin.cached){ - var cachedVm = avalon.vmodels[optionMixin.$id] - if(cachedVm){ - var _wid = cachedVm.$events.__wid__ - delete resolvedComponents[wid] - wid = _wid - } - } - - var docker = resolvedComponents[wid] - if (!docker) { - resolvedComponents[wid] = node - docker = node + } + }) + + + +/***/ }, +/* 65 */ +/***/ function(module, exports) { + + /** + * ------------------------------------------------------------ + * patch 对某一个视图根据对应的虚拟DOM树进行全量更新 + * ------------------------------------------------------------ + */ + var sp = /^\s*$/ + function patch(nodes, vnodes, parent, steps) { + var next = nodes[0] + if ((!next && !parent) || !steps.count) { + return + } + parent = parent || next.parentNode + for (var i = 0, vn = vnodes.length; i < vn; i++) { + var vnode = vnodes[i] + var node = next + //IE6-8不会生成空白的文本节点,造成虚拟DOM与真实DOM的个数不一致,需要跳过,#1333 + if (avalon.msie < 9 && !vnode.fixIESkip && vnode.nodeType === 3 && sp.test(vnode.nodeValue) ) { + continue } - //如果此组件的实例已经存在,那么重新渲染 - if (docker.render) { - return docker - } - var tagName = node.type.indexOf('-') > 0 ? node.type : optionMixin.is - var placeholder = { - nodeType: 8, - type: '#comment', - directive: 'widget', - props: {'ms-widget': wid}, - nodeValue: 'ms-widget placeholder' + + if (node) { + next = node.nextSibling } - if (!avalon.components[tagName]) { - //如果组件还没有定义,那么返回一个注释节点占位 - return placeholder - } else { - var type = node.type - //判定用户传入的标签名是否符合规格 - if (!componentContainers[type] && !isCustomTag(type)) { - avalon.warn(type + '不合适做组件的标签') - } - //将用户声明组件用的自定义标签(或xmp.template)的template转换成虚拟DOM - if (type === 'xmp' || type === 'template' || node.children.length === 0) { - node.children = avalon.lexer(docker.template) - } - //对于IE6-8,需要对自定义标签进行hack - definition = avalon.components[tagName] - if (!avalon.modern && !definition.fixTag) { - avalon.document.createElement(tagName) - definition.fixTag = 1 - } - //对组件内置的template转换成虚拟DOM - var vtree = avalon.lexer(definition.template.trim()) - if (vtree.length > 1) { - avalon.error('组件必须用一个元素包起来') - } - var widgetNode = vtree[0] - if (widgetNode.type !== tagName) { - avalon.warn('模板容器标签最好为' + tagName) - } - //将用户标签中的属性合并到组件标签的属性里 - for (var k in docker.props) { - if(k !== 'ms-widget'){ - widgetNode.props[k] = docker.props[k] + if (vnode.directive === 'for') { + if (vnode.hasChange) { + if (!node) { + return } - } - - //抽取用户标签里带slot属性的元素,替换组件的虚拟DOM树中的slot元素 - if (definition.soleSlot) { - var slots = {} - var slotName = definition.soleSlot - slots[slotName] = /\S/.test(docker.template) ? node.children : new VText('{{@' + slotName + '}}') - mergeTempale(vtree, slots) - } else if (!node.isVoidTag) { - insertSlots(vtree, node, definition.soleSlot) - } - //开始构建组件的vm的配置对象 - var diff = optionMixin.diff - var define = optionMixin.define - define = define || avalon.directives.widget.define - var $id = optionMixin.$id || avalon.makeHashCode(tagName.replace(/-/g, '_')) - - var defaults = definition.defaults - mixinHooks(defaults, false) - var defineArgs = [topVm, defaults].concat(options) - var vmodel = define.apply(function (a, b) { - for (var k in needDel) { - delete a[k] - delete b[k] + if (node.nodeType === 1) { + var startRepeat = document.createComment(vnode.nodeValue) + parent.insertBefore(startRepeat, node) + vnode.endRepeat = document.createComment('ms-for-end:') + parent.insertBefore(vnode.endRepeat, node.nextSibling) + node = startRepeat + } else {//如果是注释节点 + if (!vnode.endRepeat) { + vnode.endRepeat = getEndRepeat(node) + } } - }, defineArgs) - vmodel.$id = $id - vmodel.$element = topVm.$element - avalon.vmodels[$id] = vmodel - for (k in componentEvents) { - if (optionMixin[k]) { - optionMixin[k].forEach(function (fn) { - vmodel.$watch(k, fn) - }) + if(node.nodeType !== 8){//fix IE6-8 + node = node.nextSibling } + next = vnode.endRepeat.nextSibling + } + } + //ms-for, ms-if, ms-widget会返回false + if (false === execHooks(node, vnode, parent, steps, 'change')) { + if (vnode.repeatCount) { + i += vnode.repeatCount + 1 //修正索引值 } + execHooks(node, vnode, parent, steps, 'afterChange') + continue + } + if (!vnode.skipContent && vnode.children && node && node.nodeType === 1) { + //处理子节点 + patch(avalon.slice(node.childNodes), vnode.children, node, steps) + } + // ms-if=false内的ms-controller无法正确的关联dom + var vmID = vnode.props && vnode.props['ms-controller'] + if (vmID && node) { + var vm = avalon.vmodels[vmID] + if (vm.$render) vm.$render.dom = node + } + //ms-duplex + execHooks(node, vnode, parent, steps, 'afterChange') + if (!steps.count) + break + } + } - //生成组件的render - var num = num || String(new Date - 0).slice(0, 6) - var render = parseView(vtree, num) + '\nreturn (avalon.__widget = vnodes' + num + ');\n' - vmodel.$render = topVm.$render - vmodel.$events.__wid__ = wid - //触发onInit回调 - vmodel.$fire('onInit', { - type: 'init', - vmodel: vmodel, - wid: wid, - target: null - }) + function getEndRepeat(node) { + var isBreak = 0, ret = [], node + while (node) { + if (node.nodeType === 8) { + if (node.nodeValue.indexOf('ms-for:') === 0) { + ++isBreak + } else if (node.nodeValue.indexOf('ms-for-end:') === 0) { + --isBreak + } + } + ret.push(node) + node = node.nextSibling + if (isBreak === 0) { + break + } + } + return ret.pop() + } - avalon.shadowCopy(docker, { - diff: diff, - render: render, - vmodel: vmodel, - cached: !!optionMixin.cached, - placeholder: placeholder - }) - return docker + function execHooks(node, vnode, parent, steps, hookName) { + var hooks = vnode[hookName] + if (hooks) { + for (var hook; hook = hooks.shift(); ) { + steps.count -= 1 + if (false === hook(node, vnode, parent)) { + return false + } } + delete vnode[hookName] } } - var ralphabet = /^[a-z]+$/ + module.exports = patch - function isCustomTag(type) { - return type.length > 3 && type.indexOf('-') > 0 && - ralphabet.test(type.charAt(0) + type.slice(-1)) +/***/ }, +/* 66 */ +/***/ function(module, exports, __webpack_require__) { + + var patch = __webpack_require__(65) + var rforPrefix = /ms-for\:\s*/ + var rforLeft = /^\s*\(\s*/ + var rforRight = /\s*\)\s*$/ + var rforSplit = /\s*,\s*/ + var rforAs = /\s+as\s+([$\w]+)/ + var rident = __webpack_require__(40).ident + var update = __webpack_require__(43) + + var rinvalid = /^(null|undefined|NaN|window|this|\$index|\$id)$/ + function getTrackKey(item){ + var type = typeof item + return item && type === 'object' ? item.$hashcode : type + item } - avalon.renderComponent = function (widgetNode) { - var docker = avalon.resolvedComponents[widgetNode.props.wid] - var order = widgetNode.order - - widgetNode.order = order ? - 'ms-widget;;' + order : 'ms-widget' - if (!isComponentReady(widgetNode)) { - return docker.placeholder + + avalon._each = function (obj, fn) { + if (Array.isArray(obj)) { + for (var i = 0; i < obj.length; i++) { + var item = obj[i] + var key = getTrackKey(item) + fn(i, item, key) + } + } else { + for (var i in obj) { + if (obj.hasOwnProperty(i)) { + fn(i, obj[i], i) + } + } } - if (!docker.renderCount) { - docker.renderCount = 1 + } + var loopMap = {} + function getLoopValue(object){ + if(Array.isArray(object)){ + return object.length+"|"+object.map(getTrackKey).join(';;') + }else{ + var size = 0 + var arr = [] + for(var i in object){ + if(object.hasOwnProperty(i)){ + size++ + arr.push(i) + } + } + return size+"|"+arr.join(';;') } - widgetNode.props['ms-widget'] = docker.props['ms-widget'] - widgetNode.vmodel = docker.vmodel - widgetNode.diff = docker.diff - //移除skipAttrs,以便进行diff - delete widgetNode.skipAttrs - return widgetNode } - function isComponentReady(vnode) { - var isReady = true - try { - hasUnresolvedComponent(vnode) - } catch (e) { - isReady = false + + avalon._checkLoopChange = function(key, obj){ + var cur = getLoopValue(obj) + if(!(key in loopMap)){ + loopMap[key] = cur + return true } - return isReady + if(cur !== loopMap[key]){ + loopMap[key] = cur + return true + } + return false } - function hasUnresolvedComponent(vnode) { - vnode.children.forEach(function (el) { - if (el.nodeType === 8 && el.props) { - if ('ms-widget' in el.props) { - throw 'unresolved' + avalon.directive('for', { + priority: 3, + parse: function (el, num) { + var str = el.nodeValue, aliasAs + str = str.replace(rforAs, function (a, b) { + if (!rident.test(b) || rinvalid.test(b)) { + avalon.error('alias ' + b + ' is invalid --- must be a valid JS identifier which is not a reserved name.') + } else { + aliasAs = b } - } else if (el.children) { - hasUnresolvedComponent(el) + return '' + }) + + var arr = str.replace(rforPrefix, '').split(' in ') + var assign = 'var loop' + num + ' = ' + avalon.parseExpr(arr[1]) + '\n' + var isChange = el.signature+'.hasChange = avalon._checkLoopChange("'+el.signature+'", loop' + num + ')\n' + + var alias = aliasAs ? 'var ' + aliasAs + ' = loop' + num + '\n' : '' + var kv = arr[0].replace(rforLeft, '').replace(rforRight, '').split(rforSplit) + if (kv.length === 1) {//确保avalon._each的回调有三个参数 + kv.unshift('$key') } - }) - } + //分别创建isArray, ____n, ___i, ___v, ___trackKey变量 + return assign +isChange+ alias + 'avalon._each(loop' + num + ', function(' + kv + ', traceKey){\n' - function insertSlots(vtree, node, soleSlot) { - var slots = {} - if (soleSlot) { - slots[soleSlot] = node.children - } else { - node.children.forEach(function (el) { - if (el.nodeType === 1) { - var name = el.props.slot || 'default' - if (slots[name]) { - slots[name].push(el) - } else { - slots[name] = [el] - } + }, + diff: function (current, previous, steps, __index__) { + var cur = current[__index__] + var pre = previous[__index__] || {} + + var isInit = !('directive' in pre) + var isChange = false, i, c, p + if (isInit) { + pre.components = [] + pre.repeatCount = 0 + } + + var quota = pre.components.length + var nodes = current.slice(cur.start, cur.end) + cur.endRepeat = pre.endRepeat + cur.components = getComponents(nodes.slice(1, -1), cur.signature) + var n = Math.max(nodes.length - 2, 0) - pre.repeatCount + if (n > 0) { + var spliceArgs = [__index__ + 1, 0] + for (var i = 0, n = n - 1; i < n; i++) { + spliceArgs.push(null) } - }) - } - mergeTempale(vtree, slots) - } + previous.splice.apply(previous, spliceArgs) + } else if (n < 0) { + previous.splice.apply(previous, [__index__, Math.abs(n)]) + } + cur.action = isInit ? 'init' : 'update' + if (isInit) { + /* eslint-disable no-cond-assign */ + var oldCount = steps.count + var cache = cur.cache = {} + for (i = 0; c = cur.components[i++]; ) { + /* eslint-enable no-cond-assign */ + avalon.diff(c.children, [], steps) + saveInCache(cache, c) + } + cur.removedComponents = {} + //如果没有孩子也要处理一下 + isChange = cur.components.length === 0 || + steps.count !== oldCount - function mergeTempale(vtree, slots) { - for (var i = 0, node; node = vtree[i++]; ) { - if (node.nodeType === 1) { - if (node.type === 'slot') { - var name = node.props.name || 'default' - if (slots[name]) { - var s = slots[name] - vtree.splice.apply(vtree, [i - 1, 1].concat(s)) - if (s.length === 1 && s[0].nodeType === 3) { - removeEmptyText(vtree) + } else { + var cache = pre.cache + var newCache = cur.cache = {} + /* eslint-disable no-cond-assign */ + for (i = 0; c = cur.components[i++]; ) { + /* eslint-enable no-cond-assign */ + var p = isInCache(cache, c.key) + if (p) { + if (!isChange) {//如果位置发生了变化 + isChange = c.index !== p.index + } + quota-- + c.nodes = p.nodes + avalon.diff(c.children, p.children, steps) + } else if (quota) { + p = fuzzyMatchCache(cache, c.key) + if (p) { + quota-- + isChange = true //内容发生变化 + c.nodes = p.nodes + avalon.diff(c.children, p.children, steps) } } - } else { - mergeTempale(node.children, slots) + if (!c.nodes) {//这是新添加的元素 + isChange = true + avalon.diff(c.children, [], steps) + } + + saveInCache(newCache, c) + } + + for (i in cache) { + cur.removedComponents = cache + isChange = true + break } + + } + pre.components.length = 0 //release memory + delete pre.cache + if (isChange) { + cur.steps = steps + update(cur, this.update, steps, 'for') } - } - return vtree - } + return __index__ + nodes.length - 1 + + }, + update: function (startRepeat, vnode, parent) { + var action = vnode.action + var endRepeat = vnode.endRepeat + var fragment = document.createDocumentFragment() + if (action === 'init') { + //在ms-widget中,这部分内容会先行被渲染出来 + var hasRender = false + var node = startRepeat.nextSibling + while (node && node !== endRepeat) { + if (node.nodeType === 8) { + hasRender = node.nodeValue === vnode.signature + if (hasRender) { + vnode.hasRender = true + break + } + } + node = node.nextSibling - function removeEmptyText(nodes) { - //如果定义组件时,slot元素两旁有大片空白,且slot元素又是被一个文本节点替代时,需要合并这三个文本节点 - for (var i = 0, el; el = nodes[i]; i++) { - if (el.skipContent === false && el.nodeType === 3) { - var pre = nodes[i - 1] - var next = nodes[i + 1] - if (pre && pre.nodeType === 3 && !/\S/.test(pre.nodeValue)) { - avalon.Array.remove(nodes, pre) - --i } - if (next && next.nodeType === 3 && !/\S/.test(next.nodeValue)) { - avalon.Array.remove(nodes, next) + if (!hasRender) { + node = startRepeat.nextSibling + while (node && node !== endRepeat) { + parent.removeChild(node) + node = startRepeat.nextSibling + } } } - } - } - - -/***/ }, -/* 75 */, -/* 76 */, -/* 77 */ -/***/ function(module, exports, __webpack_require__) { - - - var $$midway = {} - var $$skipArray = __webpack_require__(78) - var dispatch = __webpack_require__(79) - var $emit = dispatch.$emit - var $watch = dispatch.$watch - - - function makeFire($vmodel, heirloom) { - heirloom.__vmodel__ = $vmodel - var hide = $$midway.hideProperty - hide($vmodel, '$events', heirloom) - hide($vmodel, '$watch', function () { - if (arguments.length === 2) { - return $watch.apply($vmodel, arguments) - } else { - throw '$watch方法参数不对' + var domTemplate = avalon.parseHTML(vnode.template) + + var key = vnode.signature + for (var i in vnode.removedComponents) { + var el = vnode.removedComponents[i] + if (el.nodes) { + el.nodes.forEach(function (n, k) { + if (n.parentNode) { + avalon.applyEffect(n, el.children[k], { + hook: 'onLeaveDone', + cb: function () { + n.parentNode.removeChild(n) + }, + staggerKey: key + 'leave' + }) + } + }) + el.nodes.length = el.children.length = 0 + } } - }) - hide($vmodel, '$fire', function (expr, a, b) { - var list = $vmodel.$events[expr] - $emit(list, $vmodel, expr, a, b) - }) - } + delete vnode.removedComponents - function isSkip(key, value, skipArray) { - // 判定此属性能否转换访问器 - return key.charAt(0) === '$' || - skipArray[key] || - (typeof value === 'function') || - (value && value.nodeName && value.nodeType > 0) - } + var insertPoint = startRepeat - function modelAdaptor(definition, old, heirloom, options) { - //如果数组转换为监控数组 - if (Array.isArray(definition)) { - return $$midway.arrayFactory(definition, old, heirloom, options) - } else if (Object(definition) === definition && typeof definition !== 'function') { - //如果此属性原来就是一个VM,拆分里面的访问器属性 - if (old && old.$id) { - ++avalon.suspendUpdate - //1.5带来的优化方案 - if (old.$track !== Object.keys(definition).sort().join(';;')) { - var vm = $$midway.slaveFactory(old, definition, heirloom, options) + for (var i = 0; i < vnode.components.length; i++) { + var com = vnode.components[i] + var cnodes = com.nodes + if (cnodes) { + if (insertPoint.nextSibling !== cnodes[0]) { + var moveFragment = fragment.cloneNode(false) + for (var k = 0, cc; cc = cnodes[k++]; ) { + moveFragment.appendChild(cc) + } + parent.insertBefore(moveFragment, insertPoint.nextSibling) + applyEffects(com.nodes, com.children, { + hook: 'onMoveDone', + staggerKey: key + 'move' + }) + } + } else if (vnode.hasRender) { + //添加nodes属性但不用插入节点 + var cnodes = com.nodes = [] + insertPoint = insertPoint.nextSibling + while (insertPoint && insertPoint !== vnode.endRepeat) { + cnodes.push(insertPoint) + if (insertPoint.nodeValue === vnode.signature) { + break + } + insertPoint = insertPoint.nextSibling + } } else { - vm = old + //添加nodes属性并插入节点 + var newFragment = domTemplate.cloneNode(true) + newFragment.appendChild(document.createComment(vnode.signature)) + cnodes = com.nodes = avalon.slice(newFragment.childNodes) + parent.insertBefore(newFragment, insertPoint.nextSibling) + applyEffects(com.nodes, com.children, { + hook: 'onEnterDone', + staggerKey: key + 'enter' + }) } - for (var i in definition) { - if ($$skipArray[i]) - continue - vm[i] = definition[i] + insertPoint = cnodes[cnodes.length - 1] + if (!insertPoint) { + break } - --avalon.suspendUpdate - return vm - } else { - vm = $$midway.masterFactory(definition, heirloom, options) - return vm } - } else { - return definition + var entity = [], vnodes = [] + vnode.components.forEach(function (c) { + entity.push.apply(entity, c.nodes) + vnodes.push.apply(vnodes, c.children) + }) + vnode.repeatCount = vnodes.length + patch(entity, vnodes, parent, vnode.steps) + var cb = avalon.caches[vnode.cid] + if (cb) { + cb.call(vnode.vmodel, { + type: "rendered", + target: startRepeat, + endRepeat: endRepeat, + signature: vnode.signature + }) + } + return false } - } - $$midway.modelAdaptor = modelAdaptor + }) - function makeAccessor(sid, spath, heirloom) { - var old = NaN - function get() { - return old - } - get.heirloom = heirloom - return { - get: get, - set: function (val) { - if (old === val) { - return - } - if (val && typeof val === 'object') { - val = $$midway.modelAdaptor(val, old, heirloom, { - pathname: spath, - id: sid - }) + function getRepeatRange(nodes, i) { + var isBreak = 0, ret = [], node + while (node = nodes[i++]) { + if (node.type === '#comment') { + if (node.nodeValue.indexOf('ms-for:') === 0) { + isBreak++ + } else if (node.nodeValue.indexOf('ms-for-end:') === 0) { + isBreak-- } - var older = old - old = val - - var vm = heirloom.__vmodel__ - if (this.$hashcode && vm && !avalon.suspendUpdate) { - //★★确保切换到新的events中(这个events可能是来自oldProxy) - if (heirloom !== vm.$events) { - get.heirloom = vm.$events - } - //如果这个属性是组件配置对象中的属性,那么它需要触发组件的回调 - emitWidget(get.$decompose, spath, val, older) - //触发普通属性的回调 - if (spath.indexOf('*') === -1) { - $emit(get.heirloom[spath], vm, spath, val, older) - } - //如果这个属性是数组元素上的属性 - emitArray(sid, vm, spath, val, older) - //如果这个属性存在通配符 - emitWildcard(get.heirloom, vm, spath, val, older) + } + ret.push(node) + if (isBreak === 0) { + break + } + } + return ret + } - avalon.rerenderStart = new Date - var dotIndex = vm.$id.indexOf('.') - if (dotIndex > 0) { - avalon.batch(vm.$id.slice(0, dotIndex), true) - } else { - avalon.batch(vm, true) - } + //将要循环的节点根据锚点元素再分成一个个更大的单元,用于diff + function getComponents(nodes, signature) { + var components = [] + var com = { + children: [] + } + for (var i = 0, el; el = nodes[i]; i++) { + if (el.nodeType === 8 && el.nodeValue === signature) { + com.children.push(el) + com.key = el.key + com.index = components.length + components.push(com) + com = { + children: [] } - }, - enumerable: true, - configurable: true + } else { + com.children.push(el) + } } + return components } - var rtopsub = /([^.]+)\.(.+)/ - function emitArray(sid, vm, spath, val, older) { - if (sid.indexOf('.*.') > 0) { - var arr = sid.match(rtopsub) - var top = avalon.vmodels[ arr[1] ] - if (top) { - var path = arr[2] - $emit(top.$events[ path ], vm, spath, val, older) + var rfuzzy = /^(string|number|boolean)/ + var rkfuzzy = /^_*(string|number|boolean)/ + function fuzzyMatchCache(cache, id) { + var m = id.match(rfuzzy) + if (m) { + var fid = m[1] + for (var i in cache) { + var n = i.match(rkfuzzy) + if (n && n[1] === fid) { + return isInCache(cache, i) + } } } } - function emitWidget(whole, spath, val, older) { - if (whole && whole[spath]) { - var wvm = whole[spath] - if (!wvm.$hashcode) { - delete whole[spath] - } else { - var wpath = spath.replace(/^[^.]+\./, '') - if (wpath !== spath) { - $emit(wvm.$events[wpath], wvm, wpath, val, older) + // 新位置: 旧位置 + function isInCache(cache, id) { + var c = cache[id], cid = id + if (c) { + var ctack = cache["***" + id] + if (ctack) { + var a = ctack.pop() + delete cache[a.id] + if (ctack.length == 0) + delete cache["***" + id] + return a.c + } + var stack = [{id: id, c: c}] + while (1) { + id += '_' + if (cache[id]) { + stack.push({ + id: id, + c: cache[id] + }) + } else { + break } } + var a = stack.pop() + delete cache[a.id] + if (stack.length) { + cache['***' + cid] = stack + } + return a.c } + return c } - function emitWildcard(obj, vm, spath, val, older) { - if (obj.__fuzzy__) { - obj.__fuzzy__.replace(avalon.rword, function (expr) { - var list = obj[expr] - var reg = list.reg - if (reg && reg.test(spath)) { - $emit(list, vm, spath, val, older) + function saveInCache(cache, component) { + var trackId = component.key + if (!cache[trackId]) { + cache[trackId] = component + } else { + while (1) { + trackId += '_' + if (!cache[trackId]) { + cache[trackId] = component + break } - return expr - }) + } } } + var applyEffects = function (nodes, vnodes, opts) { + vnodes.forEach(function (el, i) { + avalon.applyEffect(nodes[i], vnodes[i], opts) + }) + } - function define(definition) { - var $id = definition.$id - if (!$id && avalon.config.debug) { - avalon.warn('vm.$id must be specified') - } - if (avalon.vmodels[$id]) { - throw Error('error:['+ $id+ '] had defined!') - } - var vm = $$midway.masterFactory(definition, {}, { - pathname: '', - id: $id, - master: true - }) - return avalon.vmodels[$id] = vm +/***/ }, +/* 67 */ +/***/ function(module, exports, __webpack_require__) { - } + var disposeDetectStrategy = __webpack_require__(68) + var patch = __webpack_require__(65) + var update = __webpack_require__(43) - function arrayFactory(array, old, heirloom, options) { - if (old && old.splice) { - var args = [0, old.length].concat(array) - ++avalon.suspendUpdate - old.splice.apply(old, args) - --avalon.suspendUpdate - return old - } else { - for (var i in __array__) { - array[i] = __array__[i] + //插入点机制,组件的模板中有一些slot元素,用于等待被外面的元素替代 + var dir = avalon.directive('widget', { + priority: 4, + parse: function (binding, num, elem) { + var isVoidTag = !!elem.isVoidTag + elem.isVoidTag = true + var wid = elem.props.wid || (elem.props.wid = avalon.makeHashCode('w')) + avalon.resolvedComponents[wid] = { + props: avalon.shadowCopy({}, elem.props), + template: elem.template } + var ret = [ + 'vnode' + num + '._isVoidTag = ' + isVoidTag, + 'vnode' + num + '.props.wid = "' + wid + '"', + 'vnode' + num + '.template = ' + avalon.quote(elem.template), + 'vnode' + num + '.props["ms-widget"] = ' + avalon.parseExpr(binding, 'widget'), + 'vnode' + num + ' = avalon.component(vnode' + num + ', __vmodel__)', + 'if(typeof vnode' + num + '.render === "string"){', + 'avalon.__widget = [];', + 'var __backup__ = __vmodel__;', + '__vmodel__ = vnode' + num + '.vmodel;', + 'try{eval(" new function(){"+ vnode' + num + '.render +"}");', + '}catch(e){avalon.warn(e)', '}', + 'vnode' + num + ' = avalon.renderComponent(avalon.__widget[0])', '}', + '__vmodel__ = __backup__;'] + return ret.join('\n') + '\n' + }, + define: function () { + return avalon.mediatorFactory.apply(this, arguments) + }, + diff: function (cur, pre, steps) { + var coms = avalon.resolvedComponents + var wid = cur.props.wid + var docker = coms[wid] + if (!docker || !docker.renderCount) { + steps.count += 1 + cur.change = [this.replaceByComment] + } else if (docker.renderCount && docker.renderCount < 2) { + cur.steps = steps + update(cur, this.replaceByComponent, steps, 'widget' ) - array.notify = function (a, b, c, d) { - var vm = heirloom.__vmodel__ - if (vm) { - var path = a === null || a === void 0 ? - options.pathname : - options.pathname + '.' + a - vm.$fire(path, b, c) - if (!d && !avalon.suspendUpdate) { - avalon.rerenderStart = new Date - avalon.batch(vm, true) - } + function fireReady(dom, vnode) { + cur.vmodel.$fire('onReady', { + type: 'ready', + target: dom, + wid: wid, + vmodel: vnode.vmodel + }) + docker.renderCount = 2 } - } - - var hashcode = avalon.makeHashCode('$') - options.array = true - options.hashcode = hashcode - options.id = options.id || hashcode - $$midway.makeObserver(array, heirloom, {}, {}, options) - - for (var j = 0, n = array.length; j < n; j++) { - array[j] = modelAdaptor(array[j], 0, {}, { - id: array.$id + '.*', - master: true - }) - } - return array - } - } - $$midway.arrayFactory = arrayFactory + update(cur, fireReady, steps, 'widget', 'afterChange' ) - var __array__ = { - set: function (index, val) { - if (((index >>> 0) === index) && this[index] !== val) { - if (index > this.length) { - throw Error(index + 'set方法的第一个参数不能大于原数组长度') + } else { + var needUpdate = !cur.diff || cur.diff(cur, pre, steps) + cur.skipContent = !needUpdate + var viewChangeObservers = cur.vmodel.$events.onViewChange + if (viewChangeObservers && viewChangeObservers.length) { + steps.count += 1 + cur.afterChange = [function (dom, vnode) { + var preHTML = pre.outerHTML + var curHTML = cur.outerHTML || + (cur.outerHTML = avalon.vdomAdaptor(cur, 'toHTML')) + if (preHTML !== curHTML) { + cur.vmodel.$fire('onViewChange', { + type: 'viewchange', + target: dom, + wid: wid, + vmodel: vnode.vmodel + }) + } + docker.renderCount++ + }] } - this.splice(index, 1, val) + } }, - contains: function (el) { //判定是否包含 - return this.indexOf(el) !== -1 - }, - ensure: function (el) { - if (!this.contains(el)) { //只有不存在才push - this.push(el) + addDisposeMonitor: function (dom) { + if (window.chrome && window.MutationEvent) { + disposeDetectStrategy.byMutationEvent(dom) + } else if (Object.defineProperty && window.Node) { + disposeDetectStrategy.byRewritePrototype(dom) + } else { + disposeDetectStrategy.byPolling(dom) } - return this - }, - pushArray: function (arr) { - return this.push.apply(this, arr) }, - remove: function (el) { //移除第一个等于给定值的元素 - return this.removeAt(this.indexOf(el)) + replaceByComment: function (dom, node, parent) { + var comment = document.createComment(node.nodeValue) + if (dom) { + parent.replaceChild(comment, dom) + } else { + parent.appendChild(comment) + } }, - removeAt: function (index) { //移除指定索引上的元素 - if ((index >>> 0) === index) { - return this.splice(index, 1) + replaceByComponent: function (dom, node, parent) { + var hasDdash = node.type.indexOf('-') > 0 + var hasDetect = false + if (hasDdash && document.registerElement) { + //必须在自定义标签实例化时,注册它 + disposeDetectStrategy.byCustomElement(node.type) + hasDetect = true } - return [] - }, - clear: function () { - this.removeAll() - return this + var com = avalon.vdomAdaptor(node, 'toDOM') + node.ouerHTML = avalon.vdomAdaptor(node, 'toHTML') + if (dom) { + parent.replaceChild(com, dom) + } else { + parent.appendChild(com) + } + patch([com], [node], parent, node.steps) + if (!hasDetect) { + dir.addDisposeMonitor(com) + } + return false } - } - avalon.define = define - - module.exports = { - $$midway: $$midway, - $$skipArray: $$skipArray, - isSkip: isSkip, - __array__: __array__, - makeFire: makeFire, - makeAccessor: makeAccessor, - modelAdaptor: modelAdaptor - } + }) -/***/ }, -/* 78 */ -/***/ function(module, exports) { - /** - * - $$skipArray:是系统级通用的不可监听属性 - $skipArray: 是当前对象特有的不可监听属性 - 不同点是 - $$skipArray被hasOwnProperty后返回false - $skipArray被hasOwnProperty后返回true - */ - module.exports = avalon.oneObject('$id,$render,$track,$element,$watch,$fire,$events,$model,$skipArray,$accessors,$hashcode,__proxy__,__data__,__const__') + // http://www.besteric.com/2014/11/16/build-blog-mirror-site-on-gitcafe/ /***/ }, -/* 79 */ +/* 68 */ /***/ function(module, exports) { - - /** - * ------------------------------------------------------------ - * 属性监听系统 - * ------------------------------------------------------------ - */ - - function adjustVm(vm, expr) { - var toppath = expr.split(".")[0], other - try { - if (vm.hasOwnProperty(toppath)) { - if (vm.$accessors) { - other = vm.$accessors[toppath].get.heirloom.__vmodel__ - } else { - other = Object.getOwnPropertyDescriptor(vm, toppath).get.heirloom.__vmodel__ - } - - } - } catch (e) { + //用于chrome, safari + var tags = {} + function byCustomElement(name) { + if (tags[name]) + return + tags[name] = true + var prototype = Object.create(HTMLElement.prototype) + prototype.detachedCallback = function () { + var dom = this + setTimeout(function () { + fireDisposeHook(dom) + }) } - return other || vm + document.registerElement(name, prototype) } - function toRegExp(expr) { - var arr = expr.split('.') - return new RegExp("^" + arr.map(function (el) { - return el === '*' ? '(?:[^.]+)' : el - }).join('\\.') + '$', 'i') + //http://stackoverflow.com/questions/11425209/are-dom-mutation-observers-slower-than-dom-mutation-events + //http://stackoverflow.com/questions/31798816/simple-mutationobserver-version-of-domnoderemovedfromdocument + function byMutationEvent(dom) { + dom.addEventListener("DOMNodeRemovedFromDocument", function () { + setTimeout(function () { + fireDisposeHook(dom) + }) + }) } - function addFuzzy(add, obj, expr) { - if (add) { - if (obj.__fuzzy__) { - if (obj.__fuzzy__.indexOf(',' + expr) === -1) { - obj.__fuzzy__ += ',' + expr - } - } else { - obj.__fuzzy__ = expr - } + //用于IE8+, firefox + function byRewritePrototype() { + if (byRewritePrototype.execute) { + return } - } - function $watch(expr, callback) { - var fuzzy = expr.indexOf('.*') > 0 || expr === '*' - var vm = fuzzy ? this : $watch.adjust(this, expr) - var hive = vm.$events - var list = hive[expr] || (hive[expr] = []) - if (fuzzy) { - list.reg = list.reg || toRegExp(expr) + byRewritePrototype.execute = true + var p = Node.prototype + var _removeChild = p.removeChild + p.removeChild = function (a, b) { + _removeChild.call(this, a, b) + if (a.nodeType === 1) { + setTimeout(function () { + fireDisposeHook(a) + }) + } + return a } - addFuzzy(fuzzy, hive, expr) - if (vm !== this) { - addFuzzy(fuzzy, this.$events, expr) - this.$events[expr] = list + var _replaceChild = p.replaceChild + p.replaceChild = function (a, b) { + _replaceChild.call(this, a, b) + if (a.nodeType === 1) { + setTimeout(function () { + fireDisposeHook(a) + }) + } + return a } - - avalon.Array.ensure(list, callback) - - return function () { - avalon.Array.remove(list, callback) + var _innerHTML = p.innerHTML + p.innerHTML = function (html) { + var all = this.getElementsByTagName('*') + _innerHTML.call(this, html) + fireDisposedComponents(all) + } + var _appendChild = p.appendChild + p.appendChild = function (a) { + _appendChild.call(this, a) + if (a.nodeType === 1 && this.nodeType === 11) { + setTimeout(function () { + fireDisposeHook(a) + }) + } + return a + } + var _insertBefore = p.insertBefore + p.insertBefore = function (a) { + _insertBefore.call(this, a) + if (a.nodeType === 1 && this.nodeType === 11) { + setTimeout(function () { + fireDisposeHook(a) + }) + } + return a } } - $watch.adjust = adjustVm - /** - * $fire 方法的内部实现 - * - * @param {Array} list 订阅者数组 - * @param {Component} vm - * @param {String} path 监听属性名或路径 - * @param {Any} a 当前值 - * @param {Any} b 过去值 - * @param {Number} i 如果抛错,让下一个继续执行 - * @returns {undefined} - */ - function $emit(list, vm, path, a, b, i) { - if (list && list.length) { - try { - for (i = i || list.length - 1; i >= 0; i--) { - var callback = list[i] - callback.call(vm, a, b, path) - } - } catch (e) { - if (i - 1 > 0) - $emit(list, vm, path, a, b, i - 1) - avalon.log(e, path) - } + //用于IE6,7 + var checkDisposeNodes = [] + var checkID = 0 + function byPolling(dom) { + avalon.Array.ensure(checkDisposeNodes, dom) + if (!checkID) { + checkID = setInterval(function () { + for (var i = 0, el; el = checkDisposeNodes[i++]; ) { + if (false === fireDisposeHook(el)) { + avalon.Array.removeAt(checkDisposeNodes, i) + --i + } + } + if (checkDisposeNodes.length == 0) { + clearInterval(checkID) + checkID = 0 + } + }, 1000) } } module.exports = { - $emit: $emit, - $watch: $watch, - adjustVm: adjustVm + byPolling: byPolling, + byMutationEvent: byMutationEvent, + byCustomElement: byCustomElement, + byRewritePrototype: byRewritePrototype } + function fireDisposeHook(el) { + if (el.nodeType === 1 && el.getAttribute('wid') && !avalon.contains(avalon.root, el)) { + var wid = el.getAttribute('wid') + var docker = avalon.resolvedComponents[ wid ] + var vm = docker.vmodel + var cached = !!docker.cached + docker.vmodel.$fire("onDispose", { + type: 'dispose', + target: el, + vmodel: vm, + cached: cached + }) + if (docker && docker.vmodel && !cached) { + vm.$element = null + vm.$hashcode = false + delete docker.vmodel + delete avalon.resolvedComponents[ wid ] + } + return false + } + } -/***/ }, -/* 80 */, -/* 81 */, -/* 82 */ -/***/ function(module, exports, __webpack_require__) { - - - var avalon = __webpack_require__(3) - var browser = __webpack_require__(4) - - avalon.shadowCopy(avalon, browser) - - __webpack_require__(83) - __webpack_require__(6) - __webpack_require__(7) - - module.exports = avalon + function fireDisposedComponents(nodes) { + for (var i = 0, el; el = nodes[i++]; ) { + fireDisposeHook(el) + } + } /***/ }, -/* 83 */ -/***/ function(module, exports) { - - //这里放置存在异议的方法 +/* 69 */ +/***/ function(module, exports, __webpack_require__) { - var serialize = avalon.inspect - var rwindow = /^\[object (?:Window|DOMWindow|global)\]$/ - var rarraylike = /(Array|List|Collection|Map|Arguments)\]$/ + var support = __webpack_require__(70) + var Cache = __webpack_require__(26) + var update = __webpack_require__(43) - avalon.quote = JSON.stringify + avalon.directive('effect', { + priority: 5, + parse: function (binding, num) { + return 'vnode' + num + '.props["ms-effect"] = ' + avalon.parseExpr(binding) + ';\n' + }, + diff: function (cur, pre, steps, name) { + var curObj = cur.props[name] + if(typeof curObj === 'string'){ + var is = curObj + curObj = cur.props[name] = { + is: is + } + + }else if (Array.isArray(curObj)) { + curObj = cur.props[name] = avalon.mix.apply({}, curObj) + } + + curObj.action = curObj.action || 'enter' + + if (Object(curObj) === curObj) { + var preObj = pre.props[name] + if ( Object(preObj) !== preObj || diffObj(curObj, preObj )) { + update(cur, this.update, steps, 'effect', 'afterChange') - // avalon.type - var class2type = {} - 'Boolean Number String Function Array Date RegExp Object Error'.replace(avalon.rword, function (name) { - class2type['[object ' + name + ']'] = name.toLowerCase() + } + } + }, + update: function (dom, vnode, parent, option) { + if(dom.animating ){ + return + } + dom.animating = true + var localeOption = vnode.props['ms-effect'] + var type = localeOption.is + option = option || {} + if(!type){//如果没有指定类型 + return avalon.warn('need is option') + } + + var effects = avalon.effects + if(support.css && !effects[type]){ + avalon.effect(type, {}) + } + var globalOption = effects[type] + if(!globalOption){//如果没有定义特效 + return avalon.warn(type+' effect is undefined') + } + var action = option.action || localeOption.action + var Effect = avalon.Effect + if (typeof Effect.prototype[action] !== 'function'){ + return avalon.warn(action+' action is undefined') + } + var effect = new Effect(dom) + var finalOption = avalon.mix(option, globalOption, localeOption) + if (finalOption.queue) { + animationQueue.push(function () { + effect[action](finalOption) + }) + callNextAnimation() + } else { + setTimeout(function(){ + effect[action](finalOption) + },4) + } + } }) - - avalon.type = function (obj) { //取得目标的类型 - if (obj == null) { - return String(obj) + function diffObj(a, b){ + for(var i in a){ + if(a[i] !== b[i]) + return true } - // 早期的webkit内核浏览器实现了已废弃的ecma262v4标准,可以将正则字面量当作函数使用,因此typeof在判定正则时会返回function - return typeof obj === 'object' || typeof obj === 'function' ? - class2type[serialize.call(obj)] || 'object' : - typeof obj + return false } - - avalon.isFunction = function (fn) { - return typeof fn === 'function' + var animationQueue = [] + function callNextAnimation() { + if (animationQueue.lock) + return + var fn = animationQueue[0] + if (fn) { + callNextAnimation.lock = true + fn() + } } - avalon.isWindow = function (obj) { - return rwindow.test(serialize.call(obj)) - } + avalon.effects = {} + //这里定义CSS动画 - /*判定是否是一个朴素的javascript对象(Object),不是DOM对象,不是BOM对象,不是自定义类的实例*/ - avalon.isPlainObject = function (obj) { - // 简单的 typeof obj === 'object'检测,会致使用isPlainObject(window)在opera下通不过 - return serialize.call(obj) === '[object Object]' && - Object.getPrototypeOf(obj) === Object.prototype + avalon.effect = function (name, definition) { + avalon.effects[name] = definition || {} + if (support.css) { + if (!definition.enterClass) { + definition.enterClass = name + '-enter' + } + if (!definition.enterActiveClass) { + definition.enterActiveClass = definition.enterClass + '-active' + } + if (!definition.leaveClass) { + definition.leaveClass = name + '-leave' + } + if (!definition.leaveActiveClass) { + definition.leaveActiveClass = definition.leaveClass + '-active' + } + } + if (!definition.action) { + definition.action = 'enter' + } } - //与jQuery.extend方法,可用于浅拷贝,深拷贝 - avalon.mix = avalon.fn.mix = function () { - var options, name, src, copy, copyIsArray, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false - - // 如果第一个参数为布尔,判定是否深拷贝 - if (typeof target === 'boolean') { - deep = target - target = arguments[1] || {} - i++ - } - //确保接受方为一个复杂的数据类型 - if (typeof target !== 'object' && typeof target !== 'function') { - target = {} - } + var Effect = function (el) { + this.el = el + } + avalon.Effect = Effect + Effect.prototype = { + enter: createAction('Enter'), + leave: createAction('Leave'), + move: createAction('Move') + } - //如果只有一个参数,那么新成员添加于mix所在的对象上 - if (i === length) { - target = this - i-- - } + var rsecond = /\d+s$/ + function toMillisecond(str){ + var ratio = rsecond.test(str) ? 1000 : 1 + return parseFloat(str) * ratio + } - for (; i < length; i++) { - //只处理非空参数 - if ((options = arguments[i]) != null) { - for (name in options) { - src = target[name] - try { - copy = options[name] //当options为VBS对象时报错 - } catch (e) { - continue - } + function execHooks(options, name, el) { + var list = options[name] + list = Array.isArray(list) ? list : typeof list === 'function' ? [list] : [] + list.forEach(function (fn) { + fn && fn(el) + }) + } + var staggerCache = new Cache(128) - // 防止环引用 - if (target === copy) { - continue + function createAction(action) { + var lower = action.toLowerCase() + return function (option) { + var elem = this.el + var $el = avalon(elem) + var enterAnimateDone + var staggerTime = isFinite(option.stagger) ? option.stagger * 1000 : 0 + if(staggerTime){ + if(option.staggerKey){ + var stagger = staggerCache.get(option.staggerKey) || + staggerCache.put(option.staggerKey, { + count:0, + items:0 + }) + stagger.count++ + stagger.items++ + } + } + var staggerIndex = stagger && stagger.count || 0 + var animationDone = function(e) { + var isOk = e !== false + elem.animating = void 0 + enterAnimateDone = true + var dirWord = isOk ? 'Done' : 'Abort' + execHooks(option, 'on' + action + dirWord, elem) + avalon.unbind(elem,support.transitionEndEvent) + avalon.unbind(elem,support.animationEndEvent) + if(stagger){ + if(--stagger.items === 0){ + stagger.count = 0 } - if (deep && copy && (avalon.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) { - - if (copyIsArray) { - copyIsArray = false - clone = src && Array.isArray(src) ? src : [] + } + if(option.queue){ + animationQueue.lock = false + animationQueue.shift() + callNextAnimation() + } + } + execHooks(option, 'onBefore' + action, elem) - } else { - clone = src && avalon.isPlainObject(src) ? src : {} - } + if (option[lower]) { + option[lower](elem, function (ok) { + animationDone(ok !== false) + }) + } else if (support.css) { + + $el.addClass(option[lower + 'Class']) + if(lower === 'leave'){ + $el.removeClass(option.enterClass+' '+option.enterActiveClass) + }else if(lower === 'enter'){ + $el.removeClass(option.leaveClass+' '+option.leaveActiveClass) + } - target[name] = avalon.mix(deep, clone, copy) - } else if (copy !== void 0) { - target[name] = copy + $el.bind(support.transitionEndEvent, animationDone) + $el.bind(support.animationEndEvent, animationDone) + setTimeout(function () { + enterAnimateDone = avalon.root.offsetWidth === NaN + $el.addClass(option[lower + 'ActiveClass']) + var computedStyles = window.getComputedStyle(elem) + var tranDuration = computedStyles[support.transitionDuration] + var animDuration = computedStyles[support.animationDuration] + var time = toMillisecond(tranDuration) || toMillisecond(animDuration) + if (!time === 0) { + animationDone(false) + }else if(!staggerTime ){ + setTimeout(function(){ + if(!enterAnimateDone){ + animationDone(false) + } + },time + 130 ) } - } - } - } - return target - } - - /*判定是否类数组,如节点集合,纯数组,arguments与拥有非负整数的length属性的纯JS对象*/ - function isArrayLike(obj) { - if (obj && typeof obj === 'object') { - var n = obj.length, - str = serialize.call(obj) - if (rarraylike.test(str)) { - return true - } else if (str === '[object Object]' && n === (n >>> 0)) { - return true //由于ecma262v5能修改对象属性的enumerable,因此不能用propertyIsEnumerable来判定了 + }, 17+ staggerTime * staggerIndex)// = 1000/60 } } - return false } - - avalon.each = function (obj, fn) { - if (obj) { //排除null, undefined - var i = 0 - if (isArrayLike(obj)) { - for (var n = obj.length; i < n; i++) { - if (fn(i, obj[i]) === false) - break - } - } else { - for (i in obj) { - if (obj.hasOwnProperty(i) && fn(i, obj[i]) === false) { - break - } + avalon.applyEffect = function(node, vnode, opts){ + var cb = opts.cb + var hook = opts.hook + var curEffect = vnode.props && vnode.props['ms-effect'] + if(curEffect && !avalon.document.hidden ){ + var old = curEffect[hook] + if(cb){ + if(Array.isArray(old)){ + old.push(cb) + }else if(old){ + curEffect[hook] = [old, cb] + }else{ + curEffect[hook] = [cb] } } + getAction(opts) + node.animate = true + avalon.directives.effect.update(node,vnode, 0, avalon.shadowCopy({},opts) ) + + }else if(cb){ + cb() } } - module.exports = { - avalon: avalon, - isArrayLike: isArrayLike + function getAction(opts){ + if(!opts.acton){ + opts.action = opts.hook.replace(/^on/,'').replace(/Done$/,'').toLowerCase() + } } - -/***/ }, -/* 84 */ -/***/ function(module, exports, __webpack_require__) { - - - /********************************************************************* - * DOM Api * - * shim,class,data,css,val,html,event,ready * - **********************************************************************/ - - __webpack_require__(85) - __webpack_require__(86) - __webpack_require__(87) - __webpack_require__(88) - __webpack_require__(89) - __webpack_require__(90) - __webpack_require__(91) - __webpack_require__(92) - - module.exports = avalon - - /***/ }, -/* 85 */ +/* 70 */ /***/ function(module, exports) { - //safari5+是把contains方法放在Element.prototype上而不是Node.prototype - if (!avalon.document.contains) { - Node.prototype.contains = function (arg) { - return !!(this.compareDocumentPosition(arg) & 16) - } + /** + * ------------------------------------------------------------ + * 检测浏览器对CSS动画的支持与API名 + * ------------------------------------------------------------ + */ + var supportTransition = false + var supportAnimation = false + var supportCSS = false + var transitionEndEvent + var animationEndEvent + var transitionDuration = avalon.cssName("transition-duration") + var animationDuration = avalon.cssName("animation-duration") + + var checker = { + 'TransitionEvent': 'transitionend', + 'WebKitTransitionEvent': 'webkitTransitionEnd', + 'OTransitionEvent': 'oTransitionEnd', + 'otransitionEvent': 'otransitionEnd' } - avalon.contains = function (root, el) { + var window = avalon.window + var tran + //有的浏览器同时支持私有实现与标准写法,比如webkit支持前两种,Opera支持1、3、4 + for (var name in checker) { + if (window[name]) { + tran = checker[name] + break + } try { - while ((el = el.parentNode)) - if (el === root) - return true - return false + var a = document.createEvent(name) + tran = checker[name] + break; } catch (e) { - return false } } - function outerHTML() { - return new XMLSerializer().serializeToString(this) + if (typeof tran === "string") { + supportTransition = true + supportCSS = true + transitionEndEvent = tran } - - var svgns = 'http://www.w3.org/2000/svg' - var svg = avalon.document.createElementNS(svgns, 'svg') - - svg.innerHTML = '' - //IE9-11,firefox,ios7,8的chrome不支持SVG元素的innerHTML,outerHTML属性 - if (!/^\[object SVG\w*Element\]$/.test(svg.firstChild)) { - function createSVG(node, parent) { - /* jshint ignore:start */ - if (node && node.childNodes) { - var nodes = node.childNodes - for (var i = 0, el; el = nodes[i++]; ) { - if (el.nodeType === 1) { - var svg = document.createElementNS(svgns, el.nodeName.toLowerCase()) - avalon.each(el.attributes, function (a, attr) { - svg.setAttribute(attr.name, attr.value) - }) - createSVG(el, svg) - parent.appendChild(svg) - } else { - parent.appendChild(el.cloneNode(true)) - } - } - } - /* jshint ignore:end */ + //animationend有两个可用形态 + //IE10+, Firefox 16+ & Opera 12.1+: animationend + //Chrome/Safari: webkitAnimationEnd + //http://blogs.msdn.com/b/davrous/archive/2011/12/06/introduction-to-css3-animat ions.aspx + //IE10也可以使用MSAnimationEnd监听,但是回调里的事件 type依然为animationend + // el.addEventListener("MSAnimationEnd", function(e) { + // alert(e.type)// animationend!!! + // }) + checker = { + 'AnimationEvent': 'animationend', + 'WebKitAnimationEvent': 'webkitAnimationEnd' + } + var ani + for (name in checker) { + if (window[name]) { + ani = checker[name]; + break; } - Object.defineProperties(SVGElement.prototype, { - outerHTML: { - configurable: true, - get: outerHTML, - set: function (html) { - var tagName = this.tagName.toLowerCase() - var parent = this.parent - var parsed = avalon.parseHTML(html) - if (tagName === 'svg') { - parent.insertBefore(parsed, this) - } else { - var empty = document.createDocumentFragment() - createSVG(parsed, empty) - parent.insertBefore(empty, this) - } - parent.removeChild(this) - } - }, - innerHTML: { - configurable: true, - get: function () { - var s = this.outerHTML - var ropen = new RegExp('<' + this.nodeName + '\\b(?:(["\'])[^"]*?(\\1)|[^>])*>', 'i') - var rclose = new RegExp('<\/' + this.nodeName + '>$', 'i') - return s.replace(ropen, '').replace(rclose, '') - }, - set: function (html) { - if (avalon.clearHTML) { - avalon.clearHTML(this) - var frag = avalon.parseHTML(html) - createSVG(frag, this) - } - } - } - }) } + if (typeof ani === "string") { + supportAnimation = true + supportCSS = true + animationEndEvent = ani + } + + module.exports = { + transition: supportTransition, + animation: supportAnimation, + css: supportCSS, + transitionEndEvent: transitionEndEvent, + animationEndEvent: animationEndEvent, + transitionDuration: transitionDuration, + animationDuration: animationDuration + } + +/***/ }, +/* 71 */ +/***/ function(module, exports, __webpack_require__) { + + + avalon.lexer = __webpack_require__(72) + avalon.diff = __webpack_require__(73) + avalon.batch = __webpack_require__(74) + // dispatch与patch 为内置模块 + var parseView = __webpack_require__(37) + function render(vtree, num, scan) { + var num = num || String(new Date - 0).slice(0, 6) + var body = parseView(vtree, num, scan) + '\n\nreturn vnodes' + num + var fn = Function('__vmodel__','__fast__', body) + return fn + } + avalon.render = render + module.exports = avalon /***/ }, -/* 86 */ -/***/ function(module, exports) { +/* 72 */ +/***/ function(module, exports, __webpack_require__) { - var rnowhite = /\S+/g + /** + * ------------------------------------------------------------ + * lexer 将字符串变成一个虚拟DOM树,方便以后进一步变成模板函数 + * 此阶段只会生成VElement,VText,VComment + * ------------------------------------------------------------ + */ - 'add,remove'.replace(avalon.rword, function (method) { - avalon.fn[method + 'Class'] = function (cls) { - var el = this[0] || {} - //https://developer.mozilla.org/zh-CN/docs/Mozilla/Firefox/Releases/26 - if (cls && typeof cls === 'string' && el.nodeType === 1) { - cls.replace(rnowhite, function (c) { - el.classList[method](c) - }) - } - return this - } - }) + var makeHashCode = avalon.makeHashCode + var vdom = __webpack_require__(15) + var VText = vdom.VText + var VComment = vdom.VComment - avalon.fn.mix({ - hasClass: function (cls) { - var el = this[0] || {} - //IE10+, chrome8+, firefox3.6+, safari5.1+,opera11.5+支持classList, - //chrome24+,firefox26+支持classList2.0 - return el.nodeType === 1 && el.classList.contains(cls) - }, - toggleClass: function (value, stateVal) { - var isBool = typeof stateVal === 'boolean' - var me = this - String(value).replace(rnowhite, function (c) { - var state = isBool ? stateVal : !me.hasClass(c) - me[state ? 'addClass' : 'removeClass'](c) - }) - return this - } - }) + //匹配只有开标签的无内容元素(Void elements 或 self-contained tags) + //http://www.colorglare.com/2014/02/03/to-close-or-not-to-close.html + //http://blog.jobbole.com/61514/ + var rfullTag = /^<([^\s>\/=.$<]+)(?:\s+[^=\s]+(?:=[^>\s]+)?)*\s*>(?:[\s\S]*)<\/\1>/ + var rvoidTag = /^<([^\s>\/=.$<]+)\s*([^>]*?)\/?>/ -/***/ }, -/* 87 */ -/***/ function(module, exports) { + var rtext = /^[^<]+/ + var rcomment = /^/ - - var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/ - avalon.parseJSON = JSON.parse + var rnumber = /\d+/g + var rspAfterForStart = /^\s*ms-for\:/ + var rspBeforeForEnd = /^\s*ms-for-end\:/ + var r = __webpack_require__(40) + var rsp = r.sp + var rfill = /\?\?\d+/g + var rleftSp = r.leftSp + var rstring = r.string - function parseData(data) { - try { - if (typeof data === 'object') - return data - data = data === 'true' ? true : - data === 'false' ? false : - data === 'null' ? null : +data + '' === data ? +data : rbrace.test(data) ? JSON.parse(data) : data - } catch (e) { - } - return data - } + var rbind = avalon.config.rbind - avalon.fn.attr = function (name, value) { - if (arguments.length === 2) { - this[0].setAttribute(name, value) - return this + + var maps = {} + var number = 1 + function dig(a) { + var key = '??' + number++ + maps[key] = a + return key + } + function fill(a) { + var val = maps[a] + return val + } + var rhasString = /=["']/ + var rlineSp = /\n\s*/g + function fixLongAttrValue(attr) { + return rhasString.test(attr) ? + attr.replace(rlineSp, '').replace(rstring, dig) : attr + } + function lexer(text, curDeep, maxDeep) { + var nodes = [] + maxDeep = maxDeep || 1 + if (typeof curDeep !== 'number') { + curDeep = 0 } else { - return this[0].getAttribute(name) + curDeep = curDeep + 1 } - } - - avalon.fn.data = function (name, value) { - name = 'data-' + avalon.hyphen(name || '') - switch (arguments.length) { - case 2: - this.attr(name, value) - return this - case 1: - var val = this.attr(name) - return parseData(val) - case 0: - var ret = {} - avalon.each(this[0].attributes, function (i, attr) { - if (attr) { - name = attr.name - if (!name.indexOf('data-')) { - name = avalon.camelize(name.slice(5)) - ret[name] = parseData(attr.value) - } - } - }) - return ret + if (curDeep >= maxDeep && !rbind.test(text)) { + return nodes } - } - + if (!curDeep) { + text = text.replace(rstring, dig) + } + do { + var outerHTML = '' + var node = false + var match = text.match(rtext) + if (match) {//尝试匹配文本 + outerHTML = match[0] + node = new VText(outerHTML.replace(rfill, fill)) + } - if (avalon.root.dataset) { - avalon.fn.data = function (name, val) { - name = name && avalon.camelize(name) - var dataset = this[0].dataset - switch (arguments.length) { - case 2: - dataset[name] = val - return this - case 1: - val = dataset[name] - return parseData(val) - case 0: - var ret = {} - for (name in dataset) { - ret[name] = parseData(dataset[name]) + if (!node) {//尝试匹配注释 + match = text.match(rcomment) + if (match) { + outerHTML = match[0] + node = new VComment(match[1].replace(rfill, fill)) + var nodeValue = node.nodeValue + if (rspBeforeForEnd.test(nodeValue)) { + var sp = nodes[nodes.length - 1] + //移除紧挨着前的空白节点 + if (sp && sp.nodeType === 3 && rsp.test(sp.nodeValue)) { + nodes.pop() + } + getForTemplate(nodes) } - return ret + } } - } - } - -/***/ }, -/* 88 */ -/***/ function(module, exports) { + if (!node) {//尝试匹配拥有闭标签的元素节点 + match = text.match(rfullTag) + if (match) { + outerHTML = match[0]//贪婪匹配 outerHTML,可能匹配过多 + var type = match[1].toLowerCase()//nodeName + outerHTML = clipOuterHTML(outerHTML, type) - var root = avalon.root - var camelize = avalon.camelize - var cssHooks = avalon.cssHooks + match = outerHTML.match(rvoidTag) //抽取所有属性 - var prefixes = ['', '-webkit-', '-o-', '-moz-', '-ms-'] - var cssMap = { - 'float': 'cssFloat' - } + var props = {} + if (match[2]) { + handleProps(fixLongAttrValue(match[2]), props) + } - avalon.cssNumber = avalon.oneObject('animationIterationCount,columnCount,order,flex,flexGrow,flexShrink,fillOpacity,fontWeight,lineHeight,opacity,orphans,widows,zIndex,zoom') + var innerHTML = outerHTML.slice(match[0].length, + (type.length + 3) * -1) //抽取innerHTML - avalon.cssName = function (name, host, camelCase) { - if (cssMap[name]) { - return cssMap[name] - } - host = host || root.style - for (var i = 0, n = prefixes.length; i < n; i++) { - camelCase = camelize(prefixes[i] + name) - if (camelCase in host) { - return (cssMap[name] = camelCase) + node = { + nodeType: 1, + type: type, + props: props, + template: innerHTML.replace(rfill, fill).trim(), + children: [] + } + node = modifyProps(node, innerHTML, nodes, curDeep, maxDeep) + } } - } - return null - } - - avalon.fn.css = function (name, value) { - if (avalon.isPlainObject(name)) { - for (var i in name) { - avalon.css(this, i, name[i]) + if (!node) { + match = text.match(rvoidTag) + if (match) {//尝试匹配自闭合标签 + outerHTML = match[0] + type = match[1].toLowerCase() + props = {} + if (match[2]) { + handleProps(fixLongAttrValue(match[2]), props) + } + node = { + nodeType: 1, + type: type, + props: props, + template: '', + children: [], + isVoidTag: true + } + modifyProps(node, '', nodes, curDeep, maxDeep) + } } - } else { - var ret = avalon.css(this, name, value) - } - return ret !== void 0 ? ret : this - } - avalon.fn.position = function () { - var offsetParent, offset, - elem = this[0], - parentOffset = { - top: 0, - left: 0 + if (node) {//从text中移除被匹配的部分 + nodes.push(node) + text = text.slice(outerHTML.length) + if (node.nodeType === 8 && rspAfterForStart.test(node.nodeValue)) { + node.signature = makeHashCode('for') + //移除紧挨着后的空白节点 + text = text.replace(rleftSp, '') } - if (!elem) { - return parentOffset - } - if (this.css("position") === "fixed") { - offset = elem.getBoundingClientRect() - } else { - offsetParent = this.offsetParent() //得到真正的offsetParent - offset = this.offset() // 得到正确的offsetParent - if (offsetParent[0].tagName !== "HTML") { - parentOffset = offsetParent.offset() + } else { + break } - parentOffset.top += avalon.css(offsetParent[0], "borderTopWidth", true) - parentOffset.left += avalon.css(offsetParent[0], "borderLeftWidth", true) - - // Subtract offsetParent scroll positions - parentOffset.top -= offsetParent.scrollTop() - parentOffset.left -= offsetParent.scrollLeft() - } - return { - top: offset.top - parentOffset.top - avalon.css(elem, "marginTop", true), - left: offset.left - parentOffset.left - avalon.css(elem, "marginLeft", true) - } - } - avalon.fn.offsetParent = function () { - var offsetParent = this[0].offsetParent - while (offsetParent && avalon.css(offsetParent, "position") === "static") { - offsetParent = offsetParent.offsetParent; + } while (1); + if (!curDeep) { + maps = {} } - return avalon(offsetParent || root) - } - - - cssHooks["@:set"] = function (node, name, value) { - node.style[name] = value + return nodes } - cssHooks["@:get"] = function (node, name) { - if (!node || !node.style) { - throw new Error("getComputedStyle要求传入一个节点 " + node) - } - var ret, computed = getComputedStyle(node) - if (computed) { - ret = name === "filter" ? computed.getPropertyValue(name) : computed[name] - if (ret === "") { - ret = node.style[name] //其他浏览器需要我们手动取内联样式 + function getForTemplate(nodes){ + var i = 1, el, k = nodes.length, ret = [] + while(el = nodes[--k]){ + if(el.nodeType === 8){ + if(rspAfterForStart.test(el.nodeValue)){ + i -= 1 + }else if(rspBeforeForEnd.test(el.nodeValue)){ + i += 1 + } + if(i === 0){ + break + } } + ret.push(avalon.vdomAdaptor(el, 'toHTML')) } - return ret - } - cssHooks["opacity:get"] = function (node) { - var ret = cssHooks["@:get"](node, "opacity") - return ret === "" ? "1" : ret + return el.template = ret.reverse().join('') } - "top,left".replace(avalon.rword, function (name) { - cssHooks[name + ":get"] = function (node) { - var computed = cssHooks["@:get"](node, name) - return /px$/.test(computed) ? computed : - avalon(node).position()[name] + "px" - } - }) + //用于创建适配某一种标签的正则表达式 + var openStr = '(?:\\s+[^>=]*?(?:=[^>]+?)?)*>' + var tagCache = {}// 缓存所有匹配开标签闭标签的正则 + var rchar = /./g + var regArgs = avalon.msie < 9 ? 'ig' : 'g'//IE6-8,标签名都是大写 + function clipOuterHTML(matchText, type) { + var opens = [] + var closes = [] + var ropen = tagCache[type + 'open'] || + (tagCache[type + 'open'] = new RegExp('<' + type + openStr, regArgs)) + var rclose = tagCache[type + 'close'] || + (tagCache[type + 'close'] = new RegExp('<\/' + type + '>', regArgs)) - var cssShow = { - position: "absolute", - visibility: "hidden", - display: "block" - } - var rdisplayswap = /^(none|table(?!-c[ea]).+)/ + /* jshint ignore:start */ + matchText.replace(ropen, function (_, b) { + //注意,页面有时很长,b的数值就很大,如 + //000000000<000000011>000000041<000000066>000000096<000000107> + opens.push(('0000000000' + b + '<').slice(-10))//取得所有开标签的位置 + return _.replace(rchar, '1') + }).replace(rclose, function (_, b) { + closes.push(('0000000000' + b + '>').slice(-10))//取得所有闭标签的位置 + }) - function showHidden(node, array) { - //http://www.cnblogs.com/rubylouvre/archive/2012/10/27/2742529.html - if (node.offsetWidth <= 0) { //opera.offsetWidth可能小于0 - var styles = getComputedStyle(node, null) - if (rdisplayswap.test(styles["display"])) { - var obj = { - node: node - } - for (var name in cssShow) { - obj[name] = styles[name] - node.style[name] = cssShow[name] - } - array.push(obj) + /* jshint ignore:end */ + //
01
02
222
333
+ //会变成000<005<012>018<025>031>037<045>051<059> + //再变成<<><>><><> + //最后获取正确的>的索引值,这里为<<><>>的最后一个字符, + var pos = opens.concat(closes).sort() + var gtlt = pos.join('').replace(rnumber, '') + var k = 0, last = 0 + + for (var i = 0, n = gtlt.length; i < n; i++) { + var c = gtlt.charAt(i) + if (c === '<') { + k += 1 + } else { + k -= 1 } - var parent = node.parentNode - if (parent && parent.nodeType === 1) { - showHidden(parent, array) + if (k === 0) { + last = i + break } } + var findex = parseFloat(pos[last]) + type.length + 3 // (为三个字符) + return matchText.slice(0, findex) //取得正确的outerHTML } - avalon.each({ - Width: "width", - Height: "height" - }, function (name, method) { - var clientProp = "client" + name, - scrollProp = "scroll" + name, - offsetProp = "offset" + name - cssHooks[method + ":get"] = function (node, which, override) { - var boxSizing = -4 - if (typeof override === "number") { - boxSizing = override - } - which = name === "Width" ? ["Left", "Right"] : ["Top", "Bottom"] - var ret = node[offsetProp] // border-box 0 - if (boxSizing === 2) { // margin-box 2 - return ret + avalon.css(node, "margin" + which[0], true) + avalon.css(node, "margin" + which[1], true) - } - if (boxSizing < 0) { // padding-box -2 - ret = ret - avalon.css(node, "border" + which[0] + "Width", true) - avalon.css(node, "border" + which[1] + "Width", true) - } - if (boxSizing === -4) { // content-box -4 - ret = ret - avalon.css(node, "padding" + which[0], true) - avalon.css(node, "padding" + which[1], true) - } - return ret - } - cssHooks[method + "&get"] = function (node) { - var hidden = []; - showHidden(node, hidden); - var val = cssHooks[method + ":get"](node) - for (var i = 0, obj; obj = hidden[i++]; ) { - node = obj.node - for (var n in obj) { - if (typeof obj[n] === "string") { - node.style[n] = obj[n] + + function modifyProps(node, innerHTML, nodes, curDeep, maxDeep) { + var type = node.type + if ('ms-skip' in node.props) { + node.skipContent = true + } else { + switch (type) { + case 'style': + case 'script': + case 'noscript': + case 'template': + case 'textarea': + node.skipContent = true + if (type === 'textarea') { + node.props.type = 'textarea' + } + break + case 'input': + if (!node.props.type) { + node.props.type = 'text' + } + case 'xmp': + node.children.push(new VText(node.template)) + break + case 'option': + node.children.push(new VText(trimHTML(node.template))) + break + default: + + if (!node.isVoidTag) { + var childs = lexer(innerHTML, curDeep, maxDeep) + node.children = childs + if (type === 'table') { + addTbody(node.children) + } } + break + } + var forExpr = node.props['ms-for'] + if (forExpr) { + var cb = node.props['data-for-rendered'] + var cid = cb+':cb' + delete node.props['ms-for'] + nodes.push({ + nodeType: 8, + type: '#comment', + nodeValue: 'ms-for:' + forExpr, + signature: makeHashCode('for'), + cid: cid, + template: avalon.vdomAdaptor(node, 'toHTML') + }) + + if(cb && !avalon.caches[cid]){ + avalon.caches[cid] = Function('return '+ avalon.parseExpr(cb, 'on'))() + } + + nodes.push(node) + node = { + nodeType: 8, + skipContent: true, + type: '#comment', + nodeValue: 'ms-for-end:' } } - return val; } - avalon.fn[method] = function (value) { //会忽视其display - var node = this[0] - if (arguments.length === 0) { - if (node.setTimeout) { //取得窗口尺寸,IE9后可以用node.innerWidth /innerHeight代替 - return node["inner" + name] - } - if (node.nodeType === 9) { //取得页面尺寸 - var doc = node.documentElement - //FF chrome html.scrollHeight< body.scrollHeight - //IE 标准模式 : html.scrollHeight> body.scrollHeight - //IE 怪异模式 : html.scrollHeight 最大等于可视窗口多一点? - return Math.max(node.body[scrollProp], doc[scrollProp], node.body[offsetProp], doc[offsetProp], doc[clientProp]) + return node + } + //如果直接将tr元素写table下面,那么浏览器将将它们(相邻的那几个),放到一个动态创建的tbody底下 + function addTbody(nodes) { + var tbody, needAddTbody = false, count = 0, start = 0, n = nodes.length + for (var i = 0; i < n; i++) { + var node = nodes[i] + if (!tbody) { + if (node.type === 'tr') { + tbody = { + nodeType: 1, + type: 'tbody', + template: '', + children: [], + props: {} + } + tbody.children.push(node) + needAddTbody = true + if (start === 0) + start = i + nodes[i] = tbody } - return cssHooks[method + "&get"](node) } else { - return this.css(method, value) + if (node.type !== 'tr' && node.nodeType === 1) { + tbody = false + } else { + tbody.children.push(node) + count++ + nodes[i] = 0 + } } } - avalon.fn["inner" + name] = function () { - return cssHooks[method + ":get"](this[0], void 0, -2) - } - avalon.fn["outer" + name] = function (includeMargin) { - return cssHooks[method + ":get"](this[0], void 0, includeMargin === true ? 2 : 0) - } - }) - avalon.fn.offset = function () { //取得距离页面左右角的坐标 - var node = this[0] - try { - var rect = node.getBoundingClientRect() - // Make sure element is not hidden (display: none) or disconnected - // https://github.com/jquery/jquery/pull/2043/files#r23981494 - if (rect.width || rect.height || node.getClientRects().length) { - var doc = node.ownerDocument - var root = doc.documentElement - var win = doc.defaultView - return { - top: rect.top + win.pageYOffset - root.clientTop, - left: rect.left + win.pageXOffset - root.clientLeft + if (needAddTbody) { + for (i = start; i < n; i++) { + if (nodes[i] === 0) { + nodes.splice(i, 1) + i-- + count-- + if (count === 0) { + break + } } } - } catch (e) { - return { - left: 0, - top: 0 - } } } - avalon.each({ - scrollLeft: "pageXOffset", - scrollTop: "pageYOffset" - }, function (method, prop) { - avalon.fn[method] = function (val) { - var node = this[0] || {}, - win = getWindow(node), - top = method === "scrollTop" - if (!arguments.length) { - return win ? win[prop] : node[method] - } else { - if (win) { - win.scrollTo(!top ? val : win[prop], top ? val : win[prop]) - } else { - node[method] = val + + var ramp = /&/g + var rnowhite = /\S+/g + var rquote = /"/g + var rnogutter = /\s*=\s*/g + function handleProps(str, props) { + str.replace(rnogutter, '=').replace(rnowhite, function (el) { + var arr = el.split('='), value = arr[1] || '', + name = arr[0].toLowerCase() + if (arr.length === 2) { + if (value.indexOf('??') === 0) { + value = value.replace(rfill, fill). + slice(1, -1). + replace(ramp, '&'). + replace(rquote, '"') } } - } - }) + props[name] = value + }) + } - function getWindow(node) { - return node.window && node.document ? node : node.nodeType === 9 ? node.defaultView : false + //form prototype.js + var rtrimHTML = /<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi + function trimHTML(v) { + return String(v).replace(rtrimHTML, '').trim() } + + module.exports = lexer + /***/ }, -/* 89 */ -/***/ function(module, exports) { +/* 73 */ +/***/ function(module, exports, __webpack_require__) { - function getValType(elem) { - var ret = elem.tagName.toLowerCase() - return ret === 'input' && /checkbox|radio/.test(elem.type) ? 'checked' : ret + /** + * ------------------------------------------------------------ + * diff 对比新旧两个虚拟DOM树,根据directive中的diff方法为新虚拟DOM树 + * 添加change, afterChange更新钩子 + * ------------------------------------------------------------ + */ + var emptyArr = [] + // 防止被引用 + var emptyObj = function() { + return { + children: [], props: {} + } } - var valHooks = { - 'select:get': function self(node, ret, index, singleton) { - var nodes = node.children, value, - getter = valHooks['option:get'] - index = ret ? index : node.selectedIndex - singleton = ret ? singleton : node.type === 'select-one' || index < 0 - ret = ret || [] - for (var i = 0, el; el = nodes[i++]; ) { - if (!el.disabled) { - switch (el.nodeName.toLowerCase()) { - case 'option': - if ((el.selected || el.index === index)) { - value = el.value - if (singleton) { - return value - } else { - ret.push(value) - } - } - break - case 'optgroup': - value = self(el, ret, index, singleton) - if (typeof value === 'string') { - return value - } - break + var directives = avalon.directives + var rbinding = __webpack_require__(40).binding + + function diff(current, previous, steps) { + if (!current) + return + for (var i = 0; i < current.length; i++) { + var cur = current[i] + var pre = previous[i] || emptyObj() + switch (cur.nodeType) { + case 3: + if (!cur.skipContent) { + directives.expr.diff(cur, pre, steps) } - } - } - return singleton ? null : ret - }, - 'select:set': function (node, values, optionSet) { - values = [].concat(values) //强制转换为数组 - for (var i = 0, el; el = node.options[i++]; ) { - if ((el.selected = values.indexOf(el.value) > -1)) { - optionSet = true - } - } - if (!optionSet) { - node.selectedIndex = -1 + break + case 8: + if (cur.directive === 'for' ) { + if(cur.hasChange){ + i = directives['for'].diff(current, previous, steps, i) + }else{ + avalon.shadowCopy(cur, previous[i]) + delete cur.hasChange + } + } else if (cur.directive ) {//if widget + directives[cur.directive].diff(cur, pre, steps) + } + break + default: + if (!cur.skipAttrs) { + diffProps(cur, pre, steps) + } + if (!cur.skipContent) { + diff(cur.children, pre.children || emptyArr, steps) + } + break } } } - avalon.fn.val = function (value) { - var node = this[0] - if (node && node.nodeType === 1) { - var get = arguments.length === 0 - var access = get ? ':get' : ':set' - var fn = valHooks[getValType(node) + access] - if (fn) { - var val = fn(node, value) - } else if (get) { - return (node.value || '').replace(/\r/g, '') - } else { - node.value = value + function diffProps(current, previous, steps) { + if (current.order) { + try { + current.order.replace(/([^;]+)/g, function (name) { + var match = name.match(rbinding) + var type = match && match[1] + if (directives[type]) { + directives[type].diff(current, previous || emptyObj(), steps, name) + } + return name + }) + } catch (e) { + avalon.log(current, previous, e, 'diffProps error') } } - return get ? val : this + + } + avalon.diffProps = diffProps + module.exports = diff + /***/ }, -/* 90 */ +/* 74 */ /***/ function(module, exports, __webpack_require__) { - var Cache = __webpack_require__(26) - var fixScript = __webpack_require__(27) - var tagHooks = new function () {// jshint ignore:line - avalon.shadowCopy(this, { - option: document.createElement('select'), - thead: document.createElement('table'), - td: document.createElement('tr'), - area: document.createElement('map'), - tr: document.createElement('tbody'), - col: document.createElement('colgroup'), - legend: document.createElement('fieldset'), - _default: document.createElement('div'), - 'g': document.createElementNS('http://www.w3.org/2000/svg', 'svg') - }) - this.optgroup = this.option - this.tbody = this.tfoot = this.colgroup = this.caption = this.thead - this.th = this.td - }// jshint ignore:line - - var svgHooks = { - g: tagHooks.g - } - String('circle,defs,ellipse,image,line,path,polygon,polyline,rect,symbol,text,use').replace(avalon.rword, function (tag) { - svgHooks[tag] = tagHooks.g //处理SVG - }) + + /** + * ------------------------------------------------------------ + * batch 同时对N个视图进行全量更新 + * ------------------------------------------------------------ + */ - var rtagName = /<([\w:]+)/ - var rxhtml = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig + var patch = __webpack_require__(65) - var rhtml = /<|&#?\w+;/ - var htmlCache = new Cache(128) - var templateHook = avalon.document.createElement('template') - var templateHook - if (!/HTMLTemplateElement/.test(templateHook)) { - templateHook = null - avalon.shadowCopy(tagHooks, svgHooks) - } - avalon.parseHTML = function (html) { - var fragment = avalon.avalonFragment.cloneNode(false), firstChild - if (typeof html !== 'string') { - return fragment - } - if (!rhtml.test(html)) { - fragment.appendChild(document.createTextNode(html)) - return fragment - } - html = html.replace(rxhtml, '<$1>').trim() - var hasCache = htmlCache.get(html) - if (hasCache) { - return hasCache.cloneNode(true) - } - var tag = (rtagName.exec(html) || ['', ''])[1].toLowerCase() - var wrapper = svgHooks[tag], firstChild - if (wrapper) {//svgHooks - wrapper.innerHTML = html - } else if (templateHook) {//templateHook - templateHook.innerHTML = html - wrapper = templateHook.content - } else {//tagHooks - wrapper = tagHooks[tag] || tagHooks._default - wrapper.innerHTML = html - } - //使用innerHTML生成的script节点不会发出请求与执行text属性 - fixScript(wrapper) - if (templateHook) { - fragment = wrapper - } else {// 将wrapper上的节点转移到文档碎片上! - while (firstChild = wrapper.firstChild) { - fragment.appendChild(firstChild) - } + //如果正在更新一个子树,那么将它放到 + var dirtyTrees = {} + var needRenderIds = [] + avalon.suspendUpdate = 0 + var isBatchingUpdates = false + function batchUpdate(id, immediate) { + var vm = typeof id === 'string' ? avalon.vmodels[id] || {} : id + id = vm.$id + if (dirtyTrees[id]) { + avalon.Array.ensure(needRenderIds, id) + } else { + dirtyTrees[id] = true } - if (html.length < 1024) { - htmlCache.put(html, fragment.cloneNode(true)) + + if ( typeof vm.$render !== 'function' || !vm.$element || isBatchingUpdates) { + return } - return fragment - } + if (!document.nodeName)//如果是在mocha等测试环境中立即返回 + return - avalon.innerHTML = function (node, html) { - var a = this.parseHTML(html) - this.clearHTML(node).appendChild(a) - } - avalon.clearHTML = function (node) { - avalon.$$unbind(node) - node.textContent = '' - while (node.lastChild) { - node.removeChild(node.lastChild) - } - return node - } + var dom = vm.$element -/***/ }, -/* 91 */ -/***/ function(module, exports, __webpack_require__) { + flushUpdate(function () { + isBatchingUpdates = true + var vtree = vm.$render() || [] + var steps = {count: 0} + + if (vm.$render.dom) { + var _vtree = findVdom(vtree, vm.$id) + if(_vtree){ + dom = vm.$render.dom + vtree = [_vtree] + } + } + avalon.diff(vtree, dom.vtree || [], steps) + patch([ dom], vtree, null, steps) + steps.count = 0 + dom.vtree = vtree + isBatchingUpdates = false + avalon.log('rerender', vm.$id, new Date - avalon.rerenderStart) + delete dirtyTrees[id] + for (var i in dirtyTrees) {//更新其他子树 + batchUpdate(i, true) + break + } - var document = avalon.document - var window = avalon.window - var root = avalon.root + }, immediate) - var getShortID = __webpack_require__(6).getShortID - var canBubbleUp = __webpack_require__(32) - var eventHooks = avalon.eventHooks - /*绑定事件*/ - avalon.bind = function (elem, type, fn) { - if (elem.nodeType === 1) { - var value = elem.getAttribute('avalon-events') || '' - //如果是使用ms-on-*绑定的回调,其uuid格式为e12122324, - //如果是使用bind方法绑定的回调,其uuid格式为_12 - var uuid = getShortID(fn) - var key = type + ':' + uuid - var hook = eventHooks[type] - if (hook) { - type = hook.type - if (hook.fix) { - fn = hook.fix(elem, fn) - fn.uuid = uuid + '0' - } - key = type + ':' + fn.uuid - } - avalon.eventListeners[fn.uuid] = fn - if (value.indexOf(type + ':') === -1) {//同一种事件只绑定一次 - if (canBubbleUp[type] || focusBlur[type]) { - delegateEvent(type) - } else { - nativeBind(elem, type, dispatch) + } + function findVdom(array, id) { + for (var i = 0, el; el = array[i++]; ) { + if (el.nodeType === 1) { + if (el.props['ms-controller'] === id) { + return el + } else if (el.children) { + var find = findVdom(el.children, id) + if(find){ + return find + } } } - var keys = value.split('??') - if (keys[0] === '') { - keys.shift() - } - if (keys.indexOf(key) === -1) { - keys.push(key) - elem.setAttribute('avalon-events', keys.join('??')) - //将令牌放进avalon-events属性中 + } + } + function flushUpdate(callback, immediate ) { + if (immediate) { + callback() + var id = needRenderIds.shift() + if (id) { + batchUpdate(id, true) } - } else { - nativeBind(elem, type, fn) + setTimeout(callback, 0) } - return fn //兼容之前的版本 } - avalon.unbind = function (elem, type, fn) { - if (elem.nodeType === 1) { - var value = elem.getAttribute('avalon-events') || '' - switch (arguments.length) { - case 1: - nativeUnBind(elem, type, dispatch) - elem.removeAttribute('avalon-events') - break - case 2: - value = value.split('??').filter(function (str) { - return str.indexOf(type + ':') === -1 - }).join('??') + module.exports = avalon.batch = batchUpdate - elem.setAttribute('avalon-events', value) - break - default: - var search = type + ':' + fn.uuid - value = value.split('??').filter(function (str) { - return str !== search - }).join('??') - elem.setAttribute('avalon-events', value) - delete avalon.eventListeners[fn.uuid] - break - } + +/***/ }, +/* 75 */ +/***/ function(module, exports, __webpack_require__) { + + + var VText = __webpack_require__(16) + var parseView = __webpack_require__(37) + var resolvedComponents = avalon.resolvedComponents + var componentContainers = {wbr:1, xmp:1, template: 1} + var componentEvents = avalon.oneObject('onInit,onReady,onViewChange,onDispose') + + var needDel = avalon.mix({ + is: 1, + diff: 1, + define: 1, + cached: 1 + }, componentEvents) + avalon.document.createElement('slot') + + avalon.component = function (name, definition) { + //这是定义组件的分支,并将列队中的同类型对象移除 + if (typeof name === 'string') { + if (!avalon.components[name]) { + avalon.components[name] = definition + }//这里没有返回值 } else { - nativeUnBind(elem, type, fn) - } - } - var reventNames = /[^\s\?]+/g - var last = +new Date() - var typeRegExp = {} - function collectHandlers(elem, type, handlers) { - var value = elem.getAttribute('avalon-events') - if (value && (elem.disabled !== true || type !== 'click')) { - var uuids = [] - var reg = typeRegExp[type] || (typeRegExp[type] = new RegExp(type+'\\:([^?\s]+)','g')) - value.replace(reg, function(a, b){ - uuids.push(b) - return a - }) - if (uuids.length) { - handlers.push({ - elem: elem, - uuids: uuids - }) + var node = name //node为页面上节点对应的虚拟DOM + var topVm = definition + var wid = node.props.wid + //处理ms-widget的参数 + var optionMixin = {} + function mixinHooks(option, index) { + for (var k in option) { + if(!option.hasOwnProperty(k)) + continue + var v = option[k] + if (componentEvents[k]) { + if (k in optionMixin) { + optionMixin[k].push(v) + } else { + optionMixin[k] = [option[k]] + } + } else if (isFinite(index)) { + optionMixin[k] = v + } + } + } + var options = node.props['ms-widget'] || {} + options = Array.isArray(options) ? options : [options] + options.forEach(mixinHooks) + if(optionMixin.cached){ + var cachedVm = avalon.vmodels[optionMixin.$id] + if(cachedVm){ + var _wid = cachedVm.$events.__wid__ + delete resolvedComponents[wid] + wid = _wid + } } - } - elem = elem.parentNode - if (elem && elem.getAttribute && canBubbleUp[type]) { - collectHandlers(elem, type, handlers) - } + + var docker = resolvedComponents[wid] + if (!docker) { + resolvedComponents[wid] = node + docker = node + } + //如果此组件的实例已经存在,那么重新渲染 + if (docker.render) { + return docker + } + var tagName = node.type.indexOf('-') > 0 ? node.type : optionMixin.is + var placeholder = { + nodeType: 8, + type: '#comment', + directive: 'widget', + props: {'ms-widget': wid}, + nodeValue: 'ms-widget placeholder' + } + if (!avalon.components[tagName]) { + //如果组件还没有定义,那么返回一个注释节点占位 + return placeholder + } else { + var type = node.type + //判定用户传入的标签名是否符合规格 + if (!componentContainers[type] && !isCustomTag(type)) { + avalon.warn(type + '不合适做组件的标签') + } + //将用户声明组件用的自定义标签(或xmp.template)的template转换成虚拟DOM + if (type === 'xmp' || type === 'template' || node.children.length === 0) { + node.children = avalon.lexer(docker.template) + } + //对于IE6-8,需要对自定义标签进行hack + definition = avalon.components[tagName] + if (!avalon.modern && !definition.fixTag) { + avalon.document.createElement(tagName) + definition.fixTag = 1 + } + //对组件内置的template转换成虚拟DOM + var vtree = avalon.lexer(definition.template.trim()) + if (vtree.length > 1) { + avalon.error('组件必须用一个元素包起来') + } + var widgetNode = vtree[0] + if (widgetNode.type !== tagName) { + avalon.warn('模板容器标签最好为' + tagName) + } + //将用户标签中的属性合并到组件标签的属性里 + for (var k in docker.props) { + if(k !== 'ms-widget'){ + widgetNode.props[k] = docker.props[k] + } + } - } + //抽取用户标签里带slot属性的元素,替换组件的虚拟DOM树中的slot元素 + if (definition.soleSlot) { + var slots = {} + var slotName = definition.soleSlot + slots[slotName] = /\S/.test(docker.template) ? node.children : new VText('{{@' + slotName + '}}') + mergeTempale(vtree, slots) + } else if (!node.isVoidTag) { + insertSlots(vtree, node, definition.soleSlot) + } + //开始构建组件的vm的配置对象 + var diff = optionMixin.diff + var define = optionMixin.define + define = define || avalon.directives.widget.define + var $id = optionMixin.$id || avalon.makeHashCode(tagName.replace(/-/g, '_')) - var rhandleHasVm = /^e\d+/ - var rneedSmooth = /move|scroll/ - function dispatch(event) { - event = new avEvent(event) - var type = event.type - var elem = event.target - var handlers = [] - collectHandlers(elem, type, handlers) - var i = 0, j, uuid, handler - while ((handler = handlers[i++]) && !event.cancelBubble) { - event.currentTarget = handler.elem - j = 0 - while ((uuid = handler.uuids[ j++ ]) && - !event.isImmediatePropagationStopped) { - var fn = avalon.eventListeners[uuid] - if (fn) { - var vm = rhandleHasVm.test(uuid) ? handler.elem._ms_context_ : 0 - if (vm && vm.$hashcode === false) { - return avalon.unbind(elem, type, fn) + var defaults = definition.defaults + mixinHooks(defaults, false) + var defineArgs = [topVm, defaults].concat(options) + var vmodel = define.apply(function (a, b) { + for (var k in needDel) { + delete a[k] + delete b[k] } - if (rneedSmooth.test(type)) { - var curr = +new Date() - if (curr - last > 16) { - fn.call(vm || elem, event) - last = curr - } - } else { - fn.call(vm || elem, event) + }, defineArgs) + vmodel.$id = $id + vmodel.$element = topVm.$element + avalon.vmodels[$id] = vmodel + for (k in componentEvents) { + if (optionMixin[k]) { + optionMixin[k].forEach(function (fn) { + vmodel.$watch(k, fn) + }) } } + + //生成组件的render + var num = num || String(new Date - 0).slice(0, 6) + var render = parseView(vtree, num) + '\nreturn (avalon.__widget = vnodes' + num + ');\n' + vmodel.$render = topVm.$render + vmodel.$events.__wid__ = wid + //触发onInit回调 + vmodel.$fire('onInit', { + type: 'init', + vmodel: vmodel, + wid: wid, + target: null + }) + + avalon.shadowCopy(docker, { + diff: diff, + render: render, + vmodel: vmodel, + cached: !!optionMixin.cached, + placeholder: placeholder + }) + return docker } } } - var focusBlur = { - focus: true, - blur: true - } - var nativeBind = function (el, type, fn, capture) { - el.addEventListener(type, fn, capture) - } - var nativeUnBind = function (el, type, fn) { - el.removeEventListener(type, fn) - } + var ralphabet = /^[a-z]+$/ - function delegateEvent(type) { - var value = root.getAttribute('delegate-events') || '' - if (value.indexOf(type) === -1) { - var arr = value.match(reventNames) || [] - arr.push(type) - root.setAttribute('delegate-events', arr.join('??')) - nativeBind(root, type, dispatch, !!focusBlur[type]) - } + function isCustomTag(type) { + return type.length > 3 && type.indexOf('-') > 0 && + ralphabet.test(type.charAt(0) + type.slice(-1)) } - - var rvendor = /^(?:ms|webkit|moz)/ - function avEvent(event) { - if (event.originalEvent) { - return this + avalon.renderComponent = function (widgetNode) { + var docker = avalon.resolvedComponents[widgetNode.props.wid] + var order = widgetNode.order + + widgetNode.order = order ? + 'ms-widget;;' + order : 'ms-widget' + if (!isComponentReady(widgetNode)) { + return docker.placeholder } - for (var i in event) { - if (!rvendor.test(i) && typeof event[i] !== 'function') { - this[i] = event[i] - } + if (!docker.renderCount) { + docker.renderCount = 1 } - this.timeStamp = new Date() - 0 - this.originalEvent = event + widgetNode.props['ms-widget'] = docker.props['ms-widget'] + widgetNode.vmodel = docker.vmodel + widgetNode.diff = docker.diff + //移除skipAttrs,以便进行diff + delete widgetNode.skipAttrs + return widgetNode } - avEvent.prototype = { - preventDefault: function () { - var e = this.originalEvent; - this.returnValue = false - if (e) { - e.returnValue = false - e.preventDefault() - } - }, - stopPropagation: function () { - var e = this.originalEvent - this.cancelBubble = true - if (e) { - e.cancelBubble = true - e.stopPropagation() - } - }, - stopImmediatePropagation: function () { - var e = this.originalEvent - this.isImmediatePropagationStopped = true - if (e.stopImmediatePropagation) { - e.stopImmediatePropagation() - } - this.stopPropagation() + function isComponentReady(vnode) { + var isReady = true + try { + hasUnresolvedComponent(vnode) + } catch (e) { + isReady = false } + return isReady } - avalon.fireDom = function (elem, type, opts) { - var hackEvent = document.createEvent('Events'); - hackEvent.initEvent(type, true, true) - avalon.shadowCopy(hackEvent, opts) - elem.dispatchEvent(hackEvent) + function hasUnresolvedComponent(vnode) { + vnode.children.forEach(function (el) { + if (el.nodeType === 8 && el.props) { + if ('ms-widget' in el.props) { + throw 'unresolved' + } + } else if (el.children) { + hasUnresolvedComponent(el) + } + }) } - var eventHooks = avalon.eventHooks - //针对firefox, chrome修正mouseenter, mouseleave(chrome30+) - if (!('onmouseenter' in root)) { - avalon.each({ - mouseenter: 'mouseover', - mouseleave: 'mouseout' - }, function (origType, fixType) { - eventHooks[origType] = { - type: fixType, - fn: function (elem, fn) { - return function (e) { - var t = e.relatedTarget - if (!t || (t !== elem && !(elem.compareDocumentPosition(t) & 16))) { - delete e.type - e.type = origType - return fn.call(this, e) - } + function insertSlots(vtree, node, soleSlot) { + var slots = {} + if (soleSlot) { + slots[soleSlot] = node.children + } else { + node.children.forEach(function (el) { + if (el.nodeType === 1) { + var name = el.props.slot || 'default' + if (slots[name]) { + slots[name].push(el) + } else { + slots[name] = [el] } } - } - }) - } - //针对IE9+, w3c修正animationend - avalon.each({ - AnimationEvent: 'animationend', - WebKitAnimationEvent: 'webkitAnimationEnd' - }, function (construct, fixType) { - if (window[construct] && !eventHooks.animationend) { - eventHooks.animationend = { - type: fixType - } + }) } - }) + mergeTempale(vtree, slots) + } - if (document.onmousewheel === void 0) { - /* IE6-11 chrome mousewheel wheelDetla 下 -120 上 120 - firefox DOMMouseScroll detail 下3 上-3 - firefox wheel detlaY 下3 上-3 - IE9-11 wheel deltaY 下40 上-40 - chrome wheel deltaY 下100 上-100 */ - eventHooks.mousewheel = { - type: 'wheel', - fn: function (elem, fn) { - return function (e) { - e.wheelDeltaY = e.wheelDelta = e.deltaY > 0 ? -120 : 120 - e.wheelDeltaX = 0 - Object.defineProperty(e, 'type', { - value: 'mousewheel' - }) - fn.call(this, e) + function mergeTempale(vtree, slots) { + for (var i = 0, node; node = vtree[i++]; ) { + if (node.nodeType === 1) { + if (node.type === 'slot') { + var name = node.props.name || 'default' + if (slots[name]) { + var s = slots[name] + vtree.splice.apply(vtree, [i - 1, 1].concat(s)) + if (s.length === 1 && s[0].nodeType === 3) { + removeEmptyText(vtree) + } + } + } else { + mergeTempale(node.children, slots) } } } - } - avalon.fn.bind = function (type, fn, phase) { - if (this[0]) { //此方法不会链 - return avalon.bind(this[0], type, fn, phase) - } + return vtree } - avalon.fn.unbind = function (type, fn, phase) { - if (this[0]) { - avalon.unbind(this[0], type, fn, phase) + function removeEmptyText(nodes) { + //如果定义组件时,slot元素两旁有大片空白,且slot元素又是被一个文本节点替代时,需要合并这三个文本节点 + for (var i = 0, el; el = nodes[i]; i++) { + if (el.skipContent === false && el.nodeType === 3) { + var pre = nodes[i - 1] + var next = nodes[i + 1] + if (pre && pre.nodeType === 3 && !/\S/.test(pre.nodeValue)) { + avalon.Array.remove(nodes, pre) + --i + } + if (next && next.nodeType === 3 && !/\S/.test(next.nodeValue)) { + avalon.Array.remove(nodes, next) + } + } } - return this - } - avalon.$$unbind = function(node) { - var nodes = node.querySelectorAll('[avalon-events]') - avalon.each(nodes, function (i, el) { - avalon.unbind(el) - }) } + /***/ }, -/* 92 */ +/* 76 */ /***/ function(module, exports, __webpack_require__) { - var scan = __webpack_require__(34) - var document = avalon.document - var window = avalon.window + /** + * ------------------------------------------------------------ + * avalon基于纯净的Object.defineProperties的vm工厂 + * masterFactory,slaveFactory,mediatorFactory, ArrayFactory + * ------------------------------------------------------------ + */ - var readyList = [], isReady - var fireReady = function (fn) { - isReady = true + var share = __webpack_require__(77) - while (fn = readyList.shift()) { - fn(avalon) - } - } + var isSkip = share.isSkip + var toJson = share.toJson + var $$midway = share.$$midway + var $$skipArray = share.$$skipArray - if (document.readyState === 'complete') { - setTimeout(fireReady) //如果在domReady之外加载 - } else { - document.addEventListener('DOMContentLoaded', fireReady) - } + var makeAccessor = share.makeAccessor + var makeObserver = share.makeObserver + var modelAccessor = share.modelAccessor + var modelAdaptor = share.modelAdaptor + var makeHashCode = avalon.makeHashCode - avalon.bind(window, 'load', fireReady) - avalon.ready = function (fn) { - if (!isReady) { - readyList.push(fn) - } else { - fn(avalon) - } + //一个vm总是为Observer的实例 + function Observer() { } - avalon.ready(function(){ - scan(document.body) - }) - + function masterFactory(definition, heirloom, options) { -/***/ }, -/* 93 */ -/***/ function(module, exports, __webpack_require__) { + var $skipArray = {} + if (definition.$skipArray) {//收集所有不可监听属性 + $skipArray = avalon.oneObject(definition.$skipArray) + delete definition.$skipArray + } - __webpack_require__(36) - __webpack_require__(43) - //处理属性样式 - __webpack_require__(94) - __webpack_require__(47) - __webpack_require__(48) - //处理内容 - __webpack_require__(96) - __webpack_require__(50) - __webpack_require__(51) - //需要用到事件的 - __webpack_require__(52) - __webpack_require__(53) - __webpack_require__(97) - __webpack_require__(61) - __webpack_require__(62) + var keys = {} + options = options || {} + heirloom = heirloom || {} + var accessors = {} + var hashcode = makeHashCode('$') + var pathname = options.pathname || '' + options.id = options.id || hashcode + options.hashcode = options.hashcode || hashcode + var key, sid, spath + for (key in definition) { + if ($$skipArray[key]) + continue + var val = keys[key] = definition[key] + if (!isSkip(key, val, $skipArray)) { + sid = options.id + '.' + key + spath = pathname ? pathname + '.' + key : key + accessors[key] = makeAccessor(sid, spath, heirloom) + } + } - //处理逻辑 - __webpack_require__(63) - __webpack_require__(65) + accessors.$model = modelAccessor + var $vmodel = new Observer() + $vmodel = addAccessors($vmodel, accessors, definition) - __webpack_require__(66) - __webpack_require__(68) + for (key in keys) { + //对普通监控属性或访问器属性进行赋值 + $vmodel[key] = keys[key] -/***/ }, -/* 94 */ -/***/ function(module, exports, __webpack_require__) { + //删除系统属性 + if (key in $skipArray) { + delete keys[key] + } else { + keys[key] = true + } + } + makeObserver($vmodel, heirloom, keys, accessors, options) - - var attrUpdate = __webpack_require__(95) + return $vmodel + } - avalon.directive('attr', { - parse: function (binding, num) { - return 'vnode' + num + '.props["ms-attr"] = ' + avalon.parseExpr(binding) + ';\n' - }, - diff: function (cur, pre, steps, name) { - var a = cur.props[name] - var p = pre.props[name] - if (Object(a) === a) { - if (Array.isArray(a)) { - a = cur.props[name] = avalon.mix.apply({}, a) - } - if (typeof p !== 'object') { - cur.changeAttr = a + $$midway.masterFactory = masterFactory + var addAccessors = __webpack_require__(82) + var empty = {} + function slaveFactory(before, after, heirloom, options) { + var keys = {} + var skips = {} + var accessors = {} + heirloom = heirloom || {} + var pathname = options.pathname + var resue = before.$accessors || {} + var key, sid, spath + for (key in after) { + if ($$skipArray[key]) + continue + keys[key] = true//包括可监控与不可监控的 + if (!isSkip(key, after[key], empty)) { + if (resue[key]) { + accessors[key] = resue[key] } else { - var patch = {} - var hasChange = false - for (var i in a) { - if (a[i] !== p[i]) { - hasChange = true - patch[i] = a[i] - } - } - if (hasChange) { - cur.changeAttr = patch - steps.count += 1 - } - } - if (cur.changeAttr) { - var list = cur.change || (cur.change = []) - if(avalon.Array.ensure(list, this.update)){ - steps.count += 1 - } + sid = options.id + '.' + key + spath = pathname ? pathname + '.' + key : key + accessors[key] = makeAccessor(sid, spath, heirloom) } } else { - cur.props[name] = p + skips[key] = after[key] + delete after[key] } - }, - //dom, vnode - update: attrUpdate - }) + } + options.hashcode = before.$hashcode || makeHashCode('$') + accessors.$model = modelAccessor + var $vmodel = new Observer() + $vmodel = addAccessors($vmodel, accessors, skips) + for (key in skips) { + $vmodel[key] = skips[key] + } -/***/ }, -/* 95 */ -/***/ function(module, exports, __webpack_require__) { + makeObserver($vmodel, heirloom, keys, accessors, options) - var propMap = __webpack_require__(46) - var rsvg = /^\[object SVG\w*Element\]$/ + return $vmodel + } - function attrUpdate(node, vnode) { - var attrs = vnode.changeAttr - if (attrs) { - for (var attrName in attrs) { - var val = attrs[attrName] - // switch - if (attrName === 'src' && window.chrome && node.tagName === 'EMBED') { - node[attrName] = val - var parent = node.parentNode //#525 chrome1-37下embed标签动态设置src不能发生请求 - var comment = document.createComment('ms-src') - parent.replaceChild(comment, node) - parent.replaceChild(node, comment) - } else if (attrName.indexOf('data-') == 0) { - node.setAttribute(attrName, val) - } else { - var propName = propMap[attrName] || attrName - if (typeof node[propName] === 'boolean') { - //布尔属性必须使用el.xxx = true|false方式设值 - //如果为false, IE全系列下相当于setAttribute(xxx,''), - //会影响到样式,需要进一步处理 - node[propName] = !!val - } - if (val === false) { - node.removeAttribute(attrName) - continue - } + $$midway.slaveFactory = slaveFactory - //SVG只能使用setAttribute(xxx, yyy), VML只能使用node.xxx = yyy , - //HTML的固有属性必须node.xxx = yyy - var isInnate = rsvg.test(node) ? false : attrName in node.cloneNode(false) - if (isInnate) { - node[propName] = val + '' - } else { - node.setAttribute(attrName, val) + function mediatorFactory(before, after) { + var keys = {}, key + var accessors = {} + var unresolve = {} + var heirloom = {} + var arr = avalon.slice(arguments) + for (var i = 0; i < arr.length; i++) { + var obj = arr[i] + //收集所有键值对及访问器属性 + var config + var configName + for (var key in obj) { + if(!obj.hasOwnProperty(key)){ + continue + } + keys[key] = obj[key] + var $accessors = obj.$accessors + if ($accessors && $accessors[key]) { + if (arr.indexOf(obj[key]) === -1) { + accessors[key] = $accessors[key] + } else { //去掉vm那个配置对象 + config = keys[key] + configName = key + delete keys[key] } + } else if (typeof keys[key] !== 'function') { + unresolve[key] = 1 } } } - vnode.changeAttr = null - } - module.exports = attrUpdate + if (typeof this === 'function') { + this(keys, unresolve) + } + for (key in unresolve) { + //系统属性跳过,已经有访问器的属性跳过 + if ($$skipArray[key] || accessors[key]) + continue + if (!isSkip(key, keys[key], empty)) { + accessors[key] = makeAccessor(before.$id, key, heirloom) + accessors[key].set(keys[key]) + } + } -/***/ }, -/* 96 */ -/***/ function(module, exports) { + var $vmodel = new Observer() + $vmodel = addAccessors($vmodel, accessors, keys) - - avalon.directive('expr', { - parse: function () { - }, - diff: function (cur, pre, steps) { - if (cur.nodeValue !== pre.nodeValue) { - var list = cur.change || (cur.change = []) - if (avalon.Array.ensure(list, this.update)) { - steps.count += 1 + for (key in keys) { + if (!accessors[key]) {//添加不可监控的属性 + $vmodel[key] = keys[key] + } + //用于通过配置对象触发组件的$watch回调 + if (configName && accessors[key] && config.hasOwnProperty(key)) { + var $$ = accessors[key] + if (!$$.get.$decompose) { + $$.get.$decompose = {} } + $$.get.$decompose[configName+'.'+key] = $vmodel } - }, - update: function (node, vnode, parent) { - if (node.nodeType !== 3) { - var textNode = document.createTextNode(vnode.nodeValue) - parent.replaceChild(textNode, node) + + if (key in $$skipArray) { + delete keys[key] } else { - node.nodeValue = vnode.nodeValue + keys[key] = true } + } - }) -/***/ }, -/* 97 */ -/***/ function(module, exports, __webpack_require__) { + makeObserver($vmodel, heirloom, keys, accessors, { + id: before.$id, + hashcode: makeHashCode('$'), + master: true + }) - - var valueHijack = __webpack_require__(55) + return $vmodel + } - var newField = __webpack_require__(56) - var initField = __webpack_require__(98) - var updateField = __webpack_require__(99) - var addField = __webpack_require__(60) - var evaluatorPool = __webpack_require__(39) - avalon.directive('duplex', { - priority: 2000, - parse: function (binding, num, vnode) { - var id = binding.expr - newField(binding, vnode) - avalon.caches[id] = vnode.field - var ret = 'vnode' + num + '.duplexVm = __vmodel__;\n' + - 'vnode' + num + '.props["ms-duplex"] = ' + avalon.quote(id) + ';\n' + - 'vnode' + num + '.props["data-duplex-get"] = ' + evaluatorPool.get('duplex:' + id) +'\n'+ - 'vnode' + num + '.props["data-duplex-set"] = ' + evaluatorPool.get('duplex:set:' + id)+'\n' - var format = evaluatorPool.get('duplex:format:' + id) - if (format) { - ret += 'vnode' + num + '.props["data-duplex-format"] = ' + format - } - return ret - }, - diff: function (cur, pre, steps) { - var duplexID = cur.props["ms-duplex"] - cur.field = pre.field || avalon.mix({}, avalon.caches[duplexID]) - var field = cur.field - if (!field.set) { - initField(cur) - } + $$midway.mediatorFactory = avalon.mediatorFactory = mediatorFactory - cur.duplexVm = null - var value = cur.props.value = field.get(field.vmodel) + var __array__ = share.__array__ - if (cur.type === 'select' && !cur.children.length) { - avalon.Array.merge(cur.children, avalon.lexer(cur.template, 0, 2)) - fixVirtualOptionSelected(cur, value) - } - if (!field.element) { - var isEqual = false - } else { - var preValue = pre.props.value - if (Array.isArray(value)) { - isEqual = value + '' === preValue + '' - } else { - isEqual = value === preValue - } - } + var ap = Array.prototype + var _splice = ap.splice + function notifySize(array, size) { + if (array.length !== size) { + array.notify('length', array.length, size, true) + } + } - if (!isEqual) { - field.modelValue = value - var afterChange = cur.afterChange || (cur.afterChange = []) - avalon.Array.ensure(afterChange, this.update) - steps.count += 1 - } - }, - update: function (node, vnode) { - var field = node._ms_field_ = vnode.field - if (!field.element) {//这是一次性绑定 - field.element = node //方便进行垃圾回收 - var events = field.events - for (var name in events) { - avalon.bind(node, name, events[name]) - delete events[name] + __array__.removeAll = function (all) { //移除N个元素 + var size = this.length + if (Array.isArray(all)) { + for (var i = this.length - 1; i >= 0; i--) { + if (all.indexOf(this[i]) !== -1) { + _splice.call(this, i, 1) } } - addField(node, vnode) - if (!avalon.msie && valueHijack === false && !node.valueHijack) { - //chrome 42及以下版本需要这个hack - node.valueHijack = field.update - var intervalID = setInterval(function () { - if (!avalon.contains(avalon.root, node)) { - clearInterval(intervalID) - } else { - node.valueHijack() - } - }, 30) - } - - var viewValue = field.format(field.modelValue) - if (field.viewValue !== viewValue) { - field.viewValue = viewValue - updateField[field.type].call(field) - if (node.caret) { - var pos = field.caretPos - pos && field.updateCaret(node, pos.start, pos.end) - field.caretPos = null + } else if (typeof all === 'function') { + for (i = this.length - 1; i >= 0; i--) { + var el = this[i] + if (all(el, i)) { + _splice.call(this, i, 1) } } - } - }) - - - function fixVirtualOptionSelected(cur, curValue) { - var options = [] - cur.children.forEach(function (a) { - if (a.type === 'option') { - options.push(a) - } else if (a.type === 'optgroup') { - a.children.forEach(function (c) { - if (c.type === 'option') { - options.push(c) - } - }) - } - }) - var multi = cur.props.multiple - var map = {} - var one = multi === null || multi === void 0 || multi === false - if (Array.isArray(curValue)) { - curValue.forEach(function (a) { - map[a] = 1 - }) } else { - map[curValue] = 1 + _splice.call(this, 0, this.length) + } - for (var i = 0, option; option = options[i++]; ) { - var v = 'value' in option.props ? option.props.value : (option.children[0] || {nodeValue: ''}).nodeValue.trim() - option.props.selected = !!map[v] - if (map[v] && one) { - break - } + if (!avalon.modern) { + this.$model = toJson(this) } + notifySize(this, size) + this.notify() } -/***/ }, -/* 98 */ -/***/ function(module, exports, __webpack_require__) { - - var window = avalon.window - - var refreshModel = __webpack_require__(58) - var markID = __webpack_require__(6).getShortID + var __method__ = ['push', 'pop', 'shift', 'unshift', 'splice'] - function initControl(cur) { - var field = cur.field - field.update = updateModel - field.updateCaret = setCaret - field.get = cur.props['data-duplex-get'] - field.set = cur.props['data-duplex-set'] - var format = cur.props['data-duplex-format'] - if (format) { - field.formatters.push(function (v) { - return format(field.vmodel, v) - }) - } + __method__.forEach(function (method) { + var original = ap[method] + __array__[method] = function (a, b) { + // 继续尝试劫持数组元素的属性 + var args = [], size = this.length - field.vmodel = cur.duplexVm + if (method === 'splice' && Object(this[0]) === this[0]) { + var old = this.slice(a, b) + var neo = ap.slice.call(arguments, 2) + var args = [a, b] + for (var j = 0, jn = neo.length; j < jn; j++) { + var item = old[j] - var events = field.events = {} - //添加需要监听的事件 - switch (field.type) { - case 'radio': - if (cur.props.type === 'radio') { - events.click = updateModel - } else { - events.change = updateModel - } - break - case 'checkbox': - case 'select': - events.change = updateModel - break - case 'contenteditable': - if (field.isChanged) { - events.blur = updateModel - } else { - if (window.webkitURL) { - // http://code.metager.de/source/xref/WebKit/LayoutTests/fast/events/ - // https://bugs.webkit.org/show_bug.cgi?id=110742 - events.webkitEditableContentChanged = updateModel - } else if (window.MutationEvent) { - events.DOMCharacterDataModified = updateModel - } - events.input = updateModel + args[j + 2] = modelAdaptor(neo[j], item, item && item.$events, { + id: this.$id + '.*', + master: true + }) } - break - case 'input': - if (field.isChanged) { - events.change = updateModel - } else { - events.input = updateModel - events.compositionstart = openComposition - events.compositionend = closeComposition + + } else { + for (var i = 0, n = arguments.length; i < n; i++) { + args[i] = modelAdaptor(arguments[i], 0, {}, { + id: this.$id + '.*', + master: true + }) } - break + } + var result = original.apply(this, args) + if (!avalon.modern) { + this.$model = toJson(this) + } + notifySize(this, size) + this.notify() + return result } + }) - if (/password|text/.test(cur.props.type)) { - events.focus = openCaret - events.blur = closeCaret + 'sort,reverse'.replace(avalon.rword, function (method) { + __array__[method] = function () { + ap[method].apply(this, arguments) + if (!avalon.modern) { + this.$model = toJson(this) + } + this.notify() + return this } + }) - } + module.exports = avalon + //使用这个来扁平化数据 https://github.com/gaearon/normalizr + //使用Promise https://github.com/stefanpenner/es6-promise + //使用这个AJAX库 https://github.com/matthew-andrews/isomorphic-fetch - function updateModel() { - var elem = this - var field = this._ms_field_ - if (elem.composing || elem.value === field.lastViewValue) - return - if (elem.caret) { - try { - var pos = getCaret(elem) - if (pos.start === pos.end || pos.start + 1 === pos.end) { - field.caretPos = pos +/***/ }, +/* 77 */ +/***/ function(module, exports, __webpack_require__) { + + var share = __webpack_require__(78) + var canHideProperty = __webpack_require__(81) + var makeFire = share.makeFire + function toJson(val) { + var xtype = avalon.type(val) + if (xtype === 'array') { + var array = [] + for (var i = 0; i < val.length; i++) { + array[i] = toJson(val[i]) + } + return array + } else if (xtype === 'object') { + var obj = {} + for (i in val) { + if (i === '__proxy__' || i === '__data__' || i === '__const__') + continue + if (val.hasOwnProperty(i)) { + var value = val[i] + obj[i] = value && value.nodeType ? value : toJson(value) } - } catch (e) { - avalon.warn('fixCaret error', e) } + return obj } - if (field.debounceTime > 4) { - var timestamp = new Date() - var left = timestamp - field.time || 0 - field.time = timestamp - if (left >= field.debounceTime) { - refreshModel[field.type].call(field) - } else { - clearTimeout(field.debounceID) - field.debounceID = setTimeout(function () { - refreshModel[field.type].call(field) - }, left) - } + return val + } + + function hideProperty(host, name, value) { + if (canHideProperty) { + Object.defineProperty(host, name, { + value: value, + writable: true, + enumerable: false, + configurable: true + }) } else { - refreshModel[field.type].call(field) + host[name] = value } } + var modelAccessor = { + get: function () { + return toJson(this) + }, + set: avalon.noop, + enumerable: false, + configurable: true + } + function makeObserver($vmodel, heirloom, keys, accessors, options) { - function openCaret() { - this.caret = true + if (options.array) { + if (avalon.modern) { + Object.defineProperty($vmodel, '$model', modelAccessor) + } else { + $vmodel.$model = toJson($vmodel) + } + } else { + function hasOwnKey(key) { + return keys[key] === true + } + hideProperty($vmodel, '$accessors', accessors) + hideProperty($vmodel, 'hasOwnProperty', hasOwnKey) + hideProperty($vmodel, '$track', Object.keys(keys).sort().join(';;')) + } + hideProperty($vmodel, '$id', options.id) + hideProperty($vmodel, '$hashcode', options.hashcode) + if (options.master === true) { + hideProperty($vmodel, '$element', null) + hideProperty($vmodel, '$render', 0) + makeFire($vmodel, heirloom) + } } - function closeCaret() { - this.caret = false + share.$$midway.makeObserver = makeObserver + + share.$$midway.hideProperty = hideProperty + + var mixin = { + toJson: toJson, + makeObserver: makeObserver, + modelAccessor: modelAccessor } - function openComposition() { - this.composing = true + for (var i in share) { + mixin[i] = share[i] } - function closeComposition(e) { - this.composing = false - updateModel.call(this, e) + module.exports = mixin + + +/***/ }, +/* 78 */ +/***/ function(module, exports, __webpack_require__) { + + + var $$midway = {} + var $$skipArray = __webpack_require__(79) + var dispatch = __webpack_require__(80) + var $emit = dispatch.$emit + var $watch = dispatch.$watch + + + function makeFire($vmodel, heirloom) { + heirloom.__vmodel__ = $vmodel + var hide = $$midway.hideProperty + + hide($vmodel, '$events', heirloom) + hide($vmodel, '$watch', function () { + if (arguments.length === 2) { + return $watch.apply($vmodel, arguments) + } else { + throw '$watch方法参数不对' + } + }) + hide($vmodel, '$fire', function (expr, a, b) { + var list = $vmodel.$events[expr] + $emit(list, $vmodel, expr, a, b) + }) } - markID(openCaret) - markID(closeCaret) - markID(openComposition) - markID(closeComposition) - markID(updateModel) + function isSkip(key, value, skipArray) { + // 判定此属性能否转换访问器 + return key.charAt(0) === '$' || + skipArray[key] || + (typeof value === 'function') || + (value && value.nodeName && value.nodeType > 0) + } + function modelAdaptor(definition, old, heirloom, options) { + //如果数组转换为监控数组 + if (Array.isArray(definition)) { + return $$midway.arrayFactory(definition, old, heirloom, options) + } else if (Object(definition) === definition && typeof definition !== 'function') { + //如果此属性原来就是一个VM,拆分里面的访问器属性 + if (old && old.$id) { + ++avalon.suspendUpdate + //1.5带来的优化方案 + if (old.$track !== Object.keys(definition).sort().join(';;')) { + var vm = $$midway.slaveFactory(old, definition, heirloom, options) + } else { + vm = old + } + for (var i in definition) { + if ($$skipArray[i]) + continue + vm[i] = definition[i] + } + --avalon.suspendUpdate + return vm + } else { + vm = $$midway.masterFactory(definition, heirloom, options) + return vm + } + } else { + return definition + } + } + $$midway.modelAdaptor = modelAdaptor - function getCaret(field) { - var start = NaN, end = NaN - if (field.setSelectionRange) { - start = field.selectionStart - end = field.selectionEnd + function makeAccessor(sid, spath, heirloom) { + var old = NaN + function get() { + return old } + get.heirloom = heirloom return { - start: start, - end: end - } - } + get: get, + set: function (val) { + if (old === val) { + return + } + if (val && typeof val === 'object') { + val = $$midway.modelAdaptor(val, old, heirloom, { + pathname: spath, + id: sid + }) + } + var older = old + old = val - function setCaret(field, begin, end) { - if (!field.value || field.readOnly) - return - field.selectionStart = begin - field.selectionEnd = end - } + var vm = heirloom.__vmodel__ + if (this.$hashcode && vm && !avalon.suspendUpdate) { + //★★确保切换到新的events中(这个events可能是来自oldProxy) + if (heirloom !== vm.$events) { + get.heirloom = vm.$events + } + //如果这个属性是组件配置对象中的属性,那么它需要触发组件的回调 + emitWidget(get.$decompose, spath, val, older) + //触发普通属性的回调 + if (spath.indexOf('*') === -1) { + $emit(get.heirloom[spath], vm, spath, val, older) + } + //如果这个属性是数组元素上的属性 + emitArray(sid, vm, spath, val, older) + //如果这个属性存在通配符 + emitWildcard(get.heirloom, vm, spath, val, older) - module.exports = initControl + avalon.rerenderStart = new Date + var dotIndex = vm.$id.indexOf('.') + if (dotIndex > 0) { + avalon.batch(vm.$id.slice(0, dotIndex), true) + } else { + avalon.batch(vm, true) + } -/***/ }, -/* 99 */ -/***/ function(module, exports) { + } + }, + enumerable: true, + configurable: true + } + } + + var rtopsub = /([^.]+)\.(.+)/ + function emitArray(sid, vm, spath, val, older) { + if (sid.indexOf('.*.') > 0) { + var arr = sid.match(rtopsub) + var top = avalon.vmodels[ arr[1] ] + if (top) { + var path = arr[2] + $emit(top.$events[ path ], vm, spath, val, older) + } + } + } - var updateField = { - input: function () {//处理单个value值处理 - this.element.value = this.viewValue - }, - radio: function () {//处理单个checked属性 - var checked - if (this.isChecked) { - checked = !!this.viewValue + function emitWidget(whole, spath, val, older) { + if (whole && whole[spath]) { + var wvm = whole[spath] + if (!wvm.$hashcode) { + delete whole[spath] } else { - checked = this.viewValue + '' === this.element.value - } - this.element.checked = checked - }, - checkbox: function () {//处理多个checked属性 - var checked = false - var element = this.element - var value = element.value - for (var i = 0; i < this.modelValue.length; i++) { - var el = this.modelValue[i] - if (el + '' === value) { - checked = true + var wpath = spath.replace(/^[^.]+\./, '') + if (wpath !== spath) { + $emit(wvm.$events[wpath], wvm, wpath, val, older) } } - element.checked = checked - }, - select: function () {//处理子级的selected属性 - var a = Array.isArray(this.viewValue) ? this.viewValue.map(String) : this.viewValue + '' - avalon(this.element).val(a) - }, - contenteditable: function () {//处理单个innerHTML - this.element.innerHTML = this.viewValue - this.update.call(this.element) } } - module.exports = updateField - -/***/ }, -/* 100 */ -/***/ function(module, exports, __webpack_require__) { + function emitWildcard(obj, vm, spath, val, older) { + if (obj.__fuzzy__) { + obj.__fuzzy__.replace(avalon.rword, function (expr) { + var list = obj[expr] + var reg = list.reg + if (reg && reg.test(spath)) { + $emit(list, vm, spath, val, older) + } + return expr + }) + } + } - /** - * ------------------------------------------------------------ - * avalon基于纯净的Object.defineProperties的vm工厂 - * masterFactory,slaveFactory,mediatorFactory, ArrayFactory - * ------------------------------------------------------------ - */ - var share = __webpack_require__(101) - var isSkip = share.isSkip - var $$midway = share.$$midway - var $$skipArray = share.$$skipArray - delete $$skipArray.$accessors - delete $$skipArray.__data__ - delete $$skipArray.__proxy__ - delete $$skipArray.__const__ - var makeAccessor = share.makeAccessor - var makeObserver = share.makeObserver - var modelAccessor = share.modelAccessor - var modelAdaptor = share.modelAdaptor - var makeHashCode = avalon.makeHashCode + function define(definition) { + var $id = definition.$id + if (!$id && avalon.config.debug) { + avalon.warn('vm.$id must be specified') + } + if (avalon.vmodels[$id]) { + throw Error('error:['+ $id+ '] had defined!') + } + var vm = $$midway.masterFactory(definition, {}, { + pathname: '', + id: $id, + master: true + }) + return avalon.vmodels[$id] = vm - //一个vm总是为Observer的实例 - function Observer() { } - function masterFactory(definition, heirloom, options) { - var $skipArray = {} - if (definition.$skipArray) {//收集所有不可监听属性 - $skipArray = avalon.oneObject(definition.$skipArray) - delete definition.$skipArray - } + function arrayFactory(array, old, heirloom, options) { + if (old && old.splice) { + var args = [0, old.length].concat(array) + ++avalon.suspendUpdate + old.splice.apply(old, args) + --avalon.suspendUpdate + return old + } else { + for (var i in __array__) { + array[i] = __array__[i] + } - var keys = {} - options = options || {} - heirloom = heirloom || {} - var accessors = {} - var hashcode = makeHashCode('$') - var pathname = options.pathname || '' - options.id = options.id || hashcode - options.hashcode = hashcode - var key, sid, spath - for (key in definition) { - if ($$skipArray[key]) - continue - var val = keys[key] = definition[key] - if (!isSkip(key, val, $skipArray)) { - sid = options.id + '.' + key - spath = pathname ? pathname + '.' + key : key - accessors[key] = makeAccessor(sid, spath, heirloom) + array.notify = function (a, b, c, d) { + var vm = heirloom.__vmodel__ + if (vm) { + var path = a === null || a === void 0 ? + options.pathname : + options.pathname + '.' + a + vm.$fire(path, b, c) + if (!d && !avalon.suspendUpdate) { + avalon.rerenderStart = new Date + avalon.batch(vm, true) + } + } } - } - accessors.$model = modelAccessor - var $vmodel = new Observer() - Object.defineProperties($vmodel, accessors) + var hashcode = avalon.makeHashCode('$') + options.array = true + options.hashcode = hashcode + options.id = options.id || hashcode + $$midway.makeObserver(array, heirloom, {}, {}, options) - for (key in keys) { - //对普通监控属性或访问器属性进行赋值 - $vmodel[key] = keys[key] - //删除系统属性 - if (key in $skipArray) { - delete keys[key] - } else { - keys[key] = true + for (var j = 0, n = array.length; j < n; j++) { + array[j] = modelAdaptor(array[j], 0, {}, { + id: array.$id + '.*', + master: true + }) } + return array } - makeObserver($vmodel, heirloom, keys, accessors, options) - - return $vmodel } - $$midway.masterFactory = masterFactory + $$midway.arrayFactory = arrayFactory - var empty = {} - function slaveFactory(before, after, heirloom, options) { - var keys = {} - var accessors = {} - var pathname = options.pathname - heirloom = heirloom || {} - var key, sid, spath - for (key in after) { - if ($$skipArray[key]) - continue - keys[key] = after[key] - if (!isSkip(key, after[key], empty)) { - var accessor = Object.getOwnPropertyDescriptor(before, key) - if (accessor && accessor.get) { - accessors[key] = accessor - } else { - sid = options.id + '.' + key - spath = pathname ? pathname + '.' + key : key - accessors[key] = makeAccessor(sid, spath, heirloom) + var __array__ = { + set: function (index, val) { + if (((index >>> 0) === index) && this[index] !== val) { + if (index > this.length) { + throw Error(index + 'set方法的第一个参数不能大于原数组长度') } + this.splice(index, 1, val) } - } - for (key in before) { - delete before[key] - } - - options.hashcode = before.$hashcode || makeHashCode('$') - accessors.$model = modelAccessor - var $vmodel = before - Object.defineProperties($vmodel, accessors) - - for (key in keys) { - if (!accessors[key]) {//添加不可监控的属性 - $vmodel[key] = keys[key] + }, + contains: function (el) { //判定是否包含 + return this.indexOf(el) !== -1 + }, + ensure: function (el) { + if (!this.contains(el)) { //只有不存在才push + this.push(el) } - keys[key] = true + return this + }, + pushArray: function (arr) { + return this.push.apply(this, arr) + }, + remove: function (el) { //移除第一个等于给定值的元素 + return this.removeAt(this.indexOf(el)) + }, + removeAt: function (index) { //移除指定索引上的元素 + if ((index >>> 0) === index) { + return this.splice(index, 1) + } + return [] + }, + clear: function () { + this.removeAll() + return this } - makeObserver($vmodel, heirloom, keys, accessors, options) + } + avalon.define = define - return $vmodel + module.exports = { + $$midway: $$midway, + $$skipArray: $$skipArray, + isSkip: isSkip, + __array__: __array__, + makeFire: makeFire, + makeAccessor: makeAccessor, + modelAdaptor: modelAdaptor } - $$midway.slaveFactory = slaveFactory +/***/ }, +/* 79 */ +/***/ function(module, exports) { - function mediatorFactory(before, after) { - var keys = {} - var accessors = {} - var unresolve = {} - var heirloom = {} - var arr = avalon.slice(arguments) - var config - var configName - for (var i = 0; i < arr.length; i++) { - var obj = arr[i] - //收集所有键值对及访问器属性 - for (var key in obj) { - keys[key] = obj[key] - var accessor = Object.getOwnPropertyDescriptor(obj, key) - if (accessor.set) { - if (arr.indexOf(obj[key]) === -1) { - accessors[key] = accessor - } else { //去掉vm那个配置对象 - config = keys[key] - configName = key - delete keys[key] - } - } else if (typeof keys[key] !== 'function') { - unresolve[key] = 1 + /** + * + $$skipArray:是系统级通用的不可监听属性 + $skipArray: 是当前对象特有的不可监听属性 + + 不同点是 + $$skipArray被hasOwnProperty后返回false + $skipArray被hasOwnProperty后返回true + */ + + module.exports = avalon.oneObject('$id,$render,$track,$element,$watch,$fire,$events,$model,$skipArray,$accessors,$hashcode,__proxy__,__data__,__const__') + +/***/ }, +/* 80 */ +/***/ function(module, exports) { + + + /** + * ------------------------------------------------------------ + * 属性监听系统 + * ------------------------------------------------------------ + */ + + function adjustVm(vm, expr) { + var toppath = expr.split(".")[0], other + try { + if (vm.hasOwnProperty(toppath)) { + if (vm.$accessors) { + other = vm.$accessors[toppath].get.heirloom.__vmodel__ + } else { + other = Object.getOwnPropertyDescriptor(vm, toppath).get.heirloom.__vmodel__ } + } + } catch (e) { } - if(typeof this === 'function'){ - this(keys, unresolve) - } - for (key in unresolve) { - if ($$skipArray[key] || accessors[key]) - continue - if (!isSkip(key, keys[key], empty)) { - accessors[key] = makeAccessor(before.$id + '.' + key, key, heirloom) - accessors[key].set(keys[key]) - } - } - - var $vmodel = new Observer() - Object.defineProperties($vmodel, accessors) + return other || vm + } - for (key in keys) { - if (!accessors[key]) {//添加不可监控的属性 - $vmodel[key] = keys[key] - } - if (configName && accessors[key] && config.hasOwnProperty(key)) { - var $$ = accessors[key] - if (!$$.get.$decompose) { - $$.get.$decompose = {} + function toRegExp(expr) { + var arr = expr.split('.') + return new RegExp("^" + arr.map(function (el) { + return el === '*' ? '(?:[^.]+)' : el + }).join('\\.') + '$', 'i') + } + function addFuzzy(add, obj, expr) { + if (add) { + if (obj.__fuzzy__) { + if (obj.__fuzzy__.indexOf(',' + expr) === -1) { + obj.__fuzzy__ += ',' + expr } - $$.get.$decompose[configName+'.'+key] = $vmodel + } else { + obj.__fuzzy__ = expr } - keys[key] = true } - - makeObserver($vmodel, heirloom, keys, accessors, { - id: before.$id, - hashcode: makeHashCode("$"), - master: true - }) - // if (after.$id && before.$element) { - // if (!after.$element) { - // after.$element = before.$element - // after.$render = before.$render - // } - // } - return $vmodel } - $$midway.mediatorFactory = avalon.mediatorFactory = mediatorFactory + function $watch(expr, callback) { + var fuzzy = expr.indexOf('.*') > 0 || expr === '*' + var vm = fuzzy ? this : $watch.adjust(this, expr) + var hive = vm.$events + var list = hive[expr] || (hive[expr] = []) + if (fuzzy) { + list.reg = list.reg || toRegExp(expr) + } + addFuzzy(fuzzy, hive, expr) + if (vm !== this) { + addFuzzy(fuzzy, this.$events, expr) + this.$events[expr] = list + } - var __array__ = share.__array__ - var ap = Array.prototype - var _splice = ap.splice - function notifySize(array, size) { - if (array.length !== size) { - array.notify('length', array.length, size, true) + avalon.Array.ensure(list, callback) + + return function () { + avalon.Array.remove(list, callback) } } - __array__.removeAll = function (all) { //移除N个元素 - var size = this.length - if (Array.isArray(all)) { - for (var i = this.length - 1; i >= 0; i--) { - if (all.indexOf(this[i]) !== -1) { - _splice.call(this, i, 1) - } - } - } else if (typeof all === 'function') { - for (i = this.length - 1; i >= 0; i--) { - var el = this[i] - if (all(el, i)) { - _splice.call(this, i, 1) + $watch.adjust = adjustVm + /** + * $fire 方法的内部实现 + * + * @param {Array} list 订阅者数组 + * @param {Component} vm + * @param {String} path 监听属性名或路径 + * @param {Any} a 当前值 + * @param {Any} b 过去值 + * @param {Number} i 如果抛错,让下一个继续执行 + * @returns {undefined} + */ + function $emit(list, vm, path, a, b, i) { + if (list && list.length) { + try { + for (i = i || list.length - 1; i >= 0; i--) { + var callback = list[i] + callback.call(vm, a, b, path) } + } catch (e) { + if (i - 1 > 0) + $emit(list, vm, path, a, b, i - 1) + avalon.log(e, path) } - } else { - _splice.call(this, 0, this.length) } - - notifySize(this, size) - this.notify() } - var __method__ = ['push', 'pop', 'shift', 'unshift', 'splice'] - __method__.forEach(function (method) { - var original = ap[method] - __array__[method] = function (a, b) { - // 继续尝试劫持数组元素的属性 - var args = [], size = this.length - if (method === 'splice' && Object(this[0]) === this[0]) { - var old = this.slice(a, b) - var neo = ap.slice.call(arguments, 2) - var args = [a, b] - for (var j = 0, jn = neo.length; j < jn; j++) { - var item = old[j] - args[j + 2] = modelAdaptor(neo[j], item, item && item.$events, { - id: this.$id + '.*', - master: true - }) - } - } else { - for (var i = 0, n = arguments.length; i < n; i++) { - args[i] = modelAdaptor(arguments[i], 0, {}, { - id: this.$id + '.*', - master: true - }) - } - } + module.exports = { + $emit: $emit, + $watch: $watch, + adjustVm: adjustVm + } - var result = original.apply(this, args) - notifySize(this, size) - this.notify() +/***/ }, +/* 81 */ +/***/ function(module, exports) { - return result - } - }) + //如果浏览器不支持ecma262v5的Object.defineProperties或者存在BUG,比如IE8 + //标准浏览器使用__defineGetter__, __defineSetter__实现 + var flag = true + try { + Object.defineProperty({}, '_', { + value: 'x' + }) + } catch (e) { + flag = false + } - 'sort,reverse'.replace(avalon.rword, function (method) { - __array__[method] = function () { - ap[method].apply(this, arguments) - this.notify() - return this - } - }) + module.exports = flag +/***/ }, +/* 82 */ +/***/ function(module, exports, __webpack_require__) { - module.exports = avalon + + var canHideProperty = __webpack_require__(81) + var $$skipArray = __webpack_require__(79) -/***/ }, -/* 101 */ -/***/ function(module, exports, __webpack_require__) { + var defineProperties = Object.defineProperties + var defineProperty - var share = __webpack_require__(77) - var makeFire = share.makeFire + var expose = new Date() - 0 - function toJson(val) { - var xtype = avalon.type(val) - if (xtype === 'array') { - var array = [] - for (var i = 0; i < val.length; i++) { - array[i] = toJson(val[i]) + if (!canHideProperty) { + if ('__defineGetter__' in avalon) { + defineProperty = function (obj, prop, desc) { + if ('value' in desc) { + obj[prop] = desc.value + } + if ('get' in desc) { + obj.__defineGetter__(prop, desc.get) + } + if ('set' in desc) { + obj.__defineSetter__(prop, desc.set) + } + return obj } - return array - } else if (xtype === 'object') { - var obj = {} - for (i in val) { - if (val.hasOwnProperty(i)) { - var value = val[i] - obj[i] = value && value.nodeType ? value : toJson(value) + defineProperties = function (obj, descs) { + for (var prop in descs) { + if (descs.hasOwnProperty(prop)) { + defineProperty(obj, prop, descs[prop]) + } } + return obj } - return obj } - return val - } - - function hideProperty(host, name, value) { - Object.defineProperty(host, name, { - value: value, - writable: true, - enumerable: false, - configurable: true - }) - } - - var modelAccessor = { - get: function () { - return toJson(this) - }, - set: avalon.noop, - enumerable: false, - configurable: true - } - - share.$$midway.hideProperty = hideProperty - - function makeObserver($vmodel, heirloom, keys, accessors, options) { - - if (options.array) { - Object.defineProperty($vmodel, '$model', modelAccessor) - } else { - function hasOwnKey(key) { - return keys[key] === true + if (avalon.msie) { + var VBClassPool = {} + window.execScript([// jshint ignore:line + 'Function parseVB(code)', + '\tExecuteGlobal(code)', + 'End Function' //转换一段文本为VB代码 + ].join('\n'), 'VBScript'); + + function VBMediator(instance, accessors, name, value) {// jshint ignore:line + var accessor = accessors[name] + if (arguments.length === 4) { + accessor.set.call(instance, value) + } else { + return accessor.get.call(instance) + } + } + defineProperties = function (name, accessors, properties) { + // jshint ignore:line + var buffer = [] + buffer.push( + '\r\n\tPrivate [__data__], [__proxy__]', + '\tPublic Default Function [__const__](d' + expose + ', p' + expose + ')', + '\t\tSet [__data__] = d' + expose + ': set [__proxy__] = p' + expose, + '\t\tSet [__const__] = Me', //链式调用 + '\tEnd Function') + //添加普通属性,因为VBScript对象不能像JS那样随意增删属性,必须在这里预先定义好 + var uniq = { + __proxy__: true, + __data__: true, + __const__: true + } + + //添加访问器属性 + for (name in accessors) { + uniq[name] = true + buffer.push( + //由于不知对方会传入什么,因此set, let都用上 + '\tPublic Property Let [' + name + '](val' + expose + ')', //setter + '\t\tCall [__proxy__](Me,[__data__], "' + name + '", val' + expose + ')', + '\tEnd Property', + '\tPublic Property Set [' + name + '](val' + expose + ')', //setter + '\t\tCall [__proxy__](Me,[__data__], "' + name + '", val' + expose + ')', + '\tEnd Property', + '\tPublic Property Get [' + name + ']', //getter + '\tOn Error Resume Next', //必须优先使用set语句,否则它会误将数组当字符串返回 + '\t\tSet[' + name + '] = [__proxy__](Me,[__data__],"' + name + '")', + '\tIf Err.Number <> 0 Then', + '\t\t[' + name + '] = [__proxy__](Me,[__data__],"' + name + '")', + '\tEnd If', + '\tOn Error Goto 0', + '\tEnd Property') + + } + for (name in properties) { + if (uniq[name] !== true) { + uniq[name] = true + buffer.push('\tPublic [' + name + ']') + } + } + for (name in $$skipArray) { + if (uniq[name] !== true) { + uniq[name] = true + buffer.push('\tPublic [' + name + ']') + } + } + buffer.push('\tPublic [' + 'hasOwnProperty' + ']') + buffer.push('End Class') + var body = buffer.join('\r\n') + var className = VBClassPool[body] + if (!className) { + className = avalon.makeHashCode('VBClass') + + window.parseVB('Class ' + className + body) + window.parseVB([ + 'Function ' + className + 'Factory(a, b)', //创建实例并传入两个关键的参数 + '\tDim o', + '\tSet o = (New ' + className + ')(a, b)', + '\tSet ' + className + 'Factory = o', + 'End Function' + ].join('\r\n')) + VBClassPool[body] = className + } + var ret = window[className + 'Factory'](accessors, VBMediator) //得到其产品 + return ret //得到其产品 } - hideProperty($vmodel, 'hasOwnProperty', hasOwnKey) - } - hideProperty($vmodel, '$id', options.id) - hideProperty($vmodel, '$hashcode', options.hashcode) - hideProperty($vmodel, '$track', Object.keys(keys).sort().join(';;')) - if (options.master === true) { - hideProperty($vmodel, '$element', null) - hideProperty($vmodel, '$render', 0) - makeFire($vmodel, heirloom) } } - share.$$midway.makeObserver = makeObserver - - var mixin = { - toJson: toJson, - makeObserver: makeObserver, - modelAccessor: modelAccessor - } - for (var i in share) { - mixin[i] = share[i] - } - - module.exports = mixin + module.exports = defineProperties /***/ }, +/* 83 */, +/* 84 */, +/* 85 */, +/* 86 */, +/* 87 */, +/* 88 */, +/* 89 */, +/* 90 */, +/* 91 */, +/* 92 */, +/* 93 */, +/* 94 */, +/* 95 */, +/* 96 */, +/* 97 */, +/* 98 */, +/* 99 */, +/* 100 */, +/* 101 */, /* 102 */, -/* 103 */ +/* 103 */, +/* 104 */ /***/ function(module, exports) { //var avalon = require('avalon') @@ -7534,11 +8508,11 @@ return /******/ (function(modules) { // webpackBootstrap }) /***/ }, -/* 104 */ +/* 105 */ /***/ function(module, exports, __webpack_require__) { - var button = __webpack_require__(103) - var tmpl = __webpack_require__(105) + var button = __webpack_require__(104) + var tmpl = __webpack_require__(106) avalon.component('ms-panel', { template: tmpl, @@ -7552,7 +8526,7 @@ return /******/ (function(modules) { // webpackBootstrap }) /***/ }, -/* 105 */ +/* 106 */ /***/ function(module, exports) { module.exports = "\n
\n \n
\n

\n
" diff --git a/karma/directives/duplex.js b/karma/directives/duplex.js index f74542869..b0980e7d4 100644 --- a/karma/directives/duplex.js +++ b/karma/directives/duplex.js @@ -28,10 +28,13 @@ describe('duplex', function () { } }) it('数据转换', function (done) { + avalon.filters.limit = function(str,a){ + return String(str).slice(0, a) + } div.innerHTML = heredoc(function () { /*
- {{@aaa}} + {{@aaa}} {{@bbb}} {{@ccc}} {{@ddd}} diff --git a/perf/controller.html b/perf/controller.html index e844418d2..e788ba812 100644 --- a/perf/controller.html +++ b/perf/controller.html @@ -32,15 +32,20 @@ }, allChecked: false, checkOne: function () {//点击UI列表的checkbox时 - this.allChecked = this.todos.every(function (val) { + + var a = this.todos.every(function (val) { return val.completed }) + console.log(a, "checkOne",this.allChecked) + this.allChecked = a }, checkAll: function (e) { var target = e.target + var checked = target.checked this.todos.forEach(function (el) { el.completed = target.checked }) + this.allChecked = checked } })