toolbar.js

/* eslint-disable prettier/prettier */
import { FindOptions } from "./find_options.js";
import { PDFFindBar } from "./pdf_find_bar.js";
import { PDFFindController } from "./pdf_find_controller.js";
import { TW_DATA_TAG } from "./util.js";
import { ViewerType } from "./base_viewer.js";

/**
 * Toolbar
 */
class Toolbar {
  /**
   * Constructor
   * @param {*} app
   * @param {*} options
   * @param {*} zoomService
   */
  constructor(app, options, zoomService) {
    this.app = app;
    this._isOpenVisible = true;
    this._isCloseVisible = true;
    this._isDownloadVisible = true;
    this._isPrintVisible = true;
    this._isZoomInVisible = true;
    this._isZoomOutVisible = true;
    this._isZoomDropDownVisible = true;
    this._isPreviousPageVisible = true;
    this._isNextPageVisible = true;
    this._isPreviousVisitedVisible = true;
    this._isNextVisitedVisible = true;
    this._isMultiViewVisible = true;
    this._isSingleViewVisible = true;
    this._isPageNumberVisible = true;
    this._isRotateClockwiseVisible = true;
    this._isRotateCounterClockwiseVisible = true;
    this._isSearchVisible = true;
    this._isDocumentInfoVisible = true;
    this._isBookmarksVisible = true;
    this._isTooltipVisible = true;

    this.findBar = new PDFFindBar({
      bar: app.elements.tw2018elem_searchDiv,
      findField: app.elements.tw2018elem_searchTerm,
      highlightAllCheckbox: app.elements.tw2018elem_findHighlightAll,
      caseSensitiveCheckbox: app.elements.tw2018elem_findMatchCase,
      wholeWord: app.elements.tw2018elem_findWholeWord,
      findMsg: app.elements.tw2018elem_findMsg,
      findResultsCount: app.elements.tw2018elem_findResultsCount,
      findPreviousButton: app.elements.tw2018elem_previousfindBtn,
      findNextButton: app.elements.tw2018elem_nextfindBtn,
      searchButton: app.elements.tw2018elem_searchBtn,
      searchResult: app.elements.tw2018elem_searchResult,
      findResultCurrent: app.elements.tw2018elem_findResultCurrent,
      app,
    });
    /**
     * @member {FindOptions} - Default options for text search
     */
    this.findOptions = new FindOptions(this.findBar);
    this.findController = null;

    this._isVisible = true;

    const me = this;
    app.elements.tw2018elem_pageNumber.addEventListener(
      "keydown",
      function (e) {
        switch (e.which || e.keyCode) {
          case 13: {
            const pageNumberValue = parseInt(
              app.elements.tw2018elem_pageNumber.value
            );
            if (isNaN(pageNumberValue)) {
              app.elements.tw2018elem_pageNumber.value = me.app.viewer.pageNum;
              return;
            }
            me.app.gotoPage(pageNumberValue);
          }
        }
      }
    );

    const btnElements =
      app.elements.tw2018elem_mainContainer.getElementsByClassName(
        "tw2018css_btn"
      );
    for (let i = 0; i < btnElements.length; i++) {
      btnElements[i].addEventListener("click", function (event) {
        if (this.disabled) {
          event.preventDefault();
        }
      });

      btnElements[i].addEventListener("mouseover", function (event) {
        if (this.disabled) {
          return;
        }
        if (!me.isTooltipVisible || !this.dataset.tooltipText) {
          return;
        }
        if (this.children.length === 0) {
          const tooltipSpan = document.createElement("span");
          tooltipSpan.innerText = this.dataset.tooltipText;
          tooltipSpan.classList.add("tw2018css_tooltiptext");
          tooltipSpan.setAttribute(TW_DATA_TAG, "");
          this.appendChild(tooltipSpan);
        }
      });

      btnElements[i].addEventListener("mouseout", function (event) {
        if (this.disabled) {
          return;
        }

        if (!me.isTooltipVisible) {
          return;
        }

        if (this.children.length > 0) {
          this.innerHTML = "";
        }
      });
    }

    app.elements.tw2018elem_findMsgClose.addEventListener("click", function () {
      app.elements.tw2018elem_findMsgBox.style.display = "none";
    });

    app.elements.tw2018elem_openBtn.addEventListener("click", function (event) {
      if (!event.defaultPrevented) {
        me.app.openThroughDialog();
      }
    });

    app.elements.tw2018elem_closeBtn.addEventListener(
      "click",
      function (event) {
        if (!event.defaultPrevented) {
          me.app.releasePdfDoc();
          me.app.elements.tw2018elem_closeBtn.innerHTML = "";
          me.enableToolbar(false);
          me._zoomService.hideZoomDropDown();
        }
      }
    );

    app.elements.tw2018elem_previousvisitedBtn.addEventListener(
      "click",
      function (event) {
        if (!event.defaultPrevented) {
          me.app.prevVisited();
        }
      }
    );

    app.elements.tw2018elem_nextvisitedBtn.addEventListener(
      "click",
      function (event) {
        if (!event.defaultPrevented) {
          me.app.nextVisited();
        }
      }
    );

    app.elements.tw2018elem_searchTerm.addEventListener("input", function () {
      app.elements.tw2018elem_searchBtn.classList.toggle(
        "tw2018css_cancel",
        app.elements.tw2018elem_searchTerm.value
      );
    });

    app.elements.tw2018elem_searchBtn.addEventListener("click", function () {
      if (
        app.elements.tw2018elem_searchBtn.classList.contains("tw2018css_cancel")
      ) {
        app.elements.tw2018elem_searchTerm.value = "";
        app.elements.tw2018elem_searchBtn.classList.remove("tw2018css_cancel");
      }
    });

    app.elements.tw2018elem_printBtn.addEventListener(
      "click",
      function (event) {
        if (!event.defaultPrevented) {
          me.app.print();
        }
      }
    );

    app.elements.tw2018elem_documentinfoBtn.addEventListener(
      "click",
      function (event) {
        if (!event.defaultPrevented) {
          me.app.showDocumentProperties();
        }
      }
    );

    app.elements.tw2018elem_optionsBtn.addEventListener(
      "click",
      function (event) {
        me._toggleFindOptions(event, me);
      }
    );

    app.elements.tw2018elem_findOptionsClose.addEventListener(
      "click",
      function (event) {
        me._toggleFindOptions(event, me);
      }
    );

    app.elements.tw2018elem_downloadBtn.addEventListener(
      "click",
      function (event) {
        if (!event.defaultPrevented) {
          me.app.downloadDocument();
        }
      }
    );

    app.elements.tw2018elem_counterclockwiseBtn.addEventListener(
      "click",
      function (event) {
        if (!event.defaultPrevented) {
          me.app.rotateCounterClockwise();
        }
      }
    );

    app.elements.tw2018elem_clockwiseBtn.addEventListener(
      "click",
      function (event) {
        if (!event.defaultPrevented) {
          me.app.rotateClockwise();
        }
      }
    );

    app.elements.tw2018elem_nextpageBtn.addEventListener(
      "click",
      function (event) {
        if (!event.defaultPrevented) {
          me.app.nextPage();
        }
      }
    );

    app.elements.tw2018elem_previouspageBtn.addEventListener(
      "click",
      function (event) {
        if (!event.defaultPrevented) {
          me.app.previousPage();
        }
      }
    );

    app.elements.tw2018elem_singlepageBtn.addEventListener(
      "click",
      function (event) {
        if (!event.defaultPrevented) {
          me.app.activateSinglePageView();
        }
      }
    );

    app.elements.tw2018elem_multipageBtn.addEventListener(
      "click",
      function (event) {
        if (!event.defaultPrevented) {
          me.app.activateMultiPageView();
        }
      }
    );

    this.enableToolbar(false);
    this.setFindController();

    /**
     * @member {boolean} - Is open button visible. Default true.
     */
    this.isOpenVisible =
      options.toolbar.isOpenVisible === undefined
        ? true
        : options.toolbar.isOpenVisible;

    /**
     * @member {boolean} - Is close button visible. Default true.
     */
    this.isCloseVisible =
      options.toolbar.isCloseVisible === undefined
        ? true
        : options.toolbar.isCloseVisible;

    /**
     * @member {boolean} - Is download button visible. Default true.
     */
    this.isDownloadVisible =
      options.toolbar.isDownloadVisible === undefined
        ? true
        : options.toolbar.isDownloadVisible;

    /**
     * @member {boolean} - Is print button visible. Default true.
     */
    this.isPrintVisible =
      options.toolbar.isPrintVisible === undefined
        ? true
        : options.toolbar.isPrintVisible;

    /**
     * @member {boolean} - Is zoom-in button visible. Default true.
     */
    this.isZoomInVisible =
      options.toolbar.isZoomInVisible === undefined
        ? true
        : options.toolbar.isZoomInVisible;

    /**
     * @member {boolean} - Is zoom-out button visible. Default true.
     */
    this.isZoomOutVisible =
      options.toolbar.isZoomOutVisible === undefined
        ? true
        : options.toolbar.isZoomOutVisible;

    /**
     * @member {boolean} - Is zoom drop down visible. Default true.
     */
    this.isZoomDropDownVisible =
      options.toolbar.isZoomDropDownVisible === undefined
        ? true
        : options.toolbar.isZoomDropDownVisible;

    /**
     * @member {boolean} - Is multi-viewer button visible. Default true.
     */
    this.isMultiViewVisible =
      options.toolbar.isMultiViewVisible === undefined
        ? true
        : options.toolbar.isMultiViewVisible;

    /**
     * @member {boolean} - Is single-viewer button visible. Default true.
     */
    this.isSingleViewVisible =
      options.toolbar.isSingleViewVisible === undefined
        ? true
        : options.toolbar.isSingleViewVisible;

    /**
     * @member {boolean} - Is previous page button visible. Default true.
     */
    this.isPreviousPageVisible =
      options.toolbar.isPreviousPageVisible === undefined
        ? true
        : options.toolbar.isPreviousPageVisible;

    /**
     * @member {boolean} - Is next page button visible. Default true.
     */
    this.isNextPageVisible =
      options.toolbar.isNextPageVisible === undefined
        ? true
        : options.toolbar.isNextPageVisible;

    /**
     * @member {boolean} - Is page number field visible. Default true.
     */
    this.isPageNumberVisible =
      options.toolbar.isPageNumberVisible === undefined
        ? true
        : options.toolbar.isPageNumberVisible;

    /**
     * @member {boolean} - Is previous visited button visible. Default true.
     */
    this.isPreviousVisitedVisible =
      options.toolbar.isPreviousVisitedVisible === undefined
        ? true
        : options.toolbar.isPreviousVisitedVisible;

    /**
     * @member {boolean} - Is next visited button visible. Default true.
     */
    this.isNextVisitedVisible =
      options.toolbar.isNextVisitedVisible === undefined
        ? true
        : options.toolbar.isNextVisitedVisible;

    /**
     // eslint-disable-next-line max-len
     * @member {boolean} - Is rotate counter-clockwise button visible. Default true.
     */
    this.isRotateCounterClockwiseVisible =
      options.toolbar.isRotateCounterClockwiseVisible === undefined
        ? true
        : options.toolbar.isRotateCounterClockwiseVisible;

    /**
     * @member {boolean} - Is rotate clockwise button visible. Default true.
     */
    this.isRotateClockwiseVisible =
      options.toolbar.isRotateClockwiseVisible === undefined
        ? true
        : options.toolbar.isRotateClockwiseVisible;

    /**
     * @member {boolean} - Is document info button visible. Default true.
     */
    this.isDocumentInfoVisible =
      options.toolbar.isDocumentInfoVisible === undefined
        ? true
        : options.toolbar.isDocumentInfoVisible;

    /**
     * @member {boolean} - Is bookmarks button visible. Default true.
     */
    this.isBookmarksVisible =
      options.toolbar.isBookmarksVisible === undefined
        ? true
        : options.toolbar.isBookmarksVisible;

    /**
     * @member {boolean} - Is search field visible. Default true.
     */
    this.isSearchVisible =
      options.toolbar.isSearchVisible === undefined
        ? true
        : options.toolbar.isSearchVisible;

    this.findOptions.caseSensitive = options.findCaseSensitive || false;
    this.findOptions.highlightAll = options.findHighlightAll || false;
    this.findOptions.wholeWord = options.find.wholeWord || false;

    /**
     * @member {boolean} - Is button's tooltip visible. Default false.
     */
    this.isTooltipVisible = options.toolbar.isTooltipVisible || false;

    /**
     * @member {boolean} - Is toolbar visible. Default true.
     */
    this.isVisible =
      options.toolbar.isToolbarVisible === undefined
        ? true
        : options.toolbar.isToolbarVisible;
    this._zoomService = zoomService;
  }

  _toggleFindOptions(event, me) {
    if (event.defaultPrevented) {
      return;
    }

    const optionsBtn = me.app.elements.tw2018elem_optionsBtn;
    if (optionsBtn.classList.contains("tw2018css_focused")) {
      optionsBtn.classList.remove("tw2018css_focused");
      me.app.elements.tw2018elem_searchOptions.classList.add(
        "tw2018css_hidden"
      );
    } else {
      optionsBtn.classList.add("tw2018css_focused");
      me.app.elements.tw2018elem_searchOptions.classList.remove(
        "tw2018css_hidden"
      );

      const coords = this.getSearchOptionsCoordinate();
      me.app.elements.tw2018elem_searchOptions.style.top = coords.y + "px";
      me.app.elements.tw2018elem_searchOptions.style.left = coords.x + "px";
    }
  }

  getSearchOptionsCoordinate() {
    const optionsBtn = this.app.elements.tw2018elem_optionsBtn;
    const rectToolbar =
      this.app.elements.tw2018elem_toolbar.getBoundingClientRect();
    const rect = optionsBtn.getBoundingClientRect();
    const rect2 =
      this.app.elements.tw2018elem_searchOptions.getBoundingClientRect();
    const y = rectToolbar.height;
    const x = rect.right - rectToolbar.left - rect2.width;
    return { x, y };
  }

  setFindController() {
    if (this.findController) {
      this.findController.state.query = "";
      // if (this.findController.offset.pageIdx != null)
      //    this.viewer.pageNum = this.findController.offset.pageIdx + 1;
      this.findController.dispose();
    }

    this.findController = new PDFFindController({
      pdfViewer: this.app.viewer,
      integratedFind: false,
    });

    this.findController.setFindBar(this.findBar);
  }

  get height() {
    return this.isVisible ? 48 : 0;
  }

  // #region properties
  get isOpenVisible() {
    return this._isOpenVisible;
  }

  set isOpenVisible(val) {
    this._isOpenVisible = val;
    this._setDisplay(val, this.app.elements.tw2018elem_openBtn);
  }

  get isCloseVisible() {
    return this._isCloseVisible;
  }

  set isCloseVisible(val) {
    this._isCloseVisible = val;
    this._setDisplay(val, this.app.elements.tw2018elem_closeBtn);
  }

  get isVisible() {
    return this._isVisible;
  }

  set isVisible(val) {
    this._isVisible = val;
    this.app.elements.tw2018elem_toolbar.classList.toggle(
      "tw2018css_hidden",
      !val
    );
    this.app.elements.tw2018elem_viewerContainer.style.top = this.height;
  }

  get isTooltipVisible() {
    return this._isTooltipVisible;
  }

  set isTooltipVisible(val) {
    this._isTooltipVisible = val;
    if (!val) {
      this._toggleTooltip(val);
    }
  }

  get isDownloadVisible() {
    return this._isDownloadVisible;
  }

  set isDownloadVisible(val) {
    this._isDownloadVisible = val;
    this._setDisplay(val, this.app.elements.tw2018elem_downloadBtn);
  }

  get isPrintVisible() {
    return this._isPrintVisible;
  }

  set isPrintVisible(val) {
    this._isPrintVisible = val;
    this._setDisplay(val, this.app.elements.tw2018elem_printBtn);
  }

  get isZoomInVisible() {
    return this._isZoomInVisible;
  }

  set isZoomInVisible(val) {
    this._isZoomInVisible = val;
    this._setDisplay(val, this.app.elements.tw2018elem_zoominBtn);
  }

  get isZoomOutVisible() {
    return this._isZoomInVisible;
  }

  set isZoomOutVisible(val) {
    this._isZoomInVisible = val;
    this._setDisplay(val, this.app.elements.tw2018elem_zoomoutBtn);
  }

  get isZoomDropDownVisible() {
    return this._isZoomDropDownVisible;
  }

  set isZoomDropDownVisible(val) {
    this._isZoomDropDownVisible = val;
    this._setDisplay(val, this.app.elements.tw2018elem_zoomDropDown);
  }

  get isPreviousPageVisible() {
    return this._isPreviousPageVisible;
  }

  set isPreviousPageVisible(val) {
    this._isPreviousPageVisible = val;
    this._setDisplay(val, this.app.elements.tw2018elem_previouspageBtn);
  }

  get isNextPageVisible() {
    return this._isNextPageVisible;
  }

  set isNextPageVisible(val) {
    this._isNextPageVisible = val;
    this._setDisplay(val, this.app.elements.tw2018elem_nextpageBtn);
  }

  get isPreviousVisitedVisible() {
    return this._isPreviousVisitedVisible;
  }

  set isPreviousVisitedVisible(val) {
    this._isPreviousVisitedVisible = val;
    this._setDisplay(val, this.app.elements.tw2018elem_previousvisitedBtn);
  }

  get isNextVisitedVisible() {
    return this._isNextVisitedVisible;
  }

  set isNextVisitedVisible(val) {
    this._isNextVisitedVisible = val;
    this._setDisplay(val, this.app.elements.tw2018elem_nextvisitedBtn);
  }

  get isMultiViewVisible() {
    return this._isMultiViewVisible;
  }

  set isMultiViewVisible(val) {
    this._isMultiViewVisible = val;
    this._setDisplay(val, this.app.elements.tw2018elem_multipageBtn);
  }

  get isSingleViewVisible() {
    return this._isSingleViewVisible;
  }

  set isSingleViewVisible(val) {
    this._isSingleViewVisible = val;
    this._setDisplay(val, this.app.elements.tw2018elem_singlepageBtn);
  }

  get isPageNumberVisible() {
    return this._isPageNumberVisible;
  }

  set isPageNumberVisible(val) {
    this._isPageNumberVisible = val;
    this._setDisplay(val, this.app.elements.tw2018elem_pageNumber);
    this.app.elements.tw2018elem_sepTotalPages.style.display = val
      ? "inline"
      : "none";
    this.app.elements.tw2018elem_sepTotalPages.visible = val;
    this.app.elements.tw2018elem_totalPages.visible = val;
    this.app.elements.tw2018elem_totalPages.style.display = val
      ? "inline"
      : "none";
  }

  get isRotateClockwiseVisible() {
    return this._isRotateClockwiseVisible;
  }

  set isRotateClockwiseVisible(val) {
    this._isRotateClockwiseVisible = val;
    this._setDisplay(val, this.app.elements.tw2018elem_clockwiseBtn);
  }

  get isRotateCounterClockwiseVisible() {
    return this._isRotateCounterClockwiseVisible;
  }

  set isRotateCounterClockwiseVisible(val) {
    this._isRotateCounterClockwiseVisible = val;
    this._setDisplay(val, this.app.elements.tw2018elem_counterclockwiseBtn);
  }

  get isSearchVisible() {
    return this._isSearchVisible;
  }

  set isSearchVisible(val) {
    this._isSearchVisible = val;
    this._setDisplay(val, this.app.elements.tw2018elem_searchDiv);
  }

  get isDocumentInfoVisible() {
    return this._isDocumentInfoVisible;
  }

  set isDocumentInfoVisible(val) {
    this._isDocumentInfoVisible = val;
    this._setDisplay(val, this.app.elements.tw2018elem_documentinfoBtn);
  }

  get isBookmarksVisible() {
    return this._isBookmarksVisible;
  }

  set isBookmarksVisible(val) {
    this._isBookmarksVisible = val;
    this._setDisplay(val, this.app.elements.tw2018elem_bookmarkBtn);
  }
  // #endregion properties

  _toggleTooltip(show) {
    const elements =
      this.app.elements.tw2018elem_mainContainer.getElementsByClassName(
        "tw2018css_tooltiptext"
      );
    for (let i = 0; i < elements.length; i++) {
      elements[i].style.display = show ? "inline" : "none";
    }
  }

  _displayToolbarGroupSeparator(group) {
    let separator;
    let hiddenChildrenCount = 0;
    let isSeparatorHidden = false;
    for (let i = 0; i < group.children.length; i++) {
      const child = group.children[i];
      if (child.classList.contains("tw2018css_separator")) {
        separator = child;
      }
      if (child.classList.contains("tw2018css_hidden")) {
        if (separator === child) {
          isSeparatorHidden = true;
        }
        hiddenChildrenCount++;
      }
    }

    if (!separator) {
      return;
    }

    if (isSeparatorHidden) {
      if (hiddenChildrenCount < group.children.length) {
        separator.classList.remove("tw2018css_hidden");
      }
    } else {
      if (hiddenChildrenCount === group.children.length - 1) {
        separator.classList.add("tw2018css_hidden");
      }
    }
  }

  _setDisplay(show, elem) {
    elem.classList.toggle("tw2018css_hidden", !show);
    this._displayToolbarGroupSeparator(elem.parentElement);
  }

  updateStatus(pageNumber) {
    this.app.elements.tw2018elem_nextpageBtn.disabled =
      pageNumber === this.app.viewer.pdfDoc.numPages;
    this.app.elements.tw2018elem_previouspageBtn.disabled = pageNumber === 1;
  }

  enableToolbar(enable) {
    const btnElements = [
      "tw2018elem_multipageBtn",
      "tw2018elem_singlepageBtn",
      "tw2018elem_previouspageBtn",
      "tw2018elem_nextpageBtn",
      "tw2018elem_printBtn",
      "tw2018elem_downloadBtn",
      "tw2018elem_closeBtn",
      "tw2018elem_zoominBtn",
      "tw2018elem_zoomoutBtn",
      "tw2018elem_previousvisitedBtn",
      "tw2018elem_nextvisitedBtn",
      "tw2018elem_clockwiseBtn",
      "tw2018elem_counterclockwiseBtn",
      "tw2018elem_documentinfoBtn",
      "tw2018elem_bookmarkBtn",
      "tw2018elem_zoomDropDownArrow",
      "tw2018elem_zoomDropDown",
      "tw2018elem_zoomValuesDropDownClose",
      "tw2018elem_searchBtn",
      "tw2018elem_previousfindBtn",
      "tw2018elem_nextfindBtn",
      "tw2018elem_optionsBtn",
    ];

    for (let i = 0; i < btnElements.length; i++) {
      const btnElement = this.app.elements[btnElements[i]];
      if (enable) {
        if (
          btnElement === this.app.elements.tw2018elem_zoominBtn &&
          this.app.viewer.currentZoomLevel ===
            this.app.zoomService.zoomLevels.length - 1
        ) {
          continue;
        }

        if (
          btnElement === this.app.elements.tw2018elem_zoomoutBtn &&
          this.app.viewer.currentZoomLevel === 0
        ) {
          continue;
        }

        if (
          btnElement === this.app.tw2018elem_bookmarkBtn &&
          !this.app.bookmarkLayer.allBookmarks.length
        ) {
          continue;
        }
      } else {
        btnElement.classList.remove("tw2018css_focused");
      }

      btnElement.disabled = !enable;
      this.app.zoomService.hideZoomDropDown.bind(this.app.zoomService);
    }

    const divElements = [
      "tw2018elem_pageNumberDiv",
      "tw2018elem_zoomDropDown",
      "tw2018elem_searchDiv",
    ];
    for (let i = 0; i < divElements.length; i++) {
      const divElement = this.app.elements[divElements[i]];
      divElement.classList.toggle("tw2018css_disabled", !enable);
    }

    const inputElements = [
      "tw2018elem_zoomDropDownValue",
      "tw2018elem_pageNumber",
      "tw2018elem_searchTerm",
    ];
    for (let i = 0; i < inputElements.length; i++) {
      this.app.elements[inputElements[i]].disabled = !enable;
    }

    if (enable) {
      this.app.elements.tw2018elem_singlepageBtn.classList.toggle(
        "tw2018css_focused",
        this.app.viewer.type === ViewerType.SINGLE_VIEW
      );
      this.app.elements.tw2018elem_multipageBtn.classList.toggle(
        "tw2018css_focused",
        this.app.viewer.type !== ViewerType.SINGLE_VIEW
      );
    }
  }
}

export { Toolbar };