Skip to content

Commit

Permalink
EPUB: Support image zoom (#151)
Browse files Browse the repository at this point in the history
  • Loading branch information
AbeJellinek authored Nov 21, 2024
1 parent 88925ed commit 3b27121
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 7 deletions.
5 changes: 5 additions & 0 deletions src/common/components/reader-ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ function View(props) {
props.onFindPrevious(primary);
}

function handleOverlayPopupClose() {
props.onCloseOverlayPopup(primary);
}

return (
<div className={name}>
<div
Expand Down Expand Up @@ -71,6 +75,7 @@ function View(props) {
params={state[name + 'ViewOverlayPopup']}
onOpenLink={props.onOpenLink}
onNavigate={props.onNavigate}
onClose={handleOverlayPopupClose}
/>
}
{state[name + 'ViewFindState'].popupOpen &&
Expand Down
16 changes: 16 additions & 0 deletions src/common/components/view-popup/overlay-popup/image-popup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';
import { useIntl } from "react-intl";

function ImagePopup({ params, onClose }) {
let { src, title, alt } = params;

const intl = useIntl();

return (
<div className="image-popup" role="button" aria-label={intl.formatMessage({ id: 'pdfReader.zoomOut' })} onClick={onClose}>
<img src={src} title={title} alt={alt} />
</div>
);
}

export default ImagePopup;
4 changes: 4 additions & 0 deletions src/common/components/view-popup/overlay-popup/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import LinkPopup from './link-popup';
import FootnotePopup from './footnote-popup';
import ReferencePopup from './reference/reference-popup';
import CitationPopup from './reference/citation-popup';
import ImagePopup from "./image-popup";


function OverlayPopup(props) {
Expand All @@ -22,6 +23,9 @@ function OverlayPopup(props) {
else if (props.params.type === 'reference') {
return <ReferencePopup {...props}/>;
}
else if (props.params.type === 'image') {
return <ImagePopup {...props}/>;
}
}

export default OverlayPopup;
5 changes: 5 additions & 0 deletions src/common/reader.js
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ class Reader {
onFindPrevious={this.findPrevious.bind(this)}
onToggleContextPane={this._onToggleContextPane}
onChangeTextSelectionAnnotationMode={this.setTextSelectionAnnotationMode.bind(this)}
onCloseOverlayPopup={this._handleOverlayPopupClose.bind(this)}
ref={this._readerRef}
tools={this._tools}
/>
Expand Down Expand Up @@ -682,6 +683,10 @@ class Reader {
this._updateState({ [primary ? 'primaryViewFindState' : 'secondaryViewFindState']: params });
}

_handleOverlayPopupClose(primary) {
this._updateState({ [primary ? 'primaryViewOverlayPopup' : 'secondaryViewOverlayPopup']: null });
}

setTextSelectionAnnotationMode(mode) {
if (!['highlight', 'underline'].includes(mode)) {
throw new Error(`Invalid 'textSelectionAnnotationMode' value '${mode}'`);
Expand Down
15 changes: 15 additions & 0 deletions src/common/stylesheets/components/_view-popup.scss
Original file line number Diff line number Diff line change
Expand Up @@ -301,3 +301,18 @@
max-height: 300px;
}
}

.image-popup {
z-index: 1;
padding: 5px;
position: absolute;
inset: 0;
background: var(--color-background);
cursor: zoom-out;

img {
object-fit: contain;
width: 100%;
height: 100%;
}
}
26 changes: 19 additions & 7 deletions src/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,15 +122,27 @@ export type SelectionPopupParams<A extends Annotation = Annotation> = {
annotation?: NewAnnotation<A> | null;
}


export type OverlayPopupParams = {
type: string;
url?: string;
css?: string;
content?: string;
type FootnotePopupParams = {
type: 'footnote';
content: string;
css: string;
rect: ArrayRect;
ref: Node;
};
}

type LinkPopupParams = {
type: 'link';
url: string;
}

type ImagePopupParams = {
type: 'image';
src: string;
title?: string;
alt?: string;
}

export type OverlayPopupParams = FootnotePopupParams | LinkPopupParams | ImagePopupParams

export type ArrayRect = [left: number, top: number, right: number, bottom: number];

Expand Down
20 changes: 20 additions & 0 deletions src/dom/epub/epub-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,26 @@ class EPUBView extends DOMView<EPUBViewState, EPUBViewData> {
this.navigate({ href });
}

protected override _handlePointerDown(event: PointerEvent) {
super._handlePointerDown(event);

if (event.defaultPrevented) {
return;
}

let target = event.target as Element;
if (target.tagName === 'IMG' && target.classList.contains('clickable-image')) {
let img = target as HTMLImageElement;
this._options.onSetOverlayPopup({
type: 'image',
src: img.currentSrc || img.src,
title: img.title,
alt: img.alt,
});
event.preventDefault();
}
}

protected override _handleKeyDown(event: KeyboardEvent) {
let { key } = event;

Expand Down
5 changes: 5 additions & 0 deletions src/dom/epub/lib/sanitize-and-render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ export async function sanitizeAndRender(xhtml: string, options: {
let img = elem as HTMLImageElement;
img.loading = 'eager';
img.decoding = 'sync';
if (!img.closest('a')) {
// TODO: Localize? No access to strings here
img.setAttribute('aria-label', 'Zoom In');
img.classList.add('clickable-image');
}
break;
}
default:
Expand Down
4 changes: 4 additions & 0 deletions src/dom/epub/stylesheets/_content.scss
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,10 @@ replaced-body {
display: none;
}
}

img.clickable-image {
cursor: zoom-in;
}
}

body.footnote-popup-content {
Expand Down

0 comments on commit 3b27121

Please sign in to comment.