migi
Version:
A JavaScript MVVM on JSX
898 lines (852 loc) • 28.9 kB
JavaScript
define(function(require, exports, module){'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _Event = require('./Event');
var _Event2 = _interopRequireDefault(_Event);
var _Component = require('./Component');
var _Component2 = _interopRequireDefault(_Component);
var _Cb = require('./Cb');
var _Cb2 = _interopRequireDefault(_Cb);
var _util = require('./util');
var _util2 = _interopRequireDefault(_util);
var _browser = require('./browser');
var _browser2 = _interopRequireDefault(_browser);
var _range = require('./range');
var _range2 = _interopRequireDefault(_range);
var _cachePool = require('./cachePool');
var _cachePool2 = _interopRequireDefault(_cachePool);
var _type = require('./type');
var _type2 = _interopRequireDefault(_type);
var _hash = require('./hash');
var _hash2 = _interopRequireDefault(_hash);
var _matchHash = require('./matchHash');
var _matchHash2 = _interopRequireDefault(_matchHash);
var _fixEvent = require('./fixEvent');
var _fixEvent2 = _interopRequireDefault(_fixEvent);
var _delegate = require('./delegate');
var _delegate2 = _interopRequireDefault(_delegate);
var _Obj = require('./Obj');
var _Obj2 = _interopRequireDefault(_Obj);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function replaceWith(elem, cns, index, vd, isText) {
// insertAdjacentHTML在插入text时浏览器行为表现不一致,ff会合并相邻text,chrome则不会
// 因此DOM使用insertAdjacentHTML,text则用textNode
var target;
if (isText) {
var s = _util2.default.stringify(vd);
target = document.createTextNode(s || '');
elem.replaceChild(target, cns[index]);
} else {
target = vd.toString();
// textNode没有insertAdjacentHTML方法,必须使用replaceChild
if (cns[index].nodeType == 1) {
cns[index].insertAdjacentHTML('afterend', target);
elem.removeChild(cns[index]);
} else {
var node = _browser2.default.getParent(vd.__name);
node.innerHTML = target;
elem.replaceChild(node.firstChild, cns[index]);
}
// 别忘了触发DOM事件
vd.emit(_Event2.default.DOM);
}
}
function insertAt(elem, cns, index, vd, isText) {
var target;
if (isText) {
var s = _util2.default.stringify(vd);
target = document.createTextNode(s || '');
if (index >= cns.length) {
elem.appendChild(target);
} else {
elem.insertBefore(target, cns[index]);
}
} else {
target = vd.toString();
if (index >= cns.length) {
elem.insertAdjacentHTML('beforeend', target);
} else {
if (cns[index].nodeType == 1) {
cns[index].insertAdjacentHTML('beforebegin', target);
} else {
var node = _browser2.default.getParent(vd.__name);
node.innerHTML = target;
elem.insertBefore(node.firstChild, cns[index]);
}
}
// 别忘了触发DOM事件
vd.emit(_Event2.default.DOM);
}
}
function add(parent, elem, vd, record, temp, last) {
if (Array.isArray(vd)) {
record.index.push(0);
// 防止空数组跳过的情况
for (var i = 0, len = Math.max(vd.length, 1); i < len; i++) {
var item = vd[i];
record.index[record.index.length - 1] = i;
add(parent, elem, item, record, temp, last && i == len - 1);
}
record.index.pop();
} else if (_util2.default.isDom(vd)) {
vd.__parent = parent;
vd.__top = parent.top;
vd.style = parent.style;
_hash2.default.set(vd);
if (temp.prev) {
if (temp.prev == _type2.default.TEXT) {
record.start++;
}
insertAt(elem, elem.childNodes, record.start++, vd);
} else {
switch (record.state) {
case _type2.default.DOM_TO_TEXT:
case _type2.default.TEXT_TO_TEXT:
// 第一次添加dom时,即使之前的text没有变化,也需记录range,但可能影响之后的t2t,也需记录
addRange(record);
record.start++;
break;
case _type2.default.TEXT_TO_DOM:
break;
case _type2.default.DOM_TO_DOM:
break;
}
insertAt(elem, elem.childNodes, record.start++, vd);
}
temp.prev = _type2.default.DOM;
} else {
if (temp.prev) {
if (temp.prev == _type2.default.DOM) {
insertAt(elem, elem.childNodes, record.start, vd, true);
recordRange(record);
}
addRange(record);
} else {
switch (record.state) {
case _type2.default.DOM_TO_TEXT:
case _type2.default.TEXT_TO_TEXT:
addRange(record);
break;
case _type2.default.TEXT_TO_DOM:
insertAt(elem, elem.childNodes, record.start, vd, true);
recordRange(record);
addRange(record);
break;
case _type2.default.DOM_TO_DOM:
insertAt(elem, elem.childNodes, record.start, vd, true);
recordRange(record);
break;
}
}
temp.prev = _type2.default.TEXT;
}
// add结束后,根据之前的state和最后add的d/t假设出当前等同的状态
if (last) {
switch (record.state) {
case _type2.default.TEXT_TO_TEXT:
if (temp.prev == _type2.default.DOM) {
record.state = _type2.default.TEXT_TO_DOM;
}
break;
case _type2.default.DOM_TO_DOM:
if (temp.prev == _type2.default.TEXT) {
record.state = _type2.default.DOM_TO_TEXT;
}
break;
case _type2.default.TEXT_TO_DOM:
if (temp.prev == _type2.default.TEXT) {
record.state = _type2.default.TEXT_TO_TEXT;
}
break;
case _type2.default.DOM_TO_TEXT:
if (temp.prev == _type2.default.DOM) {
record.state = _type2.default.DOM_TO_DOM;
}
break;
}
record.prev = temp.prev;
}
}
function del(elem, vd, record, temp, last) {
if (Array.isArray(vd)) {
for (var i = 0, len = vd.length; i < len; i++) {
del(elem, vd[i], record, temp, last && i == len - 1);
}
} else if (_util2.default.isDom(vd)) {
switch (record.state) {
case _type2.default.DOM_TO_TEXT:
case _type2.default.TEXT_TO_TEXT:
removeAt(elem, record.start + 1);
break;
case _type2.default.TEXT_TO_DOM:
case _type2.default.DOM_TO_DOM:
removeAt(elem, record.start);
break;
}
temp.prev = _type2.default.DOM;
// 缓存对象池
// 遍历孩子vd回收
_util2.default.getAllChildrenElement(vd).forEach(function (item) {
_cachePool2.default.add(item.__destroy());
});
_cachePool2.default.add(vd.__destroy());
} else {
if (temp.prev) {
if (temp.prev == _type2.default.DOM) {
switch (record.state) {
case _type2.default.DOM_TO_TEXT:
removeAt(elem, record.start + 1);
addRange(record);
break;
case _type2.default.TEXT_TO_TEXT:
removeAt(elem, record.start + 1);
addRange(record);
break;
case _type2.default.DOM_TO_DOM:
removeAt(elem, record.start);
break;
case _type2.default.TEXT_TO_DOM:
removeAt(elem, record.start);
break;
}
}
// 删过text,之后的text自动一并删除,可以忽略
// else {}
} else {
switch (record.state) {
case _type2.default.DOM_TO_TEXT:
removeAt(elem, record.start + 1);
addRange(record);
break;
case _type2.default.TEXT_TO_TEXT:
addRange(record);
break;
case _type2.default.DOM_TO_DOM:
removeAt(elem, record.start);
break;
case _type2.default.TEXT_TO_DOM:
break;
}
}
temp.prev = _type2.default.TEXT;
}
if (last) {
switch (record.state) {
case _type2.default.TEXT_TO_TEXT:
if (temp.prev == _type2.default.DOM) {
record.state = _type2.default.DOM_TO_TEXT;
} else {
addRange(record);
}
break;
case _type2.default.DOM_TO_DOM:
if (temp.prev == _type2.default.TEXT) {
record.state = _type2.default.TEXT_TO_DOM;
}
break;
case _type2.default.TEXT_TO_DOM:
if (temp.prev == _type2.default.DOM) {
record.state = _type2.default.DOM_TO_DOM;
}
break;
case _type2.default.DOM_TO_TEXT:
if (temp.prev == _type2.default.TEXT) {
record.state = _type2.default.TEXT_TO_TEXT;
}
break;
}
}
}
function removeAt(elem, start) {
// 当table省略tbody直接写tr时,浏览器可能会自动生成tbody节点,diff时不在对比内会造成bug,提前判断下
if (elem.childNodes[start]) {
elem.removeChild(elem.childNodes[start]);
}
}
function equalText(a, b) {
if (a === undefined || a === null) {
a = '';
}
if (b === undefined || b === null) {
b = '';
}
return a.toString() == b.toString();
}
function recordRange(record) {
record.history = record.index.slice();
}
function addRange(record) {
var start = record.start;
// 连续text更新防止重复,它们的dom索引start相同
if (record.range.length && record.range[record.range.length - 1].start == start) {
return;
}
record.range.push({
start: start,
index: record.history.slice()
});
}
function diffVd(ovd, nvd) {
// 相同引用说明没发生变更,在一些使用常量、变量未变的情况下会如此
if (ovd == nvd) {
return;
}
// 特殊的uid,以及一些引用赋给新vd
var elem = ovd.element;
var props = ['__uid', '__element', '__parent', '__top', '__style', '__dom', '__names'];
var i = props.length - 1;
for (; i >= 0; i--) {
var k = props[i];
nvd[k] = ovd[k];
}
// vd记录更新uid引用
_hash2.default.set(nvd);
// 记录对比过的prop
var temp = {};
for (i = ovd.__props.length - 1; i >= 0; i--) {
var item = ovd.__props[i];
var k = item[0];
// 只检查普通属性,onXXX事件由__listener中的引用移除
if (k.indexOf('on') != 0 || k == 'on') {
temp[k] = true;
// 对比老属性,多余删除,相同无需更新
if (nvd.props.hasOwnProperty(k)) {
var v = item[1];
var nv = nvd.props[k];
if (nv instanceof _Obj2.default) {
nv = nv.v;
}
if (v instanceof _Obj2.default) {
v = v.v;
}
if (nv !== v) {
nvd.__updateAttr(k, nv);
}
nvd.__cache[k] = nv;
} else {
nvd.__updateAttr(k, null);
delete nvd.__cache[k];
}
}
}
// 移除__listener记录的引用
ovd.__removeListener();
// 添加新vd的属性
var len = nvd.__props.length;
var _loop = function _loop() {
item = nvd.__props[i];
k = item[0];
var v = item[1];
if (v instanceof _Obj2.default) {
v = v.v;
}
// 事件和属性区分对待
if (k.indexOf('on') == 0 && k != 'on') {
name = k.slice(2).toLowerCase();
nvd.__addListener(name, function (e) {
e = e || window.event;
(0, _fixEvent2.default)(e);
var target = e.target;
var uid = target.getAttribute('migi-uid');
var tvd = _hash2.default.get(uid);
if (v instanceof _Cb2.default) {
v.cb.call(v.context, e, nvd, tvd);
} else if (_util2.default.isFunction(v)) {
v(e, nvd, tvd);
} else if (Array.isArray(v)) {
v.forEach(function (item) {
var cb = item[1];
if ((0, _delegate2.default)(e, item[0], nvd)) {
if (cb instanceof _Cb2.default) {
cb.cb.call(cb.context, e, nvd, tvd);
} else if (_util2.default.isFunction(cb)) {
cb(e, nvd, tvd);
}
}
});
}
});
} else if (!temp.hasOwnProperty(k)) {
nvd.__updateAttr(k, v);
}
};
for (i = 0; i < len; i++) {
var item;
var k;
var name;
_loop();
}
if (nvd.__style) {
nvd.__updateStyle(true);
}
var record = { start: 0, index: [], range: [], first: true };
diffChild(nvd, elem, ovd.children, nvd.children, record);
if (record.range.length) {
// textarea特殊判断
if (nvd.__name == 'textarea') {
nvd.__updateAttr('value', _range2.default.value(record.range[0], nvd.children));
return;
}
for (var i = 0, len = record.range.length; i < len; i++) {
_range2.default.update(record.range[i], nvd.children, elem);
}
}
// 缓存对象池
_cachePool2.default.add(ovd.__destroy());
}
function diff(parent, elem, ov, nv, record, opt) {
if (opt) {
diffArray(parent, elem, ov, nv, record, opt);
} else {
diffChild(parent, elem, ov, nv, record);
}
}
function diffChild(parent, elem, ovd, nvd, record) {
if (ovd instanceof _Obj2.default) {
ovd = ovd.v;
}
if (nvd instanceof _Obj2.default) {
nvd = nvd.v;
}
// 新老值是否是数组处理方式不同
var oa = Array.isArray(ovd);
var na = Array.isArray(nvd);
// 都是数组时,还要检查二者长度
if (oa && na) {
var ol = ovd.length;
var nl = nvd.length;
var os = ol ? 1 : 0;
var ns = nl ? 2 : 0;
record.index.push(0);
switch (os | ns) {
// 都是空数组
case 0:
if (record.state == _type2.default.TEXT_TO_DOM) {
insertAt(elem, elem.childNodes, record.start++, nvd, true);
}
record.state = _type2.default.TEXT_TO_TEXT;
record.prev = _type2.default.TEXT;
break;
// 有内容的数组变为空数组
case 1:
diffChild(parent, elem, ovd[0], nvd[0], record);
var temp = {};
for (var i = 1; i < ol; i++) {
del(elem, ovd[i], record, temp, i == ol - 1);
}
break;
// 空数组变为有内容
case 2:
diffChild(parent, elem, ovd[0], nvd[0], record);
var temp = {};
for (var i = 1; i < nl; i++) {
record.index[record.index.length - 1] = i;
add(parent, elem, nvd[i], record, temp, i == nl - 1);
}
break;
// 都有内容
case 3:
for (var i = 0, len = Math.min(ol, nl); i < len; i++) {
record.index[record.index.length - 1] = i;
diffChild(parent, elem, ovd[i], nvd[i], record);
}
var temp = {};
// 老的多余的删除
if (i < ol) {
for (; i < ol; i++) {
del(elem, ovd[i], record, temp, i == ol - 1);
}
}
// 新的多余的插入
else if (i < nl) {
for (; i < nl; i++) {
record.index[record.index.length - 1] = i;
add(parent, elem, nvd[i], record, temp, i == nl - 1);
}
}
break;
}
record.index.pop();
}
// 老的是数组新的不是
else if (oa) {
// 将老的第1个和新的相比,注意老的第一个可能还是个数组,递归下去
diffChild(parent, elem, ovd[0], nvd, record);
// 移除剩余的老的
var temp = {};
for (var i = 1, len = ovd.length; i < len; i++) {
del(elem, ovd[i], record, temp, i == len - 1);
}
}
// 新的是数组老的不是
else if (na) {
record.index.push(0);
// 将新的第1个和老的相比,注意新的第一个可能还是个数组,递归下去
diffChild(parent, elem, ovd, nvd[0], record);
var temp = {};
// 增加剩余的新的
for (var i = 1, len = nvd.length; i < len; i++) {
record.index[record.index.length - 1] = i;
add(parent, elem, nvd[i], record, temp, i == len - 1);
}
record.index.pop();
}
// 都不是数组
else {
var oe = _util2.default.isDom(ovd) ? 1 : 0;
var ne = _util2.default.isDom(nvd) ? 2 : 0;
var cns = elem.childNodes;
switch (oe | ne) {
// 都是text时,根据上个状态设置range
case 0:
if (record.first) {
// 先尝试记录range,连续的text会去重,始终以第一个text为准,后续的防重不会被记录
// 记录后只有text发生改变时才会将这条记录状态改变
recordRange(record);
if (!equalText(ovd, nvd)) {
addRange(record);
}
} else {
switch (record.state) {
case _type2.default.DOM_TO_TEXT:
elem.removeChild(cns[record.start + 1]);
// 因之前发生的d2t变更,本次t2t无需对比直接记录
addRange(record);
break;
case _type2.default.TEXT_TO_DOM:
insertAt(elem, cns, record.start, nvd, true);
recordRange(record);
// 因之前发生t2d变更,即便本次没有发生变化,但可能影响之后的t2t,也需记录
addRange(record);
break;
case _type2.default.DOM_TO_DOM:
recordRange(record);
case _type2.default.TEXT_TO_TEXT:
if (!equalText(ovd, nvd)) {
addRange(record);
}
break;
}
}
record.state = _type2.default.TEXT_TO_TEXT;
record.prev = _type2.default.TEXT;
break;
// DOM变TEXT
case 1:
ovd.__delRef();
if (record.first) {
replaceWith(elem, cns, record.start, nvd, true);
recordRange(record);
} else {
switch (record.state) {
case _type2.default.DOM_TO_TEXT:
case _type2.default.TEXT_TO_TEXT:
addRange(record);
elem.removeChild(cns[record.start + 1]);
break;
case _type2.default.TEXT_TO_DOM:
case _type2.default.DOM_TO_DOM:
replaceWith(elem, cns, record.start, nvd, true);
recordRange(record);
break;
}
}
// 遍历孩子vd回收
_util2.default.getAllChildrenElement(ovd).forEach(function (item) {
_cachePool2.default.add(item.__destroy());
});
// 缓存对象池
_cachePool2.default.add(ovd.__destroy());
record.state = _type2.default.DOM_TO_TEXT;
record.prev = _type2.default.TEXT;
break;
// TEXT变DOM
case 2:
// 这种情况下相当于add新vd,无parent和style引用
nvd.__parent = parent;
nvd.__top = parent.top;
nvd.style = parent.style;
_hash2.default.set(nvd);
if (record.first) {
replaceWith(elem, cns, record.start++, nvd);
} else {
switch (record.state) {
case _type2.default.DOM_TO_TEXT:
record.start++;
case _type2.default.DOM_TO_DOM:
replaceWith(elem, cns, record.start++, nvd);
break;
case _type2.default.TEXT_TO_DOM:
insertAt(elem, cns, record.start++, nvd);
break;
case _type2.default.TEXT_TO_TEXT:
addRange(record);
insertAt(elem, cns, ++record.start, nvd);
record.start++;
break;
}
}
record.state = _type2.default.TEXT_TO_DOM;
record.prev = _type2.default.DOM;
break;
// DOM变DOM
case 3:
switch (record.state) {
// case type.DOM_TO_DOM:
// case type.TEXT_TO_DOM:
// break;
case _type2.default.DOM_TO_TEXT:
case _type2.default.TEXT_TO_TEXT:
record.start++;
break;
}
var ocp = ovd instanceof _Component2.default ? 1 : 0;
var ncp = nvd instanceof _Component2.default ? 2 : 0;
switch (ocp | ncp) {
// DOM名没变递归diff,否则重绘
case 0:
ovd.__delRef();
if (ovd.__name == nvd.__name) {
ovd.__parent = parent;
ovd.__top = parent.top;
diffVd(ovd, nvd);
nvd.__saveRef();
} else {
nvd.__parent = parent;
nvd.__top = parent.top;
nvd.style = parent.style;
elem = ovd.element;
elem.insertAdjacentHTML('afterend', nvd.toString());
elem.parentNode.removeChild(elem);
nvd.emit(_Event2.default.DOM);
_matchHash2.default.del(ovd.__uid);
_hash2.default.set(nvd);
// 缓存对象池
_cachePool2.default.add(ovd.__destroy());
}
break;
// Component和VirtualDom变化则直接重绘
default:
ovd.__delRef();
elem = ovd.element;
elem.insertAdjacentHTML('afterend', nvd.toString());
elem.parentNode.removeChild(elem);
nvd.__parent = parent;
nvd.__top = parent.top;
// match中为模拟style的:active伪类注册了window的一些事件,需检查移除
if (ocp) {
_matchHash2.default.del(ovd.virtualDom.__uid);
} else {
_matchHash2.default.del(ovd.__uid);
}
nvd.style = parent.style;
nvd.emit(_Event2.default.DOM);
_hash2.default.set(nvd);
// 遍历孩子vd回收
_util2.default.getAllChildrenElement(ocp ? ovd.__virtualDom : ovd).forEach(function (item) {
_cachePool2.default.add(item.__destroy());
});
// 缓存对象池
_cachePool2.default.add(ovd.__destroy());
break;
}
record.state = _type2.default.DOM_TO_DOM;
record.prev = _type2.default.DOM;
record.start++;
break;
}
}
record.first = false;
}
function checkText(elem, vd, record) {
if (record.state == _type2.default.TEXT_TO_DOM) {
insertAt(elem, elem.childNodes, record.start, vd, true);
recordRange(record);
addRange(record);
} else if (record.state == _type2.default.DOM_TO_TEXT) {
addRange(record);
removeAt(elem, record.start + 1);
}
}
function diffArray(parent, elem, ovd, nvd, record, opt) {
if (ovd instanceof _Obj2.default) {
ovd = ovd.v;
}
if (nvd instanceof _Obj2.default) {
nvd = nvd.v;
}
var ol = ovd.length;
var nl = nvd.length;
var os = ol ? 1 : 0;
var ns = nl ? 2 : 0;
record.index.push(0);
switch (os | ns) {
// 都是空数组
case 0:
if (record.state == _type2.default.TEXT_TO_DOM) {
insertAt(elem, elem.childNodes, record.start++, nvd, true);
}
record.state = _type2.default.TEXT_TO_TEXT;
record.prev = _type2.default.TEXT;
break;
// 有内容的数组变为空数组
case 1:
diffChild(parent, elem, ovd[0], nvd[0], record);
var temp = {};
for (var i = 1; i < ol; i++) {
del(elem, ovd[i], record, temp, i == ol - 1);
}
break;
// 空数组变为有内容
case 2:
diffChild(parent, elem, ovd[0], nvd[0], record);
var temp = {};
for (var i = 1; i < nl; i++) {
record.index[record.index.length - 1] = i;
add(parent, elem, nvd[i], record, temp, i == nl - 1);
}
break;
// 都有内容
case 3:
var oFirst = _util2.default.arrFirst(ovd);
var nFirst = _util2.default.arrFirst(nvd);
var ot = _util2.default.isDom(oFirst) ? 1 : 0;
var nt = _util2.default.isDom(nFirst) ? 2 : 0;
var temp = {};
switch (opt.method) {
case 'push':
if (!record.first && nt == 0) {
record.index[record.index.length - 1] = 0;
checkText(elem, nFirst, record);
}
for (var i = 0; i < ol; i++) {
record.index[record.index.length - 1] = i;
scan(elem, nvd[i], record);
}
// 可能push多个参数
for (; i < nl; i++) {
record.index[record.index.length - 1] = i;
add(parent, elem, nvd[i], record, temp, i == nl - 1);
}
break;
case 'pop':
if (!record.first && nt == 0) {
record.index[record.index.length - 1] = 0;
checkText(elem, nFirst, record);
}
for (var i = 0; i < nl; i++) {
record.index[record.index.length - 1] = i;
scan(elem, nvd[i], record);
}
del(elem, ovd[nl], record, {}, true);
break;
case 'unshift':
if (record.first) {
record.state = _type2.default.DOM_TO_DOM;
}
for (var i = 0; i < nl - ol; i++) {
record.index[record.index.length - 1] = i;
add(parent, elem, nvd[i], record, temp, i == nl - ol - 1);
}
if (ot == 0) {
record.index[record.index.length - 1] = i;
checkText(elem, oFirst, record);
}
for (; i < nl; i++) {
record.index[record.index.length - 1] = i;
scan(elem, nvd[i], record);
}
break;
case 'shift':
if (record.first) {
record.state = _type2.default.DOM_TO_DOM;
}
del(elem, ovd[0], record, {}, true);
if (nt == 0) {
record.index[record.index.length - 1] = 0;
checkText(elem, nFirst, record);
}
for (var i = 0; i < nl; i++) {
record.index[record.index.length - 1] = i;
scan(elem, nvd[i], record);
}
break;
case 'splice':
var index = opt.args[0];
var delLen = opt.args[1];
var addLen = opt.args.length - 2;
for (var i = 0; i < index; i++) {
record.index[record.index.length - 1] = i;
scan(elem, nvd[i], record);
}
if (record.first) {
record.state = _type2.default.DOM_TO_DOM;
}
for (; i < Math.min(delLen, addLen) + index; i++) {
record.index[record.index.length - 1] = i;
diffChild(parent, elem, ovd[i], nvd[i], record);
}
if (delLen > addLen) {
for (var j = i; j < delLen + index; j++) {
del(elem, ovd[j], record, temp, j == delLen + index - 1);
}
} else if (delLen < addLen) {
for (; i < addLen + index; i++) {
record.index[record.index.length - 1] = i;
add(parent, elem, nvd[i], record, temp, i == addLen + index - 1);
}
}
if (i < nl) {
nFirst = _util2.default.arrFirst(nvd[i]);
if (!_util2.default.isDom(nFirst)) {
record.index[record.index.length - 1] = i;
checkText(elem, nFirst, record);
}
}
for (; i < nl; i++) {
record.index[record.index.length - 1] = i;
scan(elem, nvd[i], record);
}
break;
}
break;
}
record.index.pop();
record.first = false;
}
function scan(elem, vd, record) {
if (vd instanceof _Obj2.default) {
vd = vd.v;
}
if (Array.isArray(vd)) {
record.index.push(0);
for (var i = 0, len = vd.length; i < len; i++) {
record.index[record.index.length - 1] = i;
scan(elem, vd[i], record);
}
record.index.pop();
} else {
if (_util2.default.isDom(vd)) {
if (record.prev == _type2.default.TEXT) {
record.start++;
}
record.state = _type2.default.DOM_TO_DOM;
record.prev = _type2.default.DOM;
record.start++;
} else {
if (record.first || record.prev == _type2.default.DOM) {
recordRange(record);
}
record.state = _type2.default.TEXT_TO_TEXT;
record.prev = _type2.default.TEXT;
}
record.first = false;
}
}
exports.default = {
diff: diff,
checkText: checkText,
recordRange: recordRange,
addRange: addRange
};});