Pre-release
AdventureJS Docs Downloads Bundler Devlog
Score: 0 Moves: 0
// Display.js

// css columns
//https://developer.mozilla.org/en-US/docs/Web/CSS/columns
(function () {
  /* global AdventureJS A */

  /**
   * @class AdventureJS.Display
   * @ajsnavheading EngineClasses
   * @param {Game} game A reference to the game instance.
   * @param {containerId|HTMLElement} containerId An ID for an HTML element to build the game to.
   * @summary Manages the main game display including all related HTML elements.
   * @classdesc
   * <p>
   * <strong>Display</strong> creates and manages the game display,
   * including the main input and output areas and the status bar.
   * It also manages custom compasses, verb docks and inventory
   * docks. Authors can customize the display with custom CSS.
   * CSS styles for Display can be found in
   * <a href="/css/adventurejs.css">adventurejs.css</a>.
   * To learn more, see the
   * </p>
   */
  class Display {
    constructor(containerId, game, game_name) {
      game.log(
        "L1005",
        "log",
        1,
        "[Display.js] Constructing display.",
        "Display"
      );

      /**
       * A reference back to the main {@link AdventureJS.Game|Game} object.
       * @var {Object} AdventureJS.Display#game
       * @default {}
       */
      this.game = game;

      /**
       * An array that contains a list of references to the
       * HTML element of any compasses, including the one
       * in the status bar as well as any custom compasses.
       * @var {compasses} AdventureJS.Display#compasses
       * @default []
       */
      this.compasses = [];

      /**
       * An array that contains a list of references to the
       * HTML elements of any verb docks.
       * @var {verbdocks} AdventureJS.Display#verbdocks
       * @default []
       */
      this.verbdocks = [];

      /**
       * An array that contains a list of references to the
       * HTML elements of any room docks.
       * @var {roomdocks} AdventureJS.Display#roomdocks
       * @default []
       */
      this.roomdocks = [];

      /**
       * An array that contains a list of references to the
       * HTML elements of any room content docks.
       * @var {contentdocks} AdventureJS.Display#contentdocks
       * @default []
       */
      this.contentdocks = [];

      /**
       * An array that contains a list of references to the
       * HTML elements of any exit docks.
       * @var {exitdocks} AdventureJS.Display#exitdocks
       * @default []
       */
      this.exitdocks = [];

      /**
       * An array that contains a list of references to the
       * HTML elements of any inventory docks.
       * @var {inventorydocks} AdventureJS.Display#inventorydocks
       * @default []
       */
      this.inventorydocks = [];

      /**
       * An array that contains a list of references to the
       * HTML elements of any description docks.
       * @var {inventorydocks} AdventureJS.Display#descriptiondocks
       * @default []
       */
      this.descriptiondocks = [];

      /**
       * An array that contains a list of references to the
       * HTML elements of any image docks.
       * @var {imagedocks} AdventureJS.Display#imagedocks
       * @default []
       */
      this.imagedocks = [];

      /**
       * An array that contains a list of references to the
       * HTML elements of all docks.
       * @var {docks} AdventureJS.Display#docks
       * @default []
       */
      this.docks = [];

      /**
       * A reference to the game's HTML display element.
       * @var {HTMLElement} AdventureJS.Display#displayEl
       * @default null
       */
      this.displayEl = null;

      /**
       * The ID of the game's HTML display element.
       * @var {HTMLElement} AdventureJS.Display#containerId
       * @default null
       */
      this.containerId = null;

      this.initialize(containerId, game_name);

      this.updateDisplaySizes();
    }

    updateDisplaySizes() {
      const style = document.documentElement.style;

      /* container contains game */
      const container = this.containerEl.getBoundingClientRect();
      style.setProperty(
        "--ajs-actual-container-height",
        `${container.height}px`
      );
      style.setProperty("--ajs-actual-container-width", `${container.width}px`);
      style.setProperty("--ajs-actual-container-left", `${container.left}px`);
      style.setProperty("--ajs-actual-container-top", `${container.top}px`);

      /* content contains titlebar, statusbar, output, input */
      const content = this.contentEl.getBoundingClientRect();
      style.setProperty("--ajs-actual-content-height", `${content.height}px`);
      style.setProperty("--ajs-actual-content-width", `${content.width}px`);
      style.setProperty("--ajs-actual-content-left", `${content.left}px`);
      style.setProperty("--ajs-actual-content-top", `${content.top}px`);

      /* output is set display:flex so it expands to fit between
      titlebar, statusbar, and input */
      const output = this.outputContainerEl.getBoundingClientRect();
      style.setProperty("--ajs-actual-output-height", `${output.height}px`);
      style.setProperty("--ajs-actual-output-width", `${output.width}px`);
      style.setProperty("--ajs-actual-output-left", `${output.left}px`);
      style.setProperty("--ajs-actual-output-top", `${output.top}px`);

      /* input has a set height but we want to account for padding */
      const input = this.inputContainerEl.getBoundingClientRect();
      style.setProperty("--ajs-actual-input-height", `${input.height}px`);
      style.setProperty("--ajs-actual-input-width", `${input.width}px`);
      style.setProperty("--ajs-actual-input-left", `${input.left}px`);
      style.setProperty("--ajs-actual-input-top", `${input.top}px`);

      /* ui contains title and status */
      const ui = this.uiEl.getBoundingClientRect();
      style.setProperty("--ajs-actual-ui-height", `${ui.height}px`);
      style.setProperty("--ajs-actual-ui-width", `${ui.width}px`);
      style.setProperty("--ajs-actual-ui-left", `${ui.left}px`);
      style.setProperty("--ajs-actual-ui-top", `${ui.top}px`);

      /* status has a set height but we want to account for padding */
      const status = this.statusbarEl.getBoundingClientRect();
      style.setProperty("--ajs-actual-statusbar-height", `${status.height}px`);
      style.setProperty("--ajs-actual-statusbar-width", `${status.width}px`);
      style.setProperty("--ajs-actual-statusbar-left", `${status.left}px`);
      style.setProperty("--ajs-actual-statusbar-top", `${status.top}px`);

      /* status has a set height but we want to account for padding */
      const title = this.titlebarEl.getBoundingClientRect();
      style.setProperty("--ajs-actual-titlebar-height", `${title.height}px`);
      style.setProperty("--ajs-actual-titlebar-width", `${title.width}px`);
      style.setProperty("--ajs-actual-titlebar-left", `${title.left}px`);
      style.setProperty("--ajs-actual-titlebar-top", `${title.top}px`);

      const topdocks = this.topDocksContainerEl.getBoundingClientRect();
      style.setProperty("--ajs-actual-topdocks-height", `${topdocks.height}px`);
      style.setProperty("--ajs-actual-topdocks-width", `${topdocks.width}px`);
      style.setProperty("--ajs-actual-topdocks-left", `${topdocks.left}px`);
      style.setProperty("--ajs-actual-topdocks-top", `${topdocks.top}px`);

      const bottomdocks = this.bottomDocksContainerEl.getBoundingClientRect();
      style.setProperty(
        "--ajs-actual-bottomdocks-height",
        `${bottomdocks.height}px`
      );
      style.setProperty(
        "--ajs-actual-bottomdocks-width",
        `${bottomdocks.width}px`
      );
      style.setProperty(
        "--ajs-actual-bottomdocks-left",
        `${bottomdocks.left}px`
      );
      style.setProperty("--ajs-actual-bottomdocks-top", `${bottomdocks.top}px`);

      // .ajs-output-container
    }

    /**
     * Append classes to the last line of input.
     * @memberof AdventureJS.Display
     * @method AdventureJS.Display#appendClassesToLastInput
     * @param {String} classes
     */
    appendClassesToLastInput(classes) {
      let inputs = this.outputEl.querySelectorAll(".ajs-player-input");
      let last_input = inputs.item(inputs.length - 1);
      last_input.classList.add(classes);
    }

    /**
     * Append classes to the last line of output.
     * @memberof AdventureJS.Display
     * @method AdventureJS.Display#appendClassesToLastOutput
     * @param {String} classes
     */
    appendClassesToLastOutput(classes) {
      let outputs = this.outputEl.querySelectorAll(
        ".ajs-p:not(.ajs-player-input):not(.ajs-debug)"
      );
      let last_output = outputs.item(outputs.length - 1);
      last_output.classList.add(classes);
    }

    /**
     * Hide the game's statusbar.
     * @memberof AdventureJS.Display
     * @method AdventureJS.Display#hideStatusbar
     * @returns {boolean}
     */
    hideStatusbar() {
      this.statusbarEl.classList.add("ajs-hide");
      this.statusbarEl.ariaHidden = true;
      this.updateDisplaySizes();
      return true;
    }

    /**
     * Show the game's statusbar.
     * @memberof AdventureJS.Display
     * @method AdventureJS.Display#showStatusbar
     * @returns {boolean}
     */
    showStatusbar() {
      this.statusbarEl.classList.remove("ajs-hide");
      this.statusbarEl.ariaHidden = false;
      this.updateDisplaySizes();
      return true;
    }

    /**
     * Hide the game's titlebar.
     * @memberof AdventureJS.Display
     * @method AdventureJS.Display#hideTitlebar
     * @returns {boolean}
     */
    hideTitlebar() {
      this.titlebarEl.classList.add("ajs-hide");
      this.titlebarEl.ariaHidden = true;
      this.updateDisplaySizes();
      return true;
    }

    /**
     * Show the game's titlebar.
     * @memberof AdventureJS.Display
     * @method AdventureJS.Display#showTitlebar
     * @returns {boolean}
     */
    showTitlebar() {
      this.titlebarEl.classList.remove("ajs-hide");
      this.titlebarEl.ariaHidden = false;
      this.updateDisplaySizes();
      return true;
    }

    /**
     * The game's title.
     * @var {String} AdventureJS.Display#title
     * @default ""
     */
    get title() {
      return this.titleEl.innerText;
    }
    set title(title) {
      this.titleEl.innerText = title;
    }

    /**
     * The game's version.
     * @var {String} AdventureJS.Display#version
     * @default ""
     */
    get version() {
      return this.versionEl.innerText;
    }
    set version(version) {
      this.versionEl.innerText = version;
    }

    /**
     * The game's author.
     * @var {String} AdventureJS.Display#author
     * @default ""
     */
    get author() {
      return this.authorEl.innerText;
    }
    set author(author) {
      this.authorEl.innerText = author;
    }

    /**
     * The current room's name.
     * @var {String} AdventureJS.Display#room
     * @default ""
     */
    get room() {
      return this.roomEl.innerText;
    }
    set room(room) {
      this.roomEl.innerText = room;
    }

    /**
     * The current score.
     * @var {String} AdventureJS.Display#score
     * @default ""
     */
    get score() {
      return this.scoreEl.innerText;
    }
    set score(score) {
      this.scoreEl.innerText = score;
    }
  }
  AdventureJS.Display = Display;
})();