- Dynamically resolve image paths for podcast episodes in `episodes.11tydata.js` - Add podcast metadata handling with inferred URLs for MP3 and transcripts - Introduce search functionality with Lunr.js and a search index generator - Update Eleventy path prefix handling to support environment variable override - Add `.mp4` files to `.gitignore` - Expand VSCode settings to include Markdown-Eleventy support and improved terminal history - Add deployment script (`deploy.sh`) with remote rsync-based deployment and permission handling - Adjust episode layout to use dynamic image paths and updated podcast metadata - Add search and members page updates, including new URLs and search integration - Update dependencies to include `html-to-text` and related packages for search indexing
84 lines
2.4 KiB
Handlebars
84 lines
2.4 KiB
Handlebars
---
|
|
layout: base-with-heading
|
|
title: Search Episodes
|
|
eleventyExcludeFromCollections: ["episode"]
|
|
override:tags: []
|
|
override:eleventyComputed: []
|
|
---
|
|
|
|
<script src="https://unpkg.com/lunr/lunr.js"></script>
|
|
|
|
<div>
|
|
<form id="search-form">
|
|
<input type="text" class="form-control mb-3" name="searchQuery" id="searchQuery">
|
|
<button class="btn btn-primary mb-3" type="submit">Search</button>
|
|
</form>
|
|
<div id="results">
|
|
<ol></ol>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
let idx, docs
|
|
let search_index_promise = fetch('../search-index')
|
|
.then((res)=>res.json())
|
|
.then((documents)=>{
|
|
docs = documents
|
|
idx = lunr(function(){
|
|
this.ref('id')
|
|
this.field('text')
|
|
this.field('title')
|
|
this.metadataWhitelist = ['position']
|
|
documents.forEach(function (doc, idx) {
|
|
doc.id = idx;
|
|
this.add(doc);
|
|
}, this)
|
|
})
|
|
})
|
|
|
|
function highlightTokens(element, tokens) {
|
|
const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, nodeFilter, false);
|
|
let node = null;
|
|
|
|
while ((node = walker.nextNode())) {
|
|
const text = node.textContent.toLowerCase();
|
|
let found = false;
|
|
for (var i = 0; i < tokens.length && !found; i++) {
|
|
const token = tokens[i].toString();
|
|
const startIndex = text.indexOf(token);
|
|
if (startIndex == -1) {
|
|
continue;
|
|
}
|
|
let range = document.createRange();
|
|
range.setStart(node, startIndex);
|
|
range.setEnd(node, startIndex + token.length);
|
|
let mark = document.createElement('mark');
|
|
range.surroundContents(mark);
|
|
found = true;
|
|
}
|
|
walker.nextNode();
|
|
}
|
|
}
|
|
|
|
function handleSubmit(evt) {
|
|
evt.preventDefault();
|
|
const formData = new FormData(evt.target)
|
|
const {searchQuery} = Object.fromEntries(formData)
|
|
results = idx.search(searchQuery)
|
|
results.forEach(r => {
|
|
r.title = docs[r.ref].title,
|
|
r.url = docs[r.ref].url
|
|
})
|
|
console.log('Form submitted!', results)
|
|
results_ol = document.getElementById("results").querySelector('ol')
|
|
results_ol.innerHTML = ""
|
|
results.forEach(r => {
|
|
const el = document.createElement('li')
|
|
const {url, title, text, season, episode} = docs[r.ref]
|
|
el.innerHTML =`<a href="${url}">${title} (Season ${season}, episode ${episode})</a><p>${text}</p>`
|
|
results_ol.appendChild(el)
|
|
})
|
|
}
|
|
document.getElementById('search-form').addEventListener('submit', handleSubmit)
|
|
|
|
</script> |