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>
|