UNPKG

outsystems-ui

Version:
381 lines (341 loc) 11.5 kB
// eslint-disable-next-line @typescript-eslint/no-unused-vars namespace OSFramework.OSUI.Patterns { /** * Defines the Default props and methods for OutSystemsUI Patterns * * @export * @abstract * @class AbstractPattern * @implements {Interface.IPattern} * @template C */ export abstract class AbstractProviderPattern<P, C extends AbstractConfiguration> extends AbstractPattern<C> implements Interface.IProviderPattern<P> { // Holds the id of the asyncInvocation that will turn redraw async private _asyncInvocationId = 0; // Holds the callback for the provider config applied event private _platformEventProviderConfigsAppliedCallback: GlobalCallbacks.OSGeneric; // Holds the provider private _provider: P; // Holds the provider info private _providerInfo: ProviderInfo; // Holds the callback for the redraw event private _redrawCallback: GlobalCallbacks.Generic; // Holds the providerEvents instance, that manages the provider events protected providerEventsManagerInstance: Event.ProviderEvents.IProviderEventManager; /** * Creates an instance of AbstractProviderPattern. * * @param {string} uniqueId * @param {C} configs * @memberof OSFramework.Patterns.AbstractProviderPattern */ constructor(uniqueId: string, configs: C) { super(uniqueId, configs); this.isProviderBased = true; } // Method that will check if there is already a redraw process runing in order to cancel it private _cancelRedraw(): void { if (this._asyncInvocationId !== 0) { clearTimeout(this._asyncInvocationId); } } // Method to get an event index from an array private _getEventIndexFromArray(event: Event.ProviderEvents.IProviderEvent): number { // Get callback from array const _providerCallback = this.providerInfo.events[event.eventName].find((item) => { return item === event.callback; }); if (_providerCallback === undefined) { throw Error( ErrorCodes.AbstractProviderPattern.FailProviderEventRemoval.code + ': ' + ErrorCodes.AbstractProviderPattern.FailProviderEventRemoval.message ); } // Get the index, using the callback return this.providerInfo.events[event.eventName].findIndex((item) => { return item === _providerCallback; }); } // Method to check the provider events api type and add/ remove events // eslint-disable-next-line @typescript-eslint/naming-convention private _handleProviderEventsAPI( eventName: string, callback: GlobalCallbacks.Generic, addEvent: boolean, event?: Event.ProviderEvents.IProviderEvent ): void { const events = this.providerInfo.events; // Check if is array if (Array.isArray(events[eventName])) { if (addEvent) { events[eventName].push(callback); } else { events[eventName].splice(this._getEventIndexFromArray(event), 1); } } // Check if addEventListener is valid else if (typeof events.addEventListener === Constants.JavaScriptTypes.Function) { if (addEvent) { events.addEventListener(eventName, callback); } else { events.removeEventListener(eventName, callback); } } // Check if instance.on is valid else if (typeof events.on === Constants.JavaScriptTypes.Function) { if (addEvent) { events.on(eventName, callback); } else { events.off(eventName, callback); } } else { const errorMessage = addEvent ? ErrorCodes.AbstractProviderPattern.FailProviderEventSet.message : ErrorCodes.AbstractProviderPattern.FailProviderEventRemoval.message; throw new Error(`${eventName}: ${errorMessage}`); } } // Method that will execute the redraw process private _handleRedraw(): void { // Check if provider has been set! if (this._provider !== undefined) { // Destroy provider instance // eslint-disable-next-line @typescript-eslint/ban-ts-comment //@ts-expect-error this._provider.destroy(); // Trigger a new instance creation with updated configs this.prepareConfigs(); } } /** * Method that will be responsible to redraw pattern when needed * * @protected * @memberof OSFramework.Patterns.AbstractProviderPattern */ protected redraw(): void { /* If a redraw has been trigger before the previous occured, cancel the previous one and restart a new redraw process, this way multiple redraws will be prevented. */ this._cancelRedraw(); this._asyncInvocationId = OSUI.Helper.AsyncInvocation(() => { this._handleRedraw(); }); } /** * Unsets the callbacks. * * @protected * @memberof OSFramework.Patterns.AbstractProviderPattern */ protected unsetCallbacks(): void { this._platformEventProviderConfigsAppliedCallback = undefined; } /** * Method to build the pattern * * @memberof OSFramework.Patterns.AbstractProviderPattern */ public build(): void { this.providerInfo = { name: undefined, version: undefined, events: undefined, }; // Force provider redraw/update when rtl is changed in runtime this._redrawCallback = this.redraw.bind(this); OSFramework.OSUI.Event.DOMEvents.Observers.GlobalObserverManager.Instance.addHandler( Event.DOMEvents.Observers.ObserverEvent.RTL, this._redrawCallback ); super.build(); } /** * Method to check for pending events to be added * * @memberof OSFramework.Patterns.AbstractProviderPattern */ public checkAddedProviderEvents(): void { if (this.providerEventsManagerInstance?.hasEvents) { // check if there're events pending this.providerEventsManagerInstance.events.forEach((value) => { this.setProviderEvent(value.eventName, value.callback, value.eventUniqueId, false); // add provider event }); } } /** * Method to check for saved events to be added after a destroy/init cycle * * @memberof OSFramework.Patterns.AbstractProviderPattern */ public checkPendingProviderEvents(): void { if (this.providerEventsManagerInstance?.hasPendingEvents) { // check if there're events saved this.providerEventsManagerInstance.pendingEvents.forEach((value, key) => { this.setProviderEvent(value.eventName, value.callback, value.eventUniqueId); // add provider event this.providerEventsManagerInstance.removePendingEvent(key); }); } } /** * Method to destroy created instance * * @memberof OSFramework.Patterns.AbstractProviderPattern */ public dispose(): void { OSFramework.OSUI.Event.DOMEvents.Observers.GlobalObserverManager.Instance.removeHandler( Event.DOMEvents.Observers.ObserverEvent.RTL, this._redrawCallback ); this._redrawCallback = undefined; super.dispose(); } /** * Register the default events for provider based patterns. * * @abstract * @param {string} eventName * @param {GlobalCallbacks.OSGeneric} callback * @memberof AbstractProviderPattern */ public registerCallback(eventName: string, callback: GlobalCallbacks.OSGeneric): void { switch (eventName) { case GlobalEnum.ProviderEvents.OnProviderConfigsApplied: if (this._platformEventProviderConfigsAppliedCallback === undefined) { this._platformEventProviderConfigsAppliedCallback = callback; } break; default: super.registerCallback(eventName, callback); } } /** * Method used to set all the provider configs. In the AbstractProviderPattern, it * will simply trigger the callback to warn that the configs have been applied to the provider. * @param {ProviderConfigs} providerConfigs * @memberof AbstractProviderPattern */ // eslint-disable-next-line @typescript-eslint/no-unused-vars public setProviderConfigs(providerConfigs: unknown): void { this.triggerPlatformEventCallback(this._platformEventProviderConfigsAppliedCallback); } /** * Method to add a provider event using extensibility * * @param {string} eventName * @param {GlobalCallbacks.Generic} callback * @param {string} uniqueId * @param {boolean} [saveEvent=true] * @return {*} {void} * @memberof OSFramework.Patterns.AbstractProviderPattern */ public setProviderEvent( eventName: string, callback: GlobalCallbacks.Generic, uniqueId: string, saveEvent = true ): void { // If there's no instance yet, create one if (this.providerEventsManagerInstance === undefined) { this.providerEventsManagerInstance = new Event.ProviderEvents.ProviderEventsManager(); } // If the providerEventsAPI is not available, add this one to the pending events if (this.providerInfo.events === undefined) { this.providerEventsManagerInstance.addPendingEvent(eventName, callback, uniqueId); return; } // Add event this._handleProviderEventsAPI(eventName, callback, true); // Save added event if (saveEvent) { this.providerEventsManagerInstance.saveEvent(eventName, callback, uniqueId); } } /** * Method to remove a provider event using extensibility * * @param {string} eventId * @return {*} {void} * @memberof OSFramework.Patterns.AbstractProviderPattern */ public unsetProviderEvent(eventId: string): void { // Get event from saved events map const _event = this.providerEventsManagerInstance?.events.get(eventId); if (_event === undefined) { throw Error( ErrorCodes.AbstractProviderPattern.FailProviderEventRemoval.code + ': ' + ErrorCodes.AbstractProviderPattern.FailProviderEventRemoval.message ); } // Call the method that will handle the removal of this event this._handleProviderEventsAPI(_event.eventName, _event.callback, false, _event); // Removed from the saved events map if (this.providerEventsManagerInstance) { this.providerEventsManagerInstance.removeSavedEvent(eventId); } } /** * Method to update the provider events API instance and save/pending events * * @param {ProviderInfo} providerInfo * @memberof OSFramework.Patterns.AbstractProviderPattern */ public updateProviderEvents(providerInfo: ProviderInfo): void { // Update provider instance reference this.providerInfo.events = providerInfo.events; if (this.isBuilt) { // Check if there're any pending events to be added by the SetProviderEvent API Helper.AsyncInvocation(this.checkPendingProviderEvents.bind(this)); // and/or add them again after a destroy has ocurred Helper.AsyncInvocation(this.checkAddedProviderEvents.bind(this)); } else { // These won't change, so they can be updated only once this.providerInfo.name = providerInfo.name; this.providerInfo.version = providerInfo.version; } } /** * ProviderInfo getter * * @readonly * @type {ProviderInfo} * @memberof OSFramework.Patterns.AbstractProviderPattern */ public get providerInfo(): ProviderInfo { return this._providerInfo; } /** * ProviderInfo setter * * @memberof OSFramework.Patterns.AbstractProviderPattern */ public set providerInfo(providerInfo: ProviderInfo) { this._providerInfo = providerInfo; } /** * Provider setter * * @memberof OSFramework.Patterns.AbstractProviderPattern */ public set provider(p: P) { this._provider = p; } /** * Provider getter * * @readonly * @type {P} * @memberof OSFramework.Patterns.AbstractProviderPattern */ public get provider(): P { return this._provider; } // Common methods all providers must implement protected abstract prepareConfigs(): void; } }