Use containerMenu as a base for HintMenu instead of regular menu
Change-Id: Ic1ed2e216a9c61aabf1f1cac41972b1a4e96a91a
diff --git a/Changes b/Changes
index b2c076e..04fe791 100755
--- a/Changes
+++ b/Changes
@@ -47,6 +47,8 @@
lead to server crash.
- Fix query-by-match for multiple colons.
- Fix "menu below hint marker" bug.
+ - HintMenu is now based on containerMenu instead of regular
+ menu (lerepp)
0.42 2021-06-18
- Added GitHub based CI for perl.
diff --git a/dev/demo/containermenudemo.js b/dev/demo/containermenudemo.js
index e3b0f99..f1f66c0 100644
--- a/dev/demo/containermenudemo.js
+++ b/dev/demo/containermenudemo.js
@@ -24,8 +24,9 @@
},
// enter or click
- onclick : function () {
+ onclick : function (event) {
console.log(this._name);
+ event.halt();
},
// right arrow
@@ -56,6 +57,7 @@
.upgradeTo(this);
//._init();
obj.value="";
+ obj.defaultTextValue = "CI";
return obj;
},
add : function (letter) {
@@ -67,25 +69,18 @@
further : function () {
this.value = this.value + this.value;
},
+ isSelectable : function () {
+ return (this.value !== "");
+ },
+ chop : function () {
+ console.log("chop");
+ console.log(this.content(this.value));
+ },
onclick : function () {
- console.log('ContainerItem' + this.value);
+ console.log('ContainerItem ' + this.value);
console.log(this._i);
this._menu.limit(this._i);
this._menu.show();
- },
- element : function () {
- // already defined
- if (this._el !== undefined) return this._el;
-
- // Create list item
- const li = document.createElement("li");
- li.innerHTML="CI";
-
- // Connect action
- if (this["onclick"] !== undefined) {
- li["onclick"] = this.onclick.bind(this);
- };
- return this._el = li;
}
};
//List of items.
@@ -100,6 +95,7 @@
ExampleItemList[2]._i=5;
ExampleItemList[2].onclick = function (e) {
this._menu.container().removeItemByIndex(3);
+ //Should fail, that's ok. You can also try index 0 for testing functionality.
};
//Own container class.
@@ -224,6 +220,8 @@
document.getElementById('menu').appendChild(menu.element());
//document.getElementById('largemenu').appendChild(largeMenu.element());
+ menu.container().addItem({ value : "Dynamically added", defaultTextValue : "dynamic", _i : 5})
+
menu.limit(3).show(3);
menu.focus();
diff --git a/dev/demo/hintdemo.js b/dev/demo/hintdemo.js
index 413625c..4f2e12d 100644
--- a/dev/demo/hintdemo.js
+++ b/dev/demo/hintdemo.js
@@ -15,6 +15,14 @@
KorAP.Hint = hintClass.create();
+ var newItem = {
+ onclick : function (e) { console.log("CI click"); console.log(this.element()); console.log("'" + this._menu.prefix() + "'" + " <-- If this returns the empty string when\
+ it should not, we know that the click event listener in container.js gets called too early and overwrites the prefix before we can read it.");},
+ chop : function () { console.log("chop"); },
+ defaultTextValue : "Text Example"
+ };
+ KorAP.Hint.menu("-").container().addItem(newItem); //must be added to a specific context menu.
+
/**
* Add query panel
*/
@@ -69,10 +77,13 @@
}
}]
});
+
+ console.log(KorAP.Hint);
});
});
function demoAlert (pos, msg) {
if (KorAP.hint !== undefined)
KorAP.Hint.alert(pos, msg);
+ console.log(KorAP.Hint);
}
diff --git a/dev/js/spec/containerMenuSpec.js b/dev/js/spec/containerMenuSpec.js
index 40d72e0..a6d85b7 100644
--- a/dev/js/spec/containerMenuSpec.js
+++ b/dev/js/spec/containerMenuSpec.js
@@ -45,31 +45,13 @@
this.value = this.value + this.value;
},
onclick : function () {
- },
- element : function () {
- // already defined
- if (this._el !== undefined) return this._el;
-
- // Create list item
- const li = document.createElement("li");
- li.innerHTML="CI";
-
- // Connect action
- if (this["onclick"] !== undefined) {
- li["onclick"] = this.onclick.bind(this);
- };
- return this._el = li;
}
};
//List of items.
var ExampleItemList = new Array;
- ExampleItemList.push(OwnContainerItemClass.create());
- ExampleItemList.push(OwnContainerItemClass.create());
- ExampleItemList[0].value = "CIValue1 ";
- ExampleItemList[1].value = "CIValue2 ";
- ExampleItemList[0].element().innerHTML = "CIText1 ";
- ExampleItemList[1].element().innerHTML = "CIText2 ";
+ ExampleItemList.push({value : "CIValue1" , defaultTextValue : "CIText1 "});
+ ExampleItemList.push({value : "CIValue2" , defaultTextValue : "CIText2 "});
//Own container class.
const OwnContainerClass = {
@@ -228,9 +210,9 @@
expect(liElements[2].classList.contains("no-more")).toBe(false);
var items = menu.container().items;
- expect(items[0].element().innerHTML).toEqual("CIText1 ");
- expect(items[1].element().innerHTML).toEqual("CIText2 ");
- expect(items[2].element().innerHTML).toEqual("");
+ expect(items[0].content().nodeValue).toEqual("CIText1 ");
+ expect(items[1].content().nodeValue).toEqual("CIText2 ");
+ expect(items[2].element().innerHTML).toEqual(""); //prefix!
expect(items[3]).toBe(undefined);
});
@@ -2115,11 +2097,11 @@
expect(container.element().nodeName).toEqual("UL");
expect(container.element().classList.contains("menu")).toBeTruthy();
expect(container.element().classList.contains("visible")).toBeFalsy();
- expect(menu._prefix).toEqual(container._prefix);
+ expect(menu._prefix).toEqual(container._cItemPrefix);
expect(container.length()).toEqual(1);
expect(container.length()).toEqual(container.items.length);
expect(container.liveLength()).toEqual(0);
- expect(container.item(0)).toEqual(container._prefix);
+ expect(container.item(0)).toEqual(container._cItemPrefix);
expect(container.active()).toBeFalsy();
expect(directElementChildrenByTagName(menu.element(),"pref")).toEqual([]);
expect(container.element().getElementsByClassName("pref").length).toEqual(1);
@@ -2132,5 +2114,191 @@
expect(container.active()).toBeTruthy();
});
+ it("should support dynamic changing of text content", function () {
+ var list = [
+ ["Constituency"],
+ ["Lemma"],
+ ["Morphology"],
+ ["Part-of-Speech"],
+ ["Syntax"]
+ ];
+
+ var ExampleItemList2 = new Array;
+ ExampleItemList2.push({defaultTextValue : "CIText1 "});
+ ExampleItemList2.push({});
+
+ var menu = OwnContainerMenu.create(list,ExampleItemList2);
+ var container = menu.container();
+ expect(container.item(0).content().nodeValue).toEqual("CIText1 ");
+ expect(container.item(1).content().nodeValue).toEqual("");
+ expect(container.item(2)).toBeDefined();
+ expect(container.item(2).content()).toEqual(undefined);
+ expect(container._cItemPrefix.element().innerHTML).toEqual("");
+ expect(container.item(0).content("New1").nodeValue).toEqual("New1");
+ expect(container.item(1).content("New2").nodeValue).toEqual("New2");
+ expect(container._cItemPrefix.element().innerHTML).toEqual("");
+ expect(container.item(2)).toBeDefined();
+ expect(container.item(2).content()).toEqual(undefined);
+ expect(container.item(0).content().nodeValue).toEqual("CIText1 ");
+ expect(container.item(1).content().nodeValue).toEqual("");
+ expect(container._cItemPrefix.element().innerHTML).toEqual("");
+ expect(container.item(2)).toBeDefined();
+ expect(container.item(2).content()).toEqual(undefined);
+
+
+ });
+
+ it("should support dynamic adding of items", function () {
+
+ var list = [
+ ["Constituency"],
+ ["Lemma"],
+ ["Morphology"],
+ ["Part-of-Speech"],
+ ["Syntax"]
+ ];
+
+ var ExampleItemList2 = new Array;
+ ExampleItemList2.push({defaultTextValue : "CIText1 "});
+ ExampleItemList2.push({});
+
+ var menu = OwnContainerMenu.create(list,ExampleItemList2);
+ var container = menu.container();
+ expect(container.item(0).content().nodeValue).toEqual("CIText1 ");
+ expect(container.item(1).content().nodeValue).toEqual("");
+ expect(container.item(2).content()).toEqual(undefined);
+ expect(container.item(2)).toBeDefined();
+ expect(container._cItemPrefix.element().innerHTML).toEqual("");
+ container.addItem({defaultTextValue : "CIText2 "});
+ expect(container.item(0).content().nodeValue).toEqual("CIText1 ");
+ expect(container.item(1).content().nodeValue).toEqual("");
+ expect(container.item(2).content().nodeValue).toEqual("CIText2 ");
+ expect(container.item(3)).toBeDefined();
+ expect(container.item(3).content()).toEqual(undefined);
+ expect(container._cItemPrefix.element().innerHTML).toEqual("");
+ container.add("a");
+
+ menu.next();
+ menu.next();
+ menu.next();
+ menu.next();
+ menu.next();
+ expect(container.item(0).active()).toBeTruthy();
+ menu.next();
+ expect(container.item(1).active()).toBeTruthy();
+ menu.next();
+ expect(container.item(2).active()).toBeTruthy();
+ menu.next();
+ expect(container.item(3).active()).toBeTruthy();
+ menu.next();
+ expect(container.item(3).active()).toBeFalsy();
+ menu.prev();
+ expect(container.item(3).active()).toBeTruthy();
+ menu.prev();
+ expect(container.item(2).active()).toBeTruthy();
+ menu.prev();
+ expect(container.item(1).active()).toBeTruthy();
+ menu.prev();
+ expect(container.item(0).active()).toBeTruthy();
+ menu.prev();
+ expect(container.item(0).active()).toBeFalsy();
+
+
+
+ });
+
+ it("should support dynamic changing of text content", function () {
+ var list = [
+ ["Constituency"],
+ ["Lemma"],
+ ["Morphology"],
+ ["Part-of-Speech"],
+ ["Syntax"]
+ ];
+
+ var ExampleItemList2 = new Array;
+ ExampleItemList2.push({defaultTextValue : "CIText1 "});
+ ExampleItemList2.push({});
+
+ var menu = OwnContainerMenu.create(list,ExampleItemList2);
+ var container = menu.container();
+ expect(container.item(0).content().nodeValue).toEqual("CIText1 ");
+ expect(container.item(1).content().nodeValue).toEqual("");
+ expect(container.item(2)).toBeDefined();
+ expect(container.item(2).content()).toEqual(undefined);
+ expect(container._cItemPrefix.element().innerHTML).toEqual("");
+ expect(container.item(0).content("New1").nodeValue).toEqual("New1");
+ expect(container.item(1).content("New2").nodeValue).toEqual("New2");
+ expect(container._cItemPrefix.element().innerHTML).toEqual("");
+ expect(container.item(2)).toBeDefined();
+ expect(container.item(2).content()).toEqual(undefined);
+ expect(container.item(0).content().nodeValue).toEqual("CIText1 ");
+ expect(container.item(1).content().nodeValue).toEqual("");
+ expect(container._cItemPrefix.element().innerHTML).toEqual("");
+ expect(container.item(2)).toBeDefined();
+ expect(container.item(2).content()).toEqual(undefined);
+
+
+ });
+
+ it("should support dynamic adding of items", function () {
+
+ var list = [
+ ["Constituency"],
+ ["Lemma"],
+ ["Morphology"],
+ ["Part-of-Speech"],
+ ["Syntax"]
+ ];
+
+ var ExampleItemList2 = new Array;
+ ExampleItemList2.push({defaultTextValue : "CIText1 "});
+ ExampleItemList2.push({});
+
+ var menu = OwnContainerMenu.create(list,ExampleItemList2);
+ var container = menu.container();
+ expect(container.item(0).content().nodeValue).toEqual("CIText1 ");
+ expect(container.item(1).content().nodeValue).toEqual("");
+ expect(container.item(2).content()).toEqual(undefined);
+ expect(container.item(2)).toBeDefined();
+ expect(container._cItemPrefix.element().innerHTML).toEqual("");
+ container.addItem({defaultTextValue : "CIText2 "});
+ expect(container.item(0).content().nodeValue).toEqual("CIText1 ");
+ expect(container.item(1).content().nodeValue).toEqual("");
+ expect(container.item(2).content().nodeValue).toEqual("CIText2 ");
+ expect(container.item(3)).toBeDefined();
+ expect(container.item(3).content()).toEqual(undefined);
+ expect(container._cItemPrefix.element().innerHTML).toEqual("");
+ container.add("a");
+
+ menu.next();
+ menu.next();
+ menu.next();
+ menu.next();
+ menu.next();
+ expect(container.item(0).active()).toBeTruthy();
+ menu.next();
+ expect(container.item(1).active()).toBeTruthy();
+ menu.next();
+ expect(container.item(2).active()).toBeTruthy();
+ menu.next();
+ expect(container.item(3).active()).toBeTruthy();
+ menu.next();
+ expect(container.item(3).active()).toBeFalsy();
+ menu.prev();
+ expect(container.item(3).active()).toBeTruthy();
+ menu.prev();
+ expect(container.item(2).active()).toBeTruthy();
+ menu.prev();
+ expect(container.item(1).active()).toBeTruthy();
+ menu.prev();
+ expect(container.item(0).active()).toBeTruthy();
+ menu.prev();
+ expect(container.item(0).active()).toBeFalsy();
+
+
+
+ });
+
});
});
diff --git a/dev/js/spec/hintSpec.js b/dev/js/spec/hintSpec.js
index 3e95e55..e81033d 100644
--- a/dev/js/spec/hintSpec.js
+++ b/dev/js/spec/hintSpec.js
@@ -272,7 +272,6 @@
hint.inputField().insert('der Baum corenlp/');
var cont = hint.inputField().container();
-
expect(cont.getElementsByTagName('div').length).toBe(1);
expect(cont.getElementsByTagName('ul').length).toBe(0);
expect(cont.firstChild).toEqual(cont.firstChild);
@@ -281,34 +280,34 @@
// There is a menu for corenlp/
hint.show(false);
- expect(hint.inputField().container().getElementsByTagName('ul').length).toEqual(1);
- expect(hint.inputField().container().getElementsByTagName('li').length).toEqual(3);
+ expect(cont.getElementsByTagName('ul').length).toEqual(1+1); //+1 from containermenu (see container/container.js)
+ expect(cont.getElementsByTagName('li').length).toEqual(3);
// Hide the menu and focus on the input
hint.unshow();
- expect(hint.inputField().container().getElementsByTagName('div').length).toEqual(1);
- expect(hint.inputField().container().getElementsByTagName('li').length).toEqual(0);
+ expect(cont.getElementsByTagName('div').length).toEqual(1);
+ expect(cont.getElementsByTagName('li').length).toEqual(0);
hint.unshow();
hint.inputField().insert(' hhhh');
- // show with context
+ // show with context if possible
hint.show(false);
- expect(hint.inputField().container().getElementsByTagName('div').length).toEqual(4);
- expect(hint.inputField().container().getElementsByTagName('ul').length).toEqual(1);
- expect(hint.inputField().container().getElementsByTagName('li').length).toEqual(2);
+ expect(cont.getElementsByTagName('div').length).toEqual(4);
+ expect(cont.getElementsByTagName('ul').length).toEqual(1+1);//+1 from containermenu (see container/container.js)
+ expect(cont.getElementsByTagName('li').length).toEqual(2);
hint.unshow();
hint.inputField().insert(' aaaa/');
- // show with context
+ // show with context necessarily
hint.show(true);
- expect(hint.inputField().container().getElementsByTagName('div').length).toEqual(1);
- expect(hint.inputField().container().getElementsByTagName('ul').length).toEqual(0);
+ expect(cont.getElementsByTagName('div').length).toEqual(1);
+ expect(cont.getElementsByTagName('ul').length).toEqual(0); //here not +1: context doesnt fit
});
@@ -324,25 +323,25 @@
hint.show(false);
expect(hint.active()).toBeTruthy();
-
- expect(hint.inputField().container().getElementsByTagName('li')[0].firstChild.innerText).toEqual("Base Annotation");
+ var cont = hint.inputField().container();
+ expect(cont.getElementsByTagName('li')[0].firstChild.innerText).toEqual("Base Annotation");
// Type in prefix
hint.active().prefix("cor").show();
expect(hint.active().prefix()).toEqual("cor");
// Click first step
- expect(hint.inputField().container().getElementsByTagName('li')[0].firstChild.firstChild.innerText).toEqual("Cor");
- hint.inputField().container().getElementsByTagName('li')[0].click();
+ expect(cont.getElementsByTagName('li')[0].firstChild.firstChild.innerText).toEqual("Cor");
+ cont.getElementsByTagName('li')[0].click();
expect(hint.active()).toBeTruthy();
// Click second step
- expect(hint.inputField().container().getElementsByTagName('li')[0].firstChild.innerText).toEqual("Named Entity");
- hint.inputField().container().getElementsByTagName('li')[0].click()
+ expect(cont.getElementsByTagName('li')[0].firstChild.innerText).toEqual("Named Entity");
+ cont.getElementsByTagName('li')[0].click()
// Invisible menu
- expect(hint.inputField().container().getElementsByTagName('li')[0]).toBeUndefined();
+ expect(cont.getElementsByTagName('li')[0]).toBeUndefined();
// Inactive menu
expect(hint.active()).toBeFalsy();
@@ -420,10 +419,16 @@
// Type in prefix
hint.active().prefix("cor").show();
+ expect(hint.active()._prefix.value()).toBe("cor");
expect(hint.active().prefix()).toEqual("cor");
-
expect(input.value).toEqual("");
+ expect(hint.active()._prefix["isSelectable"]).not.toBeNull();
+ expect(hint._menuCollection['-']._prefix["isSelectable"]).not.toBeNull();
+ expect(hint.active()._prefix).toBe(hint._menuCollection['-']._prefix);
+ expect(hint.active()._prefix.element()).toBe(hint._menuCollection['-']._prefix.element());
hint.active()._prefix.element().click();
+
+
expect(input.value).toEqual("cor");
expect(hint.active()).toBeFalsy();
@@ -433,6 +438,7 @@
});
+
xit('should remove all menus on escape');
});
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 () {
diff --git a/dev/scss/header/containermenu.scss b/dev/scss/header/containermenu.scss
new file mode 100644
index 0000000..973bf6b
--- /dev/null
+++ b/dev/scss/header/containermenu.scss
@@ -0,0 +1,5 @@
+ul.containermenu {
+ > ul.container:not(.visible) {
+ display: none;
+ }
+}
diff --git a/dev/scss/header/header.scss b/dev/scss/header/header.scss
index 78fa532..76c583e 100644
--- a/dev/scss/header/header.scss
+++ b/dev/scss/header/header.scss
@@ -1,6 +1,7 @@
@charset "utf-8";
@import "../util";
@import "hint"; // Hint specific menu list
+@import "containermenu"; // Container menu specific
@import "searchbar"; // The search bar
@import "vc"; // Virtual corpus builder
@import "statistics"; // Statistics for VCs
@@ -141,4 +142,4 @@
&:last-child {
border-top-right-radius: 0;
}
-}
\ No newline at end of file
+}
diff --git a/lib/Kalamar/Plugin/QueryReference.pm b/lib/Kalamar/Plugin/QueryReference.pm
index bb1b390..5bdf8e8 100644
--- a/lib/Kalamar/Plugin/QueryReference.pm
+++ b/lib/Kalamar/Plugin/QueryReference.pm
@@ -25,7 +25,7 @@
$r->add_type('qname' => qr![-_\.a-zA-Z0-9]+!);
-
+
# List queries
$r->get('/query')->to(
cb => sub {
diff --git a/t/plugin/demo_server.t b/t/plugin/demo_server.t
index 1b2b524..b761fba 100644
--- a/t/plugin/demo_server.t
+++ b/t/plugin/demo_server.t
@@ -20,6 +20,6 @@
->content_type_is('application/javascript')
->content_like(qr!'app/en'!)
;
-
+
done_testing;
__END__