forked from fanruan/fineui
fay
6 years ago
14 changed files with 167032 additions and 457 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,329 @@
|
||||
;(function () { |
||||
function initWatch(vm, watch) { |
||||
vm._watchers || (vm._watchers = []); |
||||
for (var key in watch) { |
||||
var handler = watch[key]; |
||||
if (BI.isArray(handler)) { |
||||
for (var i = 0; i < handler.length; i++) { |
||||
vm._watchers.push(createWatcher(vm, key, handler[i])); |
||||
} |
||||
} else { |
||||
vm._watchers.push(createWatcher(vm, key, handler)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
function createWatcher(vm, keyOrFn, handler) { |
||||
return Fix.watch(vm.store, keyOrFn, _.bind(handler, vm), { |
||||
store: vm.store |
||||
}); |
||||
} |
||||
|
||||
var target = null; |
||||
var targetStack = []; |
||||
|
||||
function pushTarget(_target) { |
||||
if (target) targetStack.push(target); |
||||
Fix.Model.target = target = _target; |
||||
} |
||||
|
||||
function popTarget() { |
||||
Fix.Model.target = target = targetStack.pop(); |
||||
} |
||||
|
||||
var context = null; |
||||
var contextStack = []; |
||||
|
||||
function pushContext(_context) { |
||||
if (context) contextStack.push(context); |
||||
Fix.Model.context = context = _context; |
||||
} |
||||
|
||||
function popContext() { |
||||
Fix.Model.context = context = contextStack.pop(); |
||||
} |
||||
|
||||
var oldWatch = Fix.watch; |
||||
Fix.watch = function (model, expOrFn, cb, options) { |
||||
if (BI.isPlainObject(cb)) { |
||||
options = cb; |
||||
cb = cb.handler; |
||||
} |
||||
if (typeof cb === "string") { |
||||
cb = model[cb]; |
||||
} |
||||
return oldWatch.call(this, model, expOrFn, function () { |
||||
options && options.store && pushTarget(options.store); |
||||
var res = cb.apply(this, arguments); |
||||
options && options.store && popTarget(); |
||||
return res; |
||||
}, options); |
||||
}; |
||||
|
||||
function findStore(widget) { |
||||
if (target != null) { |
||||
return target; |
||||
} |
||||
widget = widget || context; |
||||
var p = widget; |
||||
while (p) { |
||||
if (p instanceof Fix.Model || p.store || p.__cacheStore) { |
||||
break; |
||||
} |
||||
p = p._parent || (p.options && p.options.element); |
||||
} |
||||
if (p) { |
||||
if (p instanceof Fix.Model) { |
||||
return widget.__cacheStore = p; |
||||
} |
||||
widget.__cacheStore = p.store || p.__cacheStore; |
||||
return p.__cacheStore || p.store; |
||||
} |
||||
} |
||||
|
||||
var _create = BI.createWidget; |
||||
BI.createWidget = function (item, options, context) { |
||||
var pushed = false; |
||||
if (BI.isWidget(options)) { |
||||
pushContext(options); |
||||
pushed = true; |
||||
} else if (context != null) { |
||||
pushContext(context); |
||||
pushed = true; |
||||
} |
||||
var result = _create.apply(this, arguments); |
||||
pushed && popContext(); |
||||
return result; |
||||
}; |
||||
|
||||
_.each(["populate", "addItems", "prependItems"], function (name) { |
||||
var old = BI.Loader.prototype[name]; |
||||
BI.Loader.prototype[name] = function () { |
||||
pushContext(this); |
||||
var result = old.apply(this, arguments); |
||||
popContext(); |
||||
return result; |
||||
}; |
||||
}); |
||||
|
||||
function createStore() { |
||||
var needPop = false; |
||||
if (_global.Fix && this._store) { |
||||
var store = findStore(this.options.context || this.options.element); |
||||
if (store) { |
||||
pushTarget(store); |
||||
needPop = true; |
||||
} |
||||
this.store = this._store(); |
||||
this.store && (this.store._widget = this); |
||||
needPop && popTarget(); |
||||
needPop = false; |
||||
pushTarget(this.store); |
||||
if (this.store instanceof Fix.Model) { |
||||
this.model = this.store.model; |
||||
} else { |
||||
this.model = this.store; |
||||
} |
||||
needPop = true; |
||||
} |
||||
return needPop; |
||||
} |
||||
|
||||
BI.Widget.prototype._init = function () { |
||||
BI.Widget.superclass._init.apply(this, arguments); |
||||
this._initRoot(); |
||||
this._initElementWidth(); |
||||
this._initElementHeight(); |
||||
this._initVisual(); |
||||
this._initState(); |
||||
if (this.beforeInit) { |
||||
this.__asking = true; |
||||
this.beforeInit(BI.bind(function () { |
||||
if (this.model && this.model.$vm) { |
||||
this.model.$vm.$digest() |
||||
} |
||||
this._render(); |
||||
}, this)); |
||||
if (this.__asking === true) { |
||||
this.__async = true; |
||||
} |
||||
} else { |
||||
this._render(); |
||||
} |
||||
} |
||||
|
||||
var _init = BI.Widget.prototype._init; |
||||
BI.Widget.prototype._init = function () { |
||||
var self = this; |
||||
var needPop = createStore.call(this); |
||||
_init.apply(this, arguments); |
||||
needPop && popTarget(); |
||||
}; |
||||
|
||||
var _render = BI.Widget.prototype._render; |
||||
BI.Widget.prototype._render = function () { |
||||
var needPop = false; |
||||
if (_global.Fix && this._store) { |
||||
needPop = true; |
||||
pushTarget(this.store); |
||||
initWatch(this, this.watch); |
||||
} |
||||
_render.apply(this, arguments); |
||||
needPop && popTarget(); |
||||
}; |
||||
|
||||
var unMount = BI.Widget.prototype.__d; |
||||
BI.Widget.prototype.__d = function () { |
||||
unMount.apply(this, arguments); |
||||
this.store && BI.isFunction(this.store.destroy) && this.store.destroy(); |
||||
BI.each(this._watchers, function (i, unwatches) { |
||||
unwatches = BI.isArray(unwatches) ? unwatches : [unwatches]; |
||||
BI.each(unwatches, function (j, unwatch) { |
||||
unwatch(); |
||||
}); |
||||
}); |
||||
this._watchers && (this._watchers = []); |
||||
if (this.store) { |
||||
this.store._parent && (this.store._parent = null); |
||||
this.store._widget && (this.store._widget = null); |
||||
this.store = null; |
||||
} |
||||
delete this.__cacheStore; |
||||
}; |
||||
|
||||
_.each(["_mount"], function (name) { |
||||
var old = BI.Widget.prototype[name]; |
||||
old && (BI.Widget.prototype[name] = function () { |
||||
this.store && pushTarget(this.store); |
||||
var res = old.apply(this, arguments); |
||||
this.store && popTarget(); |
||||
return res; |
||||
}); |
||||
}); |
||||
|
||||
var additionFunc = function () { |
||||
BI.nextTick(function () { |
||||
Fix && Fix.refreshAll && Fix.refreshAll(); |
||||
}); |
||||
}; |
||||
|
||||
$(document).ajaxStop(additionFunc); |
||||
|
||||
if (BI.history) { |
||||
var navigate = BI.history.navigate; |
||||
// navigate之后不会立即变化有一段延迟
|
||||
BI.history.navigate = function () { |
||||
navigate.apply(this, arguments); |
||||
BI.defer(function () { |
||||
additionFunc(); |
||||
}, 110); |
||||
} |
||||
var back = window.history.back; |
||||
window.history.back = function () { |
||||
back.apply(this, arguments); |
||||
BI.defer(function () { |
||||
additionFunc(); |
||||
}, 110); |
||||
} |
||||
} |
||||
|
||||
_.each(["each", "map", "reduce", "reduceRight", "find", "filter", "reject", "every", "all", "some", "any", "max", "min", |
||||
"sortBy", "groupBy", "indexBy", "countBy", "partition", |
||||
"keys", "allKeys", "values", "pairs", "invert", |
||||
"mapObject", "findKey", "pick", "omit", "tap"], function (name) { |
||||
var old = BI[name]; |
||||
BI[name] = function (obj, fn, context) { |
||||
return typeof fn === "function" ? old(obj, function (key, value) { |
||||
if (!(key in Fix.$$skipArray)) { |
||||
return fn.apply(this, arguments); |
||||
} |
||||
}, context) : old.apply(this, arguments); |
||||
}; |
||||
}); |
||||
BI.isEmpty = function (ob) { |
||||
if (BI.isPlainObject(ob) && ob.__ob__) { |
||||
return BI.keys(ob).length === 0; |
||||
} |
||||
return _.isEmpty(ob); |
||||
}; |
||||
BI.keys = function (ob) { |
||||
var keys = _.keys(ob); |
||||
var nKeys = []; |
||||
for (var i = 0; i < keys.length; i++) { |
||||
if (!(keys[i] in Fix.$$skipArray)) { |
||||
nKeys.push(keys[i]); |
||||
} |
||||
} |
||||
return nKeys; |
||||
}; |
||||
BI.values = function (ob) { |
||||
var keys = BI.keys(obj); |
||||
var length = keys.length; |
||||
var values = []; |
||||
for (var i = 0; i < length; i++) { |
||||
values[i] = obj[keys[i]]; |
||||
} |
||||
return values; |
||||
}; |
||||
BI.extend = function () { |
||||
var args = Array.prototype.slice.call(arguments); |
||||
if (args.length < 1) { |
||||
return {}; |
||||
} |
||||
var object = args[0]; |
||||
var i = 1; |
||||
while (i < args.length) { |
||||
BI.each(args[i], function (key, v) { |
||||
object[key] = v; |
||||
}); |
||||
i++; |
||||
} |
||||
return object; |
||||
}; |
||||
BI.size = function (ob) { |
||||
if (BI.isPlainObject(ob) && ob.__ob__) { |
||||
return BI.keys(ob).length; |
||||
} |
||||
return _.size(ob); |
||||
}; |
||||
BI.isEmptyObject = function (ob) { |
||||
return BI.size(ob) === 0; |
||||
}; |
||||
BI.deepClone = function (ob) { |
||||
return Fix.toJSON(ob); |
||||
}; |
||||
|
||||
Fix.define = function (model) { |
||||
var OB = BI.inherit(Fix.Model, { |
||||
state: function () { |
||||
return model |
||||
} |
||||
}); |
||||
return new OB({ |
||||
defaultCallback: additionFunc |
||||
}).model; |
||||
} |
||||
Fix.set = function (obj, k, v) { |
||||
try { |
||||
if(obj) { |
||||
obj[k] = v; |
||||
} |
||||
} catch (e) { |
||||
|
||||
} finally { |
||||
return _.cloneDeep(obj); |
||||
} |
||||
} |
||||
Fix.del = function (obj, k) { |
||||
try { |
||||
if(obj) { |
||||
obj[k] = undefined; |
||||
} |
||||
} catch (e) { |
||||
|
||||
} finally { |
||||
return _.cloneDeep(obj); |
||||
} |
||||
} |
||||
BI.watch = Fix.watch; |
||||
}()); |
@ -0,0 +1,886 @@
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } |
||||
|
||||
(function (global, factory) { |
||||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('lodash'), require('underscore')) : typeof define === 'function' && define.amd ? define(['exports', 'lodash', 'underscore'], factory) : factory(global.Fix = global.Fix || {}, global._, global._); |
||||
})(this, function (exports, lodash, _$1) { |
||||
'use strict'; |
||||
|
||||
_$1 = 'default' in _$1 ? _$1['default'] : _$1; |
||||
|
||||
function noop(a, b, c) {} |
||||
|
||||
function isNative(Ctor) { |
||||
return typeof Ctor === 'function' && /native code/.test(Ctor.toString()); |
||||
} |
||||
|
||||
var rhashcode = /\d\.\d{4}/; |
||||
|
||||
// 生成UUID http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
|
||||
function makeHashCode() { |
||||
var prefix = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'bi'; |
||||
|
||||
/* istanbul ignore next*/ |
||||
return String(Math.random() + Math.random()).replace(rhashcode, prefix); |
||||
} |
||||
|
||||
function isIE() { |
||||
if (typeof navigator === 'undefined') { |
||||
return false; |
||||
} |
||||
|
||||
return (/(msie|trident)/i.test(navigator.userAgent.toLowerCase()) |
||||
); |
||||
} |
||||
|
||||
function getIEVersion() { |
||||
var version = 0; |
||||
if (typeof navigator === 'undefined') { |
||||
return false; |
||||
} |
||||
var agent = navigator.userAgent.toLowerCase(); |
||||
var v1 = agent.match(/(?:msie\s([\w.]+))/); |
||||
var v2 = agent.match(/(?:trident.*rv:([\w.]+))/); |
||||
if (v1 && v2 && v1[1] && v2[1]) { |
||||
version = Math.max(v1[1] * 1, v2[1] * 1); |
||||
} else if (v1 && v1[1]) { |
||||
version = v1[1] * 1; |
||||
} else if (v2 && v2[1]) { |
||||
version = v2[1] * 1; |
||||
} else { |
||||
version = 0; |
||||
} |
||||
|
||||
return version; |
||||
} |
||||
var isIE9Below = isIE() && getIEVersion() < 9; |
||||
|
||||
var _toString = Object.prototype.toString; |
||||
|
||||
function isPlainObject(obj) { |
||||
return _toString.call(obj) === '[object Object]'; |
||||
} |
||||
|
||||
var bailRE = /[^\w.$]/; |
||||
|
||||
/* eslint no-param-reassign: ['off'] */ |
||||
function parsePath(path) { |
||||
if (bailRE.test(path)) { |
||||
return; |
||||
} |
||||
var segments = path.split('.'); |
||||
|
||||
return function (obj) { |
||||
for (var i = 0; i < segments.length; i++) { |
||||
if (!obj) return; |
||||
obj = obj[segments[i]]; |
||||
} |
||||
|
||||
return obj; |
||||
}; |
||||
} |
||||
|
||||
function cloneShadow(obj) { |
||||
if (obj === null) return null; |
||||
|
||||
if (Array.isArray(obj)) { |
||||
return [].concat(obj); |
||||
} |
||||
|
||||
return lodash.cloneDeep(obj); |
||||
|
||||
// const type = typeof obj;
|
||||
//
|
||||
// switch (type) {
|
||||
// case 'object':
|
||||
// return _.extend({}, obj);
|
||||
// default:
|
||||
// return obj;
|
||||
// }
|
||||
} |
||||
|
||||
var nextTick = function () { |
||||
var callbacks = []; |
||||
var pending = false; |
||||
var timerFunc = void 0; |
||||
|
||||
function nextTickHandler() { |
||||
pending = false; |
||||
var copies = callbacks.slice(0); |
||||
callbacks.length = 0; |
||||
for (var i = 0; i < copies.length; i++) { |
||||
copies[i](); |
||||
} |
||||
} |
||||
|
||||
// An asynchronous deferring mechanism.
|
||||
// In pre 2.4, we used to use microtasks (Promise/MutationObserver)
|
||||
// but microtasks actually has too high a priority and fires in between
|
||||
// supposedly sequential events (e.g. #4521, #6690) or even between
|
||||
// bubbling of the same event (#6566). Technically setImmediate should be
|
||||
// the ideal choice, but it's not available everywhere; and the only polyfill
|
||||
// that consistently queues the callback after all DOM events triggered in the
|
||||
// same loop is by using MessageChannel.
|
||||
/* istanbul ignore if */ |
||||
if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) { |
||||
timerFunc = function timerFunc() { |
||||
setImmediate(nextTickHandler); |
||||
}; |
||||
} else if (typeof MessageChannel !== 'undefined' && (isNative(MessageChannel) || |
||||
// PhantomJS
|
||||
MessageChannel.toString() === '[object MessageChannelConstructor]')) { |
||||
var channel = new MessageChannel(); |
||||
var port = channel.port2; |
||||
channel.port1.onmessage = nextTickHandler; |
||||
timerFunc = function timerFunc() { |
||||
port.postMessage(1); |
||||
}; |
||||
/* istanbul ignore next */ |
||||
} else if (typeof Promise !== 'undefined' && isNative(Promise)) { |
||||
// use microtask in non-DOM environments, e.g. Weex
|
||||
var p = Promise.resolve(); |
||||
timerFunc = function timerFunc() { |
||||
p.then(nextTickHandler); |
||||
}; |
||||
} else { |
||||
// fallback to setTimeout
|
||||
timerFunc = function timerFunc() { |
||||
setTimeout(nextTickHandler, 0); |
||||
}; |
||||
} |
||||
|
||||
return function queueNextTick(cb, ctx) { |
||||
var _resolve = void 0; |
||||
callbacks.push(function () { |
||||
if (cb) { |
||||
try { |
||||
cb.call(ctx); |
||||
} catch (e) { |
||||
console.error(e); |
||||
} |
||||
} else if (_resolve) { |
||||
_resolve(ctx); |
||||
} |
||||
}); |
||||
if (!pending) { |
||||
pending = true; |
||||
timerFunc(); |
||||
} |
||||
// $flow-disable-line
|
||||
if (!cb && typeof Promise !== 'undefined') { |
||||
return new Promise(function (resolve, reject) { |
||||
_resolve = resolve; |
||||
}); |
||||
} |
||||
}; |
||||
}(); |
||||
|
||||
var falsy = void 0; |
||||
var $$skipArray = { |
||||
$accessors: falsy, |
||||
$vbthis: falsy, |
||||
$vbsetter: falsy, |
||||
$vm: falsy |
||||
}; |
||||
|
||||
function inherit(sb, sp, overrides) { |
||||
if (typeof sp === "object") { |
||||
overrides = sp; |
||||
sp = sb; |
||||
sb = function sb() { |
||||
return sp.apply(this, arguments); |
||||
}; |
||||
} |
||||
var F = function F() {}, |
||||
spp = sp.prototype; |
||||
F.prototype = spp; |
||||
sb.prototype = new F(); |
||||
sb.superclass = spp; |
||||
_$1.extend(sb.prototype, overrides, { |
||||
superclass: sp |
||||
}); |
||||
return sb; |
||||
} |
||||
|
||||
var mixinInjection = {}; |
||||
|
||||
function getMixins(type) { |
||||
return mixinInjection[type]; |
||||
} |
||||
|
||||
function mixin(xtype, cls) { |
||||
mixinInjection[xtype] = _.cloneDeep(cls); |
||||
} |
||||
|
||||
var falsy$1 = void 0; |
||||
var operators = { |
||||
'||': falsy$1, |
||||
'&&': falsy$1, |
||||
'(': falsy$1, |
||||
')': falsy$1 |
||||
}; |
||||
|
||||
function runBinaryFunction(binarys) { |
||||
var expr = ''; |
||||
for (var i = 0, len = binarys.length; i < len; i++) { |
||||
if (_$1.isBoolean(binarys[i]) || _$1.has(operators, binarys[i])) { |
||||
expr += binarys[i]; |
||||
} else { |
||||
expr += 'false'; |
||||
} |
||||
} |
||||
|
||||
return new Function('return ' + expr)(); |
||||
} |
||||
|
||||
function watch(vm, expOrFn, cb) { |
||||
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; |
||||
|
||||
var model = vm; |
||||
if (!model.addWatch && model.$vm) { |
||||
model = model.$vm; |
||||
} |
||||
if (isPlainObject(cb)) { |
||||
options = cb; |
||||
cb = cb.handler; |
||||
} |
||||
if (typeof cb === 'string') { |
||||
cb = model[cb]; |
||||
} |
||||
options = options || {}; |
||||
options.user = true; |
||||
var exps = void 0; |
||||
if (_$1.isFunction(expOrFn) || !(exps = expOrFn.match(/[a-zA-Z0-9_.*]+|[|][|]|[&][&]|[(]|[)]/g)) || exps.length === 1 && !/\*/.test(expOrFn)) { |
||||
model.addWatch(expOrFn, cb, options); |
||||
|
||||
return []; |
||||
} |
||||
var watchers = []; |
||||
var fns = exps.slice(); |
||||
var complete = false, |
||||
running = false; |
||||
var callback = function callback(index, newValue, oldValue, attrs) { |
||||
if (complete === true) { |
||||
return; |
||||
} |
||||
fns[index] = true; |
||||
if (runBinaryFunction(fns)) { |
||||
complete = true; |
||||
cb.call(vm, newValue, oldValue, attrs); |
||||
} |
||||
if (options && options.sync) { |
||||
complete = false; |
||||
running = false; |
||||
fns = exps.slice(); |
||||
} else { |
||||
if (!running) { |
||||
running = true; |
||||
nextTick(function () { |
||||
complete = false; |
||||
running = false; |
||||
fns = exps.slice(); |
||||
}); |
||||
} |
||||
} |
||||
}; |
||||
_$1.each(exps, function (exp, i) { |
||||
if (_$1.has(operators, exp)) { |
||||
return; |
||||
} |
||||
// a.**或a.*形式
|
||||
if (/^[1-9a-zA-Z.]+(\*\*$|\*$)/.test(exp) || exp === '**') { |
||||
var isGlobal = /\*\*$/.test(exp); |
||||
if (isGlobal) { |
||||
// a.**的形式
|
||||
exp = exp.replace('.**', ''); |
||||
} else { |
||||
// a.*的形式
|
||||
exp = exp.replace('.*', ''); |
||||
} |
||||
var getter = isGlobal ? exp : function () { |
||||
var result = {}; |
||||
_$1.each(model.model, function (v, key) { |
||||
if (key in $$skipArray) return; |
||||
result[key] = v; |
||||
}); |
||||
|
||||
return result; |
||||
}; |
||||
model.addWatch(getter, function (newValue, oldValue, attrs) { |
||||
callback(i, newValue, oldValue, _$1.extend({ index: i }, attrs)); |
||||
}, _$1.extend(options, { |
||||
deep: isGlobal |
||||
})); |
||||
|
||||
return; |
||||
} |
||||
if (/\*\*$|\*$/.test(exp)) { |
||||
throw new Error('not support'); |
||||
} |
||||
// 其他含有*的情况,如*.a,*.*.a,a.*.a
|
||||
if (/\*/.test(exp)) { |
||||
// 先获取到能获取到的对象
|
||||
var paths = exp.split('.'); |
||||
var _getter = function _getter() { |
||||
var currentModels = { |
||||
root: model.model |
||||
}; |
||||
|
||||
var _loop = function _loop(len, _i) { |
||||
var models = {}; |
||||
if (paths[_i] === '*') { |
||||
_$1.each(currentModels, function (model, key) { |
||||
_$1.each(model, function (v, k) { |
||||
if (key + k in $$skipArray) return; |
||||
models[key + k] = v; |
||||
}); |
||||
}); |
||||
} else { |
||||
_$1.each(currentModels, function (model, key) { |
||||
if (key + paths[_i] in $$skipArray) return; |
||||
models[key + paths[_i]] = model[paths[_i]]; |
||||
}); |
||||
} |
||||
currentModels = models; |
||||
}; |
||||
|
||||
for (var _i = 0, len = paths.length; _i < len; _i++) { |
||||
_loop(len, _i); |
||||
} |
||||
|
||||
return currentModels; |
||||
}; |
||||
model.addWatch(_getter, function (newValue, oldValue, attrs) { |
||||
callback(i, newValue, oldValue, _$1.extend({ index: i }, attrs)); |
||||
}, options); |
||||
|
||||
return; |
||||
} |
||||
model.addWatch(exp, function (newValue, oldValue, attrs) { |
||||
callback(i, newValue, oldValue, _$1.extend({ index: i }, attrs)); |
||||
}, options); |
||||
}); |
||||
|
||||
return watchers; |
||||
} |
||||
|
||||
var SymbolProto = typeof Symbol !== 'undefined' ? Symbol.prototype : null; |
||||
var ObjProto = Object.prototype; |
||||
var toString = ObjProto.toString; |
||||
|
||||
// Internal recursive comparison function for `isEqual`.
|
||||
/* eslint no-param-reassign: ['off'] */ |
||||
/* eslint no-use-before-define: ["off"] */ |
||||
var deepEq = function deepEq(a, b, aStack, bStack) { |
||||
// Unwrap any wrapped objects.
|
||||
if (a instanceof _$1) a = a._wrapped; |
||||
if (b instanceof _$1) b = b._wrapped; |
||||
// Compare `[[Class]]` names.
|
||||
var className = toString.call(a); |
||||
if (className !== toString.call(b)) return false; |
||||
switch (className) { |
||||
// Strings, numbers, regular expressions, dates, and booleans are compared by value.
|
||||
case '[object RegExp]': |
||||
case '[object String]': |
||||
// RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
|
||||
// Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
|
||||
// equivalent to `new String("5")`.
|
||||
return '' + a === '' + b; |
||||
case '[object Number]': |
||||
// `NaN`s are equivalent, but non-reflexive.
|
||||
// Object(NaN) is equivalent to NaN.
|
||||
if (+a !== +a) return +b !== +b; |
||||
// An `egal` comparison is performed for other numeric values.
|
||||
|
||||
return +a === 0 ? 1 / +a === 1 / b : +a === +b; |
||||
case '[object Date]': |
||||
case '[object Boolean]': |
||||
// Coerce dates and booleans to numeric primitive values. Dates are compared by their
|
||||
// millisecond representations. Note that invalid dates with millisecond representations
|
||||
// of `NaN` are not equivalent.
|
||||
return +a === +b; |
||||
case '[object Symbol]': |
||||
return SymbolProto.valueOf.call(a) === SymbolProto.valueOf.call(b); |
||||
default: |
||||
} |
||||
|
||||
var areArrays = className === '[object Array]'; |
||||
|
||||
if (!areArrays) { |
||||
if (typeof a != 'object' || typeof b != 'object') return false; |
||||
|
||||
// Objects with different constructors are not equivalent, but `Object`s or `Array`s
|
||||
// from different frames are.
|
||||
var aCtor = a.constructor, |
||||
bCtor = b.constructor; |
||||
if (aCtor !== bCtor && !(_$1.isFunction(aCtor) && aCtor instanceof aCtor && _$1.isFunction(bCtor) && bCtor instanceof bCtor) && 'constructor' in a && 'constructor' in b) { |
||||
return false; |
||||
} |
||||
} |
||||
// Assume equality for cyclic structures. The algorithm for detecting cyclic
|
||||
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
|
||||
|
||||
// Initializing stack of traversed objects.
|
||||
// It's done here since we only need them for objects and arrays comparison.
|
||||
aStack = aStack || []; |
||||
bStack = bStack || []; |
||||
var length = aStack.length; |
||||
while (length--) { |
||||
// Linear search. Performance is inversely proportional to the number of
|
||||
// unique nested structures.
|
||||
if (aStack[length] === a) return bStack[length] === b; |
||||
} |
||||
|
||||
// Add the first object to the stack of traversed objects.
|
||||
aStack.push(a); |
||||
bStack.push(b); |
||||
|
||||
// Recursively compare objects and arrays.
|
||||
if (areArrays) { |
||||
// Compare array lengths to determine if a deep comparison is necessary.
|
||||
length = a.length; |
||||
if (length !== b.length) return false; |
||||
// Deep compare the contents, ignoring non-numeric properties.
|
||||
while (length--) { |
||||
if (!eq(a[length], b[length], aStack, bStack)) return false; |
||||
} |
||||
} else { |
||||
// Deep compare objects.
|
||||
var keys = _$1.keys(a);var key = void 0; |
||||
length = keys.length; |
||||
// Ensure that both objects contain the same number of properties before comparing deep equality.
|
||||
if (_$1.keys(b).length !== length) return false; |
||||
while (length--) { |
||||
// Deep compare each member
|
||||
key = keys[length]; |
||||
if (!(_$1.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false; |
||||
} |
||||
} |
||||
// Remove the first object from the stack of traversed objects.
|
||||
aStack.pop(); |
||||
bStack.pop(); |
||||
|
||||
return true; |
||||
}; |
||||
|
||||
var eq = function eq(a, b, aStack, bStack) { |
||||
// Identical objects are equal. `0 === -0`, but they aren't identical.
|
||||
// See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
|
||||
if (a === b) return a !== 0 || 1 / a === 1 / b; |
||||
// `null` or `undefined` only equal to itself (strict comparison).
|
||||
if (a == null || b == null) return false; |
||||
// `NaN`s are equivalent, but non-reflexive.
|
||||
if (a !== a) return b !== b; |
||||
// Exhaust primitive checks
|
||||
var type = typeof a; |
||||
if (type !== 'function' && type !== 'object' && typeof b != 'object') return false; |
||||
|
||||
// skip function
|
||||
if (type === 'function') return true; |
||||
|
||||
return deepEq(a, b, aStack, bStack); |
||||
}; |
||||
|
||||
function isEqual(a, b) { |
||||
return eq(a, b); |
||||
} |
||||
|
||||
var allModelInstances = {}; |
||||
var emptyFn = function emptyFn() {}; |
||||
|
||||
var Watcher = function Watcher(_ref) { |
||||
var get = _ref.get, |
||||
last = _ref.last, |
||||
listener = _ref.listener, |
||||
sync = _ref.sync, |
||||
deep = _ref.deep; |
||||
|
||||
_classCallCheck(this, Watcher); |
||||
|
||||
this.get = get; |
||||
this.last = cloneShadow(last); |
||||
this.listener = listener || emptyFn; |
||||
this.sync = sync || false; |
||||
|
||||
return { |
||||
get: this.get, |
||||
last: this.last, |
||||
listener: this.listener |
||||
}; |
||||
}; |
||||
|
||||
function initState(vm, state) { |
||||
var watchers = vm._stateWatchers = {}; |
||||
for (var key in state) { |
||||
vm.model[key] = state[key]; |
||||
} |
||||
// state暂不支持func和context
|
||||
|
||||
var _loop2 = function _loop2(_key) { |
||||
var userDef = state[_key]; |
||||
|
||||
watchers[_key] = new Watcher({ |
||||
get: function get() { |
||||
return vm.model[_key]; |
||||
}, |
||||
last: userDef, |
||||
listener: vm.options.defaultCallback || emptyFn |
||||
}); |
||||
}; |
||||
|
||||
for (var _key in state) { |
||||
_loop2(_key); |
||||
} |
||||
} |
||||
|
||||
function initComputed(vm, computed) { |
||||
var watchers = vm._computedWatchers = {}; |
||||
var order = vm._computedOrder = []; |
||||
|
||||
for (var key in computed) { |
||||
var userDef = computed[key], |
||||
context = vm; |
||||
|
||||
order.push(key); |
||||
|
||||
watchers[key] = new Watcher({ |
||||
get: _$1.bind(userDef, context), |
||||
last: undefined, |
||||
listener: emptyFn |
||||
}); |
||||
} |
||||
} |
||||
|
||||
function initWatch(vm, watchObj) { |
||||
vm._watchers || (vm._watchers = []); |
||||
for (var expOrFn in watchObj) { |
||||
var handler = watchObj[expOrFn]; |
||||
if (_$1.isArray(handler)) { |
||||
for (var i = 0; i < handler.length; i++) { |
||||
watch(vm, expOrFn, handler[i]); |
||||
} |
||||
} else { |
||||
watch(vm, expOrFn, handler); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/* eslint no-param-reassign: ['off'] */ |
||||
function createWatcher(vm, expOrFn, cb) { |
||||
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; |
||||
|
||||
if (isPlainObject(cb)) { |
||||
options = cb; |
||||
cb = cb.handler; |
||||
} |
||||
if (typeof cb === 'string') { |
||||
cb = vm[cb]; |
||||
} |
||||
var getter = _$1.isFunction(expOrFn) ? _$1.bind(expOrFn, vm) : _$1.bind(function () { |
||||
return parsePath('model.' + expOrFn)(vm); |
||||
}, vm); |
||||
|
||||
return new Watcher({ |
||||
get: getter, |
||||
listener: _$1.bind(cb, vm), |
||||
last: getter(), |
||||
sync: options.sync, |
||||
deep: options.deep |
||||
}); |
||||
} |
||||
|
||||
function injectMethod(method, vm) { |
||||
return function () { |
||||
var result = method.apply(vm, [].concat(Array.prototype.slice.call(arguments))); |
||||
// 有回调的函数不作处理,拦截ajax请求
|
||||
vm.$digest(); |
||||
|
||||
return result; |
||||
}; |
||||
} |
||||
|
||||
function initMethods(vm, methods) { |
||||
for (var key in methods) { |
||||
vm[key] = methods[key] == null ? noop : injectMethod(methods[key], vm); |
||||
} |
||||
} |
||||
|
||||
function initMixins(vm) { |
||||
var mixins = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; |
||||
|
||||
_$1.each(mixins.reverse(), function (mixinType) { |
||||
var mixin$$1 = getMixins(mixinType); |
||||
|
||||
for (var key in mixin$$1) { |
||||
if (typeof mixin$$1[key] !== 'function') continue; |
||||
|
||||
if (_$1.has(vm, key)) continue; |
||||
|
||||
vm[key] = injectMethod(mixin$$1[key], vm); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
function defineContext(vm, keys) { |
||||
var watchers = vm._contextWatchers = {}; |
||||
|
||||
// 相关context挂上别的model中的修改监听
|
||||
function getSingleContext(key) { |
||||
var p = vm._parent; |
||||
while (p) { |
||||
if (p.childContext && p.childContext.indexOf(key) > -1) { |
||||
p.addWatch(key, function (cur, last, p) { |
||||
if (!vm.alive) return; |
||||
vm.model[key] = cur; |
||||
vm._contextWatchers[key].last = cloneShadow(cur); // 避免重复调用(可以改成给watch添加一个参数保证下次比较一定相同)
|
||||
vm.$digest(); |
||||
}); |
||||
|
||||
return { |
||||
p: p, |
||||
value: p.model[key] |
||||
}; |
||||
} |
||||
p = p._parent; |
||||
} |
||||
} |
||||
|
||||
_$1.each(keys, function (key) { |
||||
var context = getSingleContext(key); |
||||
if (!context) return; |
||||
vm.model[key] = context.p ? context.p.model[key] : undefined; |
||||
watchers[key] = new Watcher({ |
||||
get: function get() { |
||||
return vm.model[key]; |
||||
}, |
||||
last: vm.model[key], |
||||
listener: _$1.bind(function () { |
||||
context.p.model[key] = vm.model[key]; |
||||
context.p.$digest(); |
||||
}, context.p) |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
function addToListenerQueue(vm, watcher, cur, last) { |
||||
var listener = _$1.bind(watcher.listener, vm, cur, last, vm); |
||||
watcher.sync === true ? vm.syncListeners.push(listener) : vm.asyncListeners.push(listener); |
||||
} |
||||
|
||||
function digestState(vm) { |
||||
var dirty = false; |
||||
_$1.each(vm._stateWatchers, function (watcher, key) { |
||||
var cur = watcher.get(); |
||||
var last = watcher.last; |
||||
if (!isEqual(cur, last)) { |
||||
addToListenerQueue(vm, watcher, cur, last); |
||||
vm.model[key] = cur; |
||||
dirty = true; |
||||
watcher.last = cloneShadow(cur); |
||||
} |
||||
}); |
||||
|
||||
return dirty; |
||||
} |
||||
|
||||
function digestComputed(vm) { |
||||
var dirty = false; |
||||
var dirtyQueue = [], |
||||
cleanQueue = []; |
||||
|
||||
_$1.each(vm._computedOrder, function (key) { |
||||
var watcher = vm._computedWatchers[key]; |
||||
|
||||
try { |
||||
var cur = watcher.get(); |
||||
var last = watcher.last; |
||||
if (!isEqual(cur, last)) { |
||||
addToListenerQueue(vm, watcher, cur, last); |
||||
vm.model[key] = cur; |
||||
dirty = true; |
||||
dirtyQueue.push(key); |
||||
watcher.last = cloneShadow(cur); |
||||
} else { |
||||
cleanQueue.push(key); |
||||
} |
||||
} catch (err) { |
||||
dirty = true; |
||||
dirtyQueue.push(key); |
||||
} |
||||
}); |
||||
|
||||
vm._computedOrder = [].concat(cleanQueue, dirtyQueue); |
||||
|
||||
return dirty; |
||||
} |
||||
|
||||
function digestContext(vm) { |
||||
var dirty = false; |
||||
_$1.each(vm._contextWatchers, function (watcher, key) { |
||||
var cur = watcher.get(); |
||||
var last = watcher.last; |
||||
if (!isEqual(cur, last)) { |
||||
var listener = _$1.bind(watcher.listener, vm, cur, last, vm); |
||||
vm.contextListeners.push(listener); |
||||
vm.model[key] = cur; |
||||
dirty = true; |
||||
watcher.last = cloneShadow(cur); |
||||
} |
||||
}); |
||||
|
||||
return dirty; |
||||
} |
||||
|
||||
function digest(vm) { |
||||
var ttl = 10, |
||||
dirty = true; |
||||
do { |
||||
dirty = digestState(vm) || digestContext(vm) || digestComputed(vm); |
||||
} while (dirty && ttl-- >= 0); |
||||
} |
||||
|
||||
function executeWatchListeners(vm) { |
||||
var syncListeners = [].concat(vm.syncListeners || []); |
||||
var asyncListeners = [].concat(vm.asyncListeners || []); |
||||
var contextListeners = [].concat(vm.contextListeners || []); |
||||
|
||||
vm.asyncListeners = []; |
||||
vm.syncListeners = []; |
||||
|
||||
var watchers = [].concat(vm._watchers); |
||||
|
||||
_$1.each(watchers, function (watcher) { |
||||
var cur = watcher.get(); |
||||
var last = watcher.last; |
||||
|
||||
if (_$1.isEqual(cur, last)) return; |
||||
|
||||
var listner = _$1.bind(watcher.listener, vm, cur, last, vm); |
||||
|
||||
watcher.sync === true ? syncListeners.push(listner) : asyncListeners.push(listner); |
||||
|
||||
watcher.last = cloneShadow(cur); |
||||
}); |
||||
|
||||
_$1.each(syncListeners, function (listener) { |
||||
listener(); |
||||
}); |
||||
|
||||
nextTick(function () { |
||||
_$1.each(contextListeners, function (listener) { |
||||
listener(); |
||||
}); |
||||
|
||||
_$1.each(asyncListeners, function (listener) { |
||||
if (!vm.alive) return; |
||||
listener(); |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
var Model = function () { |
||||
function Model(model) { |
||||
_classCallCheck(this, Model); |
||||
|
||||
this.alive = true; |
||||
this.options = model || {}; |
||||
this.model = { |
||||
$vm: this |
||||
}; |
||||
this._modelHashId = makeHashCode('model'); |
||||
this.syncListeners = []; |
||||
this.asyncListeners = []; |
||||
this.contextListeners = []; |
||||
|
||||
this._parent = Model.target; |
||||
var state = _$1.isFunction(this.state) ? this.state() : this.state; |
||||
var computed = this.computed; |
||||
// Todo
|
||||
var context = this.context; |
||||
var childContext = this.childContext; |
||||
var watch$$1 = this.watch; |
||||
var actions = this.actions; |
||||
var mixins = this.mixins; |
||||
|
||||
context && defineContext(this, context); |
||||
|
||||
initMixins(this, mixins); |
||||
this._init(); |
||||
initState(this, state); |
||||
initComputed(this, computed); |
||||
digest(this); |
||||
initWatch(this, watch$$1); |
||||
initMethods(this, actions); |
||||
this.created && this.created(); |
||||
allModelInstances[this._modelHashId] = this; |
||||
} |
||||
|
||||
Model.prototype._init = function _init() {}; |
||||
|
||||
Model.prototype.addWatch = function addWatch(expOrFn, cb, options) { |
||||
var watcher = createWatcher(this, expOrFn, cb, options); |
||||
this._watchers.push(watcher); |
||||
}; |
||||
|
||||
Model.prototype.destroy = function destroy() { |
||||
this.alive = false; |
||||
allModelInstances[this._modelHashId] = null; |
||||
this._watchers && (this._watchers = []); |
||||
this._computedWatchers && (this._computedWatchers = []); |
||||
this._stateWatchers && (this._stateWatchers = []); |
||||
this._contextWatchers && (this._contextWatchers = []); |
||||
this.destroyed && this.destroyed(); |
||||
}; |
||||
|
||||
Model.prototype.$digest = function $digest() { |
||||
digest(this); |
||||
|
||||
executeWatchListeners(this); |
||||
}; |
||||
|
||||
return Model; |
||||
}(); |
||||
|
||||
function getAllModelInstances() { |
||||
return allModelInstances; |
||||
} |
||||
|
||||
function refreshAll() { |
||||
_$1.each(getAllModelInstances(), function (insta) { |
||||
insta && insta.$digest && insta.$digest(); |
||||
}); |
||||
} |
||||
|
||||
function toJSON(model) { |
||||
var result = void 0; |
||||
if (_.isArray(model)) { |
||||
result = []; |
||||
for (var i = 0, len = model.length; i < len; i++) { |
||||
result[i] = toJSON(model[i]); |
||||
} |
||||
} else if (model && isPlainObject(model)) { |
||||
result = {}; |
||||
for (var key in model) { |
||||
if (!_.has($$skipArray, key)) { |
||||
result[key] = toJSON(model[key]); |
||||
} |
||||
} |
||||
} else { |
||||
result = model; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
var version = '2.0'; |
||||
|
||||
exports.version = version; |
||||
exports.$$skipArray = $$skipArray; |
||||
exports.mixin = mixin; |
||||
exports.Model = Model; |
||||
exports.getAllModelInstances = getAllModelInstances; |
||||
exports.refreshAll = refreshAll; |
||||
exports.inherit = inherit; |
||||
exports.watch = watch; |
||||
exports.toJSON = toJSON; |
||||
|
||||
exports.__esModule = true; |
||||
}); |
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue