Skip to content

Commit

Permalink
Updated Shakespeare search to fix scrollIntoView jank and use History…
Browse files Browse the repository at this point in the history
….pushState
  • Loading branch information
samdutton committed Jan 15, 2018
1 parent 036f894 commit 314276f
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 19 deletions.
2 changes: 1 addition & 1 deletion search/shakespeare/elasticlunr/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ iframe {
height: calc(100% - 100px);
opacity: 1;
overflow: scroll;
transition: opacity 2.5s;
/* transition: opacity .5s;*/
width: 100%;
}

Expand Down
42 changes: 24 additions & 18 deletions search/shakespeare/elasticlunr/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,8 @@ limitations under the License.

/* global elasticlunr */

const queryInput = document.getElementById('query');
// Search for products whenever query input text changes
queryInput.oninput = doSearch;
const matchesList = document.getElementById('matches');
const queryInput = document.getElementById('query');
const textIframe = document.querySelector('iframe');

const SEARCH_OPTIONS = {
Expand Down Expand Up @@ -58,7 +56,7 @@ window.addEventListener('beforeunload', function(event) {
console.log('beforeunload event', event);
});

// Get index data and load index
// Get and load index data
console.log('Fetching index...');
console.time('Fetch index');
fetch(INDEX_FILE).then(response => {
Expand All @@ -77,28 +75,31 @@ fetch(INDEX_FILE).then(response => {
queryInput.focus();
});


function doSearch() {
// Search whenever query input text changes, with debounce delay
queryInput.oninput = function() {
matchesList.textContent = '';
const query = queryInput.value;
if (query.length < 3) {
return;
}
// debounce text entry
clearTimeout(timeout);
timeout = setTimeout(function() {
console.time(`Do search for ${query}`);
const matches = index.search(query, SEARCH_OPTIONS);
if (matches.length > 0) {
hide(textIframe);
hide(textIframe); // hide the iframe for play or poem texts
displayMatches(matches, query);
show(matchesList);
highlighttches(matches, query);
}
console.timeEnd(`Do search for ${query}`);
}, DEBOUNCE_DELAY);
}
history.pushState(null, null, `${window.location.origin}#${query}`);
document.title = `Search Shakespeare: ${query}`;
};

// Display a list of matched lines, stage directions and scene descriptions
function highlighttches(matches, query) {
function displayMatches(matches, query) {
const exactPhrase = new RegExp(query, 'i');
// keep exact matches only
// matches = matches.filter(function(match) {
Expand All @@ -108,7 +109,7 @@ function highlighttches(matches, query) {
matches = matches.sort((a, b) => {
return exactPhrase.test(a.doc.t) ? -1 : exactPhrase.test(b.doc.t) ? 1 : 0;
});
// sort not necessary
// sort (not necessary)
// matches = matches.sort((a, b) =>
// a.doc.l.localeCompare(b.doc.l, {numeric: true}));
for (const match of matches) {
Expand All @@ -124,7 +125,7 @@ function addMatch(match) {
if (match.i) { // stage direction matches have an index
matchElement.dataset.index = match.i;
}
// add em tags if match is a spoken line, i.e. has a speaker (match.s)
// add em tags if match is stage dir or scene descr, i.e. no speaker (match.s)
const html = match.s ? match.t : `<em>${match.t}</em>`;
matchElement.innerHTML = html;
matchElement.onclick = function() {
Expand All @@ -136,17 +137,21 @@ function addMatch(match) {
// Display the appropriate text and location when a user taps/clicks on a match
function displayText(match) {
hide(matchesList);
const location = match.l.split('.'); // l represents location, e.g. Ham.3.3.2
textIframe.src = HTML_DIR + location[0] + '.html';
// match.l is a citation for a play or poem, e.g. Ham.3.3.2
history.pushState(null, null, `${window.location.origin}/${match.l}`);
document.title = `Search Shakespeare: ${match.l}`;
const location = match.l.split('.');
const play = location[0];
textIframe.src = `${HTML_DIR}${play}.html`;
textIframe.onload = function() {
const actIndex = location[1];
const sceneIndex = location[2];
const textIframeDoc = textIframe.contentWindow.document;
const act = textIframeDoc.querySelectorAll('.act')[actIndex];
// console.log('acts', textIframeDoc.querySelectorAll('section.act'));
// console.log('acts', textIframeDoc.querySelectorAll('.act'));
const scene = act.querySelectorAll('section.scene')[sceneIndex];
// text matches are lines, scene titles or stage directions
if (match.s) { // if the match has a speaker (match.s) it's a line
if (match.s) { // if the match has a speaker (match.s) it's a spoken line
const lineIndex = location[3];
// some list items in speeches are stage directions
highlightMatch(scene, 'li:not(.stage-direction)', lineIndex);
Expand All @@ -155,15 +160,16 @@ function displayText(match) {
} else if (match.r === 't') { // match is a scene title, only ever one
highlightMatch(scene, '.scene-description', 0);
}
show(textIframe);
};
show(textIframe);
}

function highlightMatch(scene, selector, elementIndex) {
console.log('scene, selector, elementIndex: ', scene, selector, elementIndex);
const element = scene.querySelectorAll(selector)[elementIndex];
element.classList.add('highlight');
element.scrollIntoView({behviour: 'smooth', inline: 'center'});
element.scrollIntoView(); // inline: center problematic unless iframe shown :(
textIframe.contentWindow.scrollBy(0, -220);
}

// Format location for display to the right of each match
Expand Down

0 comments on commit 314276f

Please sign in to comment.