123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- 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<MatchType[]>([]);
- 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<string[]> => {
- 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<void> => {
- 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<void> => {
- 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 (
- <SearchComponent
- matchesTotal={matchTotal}
- current={currentIndex + 1}
- onPrev={clickPrev}
- onNext={clickNext}
- onEnter={handleSearch}
- isActive={navbarState === 'search'}
- close={handleClose}
- />
- );
- };
- export default Search;
|