This commit is contained in:
@@ -22,7 +22,13 @@ import { useTranslation } from '@/hooks/useTranslation';
|
||||
import { useResponsiveSize } from '@/hooks/useResponsiveSize';
|
||||
import { useFoliateEvents } from '../../hooks/useFoliateEvents';
|
||||
import { useNotesSync } from '../../hooks/useNotesSync';
|
||||
import { getPopupPosition, getPosition, Position, TextSelection } from '@/utils/sel';
|
||||
import {
|
||||
getPopupPosition,
|
||||
getPosition,
|
||||
getTextFromRange,
|
||||
Position,
|
||||
TextSelection,
|
||||
} from '@/utils/sel';
|
||||
import { eventDispatcher } from '@/utils/event';
|
||||
import { findTocItemBS } from '@/utils/toc';
|
||||
import { transformContent } from '@/services/transformService';
|
||||
@@ -48,6 +54,7 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
const bookData = getBookData(bookKey)!;
|
||||
const view = getView(bookKey);
|
||||
const viewSettings = getViewSettings(bookKey)!;
|
||||
const primaryLang = bookData.book?.primaryLanguage || 'en';
|
||||
|
||||
const isShowingPopup = useRef(false);
|
||||
const isTextSelected = useRef(false);
|
||||
@@ -98,6 +105,9 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
transformers: ['punctuation'],
|
||||
reversePunctuationTransform: true,
|
||||
};
|
||||
const getAnnotationText = (range: Range) => {
|
||||
return getTextFromRange(range, primaryLang.startsWith('ja') ? ['rt'] : []);
|
||||
};
|
||||
const makeSelection = async (sel: Selection, rebuildRange = false) => {
|
||||
isTextSelected.current = true;
|
||||
const range = sel.getRangeAt(0);
|
||||
@@ -105,7 +115,7 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(range);
|
||||
}
|
||||
transformCtx['content'] = sel.toString();
|
||||
transformCtx['content'] = getAnnotationText(range);
|
||||
setSelection({ key: bookKey, text: await transformContent(transformCtx), range, index });
|
||||
};
|
||||
// FIXME: extremely hacky way to dismiss system selection tools on iOS
|
||||
@@ -117,7 +127,7 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
setTimeout(async () => {
|
||||
if (!isTextSelected.current) return;
|
||||
sel.addRange(range);
|
||||
transformCtx['content'] = range.toString();
|
||||
transformCtx['content'] = getAnnotationText(range);
|
||||
setSelection({ key: bookKey, text: await transformContent(transformCtx), range, index });
|
||||
}, 40);
|
||||
}, 0);
|
||||
|
||||
@@ -32,6 +32,7 @@ const SearchBar: React.FC<SearchBarProps> = ({
|
||||
const _ = useTranslation();
|
||||
const { envConfig } = useEnv();
|
||||
const { settings } = useSettingsStore();
|
||||
const { getBookData } = useBookDataStore();
|
||||
const { getConfig, saveConfig } = useBookDataStore();
|
||||
const { getView, getProgress } = useReaderStore();
|
||||
const [searchTerm, setSearchTerm] = useState(term);
|
||||
@@ -39,7 +40,9 @@ const SearchBar: React.FC<SearchBarProps> = ({
|
||||
|
||||
const view = getView(bookKey)!;
|
||||
const config = getConfig(bookKey)!;
|
||||
const bookData = getBookData(bookKey)!;
|
||||
const progress = getProgress(bookKey)!;
|
||||
const primaryLang = bookData.book?.primaryLanguage || 'en';
|
||||
const searchConfig = config.searchConfig! as BookSearchConfig;
|
||||
|
||||
const queuedSearchTerm = useRef('');
|
||||
@@ -120,12 +123,30 @@ const SearchBar: React.FC<SearchBarProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
const createAcceptNode = ({ withRT = true } = {}) => {
|
||||
return (node: Node): number => {
|
||||
if (node.nodeType === Node.ELEMENT_NODE) {
|
||||
const name = (node as Element).tagName.toLowerCase();
|
||||
if (name === 'script' || name === 'style' || (!withRT && name === 'rt')) {
|
||||
return NodeFilter.FILTER_REJECT;
|
||||
}
|
||||
return NodeFilter.FILTER_SKIP;
|
||||
}
|
||||
return NodeFilter.FILTER_ACCEPT;
|
||||
};
|
||||
};
|
||||
|
||||
const handleSearch = async (term: string) => {
|
||||
console.log('searching for:', term);
|
||||
isSearchPending.current = true;
|
||||
const { section } = progress;
|
||||
const index = searchConfig.scope === 'section' ? section.current : undefined;
|
||||
const generator = await view.search({ ...searchConfig, query: term, index });
|
||||
const generator = await view.search({
|
||||
...searchConfig,
|
||||
index,
|
||||
query: term,
|
||||
acceptNode: createAcceptNode({ withRT: !primaryLang.startsWith('ja') }),
|
||||
});
|
||||
const results: BookSearchResult[] = [];
|
||||
for await (const result of generator) {
|
||||
if (typeof result === 'string') {
|
||||
|
||||
@@ -143,6 +143,7 @@ export interface BookSearchConfig {
|
||||
matchDiacritics: boolean;
|
||||
index?: number;
|
||||
query?: string;
|
||||
acceptNode?: (node: Node) => number;
|
||||
}
|
||||
|
||||
export interface SearchExcerpt {
|
||||
|
||||
@@ -159,3 +159,26 @@ export const getPopupPosition = (
|
||||
|
||||
return { point: popupPoint, dir: position.dir } as Position;
|
||||
};
|
||||
|
||||
export const getTextFromRange = (range: Range, rejects: string[] = []): string => {
|
||||
const clonedRange = range.cloneRange();
|
||||
const fragment = clonedRange.cloneContents();
|
||||
const walker = document.createTreeWalker(fragment, NodeFilter.SHOW_TEXT, {
|
||||
acceptNode: (node) => {
|
||||
const parent = node.parentElement;
|
||||
if (rejects.includes(parent?.tagName.toLowerCase() || '')) {
|
||||
return NodeFilter.FILTER_REJECT;
|
||||
}
|
||||
return NodeFilter.FILTER_ACCEPT;
|
||||
},
|
||||
});
|
||||
|
||||
let text = '';
|
||||
let node: Text | null;
|
||||
|
||||
while ((node = walker.nextNode() as Text | null)) {
|
||||
text += node.nodeValue ?? '';
|
||||
}
|
||||
|
||||
return text;
|
||||
};
|
||||
|
||||
+1
-1
Submodule packages/foliate-js updated: 1f545c5ef5...4078287cae
Reference in New Issue
Block a user