Skip to content
Open
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
3 changes: 3 additions & 0 deletions src/viewer/annotation-layer.css
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@

.annotation-layer .linkAnnotation {
pointer-events: auto;
/* PDF.js adds inline borders for LaTeX/hyperref links. Keep the hit areas
without drawing boxes around citations and footnote markers. */
border: 0 !important;
}

.annotation-layer .linkAnnotation > a {
Expand Down
6 changes: 3 additions & 3 deletions src/viewer/navigation/minimap.css
Original file line number Diff line number Diff line change
Expand Up @@ -210,11 +210,11 @@ html.minimap-disabled body::-webkit-scrollbar-thumb {
height: 100%;
}

:is(.minimap-local, .minimap-local-active) .minimap-page {
.minimap-local .minimap-page {
z-index: 1;
}

:is(.minimap-local, .minimap-local-active) .minimap-local-thumbnail {
.minimap-local .minimap-local-thumbnail {
display: block;
}

Expand Down Expand Up @@ -256,7 +256,7 @@ html.minimap-disabled body::-webkit-scrollbar-thumb {
filter: invert(1) brightness(2.4) contrast(1.1) invert(1);
}

:is(.minimap-local, .minimap-local-active) .minimap-strip {
.minimap-local .minimap-strip {
opacity: 1;
}

Expand Down
17 changes: 5 additions & 12 deletions src/viewer/navigation/minimap.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,8 @@ function minimapMode() {
return document.documentElement.classList.contains("minimap-local") ? "local" : "overview";
}

function displayedMinimapMode(widthScaledHeight, trackHeight) {
return minimapMode() === "local" || widthScaledHeight <= trackHeight ? "local" : "overview";
}

function localMinimapActive() {
return minimapMode() === "local" ||
document.documentElement.classList.contains("minimap-local-active");
return minimapMode() === "local";
}

function setMinimapAccessibility() {
Expand Down Expand Up @@ -295,13 +290,11 @@ function syncMinimap() {
const widthScale = thumbnailWidth / pageWidth;
const widthScaledHeights = pages.map((page) => page.getBoundingClientRect().height * widthScale);
const widthScaledHeight = widthScaledHeights.reduce((total, height) => total + height, 0);
const displayMode = displayedMinimapMode(widthScaledHeight, trackHeight);
document.documentElement.classList.toggle(
"minimap-local-active",
displayMode === "local" && minimapMode() !== "local",
);
const displayMode = minimapMode();
// Overview spans the full track, including short PDFs on tall monitors.
// Local mode retains thumbnails at their natural width-scaled height.
const heightCompression =
displayMode === "overview" && widthScaledHeight > trackHeight
displayMode === "overview" && widthScaledHeight > 0
? trackHeight / widthScaledHeight
: 1;
const scale = widthScale * heightCompression;
Expand Down
52 changes: 23 additions & 29 deletions tests/minimap.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -93,48 +93,42 @@ test('switching to local view keeps thumbnails unclipped at the middle and end',
}
});

test('short overview documents temporarily use local navigator sizing until the viewport needs compression', () => {
const f = fixture(2);
assert.ok(!f.classes.has('minimap-local'));
assert.ok(f.classes.has('minimap-local-active'));
assert.equal(f.storedValues.get('pdf-viewer-minimap-mode'), undefined);
assert.equal(parseFloat(f.tiles[0].style.top), 0);
assert.equal(parseFloat(f.tiles[0].style.height), 112);
assert.ok(parseFloat(f.tiles[1].style.top) + 112 < f.track.clientHeight);

f.window.innerHeight = 200;
f.track.clientHeight = 148;
f.sync();
assert.ok(!f.classes.has('minimap-local-active'));
assert.ok(parseFloat(f.tiles[0].style.height) < 112);
assert.ok(Math.abs(
parseFloat(f.tiles[1].style.top) + parseFloat(f.tiles[1].style.height) - f.track.clientHeight,
) < 0.00001);

f.window.innerHeight = 1600;
f.track.clientHeight = 1548;
f.sync();
assert.ok(f.classes.has('minimap-local-active'));
assert.equal(parseFloat(f.tiles[0].style.height), 112);
test('short overview documents fill the track on tall monitors and after resizing', () => {
for (const count of [1, 2, 9]) {
const f = fixture(count, 1900);
for (const height of [1900, 200, 1600]) {
f.window.innerHeight = height;
f.track.clientHeight = height - 52;
f.sync();
const last = f.tiles.at(-1);
const lastBottom = parseFloat(last.style.top) + parseFloat(last.style.height);
assert.ok(Math.abs(lastBottom - f.track.clientHeight) < 0.00001);
assert.ok(!f.classes.has('minimap-local'));
assert.equal(f.storedValues.get('pdf-viewer-minimap-mode'), undefined);
assert.equal(vm.runInContext('mapOffset', f.context), 0);
vm.runInContext('scrollFromViewportTop(mapHeight - viewportHeight)', f.context);
assert.equal(f.window.scrollY, Math.max(count * 1420 - height, 0));
}
}
});

test('short minimaps gradually fade their document-colored tail to half opacity', () => {
const f = fixture(2);
test('explicit local mode keeps natural thumbnail heights and fades the unused tail', () => {
const f = fixture(2, 1900, { 'pdf-viewer-minimap-mode': 'local' });
assert.ok(f.classes.has('minimap-local'));
assert.equal(f.track.style['--minimap-content-height'], '224px');
assert.equal(f.track.style['--minimap-tail-fade-height'], '112px');
assert.match(styles, /\.minimap::after\s*\{[\s\S]*?top:\s*min\(var\(--minimap-content-height, 100%\), 100%\)/);
assert.match(styles, /\.minimap::after\s*\{[\s\S]*?right:\s*8px;[\s\S]*?left:\s*8px;/);
assert.match(styles, /\.minimap::after\s*\{[\s\S]*?background:\s*linear-gradient\(\s*to bottom,\s*var\(--page-bg\) 0,\s*color-mix\(in srgb, var\(--page-bg\) 50%, transparent\)\s*max\(100%, var\(--minimap-tail-fade-height, 0px\)\)\s*\)/);
assert.match(styles, /\.minimap-pages\s*\{[\s\S]*?z-index:\s*1/);

f.window.innerHeight = 200;
f.track.clientHeight = 148;
f.sync();
assert.equal(parseFloat(f.tiles[0].style.height), 112);
assert.equal(f.track.style['--minimap-content-height'], '148px');
});

test('minimap packs page thumbnails without viewer gaps', () => {
const f = fixture(3);
test('local minimap packs page thumbnails without viewer gaps', () => {
const f = fixture(3, 900, { 'pdf-viewer-minimap-mode': 'local' });
assert.equal(parseFloat(f.tiles[0].style.top), 0);
assert.equal(parseFloat(f.tiles[1].style.top), 112);
assert.equal(parseFloat(f.tiles[2].style.top), 224);
Expand Down
Loading