Introduce touch gesture for hint menu

Change-Id: I63e55405ea0d4df8a51932f96c6bbd312ebe4388
diff --git a/Changes b/Changes
index e76a4e8..42669a2 100755
--- a/Changes
+++ b/Changes
@@ -3,6 +3,8 @@
           in favor of Kalamar.api_path.
         - Fix replacement of docs with docGroupRefs in
           VC builder.
+        - Improve touch support for menus.
+        - Improve touch support for annotation assistant.
 
 0.28 2018-08-29
         - Introduced Widget based plugin system.
@@ -50,7 +52,7 @@
         - Added Piwik/Matomo integration.
 
 0.25 2018-01-31
-        - Make annotation helper configurable.
+        - Make annotation assistant configurable.
         - Support multiple prefixes in menus.
         - Show annotation tooltips in table views.
         - Improve result display when JavaScript is disabled.
@@ -80,11 +82,11 @@
 0.21 2017-02-01
         - Use textSigle for API communication instead of
           {corpus,doc,text}ID.
-        - Added alert to hint helper.
+        - Added alert to annotation assistant.
         - Improved menu creation.
         - Introduced benchmark system.
         - select elements are now improved menus.
-        - Hint menu do not append menus anymore.
+        - Annotation menu do not append menus anymore.
         - Updated dependency for bugfixed Localize.
         - Improved readme for localization generation.
         - Fixed select menus to show selected item on
@@ -140,7 +142,7 @@
         - Project name is now "Kalamar"
         - Removed Mr Crabs - introduced Karl
         - Support semantic markup for KWIC
-        - Fixed Click-bug in hint-menu
+        - Fixed Click-bug in annotation menu
         - Renamed "KorAP" classes to "Kalamar"
         - Support proxy
 
diff --git a/dev/demo/plugin-server.html b/dev/demo/plugin-server.html
index 1c87fa2..5065d41 100644
--- a/dev/demo/plugin-server.html
+++ b/dev/demo/plugin-server.html
@@ -7,7 +7,7 @@
         see https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
     <meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">
 -->
-    <script data-main="/demo/menudemo.js" src="/js/lib/require.js" async="async"></script>
+    <script data-main="/demo/plugin-serverdemo.js" src="/js/lib/require.js" async="async"></script>
   </head>
   <body>
     <p>Start the demo server with <code>morbo -l 'http://*:3003' t/plugin-server.pl</code> and open <a href="http://localhost:3003/demo/plugin-server.html"><code>this website</code></a>.</p>
diff --git a/dev/js/src/hint.js b/dev/js/src/hint.js
index 519ed26..91381f5 100644
--- a/dev/js/src/hint.js
+++ b/dev/js/src/hint.js
@@ -23,9 +23,9 @@
   'hint/alert',
   'util'
 ], function (inputClass, 
-	     menuClass,
-	     analyzerClass,
-	     alertClass) {
+             menuClass,
+             analyzerClass,
+             alertClass) {
   "use strict";
 
   /**
@@ -101,17 +101,17 @@
       var that = this;
 
       this._inputField.container().addEventListener('click', function (e) {
-	      if (!this.classList.contains('active')) {
-	        that.show(false);
-	      };
+        if (!this.classList.contains('active')) {
+          that.show(false);
+        };
       });
 
       var _down = function (e) {
-	      var code = _codeFromEvent(e);
-	      if (code === 40) {
-	        this.show(false);
-	        e.halt();
-	      };
+        var code = _codeFromEvent(e);
+        if (code === 40) {
+          this.show(false);
+          e.halt();
+        };
       };
       
       // Move infobox
@@ -120,12 +120,29 @@
 
       // Add event listener for key pressed down
       inputFieldElement.addEventListener(
-	      "keydown", _down.bind(this), false
+        "keydown", _down.bind(this), false
+      );
+
+      // Add touch events
+      inputFieldElement.addEventListener(
+        'touchstart',
+        this._touch.bind(this),
+        false
+      );
+      inputFieldElement.addEventListener(
+        'touchend',
+        this._touch.bind(this),
+        false
+      );
+      inputFieldElement.addEventListener(
+        'touchmove',
+        this._touch.bind(this),
+        false
       );
 
       // Set Analyzer for context
       this._analyzer = analyzerClass.create(
-	      param["context"] || KorAP.context
+        param["context"] || KorAP.context
       );
       return this;
     },
@@ -145,11 +162,11 @@
     alert : function (charPos, msg) {
 
       if (arguments.length === 0)
-	      return this._alert;
+        return this._alert;
 
       // Do not alert if already alerted!
       if (this._alert.active)
-	      return false;
+        return false;
 
       // Move to the correct position
       this._inputField.moveto(charPos);
@@ -169,7 +186,7 @@
     update : function () {
       this._inputField.update();
       if (this._alert.hide())
-	      this.active(null);
+        this.active(null);
     },
 
 
@@ -179,14 +196,14 @@
     menu : function (action) {
       if (this._menu[action] === undefined) {
 
-	      // No matching hint menu
-	      if (KorAP.annotationHelper[action] === undefined)
-	        return;
+        // No matching hint menu
+        if (KorAP.annotationHelper[action] === undefined)
+          return;
 
-	      // Create matching hint menu
-	      this._menu[action] = menuClass.create(
-	        this, action, KorAP.annotationHelper[action]
-	      );
+        // Create matching hint menu
+        this._menu[action] = menuClass.create(
+          this, action, KorAP.annotationHelper[action]
+        );
       };
 
       // Return matching hint menu
@@ -209,7 +226,7 @@
       context = this._analyzer.test(context);
 
       if (context === undefined || context.length == 0) {
-	      return ifContext ? undefined : this.menu("-");
+        return ifContext ? undefined : this.menu("-");
       };
 
       return this.menu(context) || (ifContext ? undefined : this.menu('-'));
@@ -225,19 +242,19 @@
 
       // A menu or null was passed
       if (arguments.length === 1) {
-	      var c = this._inputField.container();
+        var c = this._inputField.container();
 
         // Make the menu active
-	      if (obj !== null) {
-	        c.classList.add('active');
-	        this._active = obj;
-	      }
+        if (obj !== null) {
+          c.classList.add('active');
+          this._active = obj;
+        }
 
         // Make the menu inactive
-	      else {
-	        c.classList.remove('active');
-	        this._active = null;
-	      }
+        else {
+          c.classList.remove('active');
+          this._active = null;
+        }
       };
 
       // Return
@@ -258,19 +275,19 @@
 
       // Remove the active object
       this._unshow();
-     
+      
       // Get the menu
       var menu;
       if (menu = this.contextMenu(ifContext)) {
-	      this.active(menu);
+        this.active(menu);
 
         var c = this._inputField.container();        
-	      c.appendChild(menu.element());
+        c.appendChild(menu.element());
 
-	      menu.show();
-	      menu.focus();
-	      // Focus on input field
-	      // this.inputField.element.focus();
+        menu.show();
+        menu.focus();
+        // Focus on input field
+        // this.inputField.element.focus();
       }
       else {
         this._inputField.element().focus();
@@ -296,19 +313,40 @@
       this._inputField.element().focus();
     },
 
+
+    // Catch touch events
+    _touch : function (e) {
+
+      if (e.type === 'touchstart') {
+        var t = e.touches[0];
+        this._lastTouch = t.clientY;
+      }
+      else if (e.type === 'touchend') {
+        this._lastTouch = undefined;
+      }
+      else if (e.type == 'touchmove') {
+        var t = e.touches[0];
+        if ((this._lastTouch + 10) < t.clientY) {
+          this.show();
+          this._lastTouch = undefined;
+        };
+        e.halt();
+      }
+    },
+
     
     _unshow : function () {
       if (this.active() !== null) {
         // var act = this.active();
 
         // This does not work for alert currently!
-	      //if (act._type !== 'alert') {
+        //if (act._type !== 'alert') {
         if (!this._alert.active) {
 
           // This does not work for webkit!
           var c = this._inputField.container();
           c.removeChild(this._active.element());
-	      }
+        }
         else {
           this._unshowAlert();
         };
diff --git a/dev/js/src/hint/input.js b/dev/js/src/hint/input.js
index e61d820..a163727 100644
--- a/dev/js/src/hint/input.js
+++ b/dev/js/src/hint/input.js
@@ -49,6 +49,7 @@
     return this._element.value;
   },
 
+
   /**
    * Get the value of the input field mirror.
    */
@@ -58,7 +59,7 @@
 
 
   /**
-     * Reset the input value
+   * Reset the input value
    */
   reset : function () {
     this._element.value = "";
@@ -138,7 +139,7 @@
     return this._split()[0];
   },
 
-  
+
   // Initialize new input field
   _init : function (element) {
     this._element = element;
@@ -162,6 +163,7 @@
     return this;
   },
 
+
   // Get the right position
   _rightPos : function () {
     var box = this._mirror.firstChild.getBoundingClientRect();
diff --git a/dev/js/src/menu.js b/dev/js/src/menu.js
index 7155cdf..1f9d849 100644
--- a/dev/js/src/menu.js
+++ b/dev/js/src/menu.js
@@ -335,8 +335,6 @@
       else if (e.type === "touchend") {
         // s.active(false);
         this._lastTouch = undefined;
-        // TODO:
-        // Release click event on touchend!
       }
       else if (e.type === "touchmove") {
         var t = e.touches[0];
diff --git a/package.json b/package.json
index b26b983..b9d3f8d 100755
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
   "name": "Kalamar",
   "description": "Mojolicious-based Frontend for KorAP",
   "license": "BSD-2-Clause",
-  "version": "0.29.0",
+  "version": "0.29.1",
   "pluginVersion": "0.1",
   "repository" : {
     "type": "git",