merge del branch 'notifs' di goodoldpaul

This commit is contained in:
pezcurrel 2020-05-21 05:12:18 +02:00
commit e6ac1f3de8
8 changed files with 606 additions and 27 deletions

View file

@ -1,3 +1,2 @@
RewriteEngine Off RewriteEngine Off
RewriteEngine On RewriteEngine On
php_flag mail.add_x_header Off

View file

@ -7,7 +7,7 @@ if ($account['Level']!='guest') {
'instances'=>array('liadd'=>null, 'href'=>'instances.php', 'title'=>'Istanze', 'selected'=>false, 'submenu'=>null), 'instances'=>array('liadd'=>null, 'href'=>'instances.php', 'title'=>'Istanze', 'selected'=>false, 'submenu'=>null),
'blacklist'=>array('liadd'=>null, 'href'=>'#', 'title'=>'Blacklist', 'selected'=>false, 'submenu'=>null), 'blacklist'=>array('liadd'=>null, 'href'=>'#', 'title'=>'Blacklist', 'selected'=>false, 'submenu'=>null),
'accounts'=>array('liadd'=>null, 'href'=>'#', 'title'=>'Accounts', 'selected'=>false, 'submenu'=>null), 'accounts'=>array('liadd'=>null, 'href'=>'#', 'title'=>'Accounts', 'selected'=>false, 'submenu'=>null),
'notifs'=>array('liadd'=>null, 'href'=>'#', 'title'=>'Notifiche', 'selected'=>false, 'submenu'=>null), 'notifs'=>array('liadd'=>null, 'href'=>'notifs.php', 'title'=>'Notifiche', 'selected'=>false, 'submenu'=>null),
'account'=>array('liadd'=>null, 'href'=>'account.php?id='.$account['ID'], 'title'=>'Il tuo account', 'selected'=>false, 'submenu'=>null), 'account'=>array('liadd'=>null, 'href'=>'account.php?id='.$account['ID'], 'title'=>'Il tuo account', 'selected'=>false, 'submenu'=>null),
'logout'=>array('liadd'=>null, 'href'=>'logout.php', 'title'=>'Logout', 'selected'=>false, 'submenu'=>null) 'logout'=>array('liadd'=>null, 'href'=>'logout.php', 'title'=>'Logout', 'selected'=>false, 'submenu'=>null)
) )

View file

@ -2,12 +2,14 @@
function notifs(&$link) { function notifs(&$link) {
$chunksize=20; // questo deve essere settato paro-paro in notifsh.php $chunksize=20; // questo deve essere settato paro-paro in notifsh.php
$i=0; $i=0;
$notifs='<div id="notifc">'.N; $notifs = array();
$notifs.='<div id="notifs" onscroll="morenotifs();">'.N; $notif_divs='<div id="notifc">'.N;
$notif_divs.='<div id="notifs" onscroll="morenotifs();">'.N;
$unreadnotifs=false; $unreadnotifs=false;
$res=mysqli_query($link,'SELECT * FROM Notifications ORDER BY Microtime DESC') $res=mysqli_query($link,'SELECT * FROM Notifications ORDER BY Microtime DESC')
or muoribene(mysqli_error($link),true); or muoribene(mysqli_error($link),true);
while ($row=mysqli_fetch_assoc($res)) { while ($row=mysqli_fetch_assoc($res)) {
array_push($notifs, $row);
if ($row['Seen']==0) { if ($row['Seen']==0) {
$unreadnotifs=true; $unreadnotifs=true;
$notifclass='notifunseen'; $notifclass='notifunseen';
@ -17,12 +19,12 @@ function notifs(&$link) {
$i++; $i++;
if ($i<=$chunksize) { if ($i<=$chunksize) {
if ($i==1) $lastmicrotime=$row['Microtime']; if ($i==1) $lastmicrotime=$row['Microtime'];
$notifs.='<div id="notif-'.$row['ID'].'" class="'.$notifclass.'" onclick="markread(this)">'.strftime('%d/%m/%y %T',$row['Microtime']).': '.$row['Notification'].'</div>'.N; $notif_divs.='<div id="notif-'.$row['ID'].'" class="'.$notifclass.'" onclick="markread(this)">'.strftime('%d/%m/%y %T',$row['Microtime']).': '.$row['Notification'].'</div>'.N;
} }
} }
$notifs.='</div>'.N; $notif_divs.='</div>'.N;
$notifs.='<div id="notifa"><a href="notifs.php">Vedi tutte le notifiche</a></div>'.N; $notif_divs.='<div id="notifa"><a href="notifs.php">Vedi tutte le notifiche</a></div>'.N;
$notifs.='</div>'.N; $notif_divs.='</div>'.N;
if ($unreadnotifs) { if ($unreadnotifs) {
$imgoff='imgs/bell_act_off.svg'; $imgoff='imgs/bell_act_off.svg';
$imgon='imgs/bell_act_on.svg'; $imgon='imgs/bell_act_on.svg';
@ -31,7 +33,8 @@ function notifs(&$link) {
$imgon='imgs/bell_on.svg'; $imgon='imgs/bell_on.svg';
} }
return(array( return(array(
'div'=>$notifs, 'notifs'=>$notifs,
'div'=>$notif_divs,
'imgoff'=>$imgoff, 'imgoff'=>$imgoff,
'imgon'=>$imgon, 'imgon'=>$imgon,
'lastmicrotime'=>$lastmicrotime, 'lastmicrotime'=>$lastmicrotime,

View file

@ -19,19 +19,112 @@ function markread(notif) {
xhr.responseType='json'; xhr.responseType='json';
xhr.send(); xhr.send();
xhr.onload=function() { xhr.onload=function() {
notif.className='notifseen';
let jarr=xhr.response; let jarr=xhr.response;
if (jarr['hmunseen']==0) { if (jarr['hmunseen']==0) {
notifimgon='imgs/bell_on.svg'; notifimgon='imgs/bell_on.svg';
notifimgoff='imgs/bell_off.svg'; notifimgoff='imgs/bell_off.svg';
bell.src=notifimgon; bell.src=notifimgon;
} }
if (notif.classList.contains("notifunseen")){
// Notifica nella navbar
notif.className='notifseen';
} else if (notif.classList.contains("unseen")) {
// Notifica nella pagina di gestione notifiche
notif.classList.remove("unseen");
notif.classList.add("seen");
}
}; };
xhr.onerror=function() { xhr.onerror=function() {
alert('La richiesta è fallita.'); alert('La richiesta è fallita.');
}; };
} }
lmt=<?php echo($notifs['lastmicrotime']); ?>;
function markdeleted(notif) {
let xhr = new XMLHttpRequest();
xhr.open('GET', 'notifsh.php?act=delete&id=' + notif.id.replace(/^notif-([0-9]+)$/, '$1'));
xhr.responseType = 'json';
xhr.send();
xhr.onload = function () {
if (xhr.response['deleted']) {
notif.classList.add("deleted");
} else {
alert("Il server non ha potuto cancellare la notifica '" + notif.text + "'");
}
};
xhr.onerror = function () {
alert('La richiesta è fallita.');
};
}
function getAliveNotifs(){
let notifs = Array.from(document.querySelectorAll("div.notif"));
return notifs.filter(n => {
let classes = Array.from(n.classList);
return !(classes.includes("deleted") || classes.includes("filtered"));
})
}
function getAliveCheckboxes() {
let notifs = getAliveNotifs();
return notifs.map(n => n.querySelector("input.seen-checkbox"))
}
function readSelected() {
let selected = getSelectedNotifs()
let request = {
"act": "massread",
"ids": selected.map(div => div.id.replace(/^notif-([0-9]+)$/, '$1'))
}
let xhr = new XMLHttpRequest();
xhr.open('POST', 'notifs.php');
xhr.setRequestHeader('Content-type','application/json');
xhr.responseType = 'json';
xhr.send(JSON.stringify(request));
xhr.onload = function () {
if (xhr.response['done']) {
selected.forEach(notif => {
notif.classList.remove("unseen");
notif.classList.add("seen");
})
} else {
alert("Il server non ha potuto completare la richiesta:\n" + xhr.response["error"]);
}
};
xhr.onerror = function () {
alert('La richiesta è fallita.');
};
}
function deleteSelected() {
let selected = getSelectedNotifs()
let request = {
"act": "massdelete",
"ids": selected.map(div => div.id.replace(/^notif-([0-9]+)$/, '$1'))
}
let xhr = new XMLHttpRequest();
xhr.open('POST', 'notifs.php');
xhr.setRequestHeader('Content-type','application/json');
xhr.responseType = 'json';
xhr.send(JSON.stringify(request));
xhr.onload = function () {
if (xhr.response['done']) {
selected.forEach(notif => notif.classList.add("deleted"));
} else {
alert("Il server non ha potuto completare la richiesta:\n" + xhr.response["error"]);
}
};
xhr.onerror = function () {
alert('La richiesta è fallita.');
};
}
function getSelectedNotifs() {
let notifs = getAliveNotifs();
return notifs.filter(notif => notif.querySelector("input.seen-checkbox").checked)
}
lmt =<?php echo($notifs['lastmicrotime']); ?>;
chunk=0; chunk=0;
end=false; end=false;
loading=false; loading=false;

368
web/mustard/notifs.php Normal file
View file

@ -0,0 +1,368 @@
<?php
require('include/glob.php');
require('include/muoribene.php');
require('include/sessionstart.php');
require('include/myconn.php');
require('include/getadmacc.php');
if ($account['Level'] == 'guest')
muoribene('Sorry, you are not authorized.', true);
require('include/menu.php');
$menu['menu']['selected'] = true;
$menu['menu']['submenu']['notifs']['selected'] = true;
buildmenu($menu);
$dbg = '';
// praticamente una macro
function hspech($str)
{
return (htmlspecialchars($str, ENT_QUOTES | ENT_HTML5, 'UTF-8'));
}
function are_valid_ids($ids)
{
if (count($ids) <= 0) return false;
foreach ($ids as $id) {
if (!(preg_match('/^[0-9]+$/', $id) === 1)) {
return false;
}
}
return true;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $_SERVER["CONTENT_TYPE"] === "application/json") {
$response = array(
"done" => true,
"error" => ""
);
$body = json_decode(file_get_contents('php://input'), true);
if (array_key_exists('act', $body) &&
array_key_exists('ids', $body) &&
are_valid_ids($body["ids"])) {
switch ($body['act']) {
case "massread":
mysqli_query($link, 'UPDATE Notifications SET Seen=1 WHERE ID in (' . implode(", ", $body["ids"]) . ')')
or muoribene(mysqli_error($link), true);
break;
case "massdelete":
mysqli_query($link, 'UPDATE Notifications SET Deleted=1 WHERE ID in (' . implode(", ", $body["ids"]) . ')')
or muoribene(mysqli_error($link), true);
break;
default:
http_response_code(400);
$response["done"] = false;
$response["error"] = "Unknown act.";
}
} else {
http_response_code(400);
$response["done"] = false;
$response["error"] = "Bad request.";
}
echo(json_encode($response));
mysqli_close($link);
exit(0);
}
$dbg .= $dlang . '<br>' . N;
$dbg .= '<pre>' . print_r($_GET, 1) . '</pre>';
$dbg .= '<pre>' . print_r($inst, 1) . '</pre>' . N;
if ($account['Level'] != 'guest') {
require('include/notifs.php');
$notifs = notifs($link);
} else {
muoribene("Non hai i permessi per vedere questa pagina", true);
}
$filtordon = false;
if ($filtordon) {
$filtordimgoff = 'imgs/cerca_act_off.svg';
$filtordimgon = 'imgs/cerca_act_on.svg';
} else {
$filtordimgoff = 'imgs/cerca_off.svg';
$filtordimgon = 'imgs/cerca_on.svg';
}
?>
<!DOCTYPE HTML>
<html lang="en">
<head>
<title>Mustard - Notifs</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="description" content="Admin pages for Mastodon Startpage">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="icon" type="image/png" href="imgs/icona-32.png" sizes="32x32">
<link rel="icon" type="image/png" href="imgs/icona-192.png" sizes="192x192">
<link rel="icon" type="image/png" href="imgs/icona-512.png" sizes="512x512">
<link rel="apple-touch-icon-precomposed" href="imgs/icona-180.png">
<script language="JavaScript" src="js/menu.js?v=<?php echo($cjrand); ?>"></script>
<script language="JavaScript" src="js/confirma.js?v=<?php echo($cjrand); ?>"></script>
<script language="JavaScript" src="js/alerta.js?v=<?php echo($cjrand); ?>"></script>
<link rel="stylesheet" type="text/css" href="theme.css?v=<?php echo($cjrand); ?>">
<script language="JavaScript">
<!--
<?php if ($account['Level'] != 'guest') require('js/notifs.js.php'); ?>
function reverseSelection() {
let checkboxes = getAliveCheckboxes()
checkboxes.forEach(function (box) {
box.checked = !box.checked;
})
let n_selected = getSelectedNotifs().length;
if (n_selected > 0) {
setBtnsVisibility("visible");
} else if (n_selected === 0) {
setBtnsVisibility("hidden");
document.getElementById("global-selector").checked = false;
}
if (n_selected === checkboxes.length) {
document.getElementById("global-selector").checked = true;
}
}
function setBtnsVisibility(state) {
let controls = document.querySelector("#notifs-list-controls");
controls.querySelector("#read-btn").style.visibility = state;
controls.querySelector("#delete-btn").style.visibility = state;
}
function toggleState(check) {
if (check.checked) {
setBtnsVisibility("visible");
} else {
setBtnsVisibility("hidden")
}
let checkboxes = getAliveCheckboxes()
checkboxes.forEach(function (box) {
box.checked = check.checked;
});
}
function notifSelect(check) {
let checkboxes = getAliveCheckboxes()
if (check.checked) {
setBtnsVisibility("visible");
} else if (checkboxes.every(box => !box.checked)) {
setBtnsVisibility("hidden");
}
}
function showFilterPanel() {
let plancia = document.querySelector("#plancia");
if (plancia.style.display !== "block") {
if (plancia.childElementCount <= 3) {
addAfter(plancia.firstElementChild);
}
plancia.style.display = "block";
}
}
function getFilters() {
return Array.from(document.querySelectorAll("#plancia .notifs-criterion"));
}
function newFilter() {
return "<div class='notifs-criterion'>" +
" <label for='start-date'>Da</label>" +
" <input id='start-date' name='start-date' type='date'>" +
" <label for='stop-date'>A</label>" +
" <input id='stop-date' name='stop-date' type='date'>" +
" <select id='severity'>" +
" <option value='-1'>Indifferente</option>" +
" <option value='1'>Normal</option>" +
" <option value='2'>Warning</option>" +
" <option value='3'>Error</option>" +
" </select>" +
" <select id='operation'>" +
" <option value='0'>E</option>" +
" <option value='1'>O</option>" +
" </select>" +
" <img class='plus' src='imgs/plus.svg' title='Aggiungi un criterio sotto questo'" +
" onclick='addAfter(this.parentElement)'>" +
" <img class='minus' src='imgs/minus.svg' title='Rimuovi questo criterio'" +
" onclick='removeFilter(this.parentElement)'>" +
"</div>";
}
function addAfter(elem) {
let filters = getFilters();
if (filters.length < 7) {
elem.insertAdjacentHTML('afterend', newFilter());
filters = getFilters();
if (filters.length > 1) {
let select = elem.querySelector("#operation");
if (select.disabled) {
select.disabled = false;
}
}
filters[filters.length - 1].querySelector("#operation").disabled = true;
}
}
function removeFilter(elem) {
let filters = getFilters();
if (filters.length > 1) {
elem.remove();
filters = getFilters();
filters[filters.length - 1].querySelector("#operation").disabled = true;
}
}
function clearFilters() {
let filtered = document.querySelectorAll(".filtered");
filtered.forEach(f => f.classList.remove("filtered"))
getFilters().forEach(f => f.remove());
document.querySelector("#plancia").style.display = "none";
}
function makeDateFilter(criterion) {
let start = criterion.querySelector("#start-date").value;
let stop = criterion.querySelector("#stop-date").value;
start = (start === '') ? new Date(0) : new Date(start);
stop = (stop === '') ? new Date() : new Date(stop);
return date => (date <= stop) && (date >= start);
}
function makeSeverityFilter(criterion) {
let select = criterion.querySelector("#severity");
let severity = select.options[select.selectedIndex].value;
if (severity === "-1") {
return x => true;
}
return x => x === severity;
}
function makeFilterFunction(criterion) {
let dateFilter = makeDateFilter(criterion);
let severityFilter = makeSeverityFilter(criterion);
return notif => {
let microtime = new Date(parseFloat(notif.dataset.microtime) * 1000);
let severity = notif.dataset.severity;
return dateFilter(microtime) && severityFilter(severity);
}
}
function applyFilters() {
let filters = getFilters();
let notifs = getAliveNotifs();
let filterFunctions = filters.map(makeFilterFunction);
let fun = x => filterFunctions[0](x);
for (let i = 0; i < filters.length - 1; i++) {
// Questo hack serve per evitare che la chiamata
// al filtro sia interpretata come ricorsione.
let filter = fun;
if (filters[i].querySelector("#operation").value === "0") {
fun = x => (filter(x) && filterFunctions[i + 1](x));
} else {
fun = x => (filter(x) || filterFunctions[i + 1](x));
}
}
notifs.forEach(notif => {
if (!fun(notif)) {
notif.classList.add("filtered");
}
});
document.querySelector("#plancia").style.display = "none";
}
// -->
</script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fork-awesome@1.1.7/css/fork-awesome.min.css"
integrity="sha256-gsmEoJAws/Kd3CjuOQzLie5Q3yshhvmo7YNtBG7aaEY=" crossorigin="anonymous">
</head>
<body>
<nav>
<div id="hmenu">
<ul>
<?php echo($menuout); ?>
</ul>
<div class="mtit">Notifiche</div>
<div id="rightdiv">
<img src="<?php echo($filtordimgoff); ?>" id="lente" class="rlinks" title="Mostra il pannello di filtraggio"
onclick="showFilterPanel();">
<?php if ($account['Level'] != 'guest') echo('<img src="' . $notifs['imgoff'] . '" id="bell" class="rlinks" title="Show notifications" onclick="shidenotifs();">' . N); ?>
<img src="imgs/esci.svg" class="rlinks" title="Logout" onclick="document.location.href='logout.php';">
</div>
</div>
</nav>
<?php echo($notifs['div']); ?>
<div id="notifs-grid">
<div id="notifs-list">
<?php
if ($account['Level'] != 'guest') {
$sev_classes = array(
1 => "sev-normal",
2 => "sev-warning",
3 => "sev-error"
);
$seen_class = array(
0 => "unseen",
1 => "seen"
);
$deleted = array(
0 => "",
1 => "deleted"
);
foreach ($notifs['notifs'] as $n) {
echo("<div id=\"notif-" . $n["ID"] . "\" class=\"" . "notif " . $deleted[$n["Deleted"]] . " " . $sev_classes[$n["Severity"]] . " " . $seen_class[$n["Seen"]] .
"\" data-microtime='" . $n['Microtime'] . "' " .
"data-severity='" . $n['Severity'] . "'>" .
"<input type=\"checkbox\" class=\"seen-checkbox\" onclick='notifSelect(this)'>" .
"<button type='button' onclick='markread(this.parentElement)'><i class=\"fa fa-envelope-open-o\" aria-hidden=\"true\"></i></button>" .
"<button type='button' onclick='markdeleted(this.parentElement)'><i class=\"fa fa-trash-o\" aria-hidden=\"true\"></i></button>" .
"<p id='notif-text'>" . strftime('%d/%m/%y %T', $n['Microtime']) . ": " . $n["Notification"] . "</p>" .
"</div>\n");
}
} ?>
</div>
<div id="popup">
<div id="inpopup">
<div id="popupcont">
...
</div>
</div>
</div>
<div id="footer">
<div id="notifs-list-controls">
<input id="global-selector" type="checkbox" onclick="toggleState(this)">
<button id='reverse-btn' type='button' class="control-btn" onclick="reverseSelection()">
Inverti selezione
</button>
<button id='read-btn' type='button' class="control-btn" onclick="readSelected()">
<i class="fa fa-envelope-open-o" aria-hidden="true"></i>
</button>
<button id='delete-btn' type='button' class="control-btn" onclick="deleteSelected()">
<i class="fa fa-trash-o" aria-hidden="true"></i>
</button>
</div>
</div>
</div>
<div id="plancia">
<button id='clear-filters-btn' type='button'
onclick="confirma('Confermi di voler rimuovere tutti i criteri di filtraggio?','clearFilters()')">
Rimuovi tutti i criteri di filtraggio
</button>
<div id="criterion-list"></div>
<button id='apply-filters-btn' type='button' onclick="applyFilters()">
Applica
</button>
</div>
</body>
</html>
<?php
mysqli_close($link);
exit(0);
?>

View file

@ -10,22 +10,27 @@ require('include/getadmacc.php');
if ($account['Level']=='guest') if ($account['Level']=='guest')
muoribene('Sorry, you are not authorized.',true); muoribene('Sorry, you are not authorized.',true);
if (array_key_exists('act',$_GET) && $_GET['act']=='markread' && array_key_exists('id',$_GET) && preg_match('/^[0-9]+$/',$_GET['id'])===1) { if (array_key_exists('act', $_GET) && $_GET['act'] == 'markread' && array_key_exists('id', $_GET) && preg_match('/^[0-9]+$/', $_GET['id']) === 1) {
$_GET['id']+=0; $_GET['id'] += 0;
mysqli_query($link,'UPDATE Notifications SET Seen=1 WHERE ID='.$_GET['id']) mysqli_query($link, 'UPDATE Notifications SET Seen=1 WHERE ID=' . $_GET['id'])
or muoribene(mysqli_error($link),true); or muoribene(mysqli_error($link), true);
$res=mysqli_query($link,'SELECT ID FROM Notifications WHERE Seen=0') $res = mysqli_query($link, 'SELECT ID FROM Notifications WHERE Seen=0')
or muoribene(mysqli_error($link),true); or muoribene(mysqli_error($link), true);
echo('{"hmunseen":'.mysqli_num_rows($res).'}'.N); echo('{"hmunseen":' . mysqli_num_rows($res) . '}' . N);
} elseif (array_key_exists('act',$_GET) && $_GET['act']=='loadchunk' && array_key_exists('chunk',$_GET) && preg_match('/^[0-9]+$/',$_GET['chunk'])===1) { } elseif (array_key_exists('act', $_GET) && $_GET['act'] == 'delete' && array_key_exists('id', $_GET) && preg_match('/^[0-9]+$/', $_GET['id']) === 1) {
$_GET['chunk']+=0; $_GET['id'] += 0;
$chunksize=20; // questo dev'essere uguale in include/notifs.php mysqli_query($link, 'UPDATE Notifications SET Deleted=1 WHERE ID=' . $_GET['id'])
$res=mysqli_query($link,'SELECT * FROM Notifications WHERE Deleted=0 ORDER BY Microtime DESC LIMIT '.($_GET['chunk']*$chunksize).','.$chunksize) or muoribene(mysqli_error($link), true);
or muoribene(mysqli_error($link),true); echo('{"deleted":' . true . '}' . N);
$buf=array(); } elseif (array_key_exists('act', $_GET) && $_GET['act'] == 'loadchunk' && array_key_exists('chunk', $_GET) && preg_match('/^[0-9]+$/', $_GET['chunk']) === 1) {
while ($row=mysqli_fetch_assoc($res)) { $_GET['chunk'] += 0;
($row['Seen']==0) ? $notifclass='notifunseen' : $notifclass='notifseen'; $chunksize = 20; // questo dev'essere uguale in include/notifs.php
$buf[]='<div id="notif-'.$row['ID'].'" class="'.$notifclass.'" onclick="markread(this)">'.strftime('%d/%m/%y %T',$row['Microtime']).': '.$row['Notification'].'</div>'; $res = mysqli_query($link, 'SELECT * FROM Notifications WHERE Deleted=0 ORDER BY Microtime DESC LIMIT ' . ($_GET['chunk'] * $chunksize) . ',' . $chunksize)
or muoribene(mysqli_error($link), true);
$buf = array();
while ($row = mysqli_fetch_assoc($res)) {
($row['Seen'] == 0) ? $notifclass = 'notifunseen' : $notifclass = 'notifseen';
$buf[] = '<div id="notif-' . $row['ID'] . '" class="' . $notifclass . '" onclick="markread(this)">' . strftime('%d/%m/%y %T', $row['Microtime']) . ': ' . $row['Notification'] . '</div>';
} }
echo(json_encode($buf)); echo(json_encode($buf));
} elseif (array_key_exists('act',$_GET) && $_GET['act']=='loadnew' && array_key_exists('lmt',$_GET) && preg_match('/^[0-9]+(\.[0-9]+)?$/',$_GET['lmt'])===1) { } elseif (array_key_exists('act',$_GET) && $_GET['act']=='loadnew' && array_key_exists('lmt',$_GET) && preg_match('/^[0-9]+(\.[0-9]+)?$/',$_GET['lmt'])===1) {

1
web/mustard/php.ini Normal file
View file

@ -0,0 +1 @@
mail.add_x_header="0"

View file

@ -578,6 +578,7 @@ input {
} }
.edtab .desc { .edtab .desc {
margin-bottom: 6px; margin-bottom: 6px;
} }
.edtab .butdiv { .edtab .butdiv {
width: 22px; width: 22px;
@ -840,6 +841,115 @@ input {
} }
#notifs-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 10px;
margin-top: 32px;
}
#notifs-list-controls {
display: inline-block;
position: absolute;
left: 50%;
transform: translateX(-50%);
margin-top: 5px;
}
#global-selector {
width: auto;
margin: 2px 1px 2px 2px;
}
.control-btn {
margin-top: 2px;
margin-bottom: 2px;
}
#read-btn {
margin-left: 1px;
margin-right: 2px;
float: right;
visibility: hidden;
}
#delete-btn {
margin-left: 1px;
margin-right: 1px;
float: right;
visibility: hidden;
}
#reverse-btn {
margin-left: 1px;
margin-right: 1px;
}
#notifs-list {
grid-column: 2;
}
div.notif {
padding: 5px;
margin: 10px;
word-break: break-word;
background-color: #87DE87;
border-radius: 5px;
}
div.notif p {
font-size: 10pt;
text-align: center;
margin: 10px;
padding: 3px;
}
div.notif input {
width: auto;
}
div.notif button {
float: right;
}
div.deleted {
display: none;
}
div.sev-warning {
background-color: #FFEEAA;
}
div.sev-error {
background-color: #DE8787;
}
div.seen {
background-color: lightgrey;
}
div.filtered {
display: none;
}
#plancia .notifs-criterion {
display: flex;
}
#plancia .notifs-criterion label {
margin: 2px;
}
#plancia #clear-filters-btn {
margin: 2px auto;
width: 100%;
}
#plancia #apply-filters-btn {
margin: 2px auto;
width: 100%;
}
@media only screen and (max-width:720px) { @media only screen and (max-width:720px) {
.bigtab td { .bigtab td {
width: 244px; width: 244px;