Merge pull request #20467 from calixteman/make_sidebar
Create a sidebar object
This commit is contained in:
commit
925fc3d8f2
@ -22,6 +22,8 @@ import {
|
|||||||
getEditorSelector,
|
getEditorSelector,
|
||||||
getRect,
|
getRect,
|
||||||
highlightSpan,
|
highlightSpan,
|
||||||
|
kbModifierDown,
|
||||||
|
kbModifierUp,
|
||||||
loadAndWait,
|
loadAndWait,
|
||||||
scrollIntoView,
|
scrollIntoView,
|
||||||
selectEditor,
|
selectEditor,
|
||||||
@ -546,6 +548,59 @@ describe("Comment", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("must check that the comment sidebar is resizable with the keyboard", async () => {
|
||||||
|
await Promise.all(
|
||||||
|
pages.map(async ([browserName, page]) => {
|
||||||
|
await switchToComment(page);
|
||||||
|
|
||||||
|
const sidebarSelector = "#editorCommentParamsToolbar";
|
||||||
|
const handle = await createPromise(page, resolve => {
|
||||||
|
document
|
||||||
|
.getElementById("editorCommentsSidebarResizer")
|
||||||
|
.addEventListener("focus", () => resolve(), { once: true });
|
||||||
|
});
|
||||||
|
await page.focus(`${sidebarSelector} #editorCommentsSidebarResizer`);
|
||||||
|
await awaitPromise(handle);
|
||||||
|
|
||||||
|
// Use Ctrl+ArrowLeft/Right to resize the sidebar.
|
||||||
|
for (const extraWidth of [10, -10]) {
|
||||||
|
const rect = await getRect(page, sidebarSelector);
|
||||||
|
const arrowKey = extraWidth > 0 ? "ArrowLeft" : "ArrowRight";
|
||||||
|
for (let i = 0; i < Math.abs(extraWidth); i++) {
|
||||||
|
await kbModifierDown(page);
|
||||||
|
await page.keyboard.press(arrowKey);
|
||||||
|
await kbModifierUp(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
const rectAfter = await getRect(page, sidebarSelector);
|
||||||
|
expect(Math.abs(rectAfter.width - (rect.width + 10 * extraWidth)))
|
||||||
|
.withContext(`In ${browserName}`)
|
||||||
|
.toBeLessThanOrEqual(1);
|
||||||
|
expect(Math.abs(rectAfter.x - (rect.x - 10 * extraWidth)))
|
||||||
|
.withContext(`In ${browserName}`)
|
||||||
|
.toBeLessThanOrEqual(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use ArrowLeft/Right to resize the sidebar.
|
||||||
|
for (const extraWidth of [10, -10]) {
|
||||||
|
const rect = await getRect(page, sidebarSelector);
|
||||||
|
const arrowKey = extraWidth > 0 ? "ArrowLeft" : "ArrowRight";
|
||||||
|
for (let i = 0; i < Math.abs(extraWidth); i++) {
|
||||||
|
await page.keyboard.press(arrowKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
const rectAfter = await getRect(page, sidebarSelector);
|
||||||
|
expect(Math.abs(rectAfter.width - (rect.width + extraWidth)))
|
||||||
|
.withContext(`In ${browserName}`)
|
||||||
|
.toBeLessThanOrEqual(1);
|
||||||
|
expect(Math.abs(rectAfter.x - (rect.x - extraWidth)))
|
||||||
|
.withContext(`In ${browserName}`)
|
||||||
|
.toBeLessThanOrEqual(1);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it("must check that comments are in chronological order", async () => {
|
it("must check that comments are in chronological order", async () => {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
pages.map(async ([browserName, page]) => {
|
pages.map(async ([browserName, page]) => {
|
||||||
|
|||||||
@ -27,6 +27,7 @@ import {
|
|||||||
Util,
|
Util,
|
||||||
} from "pdfjs-lib";
|
} from "pdfjs-lib";
|
||||||
import { binarySearchFirstItem } from "./ui_utils.js";
|
import { binarySearchFirstItem } from "./ui_utils.js";
|
||||||
|
import { Sidebar } from "./sidebar.js";
|
||||||
|
|
||||||
class CommentManager {
|
class CommentManager {
|
||||||
#dialog;
|
#dialog;
|
||||||
@ -141,7 +142,7 @@ class CommentManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CommentSidebar {
|
class CommentSidebar extends Sidebar {
|
||||||
#annotations = null;
|
#annotations = null;
|
||||||
|
|
||||||
#eventBus;
|
#eventBus;
|
||||||
@ -150,8 +151,6 @@ class CommentSidebar {
|
|||||||
|
|
||||||
#boundCommentKeydown = this.#commentKeydown.bind(this);
|
#boundCommentKeydown = this.#commentKeydown.bind(this);
|
||||||
|
|
||||||
#sidebar;
|
|
||||||
|
|
||||||
#closeButton;
|
#closeButton;
|
||||||
|
|
||||||
#commentsList;
|
#commentsList;
|
||||||
@ -174,16 +173,6 @@ class CommentSidebar {
|
|||||||
|
|
||||||
#uiManager = null;
|
#uiManager = null;
|
||||||
|
|
||||||
#minWidth = 0;
|
|
||||||
|
|
||||||
#maxWidth = 0;
|
|
||||||
|
|
||||||
#initialWidth = 0;
|
|
||||||
|
|
||||||
#width = 0;
|
|
||||||
|
|
||||||
#ltr;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
{
|
{
|
||||||
learnMoreUrl,
|
learnMoreUrl,
|
||||||
@ -201,7 +190,11 @@ class CommentSidebar {
|
|||||||
dateFormat,
|
dateFormat,
|
||||||
ltr
|
ltr
|
||||||
) {
|
) {
|
||||||
this.#sidebar = sidebar;
|
super(
|
||||||
|
{ sidebar, resizer: sidebarResizer, toggleButton: commentToolbarButton },
|
||||||
|
ltr,
|
||||||
|
/* isResizerOnTheLeft = */ true
|
||||||
|
);
|
||||||
this.#sidebarTitle = sidebarTitle;
|
this.#sidebarTitle = sidebarTitle;
|
||||||
this.#commentsList = commentsList;
|
this.#commentsList = commentsList;
|
||||||
this.#commentCount = commentCount;
|
this.#commentCount = commentCount;
|
||||||
@ -210,17 +203,8 @@ class CommentSidebar {
|
|||||||
this.#closeButton = closeButton;
|
this.#closeButton = closeButton;
|
||||||
this.#popup = popup;
|
this.#popup = popup;
|
||||||
this.#dateFormat = dateFormat;
|
this.#dateFormat = dateFormat;
|
||||||
this.#ltr = ltr;
|
|
||||||
this.#eventBus = eventBus;
|
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", () => {
|
closeButton.addEventListener("click", () => {
|
||||||
eventBus.dispatch("switchannotationeditormode", {
|
eventBus.dispatch("switchannotationeditormode", {
|
||||||
source: this,
|
source: this,
|
||||||
@ -238,64 +222,6 @@ class CommentSidebar {
|
|||||||
};
|
};
|
||||||
commentToolbarButton.addEventListener("keydown", keyDownCallback);
|
commentToolbarButton.addEventListener("keydown", keyDownCallback);
|
||||||
sidebar.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) {
|
setUIManager(uiManager) {
|
||||||
@ -318,7 +244,7 @@ class CommentSidebar {
|
|||||||
} else {
|
} else {
|
||||||
this.#setCommentsCount();
|
this.#setCommentsCount();
|
||||||
}
|
}
|
||||||
this.#sidebar.hidden = false;
|
this._sidebar.hidden = false;
|
||||||
this.#eventBus.dispatch("reporttelemetry", {
|
this.#eventBus.dispatch("reporttelemetry", {
|
||||||
source: this,
|
source: this,
|
||||||
details: {
|
details: {
|
||||||
@ -329,7 +255,7 @@ class CommentSidebar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hide() {
|
hide() {
|
||||||
this.#sidebar.hidden = true;
|
this._sidebar.hidden = true;
|
||||||
this.#commentsList.replaceChildren();
|
this.#commentsList.replaceChildren();
|
||||||
this.#elementsToAnnotations = null;
|
this.#elementsToAnnotations = null;
|
||||||
this.#idsToElements = null;
|
this.#idsToElements = null;
|
||||||
@ -356,7 +282,7 @@ class CommentSidebar {
|
|||||||
if (!element) {
|
if (!element) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.#sidebar.scrollTop = element.offsetTop - this.#sidebar.offsetTop;
|
this._sidebar.scrollTop = element.offsetTop - this._sidebar.offsetTop;
|
||||||
for (const el of this.#commentsList.children) {
|
for (const el of this.#commentsList.children) {
|
||||||
el.classList.toggle("selected", el === element);
|
el.classList.toggle("selected", el === element);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,6 +22,7 @@
|
|||||||
--sidebar-box-shadow:
|
--sidebar-box-shadow:
|
||||||
0 0.25px 0.75px light-dark(rgb(0 0 0 / 0.05), rgb(0 0 0 / 0.2)),
|
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));
|
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-border-radius: 8px;
|
||||||
--sidebar-padding: 5px;
|
--sidebar-padding: 5px;
|
||||||
--sidebar-min-width: 180px;
|
--sidebar-min-width: 180px;
|
||||||
@ -46,6 +47,7 @@
|
|||||||
width: var(--sidebar-width);
|
width: var(--sidebar-width);
|
||||||
min-width: var(--sidebar-min-width);
|
min-width: var(--sidebar-min-width);
|
||||||
max-width: var(--sidebar-max-width);
|
max-width: var(--sidebar-max-width);
|
||||||
|
backdrop-filter: var(--sidebar-backdrop-filter);
|
||||||
|
|
||||||
.sidebarResizer {
|
.sidebarResizer {
|
||||||
width: var(--resizer-width);
|
width: var(--resizer-width);
|
||||||
@ -64,6 +66,10 @@
|
|||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--resizer-hover-bg-color);
|
background-color: var(--resizer-hover-bg-color);
|
||||||
}
|
}
|
||||||
|
&:focus-visible {
|
||||||
|
background-color: var(--resizer-hover-bg-color);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.resizing {
|
&.resizing {
|
||||||
|
|||||||
180
web/sidebar.js
Normal file
180
web/sidebar.js
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
/* Copyright 2025 Mozilla Foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { MathClamp, noContextMenu, stopEvent } from "pdfjs-lib";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Viewer control to display a sidebar with resizer functionality.
|
||||||
|
*/
|
||||||
|
class Sidebar {
|
||||||
|
#minWidth = 0;
|
||||||
|
|
||||||
|
#maxWidth = 0;
|
||||||
|
|
||||||
|
#initialWidth = 0;
|
||||||
|
|
||||||
|
#width = 0;
|
||||||
|
|
||||||
|
#coefficient;
|
||||||
|
|
||||||
|
#visible = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} SidebarElements
|
||||||
|
* @property {HTMLElement} sidebar - The sidebar element.
|
||||||
|
* @property {HTMLElement} resizer - The sidebar resizer element.
|
||||||
|
* @property {HTMLElement} toggleButton - The button used to toggle the
|
||||||
|
* sidebar.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a sidebar with resizer functionality.
|
||||||
|
* @param {SidebarElements} sidebarElements
|
||||||
|
* @param {boolean} ltr
|
||||||
|
* @param {boolean} isResizerOnTheLeft
|
||||||
|
*/
|
||||||
|
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,
|
||||||
|
/* isFromKeyboard */ 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,
|
||||||
|
/* isFromKeyboard */ 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 the sidebar's visibility.
|
||||||
|
*/
|
||||||
|
toggle() {
|
||||||
|
this._sidebar.hidden = !(this.#visible = !this.#visible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Sidebar };
|
||||||
@ -335,7 +335,7 @@ See https://github.com/adobe-type-tools/cmap-resources
|
|||||||
</button>
|
</button>
|
||||||
<div class="editorParamsToolbar hidden menu" id="editorCommentParamsToolbar">
|
<div class="editorParamsToolbar hidden menu" id="editorCommentParamsToolbar">
|
||||||
<div id="editorCommentsSidebar" class="menuContainer comment sidebar" role="landmark" aria-labelledby="editorCommentsSidebarHeader">
|
<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">
|
<div id="editorCommentsSidebarHeader" role="heading" aria-level="2">
|
||||||
<span class="commentCount">
|
<span class="commentCount">
|
||||||
<span id="editorCommentsSidebarTitle" data-l10n-id="pdfjs-editor-comments-sidebar-title" data-l10n-args='{ "count": 0 }'></span>
|
<span id="editorCommentsSidebarTitle" data-l10n-id="pdfjs-editor-comments-sidebar-title" data-l10n-args='{ "count": 0 }'></span>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user