Skip to content

Commit c37e9a9

Browse files
committed
Fix search CORS in file URIs
1 parent 94e2b62 commit c37e9a9

File tree

4 files changed

+37
-39
lines changed

4 files changed

+37
-39
lines changed

src/renderer/html_handlebars/search.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ pub fn create_files(search_config: &Search, destination: &Path, book: &Book) ->
2222
render_item(&mut index, &search_config, item)?;
2323
}
2424

25-
let json = write_to_json(index, &search_config)?;
25+
let index = write_to_js(index, &search_config)?;
2626
debug!("Writing search index ✓");
2727

2828
if search_config.copy_js {
29-
utils::fs::write_file(destination, "searchindex.json", json.as_bytes())?;
29+
utils::fs::write_file(destination, "searchindex.js", index.as_bytes())?;
3030
utils::fs::write_file(destination, "searcher.js", searcher::JS)?;
3131
utils::fs::write_file(destination, "mark.min.js", searcher::MARK_JS)?;
3232
utils::fs::write_file(destination, "elasticlunr.min.js", searcher::ELASTICLUNR_JS)?;
@@ -144,8 +144,10 @@ fn render_item(index: &mut Index, search_config: &Search, item: &BookItem) -> Re
144144
Ok(())
145145
}
146146

147-
/// Converts the index and search options to a JSON string
148-
fn write_to_json(index: Index, search_config: &Search) -> Result<String> {
147+
/// Exports the index and search options to a JS script which stores the index in `window.search`.
148+
/// Using a JS script is a workaround for CORS in `file://` URIs. It also removes the need for
149+
/// downloading/parsing JSON in JS.
150+
fn write_to_js(index: Index, search_config: &Search) -> Result<String> {
149151
// These structs mirror the configuration javascript object accepted by
150152
// http://elasticlunr.com/docs/configuration.js.html
151153

@@ -204,6 +206,7 @@ fn write_to_json(index: Index, search_config: &Search) -> Result<String> {
204206
searchoptions: searchoptions,
205207
index: index,
206208
};
209+
let json_contents = serde_json::to_string(&json_contents)?;
207210

208-
Ok(serde_json::to_string(&json_contents)?)
211+
Ok(format!("window.search = {};", json_contents))
209212
}

src/theme/index.hbs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,9 @@
246246
<script src="theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
247247
{{/if}}
248248

249+
{{#if search_enabled}}
250+
<script src="searchindex.js" type="text/javascript" charset="utf-8"></script>
251+
{{/if}}
249252
{{#if search_js}}
250253
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
251254
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>

src/theme/searcher/searcher.js

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
window.search = {};
1+
window.search = window.search || {};
22
(function search(search) {
33
// Search functionality
44
//
@@ -236,28 +236,18 @@ window.search = {};
236236
}
237237

238238
function init() {
239-
var request = new XMLHttpRequest();
240-
request.open('GET', 'searchindex.json', true);
241-
242-
request.onload = function() {
243-
if (this.status >= 200 && this.status < 400) {
244-
var json = JSON.parse(this.response);
245-
246-
searchoptions = json.searchoptions;
247-
searchindex = elasticlunr.Index.load(json.index);
248-
249-
// Set up events
250-
searchicon.addEventListener('click', function(e) { searchIconClickHandler(); }, false);
251-
searchbar.addEventListener('keyup', function(e) { searchbarKeyUpHandler(); }, false);
252-
document.addEventListener('keydown', function (e) { globalKeyHandler(e); }, false);
253-
// If the user uses the browser buttons, do the same as if a reload happened
254-
window.onpopstate = function(e) { doSearchOrMarkFromUrl(); };
255-
256-
// If reloaded, do the search or mark again, depending on the current url parameters
257-
doSearchOrMarkFromUrl();
258-
}
259-
};
260-
request.send();
239+
searchoptions = window.search.searchoptions;
240+
searchindex = elasticlunr.Index.load(window.search.index);
241+
242+
// Set up events
243+
searchicon.addEventListener('click', function(e) { searchIconClickHandler(); }, false);
244+
searchbar.addEventListener('keyup', function(e) { searchbarKeyUpHandler(); }, false);
245+
document.addEventListener('keydown', function (e) { globalKeyHandler(e); }, false);
246+
// If the user uses the browser buttons, do the same as if a reload happened
247+
window.onpopstate = function(e) { doSearchOrMarkFromUrl(); };
248+
249+
// If reloaded, do the search or mark again, depending on the current url parameters
250+
doSearchOrMarkFromUrl();
261251
}
262252

263253
function unfocusSearchbar() {

tests/rendered_output.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -349,15 +349,21 @@ mod search {
349349
use mdbook::MDBook;
350350
use dummy_book::DummyBook;
351351

352+
fn read_book_index(root: &Path) -> serde_json::Value {
353+
let index = root.join("book/searchindex.js");
354+
let index = file_to_string(index).unwrap();
355+
let index = index.trim_left_matches("window.search = ");
356+
let index = index.trim_right_matches(";");
357+
serde_json::from_str(&index).unwrap()
358+
}
359+
352360
#[test]
353361
fn book_creates_reasonable_search_index() {
354362
let temp = DummyBook::new().build().unwrap();
355363
let md = MDBook::load(temp.path()).unwrap();
356364
md.build().unwrap();
357365

358-
let index = temp.path().join("book/searchindex.json");
359-
let index = file_to_string(index).unwrap();
360-
let index: serde_json::Value = serde_json::from_str(&index).unwrap();
366+
let index = read_book_index(temp.path());
361367

362368
let bodyidx = &index["index"]["index"]["body"]["root"];
363369
let textidx = &bodyidx["t"]["e"]["x"]["t"];
@@ -393,13 +399,11 @@ mod search {
393399
let md = MDBook::load(temp.path()).unwrap();
394400
md.build().unwrap();
395401

396-
let src = temp.path().join("book/searchindex.json");
397-
let src = File::open(src).unwrap();
398-
let src: serde_json::Value = serde_json::from_reader(src).unwrap();
402+
let src = read_book_index(temp.path());
399403

400404
let dest = Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/searchindex_fixture.json");
401-
let mut dest = File::create(&dest).unwrap();
402-
serde_json::to_writer_pretty(&mut dest, &src).unwrap();
405+
let dest = File::create(&dest).unwrap();
406+
serde_json::to_writer_pretty(dest, &src).unwrap();
403407

404408
src
405409
} else {
@@ -423,9 +427,7 @@ mod search {
423427
let md = MDBook::load(temp.path()).unwrap();
424428
md.build().unwrap();
425429

426-
let book_index = temp.path().join("book/searchindex.json");
427-
let book_index = File::open(book_index).unwrap();
428-
let book_index: serde_json::Value = serde_json::from_reader(book_index).unwrap();
430+
let book_index = read_book_index(temp.path());
429431

430432
let fixture_index = get_fixture();
431433

0 commit comments

Comments
 (0)