blob: 60bc0d94c70e8a65d5bb661084003e38857a3876 [file] [log] [blame]
Leo Reppd162b2e2021-06-30 13:51:07 +02001/**
2 * Container for several containerItem style items. Functions like a mini menu with next, prev, add etc propagation,
3 * but no event handling or slider or lengthField. Supposed to be subelement to a (container)menu class item.
4 *
5 * @author Leo Repp
6 */
7
8"use strict";
9define([
10 'container/containeritem' //TODO why does this not work!!!
11], function (
12 defaultContainerItemClass
13) {
14
15 return {
16 /**
17 *
18 * @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
19 * @param {object} params May contain attribute containerItemClass for a base class all containerItems build upon
20 * @returns The container object
21 */
22 create : function (listOfContainerItems, params) {
23 var obj = Object.create(this);
24 obj._init(listOfContainerItems, params);
25 return obj;
26 },
27
28 _init : function (listOfContainerItems, params){
29 if (params !== undefined && params["containerItemClass"] !== undefined){
30 this._containerItemClass = params["containerItemClass"];
31 } else {
32 this._containerItemClass = defaultContainerItemClass;
33 };
34 var el = document.createElement("ul");
35 el.style.outline = 0;
36 el.setAttribute('tabindex', 0);
37 el.classList.add('menu', 'container'); //container class allows for more stylesheet changes
38
39 this._el = el;
40 this._prefix = undefined; //required for re-setting the menus pointer correctly
41 // after having upgraded a new item scss style to the prefix object.
42
43 this.items = new Array();
44 if (listOfContainerItems !== undefined) {
45 for (let item of listOfContainerItems) {
46 this.addItem(item);
47 }
48 }
49
50 this.position = undefined; //undefined = not in container, 0 to length-1 = in container
51
52
53 //t._el.classList.add('visible'); //Done by containermenu
54
55
56 },
Leo Reppd162b2e2021-06-30 13:51:07 +020057
58 addItem : function (item) {
59 var cItem = this._containerItemClass.create().upgradeTo(item);
60 cItem._menu = this._menu; //if not set then undefined, but thats OK
61 this.items.push(cItem);
62 this._el.appendChild(cItem.element());
63 return cItem;
64 },
65
66 addMenu : function (menu) {
67 this._menu = menu;
68 if (this._prefix !== undefined) {
69 this._menu._prefix = this._prefix; // better than going via classList or something
70 };
71 for (let item of this.items) {
72 item._menu=menu;
73 }
74 },
75
76 addPrefix : function (prefix) {
77 prefix.isSelectable = function () {
78 return this.isSet(); //TODO check!
79 }
80 var prefItem = this.addItem(prefix);
81 this._prefix = prefItem;
82 if (this._menu !== undefined){
83 this._menu._prefix=prefItem;
84 }
85 },
86
87 /**
88 * Exit the container unconditionally. Required so that active returns the
89 * correct result. Called when the prefix or similar resets the currently visual
90 * field.
91 */
92 exit : function () {
93 if (this.position !== undefined) {
94 this.item().active(false);
95 this.position = undefined;
96 };
97 },
98
99 element : function () {
100 return this._el;
101 },
102
103 destroy : function () {
104 for (let item of this.items){
105 delete item['_menu'];
106 }
107 },
108
109 /**
110 * @returns whether an item within the container is active (by checking this.position)
111 */
112 active : function () {
113 return this.position !== undefined;
114 },
115
116 /**
117 * Getter for items
118 * @param {Integer} index [optional] Index of to select item. If left blank this.position.
119 * @returns item at location index
120 */
121 item : function (index) {
122 if (index === undefined) return this.items[this.position];
123 return this.items[index];
124 },
125
126 /**
127 * Move on to the next item in container. Returns true if we then leave the container, false otherwise.
128 */
129 next : function() {
130 if (this.position !== undefined){
131 this.item().active(false);
132 this.position++;
133 } else {
134 this.position = 0;
135 };
136 if (this.position >= this.length()) {
137 this.position=undefined;
138 return true;
139 };
140 while (!this.item().isSelectable()) {
141 this.position++;
142 if (this.position >= this.length()) {
143 this.position=undefined;
144 return true;
145 }
146 };
147 this.item().active(true);
148 return false;
149 },
150
151 /**
152 * Move on to the previous item in container. Returns true if we then leave the container, false otherwise.
153 */
154 prev : function() {
155 if (this.position !== undefined){
156 this.item().active(false);
157 this.position = (this.position-1)
158 } else {
159 this.position = (this.items.length-1);
160 }
161 if (this.position<0) {
162 this.position=undefined;
163 return true;
164 }
165 while (!this.item().isSelectable()) {
166 this.position--;
167 if (this.position<0){
168 this.position=undefined;
169 return true;
170 };
171 };
172 this.item().active(true);
173 return false;
174 },
175
176 further : function () {
177 const item = this.item();
178 if (item["further"] !== undefined) {
179 item["further"].bind(item).apply();
180 };
181 },
182
183 enter : function (event) {
184 this.item().onclick(event);
185 },
186
187 chop : function () {
188 for (let item of this.items) {
189 item.chop();
190 }
191 },
192
193 add : function (letter) {
194 for (let item of this.items) {
195 item.add(letter);
196 }
197 },
198
199 length : function () {
200 return this.items.length;
201 },
202
203 /**
204 *
205 * @returns The number of items that are selectable. Is the actual length of the list.
206 */
207 liveLength : function () {
208 var ll = 0;
209 for (let item of this.items){
210 if (item.isSelectable()){
211 ll++;
212 }
213 }
214 return ll;
215 }
216
217};
Akronb7a005a2021-09-21 17:43:02 +0200218});