UNPKG

vue-book-reader

Version:

<div align="center"> <img width=250 src="https://raw.githubusercontent.com/jinhuan138/vue--book-reader/master/public/logo.png" /> <h1>VueReader</h1> </div>

122 lines (121 loc) 5.3 kB
"use strict"; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const CONTEXT_LENGTH = 50; const normalizeWhitespace = (str) => str.replace(/\s+/g, " "); const makeExcerpt = (strs, { startIndex, startOffset, endIndex, endOffset }) => { const start = strs[startIndex]; const end = strs[endIndex]; const match = start === end ? start.slice(startOffset, endOffset) : start.slice(startOffset) + strs.slice(start + 1, end).join("") + end.slice(0, endOffset); const trimmedStart = normalizeWhitespace(start.slice(0, startOffset)).trimStart(); const trimmedEnd = normalizeWhitespace(end.slice(endOffset)).trimEnd(); const ellipsisPre = trimmedStart.length < CONTEXT_LENGTH ? "" : "…"; const ellipsisPost = trimmedEnd.length < CONTEXT_LENGTH ? "" : "…"; const pre = `${ellipsisPre}${trimmedStart.slice(-CONTEXT_LENGTH)}`; const post = `${trimmedEnd.slice(0, CONTEXT_LENGTH)}${ellipsisPost}`; return { pre, match, post }; }; const simpleSearch = function* (strs, query, options = {}) { const { locales = "en", sensitivity } = options; const matchCase = sensitivity === "variant"; const haystack = strs.join(""); const lowerHaystack = matchCase ? haystack : haystack.toLocaleLowerCase(locales); const needle = matchCase ? query : query.toLocaleLowerCase(locales); const needleLength = needle.length; let index = -1; let strIndex = -1; let sum = 0; do { index = lowerHaystack.indexOf(needle, index + 1); if (index > -1) { while (sum <= index) sum += strs[++strIndex].length; const startIndex = strIndex; const startOffset = index - (sum - strs[strIndex].length); const end = index + needleLength; while (sum <= end) sum += strs[++strIndex].length; const endIndex = strIndex; const endOffset = end - (sum - strs[strIndex].length); const range = { startIndex, startOffset, endIndex, endOffset }; yield { range, excerpt: makeExcerpt(strs, range) }; } } while (index > -1); }; const segmenterSearch = function* (strs, query, options = {}) { var _a; const { locales = "en", granularity = "word", sensitivity = "base" } = options; let segmenter, collator; try { segmenter = new Intl.Segmenter(locales, { usage: "search", granularity }); collator = new Intl.Collator(locales, { sensitivity }); } catch (e) { console.warn(e); segmenter = new Intl.Segmenter("en", { usage: "search", granularity }); collator = new Intl.Collator("en", { sensitivity }); } const queryLength = Array.from(segmenter.segment(query)).length; const substrArr = []; let strIndex = 0; let segments = segmenter.segment(strs[strIndex])[Symbol.iterator](); main: while (strIndex < strs.length) { while (substrArr.length < queryLength) { const { done, value } = segments.next(); if (done) { strIndex++; if (strIndex < strs.length) { segments = segmenter.segment(strs[strIndex])[Symbol.iterator](); continue; } else break main; } const { index, segment } = value; if (!/[^\p{Format}]/u.test(segment)) continue; if (/\s/u.test(segment)) { if (!/\s/u.test((_a = substrArr[substrArr.length - 1]) == null ? void 0 : _a.segment)) substrArr.push({ strIndex, index, segment: " " }); continue; } value.strIndex = strIndex; substrArr.push(value); } const substr = substrArr.map((x) => x.segment).join(""); if (collator.compare(query, substr) === 0) { const endIndex = strIndex; const lastSeg = substrArr[substrArr.length - 1]; const endOffset = lastSeg.index + lastSeg.segment.length; const startIndex = substrArr[0].strIndex; const startOffset = substrArr[0].index; const range = { startIndex, startOffset, endIndex, endOffset }; yield { range, excerpt: makeExcerpt(strs, range) }; } substrArr.shift(); } }; const search = (strs, query, options) => { const { granularity = "grapheme", sensitivity = "base" } = options; if (!(Intl == null ? void 0 : Intl.Segmenter) || granularity === "grapheme" && (sensitivity === "variant" || sensitivity === "accent")) return simpleSearch(strs, query, options); return segmenterSearch(strs, query, options); }; const searchMatcher = (textWalker, opts) => { const { defaultLocale, matchCase, matchDiacritics, matchWholeWords, acceptNode } = opts; return function* (doc, query) { const iter = textWalker(doc, function* (strs, makeRange) { for (const result of search(strs, query, { locales: doc.body.lang || doc.documentElement.lang || defaultLocale || "en", granularity: matchWholeWords ? "word" : "grapheme", sensitivity: matchDiacritics && matchCase ? "variant" : matchDiacritics && !matchCase ? "accent" : !matchDiacritics && matchCase ? "case" : "base" })) { const { startIndex, startOffset, endIndex, endOffset } = result.range; result.range = makeRange(startIndex, startOffset, endIndex, endOffset); yield result; } }, acceptNode); for (const result of iter) yield result; }; }; exports.search = search; exports.searchMatcher = searchMatcher;