Use containerMenu as a base for HintMenu instead of regular menu
Change-Id: Ic1ed2e216a9c61aabf1f1cac41972b1a4e96a91a
diff --git a/dev/js/src/container/container.js b/dev/js/src/container/container.js
index 02d6fba..0936e6c 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,31 @@
} 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 = 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._el.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(this));
+ this._el.addEventListener("click", function (e) {
+ this._menu.prefix("");
+ this._menu.hint().inputField().insert("").update();
+ this._menu.element().blur();
+ this._menu.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?
- 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.
+ //by default, click focuses its target. Maybe that is why e.halt() is necessary? (https://w3c.github.io/uievents/#event-type-click)
+ }.bind(this));
this.items = new Array();
//items are stored in the order they are added in. This includes the prefix.
@@ -54,24 +71,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 +124,16 @@
return this.isSet(); //TODO check!
}
this._prefixPosition = this.items.length;
+ prefix.content = function (t) {}; //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 +144,9 @@
KorAP.log(0,"Invalid item in containers removeItemByIndex: This containerItem is not contained", "container.js");
return;
};
- if (item === this._prefix) {//CHANGE TO _cItemPrefix later!!!
+ if (item === this._cItemPrefix) {//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");
+ the connection container._cItemPrefix before calling this function if you really want to remove the prefix.","container.js");
return;
};
if (item.active()) {
@@ -173,14 +217,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 () {