@mhmttosun/dnd 0.0.0-stage → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,820 @@
1
+ /**
2
+ * ExportManager - Etkinliği tek bir bağımsız, çevrimdışı çalışabilen
3
+ * ve sıfır harici bağımlılığı olan HTML dosyası olarak dışa aktarır.
4
+ */
5
+ class ExportManager {
6
+ constructor(core) {
7
+ this.core = core;
8
+ }
9
+
10
+ /**
11
+ * Projeyi tek bir HTML dosyası olarak derler ve indirir
12
+ */
13
+ exportStandaloneHTML() {
14
+ const projectData = this.core.getProjectData();
15
+
16
+ // Doğrulama kontrolü
17
+ const playability = window.DND.ValidationEngine.validatePlayability(projectData);
18
+ if (!playability.ready) {
19
+ const confirmContinue = confirm(
20
+ 'Dikkat: Etkinlikte bazı eksiklikler tespit edildi:\n\n• ' +
21
+ playability.issues.join('\n• ') +
22
+ '\n\nYine de dışa aktarmak istiyor musunuz?'
23
+ );
24
+ if (!confirmContinue) return false;
25
+ }
26
+
27
+ const htmlContent = this.generateStandaloneHTMLString(projectData);
28
+ const blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' });
29
+ const url = URL.createObjectURL(blob);
30
+
31
+ const safeTitle = (projectData.project.name || 'etkinlik')
32
+ .toLowerCase()
33
+ .replace(/[^a-z0-9ğüşıöç]+/g, '_')
34
+ .replace(/^_+|_+$/g, '');
35
+
36
+ const a = document.createElement('a');
37
+ a.href = url;
38
+ a.download = `${safeTitle}_etkinlik.html`;
39
+ document.body.appendChild(a);
40
+ a.click();
41
+ document.body.removeChild(a);
42
+ URL.revokeObjectURL(url);
43
+
44
+ return true;
45
+ }
46
+
47
+ generateStandaloneHTMLString(projectData) {
48
+ const title = window.DND.ValidationEngine.sanitizeText(projectData.project.name || 'Sürükle Bırak Etkinliği');
49
+ const projectJsonEscaped = JSON.stringify(projectData).replace(/<\/script>/gi, '<\\/script>');
50
+
51
+ return `<!DOCTYPE html>
52
+ <html lang="tr">
53
+ <head>
54
+ <meta charset="UTF-8">
55
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
56
+ <title>${title}</title>
57
+ <style>
58
+ /* RESET & TEMEL STILLER */
59
+ *, *::before, *::after {
60
+ box-sizing: border-box;
61
+ margin: 0;
62
+ padding: 0;
63
+ -webkit-tap-highlight-color: transparent;
64
+ }
65
+
66
+ body {
67
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
68
+ background: #0f172a;
69
+ color: #1e293b;
70
+ min-height: 100vh;
71
+ display: flex;
72
+ flex-direction: column;
73
+ overflow: hidden;
74
+ user-select: none;
75
+ -webkit-user-select: none;
76
+ }
77
+
78
+ /* OYNATICI ÇERÇEVESİ */
79
+ .player-wrapper {
80
+ width: 100vw;
81
+ height: 100vh;
82
+ max-width: 100%;
83
+ max-height: 100%;
84
+ display: flex;
85
+ flex-direction: column;
86
+ overflow: hidden;
87
+ position: relative;
88
+ background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
89
+ }
90
+
91
+ .player-header {
92
+ height: 60px;
93
+ min-height: 52px;
94
+ flex-shrink: 0;
95
+ padding: 0 20px;
96
+ display: flex;
97
+ align-items: center;
98
+ justify-content: space-between;
99
+ background: rgba(15, 23, 42, 0.85);
100
+ backdrop-filter: blur(8px);
101
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
102
+ z-index: 100;
103
+ }
104
+
105
+ .player-header.player-header-minimal {
106
+ position: absolute;
107
+ top: 14px;
108
+ right: 18px;
109
+ height: auto;
110
+ min-height: unset;
111
+ padding: 0;
112
+ background: transparent;
113
+ border-bottom: none;
114
+ backdrop-filter: none;
115
+ z-index: 500;
116
+ pointer-events: auto;
117
+ }
118
+
119
+ .player-header.player-header-minimal .exit-btn {
120
+ background: rgba(239, 68, 68, 0.18);
121
+ border: 1px solid rgba(239, 68, 68, 0.45);
122
+ color: #fca5a5;
123
+ backdrop-filter: blur(8px);
124
+ box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
125
+ border-radius: 9999px;
126
+ padding: 7px 16px;
127
+ font-size: 0.85rem;
128
+ font-weight: 600;
129
+ cursor: pointer;
130
+ transition: all 0.2s ease;
131
+ }
132
+
133
+ .player-title-box {
134
+ display: flex;
135
+ align-items: center;
136
+ gap: 12px;
137
+ }
138
+
139
+ .player-title {
140
+ font-size: 1.15rem;
141
+ font-weight: 700;
142
+ color: #f8fafc;
143
+ letter-spacing: -0.01em;
144
+ }
145
+
146
+ .player-badge {
147
+ font-size: 0.75rem;
148
+ font-weight: 600;
149
+ background: rgba(99, 102, 241, 0.25);
150
+ color: #a5b4fc;
151
+ border: 1px solid rgba(99, 102, 241, 0.4);
152
+ padding: 3px 8px;
153
+ border-radius: 9999px;
154
+ }
155
+
156
+ .player-stats {
157
+ display: flex;
158
+ align-items: center;
159
+ gap: 12px;
160
+ }
161
+
162
+ .stat-pill {
163
+ display: flex;
164
+ align-items: center;
165
+ gap: 6px;
166
+ background: rgba(30, 41, 59, 0.9);
167
+ border: 1px solid rgba(255, 255, 255, 0.12);
168
+ padding: 6px 14px;
169
+ border-radius: 9999px;
170
+ font-size: 0.85rem;
171
+ font-weight: 600;
172
+ color: #e2e8f0;
173
+ }
174
+
175
+ .stat-pill .stat-value {
176
+ color: #38bdf8;
177
+ }
178
+
179
+ .player-actions {
180
+ display: flex;
181
+ align-items: center;
182
+ gap: 10px;
183
+ }
184
+
185
+ .player-btn {
186
+ display: inline-flex;
187
+ align-items: center;
188
+ justify-content: center;
189
+ gap: 6px;
190
+ padding: 8px 16px;
191
+ border-radius: 8px;
192
+ font-size: 0.85rem;
193
+ font-weight: 600;
194
+ border: 1px solid rgba(255, 255, 255, 0.15);
195
+ background: rgba(255, 255, 255, 0.08);
196
+ color: #f8fafc;
197
+ cursor: pointer;
198
+ transition: all 0.2s ease;
199
+ }
200
+
201
+ .player-btn:hover {
202
+ background: rgba(255, 255, 255, 0.16);
203
+ transform: translateY(-1px);
204
+ }
205
+
206
+ .player-btn:active {
207
+ transform: translateY(0);
208
+ }
209
+
210
+ .primary-btn,
211
+ .check-answers-btn {
212
+ background: #0f172a;
213
+ border: 1px solid #0f172a;
214
+ color: #ffffff;
215
+ border-radius: 9999px;
216
+ padding: 8px 20px;
217
+ font-size: 0.875rem;
218
+ font-weight: 600;
219
+ display: inline-flex;
220
+ align-items: center;
221
+ gap: 6px;
222
+ cursor: pointer;
223
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
224
+ transition: all 0.15s ease;
225
+ }
226
+
227
+ .primary-btn:hover,
228
+ .check-answers-btn:hover {
229
+ background: #1e293b;
230
+ border-color: #1e293b;
231
+ transform: translateY(-1px);
232
+ box-shadow: 0 4px 12px rgba(15, 23, 42, 0.15);
233
+ }
234
+
235
+ .player-btn.secondary-btn,
236
+ .player-btn.reset-btn {
237
+ background: transparent;
238
+ border: none;
239
+ color: #475569;
240
+ font-size: 0.875rem;
241
+ font-weight: 500;
242
+ padding: 7px 12px;
243
+ border-radius: 8px;
244
+ cursor: pointer;
245
+ display: inline-flex;
246
+ align-items: center;
247
+ gap: 6px;
248
+ transition: all 0.15s ease;
249
+ box-shadow: none;
250
+ }
251
+
252
+ .player-btn.secondary-btn:hover,
253
+ .player-btn.reset-btn:hover {
254
+ background: #f1f5f9;
255
+ color: #0f172a;
256
+ transform: none;
257
+ }
258
+
259
+ .player-btn.reset-btn .btn-icon {
260
+ font-size: 1.05rem;
261
+ line-height: 1;
262
+ }
263
+
264
+ .player-btn.retry-btn {
265
+ background: #d97706;
266
+ border: 1px solid #d97706;
267
+ color: #ffffff;
268
+ border-radius: 9999px;
269
+ padding: 8px 20px;
270
+ font-size: 0.875rem;
271
+ font-weight: 600;
272
+ display: inline-flex;
273
+ align-items: center;
274
+ gap: 6px;
275
+ cursor: pointer;
276
+ box-shadow: 0 2px 8px rgba(217, 119, 6, 0.25);
277
+ transition: all 0.15s ease;
278
+ }
279
+
280
+ .player-btn.retry-btn:hover {
281
+ background: #b45309;
282
+ border-color: #b45309;
283
+ transform: translateY(-1px);
284
+ }
285
+
286
+ /* OYUN ALANI VE SAHNE */
287
+ .player-viewport,
288
+ .player-stage-viewport {
289
+ flex: 1 1 0%;
290
+ min-width: 0;
291
+ min-height: 0;
292
+ width: 100%;
293
+ height: 100%;
294
+ position: relative;
295
+ overflow: hidden;
296
+ display: flex;
297
+ flex-direction: column;
298
+ background: #f8fafc;
299
+ touch-action: none;
300
+ }
301
+
302
+ .player-stage-container {
303
+ flex: 1 1 0%;
304
+ min-width: 0;
305
+ min-height: 0;
306
+ width: 100%;
307
+ position: relative;
308
+ overflow: hidden;
309
+ display: flex;
310
+ flex-direction: column;
311
+ align-items: center;
312
+ justify-content: center;
313
+ touch-action: none;
314
+ }
315
+
316
+ .player-stage-board {
317
+ display: flex;
318
+ flex-direction: column;
319
+ box-shadow: 0 10px 30px -5px rgba(0, 0, 0, 0.08), 0 0 0 1px rgba(0, 0, 0, 0.05);
320
+ border-radius: 16px;
321
+ overflow: hidden;
322
+ background: #ffffff;
323
+ border: 1px solid #e2e8f0;
324
+ box-sizing: border-box;
325
+ flex-shrink: 0;
326
+ }
327
+
328
+ .player-stage-scaler {
329
+ position: relative;
330
+ overflow: hidden;
331
+ flex-shrink: 0;
332
+ border-radius: 16px 16px 0 0;
333
+ }
334
+
335
+ .player-stage {
336
+ position: absolute;
337
+ top: 0;
338
+ left: 0;
339
+ overflow: hidden;
340
+ touch-action: none;
341
+ transform-origin: top left;
342
+ user-select: none;
343
+ -webkit-user-select: none;
344
+ flex-shrink: 0;
345
+ }
346
+
347
+ .player-targets-layer,
348
+ .player-draggables-layer {
349
+ position: absolute;
350
+ top: 0;
351
+ left: 0;
352
+ width: 100%;
353
+ height: 100%;
354
+ pointer-events: none;
355
+ }
356
+
357
+ .player-object {
358
+ position: absolute;
359
+ top: 0;
360
+ left: 0;
361
+ display: flex;
362
+ align-items: center;
363
+ justify-content: center;
364
+ box-sizing: border-box;
365
+ pointer-events: auto;
366
+ user-select: none;
367
+ }
368
+
369
+ .player-object.is-draggable {
370
+ cursor: grab;
371
+ touch-action: none;
372
+ transition: box-shadow 0.2s ease, filter 0.2s ease;
373
+ }
374
+
375
+ .player-object.is-draggable:hover {
376
+ filter: brightness(1.05);
377
+ box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2) !important;
378
+ }
379
+
380
+ .player-object.is-dragging {
381
+ cursor: grabbing !important;
382
+ opacity: 0.92;
383
+ filter: drop-shadow(0 15px 30px rgba(0, 0, 0, 0.35));
384
+ }
385
+
386
+ .player-object.is-locked {
387
+ cursor: default !important;
388
+ opacity: 0.95;
389
+ pointer-events: none;
390
+ }
391
+
392
+ .player-object.is-correct {
393
+ border-color: #10b981 !important;
394
+ background-color: #ecfdf5 !important;
395
+ color: #065f46 !important;
396
+ }
397
+
398
+ .player-object.is-incorrect {
399
+ border-color: #ef4444 !important;
400
+ background-color: #fef2f2 !important;
401
+ }
402
+
403
+ .player-object.is-incorrect .player-object-content {
404
+ animation: shake 0.4s ease-in-out;
405
+ }
406
+
407
+ .player-object.hover-active {
408
+ border-color: #38bdf8 !important;
409
+ box-shadow: 0 0 0 4px rgba(56, 189, 248, 0.35) !important;
410
+ }
411
+
412
+ .player-object.keyboard-active {
413
+ outline: 4px solid #f59e0b;
414
+ outline-offset: 4px;
415
+ animation: pulse 1s infinite alternate;
416
+ }
417
+
418
+ @keyframes shake {
419
+ 0%, 100% { transform: translateX(0); }
420
+ 20%, 60% { transform: translateX(-8px); }
421
+ 40%, 80% { transform: translateX(8px); }
422
+ }
423
+
424
+ @keyframes pulse {
425
+ from { box-shadow: 0 0 0 2px #f59e0b; }
426
+ to { box-shadow: 0 0 0 8px rgba(245, 158, 11, 0.4); }
427
+ }
428
+
429
+ /* DOĞRU / YANLIŞ İKON ROZETLERİ (✓ / ✕) */
430
+ .player-status-badge {
431
+ position: absolute;
432
+ top: -10px;
433
+ right: -10px;
434
+ width: 24px;
435
+ height: 24px;
436
+ border-radius: 50%;
437
+ display: flex;
438
+ align-items: center;
439
+ justify-content: center;
440
+ font-size: 13px;
441
+ font-weight: 900;
442
+ box-shadow: 0 3px 8px rgba(0, 0, 0, 0.3);
443
+ z-index: 100;
444
+ animation: badgePop 0.28s cubic-bezier(0.34, 1.56, 0.64, 1);
445
+ pointer-events: none;
446
+ }
447
+
448
+ .player-status-badge.badge-correct {
449
+ background: #10b981;
450
+ color: #ffffff;
451
+ border: 2px solid #ffffff;
452
+ }
453
+
454
+ .player-status-badge.badge-incorrect {
455
+ background: #ef4444;
456
+ color: #ffffff;
457
+ border: 2px solid #ffffff;
458
+ }
459
+
460
+ @keyframes badgePop {
461
+ 0% { transform: scale(0); opacity: 0; }
462
+ 100% { transform: scale(1); opacity: 1; }
463
+ }
464
+
465
+ .player-object.is-target.is-target-locked {
466
+ pointer-events: none !important;
467
+ opacity: 0.9;
468
+ border-color: #10b981 !important;
469
+ }
470
+
471
+ .player-object-content {
472
+ width: 100%;
473
+ height: 100%;
474
+ display: flex;
475
+ flex-direction: column;
476
+ align-items: center;
477
+ justify-content: center;
478
+ overflow: hidden;
479
+ word-break: break-word;
480
+ white-space: pre-wrap;
481
+ }
482
+
483
+ /* Çizgi Nesnesi Oynatıcı Stilleri */
484
+ .player-object[data-type="line"] {
485
+ background-color: transparent !important;
486
+ border: none !important;
487
+ box-shadow: none !important;
488
+ }
489
+
490
+ .player-line-bar {
491
+ width: 100%;
492
+ height: 0;
493
+ pointer-events: none;
494
+ box-sizing: border-box;
495
+ }
496
+
497
+ .player-object-content span,
498
+ .player-object-content .player-text-span {
499
+ width: 100%;
500
+ display: block;
501
+ text-align: inherit;
502
+ box-sizing: border-box;
503
+ }
504
+
505
+ .player-object-content img {
506
+ max-width: 100%;
507
+ max-height: 100%;
508
+ object-fit: contain;
509
+ pointer-events: none;
510
+ }
511
+
512
+ .image-caption {
513
+ margin-top: 4px;
514
+ font-size: 0.85rem;
515
+ font-weight: 600;
516
+ }
517
+
518
+ .cat-title {
519
+ font-size: 1.15rem;
520
+ font-weight: 700;
521
+ color: #065f46;
522
+ margin-bottom: 8px;
523
+ }
524
+
525
+ .slot-badge {
526
+ font-size: 1.4rem;
527
+ font-weight: 800;
528
+ color: #6d28d9;
529
+ }
530
+
531
+ .slot-text {
532
+ font-size: 0.85rem;
533
+ font-weight: 600;
534
+ color: #64748b;
535
+ }
536
+
537
+ /* KONTROL ALANI (Açık Zemin, Hiyerarşik Butonlar) */
538
+ .player-controls {
539
+ flex-shrink: 0;
540
+ min-height: 54px;
541
+ padding: 10px 18px;
542
+ display: flex;
543
+ align-items: center;
544
+ justify-content: space-between;
545
+ gap: 12px;
546
+ background: #ffffff;
547
+ border-top: 1px solid #f1f5f9;
548
+ box-sizing: border-box;
549
+ width: 100%;
550
+ }
551
+
552
+ .player-actions {
553
+ display: flex;
554
+ align-items: center;
555
+ gap: 10px;
556
+ margin-left: auto;
557
+ }
558
+
559
+ /* MOD DEĞİŞTİRİCİ (Segmented Switch) */
560
+ .player-mode-switch {
561
+ display: inline-flex;
562
+ align-items: center;
563
+ background: #f1f5f9;
564
+ border: 1px solid #e2e8f0;
565
+ border-radius: 10px;
566
+ padding: 3px;
567
+ gap: 2px;
568
+ }
569
+
570
+ .player-mode-switch .mode-btn {
571
+ border: none;
572
+ background: transparent;
573
+ color: #64748b;
574
+ font-size: 0.85rem;
575
+ font-weight: 500;
576
+ padding: 6px 14px;
577
+ border-radius: 7px;
578
+ cursor: pointer;
579
+ transition: all 0.15s ease;
580
+ display: inline-flex;
581
+ align-items: center;
582
+ gap: 4px;
583
+ white-space: nowrap;
584
+ user-select: none;
585
+ }
586
+
587
+ .player-mode-switch .mode-btn:hover {
588
+ color: #0f172a;
589
+ }
590
+
591
+ .player-mode-switch .mode-btn.active {
592
+ background: #ffffff;
593
+ color: #0f172a;
594
+ font-weight: 600;
595
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);
596
+ }
597
+
598
+ /* YARDIMCI İPUCU METNİ (Koyu panel değil, sade yardımcı metin) */
599
+ .player-footer {
600
+ height: auto;
601
+ min-height: 28px;
602
+ flex-shrink: 0;
603
+ padding: 8px 16px 2px 16px;
604
+ display: flex;
605
+ align-items: center;
606
+ justify-content: center;
607
+ background: transparent;
608
+ border: none;
609
+ color: #64748b;
610
+ font-size: 0.82rem;
611
+ box-sizing: border-box;
612
+ width: 100%;
613
+ }
614
+
615
+ .player-hint {
616
+ text-align: center;
617
+ display: inline-flex;
618
+ align-items: center;
619
+ justify-content: center;
620
+ gap: 6px;
621
+ color: #64748b;
622
+ font-size: 0.82rem;
623
+ line-height: 1.4;
624
+ overflow: hidden;
625
+ text-overflow: ellipsis;
626
+ white-space: nowrap;
627
+ }
628
+
629
+ /* TAMAMLANMA SONUÇ KARTI */
630
+ .completion-result-card {
631
+ min-height: 74px;
632
+ margin-top: 16px;
633
+ padding: 14px 16px;
634
+ display: flex;
635
+ align-items: center;
636
+ justify-content: space-between;
637
+ gap: 16px;
638
+ flex-shrink: 0;
639
+ box-sizing: border-box;
640
+ border: 1px solid #dcece2;
641
+ border-radius: 14px;
642
+ background: #f3f9f5;
643
+ animation: completionResultIn 0.3s ease-out;
644
+ }
645
+
646
+ .completion-result-card[hidden],
647
+ .player-controls[hidden],
648
+ .player-footer[hidden] {
649
+ display: none !important;
650
+ }
651
+
652
+ .completion-result-message {
653
+ min-width: 0;
654
+ display: flex;
655
+ align-items: center;
656
+ gap: 12px;
657
+ }
658
+
659
+ .completion-result-icon {
660
+ width: 44px;
661
+ height: 44px;
662
+ display: inline-flex;
663
+ align-items: center;
664
+ justify-content: center;
665
+ flex-shrink: 0;
666
+ border-radius: 12px;
667
+ background: #e0f2e6;
668
+ color: #29885a;
669
+ }
670
+
671
+ .completion-result-title {
672
+ margin: 0;
673
+ color: #253b30;
674
+ font-size: 1.0625rem;
675
+ font-weight: 600;
676
+ line-height: 1.3;
677
+ }
678
+
679
+ .completion-replay-btn {
680
+ min-height: 40px;
681
+ padding: 8px 14px;
682
+ display: inline-flex;
683
+ align-items: center;
684
+ justify-content: center;
685
+ gap: 7px;
686
+ flex-shrink: 0;
687
+ border: 1px solid #d3e2d8;
688
+ border-radius: 9px;
689
+ background: #ffffff;
690
+ color: #365747;
691
+ font: inherit;
692
+ font-size: 0.875rem;
693
+ font-weight: 600;
694
+ cursor: pointer;
695
+ transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
696
+ }
697
+
698
+ .completion-replay-btn:hover {
699
+ background: #f8fbf9;
700
+ border-color: #bcd5c5;
701
+ color: #253b30;
702
+ }
703
+
704
+ .completion-replay-btn:focus-visible {
705
+ outline: 2px solid #29885a;
706
+ outline-offset: 2px;
707
+ }
708
+
709
+ @keyframes completionResultIn {
710
+ from {
711
+ opacity: 0;
712
+ transform: translateY(8px);
713
+ }
714
+ to {
715
+ opacity: 1;
716
+ transform: translateY(0);
717
+ }
718
+ }
719
+
720
+ @media (max-width: 768px) {
721
+ .completion-result-card {
722
+ min-height: 68px;
723
+ margin-top: 12px;
724
+ padding: 12px;
725
+ gap: 12px;
726
+ flex-wrap: wrap;
727
+ }
728
+
729
+ .completion-result-icon {
730
+ width: 40px;
731
+ height: 40px;
732
+ border-radius: 10px;
733
+ }
734
+
735
+ .completion-result-title {
736
+ font-size: 1rem;
737
+ }
738
+
739
+ .completion-replay-btn {
740
+ margin-left: auto;
741
+ }
742
+ }
743
+
744
+ @media (max-width: 480px) {
745
+ .completion-result-card {
746
+ align-items: stretch;
747
+ flex-direction: column;
748
+ }
749
+
750
+ .completion-replay-btn {
751
+ width: 100%;
752
+ margin-left: 0;
753
+ }
754
+ }
755
+
756
+ @media (prefers-reduced-motion: reduce) {
757
+ .completion-result-card {
758
+ animation: none;
759
+ }
760
+ }
761
+ </style>
762
+ </head>
763
+ <body>
764
+ <div id="activity-app"></div>
765
+
766
+ <!-- Gömülü Proje Verisi -->
767
+ <script id="activity-data" type="application/json">
768
+ ${projectJsonEscaped}
769
+ <\/script>
770
+
771
+ <script>
772
+ ${this.getBundledRuntimeScript()}
773
+ <\/script>
774
+ </body>
775
+ </html>`;
776
+ }
777
+
778
+ getBundledRuntimeScript() {
779
+ // Sadece oynatıcı için gereken sınıflar: AudioSynthesizer, ValidationEngine (sanitizeText) ve ActivityEngine
780
+ return `
781
+ // Namespace
782
+ window.DND = window.DND || {};
783
+
784
+ // 1. AudioSynthesizer
785
+ ${AudioSynthesizer.toString()}
786
+ window.DND.AudioSynthesizer = AudioSynthesizer;
787
+
788
+ // 2. ValidationEngine (Sanitize)
789
+ window.DND.ValidationEngine = {
790
+ sanitizeText: function(str) {
791
+ if (str === null || str === undefined) return '';
792
+ const temp = document.createElement('div');
793
+ temp.textContent = String(str);
794
+ return temp.innerHTML;
795
+ }
796
+ };
797
+
798
+ // 3. ActivityEngine
799
+ ${ActivityEngine.toString()}
800
+ window.DND.ActivityEngine = ActivityEngine;
801
+
802
+ // 4. Otomatik Başlatma
803
+ window.addEventListener('DOMContentLoaded', function() {
804
+ try {
805
+ const rawData = document.getElementById('activity-data').textContent;
806
+ const project = JSON.parse(rawData);
807
+ const container = document.getElementById('activity-app');
808
+ window.gameInstance = new window.DND.ActivityEngine(container, project);
809
+ } catch (err) {
810
+ console.error('Etkinlik başlatma hatası:', err);
811
+ document.body.innerHTML = '<div style="color:white;padding:40px;font-family:sans-serif;">Etkinlik yüklenirken bir hata oluştu: ' + err.message + '</div>';
812
+ }
813
+ });
814
+ `;
815
+ }
816
+ }
817
+
818
+ // Global namespace
819
+ window.DND = window.DND || {};
820
+ window.DND.ExportManager = ExportManager;