New menu with a container for mutliple always available non scrollable items
Change-Id: I5c8379cc82038da4a6c0923bbf59ec8faaa1eb9f
diff --git a/dev/js/src/container/container.js b/dev/js/src/container/container.js
new file mode 100644
index 0000000..9b436ca
--- /dev/null
+++ b/dev/js/src/container/container.js
@@ -0,0 +1,230 @@
+/**
+ * Container for several containerItem style items. Functions like a mini menu with next, prev, add etc propagation,
+ * but no event handling or slider or lengthField. Supposed to be subelement to a (container)menu class item.
+ *
+ * @author Leo Repp
+ */
+
+"use strict";
+define([
+ 'container/containeritem' //TODO why does this not work!!!
+], function (
+ defaultContainerItemClass
+) {
+
+ return {
+ /**
+ *
+ * @param {Array<object>} listOfContainerItems List of items that will be placed within the container and that realise some of the functions supplied in containeritem.js
+ * @param {object} params May contain attribute containerItemClass for a base class all containerItems build upon
+ * @returns The container object
+ */
+ create : function (listOfContainerItems, params) {
+ var obj = Object.create(this);
+ obj._init(listOfContainerItems, params);
+ return obj;
+ },
+
+ _init : function (listOfContainerItems, params){
+ if (params !== undefined && params["containerItemClass"] !== undefined){
+ this._containerItemClass = params["containerItemClass"];
+ } 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.items = new Array();
+ if (listOfContainerItems !== undefined) {
+ for (let item of listOfContainerItems) {
+ this.addItem(item);
+ }
+ }
+
+ this.position = undefined; //undefined = not in container, 0 to length-1 = in container
+
+
+ //t._el.classList.add('visible'); //Done by containermenu
+
+
+ },
+ /**
+ * Upgrade this object to another object,
+ * while private data stays intact.
+ *
+ * @param {Object} An object with properties.
+ */
+ upgradeTo : function (props) {
+ for (let prop in props) {
+ this[prop] = props[prop];
+ };
+ return this;
+ },
+
+ addItem : function (item) {
+ var cItem = this._containerItemClass.create().upgradeTo(item);
+ cItem._menu = this._menu; //if not set then undefined, but thats OK
+ this.items.push(cItem);
+ this._el.appendChild(cItem.element());
+ return cItem;
+ },
+
+ addMenu : function (menu) {
+ this._menu = menu;
+ if (this._prefix !== undefined) {
+ this._menu._prefix = this._prefix; // better than going via classList or something
+ };
+ for (let item of this.items) {
+ item._menu=menu;
+ }
+ },
+
+ addPrefix : function (prefix) {
+ prefix.isSelectable = function () {
+ return this.isSet(); //TODO check!
+ }
+ var prefItem = this.addItem(prefix);
+ this._prefix = prefItem;
+ if (this._menu !== undefined){
+ this._menu._prefix=prefItem;
+ }
+ },
+
+ /**
+ * Exit the container unconditionally. Required so that active returns the
+ * correct result. Called when the prefix or similar resets the currently visual
+ * field.
+ */
+ exit : function () {
+ if (this.position !== undefined) {
+ this.item().active(false);
+ this.position = undefined;
+ };
+ },
+
+ element : function () {
+ return this._el;
+ },
+
+ destroy : function () {
+ for (let item of this.items){
+ delete item['_menu'];
+ }
+ },
+
+ /**
+ * @returns whether an item within the container is active (by checking this.position)
+ */
+ active : function () {
+ return this.position !== undefined;
+ },
+
+ /**
+ * Getter for items
+ * @param {Integer} index [optional] Index of to select item. If left blank this.position.
+ * @returns item at location index
+ */
+ item : function (index) {
+ if (index === undefined) return this.items[this.position];
+ return this.items[index];
+ },
+
+ /**
+ * Move on to the next item in container. Returns true if we then leave the container, false otherwise.
+ */
+ next : function() {
+ if (this.position !== undefined){
+ this.item().active(false);
+ this.position++;
+ } else {
+ this.position = 0;
+ };
+ if (this.position >= this.length()) {
+ this.position=undefined;
+ return true;
+ };
+ while (!this.item().isSelectable()) {
+ this.position++;
+ if (this.position >= this.length()) {
+ this.position=undefined;
+ return true;
+ }
+ };
+ this.item().active(true);
+ return false;
+ },
+
+ /**
+ * Move on to the previous item in container. Returns true if we then leave the container, false otherwise.
+ */
+ prev : function() {
+ if (this.position !== undefined){
+ this.item().active(false);
+ this.position = (this.position-1)
+ } else {
+ this.position = (this.items.length-1);
+ }
+ if (this.position<0) {
+ this.position=undefined;
+ return true;
+ }
+ while (!this.item().isSelectable()) {
+ this.position--;
+ if (this.position<0){
+ this.position=undefined;
+ return true;
+ };
+ };
+ this.item().active(true);
+ return false;
+ },
+
+ further : function () {
+ const item = this.item();
+ if (item["further"] !== undefined) {
+ item["further"].bind(item).apply();
+ };
+ },
+
+ enter : function (event) {
+ this.item().onclick(event);
+ },
+
+ chop : function () {
+ for (let item of this.items) {
+ item.chop();
+ }
+ },
+
+ add : function (letter) {
+ for (let item of this.items) {
+ item.add(letter);
+ }
+ },
+
+ length : function () {
+ return this.items.length;
+ },
+
+ /**
+ *
+ * @returns The number of items that are selectable. Is the actual length of the list.
+ */
+ liveLength : function () {
+ var ll = 0;
+ for (let item of this.items){
+ if (item.isSelectable()){
+ ll++;
+ }
+ }
+ return ll;
+ }
+
+};
+});
\ No newline at end of file