482 lines
20 KiB
HTML
482 lines
20 KiB
HTML
|
<html>
|
|||
|
|
|||
|
<link rel="stylesheet" type="text/css" href="../../lib/css/themes/jquery-ui/redmond/jquery-ui.min.css"/>
|
|||
|
<script type="text/javascript" src="../../lib/js/jquery-1.11.1.min.js"></script>
|
|||
|
<script type="text/javascript" src="../../socket.io/socket.io.js"></script>
|
|||
|
<script type="text/javascript" src="../../lib/js/jquery-ui-1.10.3.full.min.js"></script>
|
|||
|
|
|||
|
<link rel="stylesheet" type="text/css" href="../../css/adapter.css"/>
|
|||
|
<script type="text/javascript" src="../../js/translate.js"></script>
|
|||
|
<script type="text/javascript" src="../../js/adapter-settings.js"></script>
|
|||
|
|
|||
|
<style>
|
|||
|
#drop-zone {
|
|||
|
width: calc(100% - 10px);
|
|||
|
height: calc(100% - 10px);
|
|||
|
position: absolute;
|
|||
|
opacity: 0.8;
|
|||
|
top: 0;
|
|||
|
left: 0;
|
|||
|
background: #eee;
|
|||
|
-webkit-border-radius: 15px;
|
|||
|
-moz-border-radius: 15px;
|
|||
|
border-radius: 15px;
|
|||
|
z-index: 1;
|
|||
|
font-size: 32px;
|
|||
|
font-weight: bold;
|
|||
|
text-align: center;
|
|||
|
border: 5px dashed darkgray;
|
|||
|
}
|
|||
|
|
|||
|
.dropZone-error {
|
|||
|
background: #faa !important;
|
|||
|
color: #f00;
|
|||
|
}
|
|||
|
</style>
|
|||
|
<script type="text/javascript">
|
|||
|
var onChange;
|
|||
|
|
|||
|
systemDictionary = {
|
|||
|
"OwnTracks adapter settings": {
|
|||
|
"en": "OwnTracks adapter settings",
|
|||
|
"de": "OwnTracks adapter settings",
|
|||
|
"ru": "Настройки драйвера OwnTracks"
|
|||
|
},
|
|||
|
"Server settings": {"en": "Server settings", "de": "Server settings", "ru": "Настройки сервера settings"},
|
|||
|
"User:": {"en": "User:", "de": "Anwender:", "ru": "Пользователь:"},
|
|||
|
"Password:": {"en": "Password:", "de": "Kennwort:", "ru": "Пароль:"},
|
|||
|
"Password repeat:": {"en": "Password repeat:", "de": "Kennwort-Wiederholung:", "ru": "Повтор пароля:"},
|
|||
|
"Empty name not allowed!": {
|
|||
|
"en": "Empty name not allowed!",
|
|||
|
"de": "Ohne Namen ist nicht erlaubt!",
|
|||
|
"ru": "Пустое имя пользователя не разрешено!"
|
|||
|
},
|
|||
|
"Ok": {"en": "Ok", "de": "Ok", "ru": "Ok"},
|
|||
|
"IP:": {"de": "IP:", "ru": "IP:"},
|
|||
|
"Port:": {"de": "Port:", "ru": "Порт:"},
|
|||
|
"Secure(HTTPS):": {"de": "Verschlüsselung(HTTPS):", "ru": "Шифрование(HTTPS):"},
|
|||
|
"Authentication:": {"de": "Authentifikation:", "ru": "Аутентификация:"},
|
|||
|
"Listen on all IPs": {"en": "Listen on all IPs", "de": "An allen IP Adressen hören", "ru": "Открыть сокет на всех IP адресах"},
|
|||
|
"help_tip": {
|
|||
|
"en": "On save the adapter restarts with new configuration immediately",
|
|||
|
"de": "Beim Speichern von Einstellungen der Adapter wird sofort neu gestartet.",
|
|||
|
"ru": "Сразу после сохранения настроек драйвер перезапуститься с новыми значениями"
|
|||
|
},
|
|||
|
"Public certificate:": {"en": "Public certificate:", "de": "Publikzertifikat:", "ru": "'Public' сертификат:"},
|
|||
|
"Private certificate:": {"en": "Private certificate:", "de": "Privatzertifikat:", "ru": "'Private' сертификат:"},
|
|||
|
"Chained certificate:": {"en": "Chained certificate:", "de": "Kettenzertifikat:", "ru": "'Chained' сертификат:"},
|
|||
|
"Let's Encrypt settings": {
|
|||
|
"en": "Let's Encrypt settings",
|
|||
|
"de": "Einstellungen Let's Encrypt",
|
|||
|
"ru": "Настройкт Let's Encrypt"
|
|||
|
},
|
|||
|
"Use Lets Encrypt certificates:": {
|
|||
|
"en": "Use Let's Encrypt certificates:",
|
|||
|
"de": "Benutzen Let's Encrypt Zertifikate:",
|
|||
|
"ru": "Использовать сертификаты Let's Encrypt:"
|
|||
|
},
|
|||
|
"Use this instance for automatic update:": {
|
|||
|
"en": "Use this instance for automatic update:",
|
|||
|
"de": "Benutze diese Instanz für automatische Updates:",
|
|||
|
"ru": "Обновлять сертификаты в этом драйвере:"
|
|||
|
},
|
|||
|
"Port to check the domain:": {
|
|||
|
"en": "Port to check the domain:",
|
|||
|
"de": "Port um die Domain zu prüfen:",
|
|||
|
"ru": "Порт для проверки доменного имени:"
|
|||
|
},
|
|||
|
"Drop the files here": {"en": "Drop the files here", "de": "Die Datei hier platzieren", "ru": "Перетащить файлы сюда"},
|
|||
|
"Unknown file format!": {"en": "Unknown file format!", "de": "Unbekannter Dateiformat!", "ru": "Неизвестный формат файла"},
|
|||
|
"Cannot read file!": {"en": "Cannot read file!", "de": "Kann die Datei nicht lesen!", "ru": "Невозможно прочитать файл!"},
|
|||
|
"File is too big!": {"en": "File is too big!", "de": "Datei ist zu groß!", "ru": "Слишком большой файл!"}
|
|||
|
};
|
|||
|
|
|||
|
function encrypt(key, value) {
|
|||
|
var result = '';
|
|||
|
for(var i = 0; i < value.length; i++) {
|
|||
|
result += String.fromCharCode(key[i % key.length].charCodeAt(0) ^ value.charCodeAt(i));
|
|||
|
}
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
function decrypt(key, value) {
|
|||
|
var result = '';
|
|||
|
for(var i = 0; i < value.length; i++) {
|
|||
|
result += String.fromCharCode(key[i % key.length].charCodeAt(0) ^ value.charCodeAt(i));
|
|||
|
}
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
function showHideSettings() {
|
|||
|
if ($('#secure').prop('checked')) {
|
|||
|
$('#_certPublic').show();
|
|||
|
$('#_certPrivate').show();
|
|||
|
$('#_certChained').show();
|
|||
|
$('.le-settings').show();
|
|||
|
|
|||
|
if ($('#leEnabled').prop('checked')) {
|
|||
|
$('.le-sub-settings').show();
|
|||
|
if ($('#leUpdate').prop('checked')) {
|
|||
|
$('.le-sub-settings-update').show();
|
|||
|
} else {
|
|||
|
$('.le-sub-settings-update').hide();
|
|||
|
}
|
|||
|
} else {
|
|||
|
$('.le-sub-settings').hide();
|
|||
|
}
|
|||
|
} else {
|
|||
|
$('#_certPublic').hide();
|
|||
|
$('#_certPrivate').hide();
|
|||
|
$('#_certChained').hide();
|
|||
|
$('.le-settings').hide();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function fileHandler(event) {
|
|||
|
event.preventDefault();
|
|||
|
var file = event.dataTransfer ? event.dataTransfer.files[0] : event.target.files[0];
|
|||
|
|
|||
|
var $dz = $('#drop-zone');
|
|||
|
if (file.size > 1000000) {
|
|||
|
$('#drop-text').html(_('File is too big!'));
|
|||
|
$dz.addClass('dropZone-error').animate({opacity: 0}, 1000, function () {
|
|||
|
$dz.hide().removeClass('dropZone-error').css({opacity: 1});
|
|||
|
showMessage(_('File is too big!'));
|
|||
|
$('#drop-text').html(_('Drop the files here'));
|
|||
|
});
|
|||
|
return false;
|
|||
|
}
|
|||
|
$dz.show();
|
|||
|
var reader = new FileReader();
|
|||
|
reader.onload = function (evt) {
|
|||
|
var text;
|
|||
|
try {
|
|||
|
text = evt.target.result; // string has form data:;base64,TEXT==
|
|||
|
if ($('#drop-file').data('index') !== null) {
|
|||
|
resizeImage(text, function (result) {
|
|||
|
var pictures = getPictures();
|
|||
|
pictures[$('#drop-file').data('index')].base64 = result;
|
|||
|
onChange();
|
|||
|
showPictures(pictures);
|
|||
|
});
|
|||
|
} else {
|
|||
|
resizeImage(text, function (result) {
|
|||
|
addPicture(null, result);
|
|||
|
});
|
|||
|
}
|
|||
|
$dz.hide().removeClass('dropZone-error').css({opacity: 1});
|
|||
|
} catch (err) {
|
|||
|
console.error(err);
|
|||
|
$('#drop-text').html(_('Cannot read file!'));
|
|||
|
$dz.addClass('dropZone-error').animate({opacity: 0}, 1000, function () {
|
|||
|
$dz.hide().removeClass('dropZone-error').css({opacity: 1});
|
|||
|
showMessage(_('Cannot read file!'));
|
|||
|
$('#drop-text').html(_('Drop the files here'));
|
|||
|
});
|
|||
|
}
|
|||
|
};
|
|||
|
reader.readAsDataURL(file);
|
|||
|
}
|
|||
|
|
|||
|
function showPictureLine(pictures, i) {
|
|||
|
var text = '<tr>';
|
|||
|
text += '<td><input type="text" style="width: 100%" class="pictures-value" data-name="name" value="' + pictures[i].name + '" data-index="' + i +'"></td>';
|
|||
|
text += '<td>' +
|
|||
|
'<img width="64" src="' + pictures[i].base64 + '" class="pictures-value" data-name="base64" data-index="' + i +'" />' +
|
|||
|
'<button class="pictures-upload" data-index="' + i +'"></td>';
|
|||
|
text += '<td><button class="pictures-delete" data-index="' + i +'"></td>';
|
|||
|
text += '</tr>';
|
|||
|
return text;
|
|||
|
}
|
|||
|
|
|||
|
function resizeImage(srcBase64, callback) {
|
|||
|
var maxW = 64;
|
|||
|
var maxH = 64;
|
|||
|
var canvas = document.createElement('canvas');
|
|||
|
var ctx = canvas.getContext('2d');
|
|||
|
var cw = canvas.width;
|
|||
|
var ch = canvas.height;
|
|||
|
|
|||
|
var img = new Image;
|
|||
|
img.onload = function() {
|
|||
|
var iw = img.width;
|
|||
|
var ih = img.height;
|
|||
|
var scale = Math.min((maxW / iw), (maxH / ih));
|
|||
|
var iwScaled = iw*scale;
|
|||
|
var ihScaled = ih*scale;
|
|||
|
canvas.width = iwScaled;
|
|||
|
canvas.height = ihScaled;
|
|||
|
ctx.drawImage(img,0,0,iwScaled,ihScaled);
|
|||
|
callback(canvas.toDataURL());
|
|||
|
};
|
|||
|
try {
|
|||
|
img.src = srcBase64;
|
|||
|
} catch (e) {
|
|||
|
callback(srcBase64);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function showPictures(pictures) {
|
|||
|
var text = '';
|
|||
|
for (var i = 0; i < pictures.length; i++) {
|
|||
|
text += showPictureLine(pictures, i);
|
|||
|
}
|
|||
|
$('#pictures').html(text);
|
|||
|
// init inputs and buttons
|
|||
|
$('.pictures-value').change(function () {
|
|||
|
onChange();
|
|||
|
}).keyup(function () {
|
|||
|
$(this).trigger('change');
|
|||
|
});
|
|||
|
|
|||
|
$('.pictures-delete').button({
|
|||
|
icons: {
|
|||
|
primary: 'ui-icon-trash'
|
|||
|
},
|
|||
|
text: false
|
|||
|
})
|
|||
|
.css({width: 18, height: 18, float: 'right', 'margin-top': -5})
|
|||
|
.attr('title', _('Delete picture and person'))
|
|||
|
.click(function () {
|
|||
|
// todo are you sure
|
|||
|
var index = $(this).data('index');
|
|||
|
var pictures = getPictures();
|
|||
|
pictures.splice(index, 1);
|
|||
|
showPictures(pictures);
|
|||
|
});
|
|||
|
$('.pictures-upload').button({
|
|||
|
icons: {
|
|||
|
primary: 'ui-icon-arrowthickstop-1-s'
|
|||
|
},
|
|||
|
text: false
|
|||
|
})
|
|||
|
.attr('title', _('Upload picture'))
|
|||
|
.css({width: 18, height: 18, float: 'right', 'margin-top': 20})
|
|||
|
.click(function () {
|
|||
|
$('#drop-file').data('index', $(this).data('index'));
|
|||
|
$('#drop-file').trigger('click');
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
function getPictures() {
|
|||
|
var pictures = [];
|
|||
|
$('.pictures-value').each(function () {
|
|||
|
var index = $(this).data('index');
|
|||
|
var name = $(this).data('name');
|
|||
|
pictures[index] = pictures[index] || {};
|
|||
|
if ($(this).prop('tagName') === 'IMG') {
|
|||
|
pictures[index][name] = $(this).attr('src');
|
|||
|
} else {
|
|||
|
pictures[index][name] = $(this).val();
|
|||
|
}
|
|||
|
});
|
|||
|
return pictures;
|
|||
|
}
|
|||
|
|
|||
|
function addPicture(name, base64) {
|
|||
|
var pictures = getPictures();
|
|||
|
var id = 1;
|
|||
|
if (!name) {
|
|||
|
var found;
|
|||
|
do {
|
|||
|
found = false;
|
|||
|
name = _('User') + ' ' + id;
|
|||
|
for (var i = 0; i < pictures.length; i++) {
|
|||
|
if (pictures[i].name === name) {
|
|||
|
found = true;
|
|||
|
id++
|
|||
|
}
|
|||
|
}
|
|||
|
} while (found);
|
|||
|
}
|
|||
|
|
|||
|
pictures.push({name: name, base64: base64 || ''});
|
|||
|
onChange();
|
|||
|
showPictures(pictures);
|
|||
|
}
|
|||
|
|
|||
|
// the function loadSettings has to exist ...
|
|||
|
function load(settings, _onChange) {
|
|||
|
if (!settings) return;
|
|||
|
onChange = _onChange;
|
|||
|
|
|||
|
$('#tabs').tabs({
|
|||
|
activate: function (event, ui) {
|
|||
|
if (ui.newPanel.selector == '#tabs-2') {
|
|||
|
$('#drop-zone').show().css({opacity: 1}).animate({opacity: 0}, 2000, function () {
|
|||
|
$('#drop-zone').hide().css({opacity: 1});
|
|||
|
});
|
|||
|
}
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
var $dropZone = $('#adapter-container');
|
|||
|
if (typeof(window.FileReader) !== 'undefined' && !$dropZone.data('installed')) {
|
|||
|
$dropZone.data('installed', true);
|
|||
|
var $dz = $('#drop-zone');
|
|||
|
$('#drop-text').html(_('Drop the files here'));
|
|||
|
$dropZone[0].ondragover = function() {
|
|||
|
$dz.unbind('click');
|
|||
|
$dz.show();
|
|||
|
return false;
|
|||
|
};
|
|||
|
$dz.click(function () {
|
|||
|
$dz.hide();
|
|||
|
});
|
|||
|
|
|||
|
$dz[0].ondragleave = function() {
|
|||
|
$dz.hide();
|
|||
|
return false;
|
|||
|
};
|
|||
|
|
|||
|
$dz[0].ondrop = function (e) {
|
|||
|
$('#drop-file').data('index', null);
|
|||
|
fileHandler(e);
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
$('#drop-file').change(fileHandler);
|
|||
|
|
|||
|
// this functions are loaded from library
|
|||
|
getIPs(function(ips) {
|
|||
|
for (var i = 0; i < ips.length; i++) {
|
|||
|
$('#bind').append('<option value="' + ips[i].address + '">' + ips[i].name + '</option>');
|
|||
|
}
|
|||
|
$('#bind.value').val(settings.bind);
|
|||
|
});
|
|||
|
|
|||
|
$('.value').each(function () {
|
|||
|
var key = $(this).attr('id');
|
|||
|
|
|||
|
if ($('#' + key + '.value').attr('type') === 'checkbox') {
|
|||
|
$('#' + key + '.value').prop('checked', settings[key]).change(function() {
|
|||
|
_onChange();
|
|||
|
});
|
|||
|
} else {
|
|||
|
if (key === 'pass') settings[key] = decrypt('Zgfr56gFe87jJOM', settings[key]);
|
|||
|
|
|||
|
$('#' + key + '.value').val(settings[key]).change(function() {
|
|||
|
_onChange();
|
|||
|
}).keyup(function() {
|
|||
|
_onChange();
|
|||
|
});
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
settings.pictures = settings.pictures || [];
|
|||
|
|
|||
|
$('#passRepeat').val($('#pass').val());
|
|||
|
// Signal to admin, that no changes yet
|
|||
|
_onChange(false);
|
|||
|
|
|||
|
// this functions are loaded from library
|
|||
|
fillSelectCertificates('#certPublic', 'public', settings.certPublic);
|
|||
|
fillSelectCertificates('#certPrivate', 'private', settings.certPrivate);
|
|||
|
fillSelectCertificates('#certChained', 'chained', settings.certChained);
|
|||
|
fillUsers('#defaultUser', settings.defaultUser);
|
|||
|
|
|||
|
$('#secure').change(showHideSettings);
|
|||
|
|
|||
|
showPictures(settings.pictures);
|
|||
|
$('#add').button({
|
|||
|
icons: {
|
|||
|
primary: 'ui-icon-plus'
|
|||
|
},
|
|||
|
text: false
|
|||
|
})
|
|||
|
.css({width: 18, height: 18, margin: 5})
|
|||
|
.attr('title', _('Add picture for person'))
|
|||
|
.click(function () {
|
|||
|
addPicture();
|
|||
|
});
|
|||
|
|
|||
|
showHideSettings();
|
|||
|
}
|
|||
|
|
|||
|
function save(callback) {
|
|||
|
var obj = {};
|
|||
|
$('.value').each(function () {
|
|||
|
var $this = $(this);
|
|||
|
var key = $this.attr('id');
|
|||
|
if ($this.attr('type') === 'checkbox') {
|
|||
|
obj[key] = $this.prop('checked');
|
|||
|
} else {
|
|||
|
if (key === 'pass') {
|
|||
|
obj[key] = encrypt('Zgfr56gFe87jJOM', $this.val());
|
|||
|
} else {
|
|||
|
obj[key] = $this.val()
|
|||
|
}
|
|||
|
}
|
|||
|
});
|
|||
|
if (!obj.user) {
|
|||
|
showMessage(_('Empty name not allowed!'));
|
|||
|
return;
|
|||
|
}
|
|||
|
obj.pictures = getPictures();
|
|||
|
callback(obj);
|
|||
|
}
|
|||
|
</script>
|
|||
|
|
|||
|
<div id="adapter-container">
|
|||
|
|
|||
|
<table><tr>
|
|||
|
<td><img src="owntracks.png"/></td>
|
|||
|
<td><h3 class="translate">OwnTracks adapter settings</h3></td>
|
|||
|
</tr></table>
|
|||
|
<div id="tabs">
|
|||
|
<ul>
|
|||
|
<li><a href="#tabs-1" class="translate">General</a></li>
|
|||
|
<li><a href="#tabs-2" class="translate">Pictures</a></li>
|
|||
|
</ul>
|
|||
|
<div id="tabs-1">
|
|||
|
<table>
|
|||
|
<tr><td colspan="2"><h4 class="translate">Server settings</h4></td></tr>
|
|||
|
<tr><td><label class="translate" for="bind">IP:</label></td><td> <select class="value" id="bind"></select></td></tr>
|
|||
|
<tr><td><label class="translate" for="port">Port:</label></td><td> <input class="value" id="port" size="5" maxlength="5"/></td></tr>
|
|||
|
<tr><td><label class="translate" for="user">User:</label></td><td> <input class="value" id="user"/></td></tr>
|
|||
|
<tr><td><label class="translate" for="pass">Password:</label></td><td> <input class="value" id="pass" type="password"/></td></tr>
|
|||
|
<tr><td><label class="translate" for="passRepeat">Password repeat:</label></td><td><input id="passRepeat" type="password"/></td></tr>
|
|||
|
|
|||
|
<!--
|
|||
|
<tr><td><label class="translate" for="secure">Secure(HTTPS):</label></td><td> <input class="value" id="secure" type="checkbox" /></td></tr>
|
|||
|
<tr id="_certPublic">
|
|||
|
<td><label class="translate" for="certPublic">Public certificate:</label></td>
|
|||
|
<td><select id="certPublic" class="value"></select></td>
|
|||
|
</tr>
|
|||
|
<tr id="_certPrivate">
|
|||
|
<td><label class="translate" for="certPrivate">Private certificate:</label></td>
|
|||
|
<td><select id="certPrivate" class="value"></select></td>
|
|||
|
</tr>
|
|||
|
<tr id="_certChained">
|
|||
|
<td><label class="translate" for="certChained">Chained certificate:</label></td>
|
|||
|
<td><select id="certChained" class="value"></select></td>
|
|||
|
</tr>
|
|||
|
<tr><td colspan="2"> </td></tr>
|
|||
|
<tr class="le-settings"><td colspan="2"><h3 class="translate">Let's Encrypt settings</h3></tr>
|
|||
|
<tr class="le-settings"><td><label for="leEnabled" class="translate">Use Lets Encrypt certificates:</label></td><td><input class="value" id="leEnabled" type="checkbox" /></td></tr>
|
|||
|
<tr class="le-settings le-sub-settings"><td><label for="leUpdate" class="translate">Use this instance for automatic update:</label></td><td><input class="value" id="leUpdate" type="checkbox" /></td></tr>
|
|||
|
<tr class="le-settings le-sub-settings le-sub-settings-update"><td><label for="lePort" class="translate">Port to check the domain:</label></td><td><input class="value number" id="lePort" type="number" size="5" maxlength="5" /></td></tr>
|
|||
|
-->
|
|||
|
</table>
|
|||
|
</div>
|
|||
|
<div id="tabs-2">
|
|||
|
<div id="drop-zone" style="display: none"><div style="padding-top: 15%" class="translate" id="drop-text"></div>
|
|||
|
<input type="file" id="drop-file" style="display: none">
|
|||
|
</div>
|
|||
|
<button id="add"></button>
|
|||
|
<table style="width: 330px">
|
|||
|
<thead>
|
|||
|
<tr class="ui-widget-header">
|
|||
|
<td class="translate" style="width: 200px">Name</td>
|
|||
|
<td class="translate">Picture</td>
|
|||
|
<td></td>
|
|||
|
</tr>
|
|||
|
</thead>
|
|||
|
<tbody id="pictures"></tbody>
|
|||
|
</table>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
</html>
|