var current_model = {};
-var current_language = config.language;
function $(id) {
return document.getElementById(id);
$(id).style.display = 'none';
}
+function split(str) {
+ return str.match(/[^\s,]+/g) || [];
+}
+
+function get_model_titles(titles) {
+ return titles.map(e => {
+ if (e.title) {
+ return e.title;
+ } else {
+ return ((e.vendor || '') + ' ' + (e.model || '') + ' ' + (e.variant || '')).trim();
+ }
+ }).join(' / ');
+}
+
function build_asa_request() {
if (!current_model || !current_model.id) {
alert('bad profile');
return;
}
- function split(str) {
- return str.match(/[^\s,]+/g) || [];
+ function showStatus(text) {
+ show('buildstatus');
+ $('buildstatus').innerHTML = text;
+ translate();
}
- function get_model_titles(titles) {
- return titles.map(e => {
- if (e.title) {
- return e.title;
- } else {
- return ((e.vendor || '') + (e.model || '') + (e.variant || '')).trim();
- }
- }).join('/');
+ function handleError(response) {
+ hide('buildspinner');
+
+ response.json()
+ .then(mobj => {
+ var message = mobj['message'] || '<span class="tr-build-failed"></span>';
+ if (mobj.buildlog == true) {
+ var url = config.asu_url + '/store/' + mobj.bin_dir + '/buildlog.txt';
+ showStatus('<a href="' + url + '">' + message + '</a>');
+ } else {
+ showStatus(message);
+ }
+ });
}
// hide image view
updateImages();
- show('loading');
+ show('buildspinner');
+ showStatus('<span class="tr-request-image"></span>');
var request_data = {
+ 'target': current_model.target,
'profile': current_model.id,
'packages': split($('packages').value),
'version': $('versions').value
}
- console.log('disable request button / show loading spinner')
-
fetch(config.asu_url + '/api/build', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
.then(response => {
switch (response.status) {
case 200:
- hide('loading');
+ hide('buildspinner');
+ showStatus('<span class="tr-build-successful"></span>');
- console.log('image found');
response.json()
.then(mobj => {
- console.log(mobj)
- var download_url = config.asu_url + '/store/' + mobj.bin_dir
+ var download_url = config.asu_url + '/store/' + mobj.bin_dir;
updateImages(
mobj.version_number,
- mobj.version_commit,
+ mobj.version_code,
mobj.build_at,
get_model_titles(mobj.titles),
download_url, mobj, true
});
break;
case 202:
- // show some spinning animation
- console.log('check again in 5 seconds');
+ showStatus('<span class="tr-check-again"></span>');
setTimeout(_ => { build_asa_request() }, 5000);
break;
case 400: // bad request
case 422: // bad package
case 500: // build failed
- hide('loading');
- console.log('error (' + response.status + ')');
- response.json()
- .then(mobj => {
- if (mobj.buildlog == true) {
- $('buildlog').href = config.asu_url + '/store/' + mobj.bin_dir + '/buildlog.txt';
- show('buildlog')
- }
- alert(mobj.message)
- });
+ handleError(response);
break;
}
})
-}
-
-function loadFile(url, callback) {
- var xmlhttp = new XMLHttpRequest();
- xmlhttp.onreadystatechange = function() {
- if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
- callback(JSON.parse(xmlhttp.responseText), url);
- }
- };
- xmlhttp.open('GET', url, true);
- xmlhttp.send();
+ .catch(err => {
+ hide('buildspinner');
+ showStatus(err);
+ })
}
function setupSelectList(select, items, onselection) {
}
// Change the translation of the entire document
-function applyLanguage(language) {
- if (language) {
- current_language = language;
- }
-
- var mapping = translations[current_language];
- if (mapping) {
- for (var tr in mapping) {
- Array.from(document.getElementsByClassName(tr))
+function translate() {
+ var mapping = translations[config.language];
+ for (var tr in mapping) {
+ Array.from(document.getElementsByClassName(tr))
.forEach(e => { e.innerText = mapping[tr]; })
- }
}
}
-function setupAutocompleteList(input, items, onselection) {
- // the setupAutocompleteList function takes two arguments,
- // the text field element and an array of possible autocompleted values:
+function setupAutocompleteList(input, items, as_list, onbegin, onend) {
var currentFocus = -1;
// sort numbers and other characters separately
items.sort(collator.compare);
- // execute a function when someone writes in the text field:
input.oninput = function(e) {
- // clear images
- updateImages();
+ onbegin();
+ var offset = 0;
var value = this.value;
+ var value_list = [];
+
+ if (as_list) {
+ // automcomplete last text item
+ offset = this.value.lastIndexOf(' ') + 1;
+ value = this.value.substr(offset);
+ value_list = split(this.value.substr(0, offset));
+ }
+
// close any already open lists of autocompleted values
closeAllLists();
// append the DIV element as a child of the autocomplete container:
this.parentNode.appendChild(list);
- // for each item in the array...
var c = 0;
for (var i = 0; i < items.length; i += 1) {
var item = items[i];
continue;
}
+ // do not offer a duplicate item
+ if (as_list && value_list.indexOf(item) != -1) {
+ continue;
+ }
+
c += 1;
if (c >= 15) {
var div = document.createElement('DIV');
+ '<input type="hidden" value="' + item + '">';
div.addEventListener('click', function(e) {
- // set text field to selected value
- input.value = this.getElementsByTagName('input')[0].value;
+ // include selected value
+ var selected = this.getElementsByTagName('input')[0].value;
+ if (as_list) {
+ input.value = value_list.join(' ') + ' ' + selected;
+ } else {
+ input.value = selected;
+ }
// close the list of autocompleted values,
- // (or any other open lists of autocompleted values:
closeAllLists();
- // callback
- onselection(input.value);
+ onend(input);
});
list.appendChild(div);
};
input.onfocus = function() {
- onselection(input.value);
+ onend(input);
+ }
+
+ // focus lost
+ input.onblur = function() {
+ onend(input);
}
function setActive(x) {
});
}
-function updateImages(version, code, date, model, url, mobj, is_custom) {
- hide('buildlog');
+// for attended sysupgrade
+function updatePackageList(version, target) {
+ // set available packages
+ fetch(config.versions[version] + '/' + target + '/index.json')
+ .then(response => response.json())
+ .then(all_packages => {
+ setupAutocompleteList($('packages'), all_packages, true, _ => {}, textarea => {
+ textarea.value = split(textarea.value)
+ // make list unique, ignore minus
+ .filter((value, index, self) => {
+ var i = self.indexOf(value.replace(/^\-/, ''));
+ return (i === index) || (i < 0);
+ })
+ // limit to available packages, ignore minus
+ .filter((value, index) => all_packages.indexOf(value.replace(/^\-/, '')) !== -1)
+ .join(' ');
+ });
+ });
+}
+function updateImages(version, code, date, model, url, mobj, is_custom) {
// add download button for image
function addLink(type, file) {
var a = document.createElement('A');
switchClass('downloads-title', 'tr-custom-downloads', 'tr-version-downloads');
}
// update title translation
- applyLanguage();
+ translate();
// fill out build info
$('image-model').innerText = model;
addLink(images[i].type, images[i].name);
}
+ if (config.asu_url) {
+ updatePackageList(version, target);
+ }
+
show('images');
} else {
hide('images');
}
}
-setupSelectList($('versions'), Object.keys(config.versions), version => {
- loadFile(config.versions[version], obj => {
- setupAutocompleteList($('models'), Object.keys(obj['models']), model => {
- if (model in obj['models']) {
- var url = obj.url;
- var code = obj.version_code;
- var date = obj.build_data || 'unknown';
- var mobj = obj['models'][model];
- updateImages(version, code, date, model, url, mobj, false);
- current_model = mobj;
- } else {
- updateImages();
- current_model = {};
- }
+function init() {
+ var build_date = "unknown"
+ setupSelectList($('versions'), Object.keys(config.versions), version => {
+ var url = config.versions[version];
+ if (config.asu_url) {
+ url += "/profiles.json";
+ }
+ fetch(url)
+ .then(obj => {
+ build_date = obj.headers.get('last-modified');
+ return obj.json();
+ })
+ .then(obj => {
+ // handle native openwrt json format
+ if ('profiles' in obj) {
+ obj['models'] = {}
+ for (const [key, value] of Object.entries(obj['profiles'])) {
+ obj['models'][get_model_titles(value.titles)] = value
+ obj['models'][get_model_titles(value.titles)]['id'] = key
+ }
+ }
+ return obj
+ })
+ .then(obj => {
+ setupAutocompleteList($('models'), Object.keys(obj['models']), false, updateImages, models => {
+ var model = models.value;
+ if (model in obj['models']) {
+ var url = obj.url || 'unknown';
+ var code = obj.version_code || 'unknown';
+ var mobj = obj['models'][model];
+ updateImages(version, code, build_date, model, url, mobj, false);
+ current_model = mobj;
+ } else {
+ updateImages();
+ current_model = {};
+ }
+ });
+
+ // trigger model update when selected version changes
+ $('models').onfocus();
+ });
});
- // trigger model update when selected version changes
- $('models').onfocus();
- });
-});
+ if (config.asu_url) {
+ show('custom');
+ }
-if (config.asu_url) {
- show('custom');
-}
+ // hide fields
+ updateImages();
+
+ var user_lang = (navigator.language || navigator.userLanguage).split('-')[0];
+ if (user_lang in translations) {
+ config.language = user_lang;
+ $('language-selection').value = user_lang;
+ }
-// hide fields
-updateImages();
-applyLanguage(config.language);
+ translate();
+
+ $('language-selection').onclick = function() {
+ config.language = this.children[this.selectedIndex].value;
+ translate();
+ }
+}