@rucebee/recycler-vue
Version:
Android RecyclerView port for Vue.js
721 lines (547 loc) • 20.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.AbstractSource = AbstractSource;
exports.ListSource = ListSource;
exports.WaterfallSource = WaterfallSource;
exports.HistorySource = HistorySource;
exports.ProxySource = ProxySource;
var _findIndex = _interopRequireDefault(require("lodash/findIndex"));
var _findLast2 = _interopRequireDefault(require("lodash/findLast"));
var _noop = _interopRequireDefault(require("lodash/noop"));
var _timeout = _interopRequireDefault(require("@rucebee/utils/src/timeout"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
function AbstractSource() {
var _this = this;
var list = [];
var recycler;
this.attached = false;
this.list = list;
this.getItem = function (position) {
return list[position];
};
this.itemCount = function () {
return list.length;
};
this.indexOf = function (item, fromIndex) {
return list.indexOf(item, fromIndex);
};
this.findIndex = function () {
return _findIndex["default"].apply(void 0, [list].concat(Array.prototype.slice.call(arguments)));
};
this.insert = function (position) {
for (var _len = arguments.length, items = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
items[_key - 1] = arguments[_key];
}
if (typeof position !== 'number') {
position = _this.indexOf(position);
if (position < 0) return;
if (typeof items[0] === 'number') position += items.shift();
}
list.splice.apply(list, [position, 0].concat(items));
_this.onInsert(position, items.length);
return _this;
};
this.remove = function (position) {
var count = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
if (typeof position !== 'number') {
position = _this.indexOf(position);
if (position < 0) return;
}
list.splice(position, count);
_this.onRemove(position, count);
return _this;
};
this.reset = function (_list) {
if (list.length) _this.onRemove(0, list.length);
list.length = 0;
if (_list !== null && _list !== void 0 && _list.length) {
list.push.apply(list, _toConsumableArray(_list));
_this.onInsert(0, _list.length);
}
return _this;
};
this.attach = function (_recycler) {
if (recycler !== _recycler) {
_this.onRecyclerChanged(recycler, _recycler);
_this.recycler = recycler = _recycler;
_this.recyclerDataset = recycler.onDatasetChanged;
_this.recyclerUpdate = recycler.onUpdate;
_this.recyclerInsert = recycler.onInsert;
_this.recyclerRemove = recycler.onRemove;
_this.triggerUpdate = recycler.update;
_this.startPosition = recycler.startPosition;
_this.endPosition = recycler.endPosition;
_this.recyclerDataset();
if (!_this.attached) {
_this.attached = true;
_this.onAttach();
}
}
};
this.detach = function (_recycler) {
if (_recycler && recycler !== _recycler) return;
if (recycler) _this.onRecyclerChanged(recycler, null);
_this.recycler = recycler = null;
if (_this.attached) {
_this.attached = false;
_this.onDetach();
}
_this.recyclerDataset = _noop["default"];
_this.recyclerUpdate = _noop["default"];
_this.recyclerInsert = _noop["default"];
_this.recyclerRemove = _noop["default"];
_this.triggerUpdate = _noop["default"];
_this.startPosition = function () {
return 0;
};
_this.endPosition = function () {
return -1;
};
};
this.detach();
}
AbstractSource.prototype.onRecyclerChanged = _noop["default"];
AbstractSource.prototype.onAttach = _noop["default"];
AbstractSource.prototype.onDetach = _noop["default"];
AbstractSource.prototype.onUpdate = function (position, count) {
this.recyclerUpdate(position, count);
};
AbstractSource.prototype.onInsert = function (position, count) {
this.recyclerInsert(position, count);
};
AbstractSource.prototype.onRemove = function (position, count) {
this.recyclerRemove(position, count);
};
AbstractSource.prototype.update = function () {
for (var _len2 = arguments.length, items = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
items[_key2] = arguments[_key2];
}
for (var _i = 0, _items = items; _i < _items.length; _i++) {
var item = _items[_i];
var position = typeof item !== 'number' ? this.indexOf(item) : item;
if (position > -1) this.onUpdate(position, 1);
}
return this;
};
AbstractSource.prototype.each = function (fn) {
for (var i = 0; i < this.list.length; i++) {
fn(this.list[i], i);
}
return this;
};
function PeriodicRefresh(query, period) {
var _this2 = this;
var before = 0,
nextTimeout = (0, _timeout["default"])(0),
attached = false;
var next = function next() {
var now = Date.now();
if (before <= now) {
_this2.query();
} else if (period && !_this2.request) {
nextTimeout.stop();
nextTimeout = (0, _timeout["default"])(before - now + 1000);
nextTimeout.then(function () {
if (attached) _this2.query();
}, _noop["default"]);
}
};
this.request = null;
this.attach = function () {
if (!attached) {
attached = true;
next();
}
};
this.detach = function () {
if (attached) {
attached = false;
nextTimeout.stop();
}
};
this.period = function (_period) {
period = _period;
if (period) {
before = Date.now() + period;
next();
} else {
nextTimeout.stop();
}
};
this.query = function (dirty) {
if (_this2.request) {
if (dirty) before = 0;
} else if (!attached) {
before = 0;
} else {
before = period ? Date.now() + period : Number.MAX_SAFE_INTEGER;
nextTimeout.stop(true);
_this2.request = query().then(function () {
_this2.request = null;
if (attached) next();
})["catch"](function (err) {
console.error(err);
if (attached) {
nextTimeout = (0, _timeout["default"])(5000, function () {
_this2.request = null;
});
nextTimeout.then(function () {
if (attached) _this2.query();
}, _noop["default"]);
} else {
_this2.request = null;
before = 0;
}
throw err;
});
}
};
}
function ListSource(query, period) {
var _this3 = this;
AbstractSource.call(this);
var list = this.list,
refresh = new PeriodicRefresh(function () {
return query.call(_this3).then(function (_list) {
_this3.onRemove(0, list.length);
list.length = 0;
_this3.insert.apply(_this3, [0].concat(_toConsumableArray(_list)));
});
}, period);
this.onAttach = refresh.attach;
this.onDetach = refresh.detach;
this.refresh = refresh.query;
}
ListSource.prototype = Object.create(AbstractSource.prototype);
ListSource.prototype.constructor = ListSource;
function subscribeRecyclerLaidout(from, to) {
if (from) from.$off('laidout', this.recyclerLaidout);
if (to) to.$on('laidout', this.recyclerLaidout);
}
function WaterfallSource(query, limit, loadingItem) {
var _this4 = this;
AbstractSource.call(this);
var list = this.list,
viewDistance = limit >> 1,
refresh = new PeriodicRefresh(function () {
var item = (0, _findLast2["default"])(list, 'id', list.length - 2);
return query.call(_this4, item, limit).then(function (_list) {
var _findLast;
if ((item === null || item === void 0 ? void 0 : item.id) !== ((_findLast = (0, _findLast2["default"])(list, 'id', list.length - 2)) === null || _findLast === void 0 ? void 0 : _findLast.id)) return;
if (_list !== null && _list !== void 0 && _list.length) {
_this4.insert.apply(_this4, [list.length - 1].concat(_toConsumableArray(_list)));
var startPos = _this4.startPosition();
if (startPos > limit) _this4.remove(0, startPos - viewDistance);
_this4.triggerUpdate();
} else if (loading) {
loading = false;
_this4.remove(loadingItem);
}
});
}, 0);
var loading = false,
attached = false;
this.onAttach = function () {
attached = true;
if (!loading) {
loading = true;
_this4.insert(list.length, loadingItem);
}
refresh.attach();
};
this.onDetach = function () {
attached = false;
refresh.detach();
};
this.reset = function () {
var len = list.length;
_this4.onRemove(0, len);
list.length = 0;
if (attached) {
_this4.insert(list.length, loadingItem);
loading = true;
}
};
this.recyclerLaidout = function (position, hs) {
if (loading && position + hs.length - 1 + viewDistance >= list.length) refresh.query();
};
this.cut = function (position) {
var len = list.length - position - 2;
if (loading) len--;
if (len < 1) return;
_this4.remove(position + 1, len);
if (!loading) {
loading = true;
_this4.insert(list.length, loadingItem);
}
_this4.triggerUpdate();
};
}
WaterfallSource.prototype = Object.create(AbstractSource.prototype);
WaterfallSource.prototype.constructor = WaterfallSource;
WaterfallSource.prototype.onRecyclerChanged = subscribeRecyclerLaidout;
function HistorySource(queryNext, queryHistory, limit, loadingItem) {
var _this5 = this;
var fromItem = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;
var period = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;
var historyItem = arguments.length > 6 ? arguments[6] : undefined;
AbstractSource.call(this);
if (!historyItem) historyItem = loadingItem;
var autoHistory = historyItem.type === 'loading';
var firstIndex = 1,
enabled = true,
attached = false;
var list = this.list,
viewDistance = limit >> 1,
cutHistory = function cutHistory() {
var startPos = _this5.startPosition();
if (startPos > limit && startPos - viewDistance < list.length - firstIndex) {
_this5.remove(firstIndex, startPos - viewDistance);
if (!firstIndex) {
firstIndex = 1;
_this5.insert(0, historyItem);
} //console.log('cutHistory', firstIndex, startPos - viewDistance, list[firstIndex])
return true;
}
},
nextRefresh = new PeriodicRefresh(function () {
return queryNext.call(_this5, list.length <= firstIndex ? fromItem : list[list.length - 1], limit).then(function (_list) {
//console.log('nextRefresh', {list, _list})
if (!fromItem && firstIndex) {
_this5.remove(0, 1);
_this5.insert(0, historyItem);
}
if (_list.length) {
if (list.length <= firstIndex) {
_this5.insert.apply(_this5, [list.length].concat(_toConsumableArray(_list)));
} else {
_this5.insert.apply(_this5, [list.length].concat(_toConsumableArray(_list)));
if (!historyRefresh.request) cutHistory();
}
if (_list.length >= limit) {
if (!fromItem) nextRefresh.query(true);
} else {
if (firstIndex) {
firstIndex = 0;
_this5.remove(0, 1);
}
if (fromItem) {
fromItem = null;
nextRefresh.period(period);
}
}
} else if (list.length <= firstIndex && firstIndex) {
firstIndex = 0;
_this5.remove(0, 1);
} else if (!historyRefresh.request) {
cutHistory();
}
});
}, fromItem ? 0 : period),
historyRefresh = new PeriodicRefresh(function () {
if (!firstIndex || list.length <= firstIndex) return Promise.resolve();
var item = list[firstIndex];
return queryHistory.call(_this5, list[firstIndex], limit).then(function (_list) {
if (!_list || !firstIndex || list.length <= firstIndex || item.id !== list[firstIndex].id || cutHistory()) return;
if (_list.length) _this5.insert.apply(_this5, [firstIndex].concat(_toConsumableArray(_list)));
if (_list.length < limit) {
firstIndex = 0;
_this5.remove(0);
} else {
_this5.triggerUpdate();
}
});
}, 0);
list.push(loadingItem);
this.empty = function () {
return list.length <= firstIndex;
};
this.refresh = nextRefresh.query;
this.refreshHistory = function () {
historyRefresh.query();
};
this._onAttach = function () {
attached = true;
if (enabled) {
nextRefresh.attach();
historyRefresh.attach();
}
};
this._onDetach = function () {
attached = false;
nextRefresh.detach();
historyRefresh.detach();
};
this.setEnabled = function (_enabled) {
enabled = _enabled;
if (attached) {
if (enabled) _this5.onAttach();else _this5.onDetach();
}
};
this.recyclerLaidout = function (position, hs) {
//console.log('recyclerLaidout', {position, hs, firstIndex, list, fromItem})
if (firstIndex && list.length > firstIndex) {
if (autoHistory && position <= viewDistance) historyRefresh.query();
if (fromItem && position + hs.length - 1 + viewDistance >= list.length) nextRefresh.query();
}
};
}
HistorySource.prototype = Object.create(AbstractSource.prototype);
HistorySource.prototype.constructor = HistorySource;
HistorySource.prototype.onAttach = function () {
this._onAttach();
};
HistorySource.prototype.onDetach = function () {
this._onDetach();
};
HistorySource.prototype.onRecyclerChanged = subscribeRecyclerLaidout;
function ProxySource() {
var _this6 = this;
for (var _len3 = arguments.length, srcs = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
srcs[_key3] = arguments[_key3];
}
AbstractSource.call(this);
this.srcs = srcs;
var self = this,
list = this.list;
var attached = false,
maxCount = null;
var recyclerProxy = function recyclerProxy(src, index) {
return {
onDatasetChanged: function onDatasetChanged() {
list.length = 0;
for (var i = 0; i < srcs.length; i++) {
list.push.apply(list, _toConsumableArray(srcs[i].list));
}
_this6.recycler.onDatasetChanged();
},
onUpdate: function onUpdate(position, count) {
var base = 0;
for (var i = 0; i < index; i++) {
base += srcs[i].itemCount();
}
list.splice.apply(list, [base + position, count].concat(_toConsumableArray(src.list.slice(position, position + count))));
_this6.recycler.onUpdate(base + position, count);
_this6.recycler.$emit('changed', index, src, base);
},
onInsert: function onInsert(position, count) {
var base = 0;
for (var i = 0; i < index; i++) {
base += srcs[i].itemCount();
} //console.log('onInsert', {position, count, base, index})
list.splice.apply(list, [base + position, 0].concat(_toConsumableArray(src.list.slice(position, position + count))));
_this6.recycler.onInsert(base + position, count);
_this6.recycler.$emit('changed', index, src, base);
},
onRemove: function onRemove(position, count) {
var base = 0;
for (var i = 0; i < index; i++) {
base += srcs[i].itemCount();
} //console.log('onRemove', {position, count, base})
list.splice(base + position, count);
_this6.recycler.onRemove(base + position, count);
_this6.recycler.$emit('changed', index, src, base);
},
update: function update() {
_this6.recycler.update();
},
startPosition: function startPosition() {
var base = 0;
for (var i = 0; i < index; i++) {
base += srcs[i].itemCount();
}
return _this6.recycler.startPosition() - base;
},
endPosition: function endPosition() {
var base = 0;
for (var i = 0; i < index; i++) {
base += srcs[i].itemCount();
}
return _this6.recycler.endPosition() - base;
},
$on: _noop["default"],
$off: _noop["default"],
$emit: function $emit() {
var _this6$recycler;
return (_this6$recycler = _this6.recycler).$emit.apply(_this6$recycler, arguments);
},
$notify: function $notify() {
var _this6$recycler2;
return (_this6$recycler2 = _this6.recycler).$notify.apply(_this6$recycler2, arguments);
},
get $router() {
return self.recycler.$router;
}
};
};
this.setMaxCount = function () {
var count = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
var prevCount = maxCount;
maxCount = count;
if (!_this6.recycler) return;
if (count === null) {
if (prevCount !== null && _this6.list.length > prevCount) _this6.recycler.onInsert(prevCount, _this6.list.length - prevCount);
} else if (count < _this6.list.length) {
_this6.recycler.onRemove(count, _this6.list.length - count);
}
};
this.getMaxCount = function () {
return maxCount;
};
this.itemCount = function () {
return maxCount !== null ? Math.min(maxCount, list.length) : list.length;
};
this.getBase = function (index) {
if (index >= srcs.length) index = srcs.length - 1;
var base = 0;
for (var i = 0; i < index; i++) {
//console.log({i, count: srcs[i].itemCount()})
base += srcs[i].itemCount();
}
return base;
};
this._onAttach = function () {
attached = true;
list.length = 0;
for (var i = 0; i < srcs.length; i++) {
list.push.apply(list, _toConsumableArray(srcs[i].list));
srcs[i].attach(recyclerProxy(srcs[i], i));
}
};
this._onDetach = function () {
attached = false;
for (var i = 0; i < srcs.length; i++) {
srcs[i].detach();
}
};
this.recyclerLaidout = function (position, hs) {
var base = 0;
for (var i = 0; i < srcs.length; i++) {
var src = srcs[i];
if (src.recyclerLaidout) {
if (position + hs.length - 1 >= base && position < base + src.itemCount()) src.recyclerLaidout( //position < base ? 0 : position - base,
Math.max(0, position - base), hs.slice( //position < base ? base - position : 0,
Math.max(0, base - position), //position + hs.length, base + src.itemCount() < position + hs.length ? hs.length - base + src.itemCount() - position : hs.length,
hs.length - Math.max(0, base - src.itemCount() + position)), base);
}
base += src.itemCount();
}
};
}
ProxySource.prototype = Object.create(AbstractSource.prototype);
ProxySource.prototype.constructor = ProxySource;
ProxySource.prototype.onAttach = function () {
this._onAttach();
};
ProxySource.prototype.onDetach = function () {
this._onDetach();
};
ProxySource.prototype.onRecyclerChanged = subscribeRecyclerLaidout;