all files / vmodel/ share.js

93.08% Statements 121/130
91.04% Branches 61/67
100% Functions 13/13
93.08% Lines 121/130
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231                                      161× 161×   160×   160× 160×             426× 426× 426× 426× 426×     426×           426×       426× 323× 323×   103× 103×       265× 265× 265× 265× 265×   265×   265× 597× 161× 436× 436× 436× 372×     265×                     265× 265× 265×     446× 444×               442×   438× 66×   372×     667× 83×   584× 584× 72× 512× 105×   584×       153× 153× 153× 153×     153× 310× 310×   153× 153× 153× 153×     684× 684× 684×   2922× 575×   2922×     390× 21×   390×                             1990× 1990× 356× 356× 1251×   356× 1634× 883× 734× 734× 734× 1513× 1513×   734×     900×       243×            
import { avalon, platform, isObject, modern } from '../seed/core'
import { $$skipArray } from './reserved'
import { Mutation } from './Mutation'
import { Computed } from './Computed'
 
 
/**
 * 这里放置ViewModel模块的共用方法
 * avalon.define: 全框架最重要的方法,生成用户VM
 * IProxy, 基本用户数据产生的一个数据对象,基于$model与vmodel之间的形态
 * modelFactory: 生成用户VM
 * canHijack: 判定此属性是否该被劫持,加入数据监听与分发的的逻辑
 * createProxy: listFactory与modelFactory的封装
 * createAccessor: 实现数据监听与分发的重要对象
 * itemFactory: ms-for循环中产生的代理VM的生成工厂
 * fuseFactory: 两个ms-controller间产生的代理VM的生成工厂
 */
 
 
avalon.define = function(definition) {
    var $id = definition.$id
    if (!$id) {
        avalon.error('vm.$id must be specified')
    }
    if (avalon.vmodels[$id]) {
        avalon.warn('error:[' + $id + '] had defined!')
    }
    var vm = platform.modelFactory(definition)
    return avalon.vmodels[$id] = vm
}
 
/**
 * 在未来的版本,avalon改用Proxy来创建VM,因此
 */
 
export function IProxy(definition, dd) {
    avalon.mix(this, definition)
    avalon.mix(this, $$skipArray)
    this.$hashcode = avalon.makeHashCode('$')
    this.$id = this.$id || this.$hashcode
    this.$events = {
        __dep__: dd || new Mutation(this.$id)
    }
    Iif (avalon.config.inProxyMode) {
        delete this.$mutations
        this.$accessors = {}
        this.$computed = {}
        this.$track = ''
    } else {
        this.$accessors = {
            $model: modelAccessor
        }
    }
    if (dd === void 0) {
        this.$watch = platform.watchFactory(this.$events)
        this.$fire = platform.fireFactory(this.$events)
    } else {
        delete this.$watch
        delete this.$fire
    }
}
 
platform.modelFactory = function modelFactory(definition, dd) {
    var $computed = definition.$computed || {}
    delete definition.$computed
    var core = new IProxy(definition, dd)
    var $accessors = core.$accessors
    var keys = []
 
    platform.hideProperty(core, '$mutations', {})
 
    for (let key in definition) {
        if (key in $$skipArray)
            continue
        var val = definition[key]
        keys.push(key)
        if (canHijack(key, val)) {
            $accessors[key] = createAccessor(key, val)
        }
    }
    for (let key in $computed) {
        Iif (key in $$skipArray)
            continue
        var val = $computed[key]
        if (typeof val === 'function') {
            val = {
                get: val
            }
        }
        Eif (val && val.get) {
            val.getter = val.get
            val.setter = val.set
            avalon.Array.ensure(keys, key)
            $accessors[key] = createAccessor(key, val, true)
        }
    }
    //将系统API以unenumerable形式加入vm,
    //添加用户的其他不可监听属性或方法
    //重写$track
    //并在IE6-8中增添加不存在的hasOwnPropert方法
    var vm = platform.createViewModel(core, $accessors, core)
    platform.afterCreate(vm, core, keys, !dd)
    return vm
}
var $proxyItemBackdoorMap = {}
 
export function canHijack(key, val, $proxyItemBackdoor) {
    if (key in $$skipArray)
        return false
    if (key.charAt(0) === '$') {
        Iif ($proxyItemBackdoor) {
            if (!$proxyItemBackdoorMap[key]) {
                $proxyItemBackdoorMap[key] = 1
                avalon.warn(`ms-for中的变量${key}不再建议以$为前缀`)
            }
            return true
        }
        return false
    }
    if (val == null) {
        avalon.warn('定义vmodel时' + key + '的属性值不能为null undefine')
        return true
    }
    if (/error|date|function|regexp/.test(avalon.type(val))) {
        return false
    }
    return !(val && val.nodeName && val.nodeType)
}
 
export function createProxy(target, dd) {
    if (target && target.$events) {
        return target
    }
    var vm
    if (Array.isArray(target)) {
        vm = platform.listFactory(target, false, dd)
    } else if (isObject(target)) {
        vm = platform.modelFactory(target, dd)
    }
    return vm
}
 
platform.createProxy = createProxy
 
platform.itemFactory = function itemFactory(before, after) {
    var keyMap = before.$model
    var core = new IProxy(keyMap)
    var state = avalon.shadowCopy(core.$accessors, before.$accessors) //防止互相污染
    var data = after.data
        //core是包含系统属性的对象
        //keyMap是不包含系统属性的对象, keys
    for (var key in data) {
        var val = keyMap[key] = core[key] = data[key]
        state[key] = createAccessor(key, val)
    }
    var keys = Object.keys(keyMap)
    var vm = platform.createViewModel(core, state, core)
    platform.afterCreate(vm, core, keys)
    return vm
}
 
function createAccessor(key, val, isComputed) {
    var mutation = null
    var Accessor = isComputed ? Computed : Mutation
    return {
        get: function Getter() {
            if (!mutation) {
                mutation = new Accessor(key, val, this)
            }
            return mutation.get()
        },
        set: function Setter(newValue) {
            if (!mutation) {
                mutation = new Accessor(key, val, this)
            }
            mutation.set(newValue)
        },
        enumerable: true,
        configurable: true
    }
}
 
 
platform.fuseFactory = function fuseFactory(before, after) {
    var keyMap = avalon.mix(before.$model, after.$model)
    var core = new IProxy(avalon.mix(keyMap, {
        $id: before.$id + after.$id
    }))
    var state = avalon.mix(core.$accessors,
            before.$accessors, after.$accessors) //防止互相污染
 
    var keys = Object.keys(keyMap)
        //将系统API以unenumerable形式加入vm,并在IE6-8中添加hasOwnPropert方法
    var vm = platform.createViewModel(core, state, core)
    platform.afterCreate(vm, core, keys, false)
    return vm
}
 
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') {
        if (typeof val.$track === 'string') {
            var obj = {}
            var arr = val.$track.match(/[^☥]+/g) || []
            arr.forEach(function(i) {
                var value = val[i]
                obj[i] = value && value.$events ? toJson(value) : value
            })
            return obj
        }
    }
    return val
}
 
var modelAccessor = {
    get: function() {
        return toJson(this)
    },
    set: avalon.noop,
    enumerable: false,
    configurable: true
}
 
platform.toJson = toJson
platform.modelAccessor = modelAccessor