mirror of
https://github.com/getzola/zola
synced 2024-11-10 14:24:27 +00:00
Search json index (#1998)
* search: Add support for a JSON index * docs: Document JSON index for search * docs: Use lazy-loaded JSON index * Add elasticlunr prefix to search engine format configuration This will be useful if support for more search libraries are added in the future
This commit is contained in:
parent
291c93e4ba
commit
7000f787b3
8 changed files with 73 additions and 26 deletions
|
@ -1,5 +1,18 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum IndexFormat {
|
||||
ElasticlunrJson,
|
||||
ElasticlunrJavascript,
|
||||
}
|
||||
|
||||
impl Default for IndexFormat {
|
||||
fn default() -> IndexFormat {
|
||||
IndexFormat::ElasticlunrJavascript
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct Search {
|
||||
|
@ -15,6 +28,8 @@ pub struct Search {
|
|||
pub include_description: bool,
|
||||
/// Include the path of the page in the search index. `false` by default.
|
||||
pub include_path: bool,
|
||||
/// Foramt of the search index to be produced. Javascript by default
|
||||
pub index_format: IndexFormat,
|
||||
}
|
||||
|
||||
impl Default for Search {
|
||||
|
@ -25,6 +40,7 @@ impl Default for Search {
|
|||
include_description: false,
|
||||
include_path: false,
|
||||
truncate_content_length: None,
|
||||
index_format: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,13 @@ mod theme;
|
|||
use std::path::Path;
|
||||
|
||||
pub use crate::config::{
|
||||
languages::LanguageOptions, link_checker::LinkChecker, link_checker::LinkCheckerLevel,
|
||||
search::Search, slugify::Slugify, taxonomies::TaxonomyConfig, Config,
|
||||
languages::LanguageOptions,
|
||||
link_checker::LinkChecker,
|
||||
link_checker::LinkCheckerLevel,
|
||||
search::{IndexFormat, Search},
|
||||
slugify::Slugify,
|
||||
taxonomies::TaxonomyConfig,
|
||||
Config,
|
||||
};
|
||||
use errors::Result;
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ use libs::rayon::prelude::*;
|
|||
use libs::tera::{Context, Tera};
|
||||
use libs::walkdir::{DirEntry, WalkDir};
|
||||
|
||||
use config::{get_config, Config};
|
||||
use config::{get_config, Config, IndexFormat};
|
||||
use content::{Library, Page, Paginator, Section, Taxonomy};
|
||||
use errors::{anyhow, bail, Context as ErrorContext, Result};
|
||||
use libs::relative_path::RelativePathBuf;
|
||||
|
@ -764,32 +764,36 @@ impl Site {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn index_for_lang(&self, lang: &str) -> Result<()> {
|
||||
let index_json = search::build_index(
|
||||
&self.config.default_language,
|
||||
&self.library.read().unwrap(),
|
||||
&self.config,
|
||||
)?;
|
||||
let (path, content) = match &self.config.search.index_format {
|
||||
IndexFormat::ElasticlunrJson => {
|
||||
let path = self.output_path.join(&format!("search_index.{}.json", lang));
|
||||
(path, index_json)
|
||||
}
|
||||
IndexFormat::ElasticlunrJavascript => {
|
||||
let path = self.output_path.join(&format!("search_index.{}.js", lang));
|
||||
let content = format!("window.searchIndex = {};", index_json);
|
||||
(path, content)
|
||||
}
|
||||
};
|
||||
create_file(&path, &content)
|
||||
}
|
||||
|
||||
pub fn build_search_index(&self) -> Result<()> {
|
||||
ensure_directory_exists(&self.output_path)?;
|
||||
// TODO: add those to the SITE_CONTENT map
|
||||
|
||||
// index first
|
||||
create_file(
|
||||
&self.output_path.join(&format!("search_index.{}.js", self.config.default_language)),
|
||||
&format!(
|
||||
"window.searchIndex = {};",
|
||||
search::build_index(
|
||||
&self.config.default_language,
|
||||
&self.library.read().unwrap(),
|
||||
&self.config
|
||||
)?
|
||||
),
|
||||
)?;
|
||||
self.index_for_lang(&self.config.default_language)?;
|
||||
|
||||
for (code, language) in &self.config.other_languages() {
|
||||
if code != &self.config.default_language && language.build_search_index {
|
||||
create_file(
|
||||
&self.output_path.join(&format!("search_index.{}.js", &code)),
|
||||
&format!(
|
||||
"window.searchIndex = {};",
|
||||
search::build_index(code, &self.library.read().unwrap(), &self.config)?
|
||||
),
|
||||
)?;
|
||||
self.index_for_lang(code)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,9 @@ description = "Everything you need to make a static site engine in one binary."
|
|||
compile_sass = true
|
||||
build_search_index = true
|
||||
|
||||
[search]
|
||||
index_format = "elasticlunr_json"
|
||||
|
||||
[markdown]
|
||||
highlight_code = true
|
||||
highlight_theme = "kronuz"
|
||||
|
|
|
@ -17,6 +17,9 @@ After `zola build` or `zola serve`, you should see two files in your public dire
|
|||
- `search_index.${default_language}.js`: so `search_index.en.js` for a default setup
|
||||
- `elasticlunr.min.js`
|
||||
|
||||
If you set `index_format = "elasticlunr_json"` in your `config.toml`, a `search_index.${default_language}.json` is generated
|
||||
instead of the default `search_index.${default_language}.js`.
|
||||
|
||||
As each site will be different, Zola makes no assumptions about your search function and doesn't provide
|
||||
the JavaScript/CSS code to do an actual search and display results. You can look at how this site
|
||||
implements it to get an idea: [search.js](https://github.com/getzola/zola/tree/master/docs/static/search.js).
|
||||
|
|
|
@ -160,6 +160,10 @@ include_content = true
|
|||
# become too big to load on the site. Defaults to not being set.
|
||||
# truncate_content_length = 100
|
||||
|
||||
# Wether to produce the search index as a javascript file or as a JSON file
|
||||
# Accepted value "elasticlunr_javascript" or "elasticlunr_json"
|
||||
index_format = "elasticlunr_javascript"
|
||||
|
||||
# Optional translation object for the default language
|
||||
# Example:
|
||||
# default_language = "fr"
|
||||
|
|
21
docs/static/search.js
vendored
21
docs/static/search.js
vendored
|
@ -142,11 +142,24 @@ function initSearch() {
|
|||
}
|
||||
};
|
||||
var currentTerm = "";
|
||||
var index = elasticlunr.Index.load(window.searchIndex);
|
||||
var index;
|
||||
|
||||
var initIndex = async function () {
|
||||
if (index === undefined) {
|
||||
index = fetch("/search_index.en.json")
|
||||
.then(
|
||||
async function(response) {
|
||||
return await elasticlunr.Index.load(await response.json());
|
||||
}
|
||||
);
|
||||
}
|
||||
let res = await index;
|
||||
return res;
|
||||
}
|
||||
|
||||
$searchInput.addEventListener("keyup", debounce(function() {
|
||||
$searchInput.addEventListener("keyup", debounce(async function() {
|
||||
var term = $searchInput.value.trim();
|
||||
if (term === currentTerm || !index) {
|
||||
if (term === currentTerm) {
|
||||
return;
|
||||
}
|
||||
$searchResults.style.display = term === "" ? "none" : "block";
|
||||
|
@ -156,7 +169,7 @@ function initSearch() {
|
|||
return;
|
||||
}
|
||||
|
||||
var results = index.search(term, options);
|
||||
var results = (await initIndex()).search(term, options);
|
||||
if (results.length === 0) {
|
||||
$searchResults.style.display = "none";
|
||||
return;
|
||||
|
|
1
docs/templates/index.html
vendored
1
docs/templates/index.html
vendored
|
@ -103,7 +103,6 @@
|
|||
</footer>
|
||||
|
||||
<script type="text/javascript" src="{{ get_url(path="elasticlunr.min.js") }}"></script>
|
||||
<script type="text/javascript" src="{{ get_url(path="search_index.en.js") }}"></script>
|
||||
<script type="text/javascript" src="{{ get_url(path="search.js") }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Reference in a new issue