Skip to content
Snippets Groups Projects
Commit 8feedead authored by Hahn Axel (hahn)'s avatar Hahn Axel (hahn)
Browse files

update viewer

parent 339b3201
No related branches found
No related tags found
No related merge requests found
...@@ -17,7 +17,10 @@ ...@@ -17,7 +17,10 @@
--box-bg: var(--darker-bg); --box-bg: var(--darker-bg);
--box-strong-color: var(--titlebar-bg); --box-strong-color: var(--titlebar-bg);
--button-bg: #e8e8f0; --button-bg: #f8f8f8;
--button-bg-active: #e8e8f0;
--button-border-active: #669;
--button-border-hover: rgba(0,0,80,0.3);
--button-color: #667; --button-color: #667;
--button-close-bg: #fff; --button-close-bg: #fff;
--button-close-color: #633; --button-close-color: #633;
...@@ -41,7 +44,6 @@ body{ ...@@ -41,7 +44,6 @@ body{
font-size: 1.0m; font-size: 1.0m;
margin: 0; margin: 0;
} }
a{ a{
color: var(--a-color); color: var(--a-color);
} }
...@@ -52,17 +54,20 @@ a.button{ ...@@ -52,17 +54,20 @@ a.button{
color: var(--button-color); color: var(--button-color);
text-decoration: none; text-decoration: none;
padding: 0.4em; padding: 0.4em;
transition: all 0.2s linear; transition: all 0.1s linear;
}
a.button:hover{
border-color: var(--button-border-hover);
box-shadow: none;
}
a.button.active{
background: var(--button-bg-active);
border-top: 4px solid var(--button-border-active);
} }
a.button.close{ a.button.close{
background: var(--button-close-bg); background: var(--button-close-bg);
color: var(--button-close-color); color: var(--button-close-color);
} }
a.button:hover{
box-shadow: none;
border-color: rgba(0,0,80,0.3);
}
footer{ footer{
background-color: var(--footer-bg); background-color: var(--footer-bg);
position: fixed; bottom: 0; position: fixed; bottom: 0;
...@@ -71,26 +76,32 @@ footer{ ...@@ -71,26 +76,32 @@ footer{
padding: 1em; padding: 1em;
opacity: 0.6; opacity: 0.6;
} }
h1{ h1{
background: var(--titlebar-bg); background: var(--titlebar-bg);
margin: 0; margin: 0;
padding-left: 0.5em; padding-left: 0.5em;
border-bottom: var(--titlebar-border-bottom); border-bottom: var(--titlebar-border-bottom);
} }
h1 small{
opacity: 0.5;
}
h1 a{ h1 a{
color: var(--titlebar-color); color: var(--titlebar-color);
text-decoration: none; text-decoration: none;
} }
iframe{
border: 0;
width: 100%;
height: 70em;
overflow: scroll;
}
pre{ pre{
background-color: var(--pre-bg); background-color: var(--pre-bg);
overflow: scroll; overflow: scroll;
padding: 1em; padding: 1em;
border-radius: 1em; border-radius: 1em;
margin: 0 0 1em;
} }
th{ th{
background-color: var(--table-head-bg); background-color: var(--table-head-bg);
padding: 0.5em; padding: 0.5em;
...@@ -110,8 +121,6 @@ td a, td span{ ...@@ -110,8 +121,6 @@ td a, td span{
padding: 0.5em; padding: 0.5em;
} }
#messages{ #messages{
margin: 1em; margin: 1em;
margin-bottom: 8em; margin-bottom: 8em;
...@@ -133,7 +142,6 @@ td a, td span{ ...@@ -133,7 +142,6 @@ td a, td span{
background-color: var(--msg-hover-bg); background-color: var(--msg-hover-bg);
} }
#singlemessage{ #singlemessage{
background: var(--simglemail-bg); background: var(--simglemail-bg);
border-top-left-radius: 1em; border-top-left-radius: 1em;
...@@ -188,3 +196,8 @@ td a, td span{ ...@@ -188,3 +196,8 @@ td a, td span{
.right{ .right{
float: right; float: right;
} }
.toolbar{
padding: 1.5em 1em 1em 0em;
width: 97%;
}
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
PHP EMAIL CATCHER PHP EMAIL CATCHER
search functionality - search functionality
- save/ restore view settings
*/ */
...@@ -11,44 +12,122 @@ search functionality ...@@ -11,44 +12,122 @@ search functionality
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
const tableId = 'messagestable'; const tableId = 'messagestable';
const searchId = 'search'; const searchId = 'search';
const lsVar = 'searchEmailCatcher';
const lsVar_prefix = "emailcatcher_";
const lsVar_search = lsVar_prefix + "_search";
const lsVar_header = lsVar_prefix + "_showHeader";
const lsVar_source = lsVar_prefix + "_showSource";
var bViewHeader = lsGet(lsVar_header, 1);
var bViewSource = lsGet(lsVar_source, 0);
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// functions // functions
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
/**
* Helper load a variable from local storage
* @param {string} key key to read from localstorage
* @param {*} defaultvalue default value if "null" or "NaN" was returned
* @returns
*/
function lsGet(key, defaultvalue) {
return localStorage.getItem(key).replace(/^(null|NaN)$/g, defaultvalue);
}
// ----------------------------------------------------------------------
/** /**
* read search field and hide non matching rows * read search field and hide non matching rows
* @returns void * @returns void
*/ */
function filterTable(){ function filterTable() {
var sFilter=document.getElementById(searchId).value; var sFilter = document.getElementById(searchId).value;
localStorage.setItem(lsVar, sFilter); localStorage.setItem(lsVar_search, sFilter);
var table=document.getElementById(tableId); var table = document.getElementById(tableId);
if (!table){ if (!table) {
return false; return false;
} }
var rows=table.rows; var rows = table.rows;
for(var i=1;i<rows.length;i++){ for (var i = 1; i < rows.length; i++) {
if(rows[i].innerText.toLowerCase().indexOf(sFilter.toLowerCase()) == -1){ if (rows[i].innerText.toLowerCase().indexOf(sFilter.toLowerCase()) == -1) {
rows[i].style.display='none'; rows[i].style.display = 'none';
} }
else{ else {
rows[i].style.display='table-row'; rows[i].style.display = 'table-row';
} }
} }
} }
// ----------------------------------------------------------------------
/**
* Show / hide message header
* @global integer bViewHeader flag: view header - 1=yes; 0=no
*/
function viewHideHeader() {
if (!document.getElementById('msg-header')) {
return false;
}
document.getElementById('msg-header').style.display = bViewHeader ? 'block' : 'none';
document.getElementById('btn-header').className = bViewHeader ? 'button active' : 'button';
return true;
}
/**
* toggle message headers; it inverst bViewHeader and calls viewHideHeader function
* @global integer bViewHeader flag: view header - 1=yes; 0=no
* @returns true
*/
function toggleViewHeader() {
bViewHeader = Math.abs(bViewHeader - 1);
localStorage.setItem(lsVar_header, bViewHeader);
viewHideHeader();
return true;
}
/**
* Show message source or html
* @global integer bViewSource flag: view html or source - 1=show source; 0=show html
*/
function viewSource(bSource) {
if (!document.getElementById('msg-html')) {
return false;
}
document.getElementById('msg-html').style.display = bSource ? 'none' : 'block';
document.getElementById('msg-source').style.display = bSource ? 'block' : 'none';
document.getElementById('btn-html').className = bSource ? 'button' : 'button active';
document.getElementById('btn-source').className = bSource ? 'button active' : 'button';
if (bSource != bViewSource) {
bViewSource = bSource;
localStorage.setItem(lsVar_source, bSource);
}
return true;
}
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// main // main
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
document.getElementById(searchId).value=''+localStorage.getItem(lsVar); // --- search field and filter table
document.getElementById(searchId).value = '' + lsGet(lsVar_search, '');
document.getElementById(searchId).addEventListener('keyup', filterTable); document.getElementById(searchId).addEventListener('keyup', filterTable);
document.getElementById(searchId).addEventListener('keypress', filterTable); document.getElementById(searchId).addEventListener('keypress', filterTable);
filterTable(); filterTable();
// --- view settings
var bViewHeader = Math.round(lsGet(lsVar_header, 1));
var bViewSource = Math.round(lsGet(lsVar_source, 0));
if (bViewHeader !== 0 && bViewHeader !== 1) {
bViewHeader = 1;
}
viewHideHeader();
viewSource(bViewSource);
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
...@@ -14,15 +14,15 @@ ...@@ -14,15 +14,15 @@
* 2024-10-08 v0.1 initial version * 2024-10-08 v0.1 initial version
* 2024-10-09 v0.2 add links * 2024-10-09 v0.2 add links
* 2024-10-21 v0.3 add tiles on top; add email search * 2024-10-21 v0.3 add tiles on top; add email search
* 2024-11-08 v0.4 view html view in preview already
* ======================================================================= * =======================================================================
*/ */
require_once('classes/emailcatcher.class.php'); require_once('classes/emailcatcher.class.php');
$_version = "0.4";
// $sJsonFile='/tmp/mailin.txt.json'; $sOpen = $_GET['open'] ?? '';
$sShowHtml = $_GET['html'] ?? '';
$sOpen=$_GET['open'] ?? '';
$sShowHtml=$_GET['html'] ?? '';
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// FUNCTIONS // FUNCTIONS
...@@ -32,36 +32,53 @@ $sShowHtml=$_GET['html'] ?? ''; ...@@ -32,36 +32,53 @@ $sShowHtml=$_GET['html'] ?? '';
function showEmail($sId) function showEmail($sId)
{ {
$sReturn=''; $sReturn = '';
$oMail=new emailcatcher(); $oMail = new emailcatcher();
if(!$oMail->setId($sId)){ if (!$oMail->setId($sId)) {
$sReturn.="❌ ERROR: Unable to open non existing email id<br>"; $sReturn .= "❌ ERROR: Unable to open non existing email id<br>";
} else { } else {
$bIsHtml=strstr( $oMail->getBody(), '<html>'); $bIsHtml = strstr($oMail->getBody(), '<html>');
$sReturn.= '<div id="singlemessage"> $sToolbar = ''
. '<a href="#" id="btn-header" onclick="toggleViewHeader(); return false;" class="button active">📜 Header</a> '
. ($bIsHtml
? "<span class=\"right\"><a href=\"?open=$sId&html=1\" class=\"button\">💠 HTML in full screen</a></span>"
. '&nbsp;&nbsp;&nbsp;&nbsp;'
. "<a href=\"#\" id=\"btn-html\" onclick=\"viewSource(0); return false;\" class=\"button active\">🌐 HTML</a> "
. "<a href=\"#\" id=\"btn-source\" onclick=\"viewSource(1); return false;\" class=\"button\">📃 Source</a>"
: ''
);
$sReturn .= '<div id="singlemessage">
<div class="header"> <div class="header">
<span class="right"><a href="?" class="button close">❌</a>&nbsp;&nbsp;&nbsp;</span> <span class="right"><a href="?" class="button close">❌</a>&nbsp;&nbsp;&nbsp;</span>
<table> <table>
<tr><td class="small">🕜 DATE</td><td>'.$oMail->getField('date').'</td></tr> <tr><td class="small">🕜 DATE</td><td>' . $oMail->getField('date') . '</td></tr>
<tr><td class="small">👤 TO</td><td>'.$oMail->getField('to').'</td></tr> <tr><td class="small">👤 TO</td><td>' . $oMail->getField('to') . '</td></tr>
</table> </table>
<strong>'.$oMail->getField('subject').'</strong> <strong>' . $oMail->getField('subject') . '</strong>
<div class="toolbar">' . $sToolbar . '</div>
</div> </div>
<div class="content"> <div class="content">
📜 Header:<br> <div id="msg-header">
<pre>'.$oMail->getHeader().'</pre> <pre>' . $oMail->getHeader() . '</pre>
<br>🗨️ ' </div>
.($bIsHtml '
? '<a href="?open='.$sId.'&html=1" class="button">👁️ Show message as HTML</a><br><br>' . ($bIsHtml
: 'Text only:' ? '<div id="msg-html">'
) . '<iframe srcdoc="' . str_replace('"', '&quot;', $oMail->getBody()) . '"></iframe>'
.'<pre>'.htmlentities($oMail->getBody()).'</pre>' . '</div>'
.'<br> . '<div id="msg-source" style="display: none;">'
. '<pre>' . htmlentities($oMail->getBody()) . '</pre>'
. '</div>'
: ''
. '<pre>' . htmlentities($oMail->getBody()) . '</pre>'
)
. '<br>
<span class="right"><a href="?" class="button close">❌ Close</a></span><br> <span class="right"><a href="?" class="button close">❌ Close</a></span><br>
<br>' <br>'
.'</div>' . '</div>'
.'</div>' . '</div>'
; ;
} }
return $sReturn; return $sReturn;
...@@ -69,85 +86,92 @@ function showEmail($sId) ...@@ -69,85 +86,92 @@ function showEmail($sId)
function showHtmlEmail($sId): void function showHtmlEmail($sId): void
{ {
$oMail=new emailcatcher(); $oMail = new emailcatcher();
echo '<button onclick="history.back();return false;">back</button><br>'; echo '
if(!$oMail->setId($sId)){ <a href="#" onclick="history.back();return false;"
style="background: #e8e8f0; border: 2px solid rgba(0,0,0,0.05); border-radius: 0.5em; color: #667; font-size: 100%; text-decoration: none; padding: 0.4em 1em; position: fixed; left: 1em; top: 1em;"
>&lt;&lt; back</a>
';
if (!$oMail->setId($sId)) {
echo "❌ ERROR: Unable to open non existing email id<br>"; echo "❌ ERROR: Unable to open non existing email id<br>";
} else { } else {
echo $oMail->getBody(); echo '<div style="border-top: 2px dashed #ddd; margin: 4em auto 3em; padding: 1em; width: 98%;">'
. $oMail->getBody()
. '</div>';
} }
die(); die();
} }
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// MAIN // MAIN
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
$oMail=new emailcatcher(); $oMail = new emailcatcher();
$aEmails=$oMail->readEmails(); $aEmails = $oMail->readEmails();
$sOut=''; $sOut = '';
$sMessage=''; $sMessage = '';
if(!count($aEmails)){ if (!count($aEmails)) {
$sOut='❌ No email was found.<br>'; $sOut = '❌ No email was found.<br>';
} else { } else {
// get a single email if id was given. // get a single email if id was given.
if ($sOpen){ if ($sOpen) {
if($sShowHtml=="1"){ if ($sShowHtml == "1") {
showHtmlEmail($sOpen); showHtmlEmail($sOpen);
} }
$sMessage=showEmail($sOpen); $sMessage = showEmail($sOpen);
} }
// show list of emails // show list of emails
$sTable=''; $sTable = '';
$sLatest=''; $sLatest = '';
foreach($aEmails as $aEmail){ foreach ($aEmails as $aEmail) {
// --- age of last email // --- age of last email
$sId=$aEmail['id']; $sId = $aEmail['id'];
if(!$sLatest){ if (!$sLatest) {
$iAge=date('U') - date('U', strtotime($aEmail['date'])); $iAge = date('U') - date('U', strtotime($aEmail['date']));
$sLatest='Less than 1 min ago.'; $sLatest = 'Just now';
if($iAge>60){ if ($iAge > 60) {
$sLatest=round($iAge / 60).' min ago'; $sLatest = round($iAge / 60) . ' min ago';
} }
if($iAge>60*60){ if ($iAge > 60 * 60) {
$sLatest=round($iAge / 60 / 60 ).' h ago'; $sLatest = round($iAge / 60 / 60) . ' h ago';
} }
if($iAge>60*60*24){ if ($iAge > 60 * 60 * 24) {
$sLatest=round($iAge / 60 / 60 / 24 ).' d ago'; $sLatest = round($iAge / 60 / 60 / 24) . ' d ago';
} }
} }
// --- table with emails // --- table with emails
$sTable.=($sId!=$sOpen $sTable .= ($sId != $sOpen
? '<tr> ? '<tr>
<td><a href="?open='.$sId.'">✉️ '.htmlentities($aEmail['subject']).'</a></td> <td><a href="?open=' . $sId . '">✉️ ' . htmlentities($aEmail['subject']) . '</a></td>
<td><a href="?open='.$sId.'">'.htmlentities($aEmail['to']).'</a></td> <td><a href="?open=' . $sId . '">' . htmlentities($aEmail['to']) . '</a></td>
<td><a href="?open='.$sId.'">'.$aEmail['date'].'</a></td> <td><a href="?open=' . $sId . '">' . $aEmail['date'] . '</a></td>
</tr> </tr>
' '
: '<tr class="active"> : '<tr class="active">
<td><span>🔶 '. htmlentities($aEmail['subject']).'</span></td> <td><span>🔶 ' . htmlentities($aEmail['subject']) . '</span></td>
<td><span>'.htmlentities($aEmail['to']).'</span></td> <td><span>' . htmlentities($aEmail['to']) . '</span></td>
<td><span>'.$aEmail['date'].'</span></td> <td><span>' . $aEmail['date'] . '</span></td>
</tr>' </tr>'
); );
} }
$sOut='<div class="box">Messages<br><strong>'.count($aEmails).'</strong></div>' $sOut = '<div class="box">Messages<br><strong>' . count($aEmails) . '</strong></div>'
.'<div class="box">Last<br><strong>'.$sLatest .'</strong></div>' . '<div class="box">Last<br><strong>' . $sLatest . '</strong></div>'
. '<div><input type="text" id="search" size="30" placeholder="Search..."></div>' . '<div><input type="text" id="search" size="30" placeholder="Search..."></div>'
. '<br><br>' . '<br><br>'
; ;
$sOut.='<table id="messagestable"> $sOut .= '<table id="messagestable">
<thead> <thead>
<tr><th>Subject</th><th>To</th><th class="date">Date</th></tr> <tr><th>Subject</th><th>To</th><th class="date">Date</th></tr>
</thead> </thead>
<tbgody>' <tbgody>'
.$sTable . $sTable
.'</tbody></table>' . '</tbody></table>'
; ;
} }
...@@ -158,14 +182,16 @@ if(!count($aEmails)){ ...@@ -158,14 +182,16 @@ if(!count($aEmails)){
?><!doctype html> ?><!doctype html>
<html> <html>
<head> <head>
<title>Email catcher :: viewer</title> <title>Email catcher :: viewer</title>
<link rel="stylesheet" href="viewer.css"> <link rel="stylesheet" href="viewer.css">
</head> </head>
<body> <body>
<h1><a href="?">🕶️ Email catcher :: viewer</a></h1> <h1><a href="?">🕶️ Email viewer <small><?php echo $_version ?></small></a></h1>
<div id="messages"><?php echo $sOut ?></div> <div id="messages"><?php echo $sOut ?></div>
...@@ -176,7 +202,8 @@ if(!count($aEmails)){ ...@@ -176,7 +202,8 @@ if(!count($aEmails)){
</footer> </footer>
<?php echo $sMessage ?> <?php echo $sMessage ?>
<script src="viewer.js"></script> <script defer src="viewer.js"></script>
</body> </body>
</html>
</html>
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment