Skip to content

Commit 42c8812

Browse files
committed
Basic interest calculator example.
1 parent 637f209 commit 42c8812

File tree

3 files changed

+229
-1
lines changed

3 files changed

+229
-1
lines changed

scratch.css

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,3 +300,49 @@ p {
300300
.matrixcontainer {
301301
margin: auto;
302302
}
303+
304+
:focus {
305+
outline: 1px dashed green;
306+
}
307+
308+
.view {
309+
border: 1px solid black;
310+
width: 400px;
311+
height: 200px;
312+
}
313+
314+
form table td {
315+
border: none;
316+
}
317+
318+
form td {
319+
width: 200px;
320+
text-align: right;
321+
}
322+
323+
#diagram td select,
324+
#diagram td input {
325+
text-align: left;
326+
width: 150px;
327+
}
328+
329+
#diagram {
330+
padding: 20px;
331+
margin-top: 50px;
332+
margin-left: 10%;
333+
}
334+
335+
#diagram td {
336+
vertical-align: bottom;
337+
text-align: center;
338+
padding: 10px;
339+
border: none;
340+
}
341+
342+
#diagram th {
343+
border: none;
344+
}
345+
346+
#diagram div {
347+
margin: auto;
348+
}

scratch.html

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,79 @@ <h1>Neptune</h1>
597597
</div>
598598

599599
<div id="preload" class="scratch"></div>
600+
601+
<div class="scratch">
602+
<p>Add an option "Jazz" using JS.</p>
603+
<select id="genres">
604+
<option value="rock">Rock</option>
605+
<option value="blues" selected>Blues</option>
606+
</select>
607+
</div>
608+
609+
<div class="scratch">
610+
<div class="codeblock">codeblock 1</div>
611+
<div class="codeblock">codeblock 2</div>
612+
<div class="codeblock">codeblock 3</div>
613+
<div class="codeblock">codeblock 4</div>
614+
</div>
615+
616+
<div class="scratch">
617+
<div id="view" class="view">Text</div>
618+
</div>
619+
620+
<div class="scratch">
621+
Hotkey example: press '<b>q</b>' and '<b>w</b>' simultaneously.
622+
</div>
623+
624+
<div class="scratch">
625+
<form name="calculator">
626+
<table>
627+
<tr>
628+
<td>Initial deposit</td>
629+
<td>
630+
<input name="money" type="number" value="10000" required>
631+
</td>
632+
</tr>
633+
<tr>
634+
<td>How many months?</td>
635+
<td>
636+
<select name="months">
637+
<option value="3">3 (minimum)</option>
638+
<option value="6">6 (half-year)</option>
639+
<option value="12" selected>12 (one year)</option>
640+
<option value="18">18 (1.5 years)</option>
641+
<option value="24">24 (2 years)</option>
642+
<option value="30">30 (2.5 years)</option>
643+
<option value="36">36 (3 years)</option>
644+
<option value="60">60 (5 years)</option>
645+
</select>
646+
</td>
647+
</tr>
648+
<tr>
649+
<td>Interest per year?</td>
650+
<td>
651+
<input name="interest" type="number" value="5" required>
652+
</td>
653+
</tr>
654+
</table>
655+
</form>
656+
<table id="diagram">
657+
<tr>
658+
<th>Was:</th>
659+
<th>Becomes:</th>
660+
</tr>
661+
<tr>
662+
<th id="money-before"></th>
663+
<th id="money-after"></th>
664+
</tr>
665+
<td>
666+
<div style="background: red;width:40px;height:100px" id="height-before"></div>
667+
</td>
668+
<td>
669+
<div style="background: green;width:40px;height:0" id="height-after"></div>
670+
</td>
671+
</table>
672+
</div>
600673
</body>
601674

602675
</html>

script.ts

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ interface HTMLCollection {
2020
HTMLCollection.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
2121

2222
//
23-
// Functions for total document height and width
23+
// Utility functions
2424
//
2525
function documentScrollHeight(): number {
2626
return Math.max(
@@ -75,6 +75,25 @@ function preloadImages(sources: string[], callback: (images: HTMLImageElement[])
7575
}
7676
}
7777

78+
function copyStyle(from: HTMLElement, to: HTMLElement) {
79+
let style = getComputedStyle(from);
80+
to.style.width = style.width;
81+
to.style.height = style.height;
82+
to.style.border = style.border;
83+
to.style.padding = style.padding;
84+
to.style.margin = style.margin;
85+
to.style.font = style.font;
86+
}
87+
88+
function isSubset<T>(subset: Set<T>, ofSet: Set<T>) {
89+
for (let x of subset) {
90+
if (!ofSet.has(x)) {
91+
return false;
92+
}
93+
}
94+
return true;
95+
}
96+
7897
// This is where the example code starts. Only do this after the
7998
// load event to ensure image sizes are known, otherwise some code
8099
// fails to work.
@@ -834,6 +853,78 @@ window.addEventListener("load", () => {
834853
document.addEventListener("scroll", imageLoader);
835854
}
836855
}
856+
857+
//
858+
// Add an option to select
859+
//
860+
861+
let genres = document.getElementById("genres") as HTMLSelectElement;
862+
genres.options.add(new Option("Jazz", "jazz", true, true), 0);
863+
864+
//
865+
// Add a tabindex (to allow focusing) to all codeblocks
866+
//
867+
let codeblocks = document.querySelectorAll(".codeblock");
868+
let tabIndex = 1;
869+
for (let codeblock of codeblocks) {
870+
codeblock.setAttribute("tabindex", String(tabIndex++));
871+
}
872+
873+
//
874+
// Turn a div into an editable textarea
875+
//
876+
let view = document.getElementById("view") as HTMLElement;
877+
view.tabIndex = 1;
878+
view.addEventListener("focus", () => {
879+
let textArea = document.createElement("textarea");
880+
textArea.textContent = view.innerHTML;
881+
copyStyle(view, textArea);
882+
textArea.addEventListener("blur", () => {
883+
view.innerHTML = textArea.value;
884+
textArea.after(view);
885+
textArea.remove();
886+
});
887+
view.after(textArea);
888+
view.remove();
889+
textArea.focus();
890+
});
891+
892+
//
893+
// Interest calculator that updates immediately on every input value change
894+
//
895+
let heightAfter = document.getElementById("height-after") as HTMLElement;
896+
let heightBefore = document.getElementById("height-before") as HTMLElement;
897+
let moneyBefore = document.getElementById("money-before") as HTMLElement;
898+
let moneyAfter = document.getElementById("money-after") as HTMLElement;
899+
let form = document.forms[0];
900+
let initialDeposit = form.money as HTMLInputElement;
901+
let months = form.months as HTMLSelectElement;
902+
let interest = form.interest as HTMLInputElement;
903+
904+
function updateChart() {
905+
let before = Number(initialDeposit.value);
906+
if (before) {
907+
moneyBefore.textContent = "$" + before;
908+
} else {
909+
moneyBefore.textContent = "$0";
910+
}
911+
912+
let multiple = Math.pow(1 + Number(interest.value) / 100, Number(months.value) / 12);
913+
if (multiple > 0) {
914+
let after = Math.round(before * multiple);
915+
moneyAfter.textContent = "$" + after;
916+
heightAfter.style.height =
917+
heightBefore.getBoundingClientRect().height * (after / before) + "px";
918+
} else {
919+
heightAfter.style.height = "0";
920+
moneyAfter.textContent = "$0";
921+
}
922+
}
923+
924+
initialDeposit.addEventListener("input", () => updateChart());
925+
months.addEventListener("input", () => updateChart());
926+
interest.addEventListener("input", () => updateChart());
927+
updateChart();
837928
});
838929

839930
//
@@ -867,3 +958,21 @@ function testLoaded(images: HTMLImageElement[]) {
867958

868959
// every image is 100x100, the total width should be 300
869960
preloadImages(sources, testLoaded);
961+
962+
//
963+
// Extended Hotkeys example
964+
//
965+
function runOnKeys(f: () => void, ...codes: string[]) {
966+
let currentlyPressedKeys = new Set();
967+
let hotKeys = new Set(codes);
968+
document.addEventListener("keydown", event => {
969+
currentlyPressedKeys.add(event.code);
970+
if (isSubset(hotKeys, currentlyPressedKeys)) {
971+
f();
972+
currentlyPressedKeys.clear();
973+
}
974+
});
975+
document.addEventListener("keyup", event => currentlyPressedKeys.delete(event.code));
976+
}
977+
978+
runOnKeys(() => alert("Pressed hotkey!"), "KeyQ", "KeyW");

0 commit comments

Comments
 (0)