blob: 9b436ca53656b1574d09ce651fcbfcb241bc8790 [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 },
57 /**
58 * Upgrade this object to another object,
59 * while private data stays intact.
60 *
61 * @param {Object} An object with properties.
62 */
63 upgradeTo : function (props) {
64 for (let prop in props) {
65 this[prop] = props[prop];
66 };
67 return this;
68 },
69
70 addItem : function (item) {
71 var cItem = this._containerItemClass.create().upgradeTo(item);
72 cItem._menu = this._menu; //if not set then undefined, but thats OK
73 this.items.push(cItem);
74 this._el.appendChild(cItem.element());
75 return cItem;
76 },
77
78 addMenu : function (menu) {
79 this._menu = menu;
80 if (this._prefix !== undefined) {
81 this._menu._prefix = this._prefix; // better than going via classList or something
82 };
83 for (let item of this.items) {
84 item._menu=menu;
85 }
86 },
87
88 addPrefix : function (prefix) {
89 prefix.isSelectable = function () {
90 return this.isSet(); //TODO check!
91 }
92 var prefItem = this.addItem(prefix);
93 this._prefix = prefItem;
94 if (this._menu !== undefined){
95 this._menu._prefix=prefItem;
96 }
97 },
98
99 /**
100 * Exit the container unconditionally. Required so that active returns the
101 * correct result. Called when the prefix or similar resets the currently visual
102 * field.
103 */
104 exit : function () {
105 if (this.position !== undefined) {
106 this.item().active(false);
107 this.position = undefined;
108 };
109 },
110
111 element : function () {
112 return this._el;
113 },
114
115 destroy : function () {
116 for (let item of this.items){
117 delete item['_menu'];
118 }
119 },
120
121 /**
122 * @returns whether an item within the container is active (by checking this.position)
123 */
124 active : function () {
125 return this.position !== undefined;
126 },
127
128 /**
129 * Getter for items
130 * @param {Integer} index [optional] Index of to select item. If left blank this.position.
131 * @returns item at location index
132 */
133 item : function (index) {
134 if (index === undefined) return this.items[this.position];
135 return this.items[index];
136 },
137
138 /**
139 * Move on to the next item in container. Returns true if we then leave the container, false otherwise.
140 */
141 next : function() {
142 if (this.position !== undefined){
143 this.item().active(false);
144 this.position++;
145 } else {
146 this.position = 0;
147 };
148 if (this.position >= this.length()) {
149 this.position=undefined;
150 return true;
151 };
152 while (!this.item().isSelectable()) {
153 this.position++;
154 if (this.position >= this.length()) {
155 this.position=undefined;
156 return true;
157 }
158 };
159 this.item().active(true);
160 return false;
161 },
162
163 /**
164 * Move on to the previous item in container. Returns true if we then leave the container, false otherwise.
165 */
166 prev : function() {
167 if (this.position !== undefined){
168 this.item().active(false);
169 this.position = (this.position-1)
170 } else {
171 this.position = (this.items.length-1);
172 }
173 if (this.position<0) {
174 this.position=undefined;
175 return true;
176 }
177 while (!this.item().isSelectable()) {
178 this.position--;
179 if (this.position<0){
180 this.position=undefined;
181 return true;
182 };
183 };
184 this.item().active(true);
185 return false;
186 },
187
188 further : function () {
189 const item = this.item();
190 if (item["further"] !== undefined) {
191 item["further"].bind(item).apply();
192 };
193 },
194
195 enter : function (event) {
196 this.item().onclick(event);
197 },
198
199 chop : function () {
200 for (let item of this.items) {
201 item.chop();
202 }
203 },
204
205 add : function (letter) {
206 for (let item of this.items) {
207 item.add(letter);
208 }
209 },
210
211 length : function () {
212 return this.items.length;
213 },
214
215 /**
216 *
217 * @returns The number of items that are selectable. Is the actual length of the list.
218 */
219 liveLength : function () {
220 var ll = 0;
221 for (let item of this.items){
222 if (item.isSelectable()){
223 ll++;
224 }
225 }
226 return ll;
227 }
228
229};
230});