├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── CYPRESS.md
├── LICENSE.md
├── README.md
├── WIKI.md
├── cypress.json
├── cypress
├── fixtures
│ ├── example.json
│ ├── profile.json
│ └── users.json
├── integration
│ └── simple-jekyll-search.js
├── plugins
│ └── index.js
└── support
│ ├── commands.js
│ └── index.js
├── dest
├── simple-jekyll-search.js
└── simple-jekyll-search.min.js
├── example
├── Gemfile
├── _includes
│ ├── footer.html
│ ├── head.html
│ └── header.html
├── _layouts
│ ├── default.html
│ ├── page.html
│ └── post.html
├── _plugins
│ ├── simple_search_filter.rb
│ └── simple_search_filter_cn.rb
├── _posts
│ ├── 2014-11-01-welcome-to-jekyll.markdown
│ └── 2014-11-02-test.markdown
├── _sass
│ ├── _base.scss
│ ├── _layout.scss
│ └── _syntax-highlighting.scss
├── about.md
├── css
│ └── main.scss
├── index.html
├── js
│ ├── simple-jekyll-search.js
│ └── simple-jekyll-search.min.js
└── search.json
├── index.html
├── package-lock.json
├── package.json
├── scripts
└── stamp.js
├── src
├── JSONLoader.js
├── OptionsValidator.js
├── Repository.js
├── SearchStrategies
│ ├── FuzzySearchStrategy.js
│ └── LiteralSearchStrategy.js
├── Templater.js
├── index.js
└── utils.js
├── tests
├── OptionsValidator.test.js
├── Repository.test.js
├── SearchStrategies
│ ├── FuzzySearchStrategy.test.js
│ └── LiteralSearchStrategy.test.js
├── Templater.test.js
└── utils.test.js
└── xscode.png
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Simple-Jekyll-Search
2 | on: [push]
3 | jobs:
4 | build_deploy:
5 | runs-on: ubuntu-18.04
6 | steps:
7 | - uses: actions/checkout@master
8 | with:
9 | ref: refs/heads/master
10 | - name: install
11 | run: |
12 | npm install
13 | - name: test
14 | run: |
15 | npm t
16 | # - name: start server for uat
17 | # run: |
18 | # npx http-server example/_site -p 4000
19 | # - name: uat
20 | # uses: cypress-io/github-action@v2
21 | # with:
22 | # record: false
23 | # # cache-key: node-v${{ matrix.node }}-on-${{ runner.os }}-hash-${{ hashFiles('package-lock.json') }}
24 | - name: publish
25 | env:
26 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
27 | run: |
28 | npm config set '//registry.npmjs.org/:_authToken' "${{ secrets.NPM_TOKEN }}"
29 | npm publish || true
30 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.sublime-workspace
2 | npm-debug.log
3 |
4 | .sass-cache/
5 | _site/
6 | node_modules/
7 | cypress/videos/
8 | cypress/screenshots/
9 | .DS_Store
10 | .idea
11 | package-lock.json
12 | .jekyll-cache
--------------------------------------------------------------------------------
/CYPRESS.md:
--------------------------------------------------------------------------------
1 | # Cypress
2 |
3 | ```bash
4 | npm i
5 | ```
6 |
7 | run example blog with jekyll search build
8 |
9 | ```bash
10 | cd example
11 | jekyll serve
12 | ```
13 |
14 | run cypress tests
15 |
16 | ```bash
17 | npm run cypress run
18 | # or
19 | npm run cypress open
20 | ```
21 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Christian Fei
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # [Simple-Jekyll-Search](https://www.npmjs.com/package/simple-jekyll-search)
2 |
3 | [](https://travis-ci.org/christian-fei/Simple-Jekyll-Search)
4 | [](https://david-dm.org/christian-fei/Simple-Jekyll-Search)
5 | [](https://david-dm.org/christian-fei/Simple-Jekyll-Search?type=dev)
6 |
7 | A JavaScript library to add search functionality to any Jekyll blog.
8 |
9 | ## Use case
10 |
11 | You have a blog, built with Jekyll, and want a **lightweight search functionality** on your blog, purely client-side?
12 |
13 | *No server configurations or databases to maintain*.
14 |
15 | Just **5 minutes** to have a **fully working searchable blog**.
16 |
17 | ---
18 |
19 | ## Installation
20 |
21 | ### npm
22 |
23 | ```sh
24 | npm install simple-jekyll-search
25 | ```
26 |
27 | ## Getting started
28 |
29 | ### Create `search.json`
30 |
31 | Place the following code in a file called `search.json` in the **root** of your Jekyll blog. (You can also get a copy [from here](/example/search.json))
32 |
33 | This file will be used as a small data source to perform the searches on the client side:
34 |
35 | ```yaml
36 | ---
37 | layout: none
38 | ---
39 | [
40 | {% for post in site.posts %}
41 | {
42 | "title" : "{{ post.title | escape }}",
43 | "category" : "{{ post.category }}",
44 | "tags" : "{{ post.tags | join: ', ' }}",
45 | "url" : "{{ site.baseurl }}{{ post.url }}",
46 | "date" : "{{ post.date }}"
47 | } {% unless forloop.last %},{% endunless %}
48 | {% endfor %}
49 | ]
50 | ```
51 |
52 |
53 | ## Preparing the plugin
54 |
55 | ### Add DOM elements
56 |
57 | SimpleJekyllSearch needs two `DOM` elements to work:
58 |
59 | - a search input field
60 | - a result container to display the results
61 |
62 | #### Give me the code
63 |
64 | Here is the code you can use with the default configuration:
65 |
66 | You need to place the following code within the layout where you want the search to appear. (See the configuration section below to customize it)
67 |
68 | For example in **_layouts/default.html**:
69 |
70 | ```html
71 |
72 |
73 |
74 |
75 |
76 |
77 | ```
78 |
79 |
80 | ## Usage
81 |
82 | Customize SimpleJekyllSearch by passing in your configuration options:
83 |
84 | ```js
85 | var sjs = SimpleJekyllSearch({
86 | searchInput: document.getElementById('search-input'),
87 | resultsContainer: document.getElementById('results-container'),
88 | json: '/search.json'
89 | })
90 | ```
91 |
92 | ### returns { search }
93 |
94 | A new instance of SimpleJekyllSearch returns an object, with the only property `search`.
95 |
96 | `search` is a function used to simulate a user input and display the matching results.
97 |
98 | E.g.:
99 |
100 | ```js
101 | var sjs = SimpleJekyllSearch({ ...options })
102 | sjs.search('Hello')
103 | ```
104 |
105 | 💡 it can be used to filter posts by tags or categories!
106 |
107 | ## Options
108 |
109 | Here is a list of the available options, usage questions, troubleshooting & guides.
110 |
111 | ### searchInput (Element) [required]
112 |
113 | The input element on which the plugin should listen for keyboard event and trigger the searching and rendering for articles.
114 |
115 |
116 | ### resultsContainer (Element) [required]
117 |
118 | The container element in which the search results should be rendered in. Typically a `
`.
119 |
120 |
121 | ### json (String|JSON) [required]
122 |
123 | You can either pass in an URL to the `search.json` file, or the results in form of JSON directly, to save one round trip to get the data.
124 |
125 |
126 | ### searchResultTemplate (String) [optional]
127 |
128 | The template of a single rendered search result.
129 |
130 | The templating syntax is very simple: You just enclose the properties you want to replace with curly braces.
131 |
132 | E.g.
133 |
134 | The template
135 |
136 | ```js
137 | var sjs = SimpleJekyllSearch({
138 | searchInput: document.getElementById('search-input'),
139 | resultsContainer: document.getElementById('results-container'),
140 | json: '/search.json',
141 | searchResultTemplate: '
149 | ```
150 |
151 | If the `search.json` contains this data
152 |
153 | ```json
154 | [
155 | {
156 | "title" : "Welcome to Jekyll!",
157 | "category" : "",
158 | "tags" : "",
159 | "url" : "/jekyll/update/2014/11/01/welcome-to-jekyll.html",
160 | "date" : "2014-11-01 21:07:22 +0100"
161 | }
162 | ]
163 | ```
164 |
165 |
166 | ### templateMiddleware (Function) [optional]
167 |
168 | A function that will be called whenever a match in the template is found.
169 |
170 | It gets passed the current property name, property value, and the template.
171 |
172 | If the function returns a non-undefined value, it gets replaced in the template.
173 |
174 | This can be potentially useful for manipulating URLs etc.
175 |
176 | Example:
177 |
178 | ```js
179 | SimpleJekyllSearch({
180 | ...
181 | templateMiddleware: function(prop, value, template) {
182 | if (prop === 'bar') {
183 | return value.replace(/^\//, '')
184 | }
185 | }
186 | ...
187 | })
188 | ```
189 |
190 | See the [tests](https://github.com/christian-fei/Simple-Jekyll-Search/blob/master/tests/Templater.test.js) for an in-depth code example
191 |
192 | ### sortMiddleware (Function) [optional]
193 |
194 | A function that will be used to sort the filtered results.
195 |
196 | It can be used for example to group the sections together.
197 |
198 | Example:
199 |
200 | ```js
201 | SimpleJekyllSearch({
202 | ...
203 | sortMiddleware: function(a, b) {
204 | var astr = String(a.section) + "-" + String(a.caption);
205 | var bstr = String(b.section) + "-" + String(b.caption);
206 | return astr.localeCompare(bstr)
207 | }
208 | ...
209 | })
210 | ```
211 |
212 | ### noResultsText (String) [optional]
213 |
214 | The HTML that will be shown if the query didn't match anything.
215 |
216 |
217 | ### limit (Number) [optional]
218 |
219 | You can limit the number of posts rendered on the page.
220 |
221 |
222 | ### fuzzy (Boolean) [optional]
223 |
224 | Enable fuzzy search to allow less restrictive matching.
225 |
226 | ### exclude (Array) [optional]
227 |
228 | Pass in a list of terms you want to exclude (terms will be matched against a regex, so URLs, words are allowed).
229 |
230 | ### success (Function) [optional]
231 |
232 | A function called once the data has been loaded.
233 |
234 | ### debounceTime (Number) [optional]
235 |
236 | Limit how many times the search function can be executed over the given time window. This is especially useful to improve the user experience when searching over a large dataset (either with rare terms or because the number of posts to display is large). If no `debounceTime` (milliseconds) is provided a search will be triggered on each keystroke.
237 |
238 | ---
239 |
240 | ## If search isn't working due to invalid JSON
241 |
242 | - There is a filter plugin in the _plugins folder which should remove most characters that cause invalid JSON. To use it, add the simple_search_filter.rb file to your _plugins folder, and use `remove_chars` as a filter.
243 |
244 | For example: in search.json, replace
245 |
246 | ```json
247 | "content": "{{ page.content | strip_html | strip_newlines }}"
248 | ```
249 |
250 | with
251 |
252 | ```json
253 | "content": "{{ page.content | strip_html | strip_newlines | remove_chars | escape }}"
254 | ```
255 |
256 | If this doesn't work when using Github pages you can try `jsonify` to make sure the content is json compatible:
257 |
258 | ```js
259 | "content": {{ page.content | jsonify }}
260 | ```
261 |
262 | **Note: you don't need to use quotes `"` in this since `jsonify` automatically inserts them.**
263 |
264 |
265 | ## Enabling full-text search
266 |
267 | Replace `search.json` with the following code:
268 |
269 | ```yaml
270 | ---
271 | layout: none
272 | ---
273 | [
274 | {% for post in site.posts %}
275 | {
276 | "title" : "{{ post.title | escape }}",
277 | "category" : "{{ post.category }}",
278 | "tags" : "{{ post.tags | join: ', ' }}",
279 | "url" : "{{ site.baseurl }}{{ post.url }}",
280 | "date" : "{{ post.date }}",
281 | "content" : "{{ post.content | strip_html | strip_newlines }}"
282 | } {% unless forloop.last %},{% endunless %}
283 | {% endfor %}
284 | ,
285 | {% for page in site.pages %}
286 | {
287 | {% if page.title != nil %}
288 | "title" : "{{ page.title | escape }}",
289 | "category" : "{{ page.category }}",
290 | "tags" : "{{ page.tags | join: ', ' }}",
291 | "url" : "{{ site.baseurl }}{{ page.url }}",
292 | "date" : "{{ page.date }}",
293 | "content" : "{{ page.content | strip_html | strip_newlines }}"
294 | {% endif %}
295 | } {% unless forloop.last %},{% endunless %}
296 | {% endfor %}
297 | ]
298 | ```
299 |
300 |
301 |
302 | ## Development
303 |
304 | - `npm install`
305 | - `npm test`
306 |
307 | #### Acceptance tests
308 |
309 | ```bash
310 | cd example; jekyll serve
311 |
312 | # in another tab
313 |
314 | npm run cypress -- run
315 | ```
316 |
317 | ## Contributors
318 |
319 | Thanks to all [contributors](https://github.com/christian-fei/Simple-Jekyll-Search/graphs/contributors) over the years! You are the best :)
320 |
321 | > [@daviddarnes](https://github.com/daviddarnes)
322 | [@XhmikosR](https://github.com/XhmikosR)
323 | [@PeterDaveHello](https://github.com/PeterDaveHello)
324 | [@mikeybeck](https://github.com/mikeybeck)
325 | [@egladman](https://github.com/egladman)
326 | [@midzer](https://github.com/midzer)
327 | [@eduardoboucas](https://github.com/eduardoboucas)
328 | [@kremalicious](https://github.com/kremalicious)
329 | [@tibotiber](https://github.com/tibotiber)
330 | and many others!
331 |
332 | ## Stargazers over time
333 |
334 | [](https://starchart.cc/christian-fei/Simple-Jekyll-Search)
335 |
--------------------------------------------------------------------------------
/WIKI.md:
--------------------------------------------------------------------------------
1 | Welcome to the Simple-Jekyll-Search wiki!
2 |
3 | Here is a list of the available options, usage questions, troubleshootings, guides.
4 |
5 | ## Options
6 | ### searchInput (Element) [required]
7 |
8 | The input element on which the plugin should listen for keyboard event and trigger the searching and rendering for articles.
9 |
10 |
11 | ### resultsContainer (Element) [required]
12 |
13 | The container element in which the search results should be rendered in. Typically an `
`.
14 |
15 |
16 | ### json (String|JSON) [required]
17 |
18 | You can either pass in an URL to the `search.json` file, or the results in form of JSON directly, to save one round trip to get the data.
19 |
20 |
21 | ### searchResultTemplate (String) [optional]
22 |
23 | The template of a single rendered search result.
24 |
25 | The templating syntax is very simple: You just enclose the properties you want to replace with curly braces.
26 |
27 | E.g.
28 |
29 | The template
30 |
31 | ```html
32 |