From 7e385db4edffb163ec85c07fb99a2fba1458def1 Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Tue, 18 Feb 2025 22:23:05 +0100 Subject: [PATCH] compat: support weread footernote, closes #391 (#401) --- .../app/reader/components/FootnotePopup.tsx | 34 +++++++++++++++++++ .../app/reader/utils/iframeEventHandlers.ts | 9 +++++ 2 files changed, 43 insertions(+) diff --git a/apps/readest-app/src/app/reader/components/FootnotePopup.tsx b/apps/readest-app/src/app/reader/components/FootnotePopup.tsx index a3381271..c206ee50 100644 --- a/apps/readest-app/src/app/reader/components/FootnotePopup.tsx +++ b/apps/readest-app/src/app/reader/components/FootnotePopup.tsx @@ -6,6 +6,7 @@ import { useFoliateEvents } from '../hooks/useFoliateEvents'; import { useTheme } from '@/hooks/useTheme'; import { getFootnoteStyles, getStyles } from '@/utils/style'; import { getPopupPosition, getPosition, Position } from '@/utils/sel'; +import { eventDispatcher } from '@/utils/event'; import { FoliateView } from '@/types/view'; import { FootnoteHandler } from 'foliate-js/footnotes.js'; import Popup from '@/components/Popup'; @@ -106,10 +107,43 @@ const FootnotePopup: React.FC = ({ bookKey, bookDoc }) => { setShowPopup(false); }; + const handleFootnotePopupEvent = (event: CustomEvent) => { + const { element, footnote } = event.detail; + const gridFrame = document.querySelector(`#gridcell-${bookKey}`); + if (!gridFrame) return; + const rect = gridFrame.getBoundingClientRect(); + const viewSettings = getViewSettings(bookKey)!; + const triangPos = getPosition(element, rect, viewSettings.vertical); + const popupPos = getPopupPosition( + triangPos, + rect, + viewSettings.vertical ? popupHeight : popupWidth, + viewSettings.vertical ? popupWidth : popupHeight, + popupPadding, + ); + if (footnoteRef.current) { + const elem = document.createElement('p'); + elem.textContent = footnote; + elem.setAttribute('style', `padding: 16px; hanging-punctuation: allow-end last;`); + footnoteRef.current.replaceChildren(elem); + setShowPopup(true); + setTrianglePosition(triangPos); + setPopupPosition(popupPos); + } + }; + useFoliateEvents(view, { onLinkClick: docLinkHandler, }); + useEffect(() => { + eventDispatcher.on('footnote-popup', handleFootnotePopupEvent); + return () => { + eventDispatcher.off('footnote-popup', handleFootnotePopupEvent); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + useEffect(() => { if (footnoteViewRef.current) { footnoteRef.current?.replaceChildren(footnoteViewRef.current); diff --git a/apps/readest-app/src/app/reader/utils/iframeEventHandlers.ts b/apps/readest-app/src/app/reader/utils/iframeEventHandlers.ts index 5827d0d4..797c98c0 100644 --- a/apps/readest-app/src/app/reader/utils/iframeEventHandlers.ts +++ b/apps/readest-app/src/app/reader/utils/iframeEventHandlers.ts @@ -3,6 +3,7 @@ import { DOUBLE_CLICK_INTERVAL_THRESHOLD_MS, LONG_HOLD_THRESHOLD, } from '@/services/constants'; +import { eventDispatcher } from '@/utils/event'; import { getOSPlatform } from '@/utils/misc'; const doubleClickEnabled = @@ -121,6 +122,14 @@ export const handleClick = (bookKey: string, event: MouseEvent) => { if (['sup', 'a', 'audio', 'video'].includes(element.tagName.toLowerCase())) { return; } + if (element.classList.contains('js_readerFooterNote')) { + eventDispatcher.dispatch('footnote-popup', { + bookKey, + element, + footnote: element.getAttribute('data-wr-footernote') || '', + }); + return; + } element = element.parentElement; }