123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 |
- /* 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 { createPromiseCapability, getFilenameFromUrl } from "pdfjs-lib";
- import { BaseTreeViewer } from "./base_tree_viewer.js";
- import { waitOnEventOrTimeout } from "./event_utils.js";
- /**
- * @typedef {Object} PDFAttachmentViewerOptions
- * @property {HTMLDivElement} container - The viewer element.
- * @property {EventBus} eventBus - The application event bus.
- * @property {DownloadManager} downloadManager - The download manager.
- */
- /**
- * @typedef {Object} PDFAttachmentViewerRenderParameters
- * @property {Object|null} attachments - A lookup table of attachment objects.
- */
- class PDFAttachmentViewer extends BaseTreeViewer {
- /**
- * @param {PDFAttachmentViewerOptions} options
- */
- constructor(options) {
- super(options);
- this.downloadManager = options.downloadManager;
- this.eventBus._on(
- "fileattachmentannotation",
- this.#appendAttachment.bind(this)
- );
- }
- reset(keepRenderedCapability = false) {
- super.reset();
- this._attachments = null;
- if (!keepRenderedCapability) {
- // The only situation in which the `_renderedCapability` should *not* be
- // replaced is when appending FileAttachment annotations.
- this._renderedCapability = createPromiseCapability();
- }
- this._pendingDispatchEvent = false;
- }
- /**
- * @private
- */
- async _dispatchEvent(attachmentsCount) {
- this._renderedCapability.resolve();
- if (attachmentsCount === 0 && !this._pendingDispatchEvent) {
- // Delay the event when no "regular" attachments exist, to allow time for
- // parsing of any FileAttachment annotations that may be present on the
- // *initially* rendered page; this reduces the likelihood of temporarily
- // disabling the attachmentsView when the `PDFSidebar` handles the event.
- this._pendingDispatchEvent = true;
- await waitOnEventOrTimeout({
- target: this.eventBus,
- name: "annotationlayerrendered",
- delay: 1000,
- });
- if (!this._pendingDispatchEvent) {
- return; // There was already another `_dispatchEvent`-call`.
- }
- }
- this._pendingDispatchEvent = false;
- this.eventBus.dispatch("attachmentsloaded", {
- source: this,
- attachmentsCount,
- });
- }
- /**
- * @private
- */
- _bindLink(element, { content, filename }) {
- element.onclick = () => {
- this.downloadManager.openOrDownloadData(element, content, filename);
- return false;
- };
- }
- /**
- * @param {PDFAttachmentViewerRenderParameters} params
- */
- render({ attachments, keepRenderedCapability = false }) {
- if (this._attachments) {
- this.reset(keepRenderedCapability);
- }
- this._attachments = attachments || null;
- if (!attachments) {
- this._dispatchEvent(/* attachmentsCount = */ 0);
- return;
- }
- const names = Object.keys(attachments).sort(function (a, b) {
- return a.toLowerCase().localeCompare(b.toLowerCase());
- });
- const fragment = document.createDocumentFragment();
- let attachmentsCount = 0;
- for (const name of names) {
- const item = attachments[name];
- const content = item.content,
- filename = getFilenameFromUrl(
- item.filename,
- /* onlyStripPath = */ true
- );
- const div = document.createElement("div");
- div.className = "treeItem";
- const element = document.createElement("a");
- this._bindLink(element, { content, filename });
- element.textContent = this._normalizeTextContent(filename);
- div.append(element);
- fragment.append(div);
- attachmentsCount++;
- }
- this._finishRendering(fragment, attachmentsCount);
- }
- /**
- * Used to append FileAttachment annotations to the sidebar.
- */
- #appendAttachment({ filename, content }) {
- const renderedPromise = this._renderedCapability.promise;
- renderedPromise.then(() => {
- if (renderedPromise !== this._renderedCapability.promise) {
- return; // The FileAttachment annotation belongs to a previous document.
- }
- const attachments = this._attachments || Object.create(null);
- for (const name in attachments) {
- if (filename === name) {
- return; // Ignore the new attachment if it already exists.
- }
- }
- attachments[filename] = {
- filename,
- content,
- };
- this.render({
- attachments,
- keepRenderedCapability: true,
- });
- });
- }
- }
- export { PDFAttachmentViewer };
|