-
Notifications
You must be signed in to change notification settings - Fork 0
/
script.js
304 lines (253 loc) · 9.36 KB
/
script.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
// elements to manipulate/check
var timer = document.getElementById("timer");
var numberOfPresenters = document.getElementsByName("number-of-people")[0];
var timeInput = document.getElementsByName("time-minutes")[0];
var namesInput = document.getElementsByName("names")[0];
var submit = document.getElementById("submit-btn-1");
var firstForm = document.getElementById("first-form");
var welcomeMsg = document.getElementById("welcome-msg");
var welcome = document.getElementById("welcome");
var stopwatchArea = document.getElementById("stopwatch-area");
var noticeArea = document.getElementById("notice-area");
var timerArea = document.getElementById("timer");
var mainStartBtn = document.getElementById("main-timer-start-btn");
var mainTimerDisplay = document.getElementById("main-timer-display");
// global intervalID so it can easily be stopped by .clearInterval()
var intervalID;
if (!window) {
console.log("No window object: this script won't work if you're running it in an environment without a window object.");
}
// Timer "state" object, which is updated to include a key for each presenter, which has another object with presenter data/state
var timerState = {
created: false,
presenterSelected: undefined,
timerActive: false,
timeLeftMS: 0,
dateNow: 0
};
// first submit
firstForm.addEventListener("submit", validateInputsAndCreateArea);
function validateInputsAndCreateArea(event) {
event.preventDefault();
// clear old data on subsequent runs
if (timerState.created) {
timerState = {
created: false,
presenterSelected: undefined,
timerActive: false,
timeLeftMS: 0,
dateNow: 0
};
// clear top description of people and time per presenter
noticeArea.textContent = "";
//remove old eventListener to avoid it being called twice
stopwatchArea.removeEventListener("click", stopwatchAreaListenerCB);
// stop interval func
clearInterval(intervalID);
// reset start button text
mainStartBtn.textContent = "Start main timer";
}
timerState.created = true;
var peopleInputVal = numberOfPresenters.value;
var timeInputVal = timeInput.value;
var presentersNamesArr = namesInput.value.split(", ");
// input validation
if (peopleInputVal.match(/[^0-9]/g) || timeInputVal.match(/[^0-9]/g)) {
stopwatchArea.textContent = "";
welcomeMsg.textContent = "Please check your number inputs! Thanks";
welcomeMsg.classList.add("notice");
} else if (presentersNamesArr.length != peopleInputVal) {
stopwatchArea.textContent = "";
welcomeMsg.textContent =
"Please ensure that the number of names that you input matches the number of people presenting";
welcomeMsg.classList.add("notice");
} else {
welcomeMsg.textContent = "";
timerStatepeople = Number(peopleInputVal);
timerState.timeLeftMS = Number(timeInputVal) * 60 * 1000;
// populate stopwatch area after clearing it
stopwatchArea.textContent = "";
createStopwatchArea(
presentersNamesArr.length,
timerState.timeLeftMS,
presentersNamesArr
);
}
// scroll up to show notice, timer, etc
document.querySelector(".notice").scrollIntoView();
}
function timerFunc() {
// this is the function called every X ms by setInterval
if (timerState.timerActive === true) {
updateTimerStateObj();
updateTimerDisplay();
}
}
function updateTimerStateObj() {
// placeholder func to update timerState.timeLeft value, and the specific presenter's time taken
let timePassed;
timerState.dateNow > 0 ? timePassed = Date.now() - timerState.dateNow : timePassed = 1000;
timerState.timeLeftMS -= timePassed;
if (timerState.presenterSelected) {
timerState[timerState.presenterSelected].timeTakenMS += timePassed;
}
timerState.dateNow = Date.now()
}
function updateTimerDisplay() {
if (timerState.presenterSelected) {
document.getElementById(
timerState.presenterSelected + "_timer"
).textContent = convertToMinsSecs(
timerState[timerState.presenterSelected].timeTakenMS
);
}
if (timerState.timeLeftMS < 0) {
mainTimerDisplay.textContent = "Time up!";
} else {
mainTimerDisplay.textContent = convertToMinsSecs(timerState.timeLeftMS);
}
}
/*
convert ms value into a string of "mm:ss"
Example:
> convertToMinsSecs(1000) // => 0:01
*/
function convertToMinsSecs(ms) {
var formattedTime = [Math.floor(ms / 60000)];
// Add leading "0" to numbers under 10
formattedTime.push(("0" + Math.round((ms % 60000) / 1000)).slice(-2));
return formattedTime.join(":");
}
// main timer event listener function
mainStartBtn.addEventListener("click", mainStartBtnCB);
function mainStartBtnCB(e) {
// only create one setInterval. Hacky way to do it but it works fine, and I can't think of any obvious scenarios where this falls down...
// Easy alterntive is to create the setInterval on load, and never call it
if (e.target.textContent === "Start main timer") {
intervalID = window.setInterval(timerFunc, 998);
}
//activate timer via timerState object (timerFunc relies on this)
timerState.timerActive = !timerState.timerActive;
if (timerState.timerActive === true) {
e.target.textContent = "pause";
} else {
e.target.textContent = "resume";
timerState.dateNow = 0;
}
}
// function to create stopwatch area
// Needs refactoring!
function createStopwatchArea(numberOfPresenters, time, arrOfPresenters) {
// create "overview" text description
var areaIntro = document.createElement("p");
areaIntro.textContent =
"There are " +
numberOfPresenters +
" people presenting (" +
arrOfPresenters.join(", ") +
"), and each presenter should aim to present for " +
convertToMinsSecs(time / numberOfPresenters);
timerArea.classList.remove("hidden"); // display main timer
mainTimerDisplay.textContent = convertToMinsSecs(time);
areaIntro.classList.add("notice");
noticeArea.appendChild(areaIntro);
createTimerObjects(time / numberOfPresenters, arrOfPresenters);
// Create mini stopwatch divs for each presenter
for (var i = 0; i < numberOfPresenters; i++) {
createPresenterStopwatches(i);
}
// then call a function to add event listener to stopwatch area
stopwatchAreaListener();
}
stopwatchAreaListener = function() {
stopwatchArea.addEventListener("click", stopwatchAreaListenerCB);
};
function stopwatchAreaListenerCB(x) {
if (x.target.id.includes("presenter") && !x.target.id.includes("timer")) {
divSelectionHandler(x.target);
} else if (x.target.parentElement.id.includes("presenter")) {
// this else if statement is to handle any div children
divSelectionHandler(x.target.parentElement);
}
}
// function to make objects to track presenters' time
function createTimerObjects(timeMS, pplNames) {
pplNum = pplNames.length;
pplNames.forEach((p, i) => {
timerState["presenter_" + (i + 1)] = {
name: p,
timeAllocMS: timeMS,
timeTakenMS: 0
};
});
}
function createPresenterStopwatches(i) {
var presenterDiv = document.createElement("div");
var timerButton = document.createElement("button");
var presenterName = document.createElement("h3");
var presenterTime = document.createElement("span");
presenterDiv.classList.add("normal");
presenterDiv.id = "presenter_" + (i + 1);
presenterName.textContent = timerState["presenter_" + (i + 1)].name;
timerButton.textContent = "select";
presenterTime.classList.add("timer");
presenterTime.id = "presenter_" + (i + 1) + "_timer";
presenterTime.textContent = "0:00";
presenterDiv.appendChild(presenterName);
presenterDiv.appendChild(presenterTime);
presenterDiv.appendChild(timerButton);
stopwatchArea.appendChild(presenterDiv);
}
selectUserForTimer = function(usr) {
// if user already selected, "deselect" them
if (timerState.presenterSelected === usr) {
timerState.presenterSelected = undefined;
} else {
timerState.presenterSelected = usr;
}
};
// Rename to "person..."?
function divSelectionHandler(divClicked) {
divClicked.parentElement.childNodes.forEach(function(div) {
if (div.id === divClicked.id) {
if (div.id === timerState.presenterSelected) {
div.classList.remove("selected");
div.classList.add("normal");
div.getElementsByTagName("button")[0].textContent = "select";
timerState.presenterSelected = undefined;
} else {
div.classList.remove("normal");
div.classList.add("selected");
div.getElementsByTagName("button")[0].textContent = "deselect";
timerState.presenterSelected = div.id;
}
} else {
div.classList.remove("selected");
div.classList.add("normal");
div.getElementsByTagName("button")[0].textContent = "select";
}
});
}
// keyboard control - assuming up to 9 presenters
var numStrArr = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];
document.addEventListener("keydown", function(e) {
if (
numStrArr.includes(e.key) &&
!e.key.ctrlKey &&
e.srcElement.nodeName.toLowerCase() !== "input"
) {
var presenterToSelect = "presenter_" + e.key;
if (document.getElementById(presenterToSelect)) {
divSelectionHandler(document.getElementById(presenterToSelect));
}
} else if (
e.key === " " &&
e.srcElement.nodeName.toLowerCase() === "body" &&
!timer.classList.contains("hidden")
) {
// stop space bar from scrolling page
e.preventDefault();
// simulate click instead of calling mainStartBtnCB because the event needs to be passed in
mainStartBtn.click();
}
});