Managementinterface retrieves data from database;

Table on interface is editable; replaced library.
This commit is contained in:
Danny Bessems 2019-03-04 10:43:08 +01:00
parent c8fe81d222
commit 1548cd4bb6
9 changed files with 232 additions and 109 deletions

View File

@ -10,9 +10,6 @@ $pageLayout['full'] = <<<'FULL'
<title>lucidAuth</title>
<meta name="application-name" content="lucidAuth" />
<meta name="theme-color" content="#003399" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
<link rel="manifest" href="/manifest.json" />
<link href="misc/style.css" rel="stylesheet" />
<link href="misc/style.theme.css" rel="stylesheet" />
<link href="misc/style.button.css" rel="stylesheet" />
@ -54,9 +51,11 @@ BARE;
$contentLayout['login'] = <<<'LOGIN'
<script src="misc/script.index.js"></script>
<fieldset>
<legend>Login Details</legend>
<section>
<ul>
<li class="misc">
<span class="indent">&nbsp;</span>
</li>
<li>
<label class="pre" for="username" data-translation="label_username">Gebruikersnaam:</label>
<input type="text" id="username" name="username" tabindex="100" />
@ -70,41 +69,45 @@ $contentLayout['login'] = <<<'LOGIN'
<input type="hidden" id="ref" name="ref" value="%1$s" />
<button id="btnlogin" class="bttn-simple bttn-xs bttn-primary" tabindex="300" data-translation="button_login">login</button>
</li>
<li class="misc">
<span class="indent">&nbsp;</span>
</li>
<li class="misc">
<span class="indent" data-translation="span_credentialsavailable">Inloggegevens verkrijgbaar op aanvraag!</span>
</li>
</ul>
</fieldset>
</section>
<img src="/images/tag_lock.png" style="position: absolute; top: 175px; left: 20px;" alt="Secure!" />
LOGIN;
$contentLayout['manage'] = <<<'MANAGE'
<script src="misc/script.editable.table.js"></script>
<script src="misc/script.manage.js"></script>
<span id="user"><span data-translation="span_loggedinas">Ingelogd als</span>&nbsp;%1$s&nbsp;---&nbsp;[<a id="linklanguage-en" href="#" tabindex="700">EN</a>&nbsp;<a id="linklanguage-nl" class="current" href="#" tabindex="700">NL</a>]&nbsp;[<a href="#" tabindex="800" data-translation="link_logout">Log uit</a>]</span>
<fieldset style="clear: both;">
<legend>Beheer Gebruikers</legend>
<section>
<ul>
<li>
<table id="usertable">
<thead>
<tr>
<th class="immutable">Username</th>
<th class="immutable">Role</th>
<th class="immutable">Sessions</th>
</tr>
</thead>
<tbody>
%2$s
</tbody>
</table>
</li>
<li>
<button id="btnaliasadd" class="bttn-simple bttn-xs bttn-primary" tabindex="200" data-translation="button_add">voeg toe</button>
<li class="buttons">
<button id="btnnewuser" class="bttn-simple bttn-xs bttn-primary" data-translation="button_new">nieuw</button>
<button id="btnfoo" class="bttn-simple bttn-xs bttn-primary" data-translation="button_foo">foo</button>
<button id="btnbar" class="bttn-simple bttn-xs bttn-primary" data-translation="button_bar">bar</button>
</li>
<li>
<label id="labelallaliases" class="pre" for="allaliases" data-translation="label_allaliases">Alle aliassen:</label><output id="aliasstats">[--]</output>
<select id="allaliases" size="10" multiple="multiple" tabindex="300">
</select>
</li>
<li>
<button id="btnaliasdelete" class="bttn-simple bttn-xs bttn-primary" tabindex="400" data-translation="button_delete">verwijder</button>
</li>
<li>
<button id="btnsync" class="bttn-simple bttn-xs bttn-primary" style="background-position: center;" tabindex="500" data-translation="button_sync">synchroniseer</button>
<li class="buttons">
<button id="btnsync" class="bttn-simple bttn-xs bttn-primary" data-translation="button_save">wijzigingen opslaan</button>
<button id="btncancel" class="bttn-simple bttn-xs bttn-primary" data-translation="button_cancel">annuleren</button>
</li>
</ul>
</fieldset>
</section>
MANAGE;
?>

View File

@ -1,27 +0,0 @@
<?php
// Basic example of PHP script to handle with jQuery-Tabledit plug-in.
// Note that is just an example. Should take precautions such as filtering the input data.
header('Content-Type: application/json');
$input = filter_input_array(INPUT_POST);
$mysqli = new mysqli('localhost', 'user', 'password', 'database');
if (mysqli_connect_errno()) {
echo json_encode(array('mysqli' => 'Failed to connect to MySQL: ' . mysqli_connect_error()));
exit;
}
if ($input['action'] === 'edit') {
$mysqli->query("UPDATE users SET username='" . $input['username'] . "', email='" . $input['email'] . "', avatar='" . $input['avatar'] . "' WHERE id='" . $input['id'] . "'");
} else if ($input['action'] === 'delete') {
$mysqli->query("UPDATE users SET deleted=1 WHERE id='" . $input['id'] . "'");
} else if ($input['action'] === 'restore') {
$mysqli->query("UPDATE users SET deleted=0 WHERE id='" . $input['id'] . "'");
}
mysqli_close($mysqli);
echo json_encode($input);

View File

@ -2,7 +2,7 @@
error_reporting(E_ALL ^ E_NOTICE);
include_once('../include/lucidAuth.functions.php');
if (!empty($_COOKIE['JWT'])) {
$validateTokenResult = validateToken($_COOKIE['JWT']);
}
@ -10,9 +10,32 @@
if ($validateTokenResult['status'] === "Success") {
include_once('../include/lucidAuth.template.php');
echo sprintf($pageLayout['full'],
try {
$allUsers = $pdoDB->query('
SELECT User.Username, Role.Rolename, COUNT(DISTINCT SecureToken.Value) AS Sessions
FROM User
LEFT JOIN Role
ON (User.RoleId=Role.Id)
LEFT JOIN SecureToken
ON (User.Id=SecureToken.UserId)
')->fetchAll(PDO::FETCH_ASSOC);
} catch (Exception $e) {
// Should really do some actual errorhandling here
throw new Exception($e);
}
foreach($allUsers as $row) {
$tableRows[] = sprintf('<tr><td>%1$s</td><td>%2$s</td><td class="immutable"><a href="?">%3$s</a></td></tr>',
explode('\\', $row['Username'])[1],
$row['Rolename'],
$row['Sessions']
);
}
echo sprintf($pageLayout['full'],
sprintf($contentLayout['manage'],
$validateTokenResult['name']
$validateTokenResult['name'],
implode($tableRows)
)
);
} else {

View File

@ -0,0 +1,131 @@
/*global $, window*/
$.fn.editableTableWidget = function (options) {
'use strict';
return $(this).each(function () {
var buildDefaultOptions = function () {
var opts = $.extend({}, $.fn.editableTableWidget.defaultOptions);
opts.editor = opts.editor.clone();
return opts;
},
activeOptions = $.extend(buildDefaultOptions(), options),
ARROW_LEFT = 37, ARROW_UP = 38, ARROW_RIGHT = 39, ARROW_DOWN = 40, ENTER = 13, ESC = 27, TAB = 9,
element = $(this),
editor = activeOptions.editor.css('position', 'absolute').hide().appendTo(element.parent()),
active,
showEditor = function (select) {
active = element.find('td:focus:not(".immutable")');
if (active.length) {
editor.val(active.text())
.removeClass('error')
.show()
.offset(active.offset())
.css(active.css(activeOptions.cloneProperties))
.width(active.width())
.height(active.height())
.focus();
if (select) {
editor.select();
}
}
},
setActiveText = function () {
var text = editor.val(),
evt = $.Event('change'),
originalContent;
if (active.text() === text || editor.hasClass('error')) {
return true;
}
originalContent = active.html();
active.text(text).trigger(evt, text);
if (evt.result === false) {
active.html(originalContent);
}
},
movement = function (element, keycode) {
if (keycode === ARROW_RIGHT) {
return element.next('td');
} else if (keycode === ARROW_LEFT) {
return element.prev('td');
} else if (keycode === ARROW_UP) {
return element.parent().prev().children().eq(element.index());
} else if (keycode === ARROW_DOWN) {
return element.parent().next().children().eq(element.index());
}
return [];
};
editor.blur(function () {
setActiveText();
editor.hide();
}).keydown(function (e) {
if (e.which === ENTER) {
setActiveText();
editor.hide();
active.focus();
e.preventDefault();
e.stopPropagation();
} else if (e.which === ESC) {
editor.val(active.text());
e.preventDefault();
e.stopPropagation();
editor.hide();
active.focus();
} else if (e.which === TAB) {
active.focus();
} else if (this.selectionEnd - this.selectionStart === this.value.length) {
var possibleMove = movement(active, e.which);
if (possibleMove.length > 0) {
possibleMove.focus();
e.preventDefault();
e.stopPropagation();
}
}
})
.on('input paste', function () {
var evt = $.Event('validate');
active.trigger(evt, editor.val());
if (evt.result === false) {
editor.addClass('error');
} else {
editor.removeClass('error');
}
});
element.on('click keypress dblclick', showEditor)
.css('cursor', 'pointer')
.keydown(function (e) {
var prevent = true,
possibleMove = movement($(e.target), e.which);
if (possibleMove.length > 0) {
possibleMove.focus();
} else if (e.which === ENTER) {
showEditor(false);
} else if (e.which === 17 || e.which === 91 || e.which === 93) {
showEditor(true);
prevent = false;
} else {
prevent = false;
}
if (prevent) {
e.stopPropagation();
e.preventDefault();
}
});
element.find('td').prop('tabindex', 1);
$(window).on('resize', function () {
if (editor.is(':visible')) {
editor.offset(active.offset())
.width(active.width())
.height(active.height());
}
});
});
};
$.fn.editableTableWidget.defaultOptions = {
cloneProperties: ['padding', 'padding-top', 'padding-bottom', 'padding-left', 'padding-right',
'text-align', 'font', 'font-size', 'font-family', 'font-weight',
'border', 'border-top', 'border-bottom', 'border-left', 'border-right'],
editor: $('<input id="editor">')
};

View File

@ -19,7 +19,7 @@ $(document).ready(function(){
password: $('#password').val(),
ref: $('#ref').val()
})
.done(function(data,status) {
.done(function(data,_status) {
if (data.Result === 'Success') {
$('#btnlogin').css({
'background': 'green url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAaklEQVQ4jeXOMQ5AQBBG4T2BC4i76EWich7ncAKbqCRuodTqnMNTkFgJs3ZU4tXz/Rlj/hUQv8EpMAClFk9sjUAiHVcCnoFMwhZYgPYG575Xe46aIOyMdJx7ji9GwrEzUgOFCu8DkRp/qxU2BKCUyZR6ygAAAABJRU5ErkJggg==) no-repeat center',

View File

@ -0,0 +1,13 @@
$(document).ready(function(){
// Initialize the editable-table functionality
$('#usertable').editableTableWidget();
$('#btnnewuser').click(function() {
var newUser = 'User' + String(Math.floor(Math.random() * Math.floor(9999))).padStart(4, '0');
$('#usertable tbody').append($('<tr><td>' + newUser + '</td><td>User</td><td class="immutable"><a href="?">0</a></td></tr>'));
// Call `editableTableWidget()` again to include the newly added `<tr>`
// To prevent recreating multiple new editors; reference the already existing `<input>`
$('#usertable').editableTableWidget({editor: $('#editor')});
});
});

File diff suppressed because one or more lines are too long

View File

@ -1,8 +1,8 @@
var locales = {
en: {
button_add: "add",
button_new: "new",
button_save: "save",
button_cancel: "cancel",
button_continue: "continue",
button_delete: "delete",
button_login: "login",
heading_error: "ERROR!",
@ -13,9 +13,9 @@ var locales = {
span_loggedinas: "Logged in as"
},
nl: {
button_add: "voeg toe",
button_cancel: "annuleer",
button_continue: "doorgaan",
button_new: "nieuw",
button_save: "opslaan",
button_cancel: "annuleren",
button_delete: "verwijder",
button_login: "log in",
heading_error: "FOUT!",
@ -37,11 +37,11 @@ $(document).ready(function(){
// Enable/disable (toggle) anchors
$('span#user a.current').removeClass('current');
$(this).addClass('current');
// Store current languagesetting in persistent localstorage
localStorage.setItem('language', selectedlang);
});
if (localStorage.getItem('language') !== null) {
$('[data-translation]').each(function(index) {
$(this).text(locales[localStorage.getItem('language')][$(this).data('translation')]);

View File

@ -96,64 +96,50 @@ body {
.main {
clear: both;
}
.main fieldset {
border: 0;
}
.main fieldset legend {
visibility: hidden;
}
.main fieldset label.pre {
.main section {
clear: both;
}
.main section label.pre {
display: inline-block;
width: 155px;
text-align: right;
vertical-align: top;
margin-top: 3px;
}
.main fieldset label#labelallaliases {
float: left;
}
.main fieldset output#aliasstats {
float: left;
clear: left;
width: 160px;
text-align: right;
font-size: 12px;
}
.main fieldset output#aliasstats:after {
margin-left: 7px;
content: ' ';
}
.main fieldset input {
.main section input {
border: 1px solid #003399;
padding: 2px;
width: 100px;
}
.main fieldset input[type=radio] {
.main section input[type=radio] {
border: none;
margin-top: 7px;
width: 20px;
}
.main fieldset button {
.main section button {
margin-left: 160px;
text-transform: uppercase;
}
.main fieldset select {
border: 1px solid #003399;
padding: 2px;
width: 375px;
}
.main fieldset select .new {
font-weight: bold;
}
.main fieldset select .deleted {
text-decoration: line-through;
}
.main fieldset#signup label.pre {
width: 205px;
}
.main fieldset#signup span.indent, .main fieldset#signup input.button {
margin-left: 210px;
}
.main section .buttons {
text-align: center;
}
.main section .buttons button {
margin-left: inherit;
}
.main section table {
width: 100%;
}
.main section table * {
font-size: 12px;
padding: 2px;
margin: 0;
}
.main section table tbody tr:nth-child(odd) {
background-color: rgb(215, 215, 215);
}
.main section table .immutable {
cursor: default !important;
}
.main li {
list-style: none;
padding: 5px;