summaryrefslogtreecommitdiff
path: root/autotable.php
diff options
context:
space:
mode:
authorNiklas Olmes <niklas@olmes.de>2026-04-24 19:30:00 +0200
committerNiklas Olmes <niklas@olmes.de>2026-04-24 19:30:00 +0200
commitcdea8caa5617f0cb77bcbc9803759abd2df50644 (patch)
tree2f7f1bd3af3b2396baf5403ad1a7ad00bcb7fae9 /autotable.php
stipcrmHEADmain
Diffstat (limited to 'autotable.php')
-rw-r--r--autotable.php1103
1 files changed, 1103 insertions, 0 deletions
diff --git a/autotable.php b/autotable.php
new file mode 100644
index 0000000..93307f7
--- /dev/null
+++ b/autotable.php
@@ -0,0 +1,1103 @@
+<?php
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+?>
+<?
+/* vim: set ts=4 sw=4 et : */
+
+require_once __DIR__ . "/auto_common.php";
+
+(function () use ($r, $id, $title, $subtitle, &$num_rows, $top, $bottom, $alwaysbottom, $off, $order, $checkboxes, $links, $rowcallback, $norefresh, $editable, $types, $entrytable, $callback, $callback_heading, $json, $jsoncallback, $pii, $nospinner, $ajax, $sql, $colsql, $makeseq, $thdef, $nochosen, $idcell, $idcellreal, $nofilter, $getthdef, $insert, $noautolinks, $nodefaultlinks) {
+ if (!isset($id) || $id == "") {
+ $pwsql = stristr($sql, ' WHERE ', true);
+ if ($pwsql === false || $pwsql === '') {
+ $pwsql = $sql;
+ }
+ $id = substr(sha1($pwsql), 0, 16);
+ }
+
+ if (!isset($order) || $order == "")
+ $order = '[[1, "desc"]]';
+
+ if (!isset($colsql) || $colsql == "")
+ $colsql = $sql . " LIMIT 1";
+
+ if (!isset($nospinner))
+ $nospinner = false;
+
+ if (!isset($ajax))
+ $ajax = false;
+
+ if (!isset($thdef))
+ $thdef = false;
+
+ if (!isset($nochosen))
+ $nochosen = false;
+
+ if (!isset($nofilter))
+ $nofilter = false;
+
+ if (!$nospinner)
+ include_once __DIR__ . '/loading_modal.php';
+
+ if (!isset($editable))
+ $editable = [];
+ if (!isset($types))
+ $types = [];
+ if (!isset($json))
+ $json = [];
+ if (!isset($off))
+ $off = false;
+ if (!isset($makeseq))
+ $makeseq = false;
+ if (!isset($alwaysbottom))
+ $alwaysbottom = false;
+
+ $pii = getPii($pii);
+
+ if (!isset($nodefaultlinks))
+ $nodefaultlinks = false;
+
+ if (!$nodefaultlinks)
+ $links = getLinks($links);
+
+ if (!isset($idcell))
+ $idcell = false;
+
+ if (!isset($idcellreal))
+ $idcellreal = $idcell;
+
+ if (isset($getthdef) && $getthdef) {
+ global $mysqli;
+ $stmt = $mysqli->prepare($sql);
+ $stmt->execute();
+ $r = $stmt->get_result();
+ }
+
+ if (!isset($noautolinks))
+ $noautolinks = false;
+
+ if (!isset($insert))
+ $insert = pathinfo(basename(__FILE__), PATHINFO_FILENAME);
+?>
+
+ <div class="autotable_containment" id="autotable_containment_<?=$id?>">
+ <div style="padding: 0; margin: 0;"></div>
+
+<?
+ if (isset($title)) {
+?>
+ <h2 id="anchor_<?=$id?>" data-table="<?=$id?>" class="prevent autotable_title" onclick="toggleTable('<?=$id?>');" style="cursor: pointer;">
+ <?=$title?>
+ <span id="<?=$id?>Count"></span>
+ <i <? if ($off) { echo 'style="display: none;"'; } ?> id="<?=$id?>Table_off" class="fas fa-toggle-on"></i>
+ <i <? if (!$off) { echo 'style="display: none;"'; } ?> id="<?=$id?>Table_on" class="fas fa-toggle-off"></i>
+ </h2>
+
+ <script>
+<? minStart(); ?>
+ function toggleTable(id, forceon) {
+ if (typeof forceon === 'undefined')
+ forceon = false;
+
+ if (forceon) {
+ $('#' + id + 'Table').show();
+ $('#' + id + 'Table_on').hide();
+ $('#' + id + 'Table_off').show();
+ } else {
+ $('#' + id + 'Table').toggle();
+ $('#' + id + 'Table_on').toggle();
+ $('#' + id + 'Table_off').toggle();
+ }
+ $('#' + id).trigger('resize');
+
+ if ($('#' + id + 'Table:visible')[0]) localStorage.setItem(location.href + '_' + id + 'Table', 'true');
+ else localStorage.setItem(location.href + '_' + id + 'Table', 'false');
+
+ setTimeout(function () {
+ $(window).resize();
+ }, 100);
+ }
+
+ $(document).ready(function () {
+<? if ($off) { ?>
+ if (localStorage.getItem(location.href + '_<?=$id?>Table') == 'true')
+ toggleTable('<?=$id?>');
+<? } else { ?>
+ if (localStorage.getItem(location.href + '_<?=$id?>Table') == 'false')
+ toggleTable('<?=$id?>');
+<? } ?>
+ });
+<? minEnd(); ?>
+ </script>
+<?
+ }
+?>
+
+ <div <? if ($off) { echo 'style="display: none;"'; } ?> id="<?=$id?>Table">
+<? if (isset($subtitle)) { ?>
+ <?=$subtitle?>
+<? } ?>
+ <span id="<?=$id?>Empty" style="display: none; padding-left: .5em;">Keine Ergebnisse!</span>
+ <div id="<?=$id?>TableInner">
+ <progress id="<?=$id?>TableProgress"></progress>
+
+<?
+ if (isset($top)) echo $top;
+
+ if ((!($ajax && $thdef)) && ($r->num_rows < 1)) {
+?>
+ <span style="padding-left: .5em;">Keine Ergebnisse!</span>
+ <script>
+<? minStart(); ?>
+ $('#<?=$id?>TableProgress').hide();
+ $('#<?=$id?>Count').html('<sup><small>(0/0)</small></sup>');
+ $('body').css('overflow', 'auto');
+ $(document).ready(function () { $('#<?=$id?>Actions').hide(); });
+<? if (!$nospinner) { ?>
+ $('#loading_modal').hide();
+<? } ?>
+<? minEnd(); ?>
+ </script>
+<?
+ if ($alwaysbottom) {
+?>
+ <?=$bottom?>
+<?
+ }
+?>
+ </div>
+ </div>
+<?
+ } else {
+ if (!$norefresh) {
+?>
+ <div class="small" id="tablereordered-<?=$id?>" style="display: none; color: darkred; margin-top: .5em; margin-bottom: .5em;">
+ <b>Spalten neu geordnet. Für die Filterfunktionen muss anschließend die <button class="small" style="background: orange;" onclick='window.location = window.location;'>Seite neu geladen werden</button></b>
+ </div>
+
+ <button class="small" id="tablereload-<?=$id?>"><i class="fas fa-sync-alt"></i> Aktualisieren</button>
+ <button class="small" id="tablereset-<?=$id?>">
+ <div class="tooltip">
+ <span class="tooltiptext">Alle Einstellungen und Filter verwerfen, anschlie&szlig;end Tabelle neuladen</span>
+ <i class="fas fa-undo-alt"></i> Reset
+ </div>
+ </button>
+ <button class="small lila" id="tableexcel-<?=$id?>">
+ <div class="tooltip"><span class="tooltiptext">Aktuelle Seite nach Excel exportieren</span><i class="fas fa-magic"></i> <i class="fas fa-eye"></i> <i class="fas fa-file-excel"></i></div>
+ </button>
+<? if ($checkboxes) { ?>
+ <button class="small lila" id="tableexcelsel-<?=$id?>">
+ <div class="tooltip"><span class="tooltiptext">Markierte nach Excel exportieren</span><i class="fas fa-magic"></i> <i class="fas fa-check"></i> <i class="fas fa-file-excel"></i></div>
+ </button>
+<? } ?>
+<?
+include __DIR__ . '/autotable_fontsettings.php';
+include __DIR__ . '/autotable_explain.php';
+?>
+
+ <div style="display: none;">
+ <form id="<?=$id?>Excel" action="/db/main/excel.php" method="post">
+ <input id="<?=$id?>ExcelName" name="name" type="hidden" value="">
+ <input id="<?=$id?>ExcelHeading" name="heading" type="hidden" value="">
+ <input id="<?=$id?>ExcelLines" name="lines" type="hidden" value="">
+ </form>
+ </div>
+
+<?
+ }
+?>
+ <style>
+ #<?=$id?>_wrapper .dataTables_scrollBody {
+ max-height: calc(100vh - 16em);
+ }
+ </style>
+
+ <table id="<?=$id?>" border="0" class="autotable display nowrap" style="width: 100%; display: none;">
+ <thead>
+ <tr>
+<?
+ if ($checkboxes || $ajax) {
+?>
+ <th></th>
+<?
+ }
+ if ($makeseq) {
+?>
+ <th>#</th>
+<?
+ }
+
+ $autotable_i = 0;
+ if (!$thdef) {
+ $l = $r->fetch_object();
+ foreach ($l as $k => $v) {
+ $bk = str_replace(' ', '<br />', $k);
+ if (substr($k, 0, 1) === '%') {
+ $k = substr($k, 1);
+ }
+
+ if ($editable[$k]) {
+?>
+ <th data-realname="<?=$editable[$k]?>" data-displayname="<?=$k?>" class="autotable_<?=$id?>_<?=$editable[$k]?> at_col_<?=$editable[$k]?> editable <? if (isset($types[$k]) && is_array($types[$k])) { ?>select no-sort<? } ?>"><?=$bk?>✎</th>
+<?
+ } else {
+?>
+ <th data-displayname="<?=$k?>" class="autotable_<?=$id?>_<?=$k?> at_col_<?=$k?> <? if (in_array($k, $editable)) { ?>editable<? } ?> <? if (isset($types[$k]) && is_array($types[$k])) { ?>select no-sort<? } ?>"><?=$bk?><? if (in_array($k, $editable)) { ?>✎<? } ?></th>
+<?
+ }
+ }
+ if ($callback) {
+?>
+ <th><?=$callback_heading?></th>
+<?
+ }
+ } else {
+ foreach ($thdef as $k) {
+ $bk = str_replace(' ', '<br />', $k);
+ if ($editable[$k]) {
+?>
+ <th data-realname="<?=$editablele[$k]?>" data-displayname="<?=$k?>" class="autotable_<?=$id?>_<?=$editable[$k]?> at_col_<?=$editable[$k]?> editable"><?=$bk?>✎</th>
+<?
+ } else {
+?>
+ <th data-displayname="<?=$k?>" class="autotable_<?=$id?>_<?=$k?> at_col_<?=$k?> <? if (in_array($k, $editable)) { ?>editable<? } ?>"><?=$bk?><? if (in_array($k, $editable)) { ?>✎<? } ?></th>
+<?
+ }
+ }
+ }
+?>
+ </tr>
+ </thead>
+
+<? if (!$ajax) { ?>
+ <script>
+ $('#<?=$id?>TableProgress').prop('max', <?=$r->num_rows?>);
+ $('#<?=$id?>TableProgress').prop('value', 0);
+ </script>
+ <tbody>
+<?
+ do {
+ $autotable_i++;
+ if (!$nospinner && $autotable_i % 100 == 0) {
+?>
+ <script>$('#progress').html('<?=$autotable_i?> Einträge von <?=$r->num_rows?> verarbeitet'); $('#<?=$id?>TableProgress').prop('value', <?=$autotable_i?>);</script>
+<?
+ }
+ if (!$nospinner && $autotable_i % 100 == 0 && $autotable_i + 350 >= $r->num_rows) {
+?>
+ <script>$('#progress').html('<?=$autotable_i?> Einträge von <?=$r->num_rows?> verarbeitet, initialisiere Tabelle'); $('#<?=$id?>TableProgress').prop('value', <?=$autotable_i?>);</script>
+<?
+ }
+ if (!$nospinner && $autotable_i == $r->num_rows) {
+?>
+ <script>$('#progress').html('Alle <?=$r->num_rows?> Einträge verarbeitet, initialisiere Tabelle'); $('#<?=$id?>TableProgress').prop('value', <?=$autotable_i?>);</script>
+<?
+ }
+ if ($nospinner) {
+?>
+ <script>$('#<?=$id?>TableProgress').prop('value', <?=$autotable_i?>);</script>
+<?
+ }
+
+ $dataid = "";
+ if ($idcell) $dataid = $l->$idcell;
+ else if (isset($l->ID)) $dataid = $l->ID;
+ else if (isset($l->uid)) $dataid = $l->uid;
+ else if (isset($l->UID)) $dataid = $l->UID;
+ else if (isset($l->id)) $dataid = $l->id;
+ else if (isset($l->PersID)) $dataid = $l->PersID;
+ else if (isset($l->StipID)) $dataid = $l->StipID;
+ else if (isset($l->EventID)) $dataid = $l->EventID;
+ else if (isset($l->FoerdID)) $dataid = $l->FoerdID;
+ else if (isset($l->OrgaID)) $dataid = $l->OrgaID;
+ else if (isset($l->NotizID)) $dataid = $l->NotizID;
+ else if (isset($l->EmailID)) $dataid = $l->EmailID;
+ else if (isset($l->AppNewsID)) $dataid = $l->AppNewsID;
+ else if (isset($l->AppSettingID)) $dataid = $l->AppSettingID;
+ else if (isset($l->AppProfileID)) $dataid = $l->AppProfileID;
+ else if (isset($l->ETID)) $dataid = $l->ETID;
+
+ if ($makeseq) $dataid = $autotable_i;
+
+ $persid = "";
+ if (isset($l->PersID)) $persid = $l->PersID;
+
+ $stipid = "";
+ if (isset($l->StipID)) $stipid = $l->StipID;
+
+ $orgaid = "";
+ if (isset($l->OrgaID)) $orgaid = $l->OrgaID;
+
+ $foerdid = "";
+ if (isset($l->FoerdID)) $foerdid = $l->FoerdID;
+
+ $eventid = "";
+ if (isset($l->EventID)) $eventid = $l->EventID;
+?>
+ <tr data-seq="<?=$autotable_i?>" data-id="<?=$dataid?>" data-persid="<?=$persid?>" data-stipid="<?=$stipid?>" data-orgaid="<?=$orgaid?>" data-foerdid="<?=$foerdid?>" data-eventid="<?=$eventid?>">
+<?
+ if ($checkboxes) {
+?>
+ <td></td>
+<?
+ }
+ if ($makeseq) {
+?>
+ <td><a href="#<?=$autotable_i?>"><?=$autotable_i?></a></td>
+<?
+ }
+
+ foreach ($l as $k => $v) {
+ if (substr($k, 0, 1) === '%') {
+ $v = utf8_encode(urldecode($v));
+ $k = substr($k, 1);
+ }
+ if (isset($links[$k])) {
+?>
+ <td class="autotable_<?=$id?>_<?=$k?>"><? if ($v != 0 || $v != '') { ?><a class="autolink" href="<?=$links[$k]?><?=$v?><? if (isset($_GET['iframe'])) { ?>?iframe<? } ?>"><?=$v?></a><? } ?></td>
+<?
+ } else {
+?>
+ <td class="autotable_<?=$id?>_<?=$k?> <? if (in_array($k, $pii)) { echo "pii"; } ?>" data-n="<? if ($editable && $editable[$k]) { echo $editable[$k]; } else { echo $k; } ?>">
+<?
+ if (in_array($k, $editable) || $editable[$k]) {
+ if (!isset($types[$k])) {
+?>
+ <input type="text" class="editable" style="width: auto; font-size: 1em; border: 0; padding: 0; margin: 0; background: rgba(255, 255, 255, 0.1);" size="<?=strlen($v)?>" value="<?=$v?>"><span style="display: none;" class="indicator"><?=$v?></span>
+<?
+ } else if ($types[$k] == 'date') {
+?>
+ <input type="date" class="editable" value="<?=$v?>"><span style="display: none;" class="indicator"><?=$v?></span>
+<?
+ } else if ($types[$k] == 'checkbox') {
+?>
+ <input type="checkbox" class="editable" <? if ($v) { echo "checked"; } ?>><span style="display: none;" class="indicator"><?=$v?></span>
+<?
+ } else if ($types[$k] == 'checkboxinverse') {
+?>
+ <input type="checkbox" class="editable inverse" <? if ($v) { echo "checked"; } ?>><span style="display: none;" class="indicator"><?=$v?></span>
+<?
+ } else if (is_array($types[$k])) {
+?>
+ <select class="editable <? if ($types[$k][0] == 'reload') { ?>reload<? } ?>">
+ <option value=""></option>
+<?
+ foreach($types[$k][1] as $a => $b) {
+?>
+ <option value="<?=$b['id']?>" <? if ($b['id'] == $v) { ?>selected<? } ?>><?=$a?><? if (isset($b['cn'])) { ?> - <?=$b['cn']?><? } ?></option>
+<?
+ }
+?>
+ </select>
+<?
+ }
+ } else if (in_array($k, $json)) {
+ $jsoncallback($k, json_decode($v));
+ } else {
+?>
+ <?=$v?>
+<?
+ }
+?>
+
+ </td>
+<?
+ }
+ }
+
+ if ($callback) {
+?>
+ <td>
+<?
+ $callback($dataid);
+?>
+ </td>
+<?
+ }
+?>
+ </tr>
+<?
+ } while (($l = $r->fetch_object()))
+?>
+ </tbody>
+<? } else { /* !$ajax */ ?>
+ <script>$('#progress').html('Initialisiere Tabelle');</script>
+<? } ?>
+
+ <tfoot>
+ <tr></tr>
+ </tfoot>
+ </table>
+
+ <script>$('#<?=$id?>TableProgress').removeProp('value');</script>
+ <script>$('#<?=$id?>TableProgress').hide();</script>
+
+<?
+ if (isset($bottom)) echo $bottom;
+?>
+
+ </div>
+ </div>
+ </div>
+
+ <script>
+<? minStart(); ?>
+ $('.prevent').on('mousedown', function (e) {
+ var doc = $(document);
+ e.preventDefault();
+ var handler = function () {
+ e.preventDefault();
+ };
+ doc.on('mousemove', handler);
+ doc.one('mouseup', function (e) {
+ doc.off('mousemove', handler);
+ });
+ });
+
+ (function () {
+<? if ($ajax) {
+ $ajaxsql = ['sql' => $sql, 'colsql' => $colsql];
+?>
+ var cDefs = [];
+<?
+ if (!$thdef) {
+?>
+ $.ajaxSetup({async:false});
+ $.ajax({
+ type: 'POST',
+ url: '/db/json/<?=$id?>?columns',
+ data: <?=json_encode($ajaxsql)?>,
+ success: function (d, s, x) {
+ try {
+ cDefs = JSON.parse(d);
+ } catch (e) {
+ alert("Interner Fehler. Kann Tabellenspaltendefinition nicht erzeugen.");
+ $('#loading_modal').hide();
+ $('body').css('border', '10px dashed red');
+ }
+ }
+ });
+ $.ajaxSetup({async:true});
+<?
+ } else {
+ $columns = [];
+ $col = new stdClass();
+ $col->data = 'ajaxident';
+ $columns[] = $col;
+
+ foreach ($thdef as $k) {
+ $col = new stdClass();
+ $col->data = $k;
+ $columns[] = $col;
+ }
+?>
+ cDefs = <?=json_encode($columns)?>;
+<?
+ }
+?>
+<? } ?>
+ var tf = $('#<?=$id?> tfoot tr');
+ $('#<?=$id?> thead th').each(function (i) {
+ var classes = "filter";
+ if ($(this).hasClass('editable')) classes += " editable";
+ if ($(this).hasClass('select')) classes += " select";
+ if ($(this).hasClass('no-sort')) classes += " no-sort";
+ tf.append('<th class="' + classes + '"></th>');
+ });
+
+ var writeChanges = function (id, n, v, num) {
+ var table = '<?=$entrytable?>';
+ var noerror = false;
+ $.ajaxSetup({async:false});
+ $.ajax({
+ type: 'POST',
+ url: '/db/main/update.php',
+ data: {
+ table: table,
+ id: id,
+ n: n,
+ v: v,
+ num: num
+ <? if ($idcellreal) { ?>, idcell: "<?=$idcellreal?>"<? } ?>
+ },
+ success: function (d, s, x) {
+ if (d == "true") noerror = true;
+ }
+ });
+ $.ajaxSetup({async:true});
+
+ if (noerror) {
+ return true;
+ } else {
+ alert(unescape('Wert\n "' + v + '"\nfür das Feld\n "' + n + '"\nin der Tabelle\n "' + table + '"\nkonnte nicht gespeichert werden.'));
+ return false;
+ }
+ };
+
+ var setupEditableChange = function () {
+ $('#<?=$id?> tbody input.editable, #<?=$id?> tbody select.editable').on('change', function () {
+ $(this).parent().addClass('changed');
+ console.debug('some change handler just fired');
+ var id = $(this).parent().parent().attr('data-id');
+ var n = $(this).parent().attr('data-n');
+ var v = $(this).val();
+ num = false;
+ if ($(this).is('input[type=checkbox]')) {
+ num = true;
+ v = $(this).prop('checked') ? 1 : 0;
+ }
+
+ if (writeChanges(id, n, v, num)) {
+ $(this).parent().removeClass('changed');
+ $(this).parent().removeClass('changesFailed');
+ $(this).parent().addClass('changesCommitted');
+ if ($(this).hasClass('reload'))
+ location.href = location.href;
+ } else {
+ $(this).parent().removeClass('changed');
+ $(this).parent().removeClass('changesCommitted');
+ $(this).parent().addClass('changesFailed');
+ }
+ });
+ };
+
+ var scramblePii = function () {
+ $('#<?=$id?> td.pii').each(function (i, e) {
+ e.innerHTML = nrot3(nshuffle(e.innerHTML));
+ });
+ };
+
+ var updateCount = function () {
+ var t = '' + dt.page.info().recordsDisplay + '';
+ t += '/' + dt.rows().count() + '';
+ // t += '/' + dt.rows(':selected').count() + '';
+ $('#<?=$id?>Count').html(' <sup><small>(' + t + ')</small></sup>');
+ if (ajaxdone && dt.rows().count() < 1) {
+ $('#<?=$id?>TableInner').hide();
+ $('#<?=$id?>Empty').show();
+ } else {
+ $('#<?=$id?>TableInner').show();
+ $('#<?=$id?>Empty').hide();
+ }
+ };
+
+ var inputTriggers = function () {
+ $('#<?=$id?> tbody td input[type=checkbox]').one('click', function () {
+ $(this).next().html($(this).prop('checked') ? 1 : 0);
+ });
+ }
+
+ var restoreState = function () {
+ var state = dt.state.loaded();
+ if (state) {
+ dt.columns().eq(0).each(function (colIdx) {
+ var colSearch = state.columns[colIdx].search;
+ var realIdx = state.ColReorder.indexOf(colIdx);
+
+ if (colSearch.search) {
+ dt.columns().footer()[realIdx].getElementsByTagName('input')[0].value = colSearch.search;
+ dt.columns().footer()[realIdx].classList.add('filteron');
+ dt.columns().header()[realIdx].classList.add('filteron');
+
+ $('tfoot th', dt.columns().footer()).eq(realIdx).find('input')
+ .val(colSearch.search)
+ .trigger('keyup')
+ .parent().addClass('filteron');
+ }
+ });
+ dt.draw();
+ }
+ }
+ window.restorestate = restoreState;
+
+ $.fn.dataTable.ext.buttons.selectFiltered = {
+ className: 'select_filtered'
+ };
+
+ $('#<?=$id?>').show();
+ var ajaxdone = false;
+ var dt = $('#<?=$id?>').DataTable({
+ "language": {
+ url: "/3rdparty/German.json",
+ processing: '<i class="fa fa-spinner fa-spin fa-3x fa-fw"></i><span class="sr-only">Lade...</span>'
+ },
+ "order": <?=$order?>,
+ "scrollX": true,
+ "colReorder": {
+ 'enable': true,
+<? if ($checkboxes) { ?>
+ 'fixedColumnsLeft': 1
+<? } ?>
+ },
+ "lengthMenu": [5, 10, 20, 50, 100, 500, 1000],
+ "stateSave": true,
+ "dom": 'Blfrtip',
+<? if ($checkboxes) { ?>
+ "buttons": ['columnsToggle', 'selectAll', { text: 'selectFiltered', extend: 'selectFiltered', action: function (e, dt) { dt.rows({filter: 'applied'}).select(); }}, 'selectNone'],
+<? } else { ?>
+ "buttons": ['columnsToggle'],
+<? } ?>
+ "processing": true,
+<? if ($ajax) {
+ ?>
+ "ajax": {
+ 'url': '/db/json/<?=$id?>',
+ 'type': 'POST',
+ 'data': <?=json_encode($ajaxsql)?>,
+ 'dataSrc': function (d) {
+ ajaxdone = true;
+ return d.data;
+ },
+ },
+ columns: cDefs,
+<? } ?>
+ "initComplete": function () {
+ console.log('init complete <?=$id?>');
+
+ this.api().columns().every(function () {
+ var column = this;
+ var idx = column.index();
+
+ var title = dt.columns().header()[idx].innerHTML.replaceAll('<br>', ' ');
+ var header = dt.columns().header()[idx];
+ if (title == "") return;
+
+ if (dt.columns().header()[idx].classList.contains('select')) return;
+
+<? if (!$nofilter) { ?>
+ var input = $('<input type="text" data-index="' + idx + '" placeholder="ᗊ ' + title + '" class="filter"><br />')
+ .appendTo($(column.footer()).empty())
+ .on('change keyup', function () {
+ $(this).next().next().val('').removeClass('filteron');
+ column.search(this.value, true).draw();
+
+ if (this.value != '') {
+ this.parentElement.classList.add('filteron');
+ header.classList.add('filteron');
+ } else {
+ this.parentElement.classList.remove('filteron');
+ header.classList.remove('filteron');
+ }
+ });
+<? } ?>
+
+ if (title.match(/ID$/)) return;
+ if (title.match(/^id$/)) return;
+ if (title.match(/^uid$/i)) return;
+
+<? if (!$nochosen) { ?>
+ var entries = column.data();
+ entriesclean = [];
+ $.each(entries, (function (i, d) {
+ if (d === "") return;
+ if ($('<div />').html(d).find('select').length > 0) {
+ entriesclean.push($('<div />').html(d).find('select option:selected').text());
+ } else {
+ entriesclean.push($('<div />').html(d).text());
+ }
+ }));
+
+ var uni = _.uniq(entriesclean).sort(function (a, b) {
+ if (a.toLowerCase() < b.toLowerCase()) return -1;
+ if (a.toLowerCase() > b.toLowerCase()) return 1;
+ return 0;
+ });
+ if (uni.length > 600) return;
+
+ var select = $('<select data-index="' + idx + '" class="filter" multiple><option value=""></option><option value="{{{}}}">[leere]</option><option value="}}}{{{">[nicht leere]</option></select>')
+ .appendTo($(column.footer()))
+ .on('change select', function () {
+ var v = $(this).val();
+ var val = "";
+ if (typeof v === 'string') {
+ if (v == '{{{}}}')
+ val = '^$';
+ else if (v == '}}}{{{')
+ val = '.+';
+ else
+ val = $.fn.dataTable.util.escapeRegex(v);
+ } else if (typeof v === 'object') {
+ $.each(v, function (i, e) {
+ console.log(e);
+ if (val != "")
+ val += '|';
+ if (e == '{{{}}}')
+ val += '^$';
+ else if (e == '}}}{{{')
+ val += '.+';
+ else
+ val += $.fn.dataTable.util.escapeRegex(e);
+ });
+ }
+
+ console.log(val);
+ if ($(this).parent().hasClass('select')) {
+ column.search(val ? val : '', true, true).draw();
+ } else {
+ column.search(val ? '^' + val + '$' : '', true, false).draw();
+ }
+
+ $(this).siblings().val('');
+ $(this).siblings().removeClass('filteron');
+ $(this).parent().removeClass('filteron');
+
+ if (this.value != '') {
+ this.classList.add('filteron');
+ header.classList.add('filteron');
+ } else {
+ this.classList.remove('filteron');
+ header.classList.remove('filteron');
+ }
+ });
+
+ $.each(uni, function (i, d) {
+ if (d == "") return;
+ var t = $('<div />').html(d).text();
+ if (t == "") return;
+ select.append('<option value="' + t + '">' + t + '</option>');
+ });
+<? } ?>
+
+<? if (true || !$ajax) { ?>
+ this.on('column-reorder', function () {
+ $('div#<?=$id?>Table table tfoot').hide();
+ $('div#tablereordered-<?=$id?>').show();
+ console.log('reordered');
+ });
+<? } ?>
+
+ });
+ console.log('after auto search setup <?=$id?>');
+
+<? if ($_SESSION['scramble']) { ?>
+ scramblePii();
+<? } ?>
+
+
+ updateCount();
+ $('body').css('overflow', 'auto');
+<? if (!$nospinner) { ?>
+ $('#loading_modal').hide();
+ $('#progress').html('');
+<? } ?>
+
+ $('#<?=$id?>_wrapper .dt-buttons').before('<div style="display: inline-block; float: left; padding-right: .5em; cursor: pointer;" id="<?=$id?>_column_toggle_on"><div class="tooltip"><span class="tooltiptext">Spaltenauswahl ein-/ausblenden</span><i class="fas fa-toggle-off"></i> <small><i class="fas fa-columns"></i></small> <span></span></div></div>');
+ $('#<?=$id?>_wrapper .dt-buttons').children().first().before('<div style="display: inline-block; float: left; padding-right: .5em; cursor: pointer;" id="<?=$id?>_column_toggle_off"><i class="fas fa-toggle-on"></i> <small><i class="fas fa-columns"></i></small> <span class="column_count"></span> [alle <span id="<?=$id?>_column_all_off"><i class="fas fa-eye-slash"></i></span> <span id="<?=$id?>_column_all_on"><i class="fas fa-eye"></i></span>]</div>');
+
+<? if ($checkboxes) { ?>
+ var btall = $('#<?=$id?>_wrapper .dt-buttons button.buttons-select-all');
+ var btnone = $('#<?=$id?>_wrapper .dt-buttons button.buttons-select-none');
+ var btfiltered = $('#<?=$id?>_wrapper .dt-buttons button.select_filtered');
+ btall.detach();
+ btnone.detach();
+ btfiltered.detach();
+ btall.html('<div class="tooltip"><span class="tooltiptext">Alle auswählen - unabhängig von Filter</span><i class="fas fa-check-double"></i></span></div>');
+ btnone.html('<div class="tooltip"><span class="tooltiptext">Nichts ausw&auml;hlen</span><i class="far fa-square"></i></span></div>');
+ btfiltered.html('<div class="tooltip"><span class="tooltiptext">Alle gefilterten ausw&auml;hlen</span><i class="fas fa-filter"></i><i class="fas fa-check"></i></span></div>');
+
+ btall.removeClass().addClass('medium');
+ btnone.removeClass().addClass('medium');
+ btfiltered.removeClass().addClass('medium');
+ btnone.insertAfter('#<?=$id?>_wrapper');
+ btall.insertAfter('#<?=$id?>_wrapper');
+ btall.after('&nbsp;');
+ btfiltered.insertAfter('#<?=$id?>_wrapper');
+ btfiltered.after('&nbsp;');
+<? } ?>
+
+ $('#<?=$id?>_column_toggle_on').on('click', function () {
+ $('#<?=$id?>_wrapper .dt-buttons').show();
+ $('#<?=$id?>_column_toggle_on').hide();
+ localStorage.setItem('table_<?=$id?>_column_toggles_on', 'true');
+ });
+ $('#<?=$id?>_column_toggle_off').on('click', function () {
+ $('#<?=$id?>_wrapper .dt-buttons').hide();
+ $('#<?=$id?>_column_toggle_on').show();
+ localStorage.setItem('table_<?=$id?>_column_toggles_on', 'false');
+ });
+
+ $('#<?=$id?>_column_all_off').on('click', function (ev) {
+ $('#<?=$id?>Table .dt-buttons button.active').click();
+ setTimeout(function () {
+ $('#<?=$id?>_wrapper .dt-buttons').show();
+ $('#<?=$id?>_column_toggle_on').hide();
+ }, 10);
+ });
+
+ $('#<?=$id?>_column_all_on').on('click', function () {
+ $('#<?=$id?>Table .dt-buttons button').not('.active').click();
+ setTimeout(function () {
+ $('#<?=$id?>_wrapper .dt-buttons').show();
+ $('#<?=$id?>_column_toggle_on').hide();
+ }, 10);
+ });
+
+ if (localStorage.getItem('table_<?=$id?>_column_toggles_on') == 'true') {
+ $('#<?=$id?>_wrapper .dt-buttons').show();
+ $('#<?=$id?>_column_toggle_on').hide();
+ } else {
+ $('#<?=$id?>_wrapper .dt-buttons').hide();
+ $('#<?=$id?>_column_toggle_on').show();
+ }
+
+ var updCount = function () {
+ var t = $('#<?=$id?>_wrapper .dt-buttons').children('.dt-button.buttons-columnVisibility').length;
+ var a = $('#<?=$id?>_wrapper .dt-buttons').children('.dt-button.buttons-columnVisibility.active').length;
+ $('#<?=$id?>_column_toggle_on span.column_count, #<?=$id?>_column_toggle_off span.column_count').html('(' + a + '/' + t + ')');
+ if (a != t) $('#<?=$id?>_column_toggle_on span.column_count, #<?=$id?>_column_toggle_off span.column_count').css('color', 'orange');
+ else $('#<?=$id?>_column_toggle_on span.column_count, #<?=$id?>_column_toggle_off span.column_count').css('color', '');
+ };
+ updCount();
+ $('#<?=$id?>_wrapper .dt-buttons .dt-button').on('click', function () {
+ setTimeout(updCount, 200);
+ });
+
+ $(window).trigger('resize');
+
+<? if (!$nochosen) { ?>
+ $('#<?=$id?>Table .dataTables_scrollFoot select').chosen({allow_single_deselect:true});
+ $('#<?=$id?>Table .dataTables_scrollFoot div.chosen-container').click(function () {
+ $(this).find('.chosen-drop').css('left', $(this).position().left + 12);
+ var h = $(this).find('.chosen-drop').height();
+ $(this).find('.chosen-drop').css('top', Math.abs($(document).scrollTop() - $(this).offset().top + h));
+ //console.log($(this).offset().top + ' ' + $(document).scrollTop() + ' ' + $(this).position().top);
+ });
+<? } ?>
+
+ restoreState();
+ }
+
+ <? if ($checkboxes) { ?>,
+ /* fixedColumns: {
+ leftColumns: 1,
+ rightColumns: 0
+ }, */
+ columnDefs: [ {
+ orderable: false,
+ searchable: false,
+ className: 'select-checkbox',
+ targets: 0
+ }, { targets: 'no-sort', searchable: false, orderable: false }
+ <? if ($ajax) { ?>,
+ {
+ render: function (data, type, row, meta) {
+ var s = '<span style="display: none;" class="ajaxident" data-id="' + data['dataid'] + '"';
+
+ if (data['persid']) s += ' data-persid="' + data['persid'] + '"';
+ if (data['stipid']) s += ' data-stipid="' + data['stipid'] + '"';
+ if (data['orgaid']) s += ' data-orgaid="' + data['orgaid'] + '"';
+ if (data['foerdid']) s += ' data-foerdid="' + data['foerdid'] + '"';
+ if (data['eventid']) s += ' data-eventid="' + data['eventid'] + '"';
+
+ s += '>' + JSON.stringify(data) + '</span>';
+ return s;
+ }, targets: 0
+ },
+ /* -------------- */
+ <?=ajaxLinks();?>
+ /* -------------- */
+ <? } ?>
+ ],
+ select: {
+ style: 'os',
+ selector: 'td:first-child'
+ }
+ <? } else { ?>
+ <? if ($ajax) { ?>,
+ columnDefs: [ {
+ visible: false,
+ searchable: 'false',
+ targets: 0
+ },
+ /* -------------- */
+ <?=ajaxLinks();?>
+ /* -------------- */
+ ]
+ <? } ?>
+ <? } ?>,
+ rowCallback: function (a, b, c, d, e, f, g, h, i, j) {
+ updateCount();
+ //inputTriggers();
+ <? if ($rowcallback) { ?>
+ <?=$rowcallback?>(a, b, c, d, e, f, g, h, i, j);
+ <? } ?>
+ <? if ($_SESSION['scramble']) { ?>
+ scramblePii();
+ <? } ?>
+ <? if ($ajax) { ?>
+ <? } ?>
+ }
+ });
+ if (typeof window.autotables === 'undefined')
+ window.autotables = [];
+ window.autotables['<?=$id?>'] = dt;
+
+
+ $('.autotable th').each(function (i) {
+ if ($(this).text().includes("AnfrageWF")) $(this).attr('title', 'Anfrage (Weiter-)-finazierung');
+ if ($(this).text().includes("apstip")) $(this).attr('title', 'Ansprechpartner beim Förderer für die Stipendiaten');
+ if ($(this).text().includes("apsf")) $(this).attr('title', 'Ansprechpartner beim Förderer für den Studienfonds OWL');
+ if ($(this).text().includes("apop")) $(this).attr('title', 'Ansprechpartner operativ');
+ if ($(this).text().includes("apstr")) $(this).attr('title', 'Ansprechpartner strategisch');
+ if ($(this).text().includes("apfi")) $(this).attr('title', 'Ansprechpartner beim Förderer für Finanzen');
+
+ if ($(this).text().includes("elsv")) $(this).attr('title', 'Einladung Stipendienvergabe');
+ if ($(this).text().includes("elfa")) $(this).attr('title', 'Einladung Fördereraustausch');
+ if ($(this).text().includes("elsft")) $(this).attr('title', 'Einladung SFT');
+ if ($(this).text().includes("elosv")) $(this).attr('title', 'Einladung Online-Stipendienvergabe');
+
+ if ($(this).text().includes("ernl")) $(this).attr('title', 'Erhalten Newsletter');
+ if ($(this).text().includes("erwk")) $(this).attr('title', 'Erhalten Weihnachtskarte');
+ if ($(this).text().includes("erjb")) $(this).attr('title', 'Erhalten Jahresbericht');
+ if ($(this).text().includes("erwm")) $(this).attr('title', 'Erhalten Willkommensmail Förderjahresbeginn');
+
+ });
+
+ $('#tablereset-<?=$id?>').click(function () {
+ localStorage.removeItem('table_<?=$id?>_column_toggles_on');
+ dt.state.clear();
+ window.location.reload();
+ });
+ $('#tablereload-<?=$id?>').click(function () {
+<? if (!$ajax) { ?>
+ window.location.reload();
+<? } else { ?>
+ window.ajaxSpSec = setTimeout(function () { $('#ajaxspinner').show(); }, 800);
+ dt.ajax.reload();
+ $(this).fadeToggle().fadeToggle();
+<? } ?>
+ });
+
+ var tableexcel = function (sel) {
+ if (typeof sel === 'undefined')
+ sel = false;
+
+ var heading = [];
+ $('#<?=$id?> thead tr').first().find('th').not('.select-checkbox').each(function (i, e) {
+ //heading.push(e.textContent.trim());
+ heading.push(e.getAttribute('data-displayname'));
+ });
+
+ var lines = [];
+ var selector = '#<?=$id?> tbody tr';
+ if (sel) {
+ selector = $.grep(autotables['<?=$id?>'].table().rows().nodes(), function (e) {
+ return e.classList.contains('selected');
+ });
+ }
+ $(selector).each(function (i, e) {
+ var line = [];
+ $(this).find('td').not('.select-checkbox').each(function (ii, ee) {
+ if (ee.getElementsByTagName('select')[0]) {
+ var sel = ee.getElementsByTagName('select')[0];
+ line.push(sel.options[sel.selectedIndex].innerText.trim());
+ } else {
+ line.push(ee.textContent.trim());
+ }
+ });
+ lines.push(line);
+ });
+
+ $('#<?=$id?>ExcelName').val("<?=$id?>");
+ $('#<?=$id?>ExcelHeading').val(JSON.stringify(heading));
+ $('#<?=$id?>ExcelLines').val(JSON.stringify(lines));
+ $('#<?=$id?>Excel').submit();
+ };
+
+<? if ($checkboxes) { ?>
+ $('#tableexcelsel-<?=$id?>').click(function () {
+ tableexcel(true);
+ });
+<? } ?>
+
+ $('#tableexcel-<?=$id?>').click(function () {
+ tableexcel(false);
+ });
+
+ $('#<?=$id?>').on('draw.dt', setupEditableChange);
+ setInterval(updateCount, 2000);
+
+ $('#<?=$id?> tbody').on('mouseenter', 'td', function () {
+ var cidx = dt.cell(this).index().column;
+ var ridx = dt.cell(this).index().row;
+
+ console.log(cidx);
+ console.log(ridx);
+
+ $(dt.cells().nodes()).removeClass('highlight');
+ $(dt.rows().nodes()).removeClass('highlight');
+
+ $(dt.column(cidx).nodes()).addClass('highlight');
+ $(dt.row(ridx).nodes()).addClass('highlight');
+ });
+ $('#<?=$id?> tbody').on('mouseleave', function () {
+ $(dt.cells().nodes()).removeClass('highlight');
+ $(dt.rows().nodes()).removeClass('highlight');
+ });
+ /* XXX:
+ * $('.dataTables_scrollBody').offset() .left .top
+ * $('.dataTables_scrollBody').scrollLeft(20); .scrollTop;
+ */
+
+ var setupAutolinks = function () {
+<?
+(function () use ($id, $noautolinks) {
+ if ($noautolinks) return;
+ $sel_id = $id;
+ include __DIR__ . "/auto_windowing.php";
+})();
+?>
+ };
+ $('#<?=$id?>').on('draw.dt', setupAutolinks);
+
+ })();
+
+ function getIDs_<?=$id?>() {
+ var ids = [];
+ var g = $.grep(autotables['<?=$id?>'].table().rows().nodes(), function (e) {
+ return e.classList.contains('selected');
+ });
+ $.each(g, function (i, e) {
+ var ee = false;
+ try { ee = e.getElementsByClassName('ajaxident')[0].getAttribute('data-id'); } catch (e) { e; }
+ if (ee) ids.push(ee);
+ else ids.push(e.getAttribute('data-id'));
+ });
+ return ids;
+ }
+
+ if ($('#insert_<?=$insert?>')) {
+ $('#insert_<?=$insert?>').replaceWith($('#autotable_containment_<?=$id?>'));
+ }
+
+ if (window.location !== window.parent.location) {
+ $('body').css('margin', '0');
+ var s = document.createElement('style');
+ s.type = "text/css";
+ s.innerHTML += '.dataTables_scrollBody { max-height: calc(100vh - 11em) !important; }';
+ document.getElementsByTagName('head')[0].appendChild(s);
+ }
+
+<? minEnd(); ?>
+ </script>
+
+<?
+ }
+
+ $num_rows = -1;
+ if (isset($r) && isset($r->num_rows))
+ $num_rows = $r->num_rows;
+ if (isset($stmt))
+ $stmt->reset();
+})();
+?>