Support space-separated multi-prefixes in menus

Change-Id: I308ce7bb3600c0b0430f4580b6cb4948e63b4cd2
diff --git a/dev/js/spec/menuSpec.js b/dev/js/spec/menuSpec.js
index aba3f1e..db3e968 100644
--- a/dev/js/spec/menuSpec.js
+++ b/dev/js/spec/menuSpec.js
@@ -295,6 +295,7 @@
         // Highlight in the middle - both
         menuItem = KorAP.ComplexMenuItem.create(['CoreNLP', 'corenlp/', 'This is my Example']);
         menuItem.highlight("e");
+
         expect(menuItem.element().innerHTML).toEqual("<div><h1>Cor<mark>e</mark>NLP</h1><h2>cor<mark>e</mark>nlp/</h2><h3>This is my <mark>E</mark>xampl<mark>e</mark></h3></div>");
 
         menuItem.lowlight();
@@ -328,6 +329,21 @@
         ["Syntax", "syn="]
       ];
 
+      var listMultiPrefix = [
+        ["PP","PP ","Personal Pronoun"],
+        ["PPP","PPP ","Personal Pronoun, Plural"],
+        ["PPPA","PPPA ","Personal Pronoun, Plural, Acc."],
+        ["PPPD","PPPD ","Personal Pronoun, Plural, Dative"],
+        ["PPPR","PPPR ","Personal Pronoun, Plural, Direct"],
+        ["PPPO","PPPO ","Personal Pronoun, Plural, Oblique"],
+        ["PPS","PPS ","Personal Pronoun, Singular"],
+        ["PPSA","PPSA ","Personal Pronoun, Singular, Accusative"],
+        ["PPSD","PPSD ","Personal Pronoun, Singular, Dative"],
+        ["PPSR","PPSR ","Personal Pronoun, Singular, Direct"],
+        ["PPSN","PPSN ","Personal Pronoun, Singular, Nominative"],
+        ["PPSO","PPSO ","Personal Pronoun, Singular, Oblique"]
+      ];
+      
       var demolist = [
         ['Titel', 'title'],
         ['Untertitel', 'subTitle'],
@@ -784,6 +800,24 @@
         expect(menu.shownItem(2)).toBe(undefined);
       });
 
+      it('should be filterable (multiple prefix = "pro sin")', function () {
+        var menu = KorAP.HintMenu.create("drukola/p=", listMultiPrefix);
+        menu._firstActive = true;
+
+        menu.limit(2);
+        expect(menu.prefix("pro sin").show()).toBe(true);
+        expect(menu.shownItem(0).name()).toEqual("PPS");
+        expect(menu.element().childNodes[3].innerHTML).toEqual(
+          "<strong>PPS</strong><span>Personal <mark>Pro</mark>noun, <mark>Sin</mark>gular</span>"
+        );
+
+        expect(menu.shownItem(0).active()).toBe(true);
+        expect(menu.shownItem(1).name()).toEqual("PPSA");
+        expect(menu.element().childNodes[4].innerHTML).toEqual("<strong>PPSA</strong><span>Personal <mark>Pro</mark>noun, <mark>Sin</mark>gular, Accusative</span>");
+        expect(menu.shownItem(1).active()).toBe(false);
+
+        expect(menu.shownItem(2)).toBe(undefined);
+      });
 
       it('should choose prefix with failing prefix (1)', function () {
         var menu = KorAP.HintMenu.create("cnx/", list);
diff --git a/dev/js/src/menu.js b/dev/js/src/menu.js
index e575b7e..c3f7fa6 100644
--- a/dev/js/src/menu.js
+++ b/dev/js/src/menu.js
@@ -181,18 +181,44 @@
        * There is a prefix set, so filter the list!
        */
       var pos;
-      var prefix = " " + this.prefix().toLowerCase();
+      var prefixList = this.prefix().toLowerCase().split(" ");
+
+      var items = [];
+      var maxPoints = 1; // minimum 1
 
       // Iterate over all items and choose preferred matching items
       // i.e. the matching happens at the word start
       for (pos = 0; pos < this._items.length; pos++) {
-        if ((this.item(pos).lcField().indexOf(prefix)) >= 0)
+
+        var points = 0;
+
+        for (pref = 0; pref < prefixList.length; pref++) {
+          var prefix = " " + prefixList[pref];
+
+          // Check if it matches at the beginning
+          if ((this.item(pos).lcField().indexOf(prefix)) >= 0) {
+            points += 5;
+          }
+
+          // Check if it matches anywhere
+          else if ((this.item(pos).lcField().indexOf(prefix.substring(1))) >= 0) {
+            points += 1;
+          };
+        };
+
+        if (points > maxPoints) {
+          this._list = [pos];
+          maxPoints = points;
+        }
+        else if (points == maxPoints) {
           this._list.push(pos);
+        }
       };
 
       // The list is empty - so lower your expectations
       // Iterate over all items and choose matching items
       // i.e. the matching happens anywhere in the word
+      /*
       prefix = prefix.substring(1);
       if (this._list.length == 0) {
         for (pos = 0; pos < this._items.length; pos++) {
@@ -200,6 +226,7 @@
             this._list.push(pos);
         };
       };
+      */
 
       this._slider.length(this._list.length).reInit();
 
diff --git a/dev/js/src/menu/item.js b/dev/js/src/menu/item.js
index 3f955be..835f69f 100644
--- a/dev/js/src/menu/item.js
+++ b/dev/js/src/menu/item.js
@@ -5,6 +5,8 @@
  * further: action happen on right arrow
  */
 
+"use strict";
+
 /**
  * Item in the Dropdown menu
  */
@@ -153,13 +155,13 @@
     for (var i = marks.length - 1; i >= 0; i--) {
       // Create text node clone
       var x = document.createTextNode(
-	marks[i].firstChild.nodeValue
+	      marks[i].firstChild.nodeValue
       );
       
       // Replace with content
       marks[i].parentNode.replaceChild(
-	x,
-	marks[i]
+	      x,
+	      marks[i]
       );
     };
 
@@ -169,48 +171,114 @@
   },
 
   // Highlight a certain substring of the menu item
-  _highlight : function (elem, prefix) {
+  _highlight : function (elem, prefixString) {    
     if (elem.nodeType === 3) {
       
       var text   = elem.nodeValue;
       var textlc = text.toLowerCase();
-      var pos    = textlc.indexOf(prefix);
+
+      // Split prefixes
+      if (prefixString) {
+        var prefixes = prefixString.trim().split(" ");
+
+        var prefix;
+        var testPos;
+        var pos = -1;
+        var len = 0;
+
+        // Iterate over all prefixes and get the best one
+        for (var i = 0; i < prefixes.length; i++) {
+
+          // Get first pos of a matching prefix
+          testPos = textlc.indexOf(prefixes[i]);
+          if (testPos < 0)
+            continue;
+
+          if (pos === -1 || testPos < pos) {
+            pos = testPos;
+            len = prefixes[i].length;
+          }
+          else if (testPos === pos && prefixes[i].length > len) {
+            len = prefixes[i].length;
+          };
+        };
+
+        // Matches!
+        if (pos >= 0) {
+	
+	        // First element
+	        if (pos > 0) {
+	          elem.parentNode.insertBefore(
+	            document.createTextNode(text.substr(0, pos)),
+	            elem
+	          );
+	        };
+	
+	        // Second element
+	        var hl = document.createElement("mark");
+	        hl.appendChild(
+	          document.createTextNode(text.substr(pos, len))
+	        );
+	        elem.parentNode.insertBefore(hl, elem);
+	
+	        // Third element
+	        var third = text.substr(pos + len);
+
+	        if (third.length > 0) {
+	          var thirdE = document.createTextNode(third);
+	          elem.parentNode.insertBefore(
+	            thirdE,
+	            elem
+	          );
+	          this._highlight(thirdE, prefixString);
+	        };
+	
+	        var p = elem.parentNode;
+	        p.removeChild(elem);
+        };
+      };
+
+      /*
+      pos = textlc.indexOf(prefix);
+
+      // Matches!
       if (pos >= 0) {
 	
-	// First element
-	if (pos > 0) {
-	  elem.parentNode.insertBefore(
-	    document.createTextNode(text.substr(0, pos)),
-	    elem
-	  );
-	};
+	      // First element
+	      if (pos > 0) {
+	        elem.parentNode.insertBefore(
+	          document.createTextNode(text.substr(0, pos)),
+	          elem
+	        );
+	      };
 	
-	// Second element
-	var hl = document.createElement("mark");
-	hl.appendChild(
-	  document.createTextNode(text.substr(pos, prefix.length))
-	);
-	elem.parentNode.insertBefore(hl, elem);
+	      // Second element
+	      var hl = document.createElement("mark");
+	      hl.appendChild(
+	        document.createTextNode(text.substr(pos, prefix.length))
+	      );
+	      elem.parentNode.insertBefore(hl, elem);
 	
-	// Third element
-	var third = text.substr(pos + prefix.length);
-	if (third.length > 0) {
-	  var thirdE = document.createTextNode(third);
-	  elem.parentNode.insertBefore(
-	    thirdE,
-	    elem
-	  );
-	  this._highlight(thirdE, prefix);
-	};
+	      // Third element
+	      var third = text.substr(pos + prefix.length);
+	      if (third.length > 0) {
+	        var thirdE = document.createTextNode(third);
+	        elem.parentNode.insertBefore(
+	          thirdE,
+	          elem
+	        );
+	        this._highlight(thirdE, prefix);
+	      };
 	
-	var p = elem.parentNode;
-	p.removeChild(elem);
+	      var p = elem.parentNode;
+	      p.removeChild(elem);
       };
+      */
     }
     else {
       var children = elem.childNodes;
       for (var i = children.length -1; i >= 0; i--) {
-	this._highlight(children[i], prefix);
+	      this._highlight(children[i], prefixString);
       };
     };
   },
diff --git a/dev/js/src/menu/prefix.js b/dev/js/src/menu/prefix.js
index abcf66c..90924c9 100644
--- a/dev/js/src/menu/prefix.js
+++ b/dev/js/src/menu/prefix.js
@@ -107,7 +107,7 @@
     // Prefix is long enough for backspace
     if (this._string.length > 1) {
       this._string = this._string.substring(
-	0, this._string.length - 1
+	      0, this._string.length - 1
       );
     }
     else {