1
+ <!DOCTYPE html>
2
+ < html lang ="en ">
3
+ < head >
4
+ < meta charset ="UTF-8 ">
5
+ < meta name ="viewport " content ="width=device-width, initial-scale=1.0 ">
6
+ < meta http-equiv ="X-UA-Compatible " content ="ie=edge ">
7
+ < title > Stateless Timer App</ title >
8
+ < style >
9
+ # divTimer {
10
+ font-size : 3em ;
11
+ }
12
+ </ style >
13
+ </ head >
14
+ < body >
15
+ < h3 > Stateless App</ h3 >
16
+
17
+ < button id = 'btnStartTimer '> Start Timer</ button >
18
+ < button id = 'btnCancelTimer '> Cancel Timer</ button >
19
+
20
+ < div id = 'divTimer '>
21
+
22
+ </ div >
23
+ < script >
24
+ /*
25
+ stateful application
26
+ 0 No Timer - Start Button is visible and Cancel is hidden
27
+ 1 Timer Running - Start button is hidden cancel is visible
28
+ */
29
+ //initial state is always 0
30
+ //if the state is 1 then timeEnd should have the time it ends
31
+ let appState = {
32
+ "state" : 0 ,
33
+ "timeEnd" : null
34
+ }
35
+
36
+ const btnStartTimer = document . getElementById ( "btnStartTimer" ) ;
37
+ const btnCancelTimer = document . getElementById ( "btnCancelTimer" ) ;
38
+ const divTimer = document . getElementById ( "divTimer" ) ;
39
+
40
+ const result = getCookie ( "timerState" ) ;
41
+ if ( result != "" )
42
+ appState = JSON . parse ( result ) ;
43
+
44
+ updateState ( appState )
45
+ resumeState ( appState )
46
+
47
+ btnStartTimer . addEventListener ( "click" , e => {
48
+ const timeEnd = new Date ( new Date ( ) . getTime ( ) + 30 * 1000 )
49
+ startTimer ( timeEnd )
50
+ } ) ;
51
+
52
+
53
+ btnCancelTimer . addEventListener ( "click" , e => {
54
+ cancelTimer ( )
55
+ } ) ;
56
+
57
+
58
+ function startTimer ( timeEnd ) {
59
+ appState . state = 1 ;
60
+ appState . timeEnd = timeEnd . toString ( ) ;
61
+ updateState ( appState ) ;
62
+ updateTimer ( timeEnd ) ;
63
+ }
64
+
65
+ function cancelTimer ( ) {
66
+ appState . state = 0 ;
67
+ appState . timeEnd = null ;
68
+ updateState ( appState )
69
+ }
70
+
71
+ function updateTimer ( ) {
72
+ const timeEnd = new Date ( appState . timeEnd )
73
+ const remainSeconds = Math . round ( ( timeEnd - ( new Date ( ) ) . getTime ( ) ) / 1000 )
74
+
75
+ divTimer . textContent = remainSeconds
76
+ //a cancel event might be sent
77
+
78
+ if ( remainSeconds <= 0 || appState . state === 0 ) {
79
+ appState . state = 0 ;
80
+ appState . timeEnd = null ;
81
+ updateState ( appState )
82
+ return ;
83
+ }
84
+
85
+
86
+ setTimeout ( updateTimer , 1000 ) ;
87
+ }
88
+
89
+ function resumeState ( state ) {
90
+ appState = state ;
91
+ if ( appState . state === 1 ) {
92
+ startTimer ( appState . timeEnd )
93
+ }
94
+ else
95
+ cancelTimer ( ) ;
96
+
97
+ }
98
+
99
+ function updateState ( appState ) {
100
+ if ( appState . state === 0 )
101
+ {
102
+ btnStartTimer . style . display = "block"
103
+ btnCancelTimer . style . display = "none"
104
+ divTimer . textContent = "" ;
105
+ }
106
+ else
107
+ {
108
+ btnStartTimer . style . display = "none"
109
+ btnCancelTimer . style . display = "block"
110
+ divTimer . textContent = "" ;
111
+ }
112
+
113
+ setCookie ( "timerState" , JSON . stringify ( appState ) )
114
+ }
115
+
116
+
117
+ function getCookie ( cname ) {
118
+ var name = cname + "=" ;
119
+ var decodedCookie = decodeURIComponent ( document . cookie ) ;
120
+ var ca = decodedCookie . split ( ';' ) ;
121
+ for ( var i = 0 ; i < ca . length ; i ++ ) {
122
+ var c = ca [ i ] ;
123
+ while ( c . charAt ( 0 ) == ' ' ) {
124
+ c = c . substring ( 1 ) ;
125
+ }
126
+ if ( c . indexOf ( name ) == 0 ) {
127
+ return c . substring ( name . length , c . length ) ;
128
+ }
129
+ }
130
+ return "" ;
131
+ }
132
+
133
+ function setCookie ( cname , cvalue , exdays ) {
134
+ var d = new Date ( ) ;
135
+ d . setTime ( d . getTime ( ) + ( exdays * 24 * 60 * 60 * 1000 ) ) ;
136
+ var expires = "expires=" + d . toUTCString ( ) ;
137
+ document . cookie = cname + "=" + cvalue + ";" + expires + ";path=/" ;
138
+ }
139
+
140
+
141
+
142
+ </ script >
143
+ </ body >
144
+ </ html >
0 commit comments