UNPKG

vscroll

Version:
186 lines 6.02 kB
import { Scroller } from './scroller'; import { runStateMachine } from './workflow-transducer'; import { Reactive } from './classes/reactive'; import { AdapterProcess, CommonProcess, ProcessStatus as Status } from './processes/index'; import { WORKFLOW, validate } from './inputs/index'; export class Workflow { constructor(params) { const { element, datasource, consumer, run, Routines } = params; const validationResult = validate(params, WORKFLOW); if (!validationResult.isValid) { throw new Error(`Invalid Workflow params: ${validationResult.errors.join(', ')}.`); } this.isInitialized = false; this.disposed = false; this.initTimer = null; this.adapterRun$ = new Reactive(); this.cyclesDone = 0; this.cyclesDone$ = new Reactive(0); this.interruptionCount = 0; this.errors = []; this.offScroll = () => null; this.propagateChanges = run; this.stateMachineMethods = { run: this.runProcess(), interrupt: this.interrupt.bind(this), done: this.done.bind(this), onError: this.onError.bind(this) }; this.scroller = new Scroller({ element, datasource, consumer, workflow: this.getUpdater(), Routines }); if (this.scroller.settings.initializeDelay) { this.initTimer = setTimeout(() => { this.initTimer = null; this.init(); }, this.scroller.settings.initializeDelay); } else { this.init(); } } init() { this.scroller.init(this.adapterRun$); // set up scroll event listener const { routines } = this.scroller; const onScrollHandler = event => this.callWorkflow({ process: CommonProcess.scroll, status: Status.start, payload: { event } }); this.offScroll = routines.onScroll(onScrollHandler); // run the Workflow this.isInitialized = true; this.callWorkflow({ process: CommonProcess.init, status: Status.start }); } changeItems(items) { this.propagateChanges(items); } callWorkflow(processSubject) { if (!this.isInitialized) { return; } const { process, status } = processSubject; // if the scroller is paused, any process other than "pause" and "reset" should be blocked if (this.scroller.state.paused.get()) { if (![AdapterProcess.pause, AdapterProcess.reset].includes(process)) { this.scroller.logger.log('scroller is paused: ' + process + ' process is ignored'); return; } } if (process && process.startsWith('adapter') && status !== Status.next) { this.adapterRun$.set(processSubject); } this.process(processSubject); } getUpdater() { return { call: this.callWorkflow.bind(this), onDataChanged: this.changeItems.bind(this) }; } process(data) { const { status, process, payload } = data; if (this.scroller.settings.logProcessRun) { this.scroller.logger.log(() => { const _fire = this.scroller.settings.logColor ? ['%cfire%c', 'color: #cc7777;', 'color: #000000;'] : ['fire']; return [..._fire, process, `"${status}"`, ...(payload !== void 0 ? [payload] : [])]; }); } this.scroller.logger.logProcess(data); if (process === CommonProcess.end) { this.scroller.finalize(); } runStateMachine({ input: data, methods: this.stateMachineMethods }); } runProcess() { return ({ run, process, name }) => (...args) => { if (this.scroller.settings.logProcessRun) { this.scroller.logger.log(() => { const _run = this.scroller.settings.logColor ? ['%crun%c', 'color: #333399;', 'color: #000000;'] : ['run']; return [..._run, process || name, ...args]; }); } run(this.scroller, ...args); }; } onError(process, payload) { const message = (payload && String(payload.error)) || ''; const { time, cycle } = this.scroller.state; this.errors.push({ process, message, time, loop: cycle.loopIdNext }); this.scroller.logger.logError(message); } interrupt({ process, finalize, datasource }) { if (finalize) { const { workflow, logger } = this.scroller; // we are going to create a new reference for the scroller.workflow object // calling the old version of the scroller.workflow by any outstanding async processes will be skipped workflow.call = (_) => logger.log('[skip wf call]'); workflow.call.interrupted = true; this.scroller.workflow = this.getUpdater(); this.interruptionCount++; logger.log(() => `workflow had been interrupted by the ${process} process (${this.interruptionCount})`); } if (datasource) { // Scroller re-initialization case const reInit = () => { this.scroller.logger.log('new Scroller instantiation'); const scroller = new Scroller({ datasource, scroller: this.scroller }); this.scroller.dispose(); this.scroller = scroller; this.scroller.init(); }; if (this.scroller.state.cycle.busy.get()) { // todo: think about immediate re-initialization even is there are pending processes this.scroller.adapter.relax(reInit.bind(this)); } else { reInit(); } } } done() { const { state, logger } = this.scroller; this.cyclesDone++; this.cyclesDone$.set(this.cyclesDone); logger.logCycle(false); state.endWorkflowCycle(this.cyclesDone + 1); this.finalize(); } dispose() { this.scroller.logger.log(() => 'disposing workflow'); if (this.initTimer) { clearTimeout(this.initTimer); } this.offScroll(); this.adapterRun$.dispose(); this.cyclesDone$.dispose(); this.scroller.dispose(true); Object.getOwnPropertyNames(this).forEach(prop => { delete this[prop]; }); this.isInitialized = false; this.disposed = true; } finalize() { } } //# sourceMappingURL=workflow.js.map