You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
886 lines
29 KiB
886 lines
29 KiB
6 years ago
|
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;
|
||
|
});
|