Skip to content

Commit a372294

Browse files
committed
[Editor] Make the comment sidebar resizable (bug 1990544)
1 parent 8448d08 commit a372294

8 files changed

Lines changed: 170 additions & 9 deletions

File tree

test/integration/comment_spec.mjs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929

3030
const switchToHighlight = switchToEditor.bind(null, "Highlight");
3131
const switchToStamp = switchToEditor.bind(null, "Stamp");
32+
const switchToComment = switchToEditor.bind(null, "Comment");
3233

3334
describe("Comment", () => {
3435
describe("Comment edit dialog must be visible in ltr", () => {
@@ -236,4 +237,55 @@ describe("Comment", () => {
236237
);
237238
});
238239
});
240+
241+
describe("Comment sidebar", () => {
242+
let pages;
243+
244+
beforeEach(async () => {
245+
pages = await loadAndWait(
246+
"comments.pdf",
247+
".annotationEditorLayer",
248+
"page-width",
249+
null,
250+
{ enableComment: true }
251+
);
252+
});
253+
254+
afterEach(async () => {
255+
await closePages(pages);
256+
});
257+
258+
it("must check that the comment sidebar is resizable", async () => {
259+
await Promise.all(
260+
pages.map(async ([browserName, page]) => {
261+
await switchToComment(page);
262+
263+
const sidebarSelector = "#editorCommentParamsToolbar";
264+
for (const extraWidth of [100, -100]) {
265+
const rect = await getRect(page, sidebarSelector);
266+
const resizerRect = await getRect(
267+
page,
268+
"#editorCommentsSidebarResizer"
269+
);
270+
const startX = resizerRect.x + resizerRect.width / 2;
271+
const startY = resizerRect.y + 2;
272+
await page.mouse.move(startX, startY);
273+
await page.mouse.down();
274+
275+
const steps = 20;
276+
await page.mouse.move(startX - extraWidth, startY, { steps });
277+
await page.mouse.up();
278+
279+
const rectAfter = await getRect(page, sidebarSelector);
280+
expect(Math.abs(rectAfter.width - (rect.width + extraWidth)))
281+
.withContext(`In ${browserName}`)
282+
.toBeLessThanOrEqual(1);
283+
expect(Math.abs(rectAfter.x - (rect.x - extraWidth)))
284+
.withContext(`In ${browserName}`)
285+
.toBeLessThanOrEqual(1);
286+
}
287+
})
288+
);
289+
});
290+
});
239291
});

web/app.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,9 @@ const PDFViewerApplication = {
506506
learnMoreUrl: AppOptions.get("commentLearnMoreUrl"),
507507
sidebar:
508508
appConfig.annotationEditorParams?.editorCommentsSidebar || null,
509+
sidebarResizer:
510+
appConfig.annotationEditorParams
511+
?.editorCommentsSidebarResizer || null,
509512
commentsList:
510513
appConfig.annotationEditorParams?.editorCommentsSidebarList ||
511514
null,

web/comment_manager.css

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -234,10 +234,7 @@
234234

235235
#editorCommentsSidebar {
236236
display: flex;
237-
width: 239px;
238237
height: auto;
239-
min-width: 180px;
240-
max-width: 632px;
241238
padding-bottom: 16px;
242239
flex-direction: column;
243240
align-items: flex-start;
@@ -331,8 +328,6 @@
331328
width: auto;
332329
padding: 4px 16px;
333330
gap: 10px;
334-
flex: 1 0 0;
335-
align-self: stretch;
336331
align-items: flex-start;
337332
flex-direction: column;
338333
list-style-type: none;

web/comment_manager.js

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
applyOpacity,
1919
CSSConstants,
2020
findContrastColor,
21+
MathClamp,
2122
noContextMenu,
2223
PDFDateString,
2324
renderRichText,
@@ -56,7 +57,8 @@ class CommentManager {
5657
eventBus,
5758
linkService,
5859
this.#popup,
59-
dateFormat
60+
dateFormat,
61+
ltr
6062
);
6163
this.#popup.sidebar = this.#sidebar;
6264
CommentManager.#hasForcedColors = hasForcedColors;
@@ -160,10 +162,21 @@ class CommentSidebar {
160162

161163
#uiManager = null;
162164

165+
#minWidth = 0;
166+
167+
#maxWidth = 0;
168+
169+
#initialWidth = 0;
170+
171+
#width = 0;
172+
173+
#ltr;
174+
163175
constructor(
164176
{
165177
learnMoreUrl,
166178
sidebar,
179+
sidebarResizer,
167180
commentsList,
168181
commentCount,
169182
sidebarTitle,
@@ -173,7 +186,8 @@ class CommentSidebar {
173186
eventBus,
174187
linkService,
175188
popup,
176-
dateFormat
189+
dateFormat,
190+
ltr
177191
) {
178192
this.#sidebar = sidebar;
179193
this.#sidebarTitle = sidebarTitle;
@@ -184,7 +198,16 @@ class CommentSidebar {
184198
this.#closeButton = closeButton;
185199
this.#popup = popup;
186200
this.#dateFormat = dateFormat;
201+
this.#ltr = ltr;
187202

203+
const style = window.getComputedStyle(sidebar);
204+
this.#minWidth = parseFloat(style.getPropertyValue("--sidebar-min-width"));
205+
this.#maxWidth = parseFloat(style.getPropertyValue("--sidebar-max-width"));
206+
this.#initialWidth = this.#width = parseFloat(
207+
style.getPropertyValue("--sidebar-width")
208+
);
209+
210+
this.#makeSidebarResizable(sidebarResizer);
188211
closeButton.addEventListener("click", () => {
189212
eventBus.dispatch("switchannotationeditormode", {
190213
source: this,
@@ -205,6 +228,63 @@ class CommentSidebar {
205228
this.#sidebar.hidden = true;
206229
}
207230

231+
#makeSidebarResizable(resizer) {
232+
let pointerMoveAC;
233+
const cancelResize = () => {
234+
this.#width = MathClamp(this.#width, this.#minWidth, this.#maxWidth);
235+
this.#sidebar.classList.remove("resizing");
236+
pointerMoveAC?.abort();
237+
pointerMoveAC = null;
238+
};
239+
resizer.addEventListener("pointerdown", e => {
240+
if (pointerMoveAC) {
241+
cancelResize();
242+
return;
243+
}
244+
const { clientX } = e;
245+
stopEvent(e);
246+
let prevX = clientX;
247+
pointerMoveAC = new AbortController();
248+
const { signal } = pointerMoveAC;
249+
const sign = this.#ltr ? -1 : 1;
250+
const sidebar = this.#sidebar;
251+
const sidebarStyle = sidebar.style;
252+
sidebar.classList.add("resizing");
253+
const parentStyle = sidebar.parentElement.style;
254+
parentStyle.minWidth = 0;
255+
window.addEventListener("contextmenu", noContextMenu, { signal });
256+
window.addEventListener(
257+
"pointermove",
258+
ev => {
259+
if (!pointerMoveAC) {
260+
return;
261+
}
262+
stopEvent(ev);
263+
const { clientX: x } = ev;
264+
const newWidth = (this.#width += sign * (x - prevX));
265+
prevX = x;
266+
if (newWidth > this.#maxWidth || newWidth < this.#minWidth) {
267+
return;
268+
}
269+
sidebarStyle.width = `${newWidth.toFixed(3)}px`;
270+
parentStyle.insetInlineStart = `${(this.#initialWidth - newWidth).toFixed(3)}px`;
271+
},
272+
{ signal, capture: true }
273+
);
274+
window.addEventListener("blur", cancelResize, { signal });
275+
window.addEventListener(
276+
"pointerup",
277+
ev => {
278+
if (pointerMoveAC) {
279+
cancelResize();
280+
stopEvent(ev);
281+
}
282+
},
283+
{ signal }
284+
);
285+
});
286+
}
287+
208288
setUIManager(uiManager) {
209289
this.#uiManager = uiManager;
210290
}

web/sidebar.css

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,44 @@
2222
--sidebar-box-shadow:
2323
0 0.25px 0.75px light-dark(rgb(0 0 0 / 0.05), rgb(0 0 0 / 0.2)),
2424
0 2px 6px 0 light-dark(rgb(0 0 0 / 0.1), rgb(0 0 0 / 0.4));
25+
--sidebar-border-radius: 8px;
26+
--sidebar-padding: 5px;
27+
--sidebar-extra-width: 0px;
28+
--sidebar-min-width: 180px;
29+
--sidebar-max-width: 632px;
30+
--sidebar-width: 239px;
2531

2632
@media screen and (forced-colors: active) {
2733
--sidebar-bg-color: Canvas;
2834
--sidebar-border-color: CanvasText;
2935
--sidebar-box-shadow: none;
3036
}
3137

32-
border-radius: 8px;
38+
border-radius: var(--sidebar-border-radius);
3339
box-shadow: var(--sidebar-box-shadow);
3440
border: 1px solid var(--sidebar-border-color);
3541
background-color: var(--sidebar-bg-color);
3642
inset-block-start: calc(100% + var(--doorhanger-height) - 2px);
43+
padding-block: var(--sidebar-padding);
44+
width: var(--sidebar-width);
45+
min-width: var(--sidebar-min-width);
46+
max-width: var(--sidebar-max-width);
47+
48+
.sidebarResizer {
49+
width: 4px;
50+
background-color: transparent;
51+
forced-color-adjust: none;
52+
cursor: ew-resize;
53+
position: absolute;
54+
inset-block: calc(var(--sidebar-padding) + var(--sidebar-border-radius));
55+
}
56+
57+
&.resizing {
58+
cursor: ew-resize;
59+
user-select: none;
60+
61+
:not(.sidebarResizer) {
62+
pointer-events: none;
63+
}
64+
}
3765
}

web/viewer.css

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1084,7 +1084,6 @@ dialog :link {
10841084
}
10851085

10861086
.menuContainer {
1087-
width: 100%;
10881087
height: auto;
10891088
max-height: calc(
10901089
var(--viewer-container-height) - var(--toolbar-height) -

web/viewer.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@
251251
</button>
252252
<div class="editorParamsToolbar hidden menu" id="editorCommentParamsToolbar">
253253
<div id="editorCommentsSidebar" class="menuContainer comment sidebar" role="landmark" aria-labelledby="editorCommentsSidebarHeader">
254+
<div id="editorCommentsSidebarResizer" class="sidebarResizer"></div>
254255
<div id="editorCommentsSidebarHeader" role="heading" aria-level="2">
255256
<span class="commentCount">
256257
<span id="editorCommentsSidebarTitle" data-l10n-id="pdfjs-editor-comments-sidebar-title" data-l10n-args='{ "count": 0 }'></span>

web/viewer.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,9 @@ function getViewerConfiguration() {
258258
editorCommentsSidebarList: document.getElementById(
259259
"editorCommentsSidebarList"
260260
),
261+
editorCommentsSidebarResizer: document.getElementById(
262+
"editorCommentsSidebarResizer"
263+
),
261264
editorFreeTextFontSize: document.getElementById("editorFreeTextFontSize"),
262265
editorFreeTextColor: document.getElementById("editorFreeTextColor"),
263266
editorInkColor: document.getElementById("editorInkColor"),

0 commit comments

Comments
 (0)