-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexamenreglement_2025-2026b.html
More file actions
448 lines (401 loc) · 28.8 KB
/
Copy pathexamenreglement_2025-2026b.html
File metadata and controls
448 lines (401 loc) · 28.8 KB
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
<!DOCTYPE html>
<html lang="nl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Interactief Examenreglement - ROC van Twente</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;600;700&display=swap" rel="stylesheet">
<style>
:root {
--primary-green: #65b438;
--light-green: #e9f5e3;
--dark-text: #333;
--light-text: #f8f9fa;
--border-color: #ddd;
--shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
}
body {
font-family: 'Montserrat', sans-serif;
margin: 0;
background-color: #f4f7f6;
color: var(--dark-text);
line-height: 1.6;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.header {
background-color: var(--primary-green);
color: white;
padding: 80px 40px;
position: relative;
clip-path: polygon(0 0, 100% 0, 100% 85%, 0% 100%);
text-align: left;
}
.header-logo { font-size: 2rem; font-weight: 700; line-height: 1; margin-bottom: 20px; }
.header-logo span { font-weight: 400; }
.header h1 { font-size: 3rem; margin: 0; font-weight: 700; }
.header p { font-size: 1.2rem; max-width: 600px; opacity: 0.9; }
.main-content { padding: 40px 0; }
.grid-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 25px;
margin-top: 20px;
}
.card {
background: white;
border-radius: 12px;
box-shadow: var(--shadow);
padding: 25px;
cursor: pointer;
transition: transform 0.3s ease, box-shadow 0.3s ease;
display: flex;
flex-direction: column;
border-left: 5px solid var(--primary-green);
}
.card:hover { transform: translateY(-8px); box-shadow: 0 8px 25px rgba(0,0,0,0.15); }
.card h3 { margin: 0 0 10px 0; color: var(--primary-green); font-size: 1.4rem; }
.card p { margin: 0; font-size: 0.95rem; flex-grow: 1; }
.card-footer { margin-top: 15px; font-size: 0.8rem; font-weight: 600; color: var(--primary-green); opacity: 0.8; }
/* Modal & Overlay Styles */
.modal, .glossary-overlay {
display: none;
position: fixed;
z-index: 1000;
left: 0; top: 0; width: 100%; height: 100%;
overflow: auto;
background-color: rgba(0,0,0,0.6);
animation: fadeIn 0.3s;
}
.glossary-overlay { z-index: 2000; background-color: rgba(0,0,0,0.7); }
.modal-content, .glossary-content {
background-color: #fefefe;
margin: 5% auto;
padding: 30px;
border-radius: 12px;
width: 80%;
max-width: 800px;
box-shadow: 0 5px 20px rgba(0,0,0,0.3);
position: relative;
animation: slideIn 0.4s;
}
.glossary-content {
margin: 15% auto;
max-width: 500px;
}
.close-btn {
color: #aaa;
position: absolute;
top: 15px; right: 25px;
font-size: 32px; font-weight: bold;
cursor: pointer;
transition: color 0.2s;
}
.close-btn:hover, .close-btn:focus { color: black; }
.modal-body { max-height: 60vh; overflow-y: auto; padding-right: 15px; }
#modal-text-content h3, .glossary-content h3 { color: var(--primary-green); border-bottom: 2px solid var(--light-green); padding-bottom: 10px; }
.glossary-content p { margin-top: 15px; }
/* Interactive word style */
.ai-word {
text-decoration: underline dotted var(--primary-green);
cursor: pointer;
font-weight: 600;
}
.ai-button {
background-color: var(--primary-green); color: white; border: none;
padding: 10px 20px; border-radius: 20px; cursor: pointer;
font-weight: 600; transition: background-color 0.3s;
margin-top: 20px; display: inline-flex; align-items: center; gap: 8px;
}
.ai-button:hover { background-color: #4a8c2a; }
.ai-button .spinner { display: none; width: 16px; height: 16px; border: 2px solid rgba(255,255,255,0.3); border-top-color: white; border-radius: 50%; animation: spin 1s linear infinite; }
.ai-summary { background-color: var(--light-green); border-left: 4px solid var(--primary-green); padding: 15px; margin-top: 20px; border-radius: 5px; }
.ai-summary ul { padding-left: 20px; margin: 0; }
/* AI Chat Assistant */
.ai-chat-container {
position: fixed; bottom: 20px; right: 20px; width: 350px;
max-width: 90vw; background-color: white; border-radius: 15px;
box-shadow: 0 10px 30px rgba(0,0,0,0.2); display: flex; flex-direction: column;
overflow: hidden; transition: height 0.3s ease-in-out; z-index: 999; height: 55px; /* Collapsed by default */
}
.ai-chat-header { background-color: var(--primary-green); color: white; padding: 15px; font-weight: 600; cursor: pointer; display: flex; justify-content: space-between; align-items: center; flex-shrink: 0; }
.ai-chat-content { flex-grow: 1; display: flex; flex-direction: column; min-height: 0; }
.ai-chat-body { flex-grow: 1; padding: 15px; overflow-y: auto; display: flex; flex-direction: column; gap: 12px; }
.ai-chat-footer { padding: 10px; border-top: 1px solid var(--border-color); background-color: #f9f9f9; flex-shrink: 0; }
.ai-chat-prompts { padding: 0 10px 10px; display: flex; flex-wrap: wrap; gap: 8px; flex-shrink: 0; }
.prompt-btn { background: var(--light-green); color: var(--primary-green); border: 1px solid var(--primary-green); padding: 5px 10px; font-size: 0.8rem; border-radius: 15px; cursor: pointer; transition: all 0.2s; }
.prompt-btn:hover { background: var(--primary-green); color: white; }
.chat-message { padding: 10px 15px; border-radius: 18px; max-width: 85%; line-height: 1.4; word-wrap: break-word; }
.user-message { background-color: var(--primary-green); color: white; align-self: flex-end; border-bottom-right-radius: 4px; }
.bot-message { background-color: #e9ecef; color: var(--dark-text); align-self: flex-start; border-bottom-left-radius: 4px; }
.bot-message .source-ref { display: block; margin-top: 8px; font-size: 0.8rem; font-style: italic; color: #6c757d; border-top: 1px solid #ddd; padding-top: 5px; }
.chat-input-area { display: flex; gap: 10px; }
#chat-input { flex-grow: 1; border: 1px solid var(--border-color); border-radius: 20px; padding: 8px 15px; font-size: 0.9rem; }
#send-btn { background: var(--primary-green); border: none; color: white; font-weight: bold; width: 40px; height: 40px; border-radius: 50%; cursor: pointer; font-size: 1.2rem; transition: background-color 0.2s; }
#send-btn:hover { background-color: #4a8c2a; }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes slideIn { from { transform: translateY(-30px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
@keyframes spin { to { transform: rotate(360deg); } }
@media (max-width: 768px) {
.header { padding: 60px 20px; clip-path: polygon(0 0, 100% 0, 100% 90%, 0% 100%); }
.header h1 { font-size: 2.2rem; }
.modal-content { width: 95%; margin: 10% auto; }
.glossary-content { width: 95%; margin: 20% auto; }
}
</style>
</head>
<body>
<header class="header">
<div class="header-logo">roc <span>van</span> twente</div>
<h1>Interactief Examenreglement</h1>
<p>Beroepsgericht Onderwijs 2025-2026. Krijg snel en eenvoudig inzicht in de regels die voor jou gelden. Klik op een onderwerp voor details.</p>
</header>
<div class="container">
<div class="main-content">
<div id="grid-container" class="grid-container"></div>
</div>
</div>
<div id="infoModal" class="modal">
<div class="modal-content">
<span class="close-btn" id="main-modal-close">×</span>
<div class="modal-body">
<div id="modal-text-content"></div>
</div>
<button id="ai-summarize-btn" class="ai-button">
<div class="spinner"></div>
Vat samen met AI
</button>
</div>
</div>
<div class="glossary-overlay" id="glossary-overlay">
<div class="glossary-content">
<span class="close-btn" id="glossary-close-btn">×</span>
<h3 id="glossary-term"></h3>
<p id="glossary-definition"></p>
</div>
</div>
<div class="ai-chat-container" id="ai-chat-container">
<div class="ai-chat-header" id="ai-chat-header">
<span>AI Examen Assistent</span>
<span id="chat-toggle-icon">▲</span>
</div>
<div class="ai-chat-content">
<div id="chat-prompts-container" class="ai-chat-prompts"></div>
<div id="ai-chat-body" class="ai-chat-body">
<div class="chat-message bot-message">Hallo! Ik ben je AI Examen Assistent. Stel een vraag over het reglement.</div>
</div>
<div class="ai-chat-footer">
<div class="chat-input-area">
<input type="text" id="chat-input" placeholder="Typ je vraag hier...">
<button id="send-btn">→</button>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const glossary = {
'onregelmatigheid': 'Elke handeling die het correcte verloop van een examen verstoort, zoals fraude, spieken, overlast veroorzaken of instructies niet opvolgen.',
'fraude': 'Opzettelijk bedrog om een beter examenresultaat te krijgen. Voorbeelden zijn afkijken, valse documenten inleveren of een telefoon gebruiken.',
'examencommissie': 'Een onafhankelijke commissie binnen het college die toeziet op de kwaliteit van examens, diploma\'s toekent en beslist over o.a. fraude en vrijstellingen.',
'vrijstelling': 'De beslissing dat je een bepaald examenonderdeel niet hoeft te maken, omdat je al hebt aangetoond dat je de benodigde kennis of vaardigheden bezit.',
'extraneus': 'Een persoon die is ingeschreven om alleen examens af te leggen, zonder deel te nemen aan de lessen of andere onderwijsactiviteiten.',
'bpv': 'Beroepspraktijkvorming, ook wel stage genoemd. Een verplicht onderdeel van de opleiding waarin je praktijkervaring opdoet bij een erkend leerbedrijf.',
'Beroepspraktijkvorming (bpv)': 'Beroepspraktijkvorming, ook wel stage genoemd. Een verplicht onderdeel van de opleiding waarin je praktijkervaring opdoet bij een erkend leerbedrijf.',
'keuzedeel': 'Een extra onderdeel van je opleiding waarmee je je kennis kunt verbreden of verdiepen. Het behalen van keuzedelen is verplicht en telt mee voor je diploma.',
'Keuzedelen': 'Een extra onderdeel van je opleiding waarmee je je kennis kunt verbreden of verdiepen. Het behalen van keuzedelen is verplicht en telt mee voor je diploma.',
'cesuur': 'De grens tussen een voldoende en een onvoldoende resultaat voor een examen. Deze wordt bepaald na analyse van de examenresultaten.',
'kwalificatiedossier': 'Een document dat precies omschrijft wat je moet kennen en kunnen voor je beroep. Het is de basis voor je opleiding en examens.'
};
const documentContent = [
{ id: 'ch1', title: 'Examenreglement', shortSummary: 'Geeft je alle informatie over examinering bij ROC van Twente en de regels die gelden bij examens.', fullText: `<h3>1. Examenreglement</h3><p>Het examenreglement geeft je alle informatie over examinering bij ROC van Twente. In het examenreglement lees je welke regels er gelden bij examens. Dit reglement geldt voor alle studenten die vanaf 1 augustus 2025 deelnemen aan een BOL-, BBL- of derde leerweg opleiding (cohort 2025). Binnen elk college heeft een examencommissie aanvullende regels. Het reglement zorgt ervoor dat het hele proces van examineren tot diplomeren goed verloopt.</p>`, aiSummary: `<ul><li>Dit document bevat alle examenregels van ROC van Twente.</li><li>Het geldt voor studenten die starten vanaf 1 augustus 2025 (cohort 2025).</li><li>Het doel is een eerlijk en soepel verloop van het examenproces.</li></ul>` },
{ id: 'ch2', title: 'De Examencommissie', shortSummary: 'Een commissie die toeziet op de kwaliteit van examinering en diplomering.', fullText: `<h3>2. De examencommissie</h3><p>Je college heeft een eigen examencommissie die toeziet op de kwaliteit van examinering en diplomering. Deze is ingesteld door het College van Bestuur. De belangrijkste taken voor jou zijn:</p><ul><li>Toezien op de kwaliteit van examens.</li><li>Vaststellen of je recht hebt op een diploma, certificaat of mbo-verklaring.</li><li>Behandelen van verzoeken om vrijstelling.</li><li>Behandelen van verzoeken voor aangepaste examens.</li><li>Beslissen bij onregelmatigheid en fraude.</li></ul>`, aiSummary: `<ul><li>Elk college heeft een eigen examencommissie.</li><li>Zij bewaken de kwaliteit van alle examens en diploma's.</li><li>Ze beslissen over vrijstellingen, aanpassingen en fraudegevallen.</li><li>Zij stellen vast of je geslaagd bent.</li></ul>` },
{ id: 'ch3', title: 'Deelname aan examens', shortSummary: 'Regels over toegang, hulpmiddelen, afwezigheid en identificatie bij examens.', fullText: `<h3>3. Deelname aan examens</h3><p>Als je ingeschreven staat, moet je deelnemen aan de examens van je opleiding. In je examenplan staat welke onderdelen er zijn en hoe ze worden geëxamineerd.</p><h4>Toegang en Identificatie</h4><p>Je hebt toegang tot de examens van je opleiding. Bij binnenkomst op de examenlocatie moet je een geldig ID-bewijs tonen (ID-kaart, paspoort, rijbewijs). Bij een onvoldoende heb je recht op één herkansing.</p><h4>Hulpmiddelen</h4><p>Je mag alleen toegestane hulpmiddelen gebruiken. Mobiele telefoons en smartwatches zijn verboden. Gebruik van AI is niet toegestaan, tenzij expliciet vermeld.</p><h4>Afwezigheid</h4><p>Ben je ziek of afwezig om een andere geldige reden? Meld dit dan volgens de procedure in je opleidingsplan. Bij afwezigheid zonder geldige reden wordt dit gezien als een onregelmatigheid.</p><h4>Extraneus</h4><p>Een extraneus is iemand die alleen examens doet, zonder onderwijs te volgen. Hier zijn kosten aan verbonden.</p>`, aiSummary: `<ul><li>Je moet meedoen aan de examens van je opleiding.</li><li>Neem altijd een geldig ID-bewijs mee naar een examen.</li><li>Gebruik van telefoons, smartwatches en ongeautoriseerde AI is verboden.</li><li>Meld je op tijd af als je ziek bent, anders telt het als fraude.</li><li>Bij een onvoldoende heb je recht op één herkansing.</li></ul>` },
{ id: 'ch7', title: 'Gang van zaken tijdens een examen', shortSummary: 'Regels over onregelmatigheden zoals fraude, plagiaat en de gevolgen daarvan.', fullText: `<h3>7. Gang van zaken tijdens een examen</h3><p>Tijdens instellingsexamens gelden strikte regels. Voor Centrale Examens geldt het protocol van het CvTE.</p><h4>7.1 Onregelmatigheden</h4><p>Een onregelmatigheid is alles wat niet mag. Voorbeelden zijn:</p><ul><li>Fraude, zoals spieken of ongeoorloofde hulpmiddelen gebruiken.</li><li>Instructies van surveillanten niet opvolgen.</li><li>Overlast veroorzaken.</li><li>Plagiaat of identiteitsfraude.</li><li>Afwezig zijn zonder geldige reden.</li></ul><p>Als een onregelmatigheid wordt geconstateerd, wordt er een procesverbaal opgemaakt. De examencommissie kan maatregelen opleggen, zoals het ongeldig verklaren van het examen, het ontzeggen van de herkansing, of uitsluiting van verdere deelname.</p>`, aiSummary: `<ul><li>Tijdens het examen gelden strikte gedragsregels.</li><li>Spieken, afkijken, telefoons gebruiken of overlast veroorzaken is verboden.</li><li>De examencommissie bepaalt de straf bij een overtreding.</li><li>Mogelijke gevolgen: examen ongeldig, geen herkansing, of zelfs uitsluiting.</li></ul>` },
{ id: 'ch8', title: 'Uitslag en Inzagerecht', shortSummary: 'Informatie over wanneer je de uitslag krijgt en hoe je je gemaakte examen kunt inzien.', fullText: `<h3>8. Uitslag examens</h3><h4>8.1 Bekendmaking</h4><p>De uitslag van een examen wordt binnen 15 werkdagen na afname bekendgemaakt. Examens worden beoordeeld met een cijfer of een waarderingsschaal.</p><h4>8.4 Inzagerecht</h4><p>Je hebt het recht om je beoordeelde examenwerk in te zien. Een verzoek tot inzage moet je binnen 5 dagen na de bekendmaking van de uitslag indienen bij je onderwijsteam. Bij de inzage mag je geen telefoon of smartwatch meenemen en geen aantekeningen maken. Voor centrale examens is er een aparte procedure. De cesuur (zak-/slaaggrens) wordt landelijk vastgesteld en gepubliceerd op Examenbladmbo.nl.</p>`, aiSummary: `<ul><li>Je ontvangt je examenresultaat binnen 15 werkdagen.</li><li>Je hebt het recht om je gemaakte werk in te zien.</li><li>Dien een verzoek voor inzage binnen 5 dagen na de uitslag in.</li><li>Tijdens inzage mag je geen opnameapparatuur gebruiken.</li></ul>` },
{ id: 'ch9', title: 'Waardepapieren', shortSummary: 'De eisen voor het behalen van een diploma, certificaat of mbo-verklaring.', fullText: `<h3>9. Waardepapieren</h3><h4>9.1 Diploma's</h4><p>Je ontvangt een diploma als je aan alle eisen hebt voldaan. De belangrijkste eisen zijn:</p><ul><li>Kerntaken: minimaal een 6.</li><li>Nederlands: minimaal een 5.</li><li>Rekenen: minimaal een 6 (of andersom met Nederlands).</li><li>Engels (niveau 4): minimaal een 6.</li><li>Beroepspraktijkvorming (bpv): met een 'voldoende' afgerond.</li><li>Keuzedelen: voldaan aan de keuzedeelverplichting.</li></ul><h4>9.1.2 Cum laude</h4><p>Je kunt 'cum laude' (met lof) slagen als je aan extra hoge eisen voldoet.</p><h4>9.3 Mbo-verklaring</h4><p>Als je de opleiding verlaat zonder diploma, maar wel examenonderdelen hebt behaald, kun je een mbo-verklaring of certificaten krijgen. Dit is een bewijs van wat je wel hebt bereikt.</p>`, aiSummary: `<ul><li>Je krijgt een diploma als je voor alle onderdelen geslaagd bent.</li><li>Cruciaal zijn voldoendes voor kerntaken, generieke vakken (Nederlands, Rekenen, Engels) en de BPV.</li><li>Als je uitmuntend presteert, kun je 'cum laude' slagen.</li><li>Stop je voortijdig? Dan kun je een mbo-verklaring krijgen voor de behaalde onderdelen.</li></ul>` }
];
const qaPairs = {
'ziek': { answer: "Als je ziek bent, moet je dit zo snel mogelijk melden volgens de procedure van je opleiding. Je krijgt dan een nieuwe kans om het examen te doen. Meld je je niet af, dan wordt het gezien als een onregelmatigheid.", source: "Pag. 7, par. 3.4" },
'herkansing': { answer: "Ja, bij een onvoldoende resultaat voor een instellingsexamen heb je recht op één herkansing. Een eventuele extra herkansing moet je aanvragen bij de examencommissie.", source: "Pag. 6, par. 3.2" },
'id': { answer: "Ja, je moet bij elk examen een geldig identiteitsbewijs kunnen tonen. Dit kan een ID-kaart, paspoort of rijbewijs zijn.", source: "Pag. 6, par. 3.2" },
'identiteit': { answer: "Ja, je moet bij elk examen een geldig identiteitsbewijs kunnen tonen. Dit kan een ID-kaart, paspoort of rijbewijs zijn.", source: "Pag. 6, par. 3.2" },
'uitslag': { answer: "De uitslag van een examen wordt normaal gesproken binnen 15 werkdagen na afname bekendgemaakt. De examencommissie kan hier in bijzondere gevallen van afwijken.", source: "Pag. 16, par. 8.1" },
'fraude': { answer: "Fraude is opzettelijk bedrog, zoals afkijken, een telefoon gebruiken of werk van een ander inleveren. De examencommissie kan zware straffen opleggen, zoals het ongeldig verklaren van je examen.", source: "Pag. 14, par. 7.1.1" },
'spieken': { answer: "Spieken valt onder fraude. Als je betrapt wordt, stelt de surveillant een procesverbaal op. De examencommissie beslist over de maatregel, wat kan variëren van een ongeldig examen tot uitsluiting van herkansing.", source: "Pag. 14, par. 7.1.1" },
'telefoon': { answer: "Nee, mobiele telefoons en smartwatches zijn verboden in de examenruimte. Het bij je hebben ervan wordt al gezien als een onregelmatigheid, zelfs als je het niet gebruikt.", source: "Pag. 7, par. 3.3" },
'cum laude': { answer: "'Cum laude' betekent 'met lof'. Je kunt dit op je diploma krijgen als je uitzonderlijk hoge cijfers hebt gehaald voor alle examenonderdelen. De precieze voorwaarden staan in de cum laude regeling.", source: "Pag. 19, par. 9.1.2" },
'inzien': { answer: "Ja, je hebt het recht om je examen in te zien. Je moet hiervoor binnen 5 dagen na de uitslag een verzoek indienen bij je onderwijsteam. Tijdens de inzage mag je geen foto's of kopieën maken.", source: "Pag. 17, par. 8.4" },
'vrijstelling': { answer: "Je kunt een vrijstelling aanvragen bij de examencommissie als je kunt bewijzen dat je een bepaald onderdeel al beheerst, bijvoorbeeld door een eerder behaald diploma. Dit bewijs mag meestal niet te oud zijn.", source: "Pag. 8, par. 4.2" },
'klacht': { answer: "Als je het niet eens bent met een beslissing van de examencommissie, kun je in beroep gaan bij de 'Commissie van Beroep voor de Examens'. De procedure hiervoor staat in de Handleiding Klacht en Bezwaar.", source: "Pag. 20, Hfst. 10" },
'beroep': { answer: "Als je het niet eens bent met een beslissing van de examencommissie, kun je in beroep gaan bij de 'Commissie van Beroep voor de Examens'. De procedure hiervoor staat in de Handleiding Klacht en Bezwaar.", source: "Pag. 20, Hfst. 10" }
};
const suggestedPrompts = [ "Wat als ik ziek ben?", "Mag ik mijn telefoon meenemen?", "Hoeveel herkansingen krijg ik?", "Wanneer krijg ik de uitslag?", "Wat is fraude?", "Kan ik mijn examen inzien?" ];
// --- DOM Elements ---
const gridContainer = document.getElementById('grid-container');
const infoModal = document.getElementById('infoModal');
const modalTextContent = document.getElementById('modal-text-content');
const mainModalCloseBtn = document.getElementById('main-modal-close');
const aiSummarizeBtn = document.getElementById('ai-summarize-btn');
const chatContainer = document.getElementById('ai-chat-container');
const chatHeader = document.getElementById('ai-chat-header');
const chatBody = document.getElementById('ai-chat-body');
const chatInput = document.getElementById('chat-input');
const sendBtn = document.getElementById('send-btn');
const chatPromptsContainer = document.getElementById('chat-prompts-container');
const chatToggleIcon = document.getElementById('chat-toggle-icon');
const glossaryOverlay = document.getElementById('glossary-overlay');
const glossaryCloseBtn = document.getElementById('glossary-close-btn');
const glossaryTermEl = document.getElementById('glossary-term');
const glossaryDefinitionEl = document.getElementById('glossary-definition');
// --- Functions ---
function renderCards() {
gridContainer.innerHTML = '';
documentContent.forEach(item => {
const card = document.createElement('div');
card.className = 'card';
card.dataset.id = item.id;
card.innerHTML = `<h3>${item.title}</h3><p>${item.shortSummary}</p><div class="card-footer">Klik voor meer info</div>`;
card.addEventListener('click', () => showInfoModal(item.id));
gridContainer.appendChild(card);
});
}
function processGlossaryTerms(text) {
let processedText = text;
Object.keys(glossary).forEach(key => {
const regex = new RegExp(`\\b(${key})\\b`, 'gi');
processedText = processedText.replace(regex, `<span class="ai-word" data-term="${key}">$1</span>`);
});
return processedText;
}
function showInfoModal(id) {
const item = documentContent.find(doc => doc.id === id);
if (item) {
modalTextContent.innerHTML = processGlossaryTerms(item.fullText);
aiSummarizeBtn.dataset.id = id;
infoModal.style.display = 'block';
}
}
function hideInfoModal() {
infoModal.style.display = 'none';
}
function showGlossaryOverlay(termKey) {
const term = termKey.charAt(0).toUpperCase() + termKey.slice(1);
const definition = glossary[termKey];
if(definition) {
glossaryTermEl.textContent = term;
glossaryDefinitionEl.textContent = definition;
glossaryOverlay.style.display = 'block';
}
}
function hideGlossaryOverlay() {
glossaryOverlay.style.display = 'none';
}
function showAiSummary() {
const spinner = aiSummarizeBtn.querySelector('.spinner');
spinner.style.display = 'inline-block';
setTimeout(() => {
const id = aiSummarizeBtn.dataset.id;
const item = documentContent.find(doc => doc.id === id);
if (item) {
modalTextContent.innerHTML = `<div class="ai-summary"><strong>AI Samenvatting:</strong>${item.aiSummary}</div>`;
}
spinner.style.display = 'none';
}, 800);
}
function handleUserMessage() {
const userInput = chatInput.value.trim();
if (userInput === '') return;
addMessageToChat(userInput, 'user');
chatInput.value = '';
setTimeout(() => {
const botResponse = getBotResponse(userInput);
addMessageToChat(botResponse, 'bot');
}, 600);
}
function addMessageToChat(message, sender) {
const messageElement = document.createElement('div');
messageElement.className = `chat-message ${sender}-message`;
if (sender === 'user') {
messageElement.textContent = message;
} else {
messageElement.innerHTML = message;
}
chatBody.appendChild(messageElement);
chatBody.scrollTop = chatBody.scrollHeight;
}
function getBotResponse(userInput) {
const lowerInput = userInput.toLowerCase();
for (const keyword in qaPairs) {
if (lowerInput.includes(keyword)) {
const { answer, source } = qaPairs[keyword];
return `<div>${answer}</div><span class="source-ref">Bron: ${source}</span>`;
}
}
return "Dat is een goede vraag. Ik heb hier geen direct antwoord op. Raadpleeg voor specifieke gevallen je studieloopbaanbegeleider of de volledige tekst van het examenreglement.";
}
function toggleChat() {
const isCollapsed = chatContainer.style.height === '55px';
if (isCollapsed) {
chatContainer.style.height = '620px';
chatToggleIcon.textContent = '▼';
} else {
chatContainer.style.height = '55px';
chatToggleIcon.textContent = '▲';
}
}
function renderSuggestedPrompts() {
chatPromptsContainer.innerHTML = '';
suggestedPrompts.forEach(prompt => {
const btn = document.createElement('button');
btn.className = 'prompt-btn';
btn.textContent = prompt;
btn.addEventListener('click', () => {
chatInput.value = prompt;
handleUserMessage();
});
chatPromptsContainer.appendChild(btn);
});
}
// --- Event Listeners ---
mainModalCloseBtn.addEventListener('click', hideInfoModal);
aiSummarizeBtn.addEventListener('click', showAiSummary);
sendBtn.addEventListener('click', handleUserMessage);
chatInput.addEventListener('keypress', (event) => { if (event.key === 'Enter') handleUserMessage(); });
chatHeader.addEventListener('click', toggleChat);
// Event delegation for glossary terms
modalTextContent.addEventListener('click', (event) => {
const target = event.target.closest('.ai-word');
if (target && target.dataset.term) {
showGlossaryOverlay(target.dataset.term);
}
});
// Glossary overlay closing listeners
glossaryCloseBtn.addEventListener('click', hideGlossaryOverlay);
glossaryOverlay.addEventListener('click', (event) => {
if (event.target === glossaryOverlay) {
hideGlossaryOverlay();
}
});
// Window-level closing listeners
window.addEventListener('click', (event) => {
if (event.target == infoModal) hideInfoModal();
});
window.addEventListener('keydown', (event) => {
if (event.key === "Escape") {
hideInfoModal();
hideGlossaryOverlay();
}
});
// --- Initialisation ---
renderCards();
renderSuggestedPrompts();
});
</script>
</body>
</html>