[Editor] Make the comment sidebar resizable (bug 1990544)
This commit is contained in:
parent
8448d08345
commit
a372294ea3
@ -29,6 +29,7 @@ import {
|
|||||||
|
|
||||||
const switchToHighlight = switchToEditor.bind(null, "Highlight");
|
const switchToHighlight = switchToEditor.bind(null, "Highlight");
|
||||||
const switchToStamp = switchToEditor.bind(null, "Stamp");
|
const switchToStamp = switchToEditor.bind(null, "Stamp");
|
||||||
|
const switchToComment = switchToEditor.bind(null, "Comment");
|
||||||
|
|
||||||
describe("Comment", () => {
|
describe("Comment", () => {
|
||||||
describe("Comment edit dialog must be visible in ltr", () => {
|
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"),
|
learnMoreUrl: AppOptions.get("commentLearnMoreUrl"),
|
||||||
sidebar:
|
sidebar:
|
||||||
appConfig.annotationEditorParams?.editorCommentsSidebar || null,
|
appConfig.annotationEditorParams?.editorCommentsSidebar || null,
|
||||||
|
sidebarResizer:
|
||||||
|
appConfig.annotationEditorParams
|
||||||
|
?.editorCommentsSidebarResizer || null,
|
||||||
commentsList:
|
commentsList:
|
||||||
appConfig.annotationEditorParams?.editorCommentsSidebarList ||
|
appConfig.annotationEditorParams?.editorCommentsSidebarList ||
|
||||||
null,
|
null,
|
||||||
|
|||||||
@ -234,10 +234,7 @@
|
|||||||
|
|
||||||
#editorCommentsSidebar {
|
#editorCommentsSidebar {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 239px;
|
|
||||||
height: auto;
|
height: auto;
|
||||||
min-width: 180px;
|
|
||||||
max-width: 632px;
|
|
||||||
padding-bottom: 16px;
|
padding-bottom: 16px;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
@ -331,8 +328,6 @@
|
|||||||
width: auto;
|
width: auto;
|
||||||
padding: 4px 16px;
|
padding: 4px 16px;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
flex: 1 0 0;
|
|
||||||
align-self: stretch;
|
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import {
|
|||||||
applyOpacity,
|
applyOpacity,
|
||||||
CSSConstants,
|
CSSConstants,
|
||||||
findContrastColor,
|
findContrastColor,
|
||||||
|
MathClamp,
|
||||||
noContextMenu,
|
noContextMenu,
|
||||||
PDFDateString,
|
PDFDateString,
|
||||||
renderRichText,
|
renderRichText,
|
||||||
@ -56,7 +57,8 @@ class CommentManager {
|
|||||||
eventBus,
|
eventBus,
|
||||||
linkService,
|
linkService,
|
||||||
this.#popup,
|
this.#popup,
|
||||||
dateFormat
|
dateFormat,
|
||||||
|
ltr
|
||||||
);
|
);
|
||||||
this.#popup.sidebar = this.#sidebar;
|
this.#popup.sidebar = this.#sidebar;
|
||||||
CommentManager.#hasForcedColors = hasForcedColors;
|
CommentManager.#hasForcedColors = hasForcedColors;
|
||||||
@ -160,10 +162,21 @@ class CommentSidebar {
|
|||||||
|
|
||||||
#uiManager = null;
|
#uiManager = null;
|
||||||
|
|
||||||
|
#minWidth = 0;
|
||||||
|
|
||||||
|
#maxWidth = 0;
|
||||||
|
|
||||||
|
#initialWidth = 0;
|
||||||
|
|
||||||
|
#width = 0;
|
||||||
|
|
||||||
|
#ltr;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
{
|
{
|
||||||
learnMoreUrl,
|
learnMoreUrl,
|
||||||
sidebar,
|
sidebar,
|
||||||
|
sidebarResizer,
|
||||||
commentsList,
|
commentsList,
|
||||||
commentCount,
|
commentCount,
|
||||||
sidebarTitle,
|
sidebarTitle,
|
||||||
@ -173,7 +186,8 @@ class CommentSidebar {
|
|||||||
eventBus,
|
eventBus,
|
||||||
linkService,
|
linkService,
|
||||||
popup,
|
popup,
|
||||||
dateFormat
|
dateFormat,
|
||||||
|
ltr
|
||||||
) {
|
) {
|
||||||
this.#sidebar = sidebar;
|
this.#sidebar = sidebar;
|
||||||
this.#sidebarTitle = sidebarTitle;
|
this.#sidebarTitle = sidebarTitle;
|
||||||
@ -184,7 +198,16 @@ class CommentSidebar {
|
|||||||
this.#closeButton = closeButton;
|
this.#closeButton = closeButton;
|
||||||
this.#popup = popup;
|
this.#popup = popup;
|
||||||
this.#dateFormat = dateFormat;
|
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", () => {
|
closeButton.addEventListener("click", () => {
|
||||||
eventBus.dispatch("switchannotationeditormode", {
|
eventBus.dispatch("switchannotationeditormode", {
|
||||||
source: this,
|
source: this,
|
||||||
@ -205,6 +228,63 @@ class CommentSidebar {
|
|||||||
this.#sidebar.hidden = true;
|
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) {
|
||||||
this.#uiManager = uiManager;
|
this.#uiManager = uiManager;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,6 +22,12 @@
|
|||||||
--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-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) {
|
@media screen and (forced-colors: active) {
|
||||||
--sidebar-bg-color: Canvas;
|
--sidebar-bg-color: Canvas;
|
||||||
@ -29,9 +35,31 @@
|
|||||||
--sidebar-box-shadow: none;
|
--sidebar-box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
border-radius: 8px;
|
border-radius: var(--sidebar-border-radius);
|
||||||
box-shadow: var(--sidebar-box-shadow);
|
box-shadow: var(--sidebar-box-shadow);
|
||||||
border: 1px solid var(--sidebar-border-color);
|
border: 1px solid var(--sidebar-border-color);
|
||||||
background-color: var(--sidebar-bg-color);
|
background-color: var(--sidebar-bg-color);
|
||||||
inset-block-start: calc(100% + var(--doorhanger-height) - 2px);
|
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 {
|
.menuContainer {
|
||||||
width: 100%;
|
|
||||||
height: auto;
|
height: auto;
|
||||||
max-height: calc(
|
max-height: calc(
|
||||||
var(--viewer-container-height) - var(--toolbar-height) -
|
var(--viewer-container-height) - var(--toolbar-height) -
|
||||||
|
|||||||
@ -251,6 +251,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="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>
|
||||||
|
|||||||
@ -258,6 +258,9 @@ function getViewerConfiguration() {
|
|||||||
editorCommentsSidebarList: document.getElementById(
|
editorCommentsSidebarList: document.getElementById(
|
||||||
"editorCommentsSidebarList"
|
"editorCommentsSidebarList"
|
||||||
),
|
),
|
||||||
|
editorCommentsSidebarResizer: document.getElementById(
|
||||||
|
"editorCommentsSidebarResizer"
|
||||||
|
),
|
||||||
editorFreeTextFontSize: document.getElementById("editorFreeTextFontSize"),
|
editorFreeTextFontSize: document.getElementById("editorFreeTextFontSize"),
|
||||||
editorFreeTextColor: document.getElementById("editorFreeTextColor"),
|
editorFreeTextColor: document.getElementById("editorFreeTextColor"),
|
||||||
editorInkColor: document.getElementById("editorInkColor"),
|
editorInkColor: document.getElementById("editorInkColor"),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user