Skip to content

Commit

Permalink
EPUB/Snapshot: Scroll when resizing past top/bottom of page
Browse files Browse the repository at this point in the history
And always show annotation that's being resized.
  • Loading branch information
AbeJellinek committed Nov 8, 2024
1 parent 4d35015 commit 7f2298d
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 12 deletions.
46 changes: 40 additions & 6 deletions src/dom/common/components/overlay/annotation-overlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,7 @@ const Resizer: React.FC<ResizerProps> = (props) => {
let { annotation, highlightRects, onResize, onResizeEnd, onResizeStart } = props;
let [resizingSide, setResizingSide] = useState<false | 'start' | 'end'>(false);
let [pointerCapture, setPointerCapture] = useState<{ elem: Element, pointerId: number } | null>(null);
let [lastPointerMove, setLastPointerMove] = useState<React.PointerEvent | null>(null);

let rtl = getComputedStyle(closestElement(annotation.range.commonAncestorContainer!)!).direction == 'rtl';

Expand Down Expand Up @@ -589,6 +590,7 @@ const Resizer: React.FC<ResizerProps> = (props) => {
setResizingSide(false);
if (pointerCapture) {
setPointerCapture(null);
setLastPointerMove(null);
onResizeEnd(annotation, false);
}
}, [annotation, onResizeEnd, pointerCapture]);
Expand All @@ -614,8 +616,9 @@ const Resizer: React.FC<ResizerProps> = (props) => {
return () => win.removeEventListener('keydown', handleKeyDown, true);
}, [win, handleKeyDown]);

let handlePointerMove = useCallback((event: React.PointerEvent, isStart: boolean) => {
let clientX = event.clientX;
let handlePointerMove = useCallback((event: React.PointerEvent) => {
let { clientX, clientY } = event;
let isStart = resizingSide === 'start' ? !rtl : rtl;
if (isSafari) {
let targetRect = (event.target as Element).getBoundingClientRect();
if (clientX >= targetRect.left && clientX <= targetRect.right) {
Expand All @@ -625,7 +628,7 @@ const Resizer: React.FC<ResizerProps> = (props) => {
clientX = isStart ? targetRect.left - 1 : targetRect.right + 1;
}
}
let pos = caretPositionFromPoint(event.view.document, clientX, event.clientY);
let pos = caretPositionFromPoint(event.view.document, clientX, clientY);
if (pos) {
// Just bail if the browser thinks the mouse is over the SVG - that seems to only happen momentarily
if (pos.offsetNode.nodeType == Node.ELEMENT_NODE && (pos.offsetNode as Element).closest('svg')) {
Expand Down Expand Up @@ -671,7 +674,38 @@ const Resizer: React.FC<ResizerProps> = (props) => {

onResize(annotation, newRange);
}
}, [annotation, doc, onResize]);

if (win) {
setLastPointerMove(event);
}
}, [annotation, doc, onResize, resizingSide, rtl, win]);

useEffect(() => {
if (!win || !resizingSide || !lastPointerMove) {
return undefined;
}
let scrollAmount = lastPointerMove.clientY < 50 ? -10 : lastPointerMove.clientY >= win.innerHeight - 50 ? 10 : 0;
if (!scrollAmount) {
return undefined;
}

win.scrollBy({ top: scrollAmount });
let intervalID = win.setInterval(() => {
win.scrollBy({ top: scrollAmount });
}, 20);
return () => win.clearInterval(intervalID);
}, [lastPointerMove, resizingSide, win]);

useEffect(() => {
if (!win || !resizingSide || !lastPointerMove) {
return undefined;
}
let handleScroll = () => {
handlePointerMove(lastPointerMove!);
};
win.addEventListener('scroll', handleScroll);
return () => win.removeEventListener('scroll', handleScroll);
}, [handlePointerMove, lastPointerMove, resizingSide, win]);

if (!highlightRects.length) {
return null;
Expand All @@ -691,7 +725,7 @@ const Resizer: React.FC<ResizerProps> = (props) => {
onPointerDown={handlePointerDown}
onPointerUp={handlePointerUp}
onPointerCancel={handlePointerUp}
onPointerMove={resizingSide == 'start' ? (event => handlePointerMove(event, !rtl)) : undefined}
onPointerMove={resizingSide == 'start' ? (event => handlePointerMove(event)) : undefined}
onGotPointerCapture={event => handleGotPointerCapture(event, 'start')}
onLostPointerCapture={handleLostPointerCapture}
/>
Expand All @@ -705,7 +739,7 @@ const Resizer: React.FC<ResizerProps> = (props) => {
onPointerDown={handlePointerDown}
onPointerUp={handlePointerUp}
onPointerCancel={handlePointerUp}
onPointerMove={resizingSide == 'end' ? (event => handlePointerMove(event, rtl)) : undefined}
onPointerMove={resizingSide == 'end' ? (event => handlePointerMove(event)) : undefined}
onGotPointerCapture={event => handleGotPointerCapture(event, 'end')}
onLostPointerCapture={handleLostPointerCapture}
/>
Expand Down
13 changes: 7 additions & 6 deletions src/dom/common/dom-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ abstract class DOMView<State extends DOMViewState, Data> {

protected _draggingNoteAnnotation: WADMAnnotation | null = null;

protected _resizing = false;
protected _resizingAnnotationID: string | null = null;

scale = 1;

Expand Down Expand Up @@ -434,7 +434,8 @@ abstract class DOMView<State extends DOMViewState, Data> {
}

displayedAnnotations = displayedAnnotations.filter(
a => isPageRectVisible(this._getBoundingPageRectCached(a.range), this._iframeWindow)
a => a.id === this._resizingAnnotationID
|| isPageRectVisible(this._getBoundingPageRectCached(a.range), this._iframeWindow)
);

let doRender = () => this._annotationRenderRoot.render(
Expand Down Expand Up @@ -724,7 +725,7 @@ abstract class DOMView<State extends DOMViewState, Data> {
}
}

if (key === 'Escape' && !this._resizing) {
if (key === 'Escape' && !this._resizingAnnotationID) {
if (this._selectedAnnotationIDs.length) {
this._options.onSelectAnnotations([], event);
}
Expand Down Expand Up @@ -999,14 +1000,14 @@ abstract class DOMView<State extends DOMViewState, Data> {
this._renderAnnotations();
};

private _handleAnnotationResizeStart = (_id: string) => {
this._resizing = true;
private _handleAnnotationResizeStart = (id: string) => {
this._resizingAnnotationID = id;
this._options.onSetAnnotationPopup(null);
this._iframeDocument.body.classList.add('resizing-annotation');
};

private _handleAnnotationResizeEnd = (id: string, range: Range, cancelled: boolean) => {
this._resizing = false;
this._resizingAnnotationID = null;
this._iframeDocument.body.classList.remove('resizing-annotation');
if (cancelled) {
return;
Expand Down

0 comments on commit 7f2298d

Please sign in to comment.