ethers.js/docs/v5/static/search.js
2020-11-22 23:07:13 -05:00

156 lines
4.7 KiB
JavaScript

"use strict";
(async function() {
const stopWords = "a an and as at for from in of on the with".split(/ /g);
function search(words) {
const blocks = [ ];
const tally = { };
const skipped = [ ];
const searchWords = [ ];
// For each word...
const leftover = words.replace(/([a-z][a-z0-9]*)/ig, (all, word) => {
if (stopWords.indexOf(word.toLowerCase()) >= 0) { return ("|stop:" + word + "|"); }
if (searchWords.indexOf(word) === -1) { searchWords.push(word); }
word = "_" + word.toLowerCase();
const found = data.indices[word];
if (found) {
found.forEach((block) => {
blocks.push(block);
const comps = block.split("/");
if (tally[block] == null) { tally[block] = 0; }
if (tally[comps[0]] == null) { tally[comps[0]] = 0; }
// Give the summary and the summary block some clout
tally[comps[0]] += 1;
tally[block] += 1;
// Give a little extra clout if the title matching
const title = (((data.summaries[comps[0]] || {}).title) || "");
if (title.indexOf(word.substring(1)) >= 0) {
tally[comps[0]] += 1;
}
});
}
// Return this to detect unprocessed characters
return "|";
});
// What parts of the search query di we discard?
leftover.split("|").forEach((junk) => {
junk = junk.trim();
if (junk) { skipped.push(junk); }
});;
console.log("Skipped: " + skipped.map((i) => JSON.stringify(i)).join(", "));
// Score each block
const scores = blocks.reduce((accum, block) => {
const comps = block.split("/");
accum[block] = 11 * tally[block] + 3 * tally[comps[0]];
return accum;
}, { });
const result = Object.keys(scores);
result.sort((a, b) => (scores[b] - scores[a]));
//console.log(scores, result);
let lastComps = [ -1, -1 ];
const output = [ ];
result.forEach((block) => {
const comps = block.split("/").map((v) => parseInt(v));
const summary = data.summaries[comps[0]];
const details = summary.blocks[comps[1]];
if (comps[0] === lastComps[0]) {
const joiner = (comps[1] === lastComps[1] + 1) ? " ": ".. ";
output[output.length - 1].text += joiner + details.text;
} else {
output.push({
title: summary.title,
link: details.link,
text: details.text
});
}
lastComps = comps;
});
return {
results: output,
searchWords: searchWords
};
}
const response = await fetch("/v5/search.json");
const data = await response.json();
const content = document.querySelector("div.content");
const footer = document.querySelector("div.content div.footer");
function htmlify(parent, text, searchWords) {
let current = "";
function flush() {
if (current.length > 0) {
const span = document.createElement("span");
span.textContent = current;
parent.appendChild(span);
current = "";
}
}
for (let i = 0; i < text.length; i++) {
current += text[i];
for (let j = 0; j < searchWords.length; j++) {
const word = searchWords[j];
const offset = current.length - word.length;
const tailValue = current.substring(offset);
if (tailValue.toLowerCase() === word) {
current = current.substring(0, offset);
flush();
const span = document.createElement("span");
span.className = "highlight";
span.textContent = tailValue;
parent.appendChild(span);
break;
}
}
}
flush();
return parent;
}
function appendBlock(title, body, link, searchWords) {
title = title.split(/=>|\(/)[0];
title = title.replace(/--/g, "\xbb");
const titleA = htmlify(document.createElement(link ? "a": "span"), title, searchWords || [ ]);
if (link) {
titleA.setAttribute("href", link);
}
const titleH3 = document.createElement("h3");
titleH3.appendChild(titleA);
content.insertBefore(titleH3, footer)
if (body) {
const bodyP = htmlify(document.createElement("p"), body, searchWords);
content.insertBefore(bodyP, footer)
}
}
const words = decodeURIComponent((location.search.split("search=")[1] || "").replace(/\+/g, " "));
document.getElementById("search").value = words;
const { results, searchWords } = search(words);
if (results.length === 0) {
appendBlock("No Results.")
} else {
results.forEach((result) => {
appendBlock(result.title, result.text, result.link, searchWords);
});
}
})();