@@ -20,7 +20,7 @@ interface HTMLCollection {
2020HTMLCollection . prototype [ Symbol . iterator ] = Array . prototype [ Symbol . iterator ] ;
2121
2222//
23- // Functions for total document height and width
23+ // Utility functions
2424//
2525function 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
869960preloadImages ( 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