Bug 1335905 - Tries implementation, console implementation draft
authormanotejmeka <manotejmeka@gmail.com>
Wed, 08 Mar 2017 01:29:57 -0500
changeset 495063 5caaab42b3c8d40fa8afc40dacf18d3f2590ab27
parent 495062 8daa40d8a081fc9e1cb614f510835c2e72f4ee56
child 548269 b95861bc5648d465eeb3fd9604132023d113352b
push id48216
push userbmo:manotejmeka@gmail.com
push dateWed, 08 Mar 2017 06:36:03 +0000
bugs1335905
milestone55.0a1
Bug 1335905 - Tries implementation, console implementation MozReview-Commit-ID: 9XJ4IJR73Jc
browser/components/preferences/in-content/findInPage.js
browser/components/preferences/in-content/jar.mn
browser/components/preferences/in-content/preferences.xul
browser/components/preferences/in-content/tries.js
--- a/browser/components/preferences/in-content/findInPage.js
+++ b/browser/components/preferences/in-content/findInPage.js
@@ -1,25 +1,30 @@
 var gFindSelection = null;
 // Search Results Pane
 var gSearchResultsCategory = null;
 // Search input
 var gMainSearchElement = null;
 
+var gInitialSearch = true;
+var gTries = null;
+
 // paneSearchResults needs init function to initialize the object
 var gSearchResultsPane = {
   init() {
     let controller = getSelectionController();
     gFindSelection = controller.getSelection(Ci.nsISelectionController.SELECTION_FIND);
 
     // document.getElementById("searchInput").addEventListener("command", searchFunction);
     gSearchResultsCategory = document.getElementById("category-search-results");
     // Obtaining the search Input
     gMainSearchElement = document.getElementById("searchInput");
     gMainSearchElement.hidden = !Services.prefs.getBoolPref("browser.preferences.search");
+
+    gTries = new Trie();
   }
 }
 
 /**
  * Check that the passed string matches the filter arguments.
  *
  * @param String str
  *    to search for filter words in.
@@ -75,31 +80,39 @@ function textNodeDescendants(node) {
       all.push(node);
     } else {
       all = all.concat(textNodeDescendants(node));
     }
   }
   return all;
 }
 
+function addToTries(listOfWords) {
+  for(i = 0; i < listOfWords.length; i++) {
+    gTries.insert(listOfWords[i].toLowerCase());
+  }
+}
 /**
  * Finding words in the text nodes
  * Cases where the word is split up due to access keys
  * @param Array textNodes
  *    List of Html elements
  * @param Array nodeSizes
  *    Running size of text nodes
  * @param String textSearch
  *    Concatination of textNodes's text content
  * @param String searchPhrase
  *    word or words to search for
  * @returns boolean
  *      Returns true when atleast one instance of search phrase is found, otherwise false
  */
 function hightlightMatches(textNodes, nodeSizes, textSearch, searchPhrase) {
+  if (gInitialSearch) {
+    addToTries(textSearch.replace(/[.,\/#!$%\^&\*;:{}=\-_`~()]/g,"").removeStopWords().split(" "));
+  }
   let regExp = new RegExp(searchPhrase, "gi");
   let result, indices = [];
 
   while ((result = regExp.exec(textSearch))) {
     indices.push(result.index);
   }
 
   // Looping through each spot the searchPhrase is found in the concatinated string
@@ -183,16 +196,17 @@ function getSelectionController() {
 function searchFunction(event) {
   let query = event.target.value.trim();
 
   gFindSelection.removeAllRanges();
 
   let srHeader = document.getElementById("header-searchResults");
 
   if (query) {
+    console.log("Tries: ",gTries.autoComplete(String(query.toLowerCase())));
     // Showing the Search Results Tag
     gotoPref("paneSearchResults");
     // srHeader.hidden = false;
     gSearchResultsCategory.hidden = false;
 
     let resultsFound = false;
 
     // Building the range for highlighted areas
@@ -233,16 +247,20 @@ function searchFunction(event) {
       document.getElementById("need-help-link").setAttribute("href", getHelpLinkURL("search"));
     }
   } else {
     gSearchResultsCategory.hidden = true;
     document.getElementById("sorry-message").textContent = "";
     // Going back to General when cleared
     gotoPref("paneGeneral");
   }
+
+  if (gInitialSearch) {
+    gInitialSearch = false;
+  }
 }
 
 /**
  * Finding leaf nodes and checking their content for words to search
  *
  * @param Node nodeObject
  *    Html element
  * @param String searchPhrase
--- a/browser/components/preferences/in-content/jar.mn
+++ b/browser/components/preferences/in-content/jar.mn
@@ -12,8 +12,9 @@ browser.jar:
    content/browser/preferences/in-content/containers.js
    content/browser/preferences/in-content/advanced.js
    content/browser/preferences/in-content/applications.js
    content/browser/preferences/in-content/content.js
    content/browser/preferences/in-content/sync.js
    content/browser/preferences/in-content/security.js
    content/browser/preferences/in-content/search.js
    content/browser/preferences/in-content/findInPage.js
+   content/browser/preferences/in-content/tries.js
--- a/browser/components/preferences/in-content/preferences.xul
+++ b/browser/components/preferences/in-content/preferences.xul
@@ -68,16 +68,17 @@
       title="&prefWindow.title;">
 #endif
 
   <html:link rel="shortcut icon"
               href="chrome://browser/skin/preferences/in-content/favicon.ico"/>
 
   <script type="application/javascript"
           src="chrome://browser/content/utilityOverlay.js"/>
+  <script src="chrome://browser/content/preferences/in-content/tries.js"/>
   <script src="chrome://browser/content/preferences/in-content/findInPage.js"/>
   <script type="application/javascript"
           src="chrome://browser/content/preferences/in-content/preferences.js"/>
   <script src="chrome://browser/content/preferences/in-content/subdialogs.js"/>
 
   <stringbundle id="bundleBrand"
                 src="chrome://branding/locale/brand.properties"/>
   <stringbundle id="bundlePreferences"
new file mode 100644
--- /dev/null
+++ b/browser/components/preferences/in-content/tries.js
@@ -0,0 +1,206 @@
+Trie = function() {
+  this.wordCount = 0;
+  this.children = [];
+	this.word = null;
+}
+
+Trie.prototype = {
+  
+  insert: function(word){
+    let node = this;
+		if (word === "") {
+			return;
+		}
+    for (let character of word.split("")) {
+      if (node.children[character] === undefined || node.children[character] === null) {
+        node.children[character] = new Trie();
+      }
+      node = node.children[character];
+    }
+    node.wordCount++;
+		node.word = word;
+  },
+
+	completeWord: function(partialWord) {
+		let node = this;
+		let listOfWords = [];
+		let child = null;
+
+		if (node.wordCount > 0) {
+			listOfWords.push(partialWord);
+		}
+		for (let childNode in node.children) {
+			child = node.children[childNode];
+			listOfWords = listOfWords.concat(child.completeWord(partialWord+childNode));
+		}
+		return listOfWords;
+	},
+
+	listOfWords: function(){
+		let node = this;
+		if (node === undefined || node === null){
+			return [];
+		}
+		let wordsList = [];
+		let child = null;
+		if (node.word != null || node.word != undefined){
+				wordsList.push(node.word);
+			}
+		for (let char in node.children){
+			child = node.children[char];
+			wordsList = wordsList.concat(child.listOfWords());
+		}
+		return wordsList;
+	},
+
+  autoComplete: function(partialWord) {
+		let node = this;
+		let typos = node.levenshteinDistance(partialWord,1);
+		let arrayTypos = firstElement(typos);
+
+		for (let char of partialWord) {
+			if (node.children[char] === undefined || node.children[char] === null){
+				return new Set([].concat(arrayTypos));
+			}
+			node = node.children[char];
+		}
+		// return node.completeWord(partialWord);
+		let complete = node.listOfWords();
+		return new Set(complete.concat(arrayTypos));
+  },
+
+	levenshteinHelper: function(letter, word, previousRow, results, maxCost) {
+		let node = this;
+		let columns = word.length + 1;
+		let currentRow = [previousRow[0] + 1];
+		let insertCost = null, deleteCost = null, replaceCost = null;
+		let child = null;
+
+		for (let i=1; i<columns; i++) {
+			insertCost = currentRow[i - 1] + 1;
+			deleteCost = previousRow[i] + 1;
+
+			if (word[i - 1] != letter) {
+				replaceCost = previousRow[i - 1] + 1;
+			} else {
+				replaceCost = previousRow[i - 1];
+			}
+
+			currentRow.push(Math.min(insertCost,deleteCost,replaceCost));
+		}
+
+		if (currentRow[currentRow.length - 1] <= maxCost && node.wordCount > 0){
+			results.push([node.word, currentRow[currentRow.length - 1]]);
+		}
+
+		if (Math.min.apply(null,currentRow) <= maxCost) {
+			for (let character in node.children) {
+				child = node.children[character];
+				child.levenshteinHelper(character, word, currentRow, results, maxCost);
+			}
+		}
+		return results;
+	},
+
+	// wrote it with the help of http://stevehanov.ca/blog/index.php?id=114
+	levenshteinDistance: function(word, maxCost) {
+		let node = this;
+		let currentRow = Array.from(Array(word.length+1).keys());
+		let results = [];
+		let child = null;
+
+		for (let character in node.children){
+			child = node.children[character]
+			child.levenshteinHelper(character, word, currentRow, results, maxCost);
+		}
+		return results;
+	}
+}
+
+function firstElement(arry) {
+	let temp = [];
+	for (i=0; i<arry.length; i++){
+		temp.push(arry[i][0]);
+	}
+	return temp;
+}
+
+/*
+Testing out the spell checker
+let t = new Trie();
+t.insert("apps");
+t.insert("app");
+t.insert("ppp");
+t.insert("bpp");
+t.insert("acp");
+t.insert("apple");
+t.insert("test");
+t.insert("tasting");
+t.insert("help");
+t.insert("helps");
+
+let ans = t.levenshteinDistance("ap",2);
+*/
+String.isStopWord = function(word)
+{
+	var regex = new RegExp("\\b"+word+"\\b","i");
+	if(stopWords.search(regex) < 0)
+	{
+		return false;
+	}else
+	{
+		return true;	
+	}
+}
+
+String.prototype.removeStopWords = function()
+{
+	words = new Array();
+	
+	this.replace(/\b[\w]+\b/g,
+			function($0)
+			{
+				if(!String.isStopWord($0))
+				{
+					words[words.length] = $0.trim();
+				}
+			}
+		); 
+	return words.join(" ");
+}
+
+var stopWords = "a,able,about,above,abst,accordance,according,accordingly,across,act,actually,added,adj,\
+affected,affecting,affects,after,afterwards,again,against,ah,all,almost,alone,along,already,also,although,\
+always,am,among,amongst,an,and,announce,another,any,anybody,anyhow,anymore,anyone,anything,anyway,anyways,\
+anywhere,apparently,approximately,are,aren,arent,arise,around,as,aside,ask,asking,at,auth,available,away,awfully,\
+b,back,be,became,because,become,becomes,becoming,been,before,beforehand,begin,beginning,beginnings,begins,behind,\
+being,believe,below,beside,besides,between,beyond,biol,both,brief,briefly,but,by,c,ca,came,can,cannot,can't,cause,causes,\
+certain,certainly,co,com,come,comes,contain,containing,contains,could,couldnt,d,date,did,didn't,different,do,does,doesn't,\
+doing,done,don't,down,downwards,due,during,e,each,ed,edu,effect,eg,eight,eighty,either,else,elsewhere,end,ending,enough,\
+especially,et,et-al,etc,even,ever,every,everybody,everyone,everything,everywhere,ex,except,f,far,few,ff,fifth,first,five,fix,\
+followed,following,follows,for,former,formerly,forth,found,four,from,further,furthermore,g,gave,get,gets,getting,give,given,gives,\
+giving,go,goes,gone,got,gotten,h,had,happens,hardly,has,hasn't,have,haven't,having,he,hed,hence,her,here,hereafter,hereby,herein,\
+heres,hereupon,hers,herself,hes,hi,hid,him,himself,his,hither,home,how,howbeit,however,hundred,i,id,ie,if,i'll,im,immediate,\
+immediately,importance,important,in,inc,indeed,index,information,instead,into,invention,inward,is,isn't,it,itd,it'll,its,itself,\
+i've,j,just,k,keep,keeps,kept,kg,km,know,known,knows,l,largely,last,lately,later,latter,latterly,least,less,lest,let,lets,like,\
+liked,likely,line,little,'ll,look,looking,looks,ltd,m,made,mainly,make,makes,many,may,maybe,me,mean,means,meantime,meanwhile,\
+merely,mg,might,million,miss,ml,more,moreover,most,mostly,mr,mrs,much,mug,must,my,myself,n,na,name,namely,nay,nd,near,nearly,\
+necessarily,necessary,need,needs,neither,never,nevertheless,new,next,nine,ninety,no,nobody,non,none,nonetheless,noone,nor,\
+normally,nos,not,noted,nothing,now,nowhere,o,obtain,obtained,obviously,of,off,often,oh,ok,okay,old,omitted,on,once,one,ones,\
+only,onto,or,ord,other,others,otherwise,ought,our,ours,ourselves,out,outside,over,overall,owing,own,p,page,pages,part,\
+particular,particularly,past,per,perhaps,placed,please,plus,poorly,possible,possibly,potentially,pp,predominantly,present,\
+previously,primarily,probably,promptly,proud,provides,put,q,que,quickly,quite,qv,r,ran,rather,rd,re,readily,really,recent,\
+recently,ref,refs,regarding,regardless,regards,related,relatively,research,respectively,resulted,resulting,results,right,run,s,\
+said,same,saw,say,saying,says,sec,section,see,seeing,seem,seemed,seeming,seems,seen,self,selves,sent,seven,several,shall,she,shed,\
+she'll,shes,should,shouldn't,show,showed,shown,showns,shows,significant,significantly,similar,similarly,since,six,slightly,so,\
+some,somebody,somehow,someone,somethan,something,sometime,sometimes,somewhat,somewhere,soon,sorry,specifically,specified,specify,\
+specifying,still,stop,strongly,sub,substantially,successfully,such,sufficiently,suggest,sup,sure,t,take,taken,taking,tell,tends,\
+th,than,thank,thanks,thanx,that,that'll,thats,that've,the,their,theirs,them,themselves,then,thence,there,thereafter,thereby,\
+thered,therefore,therein,there'll,thereof,therere,theres,thereto,thereupon,there've,these,they,theyd,they'll,theyre,they've,\
+think,this,those,thou,though,thoughh,thousand,throug,through,throughout,thru,thus,til,tip,to,together,too,took,toward,towards,\
+tried,tries,truly,try,trying,ts,twice,two,u,un,under,unfortunately,unless,unlike,unlikely,until,unto,up,upon,ups,us,use,used,\
+useful,usefully,usefulness,uses,using,usually,v,value,various,'ve,very,via,viz,vol,vols,vs,w,want,wants,was,wasn't,way,we,wed,\
+welcome,we'll,went,were,weren't,we've,what,whatever,what'll,whats,when,whence,whenever,where,whereafter,whereas,whereby,wherein,\
+wheres,whereupon,wherever,whether,which,while,whim,whither,who,whod,whoever,whole,who'll,whom,whomever,whos,whose,why,widely,\
+willing,wish,with,within,without,won't,words,world,would,wouldn't,www,x,y,yes,yet,you,youd,you'll,your,youre,yours,yourself,\
+yourselves,you've,z,zero";