Source: components/Navbar.js

"use strict";
import $ from "jquery";
import helpers, { isURL } from "../helpers";
import axios from "axios";
import Settings from "./Settings";
const spinnerElement = `<span class="spinner-border  spinner-border-sm" id="consumingSpinner" > </span>`;
let alertElement = (text, type, id) => {
  return `
  <div id="${id}" class="alert alert-${type} position-fixed top-0 start-0 p-3 w-100" style="z-index: 11" role="alert">${text}</div>`;
};
const fileConsumed = new Event("fileConsumed");
/**
 * This class creates a Navbar.
 * @type {object}
 * @constructor
 * @public
 * @property {object}  LV - Holds an instance of the LeftView class.
 * @property {object}  tc - Holds an instance of the ThingController class.
 * @property {object}  MV - Holds an instance of the MiddleView class.
 * @property {object}  htmlElement - An HTML element of the Navbar.
 */
class Navbar {
  #LV;
  #tc;
  #MV;
  #htmlElement = $.parseHTML(
    `<div id="navbar" class="">
            <form id="consumingForm" class="">
              <input class=" " type="url" name="thingURL" id="thingURL" placeholder="URL" ia-label="Search">
              <input class=""type="file" name="thingFile" accept=".json,.jsonld" id="fileInput">
              <button class="btn" id="fileInputTrigger" style="display:none" type="button">Upload</button> 
              <button class="btn" type="submit" id="consumeButton" >Consume</button>
            </form>
            <div id="thingsAvatarContainer" class="d-inline "></div>
            ${Settings.htmlElement}
    </div>`
  );
  get htmlElement() {
    this.#onClick();
    this.#onUploadingFile();
    return this.#htmlElement;
  }
  set ThingsController(tc) {
    this.#tc = tc;
  }
  set MiddleView(MV) {
    this.#MV = MV;
  }
  set LeftView(LV) {
    this.#LV = LV;
  }
  /**
   * A click event listener attached to this HTML element.
   * @type {Function}
   * @returns {void}
   */
  #onClick() {
    $(this.#htmlElement).on("click", (e) => {
      let key = e.target.className.includes("thingAvatar")
        ? "thingAvatar"
        : e.target.id;

      switch (key) {
        case "fileInputTrigger":
          this.#triggerFileBrowser();
          break;
        case "consumeButton":
          e.preventDefault();
          $("#thingURL").val().length
            ? this.#onSubmit()
            : $("#fileInput").trigger("click");
          break;
        case "thingAvatar":
          !e.target.id.includes("switcher--") &&
            this.#changeCurrentThing(e.target.id);
          break;
        case "settings-form-save":
          Settings.saveSettings();
          break;
        case "settings-form-close":
          Settings.appendSettingsForm();
          break;
        default:
          break;
      }
    });
  }
  /**
   * A change event listener attached to this HTML element.
   * @type {Function}
   * @returns {void}
   */
  #onUploadingFile() {
    $(this.#htmlElement)
      .find("#fileInput")
      .on("change", () => {
        let file = $("#fileInput").prop("files");
        try {
          if (file[0].size === 0) {
            throw "The selected file is empty!";
          } else {
            this.#onSubmit();
          }
        } catch (error) {
          $("#consumingForm").trigger("reset");
          alert(error);
        }
      });
  }
  /**
   * to trigger a click action on the file input field.
   * @type {Function}
   * @returns {void}
   */
  #triggerFileBrowser() {
    $("#thingURL").attr("type", "text");
    $("#fileInput").trigger("click");
  }
  /**
   * A submit event listener attached to this HTML element.
   * @type {Function}
   * @returns {void}
   */
  async #onSubmit() {
    let files = $("#fileInput").prop("files");
    let url = $("#thingURL").val();
    let key = false;
    $("#consumeButton").html(spinnerElement);
    if (files.length > 0) {
      let td = await helpers.fileToJSON(files[0]);
      await this.#tc.consume(td);
      key = !key;
      $("#thingURL").attr("type", "url");
    } else {
      try {
        url = !url.toLocaleLowerCase().includes("http")
          ? new URL("http://" + url)
          : new URL(url);
        await axios.get(url).then(async (response) => {
          let td = response.data;
          await this.#tc.consume(td);
          key = !key;
        });
      } catch (error) {
        let alertId = "alert-" + Date.now();
        $("body").append(alertElement(error, "danger", alertId)).show("slow");
        setTimeout(() => {
          $("#" + alertId).remove();
        }, 2000);
      }
    }
    $("#consumeButton").html("Consume");
    if (key) {
      let avatarElement = this.#thingAvatarGenerator(
        this.#tc.currentThingTitle,
        this.#tc.currentThingID
      );
      this.#appendThingAvatar(avatarElement);
      $("#logoDiv").hide();
      $("#bodyDiv").show();
      this.#LV.appendMetadata();
      this.#LV.highlightButton("affordanceMetadata");
      this.#MV.clearMiddleViewContent();
      this.#MV.addMiddleViewTitle(this.#tc.currentThingTitle);
      document.dispatchEvent(fileConsumed);
      let alertId = "alert-" + Date.now();
      $("body")
        .append(
          alertElement(
            `Successfully Consumed ${this.#tc.currentThingTitle}`,
            "success",
            alertId
          )
        )
        .show("slow");
      setTimeout(() => {
        $("#" + alertId).remove();
      }, 2000);
    }

    $("#consumingForm").trigger("reset");
  }
  /**
   * Generates an avatar.
   * @type {Function}
   * @param {string} title - the title of a Thing.
   * @param {string} title - the id of a Thing.
   * @returns {object}  - Returns an HTML element.
   */
  #thingAvatarGenerator(title, id) {
    title = title.split(" ");
    let avatarText = "";
    if (title.length > 1) {
      avatarText = (title[0][0] + title[1][0]).toUpperCase();
    } else if (title.length === 1) {
      avatarText = (title[0][0] + title[0][1]).toUpperCase();
    }
    return $.parseHTML(
      `<div id="thingAvatar--${id}"  class="thingAvatar currentThingAvatar"> ${avatarText} </div>`
    );
  }
  /**
   * Appends an avatar element to the Navbar.
   * @type {Function}
   * @param {object} id - HTML element of a thing avatar.
   * @returns {void}
   */
  #appendThingAvatar(avatarElement) {
    $(`.thingAvatar`).removeClass("currentThingAvatar");
    $("#thingsAvatarContainer").prepend(avatarElement);
  }
  /**
   * To change the current Thing.
   * @type {Function}
   * @param {string} id - A Thing id.
   * @returns {void}
   */
  #changeCurrentThing(id) {
    $(`.thingAvatar`).removeClass("currentThingAvatar");
    document.getElementById(id).classList.add("currentThingAvatar");
    $(`#${id}`).addClass("currentThingAvatar");
    let currentID = id.split("--")[1];
    this.#tc.setCurrentThingByID(currentID);
    this.#LV.appendMetadata();
    this.#LV.highlightButton("affordanceMetadata");
    this.#MV.addMiddleViewTitle(this.#tc.currentThingTitle);
    this.#MV.clearMiddleViewContent();
  }
  showSettings() {}
  hideSettings() {}
}

export default new Navbar();