commit c954fc70457a3fb93f10a89ae71ddb6f944496f0
parent 1e39260629a119a1976c5c6ef8e1cc0176547f4a
Author: Calixte Denizet <calixte.denizet@gmail.com>
Date: Fri, 28 Nov 2025 18:27:05 +0000
Bug 2003036 - Update PDF.js to new version ec5330f78c1feb384156bdf6c69b18bedf36b4a3 r=pdfjs-reviewers,marco
Differential Revision: https://phabricator.services.mozilla.com/D274441
Diffstat:
10 files changed, 1641 insertions(+), 365 deletions(-)
diff --git a/toolkit/components/pdfjs/content/build/pdf.mjs b/toolkit/components/pdfjs/content/build/pdf.mjs
@@ -21,8 +21,8 @@
*/
/**
- * pdfjsVersion = 5.4.402
- * pdfjsBuild = 57334bd20
+ * pdfjsVersion = 5.4.445
+ * pdfjsBuild = ec5330f78
*/
/******/ // The require scope
/******/ var __webpack_require__ = {};
@@ -1816,7 +1816,7 @@ function renderRichText({
intent: "richText"
});
}
- fragment.firstChild.classList.add("richText", className);
+ fragment.firstElementChild.classList.add("richText", className);
container.append(fragment);
}
function makePathFromDrawOPS(data) {
@@ -6292,11 +6292,11 @@ class AnnotationEditor {
if (nextFirstPosition !== firstPosition) {
if (nextFirstPosition < firstPosition) {
for (let i = 0; i < firstPosition - nextFirstPosition; i++) {
- this.#resizersDiv.append(this.#resizersDiv.firstChild);
+ this.#resizersDiv.append(this.#resizersDiv.firstElementChild);
}
} else if (nextFirstPosition > firstPosition) {
for (let i = 0; i < nextFirstPosition - firstPosition; i++) {
- this.#resizersDiv.firstChild.before(this.#resizersDiv.lastChild);
+ this.#resizersDiv.firstElementChild.before(this.#resizersDiv.lastElementChild);
}
}
let i = 0;
@@ -6308,7 +6308,7 @@ class AnnotationEditor {
}
this.#setResizerTabIndex(0);
this.#isResizerEnabledForKeyboard = true;
- this.#resizersDiv.firstChild.focus({
+ this.#resizersDiv.firstElementChild.focus({
focusVisible: true
});
event.preventDefault();
@@ -6539,10 +6539,10 @@ class AnnotationEditor {
}
resetAnnotationElement(annotation) {
const {
- firstChild
+ firstElementChild
} = annotation.container;
- if (firstChild?.nodeName === "DIV" && firstChild.classList.contains("annotationContent")) {
- firstChild.remove();
+ if (firstElementChild?.nodeName === "DIV" && firstElementChild.classList.contains("annotationContent")) {
+ firstElementChild.remove();
}
}
}
@@ -7102,6 +7102,9 @@ class FontFaceObject {
get disableFontFace() {
return this.#fontData.disableFontFace ?? false;
}
+ set disableFontFace(value) {
+ shadow(this, "disableFontFace", !!value);
+ }
get fontExtraProperties() {
return this.#fontData.fontExtraProperties ?? false;
}
@@ -7135,6 +7138,9 @@ class FontFaceObject {
get bbox() {
return this.#fontData.bbox;
}
+ set bbox(bbox) {
+ shadow(this, "bbox", bbox);
+ }
get fontMatrix() {
return this.#fontData.fontMatrix;
}
@@ -13083,7 +13089,7 @@ function getDocument(src = {}) {
}
const docParams = {
docId,
- apiVersion: "5.4.402",
+ apiVersion: "5.4.445",
data,
password,
disableAutoFetch,
@@ -14457,7 +14463,8 @@ class WorkerTransport {
info: results[0],
metadata: results[1] ? new Metadata(results[1]) : null,
contentDispositionFilename: this._fullReader?.filename ?? null,
- contentLength: this._fullReader?.contentLength ?? null
+ contentLength: this._fullReader?.contentLength ?? null,
+ hasStructTree: results[2]
}));
this.#methodPromises.set(name, promise);
return promise;
@@ -14671,8 +14678,8 @@ class InternalRenderTask {
}
}
}
-const version = "5.4.402";
-const build = "57334bd20";
+const version = "5.4.445";
+const build = "ec5330f78";
;// ./src/display/editor/color_picker.js
@@ -14805,13 +14812,13 @@ class ColorPicker {
return;
}
if (event.target === this.#button) {
- this.#dropdown.firstChild?.focus();
+ this.#dropdown.firstElementChild?.focus();
return;
}
event.target.nextSibling?.focus();
}
_moveToPrevious(event) {
- if (event.target === this.#dropdown?.firstChild || event.target === this.#button) {
+ if (event.target === this.#dropdown?.firstElementChild || event.target === this.#button) {
if (this.#isDropdownVisible) {
this._hideDropdownFromKeyboard();
}
@@ -14827,14 +14834,14 @@ class ColorPicker {
this.#openDropdown(event);
return;
}
- this.#dropdown.firstChild?.focus();
+ this.#dropdown.firstElementChild?.focus();
}
_moveToEnd(event) {
if (!this.#isDropdownVisible) {
this.#openDropdown(event);
return;
}
- this.#dropdown.lastChild?.focus();
+ this.#dropdown.lastElementChild?.focus();
}
#keyDown(event) {
ColorPicker._keyboardManager.exec(this, event);
@@ -24270,7 +24277,7 @@ class AnnotationEditorLayer {
return;
}
if (editor.parent && editor.annotationElementId) {
- this.#uiManager.addDeletedAnnotationElement(editor.annotationElementId);
+ this.#uiManager.addDeletedAnnotationElement(editor);
AnnotationEditor.deleteAnnotationElement(editor);
editor.annotationElementId = null;
}
@@ -24802,8 +24809,8 @@ class DrawLayer {
}
}
if (path) {
- const defs = element.firstChild;
- const pathElement = defs.firstChild;
+ const defs = element.firstElementChild;
+ const pathElement = defs.firstElementChild;
this.#updateProperties(pathElement, path);
}
}
diff --git a/toolkit/components/pdfjs/content/build/pdf.scripting.mjs b/toolkit/components/pdfjs/content/build/pdf.scripting.mjs
@@ -21,8 +21,8 @@
*/
/**
- * pdfjsVersion = 5.4.402
- * pdfjsBuild = 57334bd20
+ * pdfjsVersion = 5.4.445
+ * pdfjsBuild = ec5330f78
*/
var __webpack_exports__ = {};
diff --git a/toolkit/components/pdfjs/content/build/pdf.worker.mjs b/toolkit/components/pdfjs/content/build/pdf.worker.mjs
@@ -21,8 +21,8 @@
*/
/**
- * pdfjsVersion = 5.4.402
- * pdfjsBuild = 57334bd20
+ * pdfjsVersion = 5.4.445
+ * pdfjsBuild = ec5330f78
*/
/******/ // The require scope
/******/ var __webpack_require__ = {};
@@ -1210,6 +1210,11 @@ class RefSetCache {
yield [Ref.fromString(ref), value];
}
}
+ *keys() {
+ for (const ref of this._map.keys()) {
+ yield Ref.fromString(ref);
+ }
+ }
}
function isName(v, name) {
return v instanceof Name && (name === undefined || v.name === name);
@@ -36343,7 +36348,7 @@ class NameOrNumberTree {
this.xref = xref;
this._type = type;
}
- getAll() {
+ getAll(isRaw = false) {
const map = new Map();
if (!this.root) {
return map;
@@ -36376,7 +36381,7 @@ class NameOrNumberTree {
continue;
}
for (let i = 0, ii = entries.length; i < ii; i += 2) {
- map.set(xref.fetchIfRef(entries[i]), xref.fetchIfRef(entries[i + 1]));
+ map.set(xref.fetchIfRef(entries[i]), isRaw ? entries[i + 1] : xref.fetchIfRef(entries[i + 1]));
}
}
return map;
@@ -38084,6 +38089,9 @@ class Catalog {
}
return markInfo;
}
+ get hasStructTree() {
+ return this.#catDict.has("StructTreeRoot");
+ }
get structTreeRoot() {
let structTree = null;
try {
@@ -44754,7 +44762,7 @@ class Occur extends XFAObject {
}) : "";
this.max = attributes.max !== "" ? getInteger({
data: attributes.max,
- defaultValue: 1,
+ defaultValue: -1,
validate: x => true
}) : "";
this.min = attributes.min !== "" ? getInteger({
@@ -58282,6 +58290,7 @@ async function incrementalUpdate({
+
const MAX_LEAVES_PER_PAGES_NODE = 16;
const MAX_IN_NAME_TREE_NODE = 64;
class PageData {
@@ -58289,15 +58298,38 @@ class PageData {
this.page = page;
this.documentData = documentData;
this.annotations = null;
+ this.pointingNamedDestinations = null;
documentData.pagesMap.put(page.ref, this);
}
}
class DocumentData {
constructor(document) {
this.document = document;
+ this.destinations = null;
this.pageLabels = null;
this.pagesMap = new RefSetCache();
this.oldRefMapping = new RefSetCache();
+ this.dedupNamedDestinations = new Map();
+ this.usedNamedDestinations = new Set();
+ this.postponedRefCopies = new RefSetCache();
+ this.usedStructParents = new Set();
+ this.oldStructParentMapping = new Map();
+ this.structTreeRoot = null;
+ this.parentTree = null;
+ this.idTree = null;
+ this.roleMap = null;
+ this.classMap = null;
+ this.namespaces = null;
+ this.structTreeAF = null;
+ this.structTreePronunciationLexicon = [];
+ }
+}
+class XRefWrapper {
+ constructor(entries) {
+ this.entries = entries;
+ }
+ fetch(ref) {
+ return ref instanceof Ref ? this.entries[ref.num] : ref;
}
}
class PDFEditor {
@@ -58311,6 +58343,7 @@ class PDFEditor {
this.oldPages = [];
this.newPages = [];
this.xref = [null];
+ this.xrefWrapper = new XRefWrapper(this.xref);
this.newRefCount = 1;
[this.rootRef, this.rootDict] = this.newDict;
[this.infoRef, this.infoDict] = this.newDict;
@@ -58322,6 +58355,15 @@ class PDFEditor {
this.title = title;
this.author = author;
this.pageLabels = null;
+ this.namedDestinations = new Map();
+ this.parentTree = new Map();
+ this.structTreeKids = [];
+ this.idTree = new Map();
+ this.classMap = new Dict();
+ this.roleMap = new Dict();
+ this.namespaces = new Map();
+ this.structTreeAF = [];
+ this.structTreePronunciationLexicon = [];
}
get newRef() {
const ref = Ref.get(this.newRefCount++, 0);
@@ -58337,6 +58379,11 @@ class PDFEditor {
this.xref[ref.num] = await this.#collectDependencies(obj, true, xref);
return ref;
}
+ cloneDict(dict) {
+ const newDict = dict.clone();
+ newDict.xref = this.xrefWrapper;
+ return newDict;
+ }
async #collectDependencies(obj, mustClone, xref) {
if (obj instanceof Ref) {
const {
@@ -58348,18 +58395,32 @@ class PDFEditor {
if (newRef) {
return newRef;
}
+ const oldRef = obj;
+ obj = await xref.fetchAsync(oldRef);
+ if (typeof obj === "number") {
+ return obj;
+ }
newRef = this.newRef;
- oldRefMapping.put(obj, newRef);
- obj = await xref.fetchAsync(obj);
+ oldRefMapping.put(oldRef, newRef);
this.xref[newRef.num] = await this.#collectDependencies(obj, true, xref);
return newRef;
}
const promises = [];
+ const {
+ currentDocument: {
+ postponedRefCopies
+ }
+ } = this;
if (Array.isArray(obj)) {
if (mustClone) {
obj = obj.slice();
}
for (let i = 0, ii = obj.length; i < ii; i++) {
+ const postponedActions = postponedRefCopies.get(obj[i]);
+ if (postponedActions) {
+ postponedActions.push(ref => obj[i] = ref);
+ continue;
+ }
promises.push(this.#collectDependencies(obj[i], true, xref).then(newObj => obj[i] = newObj));
}
await Promise.all(promises);
@@ -58370,24 +58431,214 @@ class PDFEditor {
({
dict
} = obj = obj.getOriginalStream().clone());
+ dict.xref = this.xrefWrapper;
} else if (obj instanceof Dict) {
if (mustClone) {
obj = obj.clone();
+ obj.xref = this.xrefWrapper;
}
dict = obj;
}
if (dict) {
for (const [key, rawObj] of dict.getRawEntries()) {
+ const postponedActions = postponedRefCopies.get(rawObj);
+ if (postponedActions) {
+ postponedActions.push(ref => dict.set(key, ref));
+ continue;
+ }
promises.push(this.#collectDependencies(rawObj, true, xref).then(newObj => dict.set(key, newObj)));
}
await Promise.all(promises);
}
return obj;
}
+ async #cloneStructTreeNode(parentStructRef, node, xref, removedStructElements, dedupIDs, dedupClasses, dedupRoles, visited = new RefSet()) {
+ const {
+ currentDocument: {
+ pagesMap,
+ oldRefMapping
+ }
+ } = this;
+ const pg = node.getRaw("Pg");
+ if (pg instanceof Ref && !pagesMap.has(pg)) {
+ return null;
+ }
+ let kids;
+ const k = kids = node.getRaw("K");
+ if (k instanceof Ref) {
+ if (visited.has(k)) {
+ return null;
+ }
+ kids = await xref.fetchAsync(k);
+ if (!Array.isArray(kids)) {
+ kids = [k];
+ }
+ }
+ kids = Array.isArray(kids) ? kids : [kids];
+ const newKids = [];
+ const structElemIndices = [];
+ for (let kid of kids) {
+ const kidRef = kid instanceof Ref ? kid : null;
+ if (kidRef) {
+ if (visited.has(kidRef)) {
+ continue;
+ }
+ visited.put(kidRef);
+ kid = await xref.fetchAsync(kidRef);
+ }
+ if (typeof kid === "number") {
+ newKids.push(kid);
+ continue;
+ }
+ if (!(kid instanceof Dict)) {
+ continue;
+ }
+ const pgRef = kid.getRaw("Pg");
+ if (pgRef instanceof Ref && !pagesMap.has(pgRef)) {
+ continue;
+ }
+ const type = kid.get("Type");
+ if (!type || isName(type, "StructElem")) {
+ let setAsSpan = false;
+ if (kidRef && removedStructElements.has(kidRef)) {
+ if (!isName(kid.get("S"), "Link")) {
+ continue;
+ }
+ setAsSpan = true;
+ }
+ const newKidRef = await this.#cloneStructTreeNode(kidRef, kid, xref, removedStructElements, dedupIDs, dedupClasses, dedupRoles, visited);
+ if (newKidRef) {
+ structElemIndices.push(newKids.length);
+ newKids.push(newKidRef);
+ if (kidRef) {
+ oldRefMapping.put(kidRef, newKidRef);
+ }
+ if (setAsSpan) {
+ this.xref[newKidRef.num].setIfName("S", "Span");
+ }
+ }
+ continue;
+ }
+ if (isName(type, "OBJR")) {
+ if (!kidRef) {
+ continue;
+ }
+ const newKidRef = oldRefMapping.get(kidRef);
+ if (!newKidRef) {
+ continue;
+ }
+ const newKid = this.xref[newKidRef.num];
+ const objRef = newKid.getRaw("Obj");
+ if (objRef instanceof Ref) {
+ const obj = this.xref[objRef.num];
+ if (obj instanceof Dict && !obj.has("StructParent") && parentStructRef) {
+ const structParent = this.parentTree.size;
+ this.parentTree.set(structParent, [oldRefMapping, parentStructRef]);
+ obj.set("StructParent", structParent);
+ }
+ }
+ newKids.push(newKidRef);
+ continue;
+ }
+ if (isName(type, "MCR")) {
+ const newKid = await this.#collectDependencies(kidRef || kid, true, xref);
+ newKids.push(newKid);
+ continue;
+ }
+ if (kidRef) {
+ const newKidRef = await this.#collectDependencies(kidRef, true, xref);
+ newKids.push(newKidRef);
+ }
+ }
+ if (kids.length !== 0 && newKids.length === 0) {
+ return null;
+ }
+ const newNodeRef = this.newRef;
+ const newNode = this.xref[newNodeRef.num] = this.cloneDict(node);
+ newNode.delete("ID");
+ newNode.delete("C");
+ newNode.delete("K");
+ newNode.delete("P");
+ newNode.delete("S");
+ await this.#collectDependencies(newNode, false, xref);
+ const classNames = node.get("C");
+ if (classNames instanceof Name) {
+ const newClassName = dedupClasses.get(classNames.name);
+ if (newClassName) {
+ newNode.set("C", Name.get(newClassName));
+ } else {
+ newNode.set("C", classNames);
+ }
+ } else if (Array.isArray(classNames)) {
+ const newClassNames = [];
+ for (const className of classNames) {
+ if (className instanceof Name) {
+ const newClassName = dedupClasses.get(className.name);
+ if (newClassName) {
+ newClassNames.push(Name.get(newClassName));
+ } else {
+ newClassNames.push(className);
+ }
+ }
+ }
+ newNode.set("C", newClassNames);
+ }
+ const roleName = node.get("S");
+ if (roleName instanceof Name) {
+ const newRoleName = dedupRoles.get(roleName.name);
+ if (newRoleName) {
+ newNode.set("S", Name.get(newRoleName));
+ } else {
+ newNode.set("S", roleName);
+ }
+ }
+ const id = node.get("ID");
+ if (typeof id === "string") {
+ const stringId = stringToPDFString(id, false);
+ const newId = dedupIDs.get(stringId);
+ if (newId) {
+ newNode.set("ID", stringToAsciiOrUTF16BE(newId));
+ } else {
+ newNode.set("ID", id);
+ }
+ }
+ let attributes = newNode.get("A");
+ if (attributes) {
+ if (!Array.isArray(attributes)) {
+ attributes = [attributes];
+ }
+ for (let attr of attributes) {
+ attr = this.xrefWrapper.fetch(attr);
+ if (isName(attr.get("O"), "Table") && attr.has("Headers")) {
+ const headers = this.xrefWrapper.fetch(attr.getRaw("Headers"));
+ if (Array.isArray(headers)) {
+ for (let i = 0, ii = headers.length; i < ii; i++) {
+ const newId = dedupIDs.get(stringToPDFString(headers[i], false));
+ if (newId) {
+ headers[i] = newId;
+ }
+ }
+ }
+ }
+ }
+ }
+ for (const index of structElemIndices) {
+ const structElemRef = newKids[index];
+ const structElem = this.xref[structElemRef.num];
+ structElem.set("P", newNodeRef);
+ }
+ if (newKids.length === 1) {
+ newNode.set("K", newKids[0]);
+ } else if (newKids.length > 1) {
+ newNode.set("K", newKids);
+ }
+ return newNodeRef;
+ }
async extractPages(pageInfos) {
const promises = [];
let newIndex = 0;
this.hasSingleFile = pageInfos.length === 1;
+ const allDocumentData = [];
for (const {
document,
includePages,
@@ -58397,6 +58648,7 @@ class PDFEditor {
continue;
}
const documentData = new DocumentData(document);
+ allDocumentData.push(documentData);
promises.push(this.#collectDocumentData(documentData));
let keptIndices, keptRanges, deletedIndices, deletedRanges;
for (const page of includePages || []) {
@@ -58455,27 +58707,63 @@ class PDFEditor {
}
await Promise.all(promises);
promises.length = 0;
+ this.#collectValidDestinations(allDocumentData);
this.#collectPageLabels();
for (const page of this.oldPages) {
promises.push(this.#postCollectPageData(page));
}
await Promise.all(promises);
+ this.#findDuplicateNamedDestinations();
+ this.#setPostponedRefCopies(allDocumentData);
for (let i = 0, ii = this.oldPages.length; i < ii; i++) {
this.newPages[i] = await this.#makePageCopy(i, null);
}
+ this.#fixPostponedRefCopies(allDocumentData);
+ await this.#mergeStructTrees(allDocumentData);
return this.writePDF();
}
async #collectDocumentData(documentData) {
const {
- document
+ document: {
+ pdfManager,
+ xref
+ }
} = documentData;
- await document.pdfManager.ensureCatalog("rawPageLabels").then(pageLabels => documentData.pageLabels = pageLabels);
+ await Promise.all([pdfManager.ensureCatalog("destinations").then(destinations => documentData.destinations = destinations), pdfManager.ensureCatalog("rawPageLabels").then(pageLabels => documentData.pageLabels = pageLabels), pdfManager.ensureCatalog("structTreeRoot").then(structTreeRoot => documentData.structTreeRoot = structTreeRoot)]);
+ const structTreeRoot = documentData.structTreeRoot;
+ if (structTreeRoot) {
+ const rootDict = structTreeRoot.dict;
+ const parentTree = rootDict.get("ParentTree");
+ if (parentTree) {
+ const numberTree = new NumberTree(parentTree, xref);
+ documentData.parentTree = numberTree.getAll(true);
+ }
+ const idTree = rootDict.get("IDTree");
+ if (idTree) {
+ const nameTree = new NameTree(idTree, xref);
+ documentData.idTree = nameTree.getAll(true);
+ }
+ documentData.roleMap = rootDict.get("RoleMap") || null;
+ documentData.classMap = rootDict.get("ClassMap") || null;
+ let namespaces = rootDict.get("Namespaces") || null;
+ if (namespaces && !Array.isArray(namespaces)) {
+ namespaces = [namespaces];
+ }
+ documentData.namespaces = namespaces;
+ documentData.structTreeAF = rootDict.get("AF") || null;
+ documentData.structTreePronunciationLexicon = rootDict.get("PronunciationLexicon") || null;
+ }
}
async #postCollectPageData(pageData) {
const {
page: {
xref,
annotations
+ },
+ documentData: {
+ pagesMap,
+ destinations,
+ usedNamedDestinations
}
} = pageData;
if (!annotations) {
@@ -58489,6 +58777,18 @@ class PDFEditor {
promises.push(xref.fetchIfRefAsync(annotationRef).then(async annotationDict => {
if (!isName(annotationDict.get("Subtype"), "Link")) {
newAnnotations[newAnnotationIndex] = annotationRef;
+ return;
+ }
+ const action = annotationDict.get("A");
+ const dest = action instanceof Dict ? action.get("D") : annotationDict.get("Dest");
+ if (!dest || Array.isArray(dest) && (!(dest[0] instanceof Ref) || pagesMap.has(dest[0]))) {
+ newAnnotations[newAnnotationIndex] = annotationRef;
+ } else if (typeof dest === "string") {
+ const destString = stringToPDFString(dest, true);
+ if (destinations.has(destString)) {
+ newAnnotations[newAnnotationIndex] = annotationRef;
+ usedNamedDestinations.add(destString);
+ }
}
}));
}
@@ -58496,6 +58796,358 @@ class PDFEditor {
newAnnotations = newAnnotations.filter(annot => !!annot);
pageData.annotations = newAnnotations.length > 0 ? newAnnotations : null;
}
+ #setPostponedRefCopies(allDocumentData) {
+ for (const {
+ postponedRefCopies,
+ pagesMap
+ } of allDocumentData) {
+ for (const oldPageRef of pagesMap.keys()) {
+ postponedRefCopies.put(oldPageRef, []);
+ }
+ }
+ }
+ #fixPostponedRefCopies(allDocumentData) {
+ for (const {
+ postponedRefCopies,
+ oldRefMapping
+ } of allDocumentData) {
+ for (const [oldRef, actions] of postponedRefCopies.items()) {
+ const newRef = oldRefMapping.get(oldRef);
+ for (const action of actions) {
+ action(newRef);
+ }
+ }
+ postponedRefCopies.clear();
+ }
+ }
+ #visitObject(obj, callback, visited = new RefSet()) {
+ if (obj instanceof Ref) {
+ if (!visited.has(obj)) {
+ visited.put(obj);
+ this.#visitObject(this.xref[obj.num], callback, visited);
+ }
+ return;
+ }
+ if (Array.isArray(obj)) {
+ for (const item of obj) {
+ this.#visitObject(item, callback, visited);
+ }
+ return;
+ }
+ let dict;
+ if (obj instanceof BaseStream) {
+ ({
+ dict
+ } = obj);
+ } else if (obj instanceof Dict) {
+ dict = obj;
+ }
+ if (dict) {
+ callback(dict);
+ for (const value of dict.getRawValues()) {
+ this.#visitObject(value, callback, visited);
+ }
+ }
+ }
+ async #mergeStructTrees(allDocumentData) {
+ let newStructParentId = 0;
+ const {
+ parentTree: newParentTree
+ } = this;
+ for (let i = 0, ii = this.newPages.length; i < ii; i++) {
+ const {
+ documentData: {
+ parentTree,
+ oldRefMapping,
+ oldStructParentMapping,
+ usedStructParents,
+ document: {
+ xref
+ }
+ }
+ } = this.oldPages[i];
+ if (!parentTree) {
+ continue;
+ }
+ const pageRef = this.newPages[i];
+ const pageDict = this.xref[pageRef.num];
+ this.#visitObject(pageDict, dict => {
+ const structParent = dict.get("StructParent") ?? dict.get("StructParents");
+ if (typeof structParent !== "number") {
+ return;
+ }
+ usedStructParents.add(structParent);
+ let parent = parentTree.get(structParent);
+ const parentRef = parent instanceof Ref ? parent : null;
+ if (parentRef) {
+ const array = xref.fetch(parentRef);
+ if (Array.isArray(array)) {
+ parent = array;
+ }
+ }
+ if (Array.isArray(parent) && parent.every(ref => ref === null)) {
+ parent = null;
+ }
+ if (!parent) {
+ if (dict.has("StructParent")) {
+ dict.delete("StructParent");
+ } else {
+ dict.delete("StructParents");
+ }
+ return;
+ }
+ let newStructParent = oldStructParentMapping.get(structParent);
+ if (newStructParent === undefined) {
+ newStructParent = newStructParentId++;
+ oldStructParentMapping.set(structParent, newStructParent);
+ newParentTree.set(newStructParent, [oldRefMapping, parent]);
+ }
+ if (dict.has("StructParent")) {
+ dict.set("StructParent", newStructParent);
+ } else {
+ dict.set("StructParents", newStructParent);
+ }
+ });
+ }
+ const {
+ structTreeKids,
+ idTree: newIdTree,
+ classMap: newClassMap,
+ roleMap: newRoleMap,
+ namespaces: newNamespaces,
+ structTreeAF: newStructTreeAF,
+ structTreePronunciationLexicon: newStructTreePronunciationLexicon
+ } = this;
+ for (const documentData of allDocumentData) {
+ const {
+ document: {
+ xref
+ },
+ oldRefMapping,
+ parentTree,
+ usedStructParents,
+ structTreeRoot,
+ idTree,
+ classMap,
+ roleMap,
+ namespaces,
+ structTreeAF,
+ structTreePronunciationLexicon
+ } = documentData;
+ if (!structTreeRoot) {
+ continue;
+ }
+ this.currentDocument = documentData;
+ const removedStructElements = new RefSet();
+ for (const [key, value] of parentTree || []) {
+ if (!usedStructParents.has(key) && value instanceof Ref) {
+ removedStructElements.put(value);
+ }
+ }
+ const dedupIDs = new Map();
+ for (const [id, nodeRef] of idTree || []) {
+ let _id = id;
+ if (newIdTree.has(id)) {
+ for (let i = 1;; i++) {
+ const newId = `${id}_${i}`;
+ if (!newIdTree.has(newId)) {
+ dedupIDs.set(id, newId);
+ _id = newId;
+ break;
+ }
+ }
+ }
+ newIdTree.set(_id, nodeRef);
+ }
+ const dedupClasses = new Map();
+ if (classMap?.size > 0) {
+ for (let [className, classDict] of classMap) {
+ classDict = await this.#collectDependencies(classDict, true, xref);
+ if (newClassMap.has(className)) {
+ for (let i = 1;; i++) {
+ const newClassName = `${className}_${i}`;
+ if (!newClassMap.has(newClassName)) {
+ dedupClasses.set(className, newClassName);
+ className = newClassName;
+ break;
+ }
+ }
+ }
+ newClassMap.set(className, classDict);
+ }
+ }
+ const dedupRoles = new Map();
+ if (roleMap?.size > 0) {
+ for (const [roleName, mappedName] of roleMap) {
+ const newMappedName = newRoleMap.get(roleName);
+ if (!newMappedName) {
+ newRoleMap.set(roleName, mappedName);
+ continue;
+ }
+ if (newMappedName === mappedName) {
+ continue;
+ }
+ for (let i = 1;; i++) {
+ const newRoleName = `${roleName}_${i}`;
+ if (!newRoleMap.has(newRoleName)) {
+ dedupRoles.set(roleName, newRoleName);
+ newRoleMap.set(newRoleName, mappedName);
+ break;
+ }
+ }
+ }
+ }
+ if (namespaces?.length > 0) {
+ for (const namespaceRef of namespaces) {
+ const namespace = await xref.fetchIfRefAsync(namespaceRef);
+ let ns = namespace.get("NS");
+ if (!ns || newNamespaces.has(ns)) {
+ continue;
+ }
+ ns = stringToPDFString(ns, false);
+ const newNamespace = await this.#collectDependencies(namespace, true, xref);
+ newNamespaces.set(ns, newNamespace);
+ }
+ }
+ if (structTreeAF) {
+ for (const afRef of structTreeAF) {
+ newStructTreeAF.push(await this.#collectDependencies(afRef, true, xref));
+ }
+ }
+ if (structTreePronunciationLexicon) {
+ for (const lexiconRef of structTreePronunciationLexicon) {
+ newStructTreePronunciationLexicon.push(await this.#collectDependencies(lexiconRef, true, xref));
+ }
+ }
+ let kids = structTreeRoot.dict.get("K");
+ if (!kids) {
+ continue;
+ }
+ kids = Array.isArray(kids) ? kids : [kids];
+ for (let kid of kids) {
+ const kidRef = kid instanceof Ref ? kid : null;
+ if (kidRef && removedStructElements.has(kidRef)) {
+ continue;
+ }
+ kid = await xref.fetchIfRefAsync(kid);
+ const newKidRef = await this.#cloneStructTreeNode(kidRef, kid, xref, removedStructElements, dedupIDs, dedupClasses, dedupRoles);
+ if (newKidRef) {
+ structTreeKids.push(newKidRef);
+ }
+ }
+ for (const [id, nodeRef] of idTree || []) {
+ const newNodeRef = oldRefMapping.get(nodeRef);
+ const newId = dedupIDs.get(id) || id;
+ if (newNodeRef) {
+ newIdTree.set(newId, newNodeRef);
+ } else {
+ newIdTree.delete(newId);
+ }
+ }
+ }
+ for (const [key, [oldRefMapping, parent]] of newParentTree) {
+ if (!parent) {
+ newParentTree.delete(key);
+ continue;
+ }
+ if (!Array.isArray(parent)) {
+ const newParent = oldRefMapping.get(parent);
+ if (newParent === undefined) {
+ newParentTree.delete(key);
+ } else {
+ newParentTree.set(key, newParent);
+ }
+ continue;
+ }
+ const newParents = parent.map(ref => ref instanceof Ref && oldRefMapping.get(ref) || null);
+ if (newParents.length === 0 || newParents.every(ref => ref === null)) {
+ newParentTree.delete(key);
+ continue;
+ }
+ newParentTree.set(key, newParents);
+ }
+ this.currentDocument = null;
+ }
+ #collectValidDestinations(allDocumentData) {
+ for (const documentData of allDocumentData) {
+ if (!documentData.destinations) {
+ continue;
+ }
+ const {
+ destinations,
+ pagesMap
+ } = documentData;
+ const newDestinations = documentData.destinations = new Map();
+ for (const [key, dest] of Object.entries(destinations)) {
+ const pageRef = dest[0];
+ const pageData = pagesMap.get(pageRef);
+ if (!pageData) {
+ continue;
+ }
+ (pageData.pointingNamedDestinations ||= new Set()).add(key);
+ newDestinations.set(key, dest);
+ }
+ }
+ }
+ #findDuplicateNamedDestinations() {
+ const {
+ namedDestinations
+ } = this;
+ for (let i = 0, ii = this.oldPages.length; i < ii; i++) {
+ const page = this.oldPages[i];
+ const {
+ documentData: {
+ destinations,
+ dedupNamedDestinations,
+ usedNamedDestinations
+ }
+ } = page;
+ let {
+ pointingNamedDestinations
+ } = page;
+ if (!pointingNamedDestinations) {
+ continue;
+ }
+ page.pointingNamedDestinations = pointingNamedDestinations = pointingNamedDestinations.intersection(usedNamedDestinations);
+ for (const pointingDest of pointingNamedDestinations) {
+ if (!usedNamedDestinations.has(pointingDest)) {
+ continue;
+ }
+ const dest = destinations.get(pointingDest).slice();
+ if (!namedDestinations.has(pointingDest)) {
+ namedDestinations.set(pointingDest, dest);
+ continue;
+ }
+ const newName = `${pointingDest}_p${i + 1}`;
+ dedupNamedDestinations.set(pointingDest, newName);
+ namedDestinations.set(newName, dest);
+ }
+ }
+ }
+ #fixNamedDestinations(annotations, dedupNamedDestinations) {
+ if (dedupNamedDestinations.size === 0) {
+ return;
+ }
+ const fixDestination = (dict, key, dest) => {
+ if (typeof dest === "string") {
+ dict.set(key, dedupNamedDestinations.get(stringToPDFString(dest, true)) || dest);
+ }
+ };
+ for (const annotRef of annotations) {
+ const annotDict = this.xref[annotRef.num];
+ if (!isName(annotDict.get("Subtype"), "Link")) {
+ continue;
+ }
+ const action = annotDict.get("A");
+ if (action instanceof Dict && action.has("D")) {
+ const dest = action.get("D");
+ fixDestination(action, "D", dest);
+ continue;
+ }
+ const dest = annotDict.get("Dest");
+ fixDestination(annotDict, "Dest", dest);
+ }
+ }
async #collectPageLabels() {
if (!this.hasSingleFile) {
return;
@@ -58529,7 +59181,7 @@ class PDFEditor {
}
if (stFirstIndex !== -1) {
const st = currentLabel.get("St");
- currentLabel = currentLabel.clone();
+ currentLabel = this.cloneDict(currentLabel);
currentLabel.set("St", st + (i - stFirstIndex));
stFirstIndex = -1;
}
@@ -58552,10 +59204,12 @@ class PDFEditor {
const {
page,
documentData,
- annotations
+ annotations,
+ pointingNamedDestinations
} = this.oldPages[pageIndex];
this.currentDocument = documentData;
const {
+ dedupNamedDestinations,
oldRefMapping
} = documentData;
const {
@@ -58566,8 +59220,15 @@ class PDFEditor {
ref: oldPageRef
} = page;
const pageRef = this.newRef;
- const pageDict = this.xref[pageRef.num] = page.pageDict.clone();
+ const pageDict = this.xref[pageRef.num] = this.cloneDict(page.pageDict);
oldRefMapping.put(oldPageRef, pageRef);
+ if (pointingNamedDestinations) {
+ for (const pointingDest of pointingNamedDestinations) {
+ const name = dedupNamedDestinations.get(pointingDest) || pointingDest;
+ const dest = this.namedDestinations.get(name);
+ dest[0] = pageRef;
+ }
+ }
for (const key of ["Rotate", "MediaBox", "CropBox", "BleedBox", "TrimBox", "ArtBox", "Resources", "Annots", "Parent", "UserUnit"]) {
pageDict.delete(key);
}
@@ -58586,7 +59247,11 @@ class PDFEditor {
pageDict.set("UserUnit", userUnit);
}
pageDict.setIfDict("Resources", await this.#collectDependencies(resources, true, xref));
- pageDict.setIfArray("Annots", await this.#collectDependencies(annotations, true, xref));
+ if (annotations) {
+ const newAnnotations = await this.#collectDependencies(annotations, true, xref);
+ this.#fixNamedDestinations(newAnnotations, dedupNamedDestinations);
+ pageDict.setIfArray("Annots", newAnnotations);
+ }
if (this.useObjectStreams) {
const newLastRef = this.newRefCount;
const pageObjectRefs = [];
@@ -58707,14 +59372,90 @@ class PDFEditor {
const pageLabelsRef = this.#makeNameNumTree(this.pageLabels, false);
rootDict.set("PageLabels", pageLabelsRef);
}
+ #makeDestinationsTree() {
+ const {
+ namedDestinations
+ } = this;
+ if (namedDestinations.size === 0) {
+ return;
+ }
+ if (!this.namesDict) {
+ [this.namesRef, this.namesDict] = this.newDict;
+ this.rootDict.set("Names", this.namesRef);
+ }
+ this.namesDict.set("Dests", this.#makeNameNumTree(Array.from(namedDestinations.entries()), true));
+ }
+ #makeStructTree() {
+ const {
+ structTreeKids
+ } = this;
+ if (!structTreeKids || structTreeKids.length === 0) {
+ return;
+ }
+ const {
+ rootDict
+ } = this;
+ const structTreeRef = this.newRef;
+ const structTree = this.xref[structTreeRef.num] = new Dict();
+ structTree.setIfName("Type", "StructTreeRoot");
+ structTree.setIfArray("K", structTreeKids);
+ for (const kidRef of structTreeKids) {
+ const kid = this.xref[kidRef.num];
+ const type = kid.get("Type");
+ if (!type || isName(type, "StructElem")) {
+ kid.set("P", structTreeRef);
+ }
+ }
+ if (this.parentTree.size > 0) {
+ const parentTreeRef = this.#makeNameNumTree(Array.from(this.parentTree.entries()), false);
+ const parentTree = this.xref[parentTreeRef.num];
+ parentTree.setIfName("Type", "ParentTree");
+ structTree.set("ParentTree", parentTreeRef);
+ structTree.set("ParentTreeNextKey", this.parentTree.size);
+ }
+ if (this.idTree.size > 0) {
+ const idTreeRef = this.#makeNameNumTree(Array.from(this.idTree.entries()), true);
+ const idTree = this.xref[idTreeRef.num];
+ idTree.setIfName("Type", "IDTree");
+ structTree.set("IDTree", idTreeRef);
+ }
+ if (this.classMap.size > 0) {
+ const classMapRef = this.newRef;
+ this.xref[classMapRef.num] = this.classMap;
+ structTree.set("ClassMap", classMapRef);
+ }
+ if (this.roleMap.size > 0) {
+ const roleMapRef = this.newRef;
+ this.xref[roleMapRef.num] = this.roleMap;
+ structTree.set("RoleMap", roleMapRef);
+ }
+ if (this.namespaces.size > 0) {
+ const namespacesRef = this.newRef;
+ this.xref[namespacesRef.num] = Array.from(this.namespaces.values());
+ structTree.set("Namespaces", namespacesRef);
+ }
+ if (this.structTreeAF.length > 0) {
+ const structTreeAFRef = this.newRef;
+ this.xref[structTreeAFRef.num] = this.structTreeAF;
+ structTree.set("AF", structTreeAFRef);
+ }
+ if (this.structTreePronunciationLexicon.length > 0) {
+ const structTreePronunciationLexiconRef = this.newRef;
+ this.xref[structTreePronunciationLexiconRef.num] = this.structTreePronunciationLexicon;
+ structTree.set("PronunciationLexicon", structTreePronunciationLexiconRef);
+ }
+ rootDict.set("StructTreeRoot", structTreeRef);
+ }
async #makeRoot() {
const {
rootDict
} = this;
rootDict.setIfName("Type", "Catalog");
- rootDict.set("Version", this.version);
+ rootDict.setIfName("Version", this.version);
this.#makePageTree();
this.#makePageLabelsTree();
+ this.#makeDestinationsTree();
+ this.#makeStructTree();
}
#makeInfo() {
const infoMap = new Map();
@@ -59016,7 +59757,7 @@ class WorkerMessageHandler {
docId,
apiVersion
} = docParams;
- const workerVersion = "5.4.402";
+ const workerVersion = "5.4.445";
if (apiVersion !== workerVersion) {
throw new Error(`The API version "${apiVersion}" does not match ` + `the Worker version "${workerVersion}".`);
}
@@ -59302,7 +60043,7 @@ class WorkerMessageHandler {
return pdfManager.ensureCatalog("permissions");
});
handler.on("GetMetadata", function (data) {
- return Promise.all([pdfManager.ensureDoc("documentInfo"), pdfManager.ensureCatalog("metadata")]);
+ return Promise.all([pdfManager.ensureDoc("documentInfo"), pdfManager.ensureCatalog("metadata"), pdfManager.ensureCatalog("hasStructTree")]);
});
handler.on("GetMarkInfo", function (data) {
return pdfManager.ensureCatalog("markInfo");
diff --git a/toolkit/components/pdfjs/content/web/viewer-geckoview.css b/toolkit/components/pdfjs/content/web/viewer-geckoview.css
@@ -1407,6 +1407,7 @@
rgb(251 251 254 / 0.1)
);
--sidebar-box-shadow:0 0.25px 0.75px light-dark(rgb(0 0 0 / 0.05), rgb(0 0 0 / 0.2)), 0 2px 6px 0 light-dark(rgb(0 0 0 / 0.1), rgb(0 0 0 / 0.4));
+ --sidebar-backdrop-filter:none;
--sidebar-border-radius:8px;
--sidebar-padding:5px;
--sidebar-min-width:180px;
@@ -1431,6 +1432,7 @@
width:var(--sidebar-width);
min-width:var(--sidebar-min-width);
max-width:var(--sidebar-max-width);
+ backdrop-filter:var(--sidebar-backdrop-filter);
.sidebarResizer{
width:var(--resizer-width);
@@ -1449,6 +1451,10 @@
&:hover{
background-color:var(--resizer-hover-bg-color);
}
+ &:focus-visible{
+ background-color:var(--resizer-hover-bg-color);
+ outline:none;
+ }
}
&.resizing{
diff --git a/toolkit/components/pdfjs/content/web/viewer-geckoview.html b/toolkit/components/pdfjs/content/web/viewer-geckoview.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!doctype html>
<!--
Copyright 2012 Mozilla Foundation
@@ -22,8 +22,8 @@ See https://github.com/adobe-type-tools/cmap-resources
-->
<html dir="ltr" mozdisallowselectionprint>
<head>
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<title>PDF.js viewer</title>
<!-- This snippet is used in the Firefox extension (included from viewer.html) -->
@@ -33,14 +33,11 @@ See https://github.com/adobe-type-tools/cmap-resources
<link rel="localization" href="toolkit/pdfviewer/viewer.ftl"/>
<script src="resource://pdf.js/web/viewer.mjs" type="module"></script>
-
</head>
<body tabindex="0">
<div id="outerContainer">
-
<div id="mainContainer">
-
<div id="floatingToolbar">
<button id="download" class="toolbarButton" type="button" tabindex="0" data-l10n-id="pdfjs-download-button">
<span data-l10n-id="pdfjs-download-button-label"></span>
@@ -50,7 +47,8 @@ See https://github.com/adobe-type-tools/cmap-resources
<div id="viewerContainer" tabindex="0">
<div id="viewer" class="pdfViewer"></div>
</div>
- </div> <!-- mainContainer -->
+ </div>
+ <!-- mainContainer -->
<div id="dialogContainer">
<dialog id="passwordDialog">
@@ -58,16 +56,21 @@ See https://github.com/adobe-type-tools/cmap-resources
<label for="password" id="passwordText" data-l10n-id="pdfjs-password-label"></label>
</div>
<div class="row">
- <input type="password" id="password" class="toolbarField">
+ <input type="password" id="password" class="toolbarField" />
</div>
<div class="buttonRow">
- <button id="passwordCancel" class="dialogButton" type="button"><span data-l10n-id="pdfjs-password-cancel-button"></span></button>
- <button id="passwordSubmit" class="dialogButton" type="button"><span data-l10n-id="pdfjs-password-ok-button"></span></button>
+ <button id="passwordCancel" class="dialogButton" type="button">
+ <span data-l10n-id="pdfjs-password-cancel-button"></span>
+ </button>
+ <button id="passwordSubmit" class="dialogButton" type="button">
+ <span data-l10n-id="pdfjs-password-ok-button"></span>
+ </button>
</div>
</dialog>
- </div> <!-- dialogContainer -->
-
- </div> <!-- outerContainer -->
+ </div>
+ <!-- dialogContainer -->
+ </div>
+ <!-- outerContainer -->
<div id="printContainer"></div>
</body>
</html>
diff --git a/toolkit/components/pdfjs/content/web/viewer-geckoview.mjs b/toolkit/components/pdfjs/content/web/viewer-geckoview.mjs
@@ -21,8 +21,8 @@
*/
/**
- * pdfjsVersion = 5.4.402
- * pdfjsBuild = 57334bd20
+ * pdfjsVersion = 5.4.445
+ * pdfjsBuild = ec5330f78
*/
/******/ // The require scope
/******/ var __webpack_require__ = {};
@@ -2454,9 +2454,129 @@ class CaretBrowsingMode {
}
}
+;// ./web/sidebar.js
+
+class Sidebar {
+ #minWidth = 0;
+ #maxWidth = 0;
+ #initialWidth = 0;
+ #width = 0;
+ #coefficient;
+ #visible = false;
+ constructor({
+ sidebar,
+ resizer,
+ toggleButton
+ }, ltr, isResizerOnTheLeft) {
+ this._sidebar = sidebar;
+ this.#coefficient = ltr === isResizerOnTheLeft ? -1 : 1;
+ const style = window.getComputedStyle(sidebar);
+ this.#minWidth = parseFloat(style.getPropertyValue("--sidebar-min-width"));
+ this.#maxWidth = parseFloat(style.getPropertyValue("--sidebar-max-width"));
+ this.#initialWidth = this.#width = parseFloat(style.getPropertyValue("--sidebar-width"));
+ this.#makeSidebarResizable(resizer, isResizerOnTheLeft);
+ toggleButton.addEventListener("click", this.toggle.bind(this));
+ sidebar.hidden = true;
+ }
+ #makeSidebarResizable(resizer, isResizerOnTheLeft) {
+ resizer.ariaValueMin = this.#minWidth;
+ resizer.ariaValueMax = this.#maxWidth;
+ resizer.ariaValueNow = this.#width;
+ let pointerMoveAC;
+ const cancelResize = () => {
+ this.#width = MathClamp(this.#width, this.#minWidth, this.#maxWidth);
+ this._sidebar.classList.remove("resizing");
+ pointerMoveAC?.abort();
+ pointerMoveAC = null;
+ };
+ resizer.addEventListener("pointerdown", e => {
+ if (pointerMoveAC) {
+ cancelResize();
+ return;
+ }
+ const {
+ clientX
+ } = e;
+ stopEvent(e);
+ let prevX = clientX;
+ pointerMoveAC = new AbortController();
+ const {
+ signal
+ } = pointerMoveAC;
+ const sidebar = this._sidebar;
+ const sidebarStyle = sidebar.style;
+ sidebar.classList.add("resizing");
+ const parentStyle = sidebar.parentElement.style;
+ parentStyle.minWidth = 0;
+ window.addEventListener("contextmenu", noContextMenu, {
+ signal
+ });
+ window.addEventListener("pointermove", ev => {
+ if (!pointerMoveAC) {
+ return;
+ }
+ stopEvent(ev);
+ const {
+ clientX: x
+ } = ev;
+ this.#setNewWidth(x - prevX, parentStyle, resizer, sidebarStyle, isResizerOnTheLeft, false);
+ prevX = x;
+ }, {
+ signal,
+ capture: true
+ });
+ window.addEventListener("blur", cancelResize, {
+ signal
+ });
+ window.addEventListener("pointerup", ev => {
+ if (pointerMoveAC) {
+ cancelResize();
+ stopEvent(ev);
+ }
+ }, {
+ signal
+ });
+ });
+ resizer.addEventListener("keydown", e => {
+ const {
+ key
+ } = e;
+ const isArrowLeft = key === "ArrowLeft";
+ if (isArrowLeft || key === "ArrowRight") {
+ const base = e.ctrlKey || e.metaKey ? 10 : 1;
+ const dx = base * (isArrowLeft ? -1 : 1);
+ this.#setNewWidth(dx, this._sidebar.parentElement.style, resizer, this._sidebar.style, isResizerOnTheLeft, true);
+ stopEvent(e);
+ }
+ });
+ }
+ #setNewWidth(dx, parentStyle, resizer, sidebarStyle, isResizerOnTheLeft, isFromKeyboard) {
+ let newWidth = this.#width + this.#coefficient * dx;
+ if (!isFromKeyboard) {
+ this.#width = newWidth;
+ }
+ if ((newWidth > this.#maxWidth || newWidth < this.#minWidth) && (this.#width === this.#maxWidth || this.#width === this.#minWidth)) {
+ return;
+ }
+ newWidth = MathClamp(newWidth, this.#minWidth, this.#maxWidth);
+ if (isFromKeyboard) {
+ this.#width = newWidth;
+ }
+ resizer.ariaValueNow = Math.round(newWidth);
+ sidebarStyle.width = `${newWidth.toFixed(3)}px`;
+ if (isResizerOnTheLeft) {
+ parentStyle.insetInlineStart = `${(this.#initialWidth - newWidth).toFixed(3)}px`;
+ }
+ }
+ toggle() {
+ this._sidebar.hidden = !(this.#visible = !this.#visible);
+ }
+}
+
;// ./web/comment_manager.js
+
class CommentManager {
#dialog;
#popup;
@@ -2521,12 +2641,11 @@ class CommentManager {
this.#popup.destroy();
}
}
-class CommentSidebar {
+class CommentSidebar extends Sidebar {
#annotations = null;
#eventBus;
#boundCommentClick = this.#commentClick.bind(this);
#boundCommentKeydown = this.#commentKeydown.bind(this);
- #sidebar;
#closeButton;
#commentsList;
#commentCount;
@@ -2538,11 +2657,6 @@ class CommentSidebar {
#elementsToAnnotations = null;
#idsToElements = null;
#uiManager = null;
- #minWidth = 0;
- #maxWidth = 0;
- #initialWidth = 0;
- #width = 0;
- #ltr;
constructor({
learnMoreUrl,
sidebar,
@@ -2553,7 +2667,11 @@ class CommentSidebar {
closeButton,
commentToolbarButton
}, eventBus, linkService, popup, dateFormat, ltr) {
- this.#sidebar = sidebar;
+ super({
+ sidebar,
+ resizer: sidebarResizer,
+ toggleButton: commentToolbarButton
+ }, ltr, true);
this.#sidebarTitle = sidebarTitle;
this.#commentsList = commentsList;
this.#commentCount = commentCount;
@@ -2562,13 +2680,7 @@ class CommentSidebar {
this.#closeButton = closeButton;
this.#popup = popup;
this.#dateFormat = dateFormat;
- this.#ltr = ltr;
this.#eventBus = eventBus;
- const style = window.getComputedStyle(sidebar);
- this.#minWidth = parseFloat(style.getPropertyValue("--sidebar-min-width"));
- this.#maxWidth = parseFloat(style.getPropertyValue("--sidebar-max-width"));
- this.#initialWidth = this.#width = parseFloat(style.getPropertyValue("--sidebar-width"));
- this.#makeSidebarResizable(sidebarResizer);
closeButton.addEventListener("click", () => {
eventBus.dispatch("switchannotationeditormode", {
source: this,
@@ -2586,70 +2698,6 @@ class CommentSidebar {
};
commentToolbarButton.addEventListener("keydown", keyDownCallback);
sidebar.addEventListener("keydown", keyDownCallback);
- this.#sidebar.hidden = true;
- }
- #makeSidebarResizable(resizer) {
- let pointerMoveAC;
- const cancelResize = () => {
- this.#width = MathClamp(this.#width, this.#minWidth, this.#maxWidth);
- this.#sidebar.classList.remove("resizing");
- pointerMoveAC?.abort();
- pointerMoveAC = null;
- };
- resizer.addEventListener("pointerdown", e => {
- if (pointerMoveAC) {
- cancelResize();
- return;
- }
- const {
- clientX
- } = e;
- stopEvent(e);
- let prevX = clientX;
- pointerMoveAC = new AbortController();
- const {
- signal
- } = pointerMoveAC;
- const sign = this.#ltr ? -1 : 1;
- const sidebar = this.#sidebar;
- const sidebarStyle = sidebar.style;
- sidebar.classList.add("resizing");
- const parentStyle = sidebar.parentElement.style;
- parentStyle.minWidth = 0;
- window.addEventListener("contextmenu", noContextMenu, {
- signal
- });
- window.addEventListener("pointermove", ev => {
- if (!pointerMoveAC) {
- return;
- }
- stopEvent(ev);
- const {
- clientX: x
- } = ev;
- const newWidth = this.#width += sign * (x - prevX);
- prevX = x;
- if (newWidth > this.#maxWidth || newWidth < this.#minWidth) {
- return;
- }
- sidebarStyle.width = `${newWidth.toFixed(3)}px`;
- parentStyle.insetInlineStart = `${(this.#initialWidth - newWidth).toFixed(3)}px`;
- }, {
- signal,
- capture: true
- });
- window.addEventListener("blur", cancelResize, {
- signal
- });
- window.addEventListener("pointerup", ev => {
- if (pointerMoveAC) {
- cancelResize();
- stopEvent(ev);
- }
- }, {
- signal
- });
- });
}
setUIManager(uiManager) {
this.#uiManager = uiManager;
@@ -2669,7 +2717,7 @@ class CommentSidebar {
} else {
this.#setCommentsCount();
}
- this.#sidebar.hidden = false;
+ this._sidebar.hidden = false;
this.#eventBus.dispatch("reporttelemetry", {
source: this,
details: {
@@ -2681,7 +2729,7 @@ class CommentSidebar {
});
}
hide() {
- this.#sidebar.hidden = true;
+ this._sidebar.hidden = true;
this.#commentsList.replaceChildren();
this.#elementsToAnnotations = null;
this.#idsToElements = null;
@@ -2704,7 +2752,7 @@ class CommentSidebar {
if (!element) {
return;
}
- this.#sidebar.scrollTop = element.offsetTop - this.#sidebar.offsetTop;
+ this._sidebar.scrollTop = element.offsetTop - this._sidebar.offsetTop;
for (const el of this.#commentsList.children) {
el.classList.toggle("selected", el === element);
}
@@ -2733,8 +2781,8 @@ class CommentSidebar {
if (index >= this.#annotations.length) {
return;
}
- this.#setDate(element.firstChild, modificationDate || creationDate);
- this.#setText(element.lastChild, richText, contentsObj);
+ this.#setDate(element.firstElementChild, modificationDate || creationDate);
+ this.#setText(element.lastElementChild, richText, contentsObj);
this.#annotations.splice(index, 1);
index = binarySearchFirstItem(this.#annotations, a => this.#sortComments(a, annotation) >= 0);
this.#annotations.splice(index, 0, annotation);
@@ -3007,6 +3055,11 @@ class CommentDialog {
textInput.addEventListener("input", () => {
saveButton.disabled = textInput.value === this.#previousText;
});
+ textInput.addEventListener("keydown", e => {
+ if ((e.ctrlKey || e.metaKey) && e.key === "Enter" && !saveButton.disabled) {
+ this.#save();
+ }
+ });
let pointerMoveAC;
const cancelDrag = () => {
dialog.classList.remove("dragging");
@@ -3704,6 +3757,7 @@ class PasswordPrompt {
}
;// ./web/pdf_find_utils.js
+
const CharacterType = {
SPACE: 0,
ALPHA_LETTER: 1,
@@ -3773,7 +3827,7 @@ function getCharacterType(charCode) {
}
let NormalizeWithNFKC;
function getNormalizeWithNFKC() {
- NormalizeWithNFKC ||= ` ¨ª¯²-µ¸-º¼-¾IJ-ijĿ-ŀʼnſDŽ-njDZ-dzʰ-ʸ˘-˝ˠ-ˤʹͺ;΄-΅·ϐ-ϖϰ-ϲϴ-ϵϹևٵ-ٸक़-य़ড়-ঢ়য়ਲ਼ਸ਼ਖ਼-ਜ਼ਫ਼ଡ଼-ଢ଼ำຳໜ-ໝ༌གྷཌྷདྷབྷཛྷཀྵჼᴬ-ᴮᴰ-ᴺᴼ-ᵍᵏ-ᵪᵸᶛ-ᶿẚ-ẛάέήίόύώΆ᾽-῁ΈΉ῍-῏ΐΊ῝-῟ΰΎ῭-`ΌΏ´-῾ - ‑‗․-… ″-‴‶-‷‼‾⁇-⁉⁗ ⁰-ⁱ⁴-₎ₐ-ₜ₨℀-℃℅-ℇ℉-ℓℕ-№ℙ-ℝ℠-™ℤΩℨK-ℭℯ-ℱℳ-ℹ℻-⅀ⅅ-ⅉ⅐-ⅿ↉∬-∭∯-∰〈-〉①-⓪⨌⩴-⩶⫝̸ⱼ-ⱽⵯ⺟⻳⼀-⿕ 〶〸-〺゛-゜ゟヿㄱ-ㆎ㆒-㆟㈀-㈞㈠-㉇㉐-㉾㊀-㏿ꚜ-ꚝꝰꟲ-ꟴꟸ-ꟹꭜ-ꭟꭩ豈-嗀塚晴凞-羽蘒諸逸-都飯-舘並-龎ff-stﬓ-ﬗיִײַ-זּטּ-לּמּנּ-סּףּ-פּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-﷼︐-︙︰-﹄﹇-﹒﹔-﹦﹨-﹫ﹰ-ﹲﹴﹶ-ﻼ!-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ¢-₩`;
+ NormalizeWithNFKC ||= `\xA0¨ª¯²-µ¸-º¼-¾IJ-ijĿ-ŀʼnſDŽ-njDZ-dzʰ-ʸ˘-˝ˠ-ˤʹͺ;΄-΅·ϐ-ϖϰ-ϲϴ-ϵϹևٵ-ٸक़-य़ড়-ঢ়য়ਲ਼ਸ਼ਖ਼-ਜ਼ਫ਼ଡ଼-ଢ଼ำຳໜ-ໝ༌གྷཌྷདྷབྷཛྷཀྵჼᴬ-ᴮᴰ-ᴺᴼ-ᵍᵏ-ᵪᵸᶛ-ᶿẚ-ẛάέήίόύώΆ᾽-῁ΈΉ῍-῏ΐΊ῝-῟ΰΎ῭-`ΌΏ´-῾ - ‑‗․-… ″-‴‶-‷‼‾⁇-⁉⁗ ⁰-ⁱ⁴-₎ₐ-ₜ₨℀-℃℅-ℇ℉-ℓℕ-№ℙ-ℝ℠-™ℤΩℨK-ℭℯ-ℱℳ-ℹ℻-⅀ⅅ-ⅉ⅐-ⅿ↉∬-∭∯-∰〈-〉①-⓪⨌⩴-⩶⫝̸ⱼ-ⱽⵯ⺟⻳⼀-⿕ 〶〸-〺゛-゜ゟヿㄱ-ㆎ㆒-㆟㈀-㈞㈠-㉇㉐-㉾㊀-㏿ꚜ-ꚝꝰ-ꟴꟸ-ꟹꭜ-ꭟꭩ豈-嗀塚晴凞-羽蘒諸逸-都飯-舘並-龎ff-stﬓ-ﬗיִײַ-זּטּ-לּמּנּ-סּףּ-פּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-﷼︐-︙︰-﹄﹇-﹒﹔-﹦﹨-﹫ﹰ-ﹲﹴﹶ-ﻼ!-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ¢-₩`;
return NormalizeWithNFKC;
}
@@ -3805,7 +3859,7 @@ const CHARACTERS_TO_NORMALIZE = {
const DIACRITICS_EXCEPTION = new Set([0x3099, 0x309a, 0x094d, 0x09cd, 0x0a4d, 0x0acd, 0x0b4d, 0x0bcd, 0x0c4d, 0x0ccd, 0x0d3b, 0x0d3c, 0x0d4d, 0x0dca, 0x0e3a, 0x0eba, 0x0f84, 0x1039, 0x103a, 0x1714, 0x1734, 0x17d2, 0x1a60, 0x1b44, 0x1baa, 0x1bab, 0x1bf2, 0x1bf3, 0x2d7f, 0xa806, 0xa82c, 0xa8c4, 0xa953, 0xa9c0, 0xaaf6, 0xabed, 0x0c56, 0x0f71, 0x0f72, 0x0f7a, 0x0f7b, 0x0f7c, 0x0f7d, 0x0f80, 0x0f74]);
let DIACRITICS_EXCEPTION_STR;
const DIACRITICS_REG_EXP = /\p{M}+/gu;
-const SPECIAL_CHARS_REG_EXP = /([.*+?^${}()|[\]\\])|(\p{P})|(\s+)|(\p{M})|(\p{L})/gu;
+const SPECIAL_CHARS_REG_EXP = /([*+^${}()|[\]\\])|(\p{P}+)|(\s+)|(\p{M})|(\p{L})/gu;
const NOT_DIACRITIC_FROM_END_REG_EXP = /([^\p{M}])\p{M}*$/u;
const NOT_DIACRITIC_FROM_START_REG_EXP = /^\p{M}*([^\p{M}])/u;
const SYLLABLES_REG_EXP = /[\uAC00-\uD7AF\uFA6C\uFACF-\uFAD1\uFAD5-\uFAD7]+/g;
@@ -4201,12 +4255,24 @@ class PDFFindController {
matchDiacritics
} = this.#state;
let isUnicode = false;
+ const addExtraWhitespaces = (original, fixed) => {
+ if (original === query) {
+ return fixed;
+ }
+ if (query.startsWith(original)) {
+ return `${fixed}[ ]*`;
+ }
+ if (query.endsWith(original)) {
+ return `[ ]*${fixed}`;
+ }
+ return `[ ]*${fixed}[ ]*`;
+ };
query = query.replaceAll(SPECIAL_CHARS_REG_EXP, (match, p1, p2, p3, p4, p5) => {
if (p1) {
- return `[ ]*\\${p1}[ ]*`;
+ return addExtraWhitespaces(p1, `\\${p1}`);
}
if (p2) {
- return `[ ]*${p2}[ ]*`;
+ return addExtraWhitespaces(p2, p2.replaceAll(/[.?]/g, "\\$&"));
}
if (p3) {
return "[ ]+";
@@ -8300,7 +8366,7 @@ class PDFViewer {
#textLayerMode = TextLayerMode.ENABLE;
#viewerAlert = null;
constructor(options) {
- const viewerVersion = "5.4.402";
+ const viewerVersion = "5.4.445";
if (version !== viewerVersion) {
throw new Error(`The API version "${version}" does not match the Viewer version "${viewerVersion}".`);
}
@@ -11005,11 +11071,16 @@ const PDFViewerApplication = {
info,
metadata,
contentDispositionFilename,
- contentLength
+ contentLength,
+ hasStructTree
} = await pdfDocument.getMetadata();
if (pdfDocument !== this.pdfDocument) {
return;
}
+ this.externalServices.reportTelemetry({
+ type: "taggedPDF",
+ data: hasStructTree
+ });
this.documentInfo = info;
this.metadata = metadata;
this._contentDispositionFilename ??= contentDispositionFilename;
diff --git a/toolkit/components/pdfjs/content/web/viewer.css b/toolkit/components/pdfjs/content/web/viewer.css
@@ -4544,6 +4544,7 @@
rgb(251 251 254 / 0.1)
);
--sidebar-box-shadow:0 0.25px 0.75px light-dark(rgb(0 0 0 / 0.05), rgb(0 0 0 / 0.2)), 0 2px 6px 0 light-dark(rgb(0 0 0 / 0.1), rgb(0 0 0 / 0.4));
+ --sidebar-backdrop-filter:none;
--sidebar-border-radius:8px;
--sidebar-padding:5px;
--sidebar-min-width:180px;
@@ -4568,6 +4569,7 @@
width:var(--sidebar-width);
min-width:var(--sidebar-min-width);
max-width:var(--sidebar-max-width);
+ backdrop-filter:var(--sidebar-backdrop-filter);
.sidebarResizer{
width:var(--resizer-width);
@@ -4586,6 +4588,10 @@
&:hover{
background-color:var(--resizer-hover-bg-color);
}
+ &:focus-visible{
+ background-color:var(--resizer-hover-bg-color);
+ outline:none;
+ }
}
&.resizing{
diff --git a/toolkit/components/pdfjs/content/web/viewer.html b/toolkit/components/pdfjs/content/web/viewer.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!doctype html>
<!--
Copyright 2012 Mozilla Foundation
@@ -22,8 +22,8 @@ See https://github.com/adobe-type-tools/cmap-resources
-->
<html dir="ltr" mozdisallowselectionprint>
<head>
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<title>PDF.js viewer</title>
<!-- This snippet is used in the Firefox extension (included from viewer.html) -->
@@ -43,17 +43,53 @@ See https://github.com/adobe-type-tools/cmap-resources
<div id="toolbarSidebar" class="toolbarHorizontalGroup">
<div id="toolbarSidebarLeft">
<div id="sidebarViewButtons" class="toolbarHorizontalGroup toggled" role="radiogroup">
- <button id="viewThumbnail" class="toolbarButton toggled" type="button" tabindex="0" data-l10n-id="pdfjs-thumbs-button" role="radio" aria-checked="true" aria-controls="thumbnailView">
- <span data-l10n-id="pdfjs-thumbs-button-label"></span>
+ <button
+ id="viewThumbnail"
+ class="toolbarButton toggled"
+ type="button"
+ tabindex="0"
+ data-l10n-id="pdfjs-thumbs-button"
+ role="radio"
+ aria-checked="true"
+ aria-controls="thumbnailView"
+ >
+ <span data-l10n-id="pdfjs-thumbs-button-label"></span>
</button>
- <button id="viewOutline" class="toolbarButton" type="button" tabindex="0" data-l10n-id="pdfjs-document-outline-button" role="radio" aria-checked="false" aria-controls="outlineView">
- <span data-l10n-id="pdfjs-document-outline-button-label"></span>
+ <button
+ id="viewOutline"
+ class="toolbarButton"
+ type="button"
+ tabindex="0"
+ data-l10n-id="pdfjs-document-outline-button"
+ role="radio"
+ aria-checked="false"
+ aria-controls="outlineView"
+ >
+ <span data-l10n-id="pdfjs-document-outline-button-label"></span>
</button>
- <button id="viewAttachments" class="toolbarButton" type="button" tabindex="0" data-l10n-id="pdfjs-attachments-button" role="radio" aria-checked="false" aria-controls="attachmentsView">
- <span data-l10n-id="pdfjs-attachments-button-label"></span>
+ <button
+ id="viewAttachments"
+ class="toolbarButton"
+ type="button"
+ tabindex="0"
+ data-l10n-id="pdfjs-attachments-button"
+ role="radio"
+ aria-checked="false"
+ aria-controls="attachmentsView"
+ >
+ <span data-l10n-id="pdfjs-attachments-button-label"></span>
</button>
- <button id="viewLayers" class="toolbarButton" type="button" tabindex="0" data-l10n-id="pdfjs-layers-button" role="radio" aria-checked="false" aria-controls="layersView">
- <span data-l10n-id="pdfjs-layers-button-label"></span>
+ <button
+ id="viewLayers"
+ class="toolbarButton"
+ type="button"
+ tabindex="0"
+ data-l10n-id="pdfjs-layers-button"
+ role="radio"
+ aria-checked="false"
+ aria-controls="layersView"
+ >
+ <span data-l10n-id="pdfjs-layers-button-label"></span>
</button>
</div>
</div>
@@ -62,42 +98,63 @@ See https://github.com/adobe-type-tools/cmap-resources
<div id="outlineOptionsContainer" class="toolbarHorizontalGroup">
<div class="verticalToolbarSeparator"></div>
- <button id="currentOutlineItem" class="toolbarButton" type="button" disabled="disabled" tabindex="0" data-l10n-id="pdfjs-current-outline-item-button">
+ <button
+ id="currentOutlineItem"
+ class="toolbarButton"
+ type="button"
+ disabled="disabled"
+ tabindex="0"
+ data-l10n-id="pdfjs-current-outline-item-button"
+ >
<span data-l10n-id="pdfjs-current-outline-item-button-label"></span>
</button>
</div>
</div>
</div>
<div id="sidebarContent">
- <div id="thumbnailView">
- </div>
- <div id="outlineView" class="hidden">
- </div>
- <div id="attachmentsView" class="hidden">
- </div>
- <div id="layersView" class="hidden">
- </div>
+ <div id="thumbnailView"></div>
+ <div id="outlineView" class="hidden"></div>
+ <div id="attachmentsView" class="hidden"></div>
+ <div id="layersView" class="hidden"></div>
</div>
<div id="sidebarResizer"></div>
- </div> <!-- sidebarContainer -->
+ </div>
+ <!-- sidebarContainer -->
<div id="mainContainer">
<div class="toolbar">
<div id="toolbarContainer">
<div id="toolbarViewer" class="toolbarHorizontalGroup">
<div id="toolbarViewerLeft" class="toolbarHorizontalGroup">
- <button id="sidebarToggleButton" class="toolbarButton" type="button" tabindex="0" data-l10n-id="pdfjs-toggle-sidebar-button" aria-expanded="false" aria-haspopup="true" aria-controls="sidebarContainer">
+ <button
+ id="sidebarToggleButton"
+ class="toolbarButton"
+ type="button"
+ tabindex="0"
+ data-l10n-id="pdfjs-toggle-sidebar-button"
+ aria-expanded="false"
+ aria-haspopup="true"
+ aria-controls="sidebarContainer"
+ >
<span data-l10n-id="pdfjs-toggle-sidebar-button-label"></span>
</button>
<div class="toolbarButtonSpacer"></div>
<div class="toolbarButtonWithContainer">
- <button id="viewFindButton" class="toolbarButton" type="button" tabindex="0" data-l10n-id="pdfjs-findbar-button" aria-expanded="false" aria-controls="findbar">
+ <button
+ id="viewFindButton"
+ class="toolbarButton"
+ type="button"
+ tabindex="0"
+ data-l10n-id="pdfjs-findbar-button"
+ aria-expanded="false"
+ aria-controls="findbar"
+ >
<span data-l10n-id="pdfjs-findbar-button-label"></span>
</button>
<div class="hidden doorHanger toolbarHorizontalGroup" id="findbar">
<div id="findInputContainer" class="toolbarHorizontalGroup">
<span class="loadingInput end toolbarHorizontalGroup">
- <input id="findInput" class="toolbarField" tabindex="0" data-l10n-id="pdfjs-find-input" aria-invalid="false">
+ <input id="findInput" class="toolbarField" tabindex="0" data-l10n-id="pdfjs-find-input" aria-invalid="false" />
</span>
<div class="toolbarHorizontalGroup">
<button id="findPreviousButton" class="toolbarButton" type="button" tabindex="0" data-l10n-id="pdfjs-find-previous-button">
@@ -135,7 +192,8 @@ See https://github.com/adobe-type-tools/cmap-resources
<span id="findResultsCount" class="toolbarLabel"></span>
<span id="findMsg" class="toolbarLabel"></span>
</div>
- </div> <!-- findbar -->
+ </div>
+ <!-- findbar -->
</div>
<div class="toolbarHorizontalGroup hiddenSmallView">
<button class="toolbarButton" type="button" id="previous" tabindex="0" data-l10n-id="pdfjs-previous-button">
@@ -148,7 +206,16 @@ See https://github.com/adobe-type-tools/cmap-resources
</div>
<div class="toolbarHorizontalGroup">
<span class="loadingInput start toolbarHorizontalGroup">
- <input type="number" id="pageNumber" class="toolbarField" value="1" min="1" tabindex="0" data-l10n-id="pdfjs-page-input" autocomplete="off">
+ <input
+ type="number"
+ id="pageNumber"
+ class="toolbarField"
+ value="1"
+ min="1"
+ tabindex="0"
+ data-l10n-id="pdfjs-page-input"
+ autocomplete="off"
+ />
</span>
<span id="numPages" class="toolbarLabel"></span>
</div>
@@ -169,7 +236,14 @@ See https://github.com/adobe-type-tools/cmap-resources
<option id="pageActualOption" value="page-actual" data-l10n-id="pdfjs-page-scale-actual"></option>
<option id="pageFitOption" value="page-fit" data-l10n-id="pdfjs-page-scale-fit"></option>
<option id="pageWidthOption" value="page-width" data-l10n-id="pdfjs-page-scale-width"></option>
- <option id="customScaleOption" value="custom" disabled="disabled" hidden="true" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 0 }'></option>
+ <option
+ id="customScaleOption"
+ value="custom"
+ disabled="disabled"
+ hidden="true"
+ data-l10n-id="pdfjs-page-scale-percent"
+ data-l10n-args='{ "scale": 0 }'
+ ></option>
<option value="0.5" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 50 }'></option>
<option value="0.75" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 75 }'></option>
<option value="1" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 100 }'></option>
@@ -184,12 +258,22 @@ See https://github.com/adobe-type-tools/cmap-resources
<div id="toolbarViewerRight" class="toolbarHorizontalGroup">
<div id="editorModeButtons" class="toolbarHorizontalGroup">
<div id="editorComment" class="toolbarButtonWithContainer" hidden="true">
- <button id="editorCommentButton" class="toolbarButton" type="button" tabindex="0" disabled="disabled" aria-expanded="false" aria-haspopup="true" aria-controls="editorCommentParamsToolbar" data-l10n-id="pdfjs-editor-comment-button">
+ <button
+ id="editorCommentButton"
+ class="toolbarButton"
+ type="button"
+ tabindex="0"
+ disabled="disabled"
+ aria-expanded="false"
+ aria-haspopup="true"
+ aria-controls="editorCommentParamsToolbar"
+ data-l10n-id="pdfjs-editor-comment-button"
+ >
<span data-l10n-id="pdfjs-editor-comment-button-label"></span>
</button>
<div class="editorParamsToolbar hidden menu" id="editorCommentParamsToolbar">
<div id="editorCommentsSidebar" class="menuContainer comment sidebar" role="landmark" aria-labelledby="editorCommentsSidebarHeader">
- <div id="editorCommentsSidebarResizer" class="sidebarResizer"></div>
+ <div id="editorCommentsSidebarResizer" class="sidebarResizer" role="separator" aria-controls="editorCommentsSidebar" tabindex="0"></div>
<div id="editorCommentsSidebarHeader" role="heading" aria-level="2">
<span class="commentCount">
<span id="editorCommentsSidebarTitle" data-l10n-id="pdfjs-editor-comments-sidebar-title" data-l10n-args='{ "count": 0 }'></span>
@@ -206,19 +290,45 @@ See https://github.com/adobe-type-tools/cmap-resources
</div>
</div>
<div id="editorSignature" class="toolbarButtonWithContainer" hidden="true">
- <button id="editorSignatureButton" class="toolbarButton" type="button" tabindex="0" disabled="disabled" aria-expanded="false" aria-haspopup="true" aria-controls="editorSignatureParamsToolbar" data-l10n-id="pdfjs-editor-signature-button">
+ <button
+ id="editorSignatureButton"
+ class="toolbarButton"
+ type="button"
+ tabindex="0"
+ disabled="disabled"
+ aria-expanded="false"
+ aria-haspopup="true"
+ aria-controls="editorSignatureParamsToolbar"
+ data-l10n-id="pdfjs-editor-signature-button"
+ >
<span data-l10n-id="pdfjs-editor-signature-button-label"></span>
</button>
<div class="editorParamsToolbar hidden doorHangerRight menu" id="editorSignatureParamsToolbar">
<div id="addSignatureDoorHanger" class="menuContainer" role="region" data-l10n-id="pdfjs-editor-add-signature-container">
- <button id="editorSignatureAddSignature" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-editor-signature-add-signature-button">
+ <button
+ id="editorSignatureAddSignature"
+ class="toolbarButton labeled"
+ type="button"
+ tabindex="0"
+ data-l10n-id="pdfjs-editor-signature-add-signature-button"
+ >
<span data-l10n-id="pdfjs-editor-signature-add-signature-button-label" class="editorParamsLabel"></span>
</button>
</div>
</div>
</div>
<div id="editorHighlight" class="toolbarButtonWithContainer">
- <button id="editorHighlightButton" class="toolbarButton" type="button" disabled="disabled" aria-expanded="false" aria-haspopup="true" aria-controls="editorHighlightParamsToolbar" tabindex="0" data-l10n-id="pdfjs-editor-highlight-button">
+ <button
+ id="editorHighlightButton"
+ class="toolbarButton"
+ type="button"
+ disabled="disabled"
+ aria-expanded="false"
+ aria-haspopup="true"
+ aria-controls="editorHighlightParamsToolbar"
+ tabindex="0"
+ data-l10n-id="pdfjs-editor-highlight-button"
+ >
<span data-l10n-id="pdfjs-editor-highlight-button-label"></span>
</button>
<div class="editorParamsToolbar hidden doorHangerRight" id="editorHighlightParamsToolbar">
@@ -227,66 +337,123 @@ See https://github.com/adobe-type-tools/cmap-resources
<span id="highlightColorPickerLabel" class="editorParamsLabel" data-l10n-id="pdfjs-editor-highlight-colorpicker-label"></span>
</div>
<div id="editorHighlightThickness">
- <label for="editorFreeHighlightThickness" class="editorParamsLabel" data-l10n-id="pdfjs-editor-free-highlight-thickness-input"></label>
+ <label
+ for="editorFreeHighlightThickness"
+ class="editorParamsLabel"
+ data-l10n-id="pdfjs-editor-free-highlight-thickness-input"
+ ></label>
<div class="thicknessPicker">
- <input type="range" id="editorFreeHighlightThickness" class="editorParamsSlider" data-l10n-id="pdfjs-editor-free-highlight-thickness-title" value="12" min="8" max="24" step="1" tabindex="0">
+ <input
+ type="range"
+ id="editorFreeHighlightThickness"
+ class="editorParamsSlider"
+ data-l10n-id="pdfjs-editor-free-highlight-thickness-title"
+ value="12"
+ min="8"
+ max="24"
+ step="1"
+ tabindex="0"
+ />
</div>
</div>
<div id="editorHighlightVisibility">
<div class="divider"></div>
<div class="toggler">
<label for="editorHighlightShowAll" class="editorParamsLabel" data-l10n-id="pdfjs-editor-highlight-show-all-button-label"></label>
- <button id="editorHighlightShowAll" class="toggle-button" type="button" data-l10n-id="pdfjs-editor-highlight-show-all-button" aria-pressed="true" tabindex="0"></button>
+ <button
+ id="editorHighlightShowAll"
+ class="toggle-button"
+ type="button"
+ data-l10n-id="pdfjs-editor-highlight-show-all-button"
+ aria-pressed="true"
+ tabindex="0"
+ ></button>
</div>
</div>
</div>
</div>
</div>
<div id="editorFreeText" class="toolbarButtonWithContainer">
- <button id="editorFreeTextButton" class="toolbarButton" type="button" disabled="disabled" aria-expanded="false" aria-haspopup="true" aria-controls="editorFreeTextParamsToolbar" tabindex="0" data-l10n-id="pdfjs-editor-free-text-button">
+ <button
+ id="editorFreeTextButton"
+ class="toolbarButton"
+ type="button"
+ disabled="disabled"
+ aria-expanded="false"
+ aria-haspopup="true"
+ aria-controls="editorFreeTextParamsToolbar"
+ tabindex="0"
+ data-l10n-id="pdfjs-editor-free-text-button"
+ >
<span data-l10n-id="pdfjs-editor-free-text-button-label"></span>
</button>
<div class="editorParamsToolbar hidden doorHangerRight" id="editorFreeTextParamsToolbar">
<div class="editorParamsToolbarContainer">
<div class="editorParamsSetter">
<label for="editorFreeTextColor" class="editorParamsLabel" data-l10n-id="pdfjs-editor-free-text-color-input"></label>
- <input type="color" id="editorFreeTextColor" class="editorParamsColor" tabindex="0">
+ <input type="color" id="editorFreeTextColor" class="editorParamsColor" tabindex="0" />
</div>
<div class="editorParamsSetter">
<label for="editorFreeTextFontSize" class="editorParamsLabel" data-l10n-id="pdfjs-editor-free-text-size-input"></label>
- <input type="range" id="editorFreeTextFontSize" class="editorParamsSlider" value="10" min="5" max="100" step="1" tabindex="0">
+ <input type="range" id="editorFreeTextFontSize" class="editorParamsSlider" value="10" min="5" max="100" step="1" tabindex="0" />
</div>
</div>
</div>
</div>
<div id="editorInk" class="toolbarButtonWithContainer">
- <button id="editorInkButton" class="toolbarButton" type="button" disabled="disabled" aria-expanded="false" aria-haspopup="true" aria-controls="editorInkParamsToolbar" tabindex="0" data-l10n-id="pdfjs-editor-ink-button">
+ <button
+ id="editorInkButton"
+ class="toolbarButton"
+ type="button"
+ disabled="disabled"
+ aria-expanded="false"
+ aria-haspopup="true"
+ aria-controls="editorInkParamsToolbar"
+ tabindex="0"
+ data-l10n-id="pdfjs-editor-ink-button"
+ >
<span data-l10n-id="pdfjs-editor-ink-button-label"></span>
</button>
<div class="editorParamsToolbar hidden doorHangerRight" id="editorInkParamsToolbar">
<div class="editorParamsToolbarContainer">
<div class="editorParamsSetter">
<label for="editorInkColor" class="editorParamsLabel" data-l10n-id="pdfjs-editor-ink-color-input"></label>
- <input type="color" id="editorInkColor" class="editorParamsColor" tabindex="0">
+ <input type="color" id="editorInkColor" class="editorParamsColor" tabindex="0" />
</div>
<div class="editorParamsSetter">
<label for="editorInkThickness" class="editorParamsLabel" data-l10n-id="pdfjs-editor-ink-thickness-input"></label>
- <input type="range" id="editorInkThickness" class="editorParamsSlider" value="1" min="1" max="20" step="1" tabindex="0">
+ <input type="range" id="editorInkThickness" class="editorParamsSlider" value="1" min="1" max="20" step="1" tabindex="0" />
</div>
<div class="editorParamsSetter">
<label for="editorInkOpacity" class="editorParamsLabel" data-l10n-id="pdfjs-editor-ink-opacity-input"></label>
- <input type="range" id="editorInkOpacity" class="editorParamsSlider" value="1" min="0.05" max="1" step="0.05" tabindex="0">
+ <input type="range" id="editorInkOpacity" class="editorParamsSlider" value="1" min="0.05" max="1" step="0.05" tabindex="0" />
</div>
</div>
</div>
</div>
<div id="editorStamp" class="toolbarButtonWithContainer">
- <button id="editorStampButton" class="toolbarButton" type="button" disabled="disabled" aria-expanded="false" aria-haspopup="true" aria-controls="editorStampParamsToolbar" tabindex="0" data-l10n-id="pdfjs-editor-stamp-button">
+ <button
+ id="editorStampButton"
+ class="toolbarButton"
+ type="button"
+ disabled="disabled"
+ aria-expanded="false"
+ aria-haspopup="true"
+ aria-controls="editorStampParamsToolbar"
+ tabindex="0"
+ data-l10n-id="pdfjs-editor-stamp-button"
+ >
<span data-l10n-id="pdfjs-editor-stamp-button-label"></span>
</button>
<div class="editorParamsToolbar hidden doorHangerRight menu" id="editorStampParamsToolbar">
<div class="menuContainer">
- <button id="editorStampAddImage" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-editor-stamp-add-image-button">
+ <button
+ id="editorStampAddImage"
+ class="toolbarButton labeled"
+ type="button"
+ tabindex="0"
+ data-l10n-id="pdfjs-editor-stamp-add-image-button"
+ >
<span class="editorParamsLabel" data-l10n-id="pdfjs-editor-stamp-add-image-button-label"></span>
</button>
</div>
@@ -309,7 +476,16 @@ See https://github.com/adobe-type-tools/cmap-resources
<div class="verticalToolbarSeparator hiddenMediumView"></div>
<div id="secondaryToolbarToggle" class="toolbarButtonWithContainer">
- <button id="secondaryToolbarToggleButton" class="toolbarButton" type="button" tabindex="0" data-l10n-id="pdfjs-tools-button" aria-expanded="false" aria-haspopup="true" aria-controls="secondaryToolbar">
+ <button
+ id="secondaryToolbarToggleButton"
+ class="toolbarButton"
+ type="button"
+ tabindex="0"
+ data-l10n-id="pdfjs-tools-button"
+ aria-expanded="false"
+ aria-haspopup="true"
+ aria-controls="secondaryToolbar"
+ >
<span data-l10n-id="pdfjs-tools-button-label"></span>
</button>
<div id="secondaryToolbar" class="hidden doorHangerRight menu">
@@ -356,10 +532,26 @@ See https://github.com/adobe-type-tools/cmap-resources
<div class="horizontalToolbarSeparator"></div>
<div id="cursorToolButtons" role="radiogroup">
- <button id="cursorSelectTool" class="toolbarButton labeled toggled" type="button" tabindex="0" data-l10n-id="pdfjs-cursor-text-select-tool-button" role="radio" aria-checked="true">
+ <button
+ id="cursorSelectTool"
+ class="toolbarButton labeled toggled"
+ type="button"
+ tabindex="0"
+ data-l10n-id="pdfjs-cursor-text-select-tool-button"
+ role="radio"
+ aria-checked="true"
+ >
<span data-l10n-id="pdfjs-cursor-text-select-tool-button-label"></span>
</button>
- <button id="cursorHandTool" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-cursor-hand-tool-button" role="radio" aria-checked="false">
+ <button
+ id="cursorHandTool"
+ class="toolbarButton labeled"
+ type="button"
+ tabindex="0"
+ data-l10n-id="pdfjs-cursor-hand-tool-button"
+ role="radio"
+ aria-checked="false"
+ >
<span data-l10n-id="pdfjs-cursor-hand-tool-button-label"></span>
</button>
</div>
@@ -367,16 +559,48 @@ See https://github.com/adobe-type-tools/cmap-resources
<div class="horizontalToolbarSeparator"></div>
<div id="scrollModeButtons" role="radiogroup">
- <button id="scrollPage" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-scroll-page-button" role="radio" aria-checked="false">
+ <button
+ id="scrollPage"
+ class="toolbarButton labeled"
+ type="button"
+ tabindex="0"
+ data-l10n-id="pdfjs-scroll-page-button"
+ role="radio"
+ aria-checked="false"
+ >
<span data-l10n-id="pdfjs-scroll-page-button-label"></span>
</button>
- <button id="scrollVertical" class="toolbarButton labeled toggled" type="button" tabindex="0" data-l10n-id="pdfjs-scroll-vertical-button" role="radio" aria-checked="true">
+ <button
+ id="scrollVertical"
+ class="toolbarButton labeled toggled"
+ type="button"
+ tabindex="0"
+ data-l10n-id="pdfjs-scroll-vertical-button"
+ role="radio"
+ aria-checked="true"
+ >
<span data-l10n-id="pdfjs-scroll-vertical-button-label"></span>
</button>
- <button id="scrollHorizontal" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-scroll-horizontal-button" role="radio" aria-checked="false">
+ <button
+ id="scrollHorizontal"
+ class="toolbarButton labeled"
+ type="button"
+ tabindex="0"
+ data-l10n-id="pdfjs-scroll-horizontal-button"
+ role="radio"
+ aria-checked="false"
+ >
<span data-l10n-id="pdfjs-scroll-horizontal-button-label"></span>
</button>
- <button id="scrollWrapped" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-scroll-wrapped-button" role="radio" aria-checked="false">
+ <button
+ id="scrollWrapped"
+ class="toolbarButton labeled"
+ type="button"
+ tabindex="0"
+ data-l10n-id="pdfjs-scroll-wrapped-button"
+ role="radio"
+ aria-checked="false"
+ >
<span data-l10n-id="pdfjs-scroll-wrapped-button-label"></span>
</button>
</div>
@@ -384,36 +608,74 @@ See https://github.com/adobe-type-tools/cmap-resources
<div class="horizontalToolbarSeparator"></div>
<div id="spreadModeButtons" role="radiogroup">
- <button id="spreadNone" class="toolbarButton labeled toggled" type="button" tabindex="0" data-l10n-id="pdfjs-spread-none-button" role="radio" aria-checked="true">
+ <button
+ id="spreadNone"
+ class="toolbarButton labeled toggled"
+ type="button"
+ tabindex="0"
+ data-l10n-id="pdfjs-spread-none-button"
+ role="radio"
+ aria-checked="true"
+ >
<span data-l10n-id="pdfjs-spread-none-button-label"></span>
</button>
- <button id="spreadOdd" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-spread-odd-button" role="radio" aria-checked="false">
+ <button
+ id="spreadOdd"
+ class="toolbarButton labeled"
+ type="button"
+ tabindex="0"
+ data-l10n-id="pdfjs-spread-odd-button"
+ role="radio"
+ aria-checked="false"
+ >
<span data-l10n-id="pdfjs-spread-odd-button-label"></span>
</button>
- <button id="spreadEven" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-spread-even-button" role="radio" aria-checked="false">
+ <button
+ id="spreadEven"
+ class="toolbarButton labeled"
+ type="button"
+ tabindex="0"
+ data-l10n-id="pdfjs-spread-even-button"
+ role="radio"
+ aria-checked="false"
+ >
<span data-l10n-id="pdfjs-spread-even-button-label"></span>
</button>
</div>
<div id="imageAltTextSettingsSeparator" class="horizontalToolbarSeparator hidden"></div>
- <button id="imageAltTextSettings" type="button" class="toolbarButton labeled hidden" tabindex="0" data-l10n-id="pdfjs-image-alt-text-settings-button" aria-controls="altTextSettingsDialog">
+ <button
+ id="imageAltTextSettings"
+ type="button"
+ class="toolbarButton labeled hidden"
+ tabindex="0"
+ data-l10n-id="pdfjs-image-alt-text-settings-button"
+ aria-controls="altTextSettingsDialog"
+ >
<span data-l10n-id="pdfjs-image-alt-text-settings-button-label"></span>
</button>
<div class="horizontalToolbarSeparator"></div>
- <button id="documentProperties" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-document-properties-button" aria-controls="documentPropertiesDialog">
+ <button
+ id="documentProperties"
+ class="toolbarButton labeled"
+ type="button"
+ tabindex="0"
+ data-l10n-id="pdfjs-document-properties-button"
+ aria-controls="documentPropertiesDialog"
+ >
<span data-l10n-id="pdfjs-document-properties-button-label"></span>
</button>
</div>
- </div> <!-- secondaryToolbar -->
+ </div>
+ <!-- secondaryToolbar -->
</div>
</div>
</div>
<div id="loadingBar">
<div class="progress">
- <div class="glimmer">
- </div>
+ <div class="glimmer"></div>
</div>
</div>
</div>
@@ -422,7 +684,8 @@ See https://github.com/adobe-type-tools/cmap-resources
<div id="viewerContainer" tabindex="0">
<div id="viewer" class="pdfViewer"></div>
</div>
- </div> <!-- mainContainer -->
+ </div>
+ <!-- mainContainer -->
<div id="dialogContainer">
<dialog id="passwordDialog">
@@ -430,7 +693,7 @@ See https://github.com/adobe-type-tools/cmap-resources
<label for="password" id="passwordText" data-l10n-id="pdfjs-password-label"></label>
</div>
<div class="row">
- <input type="password" id="password" class="toolbarField">
+ <input type="password" id="password" class="toolbarField" />
</div>
<div class="buttonRow">
<button id="passwordCancel" class="dialogButton" type="button"><span data-l10n-id="pdfjs-password-cancel-button"></span></button>
@@ -510,7 +773,7 @@ See https://github.com/adobe-type-tools/cmap-resources
<div id="addDescription">
<div class="radio">
<div class="radioButton">
- <input type="radio" id="descriptionButton" name="altTextOption" tabindex="0" aria-describedby="descriptionAreaLabel" checked>
+ <input type="radio" id="descriptionButton" name="altTextOption" tabindex="0" aria-describedby="descriptionAreaLabel" checked />
<label for="descriptionButton" data-l10n-id="pdfjs-editor-alt-text-add-description-label"></label>
</div>
<div class="radioLabel">
@@ -524,7 +787,7 @@ See https://github.com/adobe-type-tools/cmap-resources
<div id="markAsDecorative">
<div class="radio">
<div class="radioButton">
- <input type="radio" id="decorativeButton" name="altTextOption" aria-describedby="decorativeLabel">
+ <input type="radio" id="decorativeButton" name="altTextOption" aria-describedby="decorativeLabel" />
<label for="decorativeButton" data-l10n-id="pdfjs-editor-alt-text-mark-decorative-label"></label>
</div>
<div class="radioLabel">
@@ -533,7 +796,9 @@ See https://github.com/adobe-type-tools/cmap-resources
</div>
</div>
<div id="buttons">
- <button id="altTextCancel" class="secondaryButton" type="button" tabindex="0"><span data-l10n-id="pdfjs-editor-alt-text-cancel-button"></span></button>
+ <button id="altTextCancel" class="secondaryButton" type="button" tabindex="0">
+ <span data-l10n-id="pdfjs-editor-alt-text-cancel-button"></span>
+ </button>
<button id="altTextSave" class="primaryButton" type="button" tabindex="0"><span data-l10n-id="pdfjs-editor-alt-text-save-button"></span></button>
</div>
</div>
@@ -548,17 +813,43 @@ See https://github.com/adobe-type-tools/cmap-resources
<div id="descriptionInstruction">
<div id="newAltTextDescriptionContainer">
<div class="altTextSpinner" role="status" aria-live="polite"></div>
- <textarea id="newAltTextDescriptionTextarea" aria-labelledby="descriptionAreaLabel" data-l10n-id="pdfjs-editor-new-alt-text-textarea" tabindex="0"></textarea>
+ <textarea
+ id="newAltTextDescriptionTextarea"
+ aria-labelledby="descriptionAreaLabel"
+ data-l10n-id="pdfjs-editor-new-alt-text-textarea"
+ tabindex="0"
+ ></textarea>
</div>
<span id="newAltTextDescription" role="note" data-l10n-id="pdfjs-editor-new-alt-text-description"></span>
- <div id="newAltTextDisclaimer" role="note"><div><span data-l10n-id="pdfjs-editor-new-alt-text-disclaimer1"></span> <a href="https://support.mozilla.org/en-US/kb/pdf-alt-text" target="_blank" rel="noopener noreferrer" id="newAltTextLearnMore" data-l10n-id="pdfjs-editor-new-alt-text-disclaimer-learn-more-url" tabindex="0"></a></div></div>
+ <div id="newAltTextDisclaimer" role="note">
+ <div>
+ <span data-l10n-id="pdfjs-editor-new-alt-text-disclaimer1"></span>
+ <a
+ href="https://support.mozilla.org/en-US/kb/pdf-alt-text"
+ target="_blank"
+ rel="noopener noreferrer"
+ id="newAltTextLearnMore"
+ data-l10n-id="pdfjs-editor-new-alt-text-disclaimer-learn-more-url"
+ tabindex="0"
+ ></a>
+ </div>
+ </div>
</div>
<div id="newAltTextCreateAutomatically" class="toggler">
<button id="newAltTextCreateAutomaticallyButton" class="toggle-button" type="button" aria-pressed="true" tabindex="0"></button>
- <label for="newAltTextCreateAutomaticallyButton" class="togglerLabel" data-l10n-id="pdfjs-editor-new-alt-text-create-automatically-button-label"></label>
+ <label
+ for="newAltTextCreateAutomaticallyButton"
+ class="togglerLabel"
+ data-l10n-id="pdfjs-editor-new-alt-text-create-automatically-button-label"
+ ></label>
</div>
<div id="newAltTextDownloadModel" class="hidden">
- <span id="newAltTextDownloadModelDescription" data-l10n-id="pdfjs-editor-new-alt-text-ai-model-downloading-progress" aria-valuemin="0" data-l10n-args='{ "totalSize": 0, "downloadedSize": 0 }'></span>
+ <span
+ id="newAltTextDownloadModelDescription"
+ data-l10n-id="pdfjs-editor-new-alt-text-ai-model-downloading-progress"
+ aria-valuemin="0"
+ data-l10n-args='{ "totalSize": 0, "downloadedSize": 0 }'
+ ></span>
</div>
</div>
<div id="newAltTextImagePreview"></div>
@@ -567,15 +858,23 @@ See https://github.com/adobe-type-tools/cmap-resources
<div>
<div>
<span class="title" data-l10n-id="pdfjs-editor-new-alt-text-error-title"></span>
- <span class="description" data-l10n-id="pdfjs-editor-new-alt-text-error-description"></span>
+ <span class="description" data-l10n-id="pdfjs-editor-new-alt-text-error-description"></span>
</div>
- <button id="newAltTextCloseButton" class="closeButton" type="button" tabindex="0"><span data-l10n-id="pdfjs-editor-new-alt-text-error-close-button"></span></button>
+ <button id="newAltTextCloseButton" class="closeButton" type="button" tabindex="0">
+ <span data-l10n-id="pdfjs-editor-new-alt-text-error-close-button"></span>
+ </button>
</div>
</div>
<div id="newAltTextButtons" class="dialogButtonsGroup">
- <button id="newAltTextCancel" type="button" class="secondaryButton hidden" tabindex="0"><span data-l10n-id="pdfjs-editor-alt-text-cancel-button"></span></button>
- <button id="newAltTextNotNow" type="button" class="secondaryButton" tabindex="0"><span data-l10n-id="pdfjs-editor-new-alt-text-not-now-button"></span></button>
- <button id="newAltTextSave" type="button" class="primaryButton" tabindex="0"><span data-l10n-id="pdfjs-editor-alt-text-save-button"></span></button>
+ <button id="newAltTextCancel" type="button" class="secondaryButton hidden" tabindex="0">
+ <span data-l10n-id="pdfjs-editor-alt-text-cancel-button"></span>
+ </button>
+ <button id="newAltTextNotNow" type="button" class="secondaryButton" tabindex="0">
+ <span data-l10n-id="pdfjs-editor-new-alt-text-not-now-button"></span>
+ </button>
+ <button id="newAltTextSave" type="button" class="primaryButton" tabindex="0">
+ <span data-l10n-id="pdfjs-editor-alt-text-save-button"></span>
+ </button>
</div>
</div>
</dialog>
@@ -594,7 +893,15 @@ See https://github.com/adobe-type-tools/cmap-resources
<label for="createModelButton" class="togglerLabel" data-l10n-id="pdfjs-editor-alt-text-settings-create-model-button-label"></label>
</div>
<div id="createModelDescription" class="description">
- <span data-l10n-id="pdfjs-editor-alt-text-settings-create-model-description"></span> <a href="https://support.mozilla.org/en-US/kb/pdf-alt-text" target="_blank" rel="noopener noreferrer" id="altTextSettingsLearnMore" data-l10n-id="pdfjs-editor-new-alt-text-disclaimer-learn-more-url" tabindex="0"></a>
+ <span data-l10n-id="pdfjs-editor-alt-text-settings-create-model-description"></span>
+ <a
+ href="https://support.mozilla.org/en-US/kb/pdf-alt-text"
+ target="_blank"
+ rel="noopener noreferrer"
+ id="altTextSettingsLearnMore"
+ data-l10n-id="pdfjs-editor-new-alt-text-disclaimer-learn-more-url"
+ tabindex="0"
+ ></a>
</div>
</div>
<div id="aiModelSettings">
@@ -604,8 +911,12 @@ See https://github.com/adobe-type-tools/cmap-resources
<span data-l10n-id="pdfjs-editor-alt-text-settings-ai-model-description"></span>
</div>
</div>
- <button id="deleteModelButton" type="button" class="secondaryButton" tabindex="0"><span data-l10n-id="pdfjs-editor-alt-text-settings-delete-model-button"></span></button>
- <button id="downloadModelButton" type="button" class="secondaryButton" tabindex="0"><span data-l10n-id="pdfjs-editor-alt-text-settings-download-model-button"></span></button>
+ <button id="deleteModelButton" type="button" class="secondaryButton" tabindex="0">
+ <span data-l10n-id="pdfjs-editor-alt-text-settings-delete-model-button"></span>
+ </button>
+ <button id="downloadModelButton" type="button" class="secondaryButton" tabindex="0">
+ <span data-l10n-id="pdfjs-editor-alt-text-settings-download-model-button"></span>
+ </button>
</div>
</div>
</div>
@@ -623,7 +934,9 @@ See https://github.com/adobe-type-tools/cmap-resources
</div>
</div>
<div id="buttons" class="dialogButtonsGroup">
- <button id="altTextSettingsCloseButton" type="button" class="primaryButton" tabindex="0"><span data-l10n-id="pdfjs-editor-alt-text-settings-close-button"></span></button>
+ <button id="altTextSettingsCloseButton" type="button" class="primaryButton" tabindex="0">
+ <span data-l10n-id="pdfjs-editor-alt-text-settings-close-button"></span>
+ </button>
</div>
</div>
</dialog>
@@ -635,13 +948,37 @@ See https://github.com/adobe-type-tools/cmap-resources
<span role="sectionhead" data-l10n-id="pdfjs-editor-add-signature-dialog-title" tabindex="0"></span>
</div>
<div role="tablist" id="addSignatureOptions">
- <button id="addSignatureTypeButton" type="button" role="tab" aria-selected="true" aria-controls="addSignatureTypeContainer" data-l10n-id="pdfjs-editor-add-signature-type-button" tabindex="0"></button>
- <button id="addSignatureDrawButton" type="button" role="tab" aria-selected="false" aria-controls="addSignatureDrawContainer" data-l10n-id="pdfjs-editor-add-signature-draw-button" tabindex="0"></button>
- <button id="addSignatureImageButton" type="button" role="tab" aria-selected="false" aria-controls="addSignatureImageContainer" data-l10n-id="pdfjs-editor-add-signature-image-button" tabindex="-1"></button>
+ <button
+ id="addSignatureTypeButton"
+ type="button"
+ role="tab"
+ aria-selected="true"
+ aria-controls="addSignatureTypeContainer"
+ data-l10n-id="pdfjs-editor-add-signature-type-button"
+ tabindex="0"
+ ></button>
+ <button
+ id="addSignatureDrawButton"
+ type="button"
+ role="tab"
+ aria-selected="false"
+ aria-controls="addSignatureDrawContainer"
+ data-l10n-id="pdfjs-editor-add-signature-draw-button"
+ tabindex="0"
+ ></button>
+ <button
+ id="addSignatureImageButton"
+ type="button"
+ role="tab"
+ aria-selected="false"
+ aria-controls="addSignatureImageContainer"
+ data-l10n-id="pdfjs-editor-add-signature-image-button"
+ tabindex="-1"
+ ></button>
</div>
<div id="addSignatureActionContainer" data-selected="type">
<div id="addSignatureTypeContainer" role="tabpanel" aria-labelledby="addSignatureTypeContainer">
- <input id="addSignatureTypeInput" type="text" data-l10n-id="pdfjs-editor-add-signature-type-input" tabindex="0"></input>
+ <input id="addSignatureTypeInput" type="text" data-l10n-id="pdfjs-editor-add-signature-type-input" tabindex="0" />
</div>
<div id="addSignatureDrawContainer" role="tabpanel" aria-labelledby="addSignatureDrawButton" tabindex="-1">
<svg id="addSignatureDraw" xmlns="http://www.w3.org/2000/svg" aria-labelledby="addSignatureDrawPlaceholder"></svg>
@@ -649,7 +986,17 @@ See https://github.com/adobe-type-tools/cmap-resources
<div id="thickness">
<div>
<label for="addSignatureDrawThickness" data-l10n-id="pdfjs-editor-add-signature-draw-thickness-range-label"></label>
- <input type="range" id="addSignatureDrawThickness" min="1" max="5" step="1" value="1" data-l10n-id="pdfjs-editor-add-signature-draw-thickness-range" data-l10n-args='{ "thickness": 1 }' tabindex="0">
+ <input
+ type="range"
+ id="addSignatureDrawThickness"
+ min="1"
+ max="5"
+ step="1"
+ value="1"
+ data-l10n-id="pdfjs-editor-add-signature-draw-thickness-range"
+ data-l10n-args='{ "thickness": 1 }'
+ tabindex="0"
+ />
</div>
</div>
</div>
@@ -660,7 +1007,7 @@ See https://github.com/adobe-type-tools/cmap-resources
<label id="addSignatureImageBrowse" for="addSignatureFilePicker" tabindex="0">
<a data-l10n-id="pdfjs-editor-add-signature-image-browse-link"></a>
</label>
- <input id="addSignatureFilePicker" type="file"></input>
+ <input id="addSignatureFilePicker" type="file" />
</div>
</div>
<div id="addSignatureControls">
@@ -668,14 +1015,16 @@ See https://github.com/adobe-type-tools/cmap-resources
<div id="addSignatureDescriptionContainer">
<label for="addSignatureDescInput" data-l10n-id="pdfjs-editor-add-signature-description-label"></label>
<span id="addSignatureDescription" class="inputWithClearButton">
- <input id="addSignatureDescInput" type="text" data-l10n-id="pdfjs-editor-add-signature-description-input" tabindex="0"></input>
+ <input id="addSignatureDescInput" type="text" data-l10n-id="pdfjs-editor-add-signature-description-input" tabindex="0" />
<button class="clearInputButton" type="button" tabindex="0" aria-hidden="true"></button>
</span>
</div>
- <button id="clearSignatureButton" type="button" data-l10n-id="pdfjs-editor-add-signature-clear-button" tabindex="0"><span data-l10n-id="pdfjs-editor-add-signature-clear-button-label"></span></button>
+ <button id="clearSignatureButton" type="button" data-l10n-id="pdfjs-editor-add-signature-clear-button" tabindex="0">
+ <span data-l10n-id="pdfjs-editor-add-signature-clear-button-label"></span>
+ </button>
</div>
<div id="addSignatureSaveContainer">
- <input type="checkbox" id="addSignatureSaveCheckbox"></input>
+ <input type="checkbox" id="addSignatureSaveCheckbox" />
<label for="addSignatureSaveCheckbox" data-l10n-id="pdfjs-editor-add-signature-save-checkbox"></label>
<span></span>
<span id="addSignatureSaveWarning" data-l10n-id="pdfjs-editor-add-signature-save-warning-message"></span>
@@ -687,57 +1036,68 @@ See https://github.com/adobe-type-tools/cmap-resources
<span id="addSignatureErrorTitle" class="title" data-l10n-id="pdfjs-editor-add-signature-image-upload-error-title"></span>
<span id="addSignatureErrorDescription" class="description" data-l10n-id="pdfjs-editor-add-signature-image-upload-error-description"></span>
</div>
- <button id="addSignatureErrorCloseButton" class="closeButton" type="button" tabindex="0"><span data-l10n-id="pdfjs-editor-add-signature-error-close-button"></span></button>
+ <button id="addSignatureErrorCloseButton" class="closeButton" type="button" tabindex="0">
+ <span data-l10n-id="pdfjs-editor-add-signature-error-close-button"></span>
+ </button>
</div>
</div>
<div class="dialogButtonsGroup">
- <button id="addSignatureCancelButton" type="button" class="secondaryButton" tabindex="0"><span data-l10n-id="pdfjs-editor-add-signature-cancel-button"></span></button>
- <button id="addSignatureAddButton" type="button" class="primaryButton" disabled tabindex="0"><span data-l10n-id="pdfjs-editor-add-signature-add-button"></span></button>
+ <button id="addSignatureCancelButton" type="button" class="secondaryButton" tabindex="0">
+ <span data-l10n-id="pdfjs-editor-add-signature-cancel-button"></span>
+ </button>
+ <button id="addSignatureAddButton" type="button" class="primaryButton" disabled tabindex="0">
+ <span data-l10n-id="pdfjs-editor-add-signature-add-button"></span>
+ </button>
</div>
</div>
</div>
- </dialog>
+ </dialog>
- <dialog class="dialog signatureDialog" id="editSignatureDescriptionDialog" aria-labelledby="editSignatureDescriptionTitle">
- <div id="editSignatureDescriptionContainer" class="mainContainer">
- <div class="title">
- <span id="editSignatureDescriptionTitle" role="sectionhead" data-l10n-id="pdfjs-editor-edit-signature-dialog-title" tabindex="0"></span>
- </div>
- <div id="editSignatureDescriptionAndView">
- <div id="editSignatureDescriptionContainer">
- <label for="editSignatureDescInput" data-l10n-id="pdfjs-editor-add-signature-description-label"></label>
- <span id="editSignatureDescription" class="inputWithClearButton">
- <input id="editSignatureDescInput" type="text" data-l10n-id="pdfjs-editor-add-signature-description-input" tabindex="0"></input>
- <button class="clearInputButton" type="button" tabindex="0" aria-hidden="true"></button>
- </span>
+ <dialog class="dialog signatureDialog" id="editSignatureDescriptionDialog" aria-labelledby="editSignatureDescriptionTitle">
+ <div id="editSignatureDescriptionContainer" class="mainContainer">
+ <div class="title">
+ <span id="editSignatureDescriptionTitle" role="sectionhead" data-l10n-id="pdfjs-editor-edit-signature-dialog-title" tabindex="0"></span>
+ </div>
+ <div id="editSignatureDescriptionAndView">
+ <div id="editSignatureDescriptionContainer">
+ <label for="editSignatureDescInput" data-l10n-id="pdfjs-editor-add-signature-description-label"></label>
+ <span id="editSignatureDescription" class="inputWithClearButton">
+ <input id="editSignatureDescInput" type="text" data-l10n-id="pdfjs-editor-add-signature-description-input" tabindex="0" />
+ <button class="clearInputButton" type="button" tabindex="0" aria-hidden="true"></button>
+ </span>
+ </div>
+ <svg id="editSignatureView" xmlns="http://www.w3.org/2000/svg"></svg>
+ </div>
+ <div class="dialogButtonsGroup">
+ <button id="editSignatureCancelButton" type="button" class="secondaryButton" tabindex="0">
+ <span data-l10n-id="pdfjs-editor-add-signature-cancel-button"></span>
+ </button>
+ <button id="editSignatureUpdateButton" type="button" class="primaryButton" disabled tabindex="0">
+ <span data-l10n-id="pdfjs-editor-edit-signature-update-button"></span>
+ </button>
</div>
- <svg id="editSignatureView" xmlns="http://www.w3.org/2000/svg"></svg>
- </div>
- <div class="dialogButtonsGroup">
- <button id="editSignatureCancelButton" type="button" class="secondaryButton" tabindex="0"><span data-l10n-id="pdfjs-editor-add-signature-cancel-button"></span></button>
- <button id="editSignatureUpdateButton" type="button" class="primaryButton" disabled tabindex="0"><span data-l10n-id="pdfjs-editor-edit-signature-update-button"></span></button>
</div>
- </div>
- </dialog>
+ </dialog>
- <dialog class="dialog commentManager" id="commentManagerDialog" aria-labelledby="commentManagerTitle">
- <div class="mainContainer">
- <div class="title" id="commentManagerToolbar">
- <span id="commentManagerTitle" role="sectionhead" data-l10n-id="pdfjs-editor-edit-comment-dialog-title-when-adding"></span>
- </div>
- <textarea id="commentManagerTextInput" data-l10n-id="pdfjs-editor-edit-comment-dialog-text-input" tabindex="0"></textarea>
- <div class="dialogButtonsGroup">
- <button id="commentManagerCancelButton" type="button" class="secondaryButton" tabindex="0">
- <span data-l10n-id="pdfjs-editor-edit-comment-dialog-cancel-button"></span>
- </button>
- <button id="commentManagerSaveButton" type="button" class="primaryButton" disabled tabindex="0">
- <span data-l10n-id="pdfjs-editor-edit-comment-dialog-save-button-when-adding"></span>
- </button>
+ <dialog class="dialog commentManager" id="commentManagerDialog" aria-labelledby="commentManagerTitle">
+ <div class="mainContainer">
+ <div class="title" id="commentManagerToolbar">
+ <span id="commentManagerTitle" role="sectionhead" data-l10n-id="pdfjs-editor-edit-comment-dialog-title-when-adding"></span>
+ </div>
+ <textarea id="commentManagerTextInput" data-l10n-id="pdfjs-editor-edit-comment-dialog-text-input" tabindex="0"></textarea>
+ <div class="dialogButtonsGroup">
+ <button id="commentManagerCancelButton" type="button" class="secondaryButton" tabindex="0">
+ <span data-l10n-id="pdfjs-editor-edit-comment-dialog-cancel-button"></span>
+ </button>
+ <button id="commentManagerSaveButton" type="button" class="primaryButton" disabled tabindex="0">
+ <span data-l10n-id="pdfjs-editor-edit-comment-dialog-save-button-when-adding"></span>
+ </button>
+ </div>
</div>
- </div>
- </dialog>
+ </dialog>
- </div> <!-- dialogContainer -->
+ </div>
+ <!-- dialogContainer -->
<div id="editorUndoBar" class="messageBar" role="status" aria-labelledby="editorUndoBarMessage" tabindex="-1" hidden>
<div>
@@ -751,9 +1111,10 @@ See https://github.com/adobe-type-tools/cmap-resources
<span data-l10n-id="pdfjs-editor-undo-bar-close-button-label"></span>
</button>
</div>
- </div> <!-- editorUndoBar -->
-
- </div> <!-- outerContainer -->
+ </div>
+ <!-- editorUndoBar -->
+ </div>
+ <!-- outerContainer -->
<div id="printContainer"></div>
</body>
</html>
diff --git a/toolkit/components/pdfjs/content/web/viewer.mjs b/toolkit/components/pdfjs/content/web/viewer.mjs
@@ -21,8 +21,8 @@
*/
/**
- * pdfjsVersion = 5.4.402
- * pdfjsBuild = 57334bd20
+ * pdfjsVersion = 5.4.445
+ * pdfjsBuild = ec5330f78
*/
/******/ // The require scope
/******/ var __webpack_require__ = {};
@@ -2294,6 +2294,11 @@ class NewAltTextManager {
textarea.addEventListener("input", () => {
this.#toggleTitleAndDisclaimer();
});
+ textarea.addEventListener("keydown", e => {
+ if ((e.ctrlKey || e.metaKey) && e.key === "Enter" && !saveButton.disabled) {
+ this.#save();
+ }
+ });
eventBus._on("enableguessalttext", ({
value
}) => {
@@ -2536,7 +2541,7 @@ class NewAltTextManager {
this.#overlayManager.closeIfActive(this.#dialog);
}
#close() {
- const canvas = this.#imagePreview.firstChild;
+ const canvas = this.#imagePreview.firstElementChild;
canvas.remove();
canvas.width = canvas.height = 0;
this.#imageData = null;
@@ -2680,7 +2685,7 @@ class ImageAltTextSettings {
async #download(isFromUI = false) {
if (isFromUI) {
this.#downloadModelButton.disabled = true;
- const span = this.#downloadModelButton.firstChild;
+ const span = this.#downloadModelButton.firstElementChild;
span.setAttribute("data-l10n-id", "pdfjs-editor-alt-text-settings-downloading-model-button");
await this.#mlManager.downloadModel("altText");
span.setAttribute("data-l10n-id", "pdfjs-editor-alt-text-settings-download-model-button");
@@ -2789,6 +2794,11 @@ class AltTextManager {
saveButton.addEventListener("click", this.#save.bind(this));
optionDescription.addEventListener("change", onUpdateUIState);
optionDecorative.addEventListener("change", onUpdateUIState);
+ textarea.addEventListener("keydown", e => {
+ if ((e.ctrlKey || e.metaKey) && e.key === "Enter" && !saveButton.disabled) {
+ this.#save();
+ }
+ });
this.#overlayManager.register(dialog);
}
#createSVGElement() {
@@ -3301,9 +3311,129 @@ class CaretBrowsingMode {
}
}
+;// ./web/sidebar.js
+
+class Sidebar {
+ #minWidth = 0;
+ #maxWidth = 0;
+ #initialWidth = 0;
+ #width = 0;
+ #coefficient;
+ #visible = false;
+ constructor({
+ sidebar,
+ resizer,
+ toggleButton
+ }, ltr, isResizerOnTheLeft) {
+ this._sidebar = sidebar;
+ this.#coefficient = ltr === isResizerOnTheLeft ? -1 : 1;
+ const style = window.getComputedStyle(sidebar);
+ this.#minWidth = parseFloat(style.getPropertyValue("--sidebar-min-width"));
+ this.#maxWidth = parseFloat(style.getPropertyValue("--sidebar-max-width"));
+ this.#initialWidth = this.#width = parseFloat(style.getPropertyValue("--sidebar-width"));
+ this.#makeSidebarResizable(resizer, isResizerOnTheLeft);
+ toggleButton.addEventListener("click", this.toggle.bind(this));
+ sidebar.hidden = true;
+ }
+ #makeSidebarResizable(resizer, isResizerOnTheLeft) {
+ resizer.ariaValueMin = this.#minWidth;
+ resizer.ariaValueMax = this.#maxWidth;
+ resizer.ariaValueNow = this.#width;
+ let pointerMoveAC;
+ const cancelResize = () => {
+ this.#width = MathClamp(this.#width, this.#minWidth, this.#maxWidth);
+ this._sidebar.classList.remove("resizing");
+ pointerMoveAC?.abort();
+ pointerMoveAC = null;
+ };
+ resizer.addEventListener("pointerdown", e => {
+ if (pointerMoveAC) {
+ cancelResize();
+ return;
+ }
+ const {
+ clientX
+ } = e;
+ stopEvent(e);
+ let prevX = clientX;
+ pointerMoveAC = new AbortController();
+ const {
+ signal
+ } = pointerMoveAC;
+ const sidebar = this._sidebar;
+ const sidebarStyle = sidebar.style;
+ sidebar.classList.add("resizing");
+ const parentStyle = sidebar.parentElement.style;
+ parentStyle.minWidth = 0;
+ window.addEventListener("contextmenu", noContextMenu, {
+ signal
+ });
+ window.addEventListener("pointermove", ev => {
+ if (!pointerMoveAC) {
+ return;
+ }
+ stopEvent(ev);
+ const {
+ clientX: x
+ } = ev;
+ this.#setNewWidth(x - prevX, parentStyle, resizer, sidebarStyle, isResizerOnTheLeft, false);
+ prevX = x;
+ }, {
+ signal,
+ capture: true
+ });
+ window.addEventListener("blur", cancelResize, {
+ signal
+ });
+ window.addEventListener("pointerup", ev => {
+ if (pointerMoveAC) {
+ cancelResize();
+ stopEvent(ev);
+ }
+ }, {
+ signal
+ });
+ });
+ resizer.addEventListener("keydown", e => {
+ const {
+ key
+ } = e;
+ const isArrowLeft = key === "ArrowLeft";
+ if (isArrowLeft || key === "ArrowRight") {
+ const base = e.ctrlKey || e.metaKey ? 10 : 1;
+ const dx = base * (isArrowLeft ? -1 : 1);
+ this.#setNewWidth(dx, this._sidebar.parentElement.style, resizer, this._sidebar.style, isResizerOnTheLeft, true);
+ stopEvent(e);
+ }
+ });
+ }
+ #setNewWidth(dx, parentStyle, resizer, sidebarStyle, isResizerOnTheLeft, isFromKeyboard) {
+ let newWidth = this.#width + this.#coefficient * dx;
+ if (!isFromKeyboard) {
+ this.#width = newWidth;
+ }
+ if ((newWidth > this.#maxWidth || newWidth < this.#minWidth) && (this.#width === this.#maxWidth || this.#width === this.#minWidth)) {
+ return;
+ }
+ newWidth = MathClamp(newWidth, this.#minWidth, this.#maxWidth);
+ if (isFromKeyboard) {
+ this.#width = newWidth;
+ }
+ resizer.ariaValueNow = Math.round(newWidth);
+ sidebarStyle.width = `${newWidth.toFixed(3)}px`;
+ if (isResizerOnTheLeft) {
+ parentStyle.insetInlineStart = `${(this.#initialWidth - newWidth).toFixed(3)}px`;
+ }
+ }
+ toggle() {
+ this._sidebar.hidden = !(this.#visible = !this.#visible);
+ }
+}
+
;// ./web/comment_manager.js
+
class CommentManager {
#dialog;
#popup;
@@ -3368,12 +3498,11 @@ class CommentManager {
this.#popup.destroy();
}
}
-class CommentSidebar {
+class CommentSidebar extends Sidebar {
#annotations = null;
#eventBus;
#boundCommentClick = this.#commentClick.bind(this);
#boundCommentKeydown = this.#commentKeydown.bind(this);
- #sidebar;
#closeButton;
#commentsList;
#commentCount;
@@ -3385,11 +3514,6 @@ class CommentSidebar {
#elementsToAnnotations = null;
#idsToElements = null;
#uiManager = null;
- #minWidth = 0;
- #maxWidth = 0;
- #initialWidth = 0;
- #width = 0;
- #ltr;
constructor({
learnMoreUrl,
sidebar,
@@ -3400,7 +3524,11 @@ class CommentSidebar {
closeButton,
commentToolbarButton
}, eventBus, linkService, popup, dateFormat, ltr) {
- this.#sidebar = sidebar;
+ super({
+ sidebar,
+ resizer: sidebarResizer,
+ toggleButton: commentToolbarButton
+ }, ltr, true);
this.#sidebarTitle = sidebarTitle;
this.#commentsList = commentsList;
this.#commentCount = commentCount;
@@ -3409,13 +3537,7 @@ class CommentSidebar {
this.#closeButton = closeButton;
this.#popup = popup;
this.#dateFormat = dateFormat;
- this.#ltr = ltr;
this.#eventBus = eventBus;
- const style = window.getComputedStyle(sidebar);
- this.#minWidth = parseFloat(style.getPropertyValue("--sidebar-min-width"));
- this.#maxWidth = parseFloat(style.getPropertyValue("--sidebar-max-width"));
- this.#initialWidth = this.#width = parseFloat(style.getPropertyValue("--sidebar-width"));
- this.#makeSidebarResizable(sidebarResizer);
closeButton.addEventListener("click", () => {
eventBus.dispatch("switchannotationeditormode", {
source: this,
@@ -3433,70 +3555,6 @@ class CommentSidebar {
};
commentToolbarButton.addEventListener("keydown", keyDownCallback);
sidebar.addEventListener("keydown", keyDownCallback);
- this.#sidebar.hidden = true;
- }
- #makeSidebarResizable(resizer) {
- let pointerMoveAC;
- const cancelResize = () => {
- this.#width = MathClamp(this.#width, this.#minWidth, this.#maxWidth);
- this.#sidebar.classList.remove("resizing");
- pointerMoveAC?.abort();
- pointerMoveAC = null;
- };
- resizer.addEventListener("pointerdown", e => {
- if (pointerMoveAC) {
- cancelResize();
- return;
- }
- const {
- clientX
- } = e;
- stopEvent(e);
- let prevX = clientX;
- pointerMoveAC = new AbortController();
- const {
- signal
- } = pointerMoveAC;
- const sign = this.#ltr ? -1 : 1;
- const sidebar = this.#sidebar;
- const sidebarStyle = sidebar.style;
- sidebar.classList.add("resizing");
- const parentStyle = sidebar.parentElement.style;
- parentStyle.minWidth = 0;
- window.addEventListener("contextmenu", noContextMenu, {
- signal
- });
- window.addEventListener("pointermove", ev => {
- if (!pointerMoveAC) {
- return;
- }
- stopEvent(ev);
- const {
- clientX: x
- } = ev;
- const newWidth = this.#width += sign * (x - prevX);
- prevX = x;
- if (newWidth > this.#maxWidth || newWidth < this.#minWidth) {
- return;
- }
- sidebarStyle.width = `${newWidth.toFixed(3)}px`;
- parentStyle.insetInlineStart = `${(this.#initialWidth - newWidth).toFixed(3)}px`;
- }, {
- signal,
- capture: true
- });
- window.addEventListener("blur", cancelResize, {
- signal
- });
- window.addEventListener("pointerup", ev => {
- if (pointerMoveAC) {
- cancelResize();
- stopEvent(ev);
- }
- }, {
- signal
- });
- });
}
setUIManager(uiManager) {
this.#uiManager = uiManager;
@@ -3516,7 +3574,7 @@ class CommentSidebar {
} else {
this.#setCommentsCount();
}
- this.#sidebar.hidden = false;
+ this._sidebar.hidden = false;
this.#eventBus.dispatch("reporttelemetry", {
source: this,
details: {
@@ -3528,7 +3586,7 @@ class CommentSidebar {
});
}
hide() {
- this.#sidebar.hidden = true;
+ this._sidebar.hidden = true;
this.#commentsList.replaceChildren();
this.#elementsToAnnotations = null;
this.#idsToElements = null;
@@ -3551,7 +3609,7 @@ class CommentSidebar {
if (!element) {
return;
}
- this.#sidebar.scrollTop = element.offsetTop - this.#sidebar.offsetTop;
+ this._sidebar.scrollTop = element.offsetTop - this._sidebar.offsetTop;
for (const el of this.#commentsList.children) {
el.classList.toggle("selected", el === element);
}
@@ -3580,8 +3638,8 @@ class CommentSidebar {
if (index >= this.#annotations.length) {
return;
}
- this.#setDate(element.firstChild, modificationDate || creationDate);
- this.#setText(element.lastChild, richText, contentsObj);
+ this.#setDate(element.firstElementChild, modificationDate || creationDate);
+ this.#setText(element.lastElementChild, richText, contentsObj);
this.#annotations.splice(index, 1);
index = binarySearchFirstItem(this.#annotations, a => this.#sortComments(a, annotation) >= 0);
this.#annotations.splice(index, 0, annotation);
@@ -3854,6 +3912,11 @@ class CommentDialog {
textInput.addEventListener("input", () => {
saveButton.disabled = textInput.value === this.#previousText;
});
+ textInput.addEventListener("keydown", e => {
+ if ((e.ctrlKey || e.metaKey) && e.key === "Enter" && !saveButton.disabled) {
+ this.#save();
+ }
+ });
let pointerMoveAC;
const cancelDrag = () => {
dialog.classList.remove("dragging");
@@ -5154,6 +5217,7 @@ class PDFDocumentProperties {
}
;// ./web/pdf_find_utils.js
+
const CharacterType = {
SPACE: 0,
ALPHA_LETTER: 1,
@@ -5223,7 +5287,7 @@ function getCharacterType(charCode) {
}
let NormalizeWithNFKC;
function getNormalizeWithNFKC() {
- NormalizeWithNFKC ||= ` ¨ª¯²-µ¸-º¼-¾IJ-ijĿ-ŀʼnſDŽ-njDZ-dzʰ-ʸ˘-˝ˠ-ˤʹͺ;΄-΅·ϐ-ϖϰ-ϲϴ-ϵϹևٵ-ٸक़-य़ড়-ঢ়য়ਲ਼ਸ਼ਖ਼-ਜ਼ਫ਼ଡ଼-ଢ଼ำຳໜ-ໝ༌གྷཌྷདྷབྷཛྷཀྵჼᴬ-ᴮᴰ-ᴺᴼ-ᵍᵏ-ᵪᵸᶛ-ᶿẚ-ẛάέήίόύώΆ᾽-῁ΈΉ῍-῏ΐΊ῝-῟ΰΎ῭-`ΌΏ´-῾ - ‑‗․-… ″-‴‶-‷‼‾⁇-⁉⁗ ⁰-ⁱ⁴-₎ₐ-ₜ₨℀-℃℅-ℇ℉-ℓℕ-№ℙ-ℝ℠-™ℤΩℨK-ℭℯ-ℱℳ-ℹ℻-⅀ⅅ-ⅉ⅐-ⅿ↉∬-∭∯-∰〈-〉①-⓪⨌⩴-⩶⫝̸ⱼ-ⱽⵯ⺟⻳⼀-⿕ 〶〸-〺゛-゜ゟヿㄱ-ㆎ㆒-㆟㈀-㈞㈠-㉇㉐-㉾㊀-㏿ꚜ-ꚝꝰꟲ-ꟴꟸ-ꟹꭜ-ꭟꭩ豈-嗀塚晴凞-羽蘒諸逸-都飯-舘並-龎ff-stﬓ-ﬗיִײַ-זּטּ-לּמּנּ-סּףּ-פּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-﷼︐-︙︰-﹄﹇-﹒﹔-﹦﹨-﹫ﹰ-ﹲﹴﹶ-ﻼ!-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ¢-₩`;
+ NormalizeWithNFKC ||= `\xA0¨ª¯²-µ¸-º¼-¾IJ-ijĿ-ŀʼnſDŽ-njDZ-dzʰ-ʸ˘-˝ˠ-ˤʹͺ;΄-΅·ϐ-ϖϰ-ϲϴ-ϵϹևٵ-ٸक़-य़ড়-ঢ়য়ਲ਼ਸ਼ਖ਼-ਜ਼ਫ਼ଡ଼-ଢ଼ำຳໜ-ໝ༌གྷཌྷདྷབྷཛྷཀྵჼᴬ-ᴮᴰ-ᴺᴼ-ᵍᵏ-ᵪᵸᶛ-ᶿẚ-ẛάέήίόύώΆ᾽-῁ΈΉ῍-῏ΐΊ῝-῟ΰΎ῭-`ΌΏ´-῾ - ‑‗․-… ″-‴‶-‷‼‾⁇-⁉⁗ ⁰-ⁱ⁴-₎ₐ-ₜ₨℀-℃℅-ℇ℉-ℓℕ-№ℙ-ℝ℠-™ℤΩℨK-ℭℯ-ℱℳ-ℹ℻-⅀ⅅ-ⅉ⅐-ⅿ↉∬-∭∯-∰〈-〉①-⓪⨌⩴-⩶⫝̸ⱼ-ⱽⵯ⺟⻳⼀-⿕ 〶〸-〺゛-゜ゟヿㄱ-ㆎ㆒-㆟㈀-㈞㈠-㉇㉐-㉾㊀-㏿ꚜ-ꚝꝰ-ꟴꟸ-ꟹꭜ-ꭟꭩ豈-嗀塚晴凞-羽蘒諸逸-都飯-舘並-龎ff-stﬓ-ﬗיִײַ-זּטּ-לּמּנּ-סּףּ-פּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-﷼︐-︙︰-﹄﹇-﹒﹔-﹦﹨-﹫ﹰ-ﹲﹴﹶ-ﻼ!-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ¢-₩`;
return NormalizeWithNFKC;
}
@@ -5255,7 +5319,7 @@ const CHARACTERS_TO_NORMALIZE = {
const DIACRITICS_EXCEPTION = new Set([0x3099, 0x309a, 0x094d, 0x09cd, 0x0a4d, 0x0acd, 0x0b4d, 0x0bcd, 0x0c4d, 0x0ccd, 0x0d3b, 0x0d3c, 0x0d4d, 0x0dca, 0x0e3a, 0x0eba, 0x0f84, 0x1039, 0x103a, 0x1714, 0x1734, 0x17d2, 0x1a60, 0x1b44, 0x1baa, 0x1bab, 0x1bf2, 0x1bf3, 0x2d7f, 0xa806, 0xa82c, 0xa8c4, 0xa953, 0xa9c0, 0xaaf6, 0xabed, 0x0c56, 0x0f71, 0x0f72, 0x0f7a, 0x0f7b, 0x0f7c, 0x0f7d, 0x0f80, 0x0f74]);
let DIACRITICS_EXCEPTION_STR;
const DIACRITICS_REG_EXP = /\p{M}+/gu;
-const SPECIAL_CHARS_REG_EXP = /([.*+?^${}()|[\]\\])|(\p{P})|(\s+)|(\p{M})|(\p{L})/gu;
+const SPECIAL_CHARS_REG_EXP = /([*+^${}()|[\]\\])|(\p{P}+)|(\s+)|(\p{M})|(\p{L})/gu;
const NOT_DIACRITIC_FROM_END_REG_EXP = /([^\p{M}])\p{M}*$/u;
const NOT_DIACRITIC_FROM_START_REG_EXP = /^\p{M}*([^\p{M}])/u;
const SYLLABLES_REG_EXP = /[\uAC00-\uD7AF\uFA6C\uFACF-\uFAD1\uFAD5-\uFAD7]+/g;
@@ -5651,12 +5715,24 @@ class PDFFindController {
matchDiacritics
} = this.#state;
let isUnicode = false;
+ const addExtraWhitespaces = (original, fixed) => {
+ if (original === query) {
+ return fixed;
+ }
+ if (query.startsWith(original)) {
+ return `${fixed}[ ]*`;
+ }
+ if (query.endsWith(original)) {
+ return `[ ]*${fixed}`;
+ }
+ return `[ ]*${fixed}[ ]*`;
+ };
query = query.replaceAll(SPECIAL_CHARS_REG_EXP, (match, p1, p2, p3, p4, p5) => {
if (p1) {
- return `[ ]*\\${p1}[ ]*`;
+ return addExtraWhitespaces(p1, `\\${p1}`);
}
if (p2) {
- return `[ ]*${p2}[ ]*`;
+ return addExtraWhitespaces(p2, p2.replaceAll(/[.?]/g, "\\$&"));
}
if (p3) {
return "[ ]+";
@@ -11485,7 +11561,7 @@ class PDFViewer {
#textLayerMode = TextLayerMode.ENABLE;
#viewerAlert = null;
constructor(options) {
- const viewerVersion = "5.4.402";
+ const viewerVersion = "5.4.445";
if (version !== viewerVersion) {
throw new Error(`The API version "${version}" does not match the Viewer version "${viewerVersion}".`);
}
@@ -15641,11 +15717,16 @@ const PDFViewerApplication = {
info,
metadata,
contentDispositionFilename,
- contentLength
+ contentLength,
+ hasStructTree
} = await pdfDocument.getMetadata();
if (pdfDocument !== this.pdfDocument) {
return;
}
+ this.externalServices.reportTelemetry({
+ type: "taggedPDF",
+ data: hasStructTree
+ });
this.documentInfo = info;
this.metadata = metadata;
this._contentDispositionFilename ??= contentDispositionFilename;
diff --git a/toolkit/components/pdfjs/moz.yaml b/toolkit/components/pdfjs/moz.yaml
@@ -20,8 +20,8 @@ origin:
# Human-readable identifier for this version/release
# Generally "version NNN", "tag SSS", "bookmark SSS"
- release: 57334bd20544a713c400476e7bf966491dd1c823 (2025-11-07T16:21:38Z).
- revision: 57334bd20544a713c400476e7bf966491dd1c823
+ release: ec5330f78c1feb384156bdf6c69b18bedf36b4a3 (2025-11-28T15:59:23Z).
+ revision: ec5330f78c1feb384156bdf6c69b18bedf36b4a3
# The package's license, where possible using the mnemonic from
# https://spdx.org/licenses/