Table of Contents
The search page has been linked to from most of the other pages and now we'll create this final page.
HTML - search.html
Start with the same HTML from before. Update the section between the div tags with class subheadings
with:
<h2>Search results for:</h2><h3 id="viewing"></h3>
And update the section between the main
tags with:
<div id="search-nav-top" class="search-nav search-nav-top"></div><div id="results-list" class="search-results-list list-container"></div><div id="search-nav-bottom" class="search-nav search-nav-bottom"></div>
Keep the link to the FUMS JavaScript file.
##JavaScript - search.html
const resultsList = document.querySelector(`#results-list`);const searchInput = document.querySelector(`#search-input`);const searchNavTop = document.querySelector(`#search-nav-top`);const searchNavBottom = document.querySelector(`#search-nav-bottom`);const bibleVersionID = getParameterByName(`version`) || `06125adad2d5898a-01`;const abbreviation = getParameterByName(`abbr`) || "ASV";const query = getParameterByName(`query`);if (query) {document.querySelector(`#viewing`).innerHTML = query;search(query);}function search(searchText, offset = 0) {searchInput.value = searchText;getResults(searchText, offset).then((data) => {let resultsHTML = ``;if (data.verses) {if (!data.verses[0]) {searchNavTop.innerHTML = ``;searchNavBottom.innerHTML = ``;resultsHTML = `<div class="no-results">☹️ No results. Try <a href="index.html">changing versions?</a></div>`;} else {const [topSearchNavHTML, searchNavHTML] = buildNav(offset,data.total,searchText);searchNavTop.innerHTML = topSearchNavHTML;searchNavBottom.innerHTML = searchNavHTML;resultsHTML += `<ul>`;for (let verse of data.verses) {resultsHTML += `<li><h5>${verse.reference}</h5><div class="text not-eb-container">${verse.text}</div><a href="verse.html?version=${bibleVersionID}&abbr=${abbreviation}&chapter=${verse.chapterId}">view chapter</a></li>`;}resultsHTML += `<ul>`;}}if (data.passages) {searchNavTop.innerHTML = ``;searchNavBottom.innerHTML = ``;if (!data.passages[0]) {resultsHTML = `<div class="no-results">☹️ No results. Try <a href="index.html">changing versions?</a></div>`;} else {resultsHTML += `<ul>`;for (let passage of data.passages) {resultsHTML += `<li><h5>${passage.reference}</h5><div class="text eb-container">${passage.content}</div><a href="verse.html?version=${bibleVersionID}&abbr=${abbreviation}&chapter=${passage.chapterIds[0]}">view chapter</a><br></li>`;}resultsHTML += `</ul>`;}}resultsList.innerHTML = resultsHTML;});}function buildNav(offset, total, searchText) {const topSearchNavHTML = `<span class="results-count">Showing <b>${offset * 10 + 1}-${offset * 10 + 10 > total ? total : offset * 10 + 10}</b> of <b>${total}</b> results.</span>`;let searchNavHTML = `<span class="results-current-page"> Current page: <b>${offset + 1}</b></span>`;if (offset > 0 || total / 10 > offset + 1) {searchNavHTML += `<span class="results-nav">`;}if (offset > 0) {searchNavHTML += `<button onclick="search('${searchText}', ${offset - 1})">Previous Page</button>`;}if (total / 10 > offset + 1) {searchNavHTML += `<button onclick="search('${searchText}', ${offset + 1})">Next Page</button>`;}if (offset > 0 || total / 10 > offset + 1) {searchNavHTML += `</span>`;}return [topSearchNavHTML, searchNavHTML];}function getResults(searchText, offset = 0) {return new Promise((resolve, reject) => {const xhr = new XMLHttpRequest();xhr.withCredentials = false;xhr.addEventListener(`readystatechange`, function () {if (this.readyState === this.DONE) {const { data, meta } = JSON.parse(this.responseText);_BAPI.t(meta.fumsId);resolve(data);}});xhr.open(`GET`,`https://api.scripture.api.bible/v1/bibles/${bibleVersionID}/search?query=${searchText}&offset=${offset}`);xhr.setRequestHeader(`api-key`, API_KEY);xhr.onerror = () => reject(xhr.statusText);xhr.send();});}
In line 97, notice that all the data is returned. We don't break out specific fields like usual. While the URL for a search (line 101) is the same whether a user is searching for a passage or keyword, the data returned from the API is different for each case. For a passage search (i.e. 'John 3:16-19'), the data
has an attribute called passages
. For a keyword search (i.e. 'kingdom'), the data
has an attribute called verses
. This is because a passage search can return multiple verses in a single result, while a keyword search returns each verse individually in an array.
See lines 19-39 to see how we display a list of verses. See lines 41-58 to see how we display passages.
Another tricky part of this code is displaying the navigation. On an API call for a search, an offset can be included. This refers to the page number of the results. So for a search result set that includes 100 verses, you can just get 10 at a time. In the buildNav
function on lines 64-85, you can see how we do some simple math to display page numbers and which results are being displayed.
Like before, include the
getParameterByName
andsearchButton
functions from the previous pages."