Use containerMenu as a base for HintMenu instead of regular menu

Change-Id: Ic1ed2e216a9c61aabf1f1cac41972b1a4e96a91a
diff --git a/dev/js/src/api.js b/dev/js/src/api.js
index dcc84b7..80391d8 100644
--- a/dev/js/src/api.js
+++ b/dev/js/src/api.js
@@ -145,6 +145,7 @@
     req.setRequestHeader("Accept", "application/json");
     req.setRequestHeader("Content-Type", "application/json");
     req.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
+    //req.setRequestHeader('Origin',"API");
     req.onreadystatechange = function () {
       /*
 	      States:
diff --git a/dev/js/src/container/container.js b/dev/js/src/container/container.js
index 02d6fba..3f6a54d 100644
--- a/dev/js/src/container/container.js
+++ b/dev/js/src/container/container.js
@@ -7,7 +7,7 @@
 
 "use strict";
 define([
-  'container/containeritem'   //TODO why does this not work!!!
+  'container/containeritem'
 ], function (
   defaultContainerItemClass
 ) {
@@ -31,14 +31,10 @@
       } else {
         this._containerItemClass = defaultContainerItemClass;
       };
-      var el = document.createElement("ul");
-      el.style.outline = 0;
-      el.setAttribute('tabindex', 0);
-      el.classList.add('menu', 'container'); //container class allows for more stylesheet changes
-
-      this._el = el;
-      this._prefix = undefined; //required for re-setting the menus pointer correctly
-      // after having upgraded a new item scss style to the prefix object.
+      this._el = document.createElement("ul");
+      this._el.style.outline = 0;
+      this._el.setAttribute('tabindex', 0);
+      this._el.classList.add('menu', 'container'); //container class allows for more stylesheet changes
 
       this.items = new Array();
       //items are stored in the order they are added in. This includes the prefix.
@@ -54,24 +50,48 @@
       this._prefixPosition = undefined; //Required so that switching
       // to prefix by default is supported
 
+      this._menu = undefined // add later
+
 
       
       //t._el.classList.add('visible'); //Done by containermenu
+    },
 
-  },
-
+    /**
+     * Adds a static item to this container by creating a standard containerItem as specified when this container was created,
+     * then upgrading it to the item passed to this function, and calling element() and content(). For a full list of supported functions see
+     * containeritem.js .
+     * Example:
+     * 
+     * menu.container().addItem(
+     *  {defaultTextValue : "dynamic", onClick : function (e) { ... }
+     * )
+     * 
+     *  For a full demo see containermenudemo.js.
+     * 
+     * @param {Object} item An object with any number of functions like in containeritem.js or an attribute defaultTextValue,
+     * as well as any number of own properties.
+     * @returns the new use-ready containerItem
+     */
     addItem : function (item) {
+      //Call Order: First _containerItemClass is created and then upgraded To whatever object is passed to this function
+      //Then container calls first element() and then container()
       var cItem = this._containerItemClass.create().upgradeTo(item);
       cItem._menu = this._menu; //if not set then undefined, but thats OK
       this.items.push(cItem);
+      if (this._cItemPrefix !== undefined){ //this must be dynamic adding of CIs, move prefix to the back
+        this.items.splice(this.items.indexOf(this._cItemPrefix) , 1); //remove cItemPrefix
+        this.items.push(this._cItemPrefix); //and move it to the end;
+      };
       this._el.appendChild(cItem.element());
+      cItem.content(); // create its textNode
       return cItem;
     },
 
     addMenu : function (menu) {
       this._menu = menu;
-      if (this._prefix !== undefined) {
-        this._menu._prefix = this._prefix; // better than going via classList or something
+      if (this._cItemPrefix !== undefined) {
+        this._menu._prefix = this._cItemPrefix; // better than going via classList or something
       };
       for (let item of this.items) {
         item._menu=menu;
@@ -83,13 +103,16 @@
         return this.isSet(); //TODO check!
       }
       this._prefixPosition = this.items.length;
+      prefix.content = function () {}; //Does not need a textNode Child!
       var prefItem = this.addItem(prefix);
-      this._prefix = prefItem;
+      this._cItemPrefix = prefItem;
+      prefItem._el["onclick"] = prefItem.onclick.bind(prefItem);
       if (this._menu !== undefined){
         this._menu._prefix=prefItem;
       }
     },
     
+    //Taken from Branch 5133
     /**
     * Remove a containeritem from the container by identity. Should not be used with prefix.
     * If the active item is removed, this calls menu.next().
@@ -100,9 +123,10 @@
         KorAP.log(0,"Invalid item in containers removeItemByIndex: This containerItem is not contained", "container.js");
         return;
       };
-      if (item === this._prefix) {//CHANGE TO _cItemPrefix later!!!
-        KorAP.log(0,"Tried to remove the prefix item by calling removeItem. Please cut all connections from the menu to prefix and then\
- the connection container._prefix before calling this function if you really want to remove the prefix.","container.js");
+      if (item === this._cItemPrefix) {
+        KorAP.log(0,"Tried to remove the prefix item. Illegal.");
+        console.log("Tried to remove the prefix item by calling removeItem. Please cut all connections from the menu to prefix and then\
+ the connection container._cItemPrefix before calling this function if you really want to remove the prefix.","container.js");
         return;
       };
       if (item.active()) {
@@ -173,14 +197,14 @@
      * menus list empty while we had it selected.
      * This potentially requires adjusting this.position.
      */
-     makeActive : function () {
+    makeActive : function () {
       if (this.position === undefined) {
-        if (this._prefix.isSelectable()) {
+        if (this._cItemPrefix.isSelectable()) {
           this.position = this._prefixPosition; //make prefix active if it exists
           this.item().active(true);
         } else if (this.liveLength() > 0) {
           this.position = 0;
-          this._prefix.active(false); // usually the menu makes the prefix active anyway.
+          this._cItemPrefix.active(false); // usually the menu makes the prefix active anyway.
           this.item().active(true);
         }
       }
diff --git a/dev/js/src/container/containeritem.js b/dev/js/src/container/containeritem.js
index a9a209b..6d0ef59 100644
--- a/dev/js/src/container/containeritem.js
+++ b/dev/js/src/container/containeritem.js
@@ -31,9 +31,11 @@
 
   /**
    * Get/create the document element of the container item. Can be overwritten. Standard class: li
+   * If you wish to change the textNode please overwrite the content function instead.
    */
   element : function () {
-    // already defined
+    //Call Order: First this class is created and then upgraded To whatever object is passed to container
+    //Then container calls first element() and then container()
     if (this._el !== undefined) return this._el;
     
     // Create list item
@@ -47,7 +49,32 @@
   },
 
   /**
-   * Expected to be overwritten
+   * Get/create a TextNode with text "content". If content is left blank it gets set to this.defaultTextValue,
+   * or the empty string if it does not exists
+   * @param {String} content String to which to set the text
+   * @returns textNode with content or undefined
+   */
+  content : function (content) {
+    var newText; //set textNode to this
+    if (arguments.length === 1) { //new value!
+      newText = content;
+    } else { //use default
+      if (this.defaultTextValue === undefined) { //default default is ""
+        this.defaultTextValue = "";
+      }
+      newText = this.defaultTextValue;
+    };
+    if (this._content === undefined) { //no Element until now
+      this._content = document.createTextNode(newText); //create one
+      this.element().appendChild(this._content);
+    } else { //just change it
+      this._content.nodeValue = newText; // use nodeValue instead of _innerHTML
+    };
+    return this._content;
+  },
+
+  /**
+   * Expected to be overwritten. Default returns true always.
    * @returns whether the item is currently an option to be selected, or if it should just be skipped
    */
   isSelectable : function () {
diff --git a/dev/js/src/containermenu.js b/dev/js/src/containermenu.js
index 865c3ec..83e3dc6 100644
--- a/dev/js/src/containermenu.js
+++ b/dev/js/src/containermenu.js
@@ -12,7 +12,7 @@
   'container/container',
   'util'
 ], function (defaultMenuClass,
-             defaultContainerClass) {
+            defaultContainerClass) {
 
   return {
     /**
@@ -41,13 +41,13 @@
       } else {
         obj._container = defaultContainerClass.create(containerList, params);
       }
-      obj.container().addMenu(obj);
+      obj.container().addMenu(obj); //this is your menu, container!
 
       // add entry to HTML element
       obj._el.appendChild(obj.container().element());
-      obj._el.removeChild(obj._prefix.element());
+      obj._el.removeChild(obj._prefix.element()); //different HTML element relationship required
       //Keep prefix as 'pref' style. The additional distance is fine.
-      obj.container().addPrefix(obj._prefix);
+      obj.container().addPrefix(obj._prefix); //creates containeritem as base for prefix that then is upgraded to prefix. Also ajust _menu chains.
       return obj;
     },
 
@@ -128,8 +128,16 @@
         // Click on prefix
         if (t.container().active()){
           t.container().enter(e);
+          //NEW: reset some things. These are reset for hint menu style items
+          // so I believe we need to do the same when pressing on items in the container
+          t.reset("");
+          t.hide();
+          t.hint().unshow();
+          //for clicking this is done in container.js with an eventListener for click.
         } else { // Click on item
           t.liveItem(t.position).onclick(e);
+          //Above is already done: see file dev/js/src/hint/item.js
+
         };
         e.halt();
         break;
@@ -165,25 +173,24 @@
      * @param {string} Prefix for filtering the list
      */
     show : function (active) {
-      //There are only four new lines, marked with NEW
       const t = this;
 
       // show menu based on initial offset
       t._unmark();     // Unmark everything that was marked before
       t.removeItems();
-      t.container().exit(); //NEW
+      t.container().exit();
 
       // Initialize the list
       if (!t._initList()) {
 
         // The prefix is not active
-        t._prefix.active(true);        
-        t.container().makeActive(); //NEW Incase the own
-        // list becomes empty we need to make container active for line 129 to work
+        //t._prefix.active(true);
+        t.container().makeActive(); //Incase the own
+        // list becomes empty we need to make container active for handling ENTER keypress to work
 
         // finally show the element
         t._el.classList.add('visible');
-        t.container()._el.classList.add('visible'); //NEW
+        t.container()._el.classList.add('visible');
 
         return true;
       };
@@ -236,7 +243,7 @@
 
       // finally show the element
       t._el.classList.add('visible');
-      t.container()._el.classList.add('visible'); //NEW
+      t.container()._el.classList.add('visible');
 
       // Add classes for rolling menus
       t._boundary(true);
@@ -254,7 +261,7 @@
         this._prefix.clear();
         this.onHide();
         this._el.classList.remove('visible');
-        this.container()._el.classList.remove('visible'); //NEW
+        this.container()._el.classList.remove('visible'); //NEW //apparently not necessary
       }
       // this._el.blur();
     },
diff --git a/dev/js/src/hint/item.js b/dev/js/src/hint/item.js
index 5c9a9a7..0889e11 100644
--- a/dev/js/src/hint/item.js
+++ b/dev/js/src/hint/item.js
@@ -51,19 +51,13 @@
       var m = this.menu();
       // m.hide();
 
-      // Reset prefix
-      m.prefix("");
-
-      var h = m.hint();
-
-      // Update input field
-      var input = h.inputField();
-      input.insert(this._action).update();
+      // Reset prefix and update the input field
+      m.reset(this._action);
 
       e.halt();
      
       // show alt
-      h.show(true);
+      m.hint().show(true);
     },
 
     /**
diff --git a/dev/js/src/hint/menu.js b/dev/js/src/hint/menu.js
index 89f1d10..ecd0b51 100644
--- a/dev/js/src/hint/menu.js
+++ b/dev/js/src/hint/menu.js
@@ -5,12 +5,12 @@
 "use strict";
 
 define([
-  'menu',
+  'containermenu',
 	'hint/item',
 	'hint/prefix',
 	'hint/lengthField'
 ], function (
-  menuClass,
+  containerMenuClass,
   itemClass,
   prefixClass,
   lengthFieldClass) {
@@ -21,13 +21,11 @@
      * Create new hint helper menu.
      */
     create : function (hint, context, params) {
-      const obj = Object.create(menuClass)
-	        .upgradeTo(this)
-	        ._init(params, {
-	          itemClass : itemClass,
-	          prefixClass : prefixClass,
-	          lengthFieldClass : lengthFieldClass
-	        });
+      const obj = containerMenuClass.create(params, {
+        itemClass : itemClass,
+        prefixClass : prefixClass,
+        lengthFieldClass : lengthFieldClass})
+	      .upgradeTo(this);
       obj._context = context;
       obj._el.classList.add('hint');
       obj._hint = hint;
@@ -38,6 +36,27 @@
       obj.element().addEventListener('blur', function (e) {
         this.menu.hide(); // WithoutDestruction();
       });
+      // Fix the containeritems not being clickable. Add this to the containers element.
+      obj.container().element().addEventListener("mousedown", function (e) {
+        // see https://stackoverflow.com/questions/10652852/jquery-fire-click-before-blur-event
+        e.preventDefault();
+        // It used to be, that clicking on a item within the container (see container.js) would cause the container to gain focus
+        // thanks to mousedown default behaviour, which would mean the actual menu (ul menu roll containermenu hint) would not be in focus (I think? containermenu ul is its child
+        // afterall?). This would cause blur to be called, which (see hint/menu.js) would hide the current menu and its container, causing click to target a location
+        // the containeritem USED to be.
+        //https://w3c.github.io/uievents/#event-type-mousedown
+        //These default actions are thus not supported anymore.
+        
+      }.bind(obj));
+      obj.container().element().addEventListener("click", function (e) {
+        this.reset("");
+        this.element().blur();
+        this.hint().unshow(); //hide the containermenu, not with hide but with blur, because blur would usually happen in default mousedown behaviour
+        e.halt(); // Question: my impression is that this click event handler is called after all the others and thus this should be absolutely no problem.
+        // Are we sure there are no things that do not happen now thanks to this?
+
+        //by default, click focuses its target. Maybe that is why e.halt() is necessary? (https://w3c.github.io/uievents/#event-type-click)
+      }.bind(obj));
 
       // Focus on input field on hide
       obj.onHide = function () {
@@ -60,6 +79,14 @@
      */ 
     hint : function () {
       return this._hint;
-    }
+    },
+
+    /**
+     * Reset the prefix, inputField and hide the menu. Called by hint/item.
+     */
+     reset : function (action) {
+      this.prefix("");
+      this.hint().inputField().insert(action).update();
+    },
   };
 });
diff --git a/dev/js/src/hint/prefix.js b/dev/js/src/hint/prefix.js
index 1a673f8..7f4d300 100644
--- a/dev/js/src/hint/prefix.js
+++ b/dev/js/src/hint/prefix.js
@@ -18,6 +18,7 @@
       const m = this.menu();
       const value = this.value();
       const h = m.hint();
+
       h.inputField().insert(value);
       h.active(null);
       m.hide();
diff --git a/dev/js/src/menu.js b/dev/js/src/menu.js
index 0c84c48..857c2db 100644
--- a/dev/js/src/menu.js
+++ b/dev/js/src/menu.js
@@ -491,7 +491,7 @@
      * @param {string} Prefix for filtering the list
      */
     show : function (active) {
-      //Upon change please also update alwaysmenu.js (only two lines new there)
+      //Upon change please also update alwaysmenu.js and containermenu.js (only two lines new there)
       const t = this;
 
       // show menu based on initial offset
@@ -850,6 +850,12 @@
       this.screen(this.offset + 1);
     },
 
+    /**
+     * Reset the prefix. Currently not used in regular menu.
+     */
+    reset : function () {
+      this.prefix("");
+    },
 
     // Unmark all items
     _unmark : function () {