import React, { useState, useEffect } from 'react'; import useActions from '../actions'; import useStore from '../store'; import SearchComponent from '../components/Search'; import { normalize, calcFindPhraseMatch } from '../helpers/pdf'; import { scrollIntoView } from '../helpers/utility'; type MatchType = { page: number; index: number; }; const Search: React.FC = () => { let queryString = ''; const [matchesMap, setMatchesMap] = useState([]); const [matchTotal, setMatchTotal] = useState(0); const [currentIndex, setCurrentIndex] = useState(-1); const [{ navbarState, pdf, totalPage }, dispatch] = useStore(); const { setNavbar } = useActions(dispatch); const extractTextItems = async (pageNum: number): Promise => { const page = await pdf.getPage(pageNum); const textContent = await page.getTextContent({ normalizeWhitespace: true, }); const { items } = textContent; const strBuf = []; for (let j = 0, len = items.length; j < len; j += 1) { if (items[j].str.match(/[^\s]/)) { strBuf.push(items[j].str); } } return strBuf; }; const getMatchTextIndex = async (pageNum: number): Promise => { const contentItems = await extractTextItems(pageNum); const content = normalize(contentItems.join('').toLowerCase()); const matches = calcFindPhraseMatch(content, queryString); if (matches.length) { matches.forEach(ele => { matchesMap.push({ page: pageNum, index: ele, }); }); setMatchesMap(matchesMap); setMatchTotal(cur => cur + matches.length); } if (pageNum < totalPage) { getMatchTextIndex(pageNum + 1); } }; const searchPdfPages = async (): Promise => { getMatchTextIndex(1); }; const cleanMatch = (): void => { setMatchTotal(0); setCurrentIndex(-1); setMatchesMap([]); }; const handleSearch = (val: string): void => { cleanMatch(); if (val) { queryString = val.toLowerCase(); searchPdfPages(); } }; const clickPrev = (): void => { setCurrentIndex(cur => { if (cur > 0) { return cur - 1; } return cur; }); }; const clickNext = (): void => { setCurrentIndex(cur => { if (cur + 1 < matchTotal) { return cur + 1; } return cur; }); }; const handleClose = (): void => { setNavbar(''); cleanMatch(); }; useEffect(() => { if (matchTotal === 1) { clickNext(); } }, [matchTotal]); useEffect(() => { if (currentIndex >= 0) { const indexObj = matchesMap[currentIndex]; const pageDiv: HTMLDivElement = document.getElementById( `page_${indexObj.page}` ) as HTMLDivElement; scrollIntoView(pageDiv); } }, [currentIndex, matchesMap]); return ( ); }; export default Search;