2 var current_model
= {};
3 var current_language
= config
.language
;
6 return document
.getElementById(id
);
10 $(id
).style
.display
= 'block';
14 $(id
).style
.display
= 'none';
17 function build_asa_request() {
18 if (!current_model
|| !current_model
.id
) {
24 return str
.match(/[^\s,]+/g) || [];
27 function get_model_titles(titles
) {
28 return titles
.map(e
=> {
32 return ((e
.vendor
|| '') + (e
.model
|| '') + (e
.variant
|| '')).trim();
43 'profile': current_model
.id
,
44 'packages': split($('packages').value
),
45 'version': $('versions').value
48 console
.log('disable request button / show loading spinner')
50 fetch(config
.asu_url
, {
52 headers
: { 'Content-Type': 'application/json' },
53 body
: JSON
.stringify(request_data
)
56 switch (response
.status
) {
60 console
.log('image found');
67 get_model_titles(mobj
.titles
),
73 // show some spinning animation
74 console
.log('check again in 5 seconds');
75 setTimeout(_
=> { build_asa_request() }, 5000);
77 case 400: // bad request
78 case 422: // bad package
79 case 500: // build failed
81 console
.log('error (' + response
.status
+ ')');
91 function loadFile(url
, callback
) {
92 var xmlhttp
= new XMLHttpRequest();
93 xmlhttp
.onreadystatechange = function() {
94 if (xmlhttp
.readyState
== 4 && xmlhttp
.status
== 200) {
95 callback(JSON
.parse(xmlhttp
.responseText
), url
);
98 xmlhttp
.open('GET', url
, true);
102 function setupSelectList(select
, items
, onselection
) {
103 for (var i
= 0; i
< items
.length
; i
+= 1) {
104 var option
= document
.createElement('OPTION');
105 option
.innerHTML
= items
[i
];
106 select
.appendChild(option
);
109 select
.addEventListener('change', e
=> {
110 onselection(items
[select
.selectedIndex
]);
113 if (select
.selectedIndex
>= 0) {
114 onselection(items
[select
.selectedIndex
]);
118 // Change the translation of the entire document
119 function applyLanguage(language
) {
121 current_language
= language
;
124 var mapping
= translations
[current_language
];
126 for (var tr
in mapping
) {
127 Array
.from(document
.getElementsByClassName(tr
))
128 .forEach(e
=> { e
.innerText
= mapping
[tr
]; })
133 function setupAutocompleteList(input
, items
, onselection
) {
134 // the setupAutocompleteList function takes two arguments,
135 // the text field element and an array of possible autocompleted values:
136 var currentFocus
= -1;
138 // sort numbers and other characters separately
139 var collator
= new Intl
.Collator(undefined, {numeric
: true, sensitivity
: 'base'});
141 items
.sort(collator
.compare
);
143 // execute a function when someone writes in the text field:
144 input
.oninput = function(e
) {
148 var value
= this.value
;
149 // close any already open lists of autocompleted values
156 // create a DIV element that will contain the items (values):
157 var list
= document
.createElement('DIV');
158 list
.setAttribute('id', this.id
+ '-autocomplete-list');
159 list
.setAttribute('class', 'autocomplete-items');
160 // append the DIV element as a child of the autocomplete container:
161 this.parentNode
.appendChild(list
);
163 // for each item in the array...
165 for (var i
= 0; i
< items
.length
; i
+= 1) {
169 var j
= item
.toUpperCase().indexOf(value
.toUpperCase());
176 var div
= document
.createElement('DIV');
177 div
.innerHTML
= '...';
178 list
.appendChild(div
);
181 var div
= document
.createElement('DIV');
182 // make the matching letters bold:
183 div
.innerHTML
= item
.substr(0, j
)
184 + '<strong>' + item
.substr(j
, value
.length
) + '</strong>'
185 + item
.substr(j
+ value
.length
)
186 + '<input type="hidden" value="' + item
+ '">';
188 div
.addEventListener('click', function(e
) {
189 // set text field to selected value
190 input
.value
= this.getElementsByTagName('input')[0].value
;
191 // close the list of autocompleted values,
192 // (or any other open lists of autocompleted values:
195 onselection(input
.value
);
198 list
.appendChild(div
);
203 input
.onkeydown = function(e
) {
204 var x
= document
.getElementById(this.id
+ '-autocomplete-list');
205 if (x
) x
= x
.getElementsByTagName('div');
206 if (e
.keyCode
== 40) {
209 // and and make the current item more visible:
211 } else if (e
.keyCode
== 38) {
214 // and and make the current item more visible:
216 } else if (e
.keyCode
== 13) {
217 // If the ENTER key is pressed, prevent the form from being submitted,
219 if (currentFocus
> -1) {
220 // and simulate a click on the 'active' item:
221 if (x
) x
[currentFocus
].click();
226 input
.onfocus = function() {
227 onselection(input
.value
);
230 function setActive(x
) {
231 // a function to classify an item as 'active':
232 if (!x
) return false;
233 // start by removing the 'active' class on all items:
234 for (var i
= 0; i
< x
.length
; i
++) {
235 x
[i
].classList
.remove('autocomplete-active');
237 if (currentFocus
>= x
.length
) currentFocus
= 0;
238 if (currentFocus
< 0) currentFocus
= (x
.length
- 1);
239 // add class 'autocomplete-active':
240 x
[currentFocus
].classList
.add('autocomplete-active');
243 function closeAllLists(elmnt
) {
244 // close all autocomplete lists in the document,
245 // except the one passed as an argument:
246 var x
= document
.getElementsByClassName('autocomplete-items');
247 for (var i
= 0; i
< x
.length
; i
++) {
248 if (elmnt
!= x
[i
] && elmnt
!= input
) {
249 x
[i
].parentNode
.removeChild(x
[i
]);
254 // execute a function when someone clicks in the document:
255 document
.addEventListener('click', e
=> {
256 closeAllLists(e
.target
);
260 function updateImages(version
, code
, model
, url
, mobj
, is_custom
) {
261 // add download button for image
262 function addLink(type
, file
) {
263 var a
= document
.createElement('A');
264 a
.classList
.add('download-link');
266 .replace('{target}', mobj
.target
)
267 .replace('{version}', version
)
269 var span
= document
.createElement('SPAN');
270 span
.appendChild(document
.createTextNode(''));
272 a
.appendChild(document
.createTextNode(type
.toUpperCase()));
274 if (config
.showHelp
) {
275 a
.onmouseover = function() {
276 // hide all help texts
277 Array
.from(document
.getElementsByClassName('download-help'))
278 .forEach(e
=> e
.style
.display
= 'none');
279 var lc
= type
.toLowerCase();
280 if (lc
.includes('sysupgrade')) {
281 show('sysupgrade-help');
282 } else if (lc
.includes('factory') || lc
== 'trx' || lc
== 'chk') {
283 show('factory-help');
284 } else if (lc
.includes('kernel') || lc
.includes('zimage') || lc
.includes('uimage')) {
286 } else if (lc
.includes('root')) {
288 } else if (lc
.includes('sdcard')) {
290 } else if (lc
.includes('tftp')) {
298 $('download-links').appendChild(a
);
301 function switchClass(id
, from_class
, to_class
) {
302 $(id
).classList
.remove(from_class
);
303 $(id
).classList
.add(to_class
);
306 // remove all download links
307 Array
.from(document
.getElementsByClassName('download-link'))
308 .forEach(e
=> e
.remove());
310 // hide all help texts
311 Array
.from(document
.getElementsByClassName('download-help'))
312 .forEach(e
=> e
.style
.display
= 'none');
314 if (version
&& code
&& model
&& url
&& mobj
) {
315 var target
= mobj
.target
;
316 var images
= mobj
.images
;
318 // change between "version" and "custom" title
320 switchClass('images-title', 'tr-version-build', 'tr-custom-build');
321 switchClass('downloads-title', 'tr-version-downloads', 'tr-custom-downloads');
323 switchClass('images-title', 'tr-custom-build', 'tr-version-build');
324 switchClass('downloads-title', 'tr-custom-downloads', 'tr-version-downloads');
326 // update title translation
329 // fill out build info
330 $('image-model').innerText
= model
;
331 $('image-target').innerText
= target
;
332 $('image-version').innerText
= version
;
333 $('image-code').innerText
= code
;
335 images
.sort((a
, b
) => a
.name
.localeCompare(b
.name
));
337 for (var i
in images
) {
338 addLink(images
[i
].type
, images
[i
].name
);
347 setupSelectList($('versions'), Object
.keys(config
.versions
), version
=> {
348 loadFile(config
.versions
[version
], obj
=> {
349 setupAutocompleteList($('models'), Object
.keys(obj
['models']), model
=> {
350 if (model
in obj
['models']) {
352 var code
= obj
.version_code
;
353 var mobj
= obj
['models'][model
];
354 updateImages(version
, code
, model
, url
, mobj
, false);
355 current_model
= mobj
;
362 // trigger model update when selected version changes
363 $('models').onfocus();
367 if (config
.asu_url
) {
373 applyLanguage(config
.language
);