Skip to content

Instantly share code, notes, and snippets.

@alichay
Created March 5, 2019 19:38
Show Gist options
  • Save alichay/5cea67420da04f489f778ae9a3da49e0 to your computer and use it in GitHub Desktop.
Save alichay/5cea67420da04f489f778ae9a3da49e0 to your computer and use it in GitHub Desktop.
It's not pretty, but it works.
<!DOCTYPE html>
<html>
<head>
<!-- By Zachary Pierson -->
<meta charset='utf-8'>
<title>Time conversion</title>
<style>
html {
font-size: .9em;
}
body {
padding: 30px 30px;
margin: 0 0;
}
* {
font-family: 'Segoe UI', 'Roboto', 'Helvetica Neue', sans-serif;
}
h1 {
margin-top: 0;
position: relative;
padding-left: .5em;
}
h1::before {
content: "";
position: absolute;
top: 50%;
left: 0;
height: .8em;
width: .17em;
background: rgba(0, 0, 0, 0.2);
transform: translateY(-50%) translateY(2px);
}
.converter {
display: flex;
flex-direction: row;
align-items: stretch;
position: relative;
}
.converter::before {
content: '';
display: block;
position: absolute;
z-index: -1;
left: -700px;
right: -700px;
top: 0;
bottom: 0;
box-shadow: inset 0 0 2px rgba(0,0,0,0.2)
}
.converter:nth-child(odd)::before {
background: #f6f6f6;
box-shadow: inset 0 0 2px rgba(0,0,0,0.3)
}
#converter-total::before {
background: #c6ffc6;
}
.field {
flex: 1;
font-size: 1.3em;
padding-bottom: 1.2em;
padding-top: .8em;
position: relative;
}
input {
display: block;
width: 100%;
box-sizing: border-box;
font-size: 1.2em;
}
.label {
display: block;
font-weight: 600;
margin-bottom: .3em;
}
@media(max-width: 575px) {
.converter {
display: block;
flex-direction: initial;
align-items: initial;
}
.field {
flex: initial;
display: block;
margin: 30px 0;
}
.divider {
display: none;
}
}
@media(max-width: 340px) {
h1::before {content: none}
h1 {padding-left: 0}
body {font-size: .8em;}
}
@media(max-width: 270px) {
body {font-size: .5em;}
}
@media(max-width: 190px) {
body {font-size: .3em;}
}
@media(min-width: 750px) {
#converter {
margin: 40px 0;
}
}
@media(min-width: 1000px) {
body {
width: 1000px;
box-sizing: border-box;
text-align: left;
display: inline-block;
}
html {
text-align: center;
}
}
#swap-mode {
display: block;
text-align: center;
line-height: 3em;
background-color: #505050;
color: #fff;
margin-top: 30px;
font-size: 1.3em;
font-weight: 700;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.0);
transition: background-color 0.3s ease-in-out, box-shadow 0.3s ease-in-out, transform 0.3s ease-in-out;
cursor: pointer;
transform: translateY(0);
}
#swap-mode:hover {
box-shadow: 0 0 30px rgba(0, 0, 0, 0.3);
background-color: #555055;
transform: translateY(-2px);
}
.rounding-info {
display: inline-block;
position: absolute;
width: 100%;
font-size: .8em;
margin-top: 0.5em;
color: #303030;
transition: opacity 0.4s ease-in-out;
}
.rounding-info.trans {
opacity: 0;
}
.rounding-info.error {
color: #802020;
opacity: 1;
}
.rounding-info.error::before {
content: "Input error: ";
font-weight: 600;
height: 5em;
float: left;
margin-right: .3em;
}
</style>
</head>
<body>
<h1>Time conversion - Week</h1>
<div id='converter-0' class='converter'>
<div class='input field'>
<span class='label'>Input</span>
<input class='input-tf'>
</div>
<div class="divider" style="width: 20px"></div>
<div class='output field'>
<span class='label'>Output</span>
<input class='output-tf'>
<span class='rounding-info'></span>
</div>
</div>
<div id='converter-1' class='converter'>
<div class='input field'>
<span class='label'>Input</span>
<input class='input-tf'>
</div>
<div class="divider" style="width: 20px"></div>
<div class='output field'>
<span class='label'>Output</span>
<input class='output-tf'>
<span class='rounding-info'></span>
</div>
</div>
<div id='converter-2' class='converter'>
<div class='input field'>
<span class='label'>Input</span>
<input class='input-tf'>
</div>
<div class="divider" style="width: 20px"></div>
<div class='output field'>
<span class='label'>Output</span>
<input class='output-tf'>
<span class='rounding-info'></span>
</div>
</div>
<div id='converter-3' class='converter'>
<div class='input field'>
<span class='label'>Input</span>
<input class='input-tf'>
</div>
<div class="divider" style="width: 20px"></div>
<div class='output field'>
<span class='label'>Output</span>
<input class='output-tf'>
<span class='rounding-info'></span>
</div>
</div>
<div id='converter-4' class='converter'>
<div class='input field'>
<span class='label'>Input</span>
<input class='input-tf'>
</div>
<div class="divider" style="width: 20px"></div>
<div class='output field'>
<span class='label'>Output</span>
<input class='output-tf'>
<span class='rounding-info'></span>
</div>
</div>
<div id='converter-5' class='converter'>
<div class='input field'>
<span class='label'>Input</span>
<input class='input-tf'>
</div>
<div class="divider" style="width: 20px"></div>
<div class='output field'>
<span class='label'>Output</span>
<input class='output-tf'>
<span class='rounding-info'></span>
</div>
</div>
<div id='converter-6' class='converter'>
<div class='input field'>
<span class='label'>Input</span>
<input class='input-tf'>
</div>
<div class="divider" style="width: 20px"></div>
<div class='output field'>
<span class='label'>Output</span>
<input class='output-tf'>
<span class='rounding-info'></span>
</div>
</div>
<div id='converter-total' class='converter'>
<div class='input field'>
<span class='label'>Total</span>
<input class='input-tf' id='total-input' placeholder="26.25">
</div>
<div class="divider" style="width: 20px"></div>
<div class='output field'>
<span class='label'>&nbsp;</span>
<input class='output-tf' id='total-output' placeholder="26 hour, 15 minutes">
</div>
</div>
<div id='swap-mode'>&larr; SWAP DIRECTION &rarr;</div>
<script>
var swap_mode = document.getElementById('swap-mode');
var ttf_regex = /^[\s]*(\d+(?:\.\d+)?)(?:[\s]*(?:hours|hour|hrs|hr|h)[\s]*,*[\s]*(?:and)?[\s]*)(\d+(?:\.\d+)?)(?:[\s]*(?:minutes|minute|mins|min|m)[\s]*,*[\s]*(?:and)?[\s]*)/
var total_b = document.getElementById('total-input');
var total_a = document.getElementById('total-output');
var FLOAT_TO_TIME = 0;
var TIME_TO_FLOAT = 1;
var mode = 1; // When setMode runs, this gets changed to 0 on the first run.
var placeholders = [
["2.5", "2 hours, 30 minutes"],
["3.25", "3 hours, 15 minutes"],
["3", "3 hours"],
[".25", "15 minutes"],
["10.75", "10 hours, 45 minutes"],
["1", "1 hour"],
["5.5", "5 hour, 30 minutes"]
];
var WEEK = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
function set_input_untouchable(i) {
function DENY(e) {
e.preventDefault();
return false;
}
i.addEventListener('change', DENY);
i.addEventListener('keydown', DENY);
i.addEventListener('keyup', DENY);
i.addEventListener('input', DENY);
i.addEventListener('paste', DENY);
i.addEventListener('cut', DENY)
}
set_input_untouchable(total_a);
set_input_untouchable(total_b);
total_b.addEventListener('keydown', function(e) {
if(e.keyCode == 9) {
e.preventDefault();
total_a.focus();
return false;
}
});
total_a.addEventListener('keydown', function(e) {
if(e.keyCode == 9) {
e.preventDefault();
document.getElementById('converter-0').getElementsByClassName('input-tf')[0].focus();
return false;
}
});
var times = [0,0,0,0,0,0,0];
var h_m_to_str = function(hour, min) {
var hour_str = "";
if(hour > 0) {
hour_str = hour + " hour" + (hour > 1 ? 's' : '');
}
var min_str = "";
if(min > 0) {
min_str = min + " minute" + (min > 1 ? 's' : '');
}
return (hour_str + " " + min_str).trim();
}
var h_m_to_flo = function(h, m) {
var minstr = String(m / 60).substr(2, 4);
return h + (minstr != "" ? ("." + minstr) : "");
}
var elems = [];
function update_total() {
var h = 0, m = 0;
for(var i = 0; i < elems.length; i++) {
var v = elems[i].value;
h += v[0];
m += v[1];
if(m >= 60) {
h += 1;
m -= 60;
}
}
total_a.value = h_m_to_str(h, m);
total_b.value = h_m_to_flo(h, m);
//total.value = (mode == FLOAT_TO_TIME ? h_m_to_str : h_m_to_flo)(h, m);
}
function init_converter() {
var id = elems.length;
var converter = document.getElementById('converter-' + id);
var labels = converter.getElementsByClassName('label');
for(var j = 0; j < labels.length; j++) {
labels[j].textContent += ' - ' + WEEK[id];
}
var input_tf = converter.getElementsByClassName('input-tf')[0];
var output_tf = converter.getElementsByClassName('output-tf')[0];
var round_info = converter.getElementsByClassName('rounding-info')[0];
set_input_untouchable(output_tf);
var placeholder_float = "2.5";
var placeholder_time = "2 hours, 30 minutes";
var err_clock = 0;
var setErr = function(e) {
round_info.className = 'trans';
err_clock = setTimeout((function(e) {return function() {
round_info.className = 'error';
round_info.textContent = e;
}})(e), 400);
elems[id].value = [0, 0];
update_total();
};
input_tf.addEventListener('keydown', function(e) {
if(e.keyCode == 9) {
e.preventDefault();
var conv = 'converter-' + (id + 1);
if(id == 6) {
conv = 'converter-total';
}
document.getElementById(conv).getElementsByClassName('input-tf')[0].focus();
return false;
}
})
var compute_ftt = function(_v) {
clearTimeout(err_clock);
round_info.className = '';
round_info.textContent = '';
if(_v == undefined || _v == null || _v.trim() == "") return "";
var val = Number(_v);
console.log(val, val == NaN);
if(isNaN(val)) {
setErr("Invalid input. Please ensure it follows a format like \"2.5\"");
return "";
}
var integer_component = Math.floor(val);
var decimal_component = val - integer_component;
var hour = integer_component;
var min_raw = decimal_component * 60;
var min = Math.round(min_raw);
if(min != min_raw) {
round_info.textContent = 'Minutes rounded ' + (min_raw > min ? 'down' : 'up') + ' from ' + min_raw;
}
elems[id].value = [hour, min];
update_total();
return h_m_to_str(hour, min);
}
var compute_ttf = function(v) {
clearTimeout(err_clock);
round_info.className = '';
round_info.textContent = '';
if(v == undefined || v == null || v.trim() == "") return "";
var matches = ttf_regex.exec(v);
// Absolutely disgusting hack, but it'll work for now.
if(matches == null) {
matches = ttf_regex.exec("0 hours " + v);
if(matches == null) {
matches = ttf_regex.exec(v + " 0 minutes");
}
}
//if(matches == null) {
// setErr("Invalid input. Please ensure it follows a format like \"2\"");
// return "";
//}
if(matches == null) {
setErr("Please ensure it follows a format like \"2 hours 30 minutes\" or \"2hrs 5min\"");
return "";
}
var hours = Number(matches[1]);
var mins = Number(matches[2]);
if(isNaN(hours)) {
setErr("Unable to interpret number of hours.");
return "";
}
if(isNaN(mins)) {
setErr("Unable to interpret number of minutes.");
return "";
}
elems[id].value = [hours, mins];
update_total();
return h_m_to_flo(hours, mins);
}
var input_change = function(e) {
output_tf.value = elems[id].compute_proc(input_tf.value);
}
input_tf.addEventListener('input', input_change);
input_tf.addEventListener('keyup', input_change);
elems.push({
"input_tf": input_tf,
"output_tf": output_tf,
"input_change": input_change,
"compute_proc": null,
"compute_ftt": compute_ftt,
"compute_ttf": compute_ttf,
"value": [0, 0]
});
}
function setMode() {
mode = (mode + 1) % 2;
//total.placeholder = placeholders[placeholders.length - 1][mode == FLOAT_TO_TIME ? 1 : 0];
for(var i = 0; i < elems.length; i++) {
var elem = elems[i];
elem.compute_proc = mode == FLOAT_TO_TIME ? elem.compute_ftt : elem.compute_ttf;
elem.input_tf.value = elem.output_tf.value;
elem.input_tf.placeholder = placeholders[i][mode == FLOAT_TO_TIME ? 0 : 1];
elem.output_tf.placeholder = placeholders[i][mode == FLOAT_TO_TIME ? 1 : 0];
elem.input_change();
}
}
for(var i = 0; i < 7; i++)
init_converter();
setMode();
swap_mode.addEventListener('click', function(e) {
e.preventDefault();
setMode();
})
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment