Skip to content

Commit f06387c

Browse files
committed
Added search script inlining functionality
1 parent 6ef3da7 commit f06387c

File tree

5 files changed

+66
-15
lines changed

5 files changed

+66
-15
lines changed

README.md

+9-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ plugins:
6161
2. Add a tag where the search elements should be inserted and load the search script:
6262
```markdown
6363
<div id="listing-extract-search"></div>
64-
<script src="/listing-search.js">
64+
<script src="/listing-search.js" async></script>
6565
```
6666
3. Specify where you want the plugin to write the script file to.
6767
This should match the path you used in the previous step.
@@ -73,6 +73,14 @@ This should match the path you used in the previous step.
7373
javascript_search_file: listing-search.js
7474
```
7575
76+
I recommend using an absolute path for the `script.src` attribute, since it will keep working after moving the page or after switching between directory URLs and non directory URLs pages.
77+
It just runs into problems when your base directory (where the page is deployed) is not the root directory or when you are using offline mode (from `file://` URLs).
78+
79+
Alternatively you can include the script and the data inline, but this can have tiny performance drawbacks:
80+
81+
- If you include it on multiple pages, all of them will contain a copy of the data -> reduces caching efficiency
82+
- The whole search database needs to be downloaded while your page is loading (can not use `async` or `defer` script attributes).
83+
7684
## Configuration
7785
7886
You can configure the plugin like this:

docs/plugin/inline-listing-search.md

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
hide:
3+
- toc
4+
---
5+
6+
# Inline Listing search
7+
8+
This page has a search function for all listings.
9+
10+
PLACEHOLDER_INLINE_LISTINGS_SEARCH_PLUGIN

src/mkdocs_extract_listings_plugin/__init__.py

+12-3
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,13 @@ class ListingsConfig(Config):
2424
# local
2525
from .page_processor import PageProcessor
2626
from .all_listings_page import update_all_listings_page
27-
from .search_page import write_javascript_file
27+
from .search_page import write_javascript_file, get_javascript_file_source_code
2828

2929

3030
class ListingsPlugin(BasePlugin[ListingsConfig]):
3131
def on_config(self, config: MkDocsConfig) -> None:
3232
self.page_processor = PageProcessor(self.config)
3333

34-
3534
def on_pre_build(self, config: MkDocsConfig) -> None:
3635
# Reset before every build -> prevent duplicate entries when running mkdocs serve
3736
self.page_processor.clear()
@@ -47,12 +46,22 @@ def on_pre_build(self, config: MkDocsConfig) -> None:
4746
logger.warning(f"Value for 'listings_file' should probably end in '.md', but is '{self.config.listings_file}'")
4847
else:
4948
if not self.config.javascript_search_file:
50-
logger.warning("Neither 'javascript_search_file' nor 'listings_file' are set -> This plugin will do nothing. Please check the setup instructions at https://github.com/six-two/mkdocs-extract-listings-plugin/blob/main/README.md")
49+
logger.warning("Neither 'javascript_search_file' nor 'listings_file' are set -> This plugin will do nothing, unless you use inline placeholder replacement. Please check the setup instructions at https://github.com/six-two/mkdocs-extract-listings-plugin/blob/main/README.md")
5150

5251
# https://www.mkdocs.org/dev-guide/plugins/#on_page_content
5352
def on_page_content(self, html: str, page: Page, config: MkDocsConfig, files) -> None:
5453
self.page_processor.process_page(html, page)
5554

55+
# https://www.mkdocs.org/dev-guide/plugins/#on_post_page
56+
def on_post_page(self, output: str, page: Page, config: MkDocsConfig) -> str:
57+
if "PLACEHOLDER_INLINE_LISTINGS_SEARCH_PLUGIN" in output:
58+
# Can not be cached, since script paths are dependent on current page path
59+
# https://www.mkdocs.org/dev-guide/themes/#page
60+
# https://www.mkdocs.org/dev-guide/api/#mkdocs.structure.files.File.src_uri
61+
inline_script_html = '<div id="listing-extract-search"></div>\n<script>\n' + get_javascript_file_source_code(self.page_processor.page_data_list, self.config, True, page.file.src_uri, config) + '\n</script>'
62+
output = output.replace("PLACEHOLDER_INLINE_LISTINGS_SEARCH_PLUGIN", inline_script_html)
63+
return output
64+
5665
def on_post_build(self, config: MkDocsConfig) -> None:
5766
update_all_listings_page(self.page_processor.page_data_list, self.config, config)
5867

src/mkdocs_extract_listings_plugin/listing-search.js

+21-3
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,33 @@
77
// This limits load required to parse entries, etc and should result in the user getting some quick feedback on his/her search
88
(() => {
99
PREVIEW_RESULTS = 15;
10-
BASE_URL="";
1110
DEFAULT_SEARCH_MODE="substr-i";
1211
// START: These values may be overwritten when the file is copied by the plugin
1312
STYLE=``;
1413
OFFLINE_JSON_DATA=null;
1514
// END
1615

17-
let parentDirectoryUrl = new URL(document.currentScript.src);
18-
parentDirectoryUrl.pathname = parentDirectoryUrl.pathname.substring(0, parentDirectoryUrl.pathname.lastIndexOf("/") + 1);
16+
let parentDirectoryUrl;
17+
if (document.currentScript && document.currentScript.src) {
18+
// This is run when the script is included via an <script src=...> tag.
19+
// The script is always at the same location, no matter on which page it is inluded.
20+
parentDirectoryUrl = new URL(document.currentScript.src);
21+
parentDirectoryUrl.pathname = parentDirectoryUrl.pathname.substring(0, parentDirectoryUrl.pathname.lastIndexOf("/") + 1);
22+
} else {
23+
// This is run when the script is inlined to a page.
24+
// In this case we can not be certain about where we are, but the python code fixed all relative paths, so that they should work from here.
25+
parentDirectoryUrl = new URL(window.location.href);
26+
const directoryUrlsUsed = parentDirectoryUrl.pathname.endsWith("/") || parentDirectoryUrl.pathname.endsWith("/index.html")
27+
if (directoryUrlsUsed) {
28+
// Directory URLs are in use -> go up one directory and remove file name
29+
parentDirectoryUrl.pathname = parentDirectoryUrl.pathname.substring(0, parentDirectoryUrl.pathname.lastIndexOf("/"));
30+
parentDirectoryUrl.pathname = parentDirectoryUrl.pathname.substring(0, parentDirectoryUrl.pathname.lastIndexOf("/") + 1);
31+
} else {
32+
// Directory URLs are disabled -> stay in directory but remove file name
33+
parentDirectoryUrl.pathname = parentDirectoryUrl.pathname.substring(0, parentDirectoryUrl.pathname.lastIndexOf("/") + 1);
34+
}
35+
}
36+
1937
parentDirectoryUrl.query = "";
2038
parentDirectoryUrl.hash = "";
2139
const base_url = parentDirectoryUrl.href.endsWith("/") ? parentDirectoryUrl.href : parentDirectoryUrl.href + "/";

src/mkdocs_extract_listings_plugin/search_page.py

+14-8
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,7 @@
88
from .page_processor import PageData
99

1010

11-
def write_javascript_file(page_data_list: list[PageData], plugin_config, config: MkDocsConfig) -> None:
12-
dst_path = os.path.join(config.site_dir, plugin_config.javascript_search_file)
13-
dst_path_parent = os.path.dirname(dst_path)
14-
if not os.path.exists(dst_path_parent):
15-
os.makedirs(dst_path_parent)
16-
11+
def get_javascript_file_source_code(page_data_list: list[PageData], plugin_config, offline: bool, script_or_page_path: str, config: MkDocsConfig) -> str:
1712
src_path = os.path.join(SCRIPT_DIR, "listing-search.js")
1813
with open(src_path, "r") as f:
1914
js = f.read()
@@ -24,8 +19,8 @@ def write_javascript_file(page_data_list: list[PageData], plugin_config, config:
2419
js = js.replace("STYLE=``;", f"STYLE=`{css}`;")
2520

2621
# We traverse from the JSON file up to the root directory
27-
path_to_root = "../" * plugin_config.javascript_search_file.count("/")
28-
if plugin_config.offline:
22+
path_to_root = "../" * script_or_page_path.count("/")
23+
if offline:
2924
json_data = get_json_data(page_data_list, path_to_root)
3025
js = js.replace("OFFLINE_JSON_DATA=null;", f"OFFLINE_JSON_DATA={json.dumps(json_data)};")
3126
else:
@@ -41,6 +36,17 @@ def write_javascript_file(page_data_list: list[PageData], plugin_config, config:
4136
# Path contains something else than just slashes
4237
js = js.replace('BASE_URL=""', f'BASE_URL="{path}"')
4338

39+
return js
40+
41+
42+
def write_javascript_file(page_data_list: list[PageData], plugin_config, config: MkDocsConfig) -> None:
43+
dst_path = os.path.join(config.site_dir, plugin_config.javascript_search_file)
44+
dst_path_parent = os.path.dirname(dst_path)
45+
if not os.path.exists(dst_path_parent):
46+
os.makedirs(dst_path_parent)
47+
48+
js = get_javascript_file_source_code(page_data_list, plugin_config, plugin_config.offline, plugin_config.javascript_search_file, config)
49+
4450
with open(dst_path, "w") as f:
4551
f.write(js)
4652

0 commit comments

Comments
 (0)