Add search bar to table of contents
This commit is contained in:
parent
a5341e770c
commit
117f1ee6ee
1
Makefile
1
Makefile
@ -6,6 +6,7 @@ install:
|
||||
cp styles.css /opt/notes2web
|
||||
cp fuse.js /opt/notes2web
|
||||
cp search.js /opt/notes2web
|
||||
cp toc_search.js /opt/notes2web
|
||||
|
||||
uninstall:
|
||||
rm -rf /usr/local/bin/notes2web.py /opt/notes2web
|
||||
|
@ -116,6 +116,7 @@ def get_args():
|
||||
parser.add_argument('-F', '--force', action="store_true", help="Generate new output html even if source file was modified before output html")
|
||||
parser.add_argument('--fuse', type=pathlib.Path, default=pathlib.Path('/opt/notes2web/fuse.js'))
|
||||
parser.add_argument('--searchjs', type=pathlib.Path, default=pathlib.Path('/opt/notes2web/search.js'))
|
||||
parser.add_argument('--tocsearchjs', type=pathlib.Path, default=pathlib.Path('/opt/notes2web/toc_search.js'))
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
@ -345,6 +346,7 @@ def main(args):
|
||||
shutil.copyfile(args.stylesheet, args.output_dir.joinpath('styles.css'))
|
||||
shutil.copyfile(args.fuse, args.output_dir.joinpath('fuse.js'))
|
||||
shutil.copyfile(args.searchjs, args.output_dir.joinpath('search.js'))
|
||||
shutil.copyfile(args.tocsearchjs, args.output_dir.joinpath('toc_search.js'))
|
||||
with open(args.output_dir.joinpath('index.html'), 'w+') as fp:
|
||||
with open(args.home_index) as fp2:
|
||||
html = re.sub(r'\$title\$', args.output_dir.parts[0], fp2.read())
|
||||
|
@ -25,7 +25,13 @@ body {
|
||||
display: flex
|
||||
}
|
||||
|
||||
#search { flex-grow: 9 }
|
||||
#search { flex-grow: 9; }
|
||||
|
||||
#sidebar #search {
|
||||
flex-grow: 0;
|
||||
padding: 1em;
|
||||
margin: 0 1em 1em 1em;
|
||||
}
|
||||
|
||||
#results {
|
||||
overflow-x: scroll;
|
||||
@ -63,6 +69,7 @@ body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 20em;
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
#toc {
|
||||
|
@ -29,6 +29,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<h3>Table of Contents</h3>
|
||||
<input id="search" placeholder="Search table of contents" />
|
||||
<div id="toc">$toc$</div>
|
||||
</div>
|
||||
<div id="content">
|
||||
@ -47,4 +48,6 @@
|
||||
$body$
|
||||
</div>
|
||||
</div>
|
||||
<script src="/fuse.js"> </script>
|
||||
<script src="/toc_search.js"> </script>
|
||||
</body>
|
||||
|
94
toc_search.js
Normal file
94
toc_search.js
Normal file
@ -0,0 +1,94 @@
|
||||
'use strict';
|
||||
|
||||
var raw_html_tree = document.getElementById('toc').firstChild.cloneNode(true);
|
||||
|
||||
function createSearchable(el) {
|
||||
var par = el.parentElement;
|
||||
var obj = el.cloneNode(true);
|
||||
|
||||
while(par != raw_html_tree) {
|
||||
var clone_parent = par.cloneNode(true);
|
||||
|
||||
while (clone_parent.firstChild != clone_parent.lastChild) {
|
||||
clone_parent.removeChild(clone_parent.lastChild);
|
||||
}
|
||||
console.log("obj.innerHTML: " + obj.innerHTML);
|
||||
console.log("clone_parent.firstChild.innerHTML: " + clone_parent.firstChild.innerHTML);
|
||||
if (obj.innerHTML != clone_parent.firstChild.innerHTML)
|
||||
clone_parent.appendChild(obj);
|
||||
|
||||
obj = clone_parent;
|
||||
par = par.parentElement;
|
||||
}
|
||||
|
||||
return {
|
||||
searchable: el.innerHTML,
|
||||
obj: obj
|
||||
};
|
||||
}
|
||||
|
||||
var searchables = [];
|
||||
Array(...raw_html_tree.getElementsByTagName('a'))
|
||||
.forEach(el => searchables.push(createSearchable(el)));
|
||||
|
||||
var fuse = new Fuse(searchables, { keys: [ 'searchable' ], includeMatches: true});
|
||||
var searchBar = document.getElementById('search');
|
||||
var resultsDiv = document.getElementById('toc');
|
||||
|
||||
function updateResults() {
|
||||
var ul = document.createElement('ul');
|
||||
resultsDiv.innerHTML = '';
|
||||
if (searchBar.value == '') {
|
||||
resultsDiv.appendChild(raw_html_tree);
|
||||
return;
|
||||
}
|
||||
var results = fuse.search(searchBar.value);
|
||||
|
||||
|
||||
results.forEach(r => {
|
||||
console.log(r)
|
||||
var content = r.item.obj
|
||||
var last_a = Array.from(r.item.obj.getElementsByTagName('a')).pop()
|
||||
|
||||
r.matches.reverse().every(match => {
|
||||
var display_match = match.value;
|
||||
if (match.indices.length >= 1) {
|
||||
match.indices.sort((a, b) => (b[1]-b[0])-(a[1]-a[0]));
|
||||
const indexPair = match.indices[0];
|
||||
const matching_slice = match.value.slice(indexPair[0], indexPair[1]+1);
|
||||
last_a.innerHTML = match.value.replace(
|
||||
matching_slice,
|
||||
'<span class="matchHighlight">' + matching_slice + '</span>'
|
||||
);
|
||||
}
|
||||
return true;
|
||||
})
|
||||
|
||||
ul.appendChild(content);
|
||||
ul.appendChild(document.createElement('br'));
|
||||
})
|
||||
resultsDiv.appendChild(ul);
|
||||
}
|
||||
|
||||
searchBar.addEventListener('keyup', e => {
|
||||
// if user pressed enter
|
||||
if (e.keyCode === 13) {
|
||||
if (e.shiftKey) {
|
||||
window.open(results[0].item.path, '_blank');
|
||||
} else {
|
||||
window.location.href = results[0].item.path;
|
||||
}
|
||||
return;
|
||||
}
|
||||
updateResults();
|
||||
})
|
||||
|
||||
searchBar.addEventListener('change', updateResults);
|
||||
|
||||
const searchParams = new URL(window.location.href).searchParams;
|
||||
searchBar.value = searchParams.get('q');
|
||||
updateResults();
|
||||
|
||||
if (searchParams.has('lucky')) {
|
||||
window.location.href = results[0].item.path;
|
||||
}
|
Reference in New Issue
Block a user