mirror of
https://github.com/caiwx86/small-packages.git
synced 2026-11-03 01:23:56 +08:00
396 lines
12 KiB
HTML
396 lines
12 KiB
HTML
<div id="app_version">
|
|
<%
|
|
local map = self.map
|
|
local api = map.api
|
|
local com = self.com
|
|
-%>
|
|
|
|
<script type="text/javascript">
|
|
//<![CDATA[
|
|
var appname = '<%=api.appname%>';
|
|
var appInfoList = new Array();
|
|
var inProgressCount = 0;
|
|
var tokenStr = '<%=token%>';
|
|
var checkUpdateText = '<%:Check update%>';
|
|
var forceUpdateText = '<%:Force update%>';
|
|
var retryText = '<%:Retry%>';
|
|
var noUpdateText = '<%:It is the latest version%>';
|
|
var updateSuccessText = '<%:Update successful%>';
|
|
var clickToUpdateText = '<%:Click to update%>';
|
|
var inProgressText = '<%:Updating...%>';
|
|
var unexpectedErrorText = '<%:Unexpected error%>';
|
|
var updateInProgressNotice = '<%:Updating, are you sure to close?%>';
|
|
var downloadingText = '<%:Downloading...%>';
|
|
var decompressioningText = '<%:Unpacking...%>';
|
|
var movingText = '<%:Moving...%>';
|
|
var installingText = '<%:Installing...%>';
|
|
var installingNotice = '<%:Do not refresh or switch pages during installation.%>';
|
|
var updateFailedText = '<%:Update failed%>';
|
|
var unknownErrorText = '<%:Unknown error%>';
|
|
var componentUpdates = 0, luciUpdating = false;
|
|
|
|
function syncUpdateButtons() {
|
|
var buttons = document.querySelectorAll('#app_version input[data-update-app]');
|
|
for (var i = 0; i < buttons.length; i++) {
|
|
var btn = buttons[i];
|
|
btn.disabled = !!btn.updateDisabled || luciUpdating ||
|
|
(btn.getAttribute('data-update-app') === appname && componentUpdates > 0);
|
|
}
|
|
}
|
|
|
|
function setButtonDisabled(btn, disabled) {
|
|
btn.updateDisabled = disabled;
|
|
syncUpdateButtons();
|
|
}
|
|
|
|
//window.onload = function () {};
|
|
|
|
function addPageNotice() {
|
|
if (inProgressCount === 0) {
|
|
window.onbeforeunload = function (e) {
|
|
e.returnValue = updateInProgressNotice;
|
|
return updateInProgressNotice;
|
|
};
|
|
}
|
|
inProgressCount++;
|
|
}
|
|
|
|
function removePageNotice(app) {
|
|
if (app === appname) luciUpdating = false;
|
|
else if (app) componentUpdates--;
|
|
inProgressCount--;
|
|
syncUpdateButtons();
|
|
if (inProgressCount === 0) {
|
|
window.onbeforeunload = undefined;
|
|
}
|
|
}
|
|
|
|
function onUpdateSuccess(btn) {
|
|
if (btn) {
|
|
btn.value = updateSuccessText;
|
|
btn.placeholder = updateSuccessText;
|
|
setButtonDisabled(btn, true);
|
|
}
|
|
|
|
if (inProgressCount === 0) {
|
|
window.setTimeout(function () {
|
|
if (inProgressCount === 0 && !luciUpdating) window.location.reload();
|
|
}, 1000);
|
|
}
|
|
}
|
|
|
|
function onRequestError(btn, errorMessage, checking) {
|
|
setButtonDisabled(btn, false);
|
|
btn.value = retryText;
|
|
|
|
var app = btn.getAttribute('data-update-app');
|
|
var detailId = app === appname ? appname + '-check_btn' : '_' + app + '-check_btn';
|
|
var ckeckDetailElm = document.getElementById(detailId + '-detail');
|
|
if (app === appname && !checking && !errorMessage) errorMessage = unknownErrorText;
|
|
if (errorMessage && ckeckDetailElm) {
|
|
ckeckDetailElm.textContent = errorMessage
|
|
}
|
|
}
|
|
|
|
function onBtnClick(btn, app) {
|
|
if (appInfoList[app] === undefined) {
|
|
checkUpdate(btn, app);
|
|
} else {
|
|
doUpdate(btn, app);
|
|
}
|
|
}
|
|
|
|
function checkUpdate(btn, app) {
|
|
setButtonDisabled(btn, true);
|
|
btn.value = inProgressText;
|
|
|
|
addPageNotice();
|
|
|
|
var ckeckDetailElm = document.getElementById(btn.id + '-detail');
|
|
if (ckeckDetailElm) {
|
|
ckeckDetailElm.textContent = "";
|
|
}
|
|
XHR.get('<%=api.url("check_")%>' + app, {
|
|
token: tokenStr,
|
|
arch: ''
|
|
}, function (x, json) {
|
|
removePageNotice();
|
|
if (!json || json.code) {
|
|
appInfoList[app] = undefined;
|
|
onRequestError(btn, json && json.error, true);
|
|
} else {
|
|
appInfoList[app] = json;
|
|
if (json.has_update) {
|
|
setButtonDisabled(btn, false);
|
|
btn.value = clickToUpdateText;
|
|
btn.placeholder = clickToUpdateText;
|
|
|
|
if (ckeckDetailElm) {
|
|
var urlNode = '';
|
|
if (json.remote_version) {
|
|
urlNode = '<em style="color:red;">' + json.remote_version + '</em>';
|
|
if (json.html_url) {
|
|
urlNode = '<a href="' + json.html_url + '" target="_blank">' + urlNode + '</a>';
|
|
}
|
|
}
|
|
ckeckDetailElm.innerHTML = urlNode;
|
|
}
|
|
} else {
|
|
setButtonDisabled(btn, true);
|
|
btn.value = noUpdateText;
|
|
var forceBtn = document.getElementById('_' + app + '-force_btn');
|
|
if (forceBtn) {
|
|
forceBtn.style.display = "inline";
|
|
}
|
|
}
|
|
}
|
|
}, 300);
|
|
}
|
|
|
|
function doUpdate(btn, app) {
|
|
if (luciUpdating || (app === appname && componentUpdates > 0)) return;
|
|
if (app === appname) luciUpdating = true;
|
|
else componentUpdates++;
|
|
setButtonDisabled(btn, true);
|
|
btn.value = downloadingText;
|
|
|
|
addPageNotice();
|
|
|
|
var appUpdateUrl = '<%=api.url("update_")%>' + app;
|
|
var appInfo = appInfoList[app];
|
|
var downloadId = Date.now().toString(36) + Math.random().toString(36).substring(2, 8);
|
|
var downloadList = appInfo && appInfo.data ? [appInfo.data] : [];
|
|
if (app === appname && Array.isArray(appInfo.i18n)) downloadList = downloadList.concat(appInfo.i18n);
|
|
var totalSize = 0;
|
|
for (var i = 0; i < downloadList.length; i++) totalSize += Number(downloadList[i].size) || 0;
|
|
if (!isFinite(totalSize) || totalSize <= 0) {
|
|
totalSize = 0;
|
|
}
|
|
var downloadProgressActive = true;
|
|
var downloadProgressPending = false;
|
|
var progressTimer = null;
|
|
|
|
function stopDownloadProgress() {
|
|
downloadProgressActive = false;
|
|
if (progressTimer) {
|
|
clearInterval(progressTimer);
|
|
progressTimer = null;
|
|
}
|
|
}
|
|
|
|
function updateDownloadProgress() {
|
|
if (!downloadProgressActive || downloadProgressPending || totalSize <= 0) {
|
|
return;
|
|
}
|
|
downloadProgressPending = true;
|
|
XHR.get(appUpdateUrl, {
|
|
token: tokenStr,
|
|
task: 'progress',
|
|
id: downloadId,
|
|
total_size: totalSize
|
|
}, function (x, json) {
|
|
downloadProgressPending = false;
|
|
if (downloadProgressActive && json && !json.code && typeof json.percent === 'number') {
|
|
btn.value = downloadingText + ' ' + json.percent + '%';
|
|
}
|
|
}, 300);
|
|
}
|
|
|
|
if (totalSize > 0) {
|
|
updateDownloadProgress();
|
|
progressTimer = setInterval(updateDownloadProgress, 1000);
|
|
}
|
|
|
|
function download(part) {
|
|
var asset = downloadList[part - 1];
|
|
XHR.get(appUpdateUrl, {
|
|
token: tokenStr, url: asset.browser_download_url,
|
|
size: (app === appname && part === 1 ? totalSize : asset.size) / 1024,
|
|
id: downloadId, part: part
|
|
}, function (x, json) {
|
|
if (json && !json.code && app === appname && part < downloadList.length) {
|
|
download(part + 1);
|
|
return;
|
|
}
|
|
stopDownloadProgress();
|
|
if (!json || json.code) {
|
|
removePageNotice(app);
|
|
onRequestError(btn, json && (json.error || updateFailedText));
|
|
} else if (app === appname) {
|
|
installLuci(btn, appUpdateUrl, downloadId);
|
|
} else if (json.zip) {
|
|
btn.value = decompressioningText;
|
|
XHR.get(appUpdateUrl, {
|
|
token: tokenStr, task: 'extract', file: json.file, subfix: appInfo.type || ''
|
|
}, function (x, json) {
|
|
if (!json || json.code) {
|
|
removePageNotice(app);
|
|
onRequestError(btn, json && json.error);
|
|
} else {
|
|
move(btn, app, appUpdateUrl, json.file);
|
|
}
|
|
}, 300);
|
|
} else {
|
|
move(btn, app, appUpdateUrl, json.file);
|
|
}
|
|
}, 300);
|
|
}
|
|
download(1);
|
|
}
|
|
|
|
function move(btn, app, url, file) {
|
|
btn.value = movingText;
|
|
|
|
// Move file to target dir
|
|
XHR.get(url, {
|
|
token: tokenStr,
|
|
task: 'move',
|
|
file: file
|
|
}, function (x, json) {
|
|
removePageNotice(app);
|
|
if (!json || json.code) {
|
|
onRequestError(btn, json && json.error);
|
|
} else {
|
|
onUpdateSuccess(btn);
|
|
}
|
|
}, 300)
|
|
}
|
|
function installLuci(btn, url, id) {
|
|
btn.value = installingText;
|
|
var detail = document.getElementById(appname + '-check_btn-detail');
|
|
detail.textContent = installingNotice;
|
|
// Read the tiny result file even if rpcd restart invalidates the session.
|
|
var pending = false, finished = false;
|
|
function finishInstall(code) {
|
|
if (finished) return;
|
|
finished = true;
|
|
clearInterval(timer);
|
|
removePageNotice(appname);
|
|
if (code) onRequestError(btn, updateFailedText);
|
|
else {
|
|
window.onbeforeunload = undefined;
|
|
window.location.reload();
|
|
}
|
|
}
|
|
var timer = setInterval(function() {
|
|
if (pending) return;
|
|
pending = true;
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open('GET', '<%=resource%>/' + appname + '-update/' + id + '.json?_=' + Date.now(), true);
|
|
xhr.timeout = 5000;
|
|
xhr.onerror = xhr.ontimeout = function() { pending = false; };
|
|
xhr.onload = function() {
|
|
pending = false;
|
|
if (finished) return;
|
|
var json;
|
|
try { json = JSON.parse(xhr.responseText); } catch (e) { return; }
|
|
if (!json || typeof json.code !== 'number') return;
|
|
finishInstall(json.code);
|
|
};
|
|
xhr.send();
|
|
}, 1000);
|
|
// Legacy LuCI has no static XHR.post(), and its instance callback has no JSON argument.
|
|
var request = new XMLHttpRequest();
|
|
request.open('POST', url, true);
|
|
request.timeout = 300000;
|
|
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
|
request.onerror = request.ontimeout = function() { finishInstall(1); };
|
|
request.onload = function() {
|
|
if (finished) return;
|
|
var json;
|
|
try { json = JSON.parse(request.responseText); } catch (e) {}
|
|
if (request.status < 200 || request.status >= 300 || !json ||
|
|
typeof json.code !== 'number' || json.code) {
|
|
finishInstall(1);
|
|
}
|
|
};
|
|
request.send('token=' + encodeURIComponent(tokenStr) + '&task=install&id=' + encodeURIComponent(id) +
|
|
'&force=' + (appInfoList[appname].has_update ? '0' : '1') +
|
|
'&languages=' + encodeURIComponent(appInfoList[appname].languages || ''));
|
|
}
|
|
|
|
//]]>
|
|
</script>
|
|
|
|
<style>
|
|
#app_version > .cbi-value {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
margin-top: 0;
|
|
margin-bottom: 0;
|
|
padding-top: .25rem;
|
|
padding-bottom: .25rem;
|
|
}
|
|
#app_version > .cbi-value > .cbi-value-title {
|
|
padding-top: 0;
|
|
padding-bottom: 0;
|
|
line-height: 1.2;
|
|
}
|
|
#app_version .app-version-sub {
|
|
display: block;
|
|
font-size: .85em;
|
|
font-weight: normal;
|
|
opacity: .7;
|
|
}
|
|
</style>
|
|
|
|
<div class="cbi-value">
|
|
<label class="cbi-value-title">Passwall2 <%:Version%>
|
|
<span class="app-version-sub"><%=api.get_version()%></span>
|
|
</label>
|
|
<div class="cbi-value-field">
|
|
<div class="cbi-value-description">
|
|
<input class="btn cbi-button cbi-button-apply" type="button" id="<%=api.appname%>-check_btn" data-update-app="<%=api.appname%>"
|
|
onclick="onBtnClick(this, appname);" value="<%:Check update%>" />
|
|
<input class="btn cbi-button cbi-button-apply" type="button" id="_<%=api.appname%>-force_btn" data-update-app="<%=api.appname%>"
|
|
onclick="doUpdate(this, appname);" value="<%:Force update%>" style="display:none" />
|
|
<span id="<%=api.appname%>-check_btn-detail"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<%for _, k in ipairs(com.order) do
|
|
local v = com[k]
|
|
%>
|
|
<div class="cbi-value">
|
|
<label class="cbi-value-title"><%=v.name%>
|
|
<%:Version%>
|
|
<span class="app-version-sub"><span class="com_version" key="<%=k%>"><%=translate("Null")%></span></span>
|
|
</label>
|
|
<div class="cbi-value-field">
|
|
<div class="cbi-value-description">
|
|
<input class="btn cbi-button cbi-button-apply" type="button" id="_<%=k%>-check_btn" data-update-app="<%=k%>"
|
|
onclick="onBtnClick(this,'<%=k%>');" value="<%:Check update%>" />
|
|
<input class="btn cbi-button cbi-button-apply" type="button" id="_<%=k%>-force_btn" data-update-app="<%=k%>"
|
|
onclick="doUpdate(this,'<%=k%>');" value="<%:Force update%>" style="display:none"/>
|
|
<span id="_<%=k%>-check_btn-detail"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<%end%>
|
|
|
|
<script type="text/javascript">
|
|
//<![CDATA[
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
let coms = document.getElementsByClassName("com_version");
|
|
if (coms.length > 0) {
|
|
for (let i = 0; i < coms.length; i++) {
|
|
let key = coms[i].getAttribute("key");
|
|
coms[i].innerHTML = "<%=translate("Collecting data...")%>";
|
|
XHR.get('<%=api.url("version_")%>' + key, null, function(x, result) {
|
|
if (x && x.status == 200 && result && result.code == 1) {
|
|
let data = result.data;
|
|
let t = "<%=translate("Null")%>";
|
|
if (data && data != "")
|
|
t = data;
|
|
coms[i].innerHTML = t;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
//]]>
|
|
</script>
|
|
</div>
|