Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 1 addition & 10 deletions gulpfile.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1203,16 +1203,7 @@ gulp.task(
function buildComponents(defines, dir) {
fs.rmSync(dir, { recursive: true, force: true });

const COMPONENTS_IMAGES = [
"web/images/annotation-*.svg",
"web/images/loading-icon.gif",
"web/images/altText_*.svg",
"web/images/editor-toolbar-*.svg",
"web/images/messageBar_*.svg",
"web/images/toolbarButton-{editorHighlight,menuArrow}.svg",
"web/images/cursor-*.svg",
"web/images/comment-*.svg",
];
const COMPONENTS_IMAGES = ["web/images/*.svg", "web/images/*.gif"];

return ordered([
createComponentsBundle(defines).pipe(gulp.dest(dir)),
Expand Down
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

71 changes: 71 additions & 0 deletions test/integration/reorganize_pages_spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ import {
closePages,
createPromise,
dragAndDrop,
getAnnotationSelector,
getRect,
getThumbnailSelector,
loadAndWait,
scrollIntoView,
waitForDOMMutation,
} from "./test_utils.mjs";

Expand Down Expand Up @@ -415,4 +417,73 @@ describe("Reorganize Pages View", () => {
);
});
});

describe("Links and outlines", () => {
let pages;

beforeEach(async () => {
pages = await loadAndWait(
"page_with_number_and_link.pdf",
"#viewsManagerToggleButton",
"page-fit",
null,
{ enableSplitMerge: true }
);
});

afterEach(async () => {
await closePages(pages);
});

it("should check that link is updated after moving pages", async () => {
await Promise.all(
pages.map(async ([browserName, page]) => {
await waitForThumbnailVisible(page, 1);
await movePages(page, [2], 10);
await scrollIntoView(page, getAnnotationSelector("107R"));
await page.click(getAnnotationSelector("107R"));
await page.waitForSelector(
".page[data-page-number='10'] + .page[data-page-number='2']",
{
visible: true,
}
);

const currentPage = await page.$eval(
"#pageNumber",
el => el.valueAsNumber
);
expect(currentPage).withContext(`In ${browserName}`).toBe(10);
})
);
});

it("should check that outlines are updated after moving pages", async () => {
await Promise.all(
pages.map(async ([browserName, page]) => {
await waitForThumbnailVisible(page, 1);
await movePages(page, [2, 4], 10);

await page.click("#viewsManagerSelectorButton");
await page.click("#outlinesViewMenu");
await page.waitForSelector("#outlinesView", { visible: true });

await page.click("#outlinesView .treeItem:nth-child(2)");
await page.waitForSelector(
".page[data-page-number='10'] + .page[data-page-number='2']",
{
visible: true,
}
);

const currentPage = await page.$eval(
"#pageNumber",
el => el.valueAsNumber
);
// 9 because 2 and 4 were moved after page 10.
expect(currentPage).withContext(`In ${browserName}`).toBe(9);
})
);
});
});
});
1 change: 1 addition & 0 deletions test/pdfs/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -869,3 +869,4 @@
!bomb_giant.pdf
!bug2009627.pdf
!page_with_number.pdf
!page_with_number_and_link.pdf
Binary file added test/pdfs/page_with_number_and_link.pdf
Binary file not shown.
11 changes: 11 additions & 0 deletions web/menu.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@
* limitations under the License.
*/

button.hasPopupMenu {
&[aria-expanded="true"] + menu {
visibility: visible;
}

&[aria-expanded="false"] + menu {
visibility: hidden;
}
}

.popupMenu {
--menuitem-checkmark-icon: url(images/checkmark.svg);
--menu-mark-icon-size: 0;
Expand Down Expand Up @@ -75,6 +85,7 @@
top: 1px;
margin: 0;
padding: 5px;
box-sizing: border-box;

background: var(--menu-bg);
background-blend-mode: var(--menu-background-blend-mode);
Expand Down
39 changes: 27 additions & 12 deletions web/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ class Menu {
return;
}
const menu = this.#menu;
menu.classList.toggle("hidden", true);
this.#triggeringButton.ariaExpanded = "false";
this.#openMenuAC.abort();
this.#openMenuAC = null;
Expand All @@ -82,7 +81,6 @@ class Menu {
}

const menu = this.#menu;
menu.classList.toggle("hidden", false);
this.#triggeringButton.ariaExpanded = "true";
this.#openMenuAC = new AbortController();
const signal = AbortSignal.any([
Expand Down Expand Up @@ -137,6 +135,13 @@ class Menu {
.focus();
stopEvent(e);
break;
default:
const char = e.key.toLocaleLowerCase();
this.#goToNextItem(e.target, true, item =>
item.textContent.trim().toLowerCase().startsWith(char)
);
stopEvent(e);
break;
}
},
{ signal, capture: true }
Expand All @@ -148,32 +153,38 @@ class Menu {
});
this.#triggeringButton.addEventListener(
"keydown",
ev => {
if (!this.#openMenuAC) {
return;
}
switch (ev.key) {
e => {
switch (e.key) {
case " ":
case "Enter":
case "ArrowDown":
case "Home":
if (!this.#openMenuAC) {
this.#triggeringButton.click();
}
this.#menuItems
.find(
item => !item.disabled && !item.classList.contains("hidden")
)
.focus();
stopEvent(ev);
stopEvent(e);
break;
case "ArrowUp":
case "End":
if (!this.#openMenuAC) {
this.#triggeringButton.click();
}
this.#menuItems
.findLast(
item => !item.disabled && !item.classList.contains("hidden")
)
.focus();
stopEvent(ev);
stopEvent(e);
break;
case "Escape":
this.#closeMenu();
stopEvent(ev);
stopEvent(e);
break;
}
},
{ signal }
Expand All @@ -185,7 +196,7 @@ class Menu {
* @param {HTMLElement} element
* @param {boolean} forward
*/
#goToNextItem(element, forward) {
#goToNextItem(element, forward, check = () => true) {
const index =
this.#lastIndex === -1
? this.#menuItems.indexOf(element)
Expand All @@ -198,7 +209,11 @@ class Menu {
i = (i + increment) % len
) {
const menuItem = this.#menuItems[i];
if (!menuItem.disabled && !menuItem.classList.contains("hidden")) {
if (
!menuItem.disabled &&
!menuItem.classList.contains("hidden") &&
check(menuItem)
) {
menuItem.focus();
this.#lastIndex = i;
break;
Expand Down
27 changes: 17 additions & 10 deletions web/pdf_link_service.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
/** @typedef {import("./event_utils").EventBus} EventBus */
/** @typedef {import("./interfaces").IPDFLinkService} IPDFLinkService */

import { PagesMapper, parseQueryString } from "./ui_utils.js";
import { isValidExplicitDest } from "pdfjs-lib";
import { parseQueryString } from "./ui_utils.js";

const DEFAULT_LINK_REL = "noopener noreferrer nofollow";

Expand Down Expand Up @@ -50,6 +50,8 @@ const LinkTarget = {
class PDFLinkService {
externalLinkEnabled = true;

#pagesMapper = PagesMapper.instance;

/**
* @param {PDFLinkServiceOptions} options
*/
Expand Down Expand Up @@ -138,7 +140,7 @@ class PDFLinkService {
if (!this.pdfDocument) {
return;
}
let namedDest, explicitDest, pageNumber;
let namedDest, explicitDest, pageId;
if (typeof dest === "string") {
namedDest = dest;
explicitDest = await this.pdfDocument.getDestination(dest);
Expand All @@ -156,13 +158,13 @@ class PDFLinkService {
const [destRef] = explicitDest;

if (destRef && typeof destRef === "object") {
pageNumber = this.pdfDocument.cachedPageNumber(destRef);
pageId = this.pdfDocument.cachedPageNumber(destRef);

if (!pageNumber) {
if (!pageId) {
// Fetch the page reference if it's not yet available. This could
// only occur during loading, before all pages have been resolved.
try {
pageNumber = (await this.pdfDocument.getPageIndex(destRef)) + 1;
pageId = (await this.pdfDocument.getPageIndex(destRef)) + 1;
} catch {
console.error(
`goToDestination: "${destRef}" is not a valid page reference, for dest="${dest}".`
Expand All @@ -171,20 +173,25 @@ class PDFLinkService {
}
}
} else if (Number.isInteger(destRef)) {
pageNumber = destRef + 1;
pageId = destRef + 1;
}
if (!pageNumber || pageNumber < 1 || pageNumber > this.pagesCount) {
if (!pageId || pageId < 1 || pageId > this.pagesCount) {
console.error(
`goToDestination: "${pageNumber}" is not a valid page number, for dest="${dest}".`
`goToDestination: "${pageId}" is not a valid page number, for dest="${dest}".`
);
return;
}

const pageNumber = this.#pagesMapper.getPageNumber(pageId);
if (pageNumber === null) {
return;
}

if (this.pdfHistory) {
// Update the browser history before scrolling the new destination into
// view, to be able to accurately capture the current document position.
this.pdfHistory.pushCurrentPosition();
this.pdfHistory.push({ namedDest, explicitDest, pageNumber });
this.pdfHistory.push({ namedDest, explicitDest, pageNumber: pageId });
}

this.pdfViewer.scrollPageIntoView({
Expand All @@ -197,7 +204,7 @@ class PDFLinkService {
this.eventBus._on(
"textlayerrendered",
evt => {
if (evt.pageNumber === pageNumber) {
if (evt.pageNumber === pageId) {
evt.source.textLayer.div.focus();
ac.abort();
}
Expand Down
9 changes: 5 additions & 4 deletions web/viewer.html
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@
<div id="viewsManagerTitle">
<div id="viewsManagerSelector">
<button
class="toolbarButton viewsManagerButton"
class="toolbarButton viewsManagerButton hasPopupMenu"
type="button"
id="viewsManagerSelectorButton"
tabindex="0"
Expand All @@ -141,7 +141,7 @@
>
<span data-l10n-id="pdfjs-views-manager-view-selector-button-label"></span>
</button>
<menu id="viewsManagerSelectorOptions" role="listbox" class="popupMenu hidden withMark">
<menu id="viewsManagerSelectorOptions" role="listbox" class="popupMenu withMark">
<li>
<button id="thumbnailsViewMenu" role="option" type="button" tabindex="-1">
<span data-l10n-id="pdfjs-views-manager-pages-option-label"></span>
Expand Down Expand Up @@ -196,15 +196,16 @@
<div id="actionSelector">
<button
id="viewsManagerStatusActionButton"
class="viewsManagerButton"
class="viewsManagerButton hasPopupMenu"
type="button"
tabindex="0"
aria-haspopup="menu"
aria-controls="viewsManagerStatusActionOptions"
aria-expanded="false"
>
<span data-l10n-id="pdfjs-views-manager-pages-status-action-button-label"></span>
</button>
<menu id="viewsManagerStatusActionOptions" class="popupMenu hidden">
<menu id="viewsManagerStatusActionOptions" class="popupMenu">
<li>
<button id="viewsManagerStatusActionCopy" class="noIcon" role="menuitem" type="button" tabindex="0">
<span data-l10n-id="pdfjs-views-manager-pages-status-copy-button-label"></span>
Expand Down
6 changes: 4 additions & 2 deletions web/views_manager.css
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@

#actionSelector {
height: 32px;
min-width: 115px;
width: auto;
display: block;

Expand Down Expand Up @@ -425,8 +426,9 @@
}
}

> .contextMenu {
min-width: 115px;
> .popupMenu {
width: auto;
z-index: 1;
}
}
}
Expand Down