UNPKG

vscroll

Version:
536 lines 20.8 kB
import { __assign, __read } from "tslib"; import { Reactive } from './reactive'; import { AdapterPropName, AdapterPropType, EMPTY_ITEM, getDefaultAdapterProps, methodPausedResult, methodPreResult, reactiveConfigStorage } from './adapter/props'; import { wantedUtils } from './adapter/wanted'; import { Direction } from '../inputs/index'; import { AdapterProcess, ProcessStatus } from '../processes/index'; var ADAPTER_PROPS_STUB = getDefaultAdapterProps(); var ALLOWED_METHODS_WHEN_PAUSED = ADAPTER_PROPS_STUB.filter(function (v) { return !!v.allowedWhenPaused; }).map(function (v) { return v.name; }); var _has = function (obj, prop) { return !!obj && typeof obj === 'object' && Object.prototype.hasOwnProperty.call(obj, prop); }; var convertAppendArgs = function (prepend, options, eof) { var result = options; if (!_has(options, 'items')) { var items = !Array.isArray(options) ? [options] : options; result = prepend ? { items: items, bof: eof } : { items: items, eof: eof }; } return result; }; var convertRemoveArgs = function (options) { if (!(_has(options, 'predicate') || _has(options, 'indexes'))) { var predicate = options; options = { predicate: predicate }; } return options; }; var Adapter = /** @class */ (function () { function Adapter(context, getWorkflow, logger) { var _this = this; this.source = {}; // for Reactive props this.box = {}; // for Scalars over Reactive props this.demand = {}; // for Scalars on demand // eslint-disable-next-line @typescript-eslint/no-unused-vars this.setFirstOrLastVisible = function (_) { }; this.getWorkflow = getWorkflow; this.logger = logger; this.relax$ = null; this.relaxRun = null; this.reloadCounter = 0; var contextId = (context === null || context === void 0 ? void 0 : context.id) || -1; // public context (if exists) should provide access to Reactive props config by id var reactivePropsStore = context && reactiveConfigStorage.get(context.id) || {}; // the Adapter initialization should not trigger "wanted" props setting; // after the initialization is completed, "wanted" functionality must be unblocked wantedUtils.setBlock(true, contextId); // make array of the original values from public context if present var adapterProps = context ? ADAPTER_PROPS_STUB.map(function (prop) { var value = context[prop.name]; // if context is augmented, we need to replace external reactive props with inner ones if (context.augmented) { var reactiveProp = reactivePropsStore[prop.name]; if (reactiveProp) { value = reactiveProp.default; // boolean doesn't matter here } } return (__assign(__assign({}, prop), { value: value })); }) : getDefaultAdapterProps(); // restore default reactive props if they were configured Object.entries(reactivePropsStore).forEach(function (_a) { var _b = __read(_a, 2), key = _b[0], value = _b[1]; var prop = adapterProps.find(function (_a) { var name = _a.name; return name === key; }); if (prop && value) { prop.value = value.default; } }); // Scalar permanent props adapterProps .filter(function (_a) { var type = _a.type, permanent = _a.permanent; return type === AdapterPropType.Scalar && permanent; }) .forEach(function (_a) { var name = _a.name, value = _a.value; return Object.defineProperty(_this, name, { configurable: true, get: function () { return value; } }); }); // Reactive props: store original values in "source" container, to avoid extra .get() calls on scalar twins set adapterProps .filter(function (prop) { return prop.type === AdapterPropType.Reactive; }) .forEach(function (_a) { var name = _a.name, value = _a.value; _this.source[name] = value; Object.defineProperty(_this, name, { configurable: true, get: function () { return _this.source[name]; } }); }); // for "wanted" props that can be explicitly requested for the first time after the Adapter initialization, // an implicit calculation of the initial value is required; // so this method should be called when accessing the "wanted" props through one of the following getters var processWanted = function (prop) { if (wantedUtils.setBox(prop, contextId)) { if ([AdapterPropName.firstVisible, AdapterPropName.firstVisible$].some(function (n) { return n === prop.name; })) { _this.setFirstOrLastVisible({ first: true }); } else if ([AdapterPropName.lastVisible, AdapterPropName.lastVisible$].some(function (n) { return n === prop.name; })) { _this.setFirstOrLastVisible({ last: true }); } } }; // Scalar props that have Reactive twins // 1) reactive props (from "source") should be triggered on set // 2) scalars should use "box" container on get // 3) "wanted" scalars should also run wanted-related logic on get adapterProps .filter(function (prop) { return prop.type === AdapterPropType.Scalar && !!prop.reactive; }) .forEach(function (prop) { var name = prop.name, value = prop.value, reactive = prop.reactive; _this.box[name] = value; Object.defineProperty(_this, name, { configurable: true, set: function (newValue) { if (newValue !== _this.box[name]) { _this.box[name] = newValue; _this.source[reactive].set(newValue); // need to emit new value through the configured reactive prop if present var reactiveProp = reactivePropsStore[reactive]; if (reactiveProp) { reactiveProp.emit(reactiveProp.source, newValue); } } }, get: function () { processWanted(prop); return _this.box[name]; } }); }); // Scalar props on-demand // these scalars should use "demand" container // setting defaults should be overridden on init() adapterProps .filter(function (prop) { return prop.type === AdapterPropType.Scalar && prop.onDemand; }) .forEach(function (_a) { var name = _a.name, value = _a.value; _this.demand[name] = value; Object.defineProperty(_this, name, { configurable: true, get: function () { return _this.demand[name]; } }); }); if (!context) { return; } // Adapter public context augmentation adapterProps .forEach(function (prop) { var name = prop.name, type = prop.type, permanent = prop.permanent; var value = _this[name]; if (type === AdapterPropType.Function) { value = value.bind(_this); } else if (type === AdapterPropType.WorkflowRunner) { value = _this.getWorkflowRunnerMethod(value, name); } else if (type === AdapterPropType.Reactive && reactivePropsStore[name]) { value = context[name]; } else if (name === AdapterPropName.augmented) { value = true; } var nonPermanentScalar = !permanent && type === AdapterPropType.Scalar; Object.defineProperty(context, name, { configurable: true, get: function () { processWanted(prop); // consider accessing "wanted" Reactive props if (nonPermanentScalar) { return _this[name]; // non-permanent Scalars should be taken in runtime } return value; // other props (Reactive/Functions/WorkflowRunners) can be defined once } }); }); this.externalContext = context; wantedUtils.setBlock(false, contextId); } Object.defineProperty(Adapter.prototype, "workflow", { get: function () { return this.getWorkflow(); }, enumerable: false, configurable: true }); Object.defineProperty(Adapter.prototype, "reloadCount", { get: function () { return this.reloadCounter; }, enumerable: false, configurable: true }); Object.defineProperty(Adapter.prototype, "reloadId", { get: function () { return this.id + '.' + this.reloadCounter; }, enumerable: false, configurable: true }); Adapter.prototype.getPromisifiedMethod = function (method, args) { var _this = this; return new Promise(function (resolve) { if (_this.relax$) { _this.relax$.once(function (value) { return resolve(value); }); } method.apply(_this, args); }); }; Adapter.prototype.getWorkflowRunnerMethod = function (method, name) { var _this = this; return function () { var _a, _b, _c, _d; var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } if (!_this.relax$) { (_b = (_a = _this.logger) === null || _a === void 0 ? void 0 : _a.log) === null || _b === void 0 ? void 0 : _b.call(_a, function () { return 'scroller is not initialized: ' + name + ' method is ignored'; }); return Promise.resolve(methodPreResult); } if (_this.paused && !ALLOWED_METHODS_WHEN_PAUSED.includes(name)) { (_d = (_c = _this.logger) === null || _c === void 0 ? void 0 : _c.log) === null || _d === void 0 ? void 0 : _d.call(_c, function () { return 'scroller is paused: ' + name + ' method is ignored'; }); return Promise.resolve(methodPausedResult); } return _this.getPromisifiedMethod(method, args); }; }; Adapter.prototype.initialize = function (_a) { var _this = this; var buffer = _a.buffer, state = _a.state, viewport = _a.viewport, logger = _a.logger, adapterRun$ = _a.adapterRun$, getWorkflow = _a.getWorkflow; // buffer Object.defineProperty(this.demand, AdapterPropName.itemsCount, { get: function () { return buffer.getVisibleItemsCount(); } }); Object.defineProperty(this.demand, AdapterPropName.bufferInfo, { get: function () { return ({ firstIndex: buffer.firstIndex, lastIndex: buffer.lastIndex, minIndex: buffer.minIndex, maxIndex: buffer.maxIndex, absMinIndex: buffer.absMinIndex, absMaxIndex: buffer.absMaxIndex, defaultSize: buffer.defaultSize, }); } }); this.bof = buffer.bof.get(); buffer.bof.on(function (bof) { return _this.bof = bof; }); this.eof = buffer.eof.get(); buffer.eof.on(function (eof) { return _this.eof = eof; }); // state Object.defineProperty(this.demand, AdapterPropName.packageInfo, { get: function () { return state.packageInfo; } }); this.loopPending = state.cycle.innerLoop.busy.get(); state.cycle.innerLoop.busy.on(function (busy) { return _this.loopPending = busy; }); this.isLoading = state.cycle.busy.get(); state.cycle.busy.on(function (busy) { return _this.isLoading = busy; }); this.paused = state.paused.get(); state.paused.on(function (paused) { return _this.paused = paused; }); //viewport this.setFirstOrLastVisible = function (_a) { var _b, _c, _d; var first = _a.first, last = _a.last, workflow = _a.workflow; if ((!first && !last) || ((_b = workflow === null || workflow === void 0 ? void 0 : workflow.call) === null || _b === void 0 ? void 0 : _b.interrupted)) { return; } var token = first ? AdapterPropName.firstVisible : AdapterPropName.lastVisible; if (!((_d = wantedUtils.getBox((_c = _this.externalContext) === null || _c === void 0 ? void 0 : _c.id)) === null || _d === void 0 ? void 0 : _d[token])) { return; } if (buffer.items.some(function (_a) { var element = _a.element; return !element; })) { logger.log('skipping first/lastVisible set because not all buffered items are rendered at this moment'); return; } var direction = first ? Direction.backward : Direction.forward; var item = viewport.getEdgeVisibleItem(buffer.items, direction).item; if (!item || item.element !== _this[token].element) { _this[token] = (item ? item.get() : EMPTY_ITEM); } }; // logger this.logger = logger; // self-pending subscription; set up only on the very first init if (adapterRun$) { if (!this.relax$) { this.relax$ = new Reactive(); } var relax$_1 = this.relax$; adapterRun$.on(function (_a) { var status = _a.status, payload = _a.payload; var unSubRelax = function () { }; if (status === ProcessStatus.start) { unSubRelax = _this.isLoading$.on(function (value) { if (!value) { unSubRelax(); relax$_1.set({ success: true, immediate: false, details: null }); } }); } else if (status === ProcessStatus.done || status === ProcessStatus.error) { unSubRelax(); relax$_1.set({ success: status !== ProcessStatus.error, immediate: true, details: status === ProcessStatus.error && payload ? String(payload.error) : null }); } }); } // workflow getter if (getWorkflow) { this.getWorkflow = getWorkflow; } // init this.init = true; }; Adapter.prototype.dispose = function () { var _this = this; if (this.relax$) { this.relax$.dispose(); } if (this.externalContext) { this.resetContext(); } Object.getOwnPropertyNames(this).forEach(function (prop) { delete _this[prop]; }); this.disposed = true; }; Adapter.prototype.resetContext = function () { var _this = this; var _a; var reactiveStore = reactiveConfigStorage.get((_a = this.externalContext) === null || _a === void 0 ? void 0 : _a.id); ADAPTER_PROPS_STUB .forEach(function (_a) { var type = _a.type, permanent = _a.permanent, name = _a.name, value = _a.value; // assign initial values to non-reactive non-permanent props if (type !== AdapterPropType.Reactive && !permanent) { Object.defineProperty(_this.externalContext, name, { configurable: true, get: function () { return value; } }); } // reset reactive props if (type === AdapterPropType.Reactive && reactiveStore) { var property = reactiveStore[name]; if (property) { property.default.reset(); property.emit(property.source, property.default.get()); } } }); }; // eslint-disable-next-line @typescript-eslint/no-explicit-any Adapter.prototype.reset = function (options) { this.reloadCounter++; this.logger.logAdapterMethod('reset', options, " of ".concat(this.reloadId)); this.workflow.call({ process: AdapterProcess.reset, status: ProcessStatus.start, payload: { options: options } }); }; // eslint-disable-next-line @typescript-eslint/no-explicit-any Adapter.prototype.reload = function (options) { this.reloadCounter++; this.logger.logAdapterMethod('reload', options, " of ".concat(this.reloadId)); this.workflow.call({ process: AdapterProcess.reload, status: ProcessStatus.start, payload: { options: options } }); }; // eslint-disable-next-line @typescript-eslint/no-explicit-any Adapter.prototype.append = function (_options, eof) { var options = convertAppendArgs(false, _options, eof); // support old signature this.logger.logAdapterMethod('append', [options.items, options.eof]); this.workflow.call({ process: AdapterProcess.append, status: ProcessStatus.start, payload: { options: options } }); }; // eslint-disable-next-line @typescript-eslint/no-explicit-any Adapter.prototype.prepend = function (_options, bof) { var options = convertAppendArgs(true, _options, bof); // support old signature this.logger.logAdapterMethod('prepend', [options.items, options.bof]); this.workflow.call({ process: AdapterProcess.prepend, status: ProcessStatus.start, payload: { options: options } }); }; // eslint-disable-next-line @typescript-eslint/no-explicit-any Adapter.prototype.check = function () { this.logger.logAdapterMethod('check'); this.workflow.call({ process: AdapterProcess.check, status: ProcessStatus.start }); }; // eslint-disable-next-line @typescript-eslint/no-explicit-any Adapter.prototype.remove = function (options) { options = convertRemoveArgs(options); // support old signature this.logger.logAdapterMethod('remove', options); this.workflow.call({ process: AdapterProcess.remove, status: ProcessStatus.start, payload: { options: options } }); }; // eslint-disable-next-line @typescript-eslint/no-explicit-any Adapter.prototype.clip = function (options) { this.logger.logAdapterMethod('clip', options); this.workflow.call({ process: AdapterProcess.clip, status: ProcessStatus.start, payload: { options: options } }); }; // eslint-disable-next-line @typescript-eslint/no-explicit-any Adapter.prototype.insert = function (options) { this.logger.logAdapterMethod('insert', options); this.workflow.call({ process: AdapterProcess.insert, status: ProcessStatus.start, payload: { options: options } }); }; // eslint-disable-next-line @typescript-eslint/no-explicit-any Adapter.prototype.replace = function (options) { this.logger.logAdapterMethod('replace', options); this.workflow.call({ process: AdapterProcess.replace, status: ProcessStatus.start, payload: { options: options } }); }; // eslint-disable-next-line @typescript-eslint/no-explicit-any Adapter.prototype.update = function (options) { this.logger.logAdapterMethod('update', options); this.workflow.call({ process: AdapterProcess.update, status: ProcessStatus.start, payload: { options: options } }); }; // eslint-disable-next-line @typescript-eslint/no-explicit-any Adapter.prototype.pause = function () { this.logger.logAdapterMethod('pause'); this.workflow.call({ process: AdapterProcess.pause, status: ProcessStatus.start }); }; // eslint-disable-next-line @typescript-eslint/no-explicit-any Adapter.prototype.resume = function () { this.logger.logAdapterMethod('resume'); this.workflow.call({ process: AdapterProcess.pause, status: ProcessStatus.start, payload: { options: { resume: true } } }); }; // eslint-disable-next-line @typescript-eslint/no-explicit-any Adapter.prototype.fix = function (options) { this.logger.logAdapterMethod('fix', options); this.workflow.call({ process: AdapterProcess.fix, status: ProcessStatus.start, payload: { options: options } }); }; Adapter.prototype.relaxUnchained = function (callback, reloadId) { var _this = this; var runCallback = function () { return typeof callback === 'function' && reloadId === _this.reloadId && callback(); }; if (!this.isLoading) { runCallback(); } return new Promise(function (resolve) { if (!_this.isLoading) { resolve(true); return; } _this.isLoading$.once(function () { runCallback(); resolve(false); }); }).then(function (immediate) { var _a, _b; if (_this.disposed) { return { immediate: immediate, success: false, details: 'Adapter was disposed' }; } var success = reloadId === _this.reloadId; (_b = (_a = _this.logger) === null || _a === void 0 ? void 0 : _a.log) === null || _b === void 0 ? void 0 : _b.call(_a, function () { return !success ? "relax promise cancelled due to ".concat(reloadId, " != ").concat(_this.reloadId) : void 0; }); return { immediate: immediate, success: success, details: !success ? 'Interrupted by reload or reset' : null }; }); }; Adapter.prototype.relax = function (callback) { var _this = this; var reloadId = this.reloadId; this.logger.logAdapterMethod('relax', callback, " of ".concat(reloadId)); if (!this.init) { return Promise.resolve(methodPreResult); } return this.relaxRun = this.relaxRun ? this.relaxRun.then(function () { return _this.relaxUnchained(callback, reloadId); }) : this.relaxUnchained(callback, reloadId).then(function (result) { _this.relaxRun = null; return result; }); }; Adapter.prototype.showLog = function () { this.logger.logAdapterMethod('showLog'); this.logger.logForce(); }; return Adapter; }()); export { Adapter }; //# sourceMappingURL=adapter.js.map