Skip to content

Instantly share code, notes, and snippets.

@VenkataRaju
Created May 12, 2015 13:12
Show Gist options
  • Save VenkataRaju/623e99544d7a8414c45e to your computer and use it in GitHub Desktop.
Save VenkataRaju/623e99544d7a8414c45e to your computer and use it in GitHub Desktop.
Simple reminder application written in HTML (Makes use of Local Storage API)
<html>
<head>
<meta charset="UTF-8">
<title>Task Tracker</title>
<!-- Version: 0.5 -->
<style>
table {
border-collapse: collapse;
}
.roundedCorner {
border: #AAAAAA solid;
border-radius: 4px;
display: inline-block;
padding: 4px;
}
.errorBorder {
border-color: red;
}
.trackerTbl tbody tr:nth-child(odd) {
background-color: #eee;
}
.trackerTbl {
border-width: 1px;
border-style: solid;
width: 90%;
min-width: 1000px;
}
.th0 {
width: 2%;
}
.th1 {
width: 61%;
}
.th2 {
width: 25%;
}
.th3 {
width: 6%;
}
.timeExpired {
color: #DD0000;
font-weight: bold;
}
</style>
<script>
const PAGE_TITLE = document.title;
const ALART_SOUND = "data:AUDIO/mpeg;base64,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";
const AUDIO = new Audio(ALART_SOUND);
AUDIO.loop = true;
const NOTIFICAION_IMAGE = "data:image/png;base64,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";
var tbody, templateRow;
var taskTF, infLbl, errorLbl;
var infTimer, updateTimer;
var userChosenVolume = 0.5;
// Contains {taskName: "Task Name", expirationTime: 3232323, expirationIndicated: true} objects
var tasks = [], focussed = true;
function $(id) document.getElementById(id);
function init()
{
templateRow = $("templateRow");
templateRow.removeAttribute("id");
tbody = templateRow.parentNode;
tbody.removeChild(templateRow);
templateRow.style.display = "table-row";
taskTF = $("taskTF");
infLbl = $("infLbl");
errorLbl = $("errorLbl");
if (!($("volumeTF").disabled = $("playMusicCB").disabled = AUDIO.error !== null))
updateVolume($("volumeTF"));
// localStorage["TaskTracker"] = null;
addEventListener("beforeunload", () => { localStorage["TaskTracker"] = JSON.stringify(tasks); });
var tasksFromStorage = JSON.parse(localStorage["TaskTracker"]);
if (tasksFromStorage && tasksFromStorage.length)
{
tasks = tasksFromStorage;
for (var i = 0; i < tasks.length; i++)
addRow(tasks[i]);
restartUpdateTimer();
}
}
function updateVolume(tf)
{
var volume = +tf.value;
if(isNaN(volume) || volume < 0 || volume > 20)
{
tf.className = "errorBorder";
return;
}
tf.className = "";
userChosenVolume = volume / 20;
tf.nextElementSibling.textContent = volume + "/20";
}
function add()
{
clearTimeout(infTimer);
infLbl.textContent = errorLbl.textContent = "";
var taskName = taskTF.value.trim();
if (!taskName)
{
errorLbl.textContent = "Task name is required";
taskTF.value = "";
taskTF.focus();
return;
}
var expirationTime = +(+$("hTimeIntervalTF").value * 60 * 60) + (+$("mTimeIntervalTF").value * 60) + (+$("sTimeIntervalTF").value);
$("hTimeIntervalTF").value = $("mTimeIntervalTF").value = $("sTimeIntervalTF").value = "";
if (isNaN(expirationTime) || expirationTime < 1)
{
errorLbl.textContent = ($("hTimeIntervalTF").value + $("mTimeIntervalTF").value + $("sTimeIntervalTF").value).trim().length === 0
? "Time interval is required"
: "Invalid time interval";
$("sTimeIntervalTF").focus();
return;
}
taskTF.value = "";
taskTF.focus();
expirationTime += millisToSeconds(Date.now());
var task =
{
taskName,
expirationTime,
expirationIndicated: false
};
for (var i = 0; i < tasks.length; i++)
{
if (tasks[i].taskName !== taskName)
continue;
tasks[i] = task;
tbody.rows[i].classList.remove("timeExpired");
infLbl.textContent = "Reset Task at row no: " + (i + 1);
infTimer = setTimeout(() => { infLbl.textContent = ""; }, 4000);
restartUpdateTimer();
return;
}
// Need to add new row
tasks.push(task);
addRow(task);
restartUpdateTimer();
}
function millisToSeconds(timeInMillis) ~~(timeInMillis/1000);
function addRow(task)
{
var clone = templateRow.cloneNode(true);
tbody.appendChild(clone);
clone.cells[0].textContent = tbody.childElementCount;
clone.cells[1].textContent = task.taskName;
if(task.expirationTime <= millisToSeconds(Date.now()))
clone.classList.add("timeExpired");
}
function restartUpdateTimer()
{
clearTimeout(updateTimer);
update(); // Immediate refresh
updateTimer = setInterval(update, 1000);
function update()
{
var now = millisToSeconds(Date.now());
for (var i = 0, diff, rt; i < tasks.length; i++)
{
diff = tasks[i].expirationTime - now;
rt = getReadableTime(Math.abs(diff));
if (diff > 0)
{
tbody.rows[i].cells[2].textContent = rt;
continue;
}
tbody.rows[i].cells[2].textContent = "Expired " + rt + " ago";
if (!tasks[i].expirationIndicated)
{
if (taskTF.value.length === 0)
{
taskTF.value = tbody.rows[i].cells[1].textContent;
taskTF.select();
}
tbody.rows[i].classList.add("timeExpired");
if (!focussed)
notifyUser("Time expired for Task", tbody.rows[i].cells[1].textContent);
tasks[i].expirationIndicated = true;
}
}
}
}
function removeRow(el)
{
var rowToBeRemoved = el.parentNode.parentNode;
for (var i = 0, rowNo = 1, rows = tbody.rows, len = rows.length; i < len;)
{
var row = rows[i];
row.cells[0].textContent = rowNo;
if (row == rowToBeRemoved)
{
if (row.cells[1].textContent == taskTF.value)
taskTF.value = "";
tbody.removeChild(row);
tasks.splice(i, 1);
if (len == 1)
clearInterval(updateTimer);
len--;
continue; // Not breaking as we have to fix the remaining row numbers
}
i++;
rowNo++;
}
}
function edit(el)
{
taskTF.value = el.parentNode.parentNode.cells[1].textContent;
$("sTimeIntervalTF").focus();
}
const getReadableTime = (function()
{
const MINUTE_IN_SECONDS = 60, HOUR_IN_SECONDS = MINUTE_IN_SECONDS * 60;
return function(timeInSecs)
{
var timeStr = "";
var time = ~~(timeInSecs / HOUR_IN_SECONDS);
if (time > 0)
{
timeStr = twoDigit(time) + "h:";
timeInSecs %= HOUR_IN_SECONDS;
}
time = ~~(timeInSecs / MINUTE_IN_SECONDS);
if (timeStr || time > 0)
{
timeStr += twoDigit(time) + "m:";
timeInSecs %= MINUTE_IN_SECONDS;
}
return timeStr + twoDigit(timeInSecs) + "s";
}
function twoDigit(num) (num <= 9 ? "0" : "") + num;
})();
const notifyUser = (function()
{
var timer, audioTimer;
return function(title, msg)
{
if ($("desktopNotificationRadio").checked)
{
if (Notification.permission === "granted")
new Notification(title, {icon: NOTIFICAION_IMAGE, body: msg});
else if (Notification.permission !== "denied")
Notification.requestPermission(function (permission)
{
if (permission === "granted")
new Notification(title, {icon: NOTIFICAION_IMAGE, body: msg});
});
}
else if ($("popupNotificationRadio").checked)
alert(msg);
else if($("titleChangeNotificationRadio").checked)
{
var i = 0, t = msg + " ";
clearInterval(timer);
timer = setInterval(function()
{
if (focussed)
{
clearInterval(timer);
document.title = PAGE_TITLE;
}
else
{
if (i === t.length)
i = 0;
document.title = t.substr(i) + t.substr(0, i++);
}
}, 500);
}
if ($("playMusicCB").checked)
{
clearInterval(audioTimer);
AUDIO.volume = userChosenVolume;
AUDIO.play();
const endTime = Date.now() + 15000;
audioTimer = setInterval(function()
{
if (focussed || Date.now() > endTime)
{
AUDIO.pause();
clearInterval(audioTimer);
}
}, 500);
}
}
})();
</script>
</head>
<body onload="init()" onfocus="focussed = true" onblur="focussed = false">
<form onsubmit="add(); return false;" style="margin-top: 2%;">
<table align="center">
<tr>
<td class="align">
<label>Task Name: </label>
</td>
<td>
<input id="taskTF" type="text" size="70" autofocus />
</td>
</tr>
<tr>
<td class="align">
<label>Time Interval: </label>
</td>
<td>
<input id="sTimeIntervalTF" type="text" size="4" title="Seconds" />&nbsp;s&nbsp;&nbsp;
<input id="mTimeIntervalTF" type="text" size="4" title="Minutes" />&nbsp;m&nbsp;&nbsp;
<input id="hTimeIntervalTF" type="text" size="4" title="Hours" />&nbsp;h&nbsp;&nbsp;
</td>
</tr>
<tr>
<td>&nbsp;
</td>
<td>
<label id="infLbl" style="float: left; color: green; font-weight: bold"></label>
<label id="errorLbl" style="float: left; color: red; font-weight: bold"></label>
</td>
</tr>
<tr>
<td colspan="2" align="center" style="padding-top: 4px">
<input type="submit" style="width: 30%" value="Add" />
</td>
</tr>
</table>
</form>
<br />
<table align="center">
<tr>
<td>
<table>
<tr>
<td>
<form onsubmit="return false;">
<fieldset class="roundedCorner">
<legend style="font-weight: bold;">If the timer expires when i'm in another page</legend>
<table align="left" style="margin: 10px;">
<tr>
<td>
<input type="radio" id="desktopNotificationRadio" name="notificationType" checked />
<label for="desktopNotificationRadio">Desktop Notification</label>
</td>
</tr>
<tr>
<td>
<input type="radio" id="popupNotificationRadio" name="notificationType" />
<label for="popupNotificationRadio">Show Popup Alert</label>
</td>
</tr>
<tr>
<td>
<input type="radio" id="titleChangeNotificationRadio" name="notificationType" />
<label for="titleChangeNotificationRadio">Scroll Page Title</label>
</td>
</tr>
<tr>
<td>
<input id="playMusicCB" type="checkbox" checked style="margin-top: 2px"
onchange='$("volumeTF").disabled=!$( "playMusicCB").checked;' />
<label for="playMusicCB">Play music</label>
</td>
</tr>
<tr>
<td>
<label for="volumeTF">Volume: </label>
<input id="volumeTF" type="range" onchange="updateVolume(this)" onkeyup="updateVolume(this)" value="4"
min="0" max="20" title="0 to 20" />
<label style="font-size:small"></label>
</td>
</tr>
</table>
</fieldset>
</form>
</td>
</tr>
</table>
</td>
</tr>
</table>
<br />
<table align="center" border="1" class="trackerTbl">
<thead>
<th class="th0">No.</th>
<th class="th1">Task Name</th>
<th class="th2">Time Left</th>
<th class="th3">Remove</th>
<th class="th3">Edit</th>
</thead>
<tbody>
<tr id="templateRow" style="display: none;">
<td></td>
<td></td>
<td style="font-size: 1.2em; font-family: monospace;"></td>
<td align="center">
<button onclick="removeRow(this)">Remove</button>
</td>
<td align="center">
<button onclick="edit(this)">Edit</button>
</td>
</tr>
</tbody>
</table>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment