Skip to content

Commit

Permalink
Merge pull request #425 from Jothsa/highlight-script
Browse files Browse the repository at this point in the history
Highlight Support
  • Loading branch information
bglw authored Oct 10, 2023
2 parents 9740deb + 71771a6 commit cfcaec4
Show file tree
Hide file tree
Showing 16 changed files with 1,127 additions and 572 deletions.
13 changes: 13 additions & 0 deletions docs/content/docs/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,19 @@ We can see that a bunch of content was indexed, and Pagefind will be running a p
Loading this in your browser, you should see a search input on your page. Try searching for some content and you will see results appear from your site.

## Highlighting

To highlight the search terms on results page, add the following snippet on every page that has been indexed

```html
<script src="/pagefind/pagefind-highlight.js"></script>
<script>
new PagefindHighlight();
<script>
```
See [Highlighting search terms](/docs/highlighting/) for more information.
The last required step is to run Pagefind after building your site on your CMS or hosting platform. If you're a CloudCannon user, add a [`.cloudcannon/postbuild`](https://cloudcannon.com/documentation/articles/extending-your-build-process-with-hooks/) file containing the npx command above (minus the `--serve` flag). For other platforms, set up an equivalent command to run after your site build — the end goal is that Pagefind will run after every build of your site before it is deployed.
For many use cases, you can stop here and mark it as complete. Or, you can dive deeper into Pagefind and configure it to your liking — check out [Configuring the index](/docs/indexing/) for some next steps.
44 changes: 44 additions & 0 deletions docs/content/docs/highlight-config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
title: "Highlight API Config"
nav_title: "Highlight API Config"
nav_section: References
weight: 65

---

`PagefindHighlight` accepts an object with any of the following options:

### markContext

```js
new PagefindHighlight({ markContext: "[data-pagefind-body]" })
```

The area in which to highlight text. Defaults to `[data-pagefind-body]` if any `[data-pagefind-body]` elements can be found, otherwise `document.body`. This can be a CSS selector string, a DOM element, an array of DOM elements, or a NodeList.

### pagefindQueryParamName

```js
new PagefindHighlight({ pagefindQueryParamName: "pagefind-highlight" })
```

The name of the query parameter that Pagefind uses to determine which terms to highlight. Defaults to `pagefind-highlight`. If the name is changed here, it *must* be changed in the [`PagefindUI` object](/docs/ui/#highlight-query-param-name) as well.

### markOptions

An object with the same shape as the [Mark.js options](https://markjs.io/#mark) object, except that the `separateWordSearch` option is not supported.

This option defaults to:

```js
{
className: "pagefind-highlight",
exclude: ["[data-pagefind-ignore]", "[data-pagefind-ignore] *"],
}
```

If either `className` or exclude are not specified they will default to the above. To disable the default `exclude` behavior, pass an empty array to `exclude`. To not add a class to the highlight elements, pass an empty string to `className`.

### addStyles

This is a boolean that determines whether or not Pagefind will add minimal styles to the highlighted elements. If set to `false`, Pagefind will not add any styles to the page. This option defaults to `true`.
17 changes: 17 additions & 0 deletions docs/content/docs/highlighting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
title: "Highlighting search terms"
nav_title: "Highlighting search terms"
nav_section: Searching
weight: 10
---

Pagefind allows you to highlight search terms on the result page. To enable this feature, import `/pagefind/pagefind-highlight.js` on the result page and create a new `PagefindHighlight` object.

```html
<script src="/pagefind/pagefind-highlight.js"></script>
<script>
new PagefindHighlight();
<script>
```
To see the options available to PagefindHighlight, see [Highlight Config](/docs/highlight-config).
13 changes: 13 additions & 0 deletions docs/content/docs/ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,19 @@ new PagefindUI({

The number of milliseconds to wait after a user stops typing before performing a search. Defaults to `300`. If you wish to disable this, set to `0`.

### Highlight query param name

{{< diffcode >}}
```javascript
new PagefindUI({
element: "#search",
+ highlightQueryParamName: 'highlight'
});
```
{{< /diffcode >}}

If the parameter is changed here, it *must* be changed in the [`PagefindHighlight` object](/docs/highlight-config/#pagefindQueryParamName) as well.

### Translations

{{< diffcode >}}
Expand Down
122 changes: 122 additions & 0 deletions pagefind/features/highlighting/highlighting_base.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
Feature: Highlighting Tests

Background:
Given I have the environment variables:
| PAGEFIND_SITE | public |
Given I have a "public/words/index.html" file with the body:
"""
<p id="has-highlight">Is this highlighted? It should be!</p>
<p data-pagefind-ignore>This should not be highlighted</p>
<p data-pagefind-ignore><span>This</span> should not be highlighted</p>
<script type="module">
await import('/pagefind/pagefind-highlight.js');
new PagefindHighlight();
</script>
"""
Given I have a "public/single-body/index.html" file with the body:
"""
<main data-pagefind-body>
<p id="has-highlight">This should be highlighted</p>
<p data-pagefind-ignore>This should not be highlighted</p>
</main>
<p id="no-highlight">This should not be highlighted</p>
<script type="module">
await import('/pagefind/pagefind-highlight.js');
new PagefindHighlight();
</script>
"""
Given I have a "public/multiple-bodies/index.html" file with the body:
"""
<main data-pagefind-body>
<p id="has-highlight">This should be highlighted</p>
<p data-pagefind-ignore>This should not be highlighted</p>
</main>
<p id="no-highlight">This should not be highlighted</p>
<div data-pagefind-body>
<p id="has-highlight">This should be highlighted</p>
<p data-pagefind-ignore>This should not be highlighted</p>
</div>
<script type="module">
await import('/pagefind/pagefind-highlight.js');
new PagefindHighlight();
</script>
"""
Given I have a "public/options/index.html" file with the body:
"""
<main data-pagefind-body>
<p id="has-highlight">This should be highlighted</p>
<p data-pagefind-ignore>This should not be highlighted</p>
</main>
<p id="no-highlight">This should not be highlighted</p>
<div data-pagefind-body>
<p id="has-highlight">This should be highlighted</p>
<p class="ignore">This should not be highlighted</p>
<p data-pagefind-ignore>This should not be highlighted</p>
</div>
<script type="module">
await import('/pagefind/pagefind-highlight.js');
new PagefindHighlight({
pagefindQueryParamName: 'custom-name',
markOptions: {
className: 'custom-class',
exclude: [
"[data-pagefind-ignore]",
"[data-pagefind-ignore] *",
".ignore"
]
}
});
</script>
"""
When I run my program
Then I should see "Running Pagefind" in stdout
When I serve the "public" directory

Scenario: Highlight script is loaded
When I load "/words/"
Then I should see the file "public/pagefind/pagefind-highlight.js"
Then There should be no logs

Scenario: Highlight script marks correctly
When I load "/words/?pagefind-highlight=this"
Then There should be no logs
Then The selector "#has-highlight mark" should contain "this"
Then The selector "#has-highlight mark.pagefind-highlight" should contain "this"
Then The selector "p[data-pagefind-ignore]:not(:has(span))" should contain "This should not be highlighted"
Then The selector "p[data-pagefind-ignore]:has(span)" should contain "<span>This</span> should not be highlighted"
When I load "/words/?pagefind-highlight=this&pagefind-highlight=should"
Then There should be no logs
Then The selector "#has-highlight mark:first-of-type" should contain "this"
Then The selector "#has-highlight mark:nth-of-type(2)" should contain "should"
When I load "/words/?pagefind-highlight=is+this"
Then There should be no logs
Then The selector "#has-highlight mark" should contain "Is this"
Then The selector "p[data-pagefind-ignore]" should contain "This should not be highlighted"
When I load "/words/?pagefind-highlight=highlighted%3F"
Then There should be no logs
Then The selector "#has-highlight mark" should contain "highlighted?"
When I load "/words/?pagefind-highlight=this+highlighted%3F"
Then There should be no logs
Then The selector "#has-highlight mark:first-of-type" should contain "this highlighted?"

Scenario: Highlight script stays within pagefind-body
When I load "/single-body/?pagefind-highlight=this"
Then There should be no logs
Then The selector "#has-highlight mark" should contain "This"
Then The selector "p[data-pagefind-ignore]" should contain "This should not be highlighted"
Then The selector "#no-highlight" should contain "This should not be highlighted"
When I load "/multiple-bodies/?pagefind-highlight=this"
Then There should be no logs
Then The selector "#has-highlight mark" should contain "This"
Then The selector "p[data-pagefind-ignore]" should contain "This should not be highlighted"
Then The selector "#no-highlight" should contain "This should not be highlighted"

Scenario: Highlight script options work
When I load "/options/?custom-name=this"
Then There should be no logs
Then The selector "#has-highlight mark" should contain "This"
Then The selector "#has-highlight mark.custom-class" should contain "This"
Then The selector "p[data-pagefind-ignore]" should contain "This should not be highlighted"
Then The selector "p.ignore" should contain "This should not be highlighted"
Then The selector "#no-highlight" should contain "This should not be highlighted"

143 changes: 143 additions & 0 deletions pagefind/features/ui/ui_highlight.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
Feature: Base UI Tests
Background:
Given I have the environment variables:
| PAGEFIND_SITE | public |

# in this senario I use the css attribute selector to make sure the link has the query param as the end
# if the link doesn't exist, the check will fail
# see https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors#syntax:~:text=%5Battr%24%3Dvalue%5D,by%20value.

Scenario: Pagefind UI adds highlight query params
Given I have a "public/index.html" file with the body:
"""
<div id="search"></div>
<script src="/pagefind/pagefind-ui.js"></script>
<script>
window.pui = new PagefindUI({ element: "#search" });
</script>
"""
Given I have a "public/cat/index.html" file with the body:
"""
<h1>hello world</h1>
<p>Hello world! How are you</p>
"""
When I run my program
Then I should see "Running Pagefind" in stdout
Then I should see the file "public/pagefind/pagefind.js"
When I serve the "public" directory
When I load "/"
When I evaluate:
"""
async function() {
window.pui.triggerSearch("world");
await new Promise(r => setTimeout(r, 1500)); // TODO: await el in humane
}
"""
Then There should be no logs
Then The selector ".pagefind-ui__result-link[href$='?pagefind-highlight=world']" should contain "hello world"
When I evaluate:
"""
async function() {
window.pui.triggerSearch("hello world");
await new Promise(r => setTimeout(r, 1500)); // TODO: await el in humane
}
"""
Then There should be no logs
Then The selector ".pagefind-ui__result-link[href$='?pagefind-highlight=hello&pagefind-highlight=world']" should contain "hello world"
When I evaluate:
"""
async function() {
window.pui.triggerSearch("hello world!");
await new Promise(r => setTimeout(r, 1500)); // TODO: await el in humane
}
"""
Then There should be no logs
Then The selector ".pagefind-ui__result-link[href$='?pagefind-highlight=hello&pagefind-highlight=world%21']" should contain "hello world"

Scenario: Pagefind UI does not add highlight query params
Given I have a "public/index.html" file with the body:
"""
<div id="search"></div>
<script src="/pagefind/pagefind-ui.js"></script>
<script>
window.pui = new PagefindUI({ element: "#search", highlightQueryParamName: null });
</script>
"""
Given I have a "public/cat/index.html" file with the body:
"""
<h1>hello world</h1>
<p>Hello world! How are you</p>
"""
When I run my program
Then I should see "Running Pagefind" in stdout
Then I should see the file "public/pagefind/pagefind.js"
When I serve the "public" directory
When I load "/"
When I evaluate:
"""
async function() {
window.pui.triggerSearch("world");
await new Promise(r => setTimeout(r, 1500)); // TODO: await el in humane
}
"""
Then There should be no logs
Then The selector ".pagefind-ui__result-link[href$='/']" should contain "hello world"
When I evaluate:
"""
async function() {
window.pui.triggerSearch("hello world");
await new Promise(r => setTimeout(r, 1500)); // TODO: await el in humane
}
"""
Then There should be no logs
Then The selector ".pagefind-ui__result-link[href$='/']" should contain "hello world"

Scenario: Pagefind UI uses custom highlight query param name
Given I have a "public/index.html" file with the body:
"""
<div id="search"></div>
<script src="/pagefind/pagefind-ui.js"></script>
<script>
window.pui = new PagefindUI({ element: "#search", highlightQueryParamName: 'custom-param' });
</script>
"""
Given I have a "public/cat/index.html" file with the body:
"""
<h1>hello world</h1>
<p>Hello world! How are you</p>
"""
When I run my program
Then I should see "Running Pagefind" in stdout
Then I should see the file "public/pagefind/pagefind.js"
When I serve the "public" directory
When I load "/"
When I evaluate:
"""
async function() {
window.pui.triggerSearch("world");
await new Promise(r => setTimeout(r, 1500)); // TODO: await el in humane
}
"""
Then There should be no logs
Then The selector ".pagefind-ui__result-link[href$='?custom-param=world']" should contain "hello world"
When I evaluate:
"""
async function() {
window.pui.triggerSearch("hello world");
await new Promise(r => setTimeout(r, 1500)); // TODO: await el in humane
}
"""
Then There should be no logs
Then The selector ".pagefind-ui__result-link[href$='?custom-param=hello&custom-param=world']" should contain "hello world"
When I evaluate:
"""
async function() {
window.pui.triggerSearch("hello world!");
await new Promise(r => setTimeout(r, 1500)); // TODO: await el in humane
}
"""
Then There should be no logs
Then The selector ".pagefind-ui__result-link[href$='?custom-param=hello&custom-param=world%21']" should contain "hello world"
3 changes: 2 additions & 1 deletion pagefind/features/ui/ui_hooks.feature
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Feature: UI Hooks
window.pui = new PagefindUI({
element: "#search",
processTerm: (t) => t.replace("word", "search"),
highlightQueryParamName: null
});
</script>
"""
Expand All @@ -31,7 +32,7 @@ Feature: UI Hooks
// TODO: Add more web test steps to humane instead of throwing js
let el = document.querySelector(".pagefind-ui__result-link");
if (el.getAttribute("href") !== "/") {
throw new Error("Search term should have been normalized by processTerm");
throw new Error(`Search term should have been normalized by processTerm. href: ${el.getAttribute("href")}`);
}
}
"""
Expand Down
Loading

0 comments on commit cfcaec4

Please sign in to comment.