| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 | /* Copyright 2012 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */import { ScrollMode, SpreadMode } from "./ui_utils.js";import { CursorTool } from "./pdf_cursor_tools.js";import { PagesCountLimit } from "./pdf_viewer.js";/** * @typedef {Object} SecondaryToolbarOptions * @property {HTMLDivElement} toolbar - Container for the secondary toolbar. * @property {HTMLButtonElement} toggleButton - Button to toggle the visibility *   of the secondary toolbar. * @property {HTMLButtonElement} presentationModeButton - Button for entering *   presentation mode. * @property {HTMLButtonElement} openFileButton - Button to open a file. * @property {HTMLButtonElement} printButton - Button to print the document. * @property {HTMLButtonElement} downloadButton - Button to download the *   document. * @property {HTMLAnchorElement} viewBookmarkButton - Button to obtain a *   bookmark link to the current location in the document. * @property {HTMLButtonElement} firstPageButton - Button to go to the first *   page in the document. * @property {HTMLButtonElement} lastPageButton - Button to go to the last page *   in the document. * @property {HTMLButtonElement} pageRotateCwButton - Button to rotate the pages *   clockwise. * @property {HTMLButtonElement} pageRotateCcwButton - Button to rotate the *   pages counterclockwise. * @property {HTMLButtonElement} cursorSelectToolButton - Button to enable the *   select tool. * @property {HTMLButtonElement} cursorHandToolButton - Button to enable the *   hand tool. * @property {HTMLButtonElement} documentPropertiesButton - Button for opening *   the document properties dialog. */class SecondaryToolbar {  /**   * @param {SecondaryToolbarOptions} options   * @param {EventBus} eventBus   */  constructor(options, eventBus, externalServices) {    this.toolbar = options.toolbar;    this.toggleButton = options.toggleButton;    this.buttons = [      {        element: options.presentationModeButton,        eventName: "presentationmode",        close: true,      },      { element: options.printButton, eventName: "print", close: true },      { element: options.downloadButton, eventName: "download", close: true },      { element: options.viewBookmarkButton, eventName: null, close: true },      { element: options.firstPageButton, eventName: "firstpage", close: true },      { element: options.lastPageButton, eventName: "lastpage", close: true },      {        element: options.pageRotateCwButton,        eventName: "rotatecw",        close: false,      },      {        element: options.pageRotateCcwButton,        eventName: "rotateccw",        close: false,      },      {        element: options.cursorSelectToolButton,        eventName: "switchcursortool",        eventDetails: { tool: CursorTool.SELECT },        close: true,      },      {        element: options.cursorHandToolButton,        eventName: "switchcursortool",        eventDetails: { tool: CursorTool.HAND },        close: true,      },      {        element: options.scrollPageButton,        eventName: "switchscrollmode",        eventDetails: { mode: ScrollMode.PAGE },        close: true,      },      {        element: options.scrollVerticalButton,        eventName: "switchscrollmode",        eventDetails: { mode: ScrollMode.VERTICAL },        close: true,      },      {        element: options.scrollHorizontalButton,        eventName: "switchscrollmode",        eventDetails: { mode: ScrollMode.HORIZONTAL },        close: true,      },      {        element: options.scrollWrappedButton,        eventName: "switchscrollmode",        eventDetails: { mode: ScrollMode.WRAPPED },        close: true,      },      {        element: options.spreadNoneButton,        eventName: "switchspreadmode",        eventDetails: { mode: SpreadMode.NONE },        close: true,      },      {        element: options.spreadOddButton,        eventName: "switchspreadmode",        eventDetails: { mode: SpreadMode.ODD },        close: true,      },      {        element: options.spreadEvenButton,        eventName: "switchspreadmode",        eventDetails: { mode: SpreadMode.EVEN },        close: true,      },      {        element: options.documentPropertiesButton,        eventName: "documentproperties",        close: true,      },    ];    if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {      this.buttons.push({        element: options.openFileButton,        eventName: "openfile",        close: true,      });    }    this.items = {      firstPage: options.firstPageButton,      lastPage: options.lastPageButton,      pageRotateCw: options.pageRotateCwButton,      pageRotateCcw: options.pageRotateCcwButton,    };    this.eventBus = eventBus;    this.externalServices = externalServices;    this.opened = false;    // Bind the event listeners for click, cursor tool, and scroll/spread mode    // actions.    this.#bindClickListeners();    this.#bindCursorToolsListener(options);    this.#bindScrollModeListener(options);    this.#bindSpreadModeListener(options);    this.reset();  }  /**   * @type {boolean}   */  get isOpen() {    return this.opened;  }  setPageNumber(pageNumber) {    this.pageNumber = pageNumber;    this.#updateUIState();  }  setPagesCount(pagesCount) {    this.pagesCount = pagesCount;    this.#updateUIState();  }  reset() {    this.pageNumber = 0;    this.pagesCount = 0;    this.#updateUIState();    // Reset the Scroll/Spread buttons too, since they're document specific.    this.eventBus.dispatch("secondarytoolbarreset", { source: this });  }  #updateUIState() {    this.items.firstPage.disabled = this.pageNumber <= 1;    this.items.lastPage.disabled = this.pageNumber >= this.pagesCount;    this.items.pageRotateCw.disabled = this.pagesCount === 0;    this.items.pageRotateCcw.disabled = this.pagesCount === 0;  }  #bindClickListeners() {    // Button to toggle the visibility of the secondary toolbar.    this.toggleButton.addEventListener("click", this.toggle.bind(this));    // All items within the secondary toolbar.    for (const { element, eventName, close, eventDetails } of this.buttons) {      element.addEventListener("click", evt => {        if (eventName !== null) {          const details = { source: this };          for (const property in eventDetails) {            details[property] = eventDetails[property];          }          this.eventBus.dispatch(eventName, details);        }        if (close) {          this.close();        }        this.externalServices.reportTelemetry({          type: "buttons",          data: { id: element.id },        });      });    }  }  #bindCursorToolsListener({ cursorSelectToolButton, cursorHandToolButton }) {    this.eventBus._on("cursortoolchanged", function ({ tool }) {      const isSelect = tool === CursorTool.SELECT,        isHand = tool === CursorTool.HAND;      cursorSelectToolButton.classList.toggle("toggled", isSelect);      cursorHandToolButton.classList.toggle("toggled", isHand);      cursorSelectToolButton.setAttribute("aria-checked", isSelect);      cursorHandToolButton.setAttribute("aria-checked", isHand);    });  }  #bindScrollModeListener({    scrollPageButton,    scrollVerticalButton,    scrollHorizontalButton,    scrollWrappedButton,    spreadNoneButton,    spreadOddButton,    spreadEvenButton,  }) {    const scrollModeChanged = ({ mode }) => {      const isPage = mode === ScrollMode.PAGE,        isVertical = mode === ScrollMode.VERTICAL,        isHorizontal = mode === ScrollMode.HORIZONTAL,        isWrapped = mode === ScrollMode.WRAPPED;      scrollPageButton.classList.toggle("toggled", isPage);      scrollVerticalButton.classList.toggle("toggled", isVertical);      scrollHorizontalButton.classList.toggle("toggled", isHorizontal);      scrollWrappedButton.classList.toggle("toggled", isWrapped);      scrollPageButton.setAttribute("aria-checked", isPage);      scrollVerticalButton.setAttribute("aria-checked", isVertical);      scrollHorizontalButton.setAttribute("aria-checked", isHorizontal);      scrollWrappedButton.setAttribute("aria-checked", isWrapped);      // Permanently *disable* the Scroll buttons when PAGE-scrolling is being      // enforced for *very* long/large documents; please see the `BaseViewer`.      const forceScrollModePage =        this.pagesCount > PagesCountLimit.FORCE_SCROLL_MODE_PAGE;      scrollPageButton.disabled = forceScrollModePage;      scrollVerticalButton.disabled = forceScrollModePage;      scrollHorizontalButton.disabled = forceScrollModePage;      scrollWrappedButton.disabled = forceScrollModePage;      // Temporarily *disable* the Spread buttons when horizontal scrolling is      // enabled, since the non-default Spread modes doesn't affect the layout.      spreadNoneButton.disabled = isHorizontal;      spreadOddButton.disabled = isHorizontal;      spreadEvenButton.disabled = isHorizontal;    };    this.eventBus._on("scrollmodechanged", scrollModeChanged);    this.eventBus._on("secondarytoolbarreset", evt => {      if (evt.source === this) {        scrollModeChanged({ mode: ScrollMode.VERTICAL });      }    });  }  #bindSpreadModeListener({    spreadNoneButton,    spreadOddButton,    spreadEvenButton,  }) {    function spreadModeChanged({ mode }) {      const isNone = mode === SpreadMode.NONE,        isOdd = mode === SpreadMode.ODD,        isEven = mode === SpreadMode.EVEN;      spreadNoneButton.classList.toggle("toggled", isNone);      spreadOddButton.classList.toggle("toggled", isOdd);      spreadEvenButton.classList.toggle("toggled", isEven);      spreadNoneButton.setAttribute("aria-checked", isNone);      spreadOddButton.setAttribute("aria-checked", isOdd);      spreadEvenButton.setAttribute("aria-checked", isEven);    }    this.eventBus._on("spreadmodechanged", spreadModeChanged);    this.eventBus._on("secondarytoolbarreset", evt => {      if (evt.source === this) {        spreadModeChanged({ mode: SpreadMode.NONE });      }    });  }  open() {    if (this.opened) {      return;    }    this.opened = true;    this.toggleButton.classList.add("toggled");    this.toggleButton.setAttribute("aria-expanded", "true");    this.toolbar.classList.remove("hidden");  }  close() {    if (!this.opened) {      return;    }    this.opened = false;    this.toolbar.classList.add("hidden");    this.toggleButton.classList.remove("toggled");    this.toggleButton.setAttribute("aria-expanded", "false");  }  toggle() {    if (this.opened) {      this.close();    } else {      this.open();    }  }}export { SecondaryToolbar };
 |