import * as React from 'react'; import {BaseFrameworkAdaptor} from '../../adaptors/framework/BaseFrameworkAdaptor'; import {logger} from '../../adaptors/logger/LoggerAdaptor'; import {Provider} from './Provider'; import {SimpleXdmDefinitionBuilder} from '../../definitions/SimpleXdmDefinitionBuilder'; export module ModuleDefinitions { export const MIN_REGISTRATION_NAME_LENGTH : number = 1; export const MAX_REGISTRATION_NAME_LENGTH : number = 50; /** * All modules (classes that extend BaseModule) must be instantiated with props * that extend this interface. This facilitates the BaseModule's provision of * common module behaviour. */ export interface Props { adaptor: BaseFrameworkAdaptor; } /** * All modules (classes that extend BaseModule) must have a state that extends this * interface. This facilitates the BaseModule's provision of common module behaviour. */ export interface State { enabled: boolean; registered: boolean; } } export interface Module { props?: Props; state?: State; /** * Enable or disable a module. * @param enabled indication of whether the module should be enabled or disabled. */ setEnabled(enabled: boolean): void; /** * Determines if a module is enabled or disabled. */ isEnabled(): boolean; /** * Get the name used to register this module with the underlying framework. */ getModuleRegistrationName(): string; /** * Implementations of this method are responsible for returning an abject that can * be used to build a module that can be registered with Simple XDM. * @returns {SimpleXdmDefinitionBuilder} */ getSimpleXdmDefinitionBuilder() : SimpleXdmDefinitionBuilder; /** * Get the provider for this module. */ getProvider(): Provider; } /** * This class provides common module behaviour and characteristics. The term 'Module' refers to * a set of related functionality and provides the interface between a product that requires the * module functionality and the framework that implements it. */ export abstract class BaseModule extends React.Component implements Module { constructor(props: Props) { super(props); } componentDidMount(): void { const props = this.props; const registrationName = this.getModuleRegistrationName(); logger.debug('Mounting module', registrationName, '...'); this.validateRegistrationName(registrationName); props.adaptor.registerModule(this, props); const moduleState : State = this.state; moduleState.enabled = true; moduleState.registered = true; this.setState(moduleState); } setEnabled(enabled: boolean): void { const moduleState : State = this.state; moduleState.enabled = enabled; this.setState(moduleState); } isEnabled(): boolean { return this.state.enabled; } componentWillUnmount(): void { // Do nothing - we don't unregister modules. } shouldComponentUpdate(): boolean { // This module hierarchy never renders anything. return false; } /** * Get the name used to register this module with the underlying framework. */ abstract getModuleRegistrationName(): string; /** * Implementations of this method are responsible for returning an abject that can * be used to build a module that can be registered with Simple XDM. * @returns {SimpleXdmDefinitionBuilder} */ abstract getSimpleXdmDefinitionBuilder() : SimpleXdmDefinitionBuilder; /** * Get the provider for this module. */ abstract getProvider(): Provider; validateRegistrationName(registrationName: string): void { if (!registrationName || registrationName.length < ModuleDefinitions.MIN_REGISTRATION_NAME_LENGTH) { throw new Error('The registration name is too short (< ' + ModuleDefinitions.MIN_REGISTRATION_NAME_LENGTH + ' characters).'); } if (registrationName.length > ModuleDefinitions.MAX_REGISTRATION_NAME_LENGTH) { throw new Error('The registration name is too long (> ' + ModuleDefinitions.MAX_REGISTRATION_NAME_LENGTH + ' characters).'); } if (!registrationName.match(/^[a-z]+$/i)) { throw new Error('The registration name must only contain alphabetic characters.'); } } render(): React.ReactElement | null { return null; } }