more progress
[web/firmware-selector-openwrt-org.git] / index.js
1
2 function loadFile(url, callback) {
3 var xmlhttp = new XMLHttpRequest();
4 xmlhttp.onreadystatechange = function() {
5 if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
6 callback(xmlhttp.responseText, url);
7 }
8 };
9 xmlhttp.open('GET', url, true);
10 xmlhttp.send();
11 }
12
13 function setupSelectList(select, items, onselection) {
14 for (var i = 0; i < items.length; i += 1) {
15 var option = document.createElement("OPTION");
16 option.innerHTML = items[i];
17 select.appendChild(option);
18 }
19
20 select.addEventListener("change", function(e) {
21 onselection(items[select.selectedIndex]);
22 });
23
24 if (select.selectedIndex >= 0) {
25 onselection(items[select.selectedIndex]);
26 }
27 }
28
29 // Change the translation of the entire document
30 function changeLanguage(language) {
31 var mapping = translations[language];
32 if (mapping) {
33 for (var id in mapping) {
34 var elements = document.getElementsByClassName(id);
35 for (var i in elements) {
36 if (elements.hasOwnProperty(i)) {
37 elements[i].innerHTML = mapping[id];
38 }
39 }
40 }
41 }
42 }
43
44 function setupAutocompleteList(input, items, onselection) {
45 // the setupAutocompleteList function takes two arguments,
46 // the text field element and an array of possible autocompleted values:
47 var currentFocus = -1;
48
49 // execute a function when someone writes in the text field:
50
51 input.oninput = function(e) {
52 console.log("input");
53 // clear images
54 updateImages();
55
56 var value = this.value;
57 // close any already open lists of autocompleted values
58 closeAllLists();
59 if (!value) { return false; }
60
61 // create a DIV element that will contain the items (values):
62 var list = document.createElement("DIV");
63 list.setAttribute("id", this.id + "-autocomplete-list");
64 list.setAttribute("class", "autocomplete-items");
65 // append the DIV element as a child of the autocomplete container:
66 this.parentNode.appendChild(list);
67
68 // for each item in the array...
69 var c = 0;
70 for (var i = 0; i < items.length; i += 1) {
71 var item = items[i];
72
73 // match
74 var j = item.toUpperCase().indexOf(value.toUpperCase());
75 if (j < 0) {
76 continue;
77 }
78
79 c += 1;
80 if (c >= 10) {
81 var div = document.createElement("DIV");
82 div.innerHTML = "...";
83 list.appendChild(div);
84 break;
85 } else {
86 var div = document.createElement("DIV");
87 // make the matching letters bold:
88 div.innerHTML = item.substr(0, j)
89 + "<strong>" + item.substr(j, value.length) + "</strong>"
90 + item.substr(j + value.length)
91 + "<input type='hidden' value='" + item + "'>";
92
93 div.addEventListener("click", function(e) {
94 // set text field to selected value
95 input.value = this.getElementsByTagName("input")[0].value;
96 // close the list of autocompleted values,
97 // (or any other open lists of autocompleted values:
98 closeAllLists();
99 // callback
100 onselection(input.value);
101 });
102
103 list.appendChild(div);
104 }
105 }
106 };
107
108 input.onkeydown = function(e) {
109 console.log("keydown " + e.keyCode);
110 var x = document.getElementById(this.id + "-autocomplete-list");
111 if (x) x = x.getElementsByTagName("div");
112 if (e.keyCode == 40) {
113 // key down
114 currentFocus += 1;
115 // and and make the current item more visible:
116 setActive(x);
117 } else if (e.keyCode == 38) {
118 // key up
119 currentFocus -= 1;
120 // and and make the current item more visible:
121 setActive(x);
122 } else if (e.keyCode == 13) {
123 // If the ENTER key is pressed, prevent the form from being submitted,
124 e.preventDefault();
125 if (currentFocus > -1) {
126 // and simulate a click on the "active" item:
127 if (x) x[currentFocus].click();
128 }
129 }
130 };
131
132 input.onfocus = function() {
133 onselection(input.value);
134 }
135
136 function setActive(x) {
137 // a function to classify an item as "active":
138 if (!x) return false;
139 // start by removing the "active" class on all items:
140 for (var i = 0; i < x.length; i++) {
141 x[i].classList.remove("autocomplete-active");
142 }
143 if (currentFocus >= x.length) currentFocus = 0;
144 if (currentFocus < 0) currentFocus = (x.length - 1);
145 // add class "autocomplete-active":
146 x[currentFocus].classList.add("autocomplete-active");
147 }
148
149 function closeAllLists(elmnt) {
150 // close all autocomplete lists in the document,
151 // except the one passed as an argument:
152 var x = document.getElementsByClassName("autocomplete-items");
153 for (var i = 0; i < x.length; i++) {
154 if (elmnt != x[i] && elmnt != input) {
155 x[i].parentNode.removeChild(x[i]);
156 }
157 }
158 }
159
160 // execute a function when someone clicks in the document:
161 document.addEventListener("click", function (e) {
162 closeAllLists(e.target);
163 });
164 }
165
166 function $(id) {
167 return document.getElementById(id);
168 }
169
170 function extractImageType(name) {
171 var m = /-(sysupgrade|factory|rootfs|kernel|tftp)[-.]/.exec(name);
172 return m ? m[1] : 'factory';
173 }
174
175 function updateImages(model, target, release, commit, images) {
176 if (model && target && release && commit && images) {
177 $('image-model').innerText = model;
178 $('image-target').innerText = target;
179 $('image-release').innerText = release;
180 $('image-commit').innerText = commit;
181
182 for(var i in images) {
183 var filename = images[i];
184 var path = "https://" + target + "/" + filename;
185 var type = extractImageType(filename);
186
187 if (type == "sysupgrade") {
188 $("sysupgrade-image").href = path;
189 $("sysupgrade-image").style.display = "inline-flex";
190 }
191
192 if (type == "factory") {
193 $("factory-image").href = path;
194 $("factory-image").style.display = "inline-flex";
195 }
196
197 if (type == "tftp") {
198 $("tftp-image").href = path;
199 $("tftp-image").style.display = "inline-flex";
200 }
201
202 if (type == "kernel") {
203 $("kernel-image").href = path;
204 $("kernel-image").style.display = "inline-flex";
205 }
206
207 if (type == "rootfs") {
208 $("rootfs-image").href = path;
209 $("rootfs-image").style.display = "inline-flex";
210 }
211 }
212 $("images").style.display = 'block';
213 } else {
214 $("images").style.display = 'none';
215 $("sysupgrade-image").style.display = "none";
216 $("factory-image").style.display = "none";
217 $("tftp-image").style.display = "none";
218 $("kernel-image").style.display = "none";
219 $("rootfs-image").style.display = "none";
220 }
221 }
222
223 // hide fields
224 updateImages();
225 changeLanguage(config.language);
226
227 function parseData(data) {
228 var obj = JSON.parse(data);
229 var out = {};
230 for (var release in obj) {
231 var entries = obj[release]['models'];
232 var commit = obj[release]['commit']
233 var models = {};
234 for (var i = 0; i < entries.length; i += 1) {
235 var entry = entries[i];
236 var name = (entry[0] + " " + entry[1] + " " + entry[2]).trim();
237 var target = entry[3];
238 var images = entry[4];
239 models[name] = {'name': name, 'target': target, 'commit': commit, 'images': images};
240 }
241 out[release] = models;
242 }
243 return out;
244 }
245
246 loadFile(config.data, function(data) {
247 var obj = parseData(data);
248 setupSelectList($("releases"), Object.keys(obj), function(release) {
249 console.log("release: " + release);
250 setupAutocompleteList($("models"), Object.keys(obj[release]), function(model) {
251 console.log("clicked " + model);
252 if (model in obj[release]) {
253 var target = obj[release][model].target;
254 var commit = obj[release][model].commit;
255 var images = obj[release][model].images;
256 updateImages(model, target, release, commit, images);
257 } else {
258 updateImages();
259 }
260 });
261
262 // trigger model update when selected release changes
263 $("models").onfocus();
264 });
265 })