Source: module.js

import Observable from './observ';

export default class Module extends Observable {
  /**
   * Класс является родителем для всех модулей кроме главного модуля (Root Module). </br>
   * Наследуется от класса Observable для реализации паттерна [Наблюдатель (Observer)]{@link https://refactoring.guru/ru/design-patterns/observer}. </br>
   * Объект модуля реализует паттерн [Одиночка (Singleton)]{@link https://refactoring.guru/ru/design-patterns/singleton}. </br>
   * Каждый модуль создается только 1 раз, последующий вызов new Module() - вернет текущий экзепляр данного класса.
   * @example <caption>Пример создания модуля</caption>
   * import Onedeck from 'onedeck';
   *
   * export default class ModuleName extends Onedeck.Module { ... }
   *
   * @example <caption>Пример получения экземпляра модуля</caption>
   * import Module from 'ModuleName/module.js'
   * const module = new Module()
   * // Событие уровня модуля
   * module.$$emit('eventName', data)
   * // Событие уровня приложения
   * module.$$gemit('eventName', data)
   *
   * @Module Module
   */
  constructor() {
    super();
    /**
     * Объект содержит в себе инстансы всех моулей
     * Модуль создается только 1 раз
     * @static
     */
    Module.instances = Module.instances || {};

    if (Module.instances[this.constructor.name]) {
      return Module.instances[this.constructor.name];
    }

    Module.instances[this.constructor.name] = this;
  }

  /**
   * Абстрактный метод. Обработчик событий. </br>
   * В этом методе должны быть описаны все события текущего моудля. </br>
   *
   * @example
   * eventHandler () {
   *   // Cоздаем событие уровня модуля в котором эмитим событие уровня приложения
   *   this.$on('event1', (data) => this.$$gemit(data));
   *   // Cоздаем событие уровня модуля в котором выполняем метод doSomething
   *   this.$on('event2', (data) => this.doSomething(data));
   * }
   * @abstract
   */
  eventHandler () { }

  /**
   * Абстрактный метод. Инициализация приложения модуля. </br>
   * В этом методе должна быть описана инициализация приложения модуля. </br>
   * Метод автоматически вызывается для каждого модуля старницы при переходе на страницу модуля. </br>
   * Для Global модуля, и для Embed модулей которые встороенные в Global - вызыввается только 1 раз, при инициализации приложения. </br>
   * Вызывается в следующем порядке: </br>
   * - init Layout модуля если на старнице меняется Layout </br>
   * - init Page модуля </br>
   * - init Embed модулей в произвольном порядке </br>
   *
   * @example
   * init (path, state) {
   *   console.log('init', this.constructor.name, path, state);
   *   // Создаем приложение модуля
   *   this.reactApp = ReactDOM.render(<App />, document.getElementById('MainContent'));
   *   // Вызываем обработчик событий
   *   this.eventHandler();
   * }
   *
   * @param {Array} path - массив с элементами url адреса.
   * @param {Object} state - данные переданные с url.
   * @abstract
   */
  init () { }

  /**
   * Абстрактный метод. Деструктор. </br>
   * В этом методе должна быть описана деструктуризация модуля. </br>
   * Метод автоматически вызывается для каждого модуля старницы при переходе на другую старницу приложнеия. </br>
   * Для Global модуля - дестуркторизация не производится. </br>
   *
   * @example
   * destroy () {
   *   // Отписываемся от всех событий уровня модуля
   *   this.$$offAll()
   *
   *   ReactDOM.unmountComponentAtNode(document.getElementById('MainContent'));
   * }
   * @abstract
   */
  destroy () { }

  /**
   * Абстрактный метод. Диспетчер. </br>
   * В этом методе должна быть описана логика модуля связанная с маршрутизацией. </br>
   * Метод автоматически вызывается для каждого модуля при изменении url адреса. </br>
   * Вызывается в следующем порядке: </br>
   * - dispatcher Root модуля </br>
   * - dispatcher всех Global модулей в произвольном порядке</br>
   * - dispatcher Layout модуля </br>
   * - dispatcher Page модуля </br>
   * - dispatcher Embed модулей в произвольном порядке </br>
   *
   * @example
   * dispatcher (path, state) {
   *   console.log('dispatcher', this.constructor.name, path, state);
   *   // Если путь my.site.com/moduleName/item/3
   *   if (path[1] === 'item') this.showItem(state, path[2]);
   * }
   *
   * @param {string} path - массив с элементами url адреса.
   * @param {Object} state - данные переданные с url.
   * @abstract
   */
  dispatcher () { }

  /**
  * Абстрактный метод. Монитирование модуля. </br>
  * Метод автоматически вызывается для каждого модуля при изменении url адреса. </br>
  * В методе доступны объекты currentModule и currentLayout. </br>
  * Вызывается в следующем порядке: </br>
  * - mounted Root модуля </br>
  * - mounted всех Global модулей в произвольном порядке </br>
  * - mounted Layout модуля </br>
  * - mounted Page модуля </br>
  * - mounted Embed модулей в произвольном порядке </br>
  * @example
  * mounted (module, layout) {
  *   console.log('mounted', this.constructor.name, module, layout);
  * }
  *
  * @param {Object} currentModule - текущий Page модуль.
  * @param {Object} currentLayout - текущий Layout модуль.
  * @abstract
  */
  mounted () { }
}