The Code for BookWorm.

                          
                            //Load a book from disk
                            function loadBook(fileName,displayName){
                                let currentBook = "";
                                let url = "/books/" + fileName;
                            
                                //reset our UI
                                document.getElementById("fileName").innerHTML = displayName;
                                document.getElementById("searchstat").innerHTML = "";
                                document.getElementById("keyword").value = "";
                            
                                //create a server request to load our book
                                var xhr = new XMLHttpRequest();
                                xhr.open("GET", url, true);
                                xhr.send();
                            
                                xhr.onreadystatechange = function () {
                                    if (xhr.readyState == 4 && xhr.status == 200) {
                                        currentBook = xhr.responseText;
                            
                                        getDocStats(currentBook);
                            
                                        //remove line breaks and carriage returns and replace with a 
currentBook = currentBook.replace(/(?:\r\n|\r|\n)/g, '
'); document.getElementById("fileContent").innerHTML = currentBook; var elmnt = document.getElementById("fileContent"); elmnt.scrolltop = 0; } }; } //get the stats for the book function getDocStats(fileContent) { var docLength = document.getElementById("docLength"); var wordCount = document.getElementById("wordCount"); var charCount = document.getElementById("charCount"); let text = fileContent.toLowerCase(); let wordArray = text.match(/\b\S+\b/g); let wordDictionary = {}; var uncommonWords = []; //filter out uncommon words uncommonWords = filterStopWords(wordArray); //count every word in wordArray for (let word in uncommonWords) { let wordValue = uncommonWords[word]; if (wordDictionary[wordValue] > 0) { wordDictionary[wordValue] += 1; } else { wordDictionary[wordValue] = 1; } } //sort the array let wordList = sortProperties(wordDictionary); //Return top 5 words var top5Words = wordList.slice(0, 6); //return least5 words var least5Words = wordList.slice(-6, wordList.length); //write to page ULTemplate(top5Words, document.getElementById("mostUsed")); ULTemplate(least5Words, document.getElementById("leastUsed")); docLength.innerText = "Document Length: " + text.length; wordCount.innerText = "Word Count: " + wordArray.length; } function ULTemplate(items, element) { let rowTemplate = document.getElementById('template-ul-items'); let templateHTML = rowTemplate.innerHTML; let resultsHTML = ""; for (i = 0; i < items.length - 1; i++) { resultsHTML += templateHTML.replace('{{val}}', items[i][0] + " : " + items[i][1] + " time(s)"); } element.innerHTML = resultsHTML; } function sortProperties(obj) { //first convert the obj to array let rtnArray = Object.entries(obj); //Sort the array rtnArray.sort(function (first, second) { return second[1] - first[1]; }); return rtnArray; } //a list of stop words we don't want to include in stats function getStopWords() { return ["a", "able", "about", "across", "after", "all", "almost", "also", "am", "among", "an", "and", "any", "are", "as", "at", "be", "because", "been", "but", "by", "can", "cannot", "could", "dear", "did", "do", "does", "either", "else", "ever", "every", "for", "from", "get", "got", "had", "has", "have", "he", "her", "hers", "him", "his", "how", "however", "i", "if", "in", "into", "is", "it", "its", "just", "least", "let", "like", "likely", "may", "me", "might", "most", "must", "my", "neither", "no", "nor", "not", "of", "off", "often", "on", "only", "or", "other", "our", "own", "rather", "said", "say", "says", "she", "should", "since", "so", "some", "than", "that", "the", "their", "them", "then", "there", "these", "they", "this", "tis", "to", "too", "twas", "us", "wants", "was", "we", "were", "what", "when", "where", "which", "while", "who", "whom", "why", "will", "with", "would", "yet", "you", "your", "ain't", "aren't", "can't", "could've", "couldn't", "didn't", "doesn't", "don't", "hasn't", "he'd", "he'll", "he's", "how'd", "how'll", "how's", "i'd", "i'll", "i'm", "i've", "isn't", "it's", "might've", "mightn't", "must've", "mustn't", "shan't", "she'd", "she'll", "she's", "should've", "shouldn't", "that'll", "that's", "there's", "they'd", "they'll", "they're", "they've", "wasn't", "we'd", "we'll", "we're", "weren't", "what'd", "what's", "when'd", "when'll", "when's", "where'd", "where'll", "where's", "who'd", "who'll", "who's", "why'd", "why'll", "why's", "won't", "would've", "wouldn't", "you'd", "you'll", "you're", "you've"]; } function filterStopWords(wordArray) { var commonWords = getStopWords(); var commonObj = {}; var uncommonArray = []; for (i = 0; i < commonWords.length; i++) { commonObj[commonWords[i].trim()] = true; } for (i = 0; i < wordArray.length; i++) { word = wordArray[i].trim().toLowerCase(); if (!commonObj[word]) { uncommonArray.push(word); } } return uncommonArray; } //highlight the words in search function performMark() { //read keyword var keyword = document.getElementById("keyword").value; var display = document.getElementById("fileContent"); var newContent = ""; //find all currently marked items let spans = document.querySelectorAll('mark'); // for (var i = 0; i < spans.length; i++) { spans[i].outerHTML = spans[i].innerHTML; } var re = new RegExp(keyword, "gi"); var replaceText = "$&" var bookContent = display.innerHTML; //add mark to book content newContent = bookContent.replace(re, replaceText); display.innerHTML = newContent; var count = document.querySelectorAll('mark').length; document.getElementById("searchstat").innerHTML = "found " + count + " matches"; if (count > 0) { var element = document.getElementById("markme"); element.scrollIntoView(); } }
App logo

The code is structured in six functions.

loadBook

This function gets the fileName and displayName from the selected file. It will load the file text into the display textbox. Special characters, such as carriage return, line feed, and nulls, are removed via a regex match.

getDocStats

This function gets the word count and page count from the loaded book file and displays the results in the stats box.

ULTemplate

This function, via a template, is used to display the stats lines in the most and least used words stat boxes.

sortProperties

This function sorts the words found in the text based on number of times found.

getStopWords

This function returns a list of words not to include in word search count.

filterStopWords

This function sorts the stop words, from retrieved list, from words found in book, to exclude from word count.

performMark

This function works in conjunction with the search box. When entered word is found, this function will highlight the found word.