support link in data json file
[web/firmware-selector-openwrt-org.git] / www / 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 items.sort();
50
51 // execute a function when someone writes in the text field:
52 input.oninput = function(e) {
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 var x = document.getElementById(this.id + "-autocomplete-list");
110 if (x) x = x.getElementsByTagName("div");
111 if (e.keyCode == 40) {
112 // key down
113 currentFocus += 1;
114 // and and make the current item more visible:
115 setActive(x);
116 } else if (e.keyCode == 38) {
117 // key up
118 currentFocus -= 1;
119 // and and make the current item more visible:
120 setActive(x);
121 } else if (e.keyCode == 13) {
122 // If the ENTER key is pressed, prevent the form from being submitted,
123 e.preventDefault();
124 if (currentFocus > -1) {
125 // and simulate a click on the "active" item:
126 if (x) x[currentFocus].click();
127 }
128 }
129 };
130
131 input.onfocus = function() {
132 onselection(input.value);
133 }
134
135 function setActive(x) {
136 // a function to classify an item as "active":
137 if (!x) return false;
138 // start by removing the "active" class on all items:
139 for (var i = 0; i < x.length; i++) {
140 x[i].classList.remove("autocomplete-active");
141 }
142 if (currentFocus >= x.length) currentFocus = 0;
143 if (currentFocus < 0) currentFocus = (x.length - 1);
144 // add class "autocomplete-active":
145 x[currentFocus].classList.add("autocomplete-active");
146 }
147
148 function closeAllLists(elmnt) {
149 // close all autocomplete lists in the document,
150 // except the one passed as an argument:
151 var x = document.getElementsByClassName("autocomplete-items");
152 for (var i = 0; i < x.length; i++) {
153 if (elmnt != x[i] && elmnt != input) {
154 x[i].parentNode.removeChild(x[i]);
155 }
156 }
157 }
158
159 // execute a function when someone clicks in the document:
160 document.addEventListener("click", function (e) {
161 closeAllLists(e.target);
162 });
163 }
164
165 function $(id) {
166 return document.getElementById(id);
167 }
168
169 function extractImageType(name) {
170 var m = /-(sysupgrade|factory|rootfs|kernel|tftp)[-.]/.exec(name);
171 return m ? m[1] : 'factory';
172 }
173
174 function updateImages(dllink, model, target, release, commit, images) {
175 var types = ['sysupgrade', 'factory', 'rootfs', 'kernel', 'tftp'];
176
177 function hideLinks() {
178 types.forEach(function(type) {
179 $(type + '-image').style.display = 'none';
180 });
181 }
182
183 function hideHelps() {
184 types.forEach(function(type) {
185 $(type + '-help').style.display = 'none';
186 });
187 }
188
189 function showLink(type, path) {
190 var e = $(type + '-image');
191 e.href = path;
192 e.style.display = 'inline-flex';
193 if (config.showHelp) {
194 e.onmouseover = function() {
195 hideHelps();
196 $(type + '-help').style.display = 'block';
197 };
198 }
199 }
200
201 hideLinks();
202 hideHelps();
203
204 if (model && target && release && commit && images) {
205 // fill out build info
206 $('image-model').innerText = model;
207 $('image-target').innerText = target;
208 $('image-release').innerText = release;
209 $('image-commit').innerText = commit;
210
211 // show links to images
212 for(var i in images) {
213 var file = images[i];
214 var path = (dllink ? dllink : config.downloadLink)
215 .replace('%target', target)
216 .replace('%release', release)
217 .replace('%file', file)
218 .replace('%commit', commit);
219 var type = extractImageType(file);
220
221 if (types.includes(type)) {
222 showLink(type, path);
223 }
224 }
225
226 $('images').style.display = 'block';
227 } else {
228 $('images').style.display = 'none';
229 }
230 }
231
232 // hide fields
233 updateImages();
234 changeLanguage(config.language);
235
236 function parseData(data) {
237 var obj = JSON.parse(data);
238 var out = {};
239 for (var release in obj) {
240 var link = obj[release]['link'];
241 var commit = obj[release]['commit']
242 var entries = obj[release]['models'];
243 var models = {};
244 for (var i = 0; i < entries.length; i += 1) {
245 var entry = entries[i];
246 var name = (entry[0] + " " + entry[1] + " " + entry[2]).trim();
247 var target = entry[3];
248 var images = entry[4];
249 models[name] = {'link': link, 'name': name, 'target': target, 'commit': commit, 'images': images};
250 }
251 out[release] = models;
252 }
253 return out;
254 }
255
256 loadFile(config.data, function(data) {
257 var obj = parseData(data);
258 setupSelectList($("releases"), Object.keys(obj), function(release) {
259 setupAutocompleteList($("models"), Object.keys(obj[release]), function(model) {
260 if (model in obj[release]) {
261 var dllink = obj[release][model].link;
262 var target = obj[release][model].target;
263 var commit = obj[release][model].commit;
264 var images = obj[release][model].images;
265 updateImages(dllink, model, target, release, commit, images);
266 } else {
267 updateImages();
268 }
269 });
270
271 // trigger model update when selected release changes
272 $("models").onfocus();
273 });
274 })