@v4fire/client
Version:
V4Fire client core library
267 lines (221 loc) • 8.2 kB
text/typescript
/*!
* V4Fire Client Core
* https://github.com/V4Fire/Client
*
* Released under the MIT license
* https://github.com/V4Fire/Client/blob/master/LICENSE
*/
import symbolGenerator from 'core/symbol';
import iVirtualScrollProps from 'base/b-virtual-scroll-new/props';
import type bVirtualScrollNew from 'base/b-virtual-scroll-new/b-virtual-scroll-new';
import type { MountedChild } from 'base/b-virtual-scroll-new/interface';
import { bVirtualScrollAsyncGroup, componentEvents, componentLocalEvents } from 'base/b-virtual-scroll-new/const';
import { isAsyncReplaceError } from 'base/b-virtual-scroll-new/modules/helpers';
import iData, { component } from 'super/i-data/i-data';
const $$ = symbolGenerator();
/**
* A class that provides an API to handle events emitted by the {@link bVirtualScroll} component.
* This class is designed to work in conjunction with {@link bVirtualScroll}.
*/
export abstract class iVirtualScrollHandlers extends iVirtualScrollProps {
/**
* Handler: component reset event.
* Resets the component state to its initial state.
*/
protected onReset(this: bVirtualScrollNew): void {
this.componentInternalState.reset();
this.observer.reset();
this.async.clearAll({group: new RegExp(bVirtualScrollAsyncGroup)});
this.componentEmitter.emit(componentEvents.resetState);
}
/**
* Handler: render start event.
* Triggered when the component rendering starts.
*/
protected onRenderStart(this: bVirtualScrollNew): void {
this.componentInternalState.updateIsLastRender();
this.componentEmitter.emit(componentEvents.renderStart);
}
/**
* Handler: render engine start event.
* Triggered when the component rendering using the rendering engine starts.
*/
protected onRenderEngineStart(this: bVirtualScrollNew): void {
this.componentEmitter.emit(componentEvents.renderEngineStart);
}
/**
* Handler: render engine done event.
* Triggered when the component rendering using the rendering engine is completed.
*/
protected onRenderEngineDone(this: bVirtualScrollNew): void {
this.componentEmitter.emit(componentEvents.renderEngineDone);
}
/**
* Handler: DOM insert start event.
* Triggered when the insertion of rendered components into the DOM tree starts.
*
* @param childList
*/
protected onDomInsertStart(this: bVirtualScrollNew, childList: MountedChild[]): void {
this.componentInternalState.updateDataOffset();
this.componentInternalState.updateMounted(childList);
this.componentInternalState.setIsInitialRender(false);
this.componentInternalState.incrementRenderPage();
this.componentEmitter.emit(componentEvents.domInsertStart);
}
/**
* Handler: DOM insert done event.
* Triggered when the insertion of rendered components into the DOM tree is completed.
*/
protected onDomInsertDone(this: bVirtualScrollNew): void {
this.componentEmitter.emit(componentEvents.domInsertDone);
}
/**
* Handler: render done event.
* Triggered when rendering is completed.
*/
protected onRenderDone(this: bVirtualScrollNew): void {
this.componentEmitter.emit(componentEvents.renderDone);
this.localEmitter.emit(componentLocalEvents.renderCycleDone);
}
/**
* Handler: lifecycle done event.
* Triggered when the internal lifecycle of the component is completed.
*/
protected onLifecycleDone(this: bVirtualScrollNew): void {
const
state = this.getVirtualScrollState(),
isDomInsertInProgress = this.componentInternalState.getIsDomInsertInProgress();
if (state.isLifecycleDone) {
return;
}
const handler = () => {
this.slotsStateController.doneState();
this.componentInternalState.setIsLifecycleDone(true);
this.componentEmitter.emit(componentEvents.lifecycleDone);
};
if (isDomInsertInProgress) {
this.localEmitter.once(componentLocalEvents.renderCycleDone, handler, {
group: bVirtualScrollAsyncGroup,
label: $$.waitUntilRenderDone
});
return;
}
return handler();
}
/**
* Handler: convert data to database event.
* Triggered when the loaded data is converted.
*
* @param data - the converted data.
*/
protected onConvertDataToDB(this: bVirtualScrollNew, data: unknown): void {
this.componentInternalState.setRawLastLoaded(data);
this.componentEmitter.emit(componentEvents.convertDataToDB, data);
}
/**
* Handler: data load start event.
* Triggered when data loading starts.
*
* @param isInitialLoading - indicates whether it is an initial component loading.
*/
protected onDataLoadStart(this: bVirtualScrollNew, isInitialLoading: boolean): void {
this.componentInternalState.setIsLoadingInProgress(true);
this.componentInternalState.setIsLastErrored(false);
this.slotsStateController.loadingProgressState(isInitialLoading);
this.componentEmitter.emit(componentEvents.dataLoadStart, isInitialLoading);
}
/**
* Handler: data load success event.
* Triggered when data loading is successfully completed.
*
* @param isInitialLoading - indicates whether it is an initial component loading.
* @param data - the loaded data.
* @throws {@link ReferenceError} if the loaded data does not have a "data" field.
*/
protected onDataLoadSuccess(this: bVirtualScrollNew, isInitialLoading: boolean, data: unknown): void {
this.componentInternalState.setIsLoadingInProgress(false);
const
dataToProvide = Object.isPlainObject(data) ? data.data : data;
if (!Array.isArray(dataToProvide)) {
throw new ReferenceError('Missing data to perform render');
}
this.componentInternalState.updateData(dataToProvide, isInitialLoading);
this.componentInternalState.incrementLoadPage();
const
isRequestsStopped = this.shouldStopRequestingDataWrapper();
this.componentEmitter.emit(componentEvents.dataLoadSuccess, dataToProvide, isInitialLoading);
this.slotsStateController.loadingSuccessState();
if (
isInitialLoading &&
isRequestsStopped &&
Object.size(dataToProvide) === 0
) {
this.onDataEmpty();
this.onLifecycleDone();
} else {
this.loadDataOrPerformRender();
}
}
/**
* Handler: data load error event.
* Triggered when data loading fails.
*
* @param isInitialLoading - indicates whether it is an initial component loading.
*/
protected onDataLoadError(this: bVirtualScrollNew, isInitialLoading: boolean): void {
this.componentInternalState.setIsLoadingInProgress(false);
this.componentInternalState.setIsLastErrored(true);
this.slotsStateController.loadingFailedState();
this.componentEmitter.emit(componentEvents.dataLoadError, isInitialLoading);
}
protected override onRequestError(this: bVirtualScrollNew, ...args: Parameters<iData['onRequestError']>): ReturnType<iData['onRequestError']> {
const
err = args[0];
if (isAsyncReplaceError(err)) {
return;
}
const
state = this.getVirtualScrollState();
this.onDataLoadError(state.isInitialLoading);
return super.onRequestError(err, this.initLoad.bind(this));
}
/**
* Handler: data empty event.
* Triggered when the loaded data is empty.
*/
protected onDataEmpty(this: bVirtualScrollNew): void {
this.slotsStateController.emptyState();
this.componentEmitter.emit(componentEvents.dataLoadEmpty);
}
/**
* Handler: component enters the viewport
* @param component - the component that enters the viewport.
*/
protected onElementEnters(this: bVirtualScrollNew, component: MountedChild): void {
this.componentInternalState.setMaxViewedIndex(component);
this.loadDataOrPerformRender();
this.componentEmitter.emit(componentEvents.elementEnter, component);
}
/**
* Handler: The tombstones slot entered the viewport
*/
protected onTombstonesEnter(this: bVirtualScrollNew): void {
this.componentInternalState.setIsTombstonesInView(true);
this.loadDataOrPerformRender();
}
/**
* Handler: The tombstones slot leaves the viewport
*/
protected onTombstonesLeave(this: bVirtualScrollNew): void {
this.componentInternalState.setIsTombstonesInView(false);
}
/**
* Handler: items to render was updated
* @param items
*/
protected onItemsInit(this: bVirtualScrollNew, items: Exclude<bVirtualScrollNew['items'], undefined>): void {
this.onDataLoadSuccess(true, items);
}
}