/* Copyright 2020 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 { BaseTreeViewer } from "./base_tree_viewer.js"; /** * @typedef {Object} PDFLayerViewerOptions * @property {HTMLDivElement} container - The viewer element. * @property {EventBus} eventBus - The application event bus. * @property {IL10n} l10n - Localization service. */ /** * @typedef {Object} PDFLayerViewerRenderParameters * @property {OptionalContentConfig|null} optionalContentConfig - An * {OptionalContentConfig} instance. * @property {PDFDocument} pdfDocument - A {PDFDocument} instance. */ class PDFLayerViewer extends BaseTreeViewer { constructor(options) { super(options); this.l10n = options.l10n; this.eventBus._on("resetlayers", this._resetLayers.bind(this)); this.eventBus._on("togglelayerstree", this._toggleAllTreeItems.bind(this)); } reset() { super.reset(); this._optionalContentConfig = null; this._pdfDocument = null; } /** * @private */ _dispatchEvent(layersCount) { this.eventBus.dispatch("layersloaded", { source: this, layersCount, }); } /** * @private */ _bindLink(element, { groupId, input }) { const setVisibility = () => { this._optionalContentConfig.setVisibility(groupId, input.checked); this.eventBus.dispatch("optionalcontentconfig", { source: this, promise: Promise.resolve(this._optionalContentConfig), }); }; element.onclick = evt => { if (evt.target === input) { setVisibility(); return true; } else if (evt.target !== element) { return true; // The target is the "label", which is handled above. } input.checked = !input.checked; setVisibility(); return false; }; } /** * @private */ async _setNestedName(element, { name = null }) { if (typeof name === "string") { element.textContent = this._normalizeTextContent(name); return; } element.textContent = await this.l10n.get( "additional_layers", null, "Additional Layers" ); element.style.fontStyle = "italic"; } /** * @private */ _addToggleButton(div, { name = null }) { super._addToggleButton(div, /* hidden = */ name === null); } /** * @private */ _toggleAllTreeItems() { if (!this._optionalContentConfig) { return; } super._toggleAllTreeItems(); } /** * @param {PDFLayerViewerRenderParameters} params */ render({ optionalContentConfig, pdfDocument }) { if (this._optionalContentConfig) { this.reset(); } this._optionalContentConfig = optionalContentConfig || null; this._pdfDocument = pdfDocument || null; const groups = optionalContentConfig && optionalContentConfig.getOrder(); if (!groups) { this._dispatchEvent(/* layersCount = */ 0); return; } const fragment = document.createDocumentFragment(), queue = [{ parent: fragment, groups }]; let layersCount = 0, hasAnyNesting = false; while (queue.length > 0) { const levelData = queue.shift(); for (const groupId of levelData.groups) { const div = document.createElement("div"); div.className = "treeItem"; const element = document.createElement("a"); div.appendChild(element); if (typeof groupId === "object") { hasAnyNesting = true; this._addToggleButton(div, groupId); this._setNestedName(element, groupId); const itemsDiv = document.createElement("div"); itemsDiv.className = "treeItems"; div.appendChild(itemsDiv); queue.push({ parent: itemsDiv, groups: groupId.order }); } else { const group = optionalContentConfig.getGroup(groupId); const input = document.createElement("input"); this._bindLink(element, { groupId, input }); input.type = "checkbox"; input.id = groupId; input.checked = group.visible; const label = document.createElement("label"); label.setAttribute("for", groupId); label.textContent = this._normalizeTextContent(group.name); element.appendChild(input); element.appendChild(label); layersCount++; } levelData.parent.appendChild(div); } } if (hasAnyNesting) { this.container.classList.add("treeWithDeepNesting"); this._lastToggleIsShow = fragment.querySelectorAll(".treeItemsHidden").length === 0; } this.container.appendChild(fragment); this._dispatchEvent(layersCount); } /** * @private */ async _resetLayers() { if (!this._optionalContentConfig) { return; } // Fetch the default optional content configuration... const optionalContentConfig = await this._pdfDocument.getOptionalContentConfig(); this.eventBus.dispatch("optionalcontentconfig", { source: this, promise: Promise.resolve(optionalContentConfig), }); // ... and reset the sidebarView to the default state. this.render({ optionalContentConfig, pdfDocument: this._pdfDocument, }); } } export { PDFLayerViewer };