Home Reference Source

src/app/app.js

'use strict'

import { HistoryRouter, HashRouter } from '../app/router.js'

/**
 * Application.
 *
 * @memberOf flatout
 */
class App {
  /* Do not call */
  constructor() {}

  /**
   * Activate application
   *
   * @param  {Class<View>} rootViewClass - root view class.
   * @param  {Object} routeMap - routing map.
   * @param  {Object} [opts]          - options.
   * @param  {Object} [opts.mode]     - HISTORY or HASH
   * @param  {Object} [opts.rootPath] - history root path.
   * @param  {Object} [opts.pathHead] - hash path prefix.
   */
  activate(rootViewClass, routeMap, opts = {}) {
    /**
     * Root area.
     * @type {View}
     */
    this._rootArea = new rootViewClass();

    /**
     * Page area replaced if path changed.
     * @type {Page}
     */
    this._curPage = null;

    const onMove = ({ view, ctx }) => { this.replace(view, ctx) };
    this._router = opts.mode === 'HISTORY'
      ? new HistoryRouter(routeMap, onMove, opts.rootPath)
      : new HashRouter(routeMap, onMove, opts.pathHead);

    const loadCb = e => { this._router.depart() }
    if (document.readyState !== 'loading') loadCb()
    else document.addEventListener('DOMContentLoaded', loadCb, false)
  }

  /**
   * Go a page.
   *
   * @param  {string} path - URL path
   * @param  {Object} ctx  - context
   * @return {boolean} always false.
   */
  go(path, ctx) {
    this._preCtx = ctx;
    this._router.go(path);
    return false;
  }

  /**
   * Back page.
   *
   * @return {boolean} - always false.
   */
  back() {
    window.history.back();
    return false;
  }

  /**
   * Replace page.
   *
   * @param {Class<Page>} page - Page class
   * @param {*} ctx - context
   */
  replace(page, ctx = {}) {
    if (this._preCtx) {
      // Merge ctx by go to layer.ctx that contains idMap
      ctx = { ...ctx, ...this._preCtx };
      this._preCtx = null;
    }
    this._replaceContent(page, ctx);
    this._updateTitle();
  }

  /**
   * Replace layer.
   *
   * @param {Class<Page>} page - new page class.
   * @param {Object} ctx - passing context.
   */
  _replaceContent(page, ctx) {
    const ra = this._rootArea, oldPage = this._curPage;
    let data = null;
    if (oldPage) {
      oldPage.destroy()
    } else {
      data = window.initPageData || {};
      delete window.initPageData;
    }

    const params = Object.assign({
      parent: ra,
      context: { ...ra.context, ...ctx }
    }, data ? { data, hasInitData: true } : {});
    this._curPage = new page(params)
  }

  /**
   * Update page title of browser
   */
  _updateTitle() {
    let ttl = '';
    if (this._curPage) {
      ttl = this._curPage.title()
    }
    document.title = this._rootArea.title(ttl);
  }
}

export default new App();