-Feature: Ab sofort werden alle Configdateien über eine Example.config.php definiert. über das Dashboard kann nun über den neuen Punkt "Config" die eigentliche config.php bearbeitet werden. Änderungen durch Programmupdates werden jetzt automatisch in der example.config.php definiert und beim nächsten Speichern der config-datei über die Website angepasst.
-Feature: Scrollen der Listen können einzeln abeschalten werden
This commit is contained in:
@@ -1,113 +1,250 @@
|
||||
<?php
|
||||
|
||||
require('config.php');
|
||||
|
||||
require('vendor/autoload.php');
|
||||
|
||||
|
||||
|
||||
?>
|
||||
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
|
||||
<title>Aufgabenmonitor</title>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Aufgabenmonitor</title>
|
||||
|
||||
<!-- Bootstrap -->
|
||||
<link rel="stylesheet" href="vendor/twbs/bootstrap/dist/css/bootstrap.min.css" >
|
||||
<script src="scripts/jquery-3.5.1.min.js"></script>
|
||||
<link href="css/sticky-footer.css" rel="stylesheet">
|
||||
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
|
||||
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
||||
<!--[if lt IE 9]>
|
||||
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
|
||||
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
||||
<![endif]-->
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function(){
|
||||
refreshAufgabenTable();
|
||||
|
||||
});
|
||||
<!-- Bootstrap -->
|
||||
<link rel="stylesheet" href="vendor/twbs/bootstrap/dist/css/bootstrap.min.css">
|
||||
<link href="css/sticky-footer.css" rel="stylesheet">
|
||||
|
||||
function refreshAufgabenTable(){
|
||||
$('#AufgabenTableHolder').load('sources/getAufgabenTable.php', function(){
|
||||
setTimeout(refreshAufgabenTable, 30000);
|
||||
});
|
||||
}
|
||||
// function refreshCheckInTable(){
|
||||
// $('#getCheckInTableHolder').load('sources/getCheckInTable.php', function(){
|
||||
// setTimeout(refreshCheckInTable, 5000);
|
||||
// });
|
||||
// }
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body style="background-color: black;">
|
||||
<style>
|
||||
body { background-color: #000; }
|
||||
.tableFixHead { overflow:auto; }
|
||||
.tableFixHead thead th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
background-color: #212529; /* .table-dark head */
|
||||
}
|
||||
.table-dark td, .table-dark th { vertical-align: middle; }
|
||||
</style>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-lg">
|
||||
<h2 class="text-light">Aufgaben</h2>
|
||||
<table class="table table-dark">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">#</th>
|
||||
<th scope="col">Bearbeiter</th>
|
||||
<th scope="col">Aufgabe</th>
|
||||
<th scope="col">Zieldatum</th>
|
||||
<th scope="col">Priorität</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="AufgabenTableHolder">
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</header>
|
||||
<script src="scripts/jquery-3.5.1.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="container-fluid py-3">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h2 class="text-light mb-3">Aufgaben</h2>
|
||||
|
||||
<!-- SCROLL CONTAINER -->
|
||||
<div id="aufgaben-scroll" class="tableFixHead">
|
||||
<table id="aufgaben-table" class="table table-dark table-striped table-hover mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" style="width:6%">#</th>
|
||||
<th scope="col" style="width:24%">Bearbeiter</th>
|
||||
<th scope="col" style="width:40%">Aufgabe</th>
|
||||
<th scope="col" style="width:15%">Zieldatum</th>
|
||||
<th scope="col" style="width:15%">Priorität</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="AufgabenTableHolder">
|
||||
<!-- wird via AJAX gefüllt -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- /SCROLL CONTAINER -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap JS -->
|
||||
<script src="vendor/twbs/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<!-- === Scroll/Reload Script (wie bei CheckIn/CheckOut) === -->
|
||||
<script type="text/javascript">
|
||||
/* ===========================
|
||||
Feature-Toggle aus PHP
|
||||
=========================== */
|
||||
const SCROLL_FLAGS = {
|
||||
aufgaben: <?php echo (defined('EnableScrollingAufgaben') && EnableScrollingAufgaben) ? 'true' : 'false'; ?>
|
||||
};
|
||||
|
||||
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
|
||||
<script src="https://code.jquery.com/jquery-1.12.4.min.js" integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous"></script>
|
||||
<!-- Include all compiled plugins (below), or include individual files as needed -->
|
||||
<script src="vendor/twbs/bootstrap/dist/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>
|
||||
</body>
|
||||
function isEnabled() { return !!SCROLL_FLAGS.aufgaben; }
|
||||
|
||||
/* ===========================
|
||||
Höhe der Scroll-Container
|
||||
- Voller Viewport ab Oberkante
|
||||
=========================== */
|
||||
function sizeScrollContainers() {
|
||||
const node = document.querySelector('#aufgaben-scroll');
|
||||
if (!node) return;
|
||||
const rect = node.getBoundingClientRect();
|
||||
const bottomMargin = 16;
|
||||
const minH = 120;
|
||||
const available = window.innerHeight - rect.top - bottomMargin;
|
||||
node.style.maxHeight = Math.max(minH, available) + 'px';
|
||||
}
|
||||
|
||||
/* ===========================
|
||||
Scroll-/Interaktionsstatus
|
||||
=========================== */
|
||||
const scrollState = new WeakMap(); // { userActive:boolean, autoTimer:number|null, loopHeight:number }
|
||||
|
||||
function ensureState(el) {
|
||||
if (!scrollState.get(el)) scrollState.set(el, { userActive: false, autoTimer: null, loopHeight: 0 });
|
||||
return scrollState.get(el);
|
||||
}
|
||||
|
||||
function attachScrollGuards($scroller) {
|
||||
const el = $scroller.get(0);
|
||||
if (!el || el.__guardsBound) return;
|
||||
if (!isEnabled()) return;
|
||||
const state = ensureState(el);
|
||||
|
||||
const markActive = () => {
|
||||
state.userActive = true;
|
||||
clearTimeout(state._quietT);
|
||||
state._quietT = setTimeout(() => { state.userActive = false; }, 800);
|
||||
stopAutoScroll($scroller);
|
||||
};
|
||||
|
||||
$scroller.on('wheel touchstart touchmove keydown mousedown mouseenter', markActive);
|
||||
$scroller.on('mouseleave', () => setTimeout(() => maybeStartAutoScroll($scroller), 600));
|
||||
el.__guardsBound = true;
|
||||
}
|
||||
|
||||
/* ===========================
|
||||
Nahtloser Loop (Clone)
|
||||
=========================== */
|
||||
function buildSeamlessLoop($table, $scroller) {
|
||||
$table.find('tbody.__loopClone').remove();
|
||||
|
||||
const scEl = $scroller.get(0);
|
||||
const st = ensureState(scEl);
|
||||
st.loopHeight = 0;
|
||||
|
||||
if (!isEnabled()) return;
|
||||
|
||||
const $main = $table.find('tbody').first();
|
||||
if ($main.length === 0 || $main.children().length === 0) return;
|
||||
|
||||
const needScroll = $main.get(0).offsetHeight > scEl.clientHeight + 1;
|
||||
if (!needScroll) return;
|
||||
|
||||
const $clone = $main.clone(false, false).addClass('__loopClone').attr('aria-hidden', 'true');
|
||||
$table.append($clone);
|
||||
st.loopHeight = $main.get(0).offsetHeight;
|
||||
}
|
||||
|
||||
/* ===========================
|
||||
Auto-Scroll
|
||||
=========================== */
|
||||
function startAutoScroll($scroller, speedPx = 1, stepMs = 40) {
|
||||
const el = $scroller.get(0);
|
||||
if (!isEnabled()) return;
|
||||
|
||||
const st = ensureState(el);
|
||||
if (st.autoTimer) return;
|
||||
if (st.loopHeight <= 0) return;
|
||||
|
||||
const tick = () => {
|
||||
if (st.userActive) { stopAutoScroll($scroller); return; }
|
||||
el.scrollTop += speedPx;
|
||||
if (el.scrollTop >= st.loopHeight) el.scrollTop -= st.loopHeight;
|
||||
};
|
||||
|
||||
st.autoTimer = setInterval(tick, stepMs);
|
||||
}
|
||||
|
||||
function stopAutoScroll($scroller) {
|
||||
const el = $scroller.get(0);
|
||||
const st = ensureState(el);
|
||||
if (st.autoTimer) {
|
||||
clearInterval(st.autoTimer);
|
||||
st.autoTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
function maybeStartAutoScroll($scroller) {
|
||||
const el = $scroller.get(0);
|
||||
if (!isEnabled()) { stopAutoScroll($scroller); return; }
|
||||
const st = ensureState(el);
|
||||
if (st.userActive) return;
|
||||
if (st.loopHeight > 0) startAutoScroll($scroller, 1, 80);
|
||||
else stopAutoScroll($scroller);
|
||||
}
|
||||
|
||||
/* ===========================
|
||||
Smart AJAX Reload
|
||||
=========================== */
|
||||
function smartLoad($scroller, $table, $target, url, intervalMs) {
|
||||
const scEl = $scroller.get(0);
|
||||
const st = ensureState(scEl);
|
||||
|
||||
const oldLoop = st.loopHeight > 0 ? st.loopHeight : Math.max(1, scEl.scrollHeight - scEl.clientHeight);
|
||||
const posInLoop = st.loopHeight > 0 ? (scEl.scrollTop % oldLoop) : scEl.scrollTop;
|
||||
const posRatio = Math.min(1, posInLoop / oldLoop);
|
||||
|
||||
$target.load(url, function () {
|
||||
buildSeamlessLoop($table, $scroller);
|
||||
|
||||
if (st.loopHeight > 0 && isEnabled()) {
|
||||
const newPos = Math.floor(posRatio * st.loopHeight);
|
||||
if (Math.abs(scEl.scrollTop - newPos) > 1) {
|
||||
requestAnimationFrame(() => { scEl.scrollTop = newPos; });
|
||||
}
|
||||
stopAutoScroll($scroller);
|
||||
startAutoScroll($scroller, 1, 80);
|
||||
} else {
|
||||
if (scEl.scrollTop !== 0) requestAnimationFrame(() => { scEl.scrollTop = 0; });
|
||||
stopAutoScroll($scroller);
|
||||
}
|
||||
|
||||
setTimeout(() => smartLoad($scroller, $table, $target, url, intervalMs), intervalMs);
|
||||
});
|
||||
}
|
||||
|
||||
/* ===========================
|
||||
Initialisierung
|
||||
=========================== */
|
||||
$(document).ready(function () {
|
||||
sizeScrollContainers();
|
||||
$(window).on('resize', function () {
|
||||
sizeScrollContainers();
|
||||
const $scroller = $('#aufgaben-scroll');
|
||||
const $table = $('#aufgaben-table');
|
||||
buildSeamlessLoop($table, $scroller);
|
||||
maybeStartAutoScroll($scroller);
|
||||
});
|
||||
|
||||
// Guards nur aktivieren, wenn Scrolling erlaubt
|
||||
if (isEnabled()) attachScrollGuards($('#aufgaben-scroll'));
|
||||
|
||||
// Erstladen
|
||||
(function init() {
|
||||
const $scroller = $('#aufgaben-scroll');
|
||||
const $table = $('#aufgaben-table');
|
||||
const $target = $('#AufgabenTableHolder');
|
||||
const url = 'sources/getAufgabenTable.php';
|
||||
const interval = 30000;
|
||||
|
||||
$target.load(url, function () {
|
||||
buildSeamlessLoop($table, $scroller);
|
||||
maybeStartAutoScroll($scroller);
|
||||
setTimeout(() => smartLoad($scroller, $table, $target, url, interval), interval);
|
||||
});
|
||||
})();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
<?php
|
||||
|
||||
// (Optional – hier nicht benötigt, aber gelassen falls du später etwas anzeigst)
|
||||
function getTimeFromSeconds(string $timestring) {
|
||||
|
||||
$hours = floor($timestring / 3600);
|
||||
$mins = floor($timestring / 60 % 60);
|
||||
$secs = floor($timestring % 60);
|
||||
|
||||
$timeFormat = sprintf('%02d:%02d', $hours, $mins);
|
||||
|
||||
return $timeFormat;
|
||||
$hours = floor($timestring / 3600);
|
||||
$mins = floor($timestring / 60 % 60);
|
||||
$timeFormat = sprintf('%02d:%02d', $hours, $mins);
|
||||
return $timeFormat;
|
||||
}
|
||||
?>
|
||||
?>
|
||||
|
||||
Reference in New Issue
Block a user