Merge pull request #20303 from calixteman/bug1990544
[Editor] Make the comment sidebar resizable (bug 1990544)
This commit is contained in:
commit
007148e2c5
@ -29,6 +29,7 @@ import {
|
||||
|
||||
const switchToHighlight = switchToEditor.bind(null, "Highlight");
|
||||
const switchToStamp = switchToEditor.bind(null, "Stamp");
|
||||
const switchToComment = switchToEditor.bind(null, "Comment");
|
||||
|
||||
describe("Comment", () => {
|
||||
describe("Comment edit dialog must be visible in ltr", () => {
|
||||
@ -236,4 +237,55 @@ describe("Comment", () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Comment sidebar", () => {
|
||||
let pages;
|
||||
|
||||
beforeEach(async () => {
|
||||
pages = await loadAndWait(
|
||||
"comments.pdf",
|
||||
".annotationEditorLayer",
|
||||
"page-width",
|
||||
null,
|
||||
{ enableComment: true }
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await closePages(pages);
|
||||
});
|
||||
|
||||
it("must check that the comment sidebar is resizable", async () => {
|
||||
await Promise.all(
|
||||
pages.map(async ([browserName, page]) => {
|
||||
await switchToComment(page);
|
||||
|
||||
const sidebarSelector = "#editorCommentParamsToolbar";
|
||||
for (const extraWidth of [100, -100]) {
|
||||
const rect = await getRect(page, sidebarSelector);
|
||||
const resizerRect = await getRect(
|
||||
page,
|
||||
"#editorCommentsSidebarResizer"
|
||||
);
|
||||
const startX = resizerRect.x + resizerRect.width / 2;
|
||||
const startY = resizerRect.y + 2;
|
||||
await page.mouse.move(startX, startY);
|
||||
await page.mouse.down();
|
||||
|
||||
const steps = 20;
|
||||
await page.mouse.move(startX - extraWidth, startY, { steps });
|
||||
await page.mouse.up();
|
||||
|
||||
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);
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -506,6 +506,9 @@ const PDFViewerApplication = {
|
||||
learnMoreUrl: AppOptions.get("commentLearnMoreUrl"),
|
||||
sidebar:
|
||||
appConfig.annotationEditorParams?.editorCommentsSidebar || null,
|
||||
sidebarResizer:
|
||||
appConfig.annotationEditorParams
|
||||
?.editorCommentsSidebarResizer || null,
|
||||
commentsList:
|
||||
appConfig.annotationEditorParams?.editorCommentsSidebarList ||
|
||||
null,
|
||||
|
||||
@ -234,10 +234,7 @@
|
||||
|
||||
#editorCommentsSidebar {
|
||||
display: flex;
|
||||
width: 239px;
|
||||
height: auto;
|
||||
min-width: 180px;
|
||||
max-width: 632px;
|
||||
padding-bottom: 16px;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
@ -331,8 +328,6 @@
|
||||
width: auto;
|
||||
padding: 4px 16px;
|
||||
gap: 10px;
|
||||
flex: 1 0 0;
|
||||
align-self: stretch;
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
list-style-type: none;
|
||||
|
||||
@ -18,6 +18,7 @@ import {
|
||||
applyOpacity,
|
||||
CSSConstants,
|
||||
findContrastColor,
|
||||
MathClamp,
|
||||
noContextMenu,
|
||||
PDFDateString,
|
||||
renderRichText,
|
||||
@ -56,7 +57,8 @@ class CommentManager {
|
||||
eventBus,
|
||||
linkService,
|
||||
this.#popup,
|
||||
dateFormat
|
||||
dateFormat,
|
||||
ltr
|
||||
);
|
||||
this.#popup.sidebar = this.#sidebar;
|
||||
CommentManager.#hasForcedColors = hasForcedColors;
|
||||
@ -160,10 +162,21 @@ class CommentSidebar {
|
||||
|
||||
#uiManager = null;
|
||||
|
||||
#minWidth = 0;
|
||||
|
||||
#maxWidth = 0;
|
||||
|
||||
#initialWidth = 0;
|
||||
|
||||
#width = 0;
|
||||
|
||||
#ltr;
|
||||
|
||||
constructor(
|
||||
{
|
||||
learnMoreUrl,
|
||||
sidebar,
|
||||
sidebarResizer,
|
||||
commentsList,
|
||||
commentCount,
|
||||
sidebarTitle,
|
||||
@ -173,7 +186,8 @@ class CommentSidebar {
|
||||
eventBus,
|
||||
linkService,
|
||||
popup,
|
||||
dateFormat
|
||||
dateFormat,
|
||||
ltr
|
||||
) {
|
||||
this.#sidebar = sidebar;
|
||||
this.#sidebarTitle = sidebarTitle;
|
||||
@ -184,7 +198,16 @@ class CommentSidebar {
|
||||
this.#closeButton = closeButton;
|
||||
this.#popup = popup;
|
||||
this.#dateFormat = dateFormat;
|
||||
this.#ltr = ltr;
|
||||
|
||||
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,
|
||||
@ -205,6 +228,63 @@ class CommentSidebar {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -22,6 +22,12 @@
|
||||
--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-border-radius: 8px;
|
||||
--sidebar-padding: 5px;
|
||||
--sidebar-extra-width: 0px;
|
||||
--sidebar-min-width: 180px;
|
||||
--sidebar-max-width: 632px;
|
||||
--sidebar-width: 239px;
|
||||
|
||||
@media screen and (forced-colors: active) {
|
||||
--sidebar-bg-color: Canvas;
|
||||
@ -29,9 +35,31 @@
|
||||
--sidebar-box-shadow: none;
|
||||
}
|
||||
|
||||
border-radius: 8px;
|
||||
border-radius: var(--sidebar-border-radius);
|
||||
box-shadow: var(--sidebar-box-shadow);
|
||||
border: 1px solid var(--sidebar-border-color);
|
||||
background-color: var(--sidebar-bg-color);
|
||||
inset-block-start: calc(100% + var(--doorhanger-height) - 2px);
|
||||
padding-block: var(--sidebar-padding);
|
||||
width: var(--sidebar-width);
|
||||
min-width: var(--sidebar-min-width);
|
||||
max-width: var(--sidebar-max-width);
|
||||
|
||||
.sidebarResizer {
|
||||
width: 4px;
|
||||
background-color: transparent;
|
||||
forced-color-adjust: none;
|
||||
cursor: ew-resize;
|
||||
position: absolute;
|
||||
inset-block: calc(var(--sidebar-padding) + var(--sidebar-border-radius));
|
||||
}
|
||||
|
||||
&.resizing {
|
||||
cursor: ew-resize;
|
||||
user-select: none;
|
||||
|
||||
:not(.sidebarResizer) {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1084,7 +1084,6 @@ dialog :link {
|
||||
}
|
||||
|
||||
.menuContainer {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
max-height: calc(
|
||||
var(--viewer-container-height) - var(--toolbar-height) -
|
||||
|
||||
@ -251,6 +251,7 @@ See https://github.com/adobe-type-tools/cmap-resources
|
||||
</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="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>
|
||||
|
||||
@ -258,6 +258,9 @@ function getViewerConfiguration() {
|
||||
editorCommentsSidebarList: document.getElementById(
|
||||
"editorCommentsSidebarList"
|
||||
),
|
||||
editorCommentsSidebarResizer: document.getElementById(
|
||||
"editorCommentsSidebarResizer"
|
||||
),
|
||||
editorFreeTextFontSize: document.getElementById("editorFreeTextFontSize"),
|
||||
editorFreeTextColor: document.getElementById("editorFreeTextColor"),
|
||||
editorInkColor: document.getElementById("editorInkColor"),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user