Skip to content

Commit

Permalink
Fix EPUB/snapshot annotation resizing in Safari
Browse files Browse the repository at this point in the history
  • Loading branch information
AbeJellinek committed Aug 16, 2023
1 parent 028b7ae commit 011030a
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 7 deletions.
17 changes: 13 additions & 4 deletions src/dom/common/components/overlay/annotation-overlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ export type DisplayedAnnotation = {
};

export const AnnotationOverlay: React.FC<AnnotationOverlayProps> = (props) => {
let { iframe, annotations, selectedAnnotationIDs, onPointerDown, onPointerUp, onDragStart, onResizeStart, onResizeEnd, disablePointerEvents } = props;
let { iframe, annotations, selectedAnnotationIDs, onPointerDown, onPointerUp, onDragStart, onResizeStart, onResizeEnd } = props;

let [isResizing, setResizing] = useState(false);
let [isPointerDownOutside, setPointerDownOutside] = useState(false);
let pointerEventsSuppressed = disablePointerEvents || isResizing || isPointerDownOutside;
let pointerEventsSuppressed = isResizing || isPointerDownOutside;

useEffect(() => {
let win = iframe.contentWindow;
Expand Down Expand Up @@ -168,7 +168,6 @@ type AnnotationOverlayProps = {
onDragStart: (id: string, dataTransfer: DataTransfer) => void;
onResizeStart: (id: string) => void;
onResizeEnd: (id: string, range: Range, cancelled: boolean) => void;
disablePointerEvents: boolean;
};

const HighlightOrUnderline: React.FC<HighlightOrUnderlineProps> = (props) => {
Expand Down Expand Up @@ -531,7 +530,17 @@ const Resizer: React.FC<ResizerProps> = (props) => {
}, [win, handleKeyDown]);

let handlePointerMove = (event: React.PointerEvent, isStart: boolean) => {
let pos = caretPositionFromPoint(event.view.document, event.clientX, event.clientY);
let clientX = event.clientX;
if (isSafari) {
let targetRect = (event.target as Element).getBoundingClientRect();
if (clientX >= targetRect.left && clientX <= targetRect.right) {
// In Safari, caretPositionFromPoint() doesn't work if the mouse is directly over the target element
// (returns the last element in the body instead), so we have to offset the X position by 1 pixel.
// This makes resizing a bit jerkier, but it's better than the alternative.
clientX = isStart ? targetRect.left - 1 : targetRect.right + 1;
}
}
let pos = caretPositionFromPoint(event.view.document, clientX, event.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
14 changes: 11 additions & 3 deletions src/dom/common/dom-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,6 @@ abstract class DOMView<State extends DOMViewState, Data> {

protected _overlayPopupDelayer: PopupDelayer;

protected _disableAnnotationPointerEvents = false;

protected _highlightedPosition: Selector | null = null;

protected _pointerMovedWhileDown = false;
Expand Down Expand Up @@ -330,7 +328,6 @@ abstract class DOMView<State extends DOMViewState, Data> {
onDragStart={this._handleAnnotationDragStart}
onResizeStart={this._handleAnnotationResizeStart}
onResizeEnd={this._handleAnnotationResizeEnd}
disablePointerEvents={this._disableAnnotationPointerEvents}
/>
), container);
}
Expand Down Expand Up @@ -770,10 +767,21 @@ abstract class DOMView<State extends DOMViewState, Data> {
private _handleAnnotationResizeStart = (_id: string) => {
this._resizing = true;
this._options.onSetAnnotationPopup(null);
if (isSafari) {
// Capturing the pointer doesn't stop text selection in Safari. We could set user-select: none
// (-webkit-user-select: none, actually), but that breaks caretPositionFromPoint (only in Safari).
// So we make the selection invisible instead.
this._iframeDocument.documentElement.style.setProperty('--selection-color', 'transparent');
}
};

private _handleAnnotationResizeEnd = (id: string, range: Range, cancelled: boolean) => {
this._resizing = false;
if (isSafari) {
// See above - this resets the highlight color and clears the selection
this.setTool(this._tool);
this._iframeDocument.getSelection()?.removeAllRanges();
}
if (cancelled) {
return;
}
Expand Down

0 comments on commit 011030a

Please sign in to comment.