Files
EpiWebview/Aufgabenmonitor.php

251 lines
8.5 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
require('config.php');
require('vendor/autoload.php');
?>
<!doctype html>
<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">
<link href="css/sticky-footer.css" rel="stylesheet">
<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>
<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%">Ziel</th>
<th scope="col" style="width:15%">Prio</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'; ?>
};
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 = 60000;
$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);
$timeFormat = sprintf('%02d:%02d', $hours, $mins);
return $timeFormat;
}
?>