-
Notifications
You must be signed in to change notification settings - Fork 3
/
script.js
executable file
·483 lines (425 loc) · 14.3 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
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
// Initiate all variables
var events = [];
var input_event = document.getElementById("event-input");
var input_from = document.getElementById("from-time");
var input_to = document.getElementById("to-time");
var upload_button = document.getElementById("upload-button");
var events_display = document.getElementById("events-display");
var instant_button = document.getElementById("instant-button");
var page_turn_select = document.getElementById("page-turn-select");
var page_turn_interval = 5;
var display_order_select = document.getElementById("display-order-select");
var mode_select = document.getElementById("mode-select");
var writing = false;
// ----------------------------------------------------
// Quill configuration
var toolbar_options = [
["bold", "italic", "underline"],
[{ color: [] }],
[{ size: ["small", false, "large"] }],
[{ list: "ordered" }, { list: "bullet" }],
["clean"],
];
// Quill initialization
var quill = new Quill("#editor", {
theme: "snow",
placeholder: "Beschreiben Sie das Event...",
modules: {
toolbar: toolbar_options,
},
});
// ------------------------------------------------------
// Load all the events from the JSON file into the array (hard coded to know if php failed)
var loaded_events =
'[{"event":"PHP Loading Failed Mad check your permissions lmao ot call me","text":"","von":"2023-11-08T00:00","bis":"2023-11-08T23:59"}]';
events = JSON.parse(loaded_events);
display();
// Fetch the json file for the first time, write it into the events array and match the settings (mode, page_turn)
fetch("../output.json")
.then((response) => response.text())
.then((data) => {
loaded_events = data;
var parsed = JSON.parse(loaded_events);
events = parsed.slice(1);
mode_select.value = parsed[0].mode;
page_turn_select.value = parsed[0].page_turn.toString();
display();
})
.catch((error) => {
console.error("Error:", error);
});
// -------------------------------------------------------
page_turn_select.addEventListener("change", function () {
page_turn_interval = page_turn_select.value;
write_into_json();
});
// Pad a number with zeroes in front (used for dates display)
function pad(num, size) {
num = num.toString();
while (num.length < size) num = "0" + num;
return num;
}
// Write it into a simple JSON file server-side ../output.json
function write_into_json() {
const temp = [
{ page_turn: page_turn_interval, mode: mode_select.value },
...events,
];
fetch("saveFile.php", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(temp),
})
.then((response) => response.text())
.then((data) => {
// console.log(data); // Log the server's response
})
.catch((error) => {
console.error("Error:", error);
});
}
// Delete an event (will be activated on_click)
function button_delete(button) {
writing = true;
fetch("../output.json")
.then((response) => response.text())
.then((data) => {
loaded_events = data;
events = JSON.parse(loaded_events).slice(1);
// Loop through all the elements in arrallevents and see if they match with the button
for (var i = 0; i < events.length; i++) {
if (events[i].event == button.name) {
// If they match, delete the element and rerender
events.splice(i, 1);
display();
// Break the loop
break;
}
}
write_into_json();
})
.catch((error) => {
console.error("Error:", error);
});
writing = false;
}
// Sanitize HTML (good practice)
function sanitize_html(html) {
const parser = new DOMParser();
const doc = parser.parseFromString(html, "text/html");
// Convert sanitized content back to HTML string
return doc.body.innerHTML;
}
// Clean up some details from the raw HTML for it to fit into quill
function clean_quill_html(html) {
var ret = html;
// ret = html.replace("<p><br></p>", "");
return ret;
}
// Edit an event (will be activated on_click)
// Will delete the old event and put the current data into the input fields
function button_edit(button) {
writing = true;
// Loop through all the elements in arrallevents and see if they match with the button
fetch("../output.json")
.then((response) => response.text())
.then((data) => {
loaded_events = data;
events = JSON.parse(loaded_events).slice(1);
for (var i = 0; i < events.length; i++) {
if (events[i].event == button.name) {
// If they match, delete the element and rerender
input_event.value = events[i].event;
// Read the text from the events array
var text = events[i].text;
// Adjust it so that quill can work with it
var new_text = text.replace(/large-text/g, "ql-size-large");
text = new_text.replace(/small-text/g, "ql-size-small");
// Sanitize it with DOMParser
var html_string = text;
// Paste it in, but do some modifications after that
quill.clipboard.dangerouslyPasteHTML(html_string);
quill.root.innerHTML = clean_quill_html(quill.root.innerHTML);
// Enter the time
input_from.value = events[i].von;
input_to.value = events[i].bis;
// Delete it from the arrallevents
events.splice(i, 1);
// Break the loop
break;
}
}
// Update the json since now the event doesn't exist anymore adn rerender
write_into_json();
display();
})
.catch((error) => {
console.error("Error:", error);
});
writing = false;
}
// Add event listener to change of display_order to instantly rerender with the new order
display_order_select.addEventListener("change", display);
// Add event listener to change of mode and instantly write it into json
mode_select.addEventListener("change", write_into_json);
// Update the HTML doc to display all the existing events
function display() {
// display order
// option 1: earliest added
// option 2: last added / reverse of option 1
// option 3: lastest date last, earliest date first (e.g. run out in 10 secs from now first, run out in 2 days from now last)
// option 4: reverse of option 3
var events_html = "";
var option = display_order_select.value;
var ordered_events = [];
if (option === "1") {
// simplest case: just in the order they were added, newest on top, this is the way it is always in the arrallevents array
for (var i = 0; i < events.length; i++) {
ordered_events.push(events[i]);
}
} else if (option === "2") {
// reverse the order of arrallevents
for (var i = 0; i < events.length; i++) {
ordered_events.push(events[events.length - i - 1]);
}
} else if (option === "3") {
// sort by bis_date, earliest to lastest
ordered_events = [...events].sort((a, b) => a.bis - b.bis);
ordered_events.sort((a, b) => {
return new Date(a.bis).getTime() - new Date(b.bis).getTime();
});
} else if (option === "4") {
// sort in opposite order as option 3
ordered_events = events;
ordered_events.sort((a, b) => {
return new Date(b.bis).getTime() - new Date(a.bis).getTime();
});
}
ordered_events.forEach(function (x) {
var von_date = new Date(x.von);
var bis_date = new Date(x.bis);
// Convert date to a readable string
var date_von =
von_date.getDate() +
"." +
(von_date.getMonth() + 1) +
"." +
von_date.getFullYear() +
" " +
pad(von_date.getHours(), 2) +
":" +
pad(von_date.getMinutes(), 2);
var date_bis =
bis_date.getDate() +
"." +
(bis_date.getMonth() + 1) +
"." +
bis_date.getFullYear() +
" " +
pad(bis_date.getHours(), 2) +
":" +
pad(bis_date.getMinutes(), 2);
// Add a new HTML element
var print_text = x.text.replace(/\n/g, "<br>");
events_html += "<div class='event-div' ";
if (x.large === "large") {
events_html += "id='large-event'";
} else if (x.large === "pending") {
events_html += "id='unconfirmed-event'";
}
events_html += ">" + "<p class='event'><b><font size=5>" + x.event;
events_html += "</font></b>";
events_html += "<div><b>" + date_von + " - " + date_bis + "</b></div></p>";
if (x.text.replace(/<p><br><\/p>/g, "") !== "") {
events_html += "<div id='text-container'>" + print_text + "</div>";
}
events_html +=
"<button onclick='button_delete(this)' class='delete' name='" +
x.event +
"'>Löschen</button>" +
"<button onclick='button_edit(this)' class='edit' name='" +
x.event +
"'>Bearbeiten</button><label>Anheften:</label>" +
"<div class='body-checkbox'> <input id='checkbox-" +
x.event +
"' type='checkbox' onclick='pin(this)' class='glass-checkbox' name='" +
x.event +
"'";
if (x.pinned) {
events_html += " checked";
}
events_html +=
"><label for='checkbox-" +
x.event +
"' class='label-glass-checkbox'></label></div>" +
"</div>\n";
});
// console.log('events_string', event_string);
events_display.innerHTML = events_html;
}
// Retrieve HTML content from Quill editor
function get_content_as_html() {
var delta = quill.getContents();
var temp_cont = document.createElement("div");
new Quill(temp_cont).setContents(delta);
var html_content = temp_cont.querySelector(".ql-editor").innerHTML;
return html_content;
}
// Modify the HTML from quill to be compatible with the backend display AND the frontend
function modify_quill_html(htmlContent) {
var modified_html = htmlContent;
modified_html = modified_html.replace(/ql-size-large/g, "large-text");
modified_html = modified_html.replace(/ql-size-small/g, "small-text");
return modified_html;
}
// The "hochladen" button, used to add new events
upload_button.addEventListener("click", function () {
writing = true;
fetch("../output.json")
.then((response) => response.text())
.then((data) => {
loaded_events = data;
events = JSON.parse(loaded_events).slice(1);
var text = get_content_as_html();
text = modify_quill_html(text);
var data = {
event: input_event.value,
text: text,
von: input_from.value,
bis: input_to.value,
pinned: false,
large: "pending",
};
// SAFEGUARDS
if (input_event.value.includes("'")) {
alert("Das Zeichen ' darf nicht im Eventnamen sein!");
return;
}
if (input_event.value == "") {
alert("Kein Event angegeben!");
return;
}
if (!(isNaN(input_from.value) && isNaN(input_to.value))) {
alert("Datum muss angegeben sein!");
return;
}
// Check for time travelling
var von_ = new Date(input_from.value);
var bis_ = new Date(input_to.value);
if (bis_ <= von_) {
alert("Das Enddatum muss später als das Startdatum sein!");
return;
}
var current_date = new Date();
if (
von_.getTime() <= current_date - 1 * 60 * 1000
) {
alert("Das Begindatum muss in der Zukunft sein!");
return;
}
for (var i = 0; i < events.length; i++) {
if (events[i].event == data.event) {
alert("Nicht dasselbe Event zweimal eintragen!");
return;
}
}
// Write it in
events.push(data);
// Update the display and update the output file
display();
write_into_json();
// Clear the inputs
input_event.value = "";
quill.clipboard.dangerouslyPasteHTML("");
input_from.value = "";
input_to.value = "";
})
.catch((error) => {
console.error("Error:", error);
});
writing = false;
});
// Check the dates to see if they belong into oblivion
function check_events() {
if (writing) {
return;
}
fetch("../output.json")
.then((response) => response.text())
.then((data) => {
loaded_events = JSON.parse(data);
events = loaded_events.slice(1);
mode_select.value = loaded_events[0].mode;
page_turn_select.value = loaded_events[0].page_turn.toString();
// Remove events that do not belong there and then rewrite without the old events
var change = false;
for (var i = 0; i < events.length; i++) {
var event = events[i];
var current_date_utc = new Date();
var date = new Date(current_date_utc);
var event_date = new Date(event.bis);
if (date >= event_date) {
events.splice(i, 1);
change = true;
// Break the loop
break;
}
}
if (change) {
write_into_json();
}
display();
})
.catch((error) => {
console.error("Error:", error);
});
}
// Check every five seconds, can be expanded
// TODO might do a thung where i mark a boolean as 'fetching' and do not perform writes or edits during the entirity of check_dates()
setInterval(check_events, 2000);
// Pin an event (mark it as pinned, will take effect only on the frontend)
function pin(checkbox) {
writing = true;
fetch("../output.json")
.then((response) => response.text())
.then((data) => {
loaded_events = data;
events = JSON.parse(loaded_events).slice(1);
var num_pinned = 0;
for (var i = 0; i < events.length; i++) {
if (events[i].pinned) num_pinned++;
}
if (num_pinned >= 2 && checkbox.checked) {
setTimeout(() => {
checkbox.checked = false;
}, 0);
alert("Es können nicht mehr als 2 Events angeheftet sein!");
return;
}
for (var i = 0; i < events.length; i++) {
if (events[i].event == checkbox.name) {
events[i].pinned = checkbox.checked;
break;
}
}
write_into_json();
})
.catch((error) => {
console.error("Error:", error);
});
writing = false;
}
// On button press just fill in the input_from with the current date in the correct format
instant_button.addEventListener("click", function () {
const current_date_utc = new Date();
// Convert UTC time to local time
const local_time =
current_date_utc.getTime() - current_date_utc.getTimezoneOffset() * 60000;
const current_date_local = new Date(local_time);
// Format the date as required by datetime-local input (YYYY-MM-DDTHH:MM)
const date_string = current_date_local.toISOString().substring(0, 16);
// Set the value of the datetime input
input_from.value = date_string;
});