Add support for Fischer increment
[jschessclock.git] / script.js
CommitLineData
72b294bb 1"use strict";
2
3function Timer(id) {
4 var precision = 100; // milliseconds
5 var defaultTime = (15 * 60 + 0) * 1000; // milliseconds
6 var time = defaultTime;
7 var intervalID;
8 this.isTicking = false;
59026107
AIL
9 var increment = 0;
10 var defaultIncrement = 0;
11
72b294bb 12 var outputTime = function() {
13 document.getElementById(id).innerHTML = timeToTimeStr(time);
14 var flagid = "flag-" + id.split('-')[1];
15 var flagelem = document.getElementById(flagid);
16 flagelem.style.visibility = time <= 0 ? "visible" : "hidden";
59026107
AIL
17 var incid = "increment-" + id.split('-')[1];
18 var incelem = document.getElementById(incid);
19 incelem.innerHTML = "+" + (increment / 1000).toString();
20 incelem.style.visibility = increment > 0 ? "visible" : "hidden";
72b294bb 21 };
6f474901
AIL
22
23 var startTickingUnixTime = null;
24 var remainingTimeAtTickingStart = null;
25
72b294bb 26 var thisTimer = this; // workaround to use this in setInterval
27 this.tick = function() {
6f474901
AIL
28 var currentPassedTime = new Date() - startTickingUnixTime;
29 time = remainingTimeAtTickingStart - currentPassedTime;
72b294bb 30 if(time <= 0) {
6f474901 31 time = 0;
72b294bb 32 // time's up
33 clearInterval(intervalID);
34 thisTimer.isTicking = false;
35 }
36 outputTime();
37 };
38 this.start = function() {
6f474901
AIL
39 startTickingUnixTime = new Date();
40 remainingTimeAtTickingStart = time;
72b294bb 41 intervalID = setInterval(this.tick, precision);
42 this.isTicking = true;
43 };
59026107 44 this.stop = function(toggle = false) {
72b294bb 45 clearInterval(intervalID);
46 this.isTicking = false;
59026107
AIL
47 if (toggle && this.getTime() > 0) {
48 this.setTime(this.getTime() + increment, increment, true);
49 }
72b294bb 50 };
59026107 51 this.setTime = function(t, inc = 0, toggle = false) {
72b294bb 52 time = t;
59026107
AIL
53 increment = inc;
54 if (!toggle) {
55 defaultTime = t;
56 defaultIncrement = inc;
57 }
72b294bb 58 outputTime();
59 };
60 this.getTime = function() {
61 return time;
62 };
63 this.reset = function() {
64 if(this.isTicking) {
65 this.stop();
66 }
59026107 67 this.setTime(defaultTime, defaultIncrement);
72b294bb 68 };
69 this.getDefaultTime = function() {
70 return defaultTime;
71 };
72}
73
74var currentTimers = new (function() {
75 this.leftTimer = new Timer("timer-left");
76 this.rightTimer = new Timer("timer-right");
77 this.active = this.leftTimer;
78 this.passive = this.rightTimer;
79 this.isPaused = true;
80 this.swap = function() {
81 var tmp = this.passive;
82 this.passive = this.active;
83 this.active = tmp;
84 var icon = document.getElementById("play");
59026107 85 icon.innerHTML = (icon.innerHTML == "⏴" ? "⏵" : "⏴");
72b294bb 86 };
87 this.pause = function() {
88 this.active.stop();
89 this.isPaused = true;
90 document.getElementById("pause").style.visibility = "visible";
91 };
92 this.resume = function() {
93 this.active.start();
94 this.isPaused = false;
95 document.getElementById("pause").style.visibility = "hidden";
96 };
97})();
98
99function timeStrToTime(timeStr) {
100 var minute = parseInt(timeStr.substr(0, 2));
101 var second = parseInt(timeStr.substr(3, 2));
102 return (minute * 60 + second) * 1000;
103}
104
105function timeToTimeStr(time) {
106 var minute = Math.floor(time / 1000 / 60);
107 var second = Math.floor(time / 1000) % 60;
108 if(minute < 10) {
109 minute = '0' + minute.toString();
110 }
111 if(second < 10) {
112 second = '0' + second.toString();
113 }
114 return minute + ':' + second;
115}
116
117document.onkeydown = function(e) {
118 if(e.key) {
119 switch(e.key) {
120 case ' ': return toggle();
121 case 'S':
122 case 's': return setTime();
123 case 'R':
124 case 'r': return reset();
125 case 'p':
126 case 'P': return pauseResume();
127 default: return;
128 }
129 } else if(e.keyCode) {
130 switch(e.keyCode) {
131 case 32: return toggle(); // space
132 case 83: return setTime(); // S
133 case 82: return reset(); // R
134 case 80: return pauseResume(); // P
135 default: return;
136 }
137 } else {
138 alert("Browser not supported");
139 }
140};
141
142function toggle() {
143 if(!currentTimers.isPaused) {
59026107 144 currentTimers.active.stop(true);
72b294bb 145 currentTimers.passive.start();
146 }
147 currentTimers.swap();
148 var lbt = document.getElementById('left-button-top');
149 var leftIsLong = lbt.getAttribute('class') == 'button-long';
150 var lbt_d = lbt.getAttribute('d').split(' ');
151 var lbb = document.getElementById('left-button-body');
152 var rbt = document.getElementById('right-button-top');
153 var rbt_d = rbt.getAttribute('d').split(' ');
154 var rbb = document.getElementById('right-button-body');
6f474901 155
72b294bb 156 var y_diff = 50 * (leftIsLong ? 1 : -1);
157 var classes = ['button-short', 'button-long'];
158
159 lbt_d[2] = (parseInt(lbt_d[2]) + y_diff).toString();
160 lbt_d[10] = (parseInt(lbt_d[10]) + y_diff).toString();
161 lbb.setAttribute('height',
162 (parseInt(lbb.getAttribute('height')) - y_diff).toString());
163 lbb.setAttribute('y', (parseInt(lbb.getAttribute('y')) + y_diff).toString());
164 rbt_d[2] = (parseInt(rbt_d[2]) - y_diff).toString();
165 rbt_d[10] = (parseInt(rbt_d[10]) - y_diff).toString();
166 rbb.setAttribute('height',
167 (parseInt(rbb.getAttribute('height')) + y_diff).toString());
168 rbb.setAttribute('y', (parseInt(rbb.getAttribute('y')) - y_diff).toString());
169 lbt.setAttribute('class', classes[(leftIsLong + 1) % 2]);
170 lbb.setAttribute('class', classes[(leftIsLong + 1) % 2]);
171 rbt.setAttribute('class', classes[(leftIsLong + 1) % 2]);
172 rbb.setAttribute('class', classes[(leftIsLong + 1) % 2]);
173 lbt.setAttribute('d', lbt_d.join(' '));
174 rbt.setAttribute('d', rbt_d.join(' '));
6f474901 175
72b294bb 176 lbt.setAttribute('onclick', leftIsLong ? '' : 'toggle()');
177 lbb.setAttribute('onclick', leftIsLong ? '' : 'toggle()');
178 lbt.setAttribute('cursor', leftIsLong ? 'default' : 'pointer');
179 lbb.setAttribute('cursor', leftIsLong ? 'default' : 'pointer');
180 rbt.setAttribute('onclick', leftIsLong ? 'toggle()' : '');
181 rbb.setAttribute('onclick', leftIsLong ? 'toggle()' : '');
182 rbt.setAttribute('cursor', leftIsLong ? 'pointer' : 'default');
183 rbb.setAttribute('cursor', leftIsLong ? 'pointer' : 'default');
184}
185
186function pauseResume() {
187 if(currentTimers.isPaused) {
188 currentTimers.resume();
189 } else {
190 currentTimers.pause();
191 }
192}
193
194function setTime() {
195 var leftstart, rightstart;
196 var def = timeToTimeStr(currentTimers.leftTimer.getDefaultTime());
59026107 197 var regex = /[0-9][0-9]:[0-5][0-9](\+[0-9]+)?/;
6f474901 198
59026107 199 leftstart = prompt("Time for LEFT player in MM:SS or MM:SS+S", def);
72b294bb 200 if(leftstart === null) return; // Cancel
201 while(!leftstart.match(regex)) {
59026107 202 leftstart = prompt("Invalid value\nTime for LEFT player in MM:SS or MM:SS+S", def);
72b294bb 203 if(leftstart === null) return; // Cancel
204 }
205 def = leftstart;
59026107 206 rightstart = prompt("Time for RIGHT player in MM:SS or MM:SS+S", def);
72b294bb 207 if(rightstart === null) return; // Cancel
208 while(!rightstart.match(regex)) {
59026107 209 rightstart = prompt("Invalid value\nTime for RIGHT player in MM:SS or MM:SS+S", def);
72b294bb 210 if(rightstart === null) return; // Cancel
211 }
59026107
AIL
212
213 if(leftstart.indexOf('+') > 0) {
214 var baseTime = leftstart.split('+')[0];
215 var inc = leftstart.split('+')[1];
216 currentTimers.leftTimer.setTime(timeStrToTime(baseTime), parseInt(inc) * 1000);
217 }
218 else {
219 currentTimers.leftTimer.setTime(timeStrToTime(leftstart));
220 }
221 if(rightstart.indexOf('+') > 0) {
222 var baseTime = rightstart.split('+')[0];
223 var inc = rightstart.split('+')[1];
224 currentTimers.rightTimer.setTime(timeStrToTime(baseTime), parseInt(inc) * 1000);
225 }
226 else {
227 currentTimers.rightTimer.setTime(timeStrToTime(leftstart));
228 }
72b294bb 229}
230
231function reset() {
232 currentTimers.pause();
233 currentTimers.active.reset();
234 currentTimers.passive.reset();
235}
236
237function init() {
238 insertcss();
6f474901 239 setTimeout(fitscreen, 2000); // hack to allow DOM to be redrawn with new css
72b294bb 240}
241
242function fitscreen() {
243 /*
244 * Scale body so as to fit the screen
245 */
246 var heightRatio = window.innerHeight / document.body.scrollHeight;
247 var widthRatio = window.innerWidth / document.body.scrollWidth;
6f474901 248 var scaleRatio = Math.min(heightRatio, widthRatio, 1);
72b294bb 249 document.body.style.transform = 'scale(' + scaleRatio + ')';
250}
251
252function insertcss() {
253 /* fix positions for browsers that don't support flex */
6f474901
AIL
254 var cssfile = document.getElementById("style");
255 if(!('align-items' in document.body.style)) {
72b294bb 256 cssfile.setAttribute("href", "noflex.css");
257 }
72b294bb 258}