Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,23 +97,24 @@ Here is a table for the available options, usage questions, troubleshooting & gu
| `success` | Function | No | A function called once the data has been loaded. |
| `debounceTime` | Number | No | Limit how many times the search function can be executed over the given time window. If no `debounceTime` (milliseconds) is provided a search will be triggered on each keystroke. |
| `searchResultTemplate` | String | No | The template of a single rendered search result. (match liquid value eg: `'<li><a href="{{ site.url }}{url}">{title}</a></li>'` |
| `templateMiddleware` | Function | No | A function that processes template placeholders and can include highlighting functionality. The function receives (prop, value, template, query, matchInfo) parameters. |

## Middleware

### templateMiddleware (Function) [optional]

A function that will be called whenever a match in the template is found.
It gets passed the current property name, property value, and the template.
It gets passed the current property name, property value, template, query, and matchInfo.
If the function returns a non-undefined value, it gets replaced in the template.

This can be potentially useful for manipulating URLs etc.
This can be potentially useful for manipulating URLs or adding highlighting.

Example:

```js
SimpleJekyllSearch({
// ...other config
templateMiddleware: function(prop, value, template) {
templateMiddleware: function(prop, value, template, query, matchInfo) {
if (prop === 'bar') {
return value.replace(/^\//, '')
}
Expand All @@ -139,3 +140,24 @@ SimpleJekyllSearch({
},
})
```

### Highlighting Search Results

The library includes built-in highlighting functionality through the `createHighlightTemplateMiddleware` function.

```js
import { createHighlightTemplateMiddleware } from 'simple-jekyll-search';

SimpleJekyllSearch({
// ...other config
templateMiddleware: createHighlightTemplateMiddleware({
highlightClass: 'highlight', // CSS class for highlighted text
contextBefore: 30, // Characters before match
contextAfter: 30, // Characters after match
maxLength: 200, // Maximum total length
ellipsis: '...' // Text to show when truncated
}),
})
```

The highlight middleware works with all search strategies and uses match information provided by the search engine for accurate highlighting.
82 changes: 82 additions & 0 deletions cypress/e2e/highlight-middleware.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
describe('Highlight Middleware', () => {
beforeEach(() => {
cy.visit('/');
});

it('should highlight search terms with default middleware', () => {
cy.window().should('have.property', 'SimpleJekyllSearch');

cy.get('#search-input').type('search');

cy.get('#results-container', { timeout: 10000 }).should('not.be.empty');

cy.get('#results-container')
.find('.sjs-highlight')
.should('exist')
.and('contain', 'search');

cy.get('#results-container')
.find('.sjs-highlight')
.should('have.length.at.least', 1);
});

it('should handle case insensitive search', () => {
cy.get('#search-input').type('SEARCH');

cy.get('#results-container').should('not.be.empty');

cy.get('#results-container')
.find('.sjs-highlight')
.should('exist')
.and('contain', 'search');
});

it('should highlight multiple search terms', () => {
cy.get('#search-input').type('search test');

cy.get('#results-container').should('not.be.empty');

cy.get('#results-container')
.find('.sjs-highlight')
.should('exist');
});

it('should show context around matches', () => {
cy.get('#search-input').type('test');

cy.get('#results-container').should('not.be.empty');

cy.get('#results-container')
.find('.sjs-highlight')
.should('exist')
.and('contain', 'test');

cy.get('#results-container')
.find('.search-snippet')
.should('contain.text', 'test')
.and('not.have.text', 'test');
});

it('should clear results when search is cleared', () => {
cy.get('#search-input').type('test');

cy.get('#results-container').should('not.be.empty');

cy.get('#search-input').clear();

cy.get('#results-container').should('be.empty');
});

it('should handle empty search gracefully', () => {
cy.get('#search-input').focus();

cy.get('#results-container').should('be.empty');
});

it('should show no results for non-matching terms', () => {
cy.get('#search-input').type('nonexistentterm');

cy.get('#results-container')
.should('contain', 'No results found');
});
});
Loading
Loading