305 lines
6.7 KiB
JavaScript
Executable File
305 lines
6.7 KiB
JavaScript
Executable File
/*
|
|
* obaa 2.1.1
|
|
* By dntzhang
|
|
* Github: https://github.com/Tencent/omi/tree/master/packages/obaa
|
|
* MIT Licensed.
|
|
*/
|
|
|
|
|
|
// __r_: root
|
|
// __c_: prop change callback
|
|
// __p_: path
|
|
|
|
; (function (win) {
|
|
function obaa(target, arr, callback) {
|
|
|
|
var eventPropArr = []
|
|
if (isArray(target)) {
|
|
if (target.length === 0) {
|
|
target.__o_ = {
|
|
__r_: target,
|
|
__p_: '#'
|
|
}
|
|
}
|
|
mock(target, target)
|
|
}
|
|
if (target && typeof target === 'object' && Object.keys(target).length === 0) {
|
|
track(target)
|
|
target.__o_.__r_ = target
|
|
}
|
|
for (var prop in target) {
|
|
if (target.hasOwnProperty(prop)) {
|
|
if (callback) {
|
|
if (isArray(arr) && isInArray(arr, prop)) {
|
|
eventPropArr.push(prop)
|
|
watch(target, prop, null, target)
|
|
} else if (isString(arr) && prop == arr) {
|
|
eventPropArr.push(prop)
|
|
watch(target, prop, null, target)
|
|
}
|
|
} else {
|
|
eventPropArr.push(prop)
|
|
watch(target, prop, null, target)
|
|
}
|
|
}
|
|
}
|
|
if (!target.__c_) {
|
|
target.__c_ = []
|
|
}
|
|
var propChanged = callback ? callback : arr
|
|
target.__c_.push({
|
|
all: !callback,
|
|
propChanged: propChanged,
|
|
eventPropArr: eventPropArr
|
|
})
|
|
}
|
|
|
|
var triggerStr = [
|
|
'concat',
|
|
'copyWithin',
|
|
'fill',
|
|
'pop',
|
|
'push',
|
|
'reverse',
|
|
'shift',
|
|
'sort',
|
|
'splice',
|
|
'unshift',
|
|
'size'
|
|
].join(',')
|
|
|
|
var methods = [
|
|
'concat',
|
|
'copyWithin',
|
|
'entries',
|
|
'every',
|
|
'fill',
|
|
'filter',
|
|
'find',
|
|
'findIndex',
|
|
'forEach',
|
|
'includes',
|
|
'indexOf',
|
|
'join',
|
|
'keys',
|
|
'lastIndexOf',
|
|
'map',
|
|
'pop',
|
|
'push',
|
|
'reduce',
|
|
'reduceRight',
|
|
'reverse',
|
|
'shift',
|
|
'slice',
|
|
'some',
|
|
'sort',
|
|
'splice',
|
|
'toLocaleString',
|
|
'toString',
|
|
'unshift',
|
|
'values',
|
|
'size'
|
|
]
|
|
|
|
function mock(target, root) {
|
|
methods.forEach(function (item) {
|
|
target[item] = function () {
|
|
var old = Array.prototype.slice.call(this, 0)
|
|
var result = Array.prototype[item].apply(
|
|
this,
|
|
Array.prototype.slice.call(arguments)
|
|
)
|
|
if (new RegExp('\\b' + item + '\\b').test(triggerStr)) {
|
|
for (var cprop in this) {
|
|
if (
|
|
this.hasOwnProperty(cprop) &&
|
|
!isFunction(this[cprop])
|
|
) {
|
|
watch(this, cprop, this.__o_.__p_, root)
|
|
}
|
|
}
|
|
//todo
|
|
onPropertyChanged(
|
|
'Array-' + item,
|
|
this,
|
|
old,
|
|
this,
|
|
this.__o_.__p_,
|
|
root
|
|
)
|
|
}
|
|
return result
|
|
}
|
|
target[
|
|
'pure' + item.substring(0, 1).toUpperCase() + item.substring(1)
|
|
] = function () {
|
|
return Array.prototype[item].apply(
|
|
this,
|
|
Array.prototype.slice.call(arguments)
|
|
)
|
|
}
|
|
})
|
|
}
|
|
|
|
function watch(target, prop, path, root) {
|
|
if (prop === '__o_') return
|
|
if (isFunction(target[prop])) return
|
|
if (!target.__o_) target.__o_ = {
|
|
__r_: root
|
|
}
|
|
if (path !== undefined && path !== null) {
|
|
target.__o_.__p_ = path
|
|
} else {
|
|
target.__o_.__p_ = '#'
|
|
}
|
|
|
|
var currentValue = (target.__o_[prop] = target[prop])
|
|
Object.defineProperty(target, prop, {
|
|
get: function () {
|
|
return this.__o_[prop]
|
|
},
|
|
set: function (value) {
|
|
var old = this.__o_[prop]
|
|
this.__o_[prop] = value
|
|
onPropertyChanged(
|
|
prop,
|
|
value,
|
|
old,
|
|
this,
|
|
target.__o_.__p_,
|
|
root
|
|
)
|
|
},
|
|
configurable: true,
|
|
enumerable: true
|
|
})
|
|
if (typeof currentValue == 'object') {
|
|
if (isArray(currentValue)) {
|
|
mock(currentValue, root)
|
|
if (currentValue.length === 0) {
|
|
track(currentValue, prop, path)
|
|
}
|
|
}
|
|
if (currentValue && Object.keys(currentValue).length === 0) {
|
|
track(currentValue, prop, path)
|
|
}
|
|
for (var cprop in currentValue) {
|
|
if (currentValue.hasOwnProperty(cprop)) {
|
|
watch(
|
|
currentValue,
|
|
cprop,
|
|
target.__o_.__p_ + '-' + prop,
|
|
root
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function track(obj, prop, path) {
|
|
if (obj.__o_) {
|
|
return
|
|
}
|
|
obj.__o_ = {}
|
|
if (path !== undefined && path !== null) {
|
|
obj.__o_.__p_ = path + '-' + prop
|
|
} else {
|
|
if (prop !== undefined && prop !== null) {
|
|
obj.__o_.__p_ = '#' + '-' + prop
|
|
} else {
|
|
obj.__o_.__p_ = '#'
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function onPropertyChanged(prop, value, oldValue, target, path, root) {
|
|
if (value !== oldValue && (!(nan(value) && nan(oldValue))) && root.__c_) {
|
|
var rootName = getRootName(prop, path)
|
|
for (
|
|
var i = 0, len = root.__c_.length;
|
|
i < len;
|
|
i++
|
|
) {
|
|
var handler = root.__c_[i]
|
|
if (
|
|
handler.all ||
|
|
isInArray(handler.eventPropArr, rootName) ||
|
|
rootName.indexOf('Array-') === 0
|
|
) {
|
|
if (value == "__deleted__") {
|
|
delete target[prop];
|
|
delete target.__o_[prop];
|
|
}
|
|
handler.propChanged.call(target, prop, value, oldValue, path)
|
|
}
|
|
}
|
|
}
|
|
|
|
if (prop.indexOf('Array-') !== 0 && typeof value === 'object') {
|
|
watch(target, prop, target.__o_.__p_, root)
|
|
}
|
|
}
|
|
|
|
function isFunction(obj) {
|
|
return Object.prototype.toString.call(obj) == '[object Function]'
|
|
}
|
|
|
|
function nan(value) {
|
|
return typeof value === "number" && isNaN(value)
|
|
}
|
|
|
|
function isArray(obj) {
|
|
return Object.prototype.toString.call(obj) === '[object Array]'
|
|
}
|
|
|
|
function isString(obj) {
|
|
return typeof obj === 'string'
|
|
}
|
|
|
|
function isInArray(arr, item) {
|
|
for (var i = arr.length; --i > -1;) {
|
|
if (item === arr[i]) return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
|
|
function getRootName(prop, path) {
|
|
if (path === '#') {
|
|
return prop
|
|
}
|
|
return path.split('-')[1]
|
|
}
|
|
|
|
obaa.add = function (obj, prop) {
|
|
watch(obj, prop, obj.__o_.__p_, obj.__o_.__r_)
|
|
}
|
|
|
|
obaa.set = function (obj, prop, value) {
|
|
if (obj[prop] === undefined) {
|
|
watch(obj, prop, obj.__o_.__p_, obj.__o_.__r_)
|
|
}
|
|
obj[prop] = value
|
|
}
|
|
|
|
obaa.delete = function (obj, prop, value) {
|
|
obj[prop] = "__deleted__";
|
|
watch(obj, prop, obj.__o_, obj.__o_)
|
|
}
|
|
|
|
Array.prototype.size = function (length) {
|
|
this.length = length
|
|
}
|
|
|
|
if (
|
|
typeof module != 'undefined' &&
|
|
module.exports) {
|
|
module.exports = obaa
|
|
} else if (typeof define === 'function' && define.amd) {
|
|
define(obaa)
|
|
} else {
|
|
win.obaa = obaa
|
|
}
|
|
})(Function('return this')());
|