123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- /* 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 { removeNullCharacters } from "./ui_utils.js";
- const TREEITEM_OFFSET_TOP = -100; // px
- const TREEITEM_SELECTED_CLASS = "selected";
- class BaseTreeViewer {
- constructor(options) {
- if (this.constructor === BaseTreeViewer) {
- throw new Error("Cannot initialize BaseTreeViewer.");
- }
- this.container = options.container;
- this.eventBus = options.eventBus;
- this.reset();
- }
- reset() {
- this._pdfDocument = null;
- this._lastToggleIsShow = true;
- this._currentTreeItem = null;
- // Remove the tree from the DOM.
- this.container.textContent = "";
- // Ensure that the left (right in RTL locales) margin is always reset,
- // to prevent incorrect tree alignment if a new document is opened.
- this.container.classList.remove("treeWithDeepNesting");
- }
- /**
- * @private
- */
- _dispatchEvent(count) {
- throw new Error("Not implemented: _dispatchEvent");
- }
- /**
- * @private
- */
- _bindLink(element, params) {
- throw new Error("Not implemented: _bindLink");
- }
- /**
- * @private
- */
- _normalizeTextContent(str) {
- // Chars in range [0x01-0x1F] will be replaced with a white space
- // and 0x00 by "".
- return (
- removeNullCharacters(str, /* replaceInvisible */ true) ||
- /* en dash = */ "\u2013"
- );
- }
- /**
- * Prepend a button before a tree item which allows the user to collapse or
- * expand all tree items at that level; see `_toggleTreeItem`.
- * @private
- */
- _addToggleButton(div, hidden = false) {
- const toggler = document.createElement("div");
- toggler.className = "treeItemToggler";
- if (hidden) {
- toggler.classList.add("treeItemsHidden");
- }
- toggler.onclick = evt => {
- evt.stopPropagation();
- toggler.classList.toggle("treeItemsHidden");
- if (evt.shiftKey) {
- const shouldShowAll = !toggler.classList.contains("treeItemsHidden");
- this._toggleTreeItem(div, shouldShowAll);
- }
- };
- div.prepend(toggler);
- }
- /**
- * Collapse or expand the subtree of a tree item.
- *
- * @param {Element} root - the root of the item (sub)tree.
- * @param {boolean} show - whether to show the item (sub)tree. If false,
- * the item subtree rooted at `root` will be collapsed.
- * @private
- */
- _toggleTreeItem(root, show = false) {
- this._lastToggleIsShow = show;
- for (const toggler of root.querySelectorAll(".treeItemToggler")) {
- toggler.classList.toggle("treeItemsHidden", !show);
- }
- }
- /**
- * Collapse or expand all subtrees of the `container`.
- * @private
- */
- _toggleAllTreeItems() {
- this._toggleTreeItem(this.container, !this._lastToggleIsShow);
- }
- /**
- * @private
- */
- _finishRendering(fragment, count, hasAnyNesting = false) {
- if (hasAnyNesting) {
- this.container.classList.add("treeWithDeepNesting");
- this._lastToggleIsShow = !fragment.querySelector(".treeItemsHidden");
- }
- this.container.append(fragment);
- this._dispatchEvent(count);
- }
- render(params) {
- throw new Error("Not implemented: render");
- }
- /**
- * @private
- */
- _updateCurrentTreeItem(treeItem = null) {
- if (this._currentTreeItem) {
- // Ensure that the current treeItem-selection is always removed.
- this._currentTreeItem.classList.remove(TREEITEM_SELECTED_CLASS);
- this._currentTreeItem = null;
- }
- if (treeItem) {
- treeItem.classList.add(TREEITEM_SELECTED_CLASS);
- this._currentTreeItem = treeItem;
- }
- }
- /**
- * @private
- */
- _scrollToCurrentTreeItem(treeItem) {
- if (!treeItem) {
- return;
- }
- // Ensure that the treeItem is *fully* expanded, such that it will first of
- // all be visible and secondly that scrolling it into view works correctly.
- let currentNode = treeItem.parentNode;
- while (currentNode && currentNode !== this.container) {
- if (currentNode.classList.contains("treeItem")) {
- const toggler = currentNode.firstElementChild;
- toggler?.classList.remove("treeItemsHidden");
- }
- currentNode = currentNode.parentNode;
- }
- this._updateCurrentTreeItem(treeItem);
- this.container.scrollTo(
- treeItem.offsetLeft,
- treeItem.offsetTop + TREEITEM_OFFSET_TOP
- );
- }
- }
- export { BaseTreeViewer };
|