Optimized menus to be reused for VC-Builder
diff --git a/public/js/demo/vc.html b/public/js/demo/vc.html
index ea4a53c..4d561e1 100644
--- a/public/js/demo/vc.html
+++ b/public/js/demo/vc.html
@@ -17,7 +17,7 @@
   </head>
   <body>
     <div id="vc"></div>
-    <div id="menu"></div>
+    <div id="menu" class="vc"></div>
 
     <script>
     var json = {
@@ -92,9 +92,10 @@
     var menu = KorAP.FieldMenu.create([
       ['Titel', 'title', 'string'],
       ['Untertitel', 'subTitle', 'string'],
-      ['Veröffentlichungsdatum', 'pubDate', 'date']
+      ['Veröffentlichungsdatum', 'pubDate', 'date'],
+      ['Autor', 'author', 'string']
     ]);
-    menu.limit(4);
+    menu.limit(3);
     menu.show();
 
     document.getElementById('menu').appendChild(menu.element());
diff --git a/public/js/spec/menuSpec.js b/public/js/spec/menuSpec.js
index cc569a8..76da135 100644
--- a/public/js/spec/menuSpec.js
+++ b/public/js/spec/menuSpec.js
@@ -361,7 +361,7 @@
     expect(menu.delete()).toBe(undefined);
     menu.limit(3);
 
-    expect(menu.show()).toBe(undefined);
+    expect(menu.show()).toBe(true);
     expect(menu.element().firstChild.innerHTML).toEqual("<strong>Constituency</strong><span>Example 1</span>");
 
     expect(menu.element().childNodes[1].innerHTML).toEqual("<strong>Lemma</strong>");
@@ -379,7 +379,7 @@
     var menu = KorAP.HintMenu.create("cnx/", list);
     menu.limit(3);
 
-    expect(menu.show("o")).toBe(undefined);
+    expect(menu.show("o")).toBe(true);
     expect(menu.element().childNodes[0].innerHTML).toEqual("<strong>C<mark>o</mark>nstituency</strong><span>Example 1</span>");
     expect(menu.element().childNodes[1].innerHTML).toEqual("<strong>M<mark>o</mark>rph<mark>o</mark>l<mark>o</mark>gy</strong><span>Example 2</span>");
     expect(menu.element().childNodes[2].innerHTML).toEqual("<strong>Part-<mark>o</mark>f-Speech</strong>");
@@ -392,7 +392,7 @@
 
     menu.limit(2);
 
-    expect(menu.show("o")).toBe(undefined);
+    expect(menu.show("o")).toBe(true);
     expect(menu.element().childNodes[0].innerHTML).toEqual("<strong>C<mark>o</mark>nstituency</strong><span>Example 1</span>");
     expect(menu.element().childNodes[1].innerHTML).toEqual("<strong>M<mark>o</mark>rph<mark>o</mark>l<mark>o</mark>gy</strong><span>Example 2</span>");
     expect(menu.element().childNodes[2]).toBe(undefined);
@@ -402,14 +402,14 @@
     expect(menu.element().childNodes[1].classList.contains("no-more")).toBe(false);
     expect(menu.element().childNodes[2]).toBe(undefined);
 
-    expect(menu.show("e")).toBe(undefined);
+    expect(menu.show("e")).toBe(true);
     expect(menu.element().childNodes[0].innerHTML).toEqual("<strong>Constitu<mark>e</mark>ncy</strong><span><mark>E</mark>xampl<mark>e</mark> 1</span>");
     expect(menu.element().childNodes[1].innerHTML).toEqual("<strong>Morphology</strong><span><mark>E</mark>xampl<mark>e</mark> 2</span>");
     expect(menu.element().childNodes[2]).toBe(undefined);
 
     menu.limit(5);
 
-    expect(menu.show("a")).toBe(undefined);
+    expect(menu.show("a")).toBe(true);
     expect(menu.element().childNodes[0].innerHTML).toEqual("<strong>Constituency</strong><span>Ex<mark>a</mark>mple 1</span>");
     expect(menu.element().childNodes[1].innerHTML).toEqual("<strong>Lemm<mark>a</mark></strong>");
     expect(menu.element().childNodes[2].innerHTML).toEqual("<strong>Morphology</strong><span>Ex<mark>a</mark>mple 2</span>");
@@ -426,7 +426,7 @@
     // Show only 3 items
     menu.limit(3);
 
-    expect(menu.show()).toBe(undefined);
+    expect(menu.show()).toBe(true);
     expect(menu.element().childNodes[0].innerHTML).toEqual("<strong>Constituency</strong><span>Example 1</span>");
     expect(menu.shownItem(0).active()).toBe(true);
     expect(menu.element().childNodes[1].innerHTML).toEqual("<strong>Lemma</strong>");
@@ -502,7 +502,7 @@
     var menu = KorAP.HintMenu.create("cnx/", list);
 
     menu.limit(3);
-    expect(menu.show()).toBe(undefined);
+    expect(menu.show()).toBe(true);
 
     expect(menu.element().childNodes[0].innerHTML).toEqual("<strong>Constituency</strong><span>Example 1</span>");
     expect(menu.shownItem(0).active()).toBe(true);
@@ -591,7 +591,7 @@
     var menu = KorAP.HintMenu.create("cnx/", list);
     menu.limit(2);
 
-    expect(menu.show("o")).toBe(undefined);
+    expect(menu.show("o")).toBe(true);
 
     expect(menu.shownItem(0).name()).toEqual("Constituency");
     expect(menu.element().childNodes[0].innerHTML).toEqual("<strong>C<mark>o</mark>nstituency</strong><span>Example 1</span>");
@@ -637,7 +637,7 @@
     var menu = KorAP.HintMenu.create("cnx/", list);
 
     menu.limit(2);
-    expect(menu.show("ex")).toBe(undefined);
+    expect(menu.show("ex")).toBe(true);
 
     expect(menu.shownItem(0).name()).toEqual("Constituency");
     expect(menu.element().childNodes[0].innerHTML).toEqual("<strong>Constituency</strong><span><mark>Ex</mark>ample 1</span>");
@@ -671,7 +671,7 @@
     menu.limit(5);
 
     // Change show
-    expect(menu.show("e")).toBe(undefined);
+    expect(menu.show("e")).toBe(true);
 
     expect(menu.shownItem(0).name()).toEqual("Constituency");
     expect(menu.element().childNodes[0].innerHTML).toEqual("<strong>Constitu<mark>e</mark>ncy</strong><span><mark>E</mark>xampl<mark>e</mark> 1</span>");
diff --git a/public/js/src/menu.js b/public/js/src/menu.js
index f0dd15d..175360a 100644
--- a/public/js/src/menu.js
+++ b/public/js/src/menu.js
@@ -9,6 +9,12 @@
 (function (KorAP) {
   "use strict";
 
+  // Don't let events bubble up
+  Event.prototype.halt = function () {
+    this.stopPropagation();
+    this.preventDefault();
+  };
+
   // Default maximum number of menu items
   KorAP.menuLimit = 8;
 
@@ -35,22 +41,101 @@
       this._element.focus();
     },
 
+    // mouse wheel treatment
+    _mousewheel : function (e) {
+      var delta = 0;
+      if (e.wheelDelta) {
+	delta = event.wheelDelta / 120; 
+      }
+      else if (e.detail) {
+	delta = - e.detail / 3;
+      };
+      if (delta < 0) {
+	this.next();
+      }
+      else {
+	this.prev();
+      };
+      e.halt();
+    },
+
+    // Arrow key and prefix treatment
+    _keydown : function (e) {
+      var code = _codeFromEvent(e);
+
+      /*
+       * keyCodes:
+       * - Down  = 40
+       * - Esc   = 27
+       * - Up    = 38
+       * - Enter = 13
+       * - shift = 16
+       * for characters use e.key
+       */
+
+      switch (code) {
+      case 27: // 'Esc'
+	e.halt();
+	this.hide();
+	break;
+      case 40: // 'Down'
+	e.halt();
+	this.next();
+	break;
+      case 38: // 'Up'
+	e.halt();
+	this.prev();
+	break;
+      case 13: // 'Enter'
+	console.log('hide');
+	e.halt();
+	this.hide();
+	break;
+      case 8: // 'Backspace'
+	var p = this.prefix();
+	if (p.length > 1) {
+	  p = p.substring(0, p.length - 1)
+	  this.show(p);
+	}
+	else {
+	  this.show();
+	};
+	e.halt();
+	break;
+      default:
+	if (e.key !== undefined && e.key.length != 1)
+	  return;
+
+	// Add prefix
+	if (!this.show(this.prefix() + e.key))
+	  this.hide();
+      };
+    },
+
     // Initialize list
     _init : function (itemClass, params) {
       // this._element.addEventListener("click", chooseHint, false);
+      var that = this;
       this._itemClass = itemClass;
-      this._element = document.createElement("ul");
-      this._element.style.opacity = 0;
+      var e =this._element = document.createElement("ul");
+      e.style.opacity = 0;
+      e.style.outline = 0;
+      e.setAttribute('tabindex', 0);
 
-/*
-      this._listener = document.createElement('input');
-      this._listener.setAttribute('type', 'text');
-//      this._listener.style.display = "none";
-*/
-      this._element.addEventListener(
+      // Arrow keys
+      e.addEventListener(
 	"keydown",
-	function (e) {
-          console.log('+++');
+	function (ev) {
+	  that._keydown(ev)
+	},
+	false
+      );
+
+      // Mousewheel
+      e.addEventListener(
+	'DOMMouseScroll',
+	function (ev) {
+	  that._mousewheel(ev)
 	},
 	false
       );
@@ -125,7 +210,7 @@
 
       // Initialize the list
       if (!this._initList())
-	return;
+	return false;
 
       // show based on initial offset
       this._showItems(0);
@@ -141,10 +226,17 @@
 
       // Add classes for rolling menus
       this._boundary(true);
+      return true;
     },
 
     hide : function () {
+      this.active = false;
+      this.delete();
       this._element.style.opacity = 0;
+
+/*
+      this._element.blur();
+*/
     },
 
     // Initialize the list
@@ -238,8 +330,10 @@
       for (var i = 0; i <= this.limit(); i++) {
 
 	// there is a visible element - unhighlight!
-	if (child = this.shownItem(i))
+	if (child = this.shownItem(i)) {
 	  child.lowlight();
+	  child.active(false);
+	};
       };
 
       // Remove all children
@@ -609,10 +703,10 @@
     },
   };
 
-/*
-  KorAP._updateKey : function (e) {
-    var code = this._codeFromEvent(e)    
+  function _codeFromEvent (e) {
+    if ((e.charCode) && (e.keyCode==0))
+      return e.charCode
+    return e.keyCode;
   };
-*/
 
 }(this.KorAP));