Created
May 12, 2015 13:12
-
-
Save VenkataRaju/623e99544d7a8414c45e to your computer and use it in GitHub Desktop.
Simple reminder application written in HTML (Makes use of Local Storage API)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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" /> s | |
<input id="mTimeIntervalTF" type="text" size="4" title="Minutes" /> m | |
<input id="hTimeIntervalTF" type="text" size="4" title="Hours" /> h | |
</td> | |
</tr> | |
<tr> | |
<td> | |
</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