Skip to content

Commit

Permalink
Merge e6621e8 into d6e99f4
Browse files Browse the repository at this point in the history
  • Loading branch information
weareoutman committed Nov 14, 2020
2 parents d6e99f4 + e6621e8 commit 3d34980
Show file tree
Hide file tree
Showing 12 changed files with 129 additions and 24 deletions.
29 changes: 15 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,20 +67,21 @@ yarn add nodejieba

## Plugin Options

| Name | Type | Default | Description |
| ---------------------------- | ------------------ | --------- | ------------------------------------------------------------------------------------------------------------------------------ |
| indexDocs | boolean | `true` | Whether to index docs. |
| indexBlog | boolean | `true` | Whether to index blog. |
| indexPages | boolean | `false` | Whether to index pages. |
| docsRouteBasePath | string \| string[] | `"/docs"` | Base route path of docs. Slash at beginning is not required. |
| blogRouteBasePath | string \| string[] | `"/blog"` | Base route path of blog. Slash at beginning is not required. |
| language | string \| string[] | `"en"` | All [lunr-languages](https://github.com/MihaiValentin/lunr-languages) supported languages, + `zh` 🔥. |
| hashed | boolean | `false` | Whether to add a hashed query when fetching index (based on the content hash of all `*.md`) |
| docsDir | string \| string[] | `"docs"` | The dir of docs to get the content hash, it's relative to the dir of your project. |
| blogDir | string \| string[] | `"blog"` | Just like the `docsDir` but applied to blog. |
| removeDefaultStopWordFilter | boolean | `false` | Sometimes people (E.g., us) want to keep the English stop words as indexed, since they maybe are relevant in programming docs. |
| searchResultLimits | number | `8` | Limit the search results. |
| searchResultContextMaxLength | number | `50` | Set the max length of characters of each search result to show. results. |
| Name | Type | Default | Description |
| -------------------------------- | ------------------ | --------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| indexDocs | boolean | `true` | Whether to index docs. |
| indexBlog | boolean | `true` | Whether to index blog. |
| indexPages | boolean | `false` | Whether to index pages. |
| docsRouteBasePath | string \| string[] | `"/docs"` | Base route path(s) of docs. Slash at beginning is not required. |
| blogRouteBasePath | string \| string[] | `"/blog"` | Base route path(s) of blog. Slash at beginning is not required. |
| language | string \| string[] | `"en"` | All [lunr-languages](https://github.com/MihaiValentin/lunr-languages) supported languages, + `zh` 🔥. |
| hashed | boolean | `false` | Whether to add a hashed query when fetching index (based on the content hash of all indexed `*.md` in `docsDir` and `blogDir` if applicable) |
| docsDir | string \| string[] | `"docs"` | The dir(s) of docs to get the content hash, it's relative to the dir of your project. |
| blogDir | string \| string[] | `"blog"` | Just like the `docsDir` but applied to blog. |
| removeDefaultStopWordFilter | boolean | `false` | Sometimes people (E.g., us) want to keep the English stop words as indexed, since they maybe are relevant in programming docs. |
| highlightSearchTermsOnTargetPage | boolean | `false` | Highlight search terms on target page. |
| searchResultLimits | number | `8` | Limit the search results. |
| searchResultContextMaxLength | number | `50` | Set the max length of characters of each search result to show. |

## Custom Styles

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@
"fs-extra": "^9.0.1",
"klaw-sync": "^6.0.0",
"lunr": "^2.3.9",
"lunr-languages": "^1.4.0"
"lunr-languages": "^1.4.0",
"mark.js": "^8.11.1"
},
"devDependencies": {
"@babel/core": "^7.12.3",
Expand Down
49 changes: 44 additions & 5 deletions src/client/theme/SearchBar/SearchBar.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import React, { ReactElement, useCallback, useRef, useState } from "react";
import React, {
ReactElement,
useCallback,
useEffect,
useRef,
useState,
} from "react";
import clsx from "clsx";
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
import { useHistory } from "@docusaurus/router";
import ExecutionEnvironment from "@docusaurus/ExecutionEnvironment";
import { useHistory, useLocation } from "@docusaurus/router";

import { fetchIndexes } from "./fetchIndexes";
import { SearchSourceFactory } from "../../utils/SearchSourceFactory";
import { SuggestionTemplate } from "./SuggestionTemplate";
import { EmptyTemplate } from "./EmptyTemplate";
import { SearchResult } from "../../../shared/interfaces";
import { searchResultLimits } from "../../utils/proxiedGenerated";
import { searchResultLimits, Mark } from "../../utils/proxiedGenerated";
import LoadingRing from "../LoadingRing/LoadingRing";

import styles from "./SearchBar.module.css";
Expand All @@ -19,6 +26,8 @@ async function fetchAutoCompleteJS(): Promise<any> {
return autoComplete.default;
}

const SEARCH_PARAM_HIGHLIGHT = "_highlight";

interface SearchBarProps {
isSearchBarExpanded: boolean;
handleSearchBarToggle: (expanded: boolean) => void;
Expand All @@ -31,6 +40,7 @@ export default function SearchBar({
siteConfig: { baseUrl },
} = useDocusaurusContext();
const history = useHistory();
const location = useLocation();
const searchBarRef = useRef<HTMLInputElement>(null);
const indexState = useRef("empty"); // empty, loaded, done
// Should the input be focused after the index is loaded?
Expand Down Expand Up @@ -104,9 +114,20 @@ export default function SearchBar({
]
).on("autocomplete:selected", function (
event: any,
{ document }: SearchResult
{ document: { u, h }, tokens }: SearchResult
) {
history.push(document.u);
let url = u;
if (Mark && tokens.length > 0) {
const params = new URLSearchParams();
for (const token of tokens) {
params.append(SEARCH_PARAM_HIGHLIGHT, token);
}
url += `?${params.toString()}`;
}
if (h) {
url += h;
}
history.push(url);
});

indexState.current = "done";
Expand All @@ -121,6 +142,24 @@ export default function SearchBar({
}
}, [baseUrl, history]);

useEffect(() => {
if (!Mark) {
return;
}
const keywords = ExecutionEnvironment.canUseDOM
? new URLSearchParams(location.search).getAll(SEARCH_PARAM_HIGHLIGHT)
: [];
if (keywords.length === 0) {
return;
}
const root = document.querySelector("article");
if (!root) {
return;
}
const mark = new Mark(root);
mark.mark(keywords);
}, [location.search]);

const onInputFocus = useCallback(() => {
focusAfterIndexLoaded.current = true;
loadIndex();
Expand Down
4 changes: 4 additions & 0 deletions src/declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ declare module "@easyops-cn/autocomplete.js" {
declare module "*/generated.js" {
export const language: string[];
export const removeDefaultStopWordFilter: string[];
export class Mark {
constructor(root: HTMLElement);
mark: (terms: string[], options?: Record<string, unknown>) => void;
}
export const indexHash: string | undefined;
export const searchResultLimits: number;
export const searchResultContextMaxLength: number;
Expand Down
24 changes: 24 additions & 0 deletions src/server/utils/generate.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ describe("generate", () => {
expect.stringMatching(/^import lunr from ".+\/lunr\/lunr\.js";$/),
'export const language = ["en"];',
"export const removeDefaultStopWordFilter = false;",
"export const Mark = null;",
'export const indexHash = "abc";',
"export const searchResultLimits = 8;",
"export const searchResultContextMaxLength = 50;",
Expand All @@ -36,6 +37,7 @@ describe("generate", () => {
'require("@easyops-cn/docusaurus-search-local/dist/client/shared/lunrLanguageZh").lunrLanguageZh(lunr);',
'export const language = ["zh"];',
"export const removeDefaultStopWordFilter = false;",
"export const Mark = null;",
'export const indexHash = "abc";',
"export const searchResultLimits = 8;",
"export const searchResultContextMaxLength = 50;",
Expand All @@ -53,6 +55,7 @@ describe("generate", () => {
),
'export const language = ["es"];',
"export const removeDefaultStopWordFilter = false;",
"export const Mark = null;",
'export const indexHash = "abc";',
"export const searchResultLimits = 8;",
"export const searchResultContextMaxLength = 50;",
Expand All @@ -73,6 +76,7 @@ describe("generate", () => {
),
'export const language = ["ja"];',
"export const removeDefaultStopWordFilter = false;",
"export const Mark = null;",
'export const indexHash = "abc";',
"export const searchResultLimits = 8;",
"export const searchResultContextMaxLength = 50;",
Expand All @@ -91,6 +95,7 @@ describe("generate", () => {
),
'export const language = ["en","zh"];',
"export const removeDefaultStopWordFilter = false;",
"export const Mark = null;",
'export const indexHash = "abc";',
"export const searchResultLimits = 8;",
"export const searchResultContextMaxLength = 50;",
Expand All @@ -112,6 +117,7 @@ describe("generate", () => {
),
'export const language = ["en","es","zh"];',
"export const removeDefaultStopWordFilter = false;",
"export const Mark = null;",
'export const indexHash = "abc";',
"export const searchResultLimits = 8;",
"export const searchResultContextMaxLength = 50;",
Expand All @@ -136,4 +142,22 @@ describe("generate", () => {
);
expect(calledContents).toEqual(contents);
});

test("highlightSearchTermsOnTargetPage", () => {
generate(
{
language: ["en"],
removeDefaultStopWordFilter: false,
highlightSearchTermsOnTargetPage: true,
searchResultLimits: 8,
searchResultContextMaxLength: 50,
} as ProcessedPluginOptions,
"/tmp"
);

expect(mockWriteFileSync).toBeCalledWith(
"/tmp/generated.js",
expect.stringContaining("export { default as Mark } from")
);
});
});
10 changes: 10 additions & 0 deletions src/server/utils/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export function generate(config: ProcessedPluginOptions, dir: string): void {
const {
language,
removeDefaultStopWordFilter,
highlightSearchTermsOnTargetPage,
searchResultLimits,
searchResultContextMaxLength,
} = config;
Expand Down Expand Up @@ -55,6 +56,15 @@ export function generate(config: ProcessedPluginOptions, dir: string): void {
removeDefaultStopWordFilter
)};`
);
if (highlightSearchTermsOnTargetPage) {
contents.push(
`export { default as Mark } from ${JSON.stringify(
require.resolve("mark.js")
)}`
);
} else {
contents.push("export const Mark = null;");
}
contents.push(`export const indexHash = ${JSON.stringify(indexHash)};`);
contents.push(
`export const searchResultLimits = ${JSON.stringify(searchResultLimits)};`,
Expand Down
7 changes: 5 additions & 2 deletions src/server/utils/scanDocuments.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,26 +84,29 @@ describe("scanDocuments", () => {
],
Array [
Object {
"h": "#first-heading",
"i": 3,
"p": 1,
"t": "First heading",
"u": "/1#first-heading",
"u": "/1",
},
],
Array [
Object {
"h": "",
"i": 2,
"p": 1,
"s": "Hello First Docs",
"t": "Leading content.",
"u": "/1",
},
Object {
"h": "#first-heading",
"i": 4,
"p": 1,
"s": "First heading",
"t": "First content.",
"u": "/1#first-heading",
"u": "/1",
},
],
]
Expand Down
6 changes: 4 additions & 2 deletions src/server/utils/scanDocuments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ export async function scanDocuments(
headingDocuments.push({
i: getNextDocId(),
t: section.title,
u: url + section.hash,
u: url,
h: section.hash,
p: titleId,
});
}
Expand All @@ -56,7 +57,8 @@ export async function scanDocuments(
i: getNextDocId(),
t: section.content,
s: section.title || pageTitle,
u: url + section.hash,
u: url,
h: section.hash,
p: titleId,
});
}
Expand Down
6 changes: 6 additions & 0 deletions src/server/utils/validateOptions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ describe("validateOptions", () => {
indexPages: false,
language: ["en"],
removeDefaultStopWordFilter: false,
highlightSearchTermsOnTargetPage: false,
searchResultLimits: 8,
searchResultContextMaxLength: 50,
},
Expand All @@ -47,6 +48,7 @@ describe("validateOptions", () => {
indexPages: false,
language: ["en", "zh"],
removeDefaultStopWordFilter: false,
highlightSearchTermsOnTargetPage: false,
searchResultLimits: 8,
searchResultContextMaxLength: 50,
},
Expand All @@ -56,6 +58,7 @@ describe("validateOptions", () => {
docsDir: "src/docs",
blogDir: "src/blog",
language: "en",
highlightSearchTermsOnTargetPage: true,
searchResultLimits: 5,
searchResultContextMaxLength: 30,
},
Expand All @@ -70,6 +73,7 @@ describe("validateOptions", () => {
indexPages: false,
language: "en",
removeDefaultStopWordFilter: false,
highlightSearchTermsOnTargetPage: true,
searchResultLimits: 5,
searchResultContextMaxLength: 30,
},
Expand All @@ -90,6 +94,7 @@ describe("validateOptions", () => {
indexPages: false,
language: ["en"],
removeDefaultStopWordFilter: false,
highlightSearchTermsOnTargetPage: false,
searchResultLimits: 8,
searchResultContextMaxLength: 50,
},
Expand All @@ -110,6 +115,7 @@ describe("validateOptions", () => {
indexPages: false,
language: ["en"],
removeDefaultStopWordFilter: false,
highlightSearchTermsOnTargetPage: false,
searchResultLimits: 8,
searchResultContextMaxLength: 50,
},
Expand Down
1 change: 1 addition & 0 deletions src/server/utils/validateOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const schema = Joi.object({
docsDir: isStringOrArrayOfStrings.default(["docs"]),
blogDir: isStringOrArrayOfStrings.default(["blog"]),
removeDefaultStopWordFilter: Joi.boolean().default(false),
highlightSearchTermsOnTargetPage: Joi.boolean().default(false),
searchResultLimits: Joi.number().default(8),
searchResultContextMaxLength: Joi.number().default(50),
});
Expand Down
9 changes: 9 additions & 0 deletions src/shared/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ export interface SearchDocument {
/** Doc URL. */
u: string;

/** Doc hash. */
h?: string;

/** Doc parent ID. */
p?: number;

Expand All @@ -68,6 +71,11 @@ export interface SearchDocument {
s?: string;
}

/**
* - 0: Doc title
* - 1: Doc heading
* - 2: Doc content
*/
export type SearchDocumentType = 0 | 1 | 2;

export interface SearchResultBase {
Expand Down Expand Up @@ -132,6 +140,7 @@ export interface PluginOptions {
docsDir?: string | string[];
blogDir?: string | string[];
removeDefaultStopWordFilter?: boolean;
highlightSearchTermsOnTargetPage?: boolean;

searchResultLimits?: number;
searchResultContextMaxLength?: number;
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5128,6 +5128,11 @@ map-visit@^1.0.0:
dependencies:
object-visit "^1.0.0"

mark.js@^8.11.1:
version "8.11.1"
resolved "https://registry.yarnpkg.com/mark.js/-/mark.js-8.11.1.tgz#180f1f9ebef8b0e638e4166ad52db879beb2ffc5"
integrity sha1-GA8fnr74sOY45BZq1S24eb6y/8U=

meow@^3.3.0:
version "3.7.0"
resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb"
Expand Down

0 comments on commit 3d34980

Please sign in to comment.