241 lines
8.4 KiB
JavaScript
241 lines
8.4 KiB
JavaScript
|
if (location.hash && location.hash.length > 0) {
|
||
|
var initialQuery = location.hash;
|
||
|
if (initialQuery[0] == "#") {
|
||
|
initialQuery = initialQuery.slice(1);
|
||
|
}
|
||
|
document.getElementById("query").value = decodeURIComponent(initialQuery);
|
||
|
}
|
||
|
|
||
|
|
||
|
var indexContainer = document.getElementById("cineraIndex");
|
||
|
var lastQuery = null;
|
||
|
var resultsToRender = [];
|
||
|
var resultsIndex = 0;
|
||
|
var resultsMarkerIndex = 0;
|
||
|
var resultsContainer = document.getElementById("results");
|
||
|
var rendering = false;
|
||
|
|
||
|
var dayContainerPrototype = document.createElement("DIV");
|
||
|
dayContainerPrototype.classList.add("dayContainer");
|
||
|
dayContainerPrototype.classList.add(projectID);
|
||
|
|
||
|
var dayNamePrototype = document.createElement("SPAN");
|
||
|
dayNamePrototype.classList.add("dayName");
|
||
|
dayContainerPrototype.appendChild(dayNamePrototype);
|
||
|
|
||
|
var markerListPrototype = document.createElement("DIV");
|
||
|
markerListPrototype.classList.add("markerList");
|
||
|
markerListPrototype.classList.add(projectID);
|
||
|
dayContainerPrototype.appendChild(markerListPrototype);
|
||
|
|
||
|
var markerPrototype = document.createElement("A");
|
||
|
markerPrototype.classList.add("marker");
|
||
|
markerPrototype.setAttribute("target", "_blank");
|
||
|
|
||
|
var highlightPrototype = document.createElement("B");
|
||
|
|
||
|
var episodes = [];
|
||
|
|
||
|
function getEpisodeName(filename) {
|
||
|
var day = filename;
|
||
|
var dayParts = day.match(/([a-zA-Z_-]+)([0-9]+)?([a-zA-Z]+)?/);
|
||
|
day = dayParts[1].slice(0, 1).toUpperCase() + dayParts[1].slice(1) + (dayParts[2] ? " " + dayParts[2] : "") + (dayParts[3] ? " " + dayParts[3].toUpperCase() : "");
|
||
|
return day;
|
||
|
}
|
||
|
|
||
|
function markerTime(totalTime) {
|
||
|
var markTime = "(";
|
||
|
var hours = Math.floor(totalTime / 60 / 60);
|
||
|
var minutes = Math.floor(totalTime / 60) % 60;
|
||
|
var seconds = totalTime % 60;
|
||
|
if (hours > 0) {
|
||
|
markTime += padTimeComponent(hours) + ":";
|
||
|
}
|
||
|
|
||
|
markTime += padTimeComponent(minutes) + ":" + padTimeComponent(seconds) + ")";
|
||
|
|
||
|
return markTime;
|
||
|
}
|
||
|
|
||
|
function padTimeComponent(component) {
|
||
|
return (component < 10 ? "0" + component : component);
|
||
|
}
|
||
|
|
||
|
function runSearch() {
|
||
|
var queryStr = document.getElementById("query").value;
|
||
|
if (lastQuery != queryStr) {
|
||
|
var oldResultsContainer = resultsContainer;
|
||
|
resultsContainer = oldResultsContainer.cloneNode(false);
|
||
|
oldResultsContainer.parentNode.insertBefore(resultsContainer, oldResultsContainer);
|
||
|
oldResultsContainer.remove();
|
||
|
resultsIndex = 0;
|
||
|
resultsMarkerIndex = 0;
|
||
|
}
|
||
|
lastQuery = queryStr;
|
||
|
resultsToRender = [];
|
||
|
var numEpisodes = 0;
|
||
|
var numMarkers = 0;
|
||
|
var totalSeconds = 0;
|
||
|
if (queryStr && queryStr.length > 0) {
|
||
|
indexContainer.style.display = "none";
|
||
|
if (episodes.length > 0) {
|
||
|
var query = new RegExp(queryStr.replace("(", "\\(").replace(")", "\\)").replace(/(^|[^\\])\\$/, "$1"), "gi");
|
||
|
for (var i = 0; i < episodes.length; ++i) {
|
||
|
var episode = episodes[i];
|
||
|
var matches = [];
|
||
|
for (var j = 0; j < episode.markers.length; ++j) {
|
||
|
query.lastIndex = 0;
|
||
|
var result = query.exec(episode.markers[j].text);
|
||
|
if (result && result[0].length > 0) {
|
||
|
numMarkers++;
|
||
|
matches.push(episode.markers[j]);
|
||
|
if (j < episode.markers.length-1) {
|
||
|
totalSeconds += episode.markers[j+1].totalTime - episode.markers[j].totalTime;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (matches.length > 0) {
|
||
|
numEpisodes++;
|
||
|
resultsToRender.push({
|
||
|
query: query,
|
||
|
episode: episode,
|
||
|
matches: matches
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!rendering) {
|
||
|
renderResults();
|
||
|
}
|
||
|
} else {
|
||
|
document.querySelector(".spinner").classList.add("show");
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
indexContainer.style.display = "block";
|
||
|
}
|
||
|
|
||
|
var totalTime = Math.floor(totalSeconds/60/60) + "h " + Math.floor(totalSeconds/60)%60 + "m " + totalSeconds%60 + "s ";
|
||
|
|
||
|
document.getElementById("resultsSummary").textContent = "Found: " + numEpisodes + " episodes, " + numMarkers + " markers, " + totalTime + "total.";
|
||
|
}
|
||
|
|
||
|
function renderMatches(renderStart) {
|
||
|
var query = resultsToRender[resultsIndex].query;
|
||
|
var episode = resultsToRender[resultsIndex].episode;
|
||
|
var matches = resultsToRender[resultsIndex].matches;
|
||
|
var markerList = null;
|
||
|
if (resultsMarkerIndex == 0) {
|
||
|
var dayContainer = dayContainerPrototype.cloneNode(true);
|
||
|
var dayName = dayContainer.children[0];
|
||
|
markerList = dayContainer.children[1];
|
||
|
dayName.textContent = episode.day + ": " + episode.title;
|
||
|
resultsContainer.appendChild(dayContainer);
|
||
|
} else {
|
||
|
markerList = document.querySelector("#results > .dayContainer:nth-child(" + (resultsIndex+1) + ") .markerList");
|
||
|
}
|
||
|
|
||
|
do {
|
||
|
var match = matches[resultsMarkerIndex];
|
||
|
var marker = markerPrototype.cloneNode();
|
||
|
marker.setAttribute("href", episode.filename.replace(/"/g, "") + "/#" + match.totalTime);
|
||
|
query.lastIndex = 0;
|
||
|
var cursor = 0;
|
||
|
var text = match.text;
|
||
|
var result = null;
|
||
|
marker.appendChild(document.createTextNode(match.prettyTime + " "));
|
||
|
while (result = query.exec(text)) {
|
||
|
if (result.index > cursor) {
|
||
|
marker.appendChild(document.createTextNode(text.slice(cursor, result.index)));
|
||
|
}
|
||
|
var highlightEl = highlightPrototype.cloneNode();
|
||
|
highlightEl.textContent = result[0];
|
||
|
marker.appendChild(highlightEl);
|
||
|
cursor = result.index + result[0].length;
|
||
|
}
|
||
|
|
||
|
if (cursor < text.length) {
|
||
|
marker.appendChild(document.createTextNode(text.slice(cursor, text.length)));
|
||
|
}
|
||
|
markerList.appendChild(marker);
|
||
|
resultsMarkerIndex++;
|
||
|
} while (resultsMarkerIndex < matches.length && performance.now() - renderStart < 1);
|
||
|
|
||
|
return resultsMarkerIndex == matches.length;
|
||
|
}
|
||
|
|
||
|
function renderResults() {
|
||
|
if (resultsIndex < resultsToRender.length) {
|
||
|
rendering = true;
|
||
|
var renderStart = performance.now();
|
||
|
while (resultsIndex < resultsToRender.length && performance.now() - renderStart < 1) {
|
||
|
var done = renderMatches(renderStart);
|
||
|
if (done) {
|
||
|
resultsMarkerIndex = 0;
|
||
|
resultsIndex++;
|
||
|
}
|
||
|
}
|
||
|
requestAnimationFrame(renderResults);
|
||
|
} else {
|
||
|
rendering = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var queryEl = document.getElementById("query")
|
||
|
queryEl.addEventListener("input", function(ev) {
|
||
|
history.replaceState(null, null, "#" + encodeURIComponent(queryEl.value));
|
||
|
runSearch();
|
||
|
});
|
||
|
|
||
|
var xhr = new XMLHttpRequest();
|
||
|
xhr.addEventListener("load", function() {
|
||
|
var contents = xhr.response;
|
||
|
var lines = contents.split("\n");
|
||
|
var mode = "none";
|
||
|
var episode = null;
|
||
|
for (var i = 0; i < lines.length; ++i) {
|
||
|
var line = lines[i];
|
||
|
if (line.trim().length == 0) { continue; }
|
||
|
if (line == "---") {
|
||
|
if (episode != null) {
|
||
|
episode.filename = episode.name;
|
||
|
episode.day = getEpisodeName(episode.filename + ".html.md");
|
||
|
episodes.push(episode);
|
||
|
}
|
||
|
episode = {};
|
||
|
mode = "none";
|
||
|
} else if (line.startsWith("name:")) {
|
||
|
episode.name = line.slice(6);
|
||
|
} else if (line.startsWith("title:")) {
|
||
|
episode.title = line.slice(7).replace(/"/g, "");
|
||
|
} else if (line.startsWith("markers")) {
|
||
|
mode = "markers";
|
||
|
episode.markers = [];
|
||
|
} else if (mode == "markers") {
|
||
|
var match = line.match(/"(\d+)": "(.+)"/);
|
||
|
if (match == null) {
|
||
|
console.log(name, line);
|
||
|
} else {
|
||
|
var totalTime = parseInt(line.slice(1));
|
||
|
var marker = {
|
||
|
totalTime: totalTime,
|
||
|
prettyTime: markerTime(totalTime),
|
||
|
text: match[2].replace(/\\"/g, "\"")
|
||
|
}
|
||
|
episode.markers.push(marker);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
document.querySelector(".spinner").classList.remove("show");
|
||
|
runSearch();
|
||
|
});
|
||
|
xhr.addEventListener("error", function() {
|
||
|
console.error("Failed to load content");
|
||
|
});
|
||
|
xhr.open("GET", indexLocation);
|
||
|
xhr.setRequestHeader("Content-Type", "text/plain");
|
||
|
xhr.send();
|
||
|
|
||
|
runSearch();
|