rails_accessibility_testing 1.5.5 → 1.5.6
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.
- checksums.yaml +4 -4
- data/ARCHITECTURE.md +336 -71
- data/CHANGELOG.md +17 -0
- data/GUIDES/getting_started.md +46 -177
- data/README.md +4 -0
- data/docs_site/_config.yml +3 -0
- data/docs_site/_layouts/default.html +95 -588
- data/docs_site/architecture.md +98 -469
- data/docs_site/ci_integration.md +87 -32
- data/docs_site/configuration.md +119 -51
- data/docs_site/contributing.md +166 -6
- data/docs_site/favicon.svg +31 -0
- data/docs_site/getting_started.md +188 -66
- data/docs_site/index.md +136 -21
- data/lib/generators/rails_a11y/install/templates/accessibility.yml.erb +16 -0
- data/lib/rails_accessibility_testing/accessibility_helper.rb +86 -16
- data/lib/rails_accessibility_testing/checks/base_check.rb +32 -5
- data/lib/rails_accessibility_testing/checks/interactive_elements_check.rb +23 -0
- data/lib/rails_accessibility_testing/config/yaml_loader.rb +9 -0
- data/lib/rails_accessibility_testing/error_message_builder.rb +28 -0
- data/lib/rails_accessibility_testing/rspec_integration.rb +25 -1
- data/lib/rails_accessibility_testing/version.rb +1 -1
- metadata +3 -2
|
@@ -6,6 +6,11 @@
|
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
7
|
<title>{% if page.title %}{{ page.title }} - {% endif %}{{ site.title }}</title>
|
|
8
8
|
<meta name="description" content="{{ site.description }}">
|
|
9
|
+
|
|
10
|
+
<!-- Favicon -->
|
|
11
|
+
<link rel="icon" type="image/svg+xml" href="{{ '/favicon.svg' | relative_url }}">
|
|
12
|
+
<link rel="alternate icon" href="{{ '/favicon.svg' | relative_url }}">
|
|
13
|
+
|
|
9
14
|
<style>
|
|
10
15
|
* {
|
|
11
16
|
margin: 0;
|
|
@@ -169,195 +174,12 @@
|
|
|
169
174
|
font-weight: 600;
|
|
170
175
|
}
|
|
171
176
|
|
|
172
|
-
/* Mermaid diagram
|
|
173
|
-
.mermaid
|
|
174
|
-
position: relative;
|
|
177
|
+
/* Mermaid diagram styles */
|
|
178
|
+
.mermaid {
|
|
175
179
|
margin: 2rem 0;
|
|
176
|
-
border: 1px solid #ddd;
|
|
177
|
-
border-radius: 8px;
|
|
178
|
-
padding: 1.5rem;
|
|
179
|
-
background: #fafafa;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
.mermaid-container .mermaid {
|
|
183
|
-
margin: 0;
|
|
184
180
|
text-align: center;
|
|
185
181
|
}
|
|
186
182
|
|
|
187
|
-
/* Fullscreen button */
|
|
188
|
-
.fullscreen-btn {
|
|
189
|
-
position: absolute;
|
|
190
|
-
top: 10px;
|
|
191
|
-
right: 10px;
|
|
192
|
-
background: #3498db;
|
|
193
|
-
color: white;
|
|
194
|
-
border: none;
|
|
195
|
-
padding: 8px 12px;
|
|
196
|
-
border-radius: 5px;
|
|
197
|
-
cursor: pointer;
|
|
198
|
-
font-size: 14px;
|
|
199
|
-
display: flex;
|
|
200
|
-
align-items: center;
|
|
201
|
-
gap: 5px;
|
|
202
|
-
transition: background 0.3s, transform 0.2s;
|
|
203
|
-
z-index: 10;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
.fullscreen-btn:hover {
|
|
207
|
-
background: #2980b9;
|
|
208
|
-
transform: scale(1.05);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
.fullscreen-btn:focus {
|
|
212
|
-
outline: 2px solid #2c3e50;
|
|
213
|
-
outline-offset: 2px;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
.fullscreen-btn svg {
|
|
217
|
-
width: 16px;
|
|
218
|
-
height: 16px;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/* Fullscreen overlay */
|
|
222
|
-
.diagram-fullscreen-overlay {
|
|
223
|
-
display: none;
|
|
224
|
-
position: fixed;
|
|
225
|
-
top: 0;
|
|
226
|
-
left: 0;
|
|
227
|
-
width: 100%;
|
|
228
|
-
height: 100%;
|
|
229
|
-
background: rgba(0, 0, 0, 0.95);
|
|
230
|
-
z-index: 9999;
|
|
231
|
-
overflow: auto;
|
|
232
|
-
animation: fadeIn 0.3s ease;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
.diagram-fullscreen-overlay.active {
|
|
236
|
-
display: flex;
|
|
237
|
-
align-items: center;
|
|
238
|
-
justify-content: center;
|
|
239
|
-
padding: 2rem;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
.diagram-fullscreen-content {
|
|
243
|
-
background: white;
|
|
244
|
-
border-radius: 8px;
|
|
245
|
-
padding: 2rem;
|
|
246
|
-
width: 98vw;
|
|
247
|
-
height: 98vh;
|
|
248
|
-
overflow: auto;
|
|
249
|
-
position: relative;
|
|
250
|
-
animation: slideIn 0.3s ease;
|
|
251
|
-
display: flex;
|
|
252
|
-
align-items: center;
|
|
253
|
-
justify-content: center;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
#diagram-zoom-wrapper {
|
|
257
|
-
display: flex;
|
|
258
|
-
align-items: center;
|
|
259
|
-
justify-content: center;
|
|
260
|
-
min-width: 100%;
|
|
261
|
-
min-height: 100%;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
.diagram-fullscreen-content .mermaid {
|
|
265
|
-
margin: 0;
|
|
266
|
-
display: block;
|
|
267
|
-
width: auto;
|
|
268
|
-
height: auto;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
.diagram-fullscreen-content .mermaid svg {
|
|
272
|
-
max-width: none !important;
|
|
273
|
-
max-height: none !important;
|
|
274
|
-
width: auto !important;
|
|
275
|
-
height: auto !important;
|
|
276
|
-
display: block;
|
|
277
|
-
margin: 0 auto;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
/* Close button */
|
|
281
|
-
.close-fullscreen-btn {
|
|
282
|
-
position: fixed;
|
|
283
|
-
top: 20px;
|
|
284
|
-
right: 20px;
|
|
285
|
-
background: #e74c3c;
|
|
286
|
-
color: white;
|
|
287
|
-
border: none;
|
|
288
|
-
padding: 10px 20px;
|
|
289
|
-
border-radius: 5px;
|
|
290
|
-
cursor: pointer;
|
|
291
|
-
font-size: 16px;
|
|
292
|
-
font-weight: bold;
|
|
293
|
-
z-index: 10000;
|
|
294
|
-
transition: background 0.3s, transform 0.2s;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
.close-fullscreen-btn:hover {
|
|
298
|
-
background: #c0392b;
|
|
299
|
-
transform: scale(1.05);
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
.close-fullscreen-btn:focus {
|
|
303
|
-
outline: 2px solid white;
|
|
304
|
-
outline-offset: 2px;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
/* Zoom controls */
|
|
308
|
-
.zoom-controls {
|
|
309
|
-
position: fixed;
|
|
310
|
-
top: 20px;
|
|
311
|
-
left: 20px;
|
|
312
|
-
display: flex;
|
|
313
|
-
gap: 10px;
|
|
314
|
-
z-index: 10000;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
.zoom-btn {
|
|
318
|
-
background: #3498db;
|
|
319
|
-
color: white;
|
|
320
|
-
border: none;
|
|
321
|
-
padding: 10px 15px;
|
|
322
|
-
border-radius: 5px;
|
|
323
|
-
cursor: pointer;
|
|
324
|
-
font-size: 16px;
|
|
325
|
-
font-weight: bold;
|
|
326
|
-
transition: background 0.3s, transform 0.2s;
|
|
327
|
-
display: flex;
|
|
328
|
-
align-items: center;
|
|
329
|
-
gap: 5px;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
.zoom-btn:hover {
|
|
333
|
-
background: #2980b9;
|
|
334
|
-
transform: scale(1.05);
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
.zoom-btn:focus {
|
|
338
|
-
outline: 2px solid white;
|
|
339
|
-
outline-offset: 2px;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
.zoom-btn:disabled {
|
|
343
|
-
background: #95a5a6;
|
|
344
|
-
cursor: not-allowed;
|
|
345
|
-
transform: none;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
.zoom-level {
|
|
349
|
-
background: rgba(255, 255, 255, 0.9);
|
|
350
|
-
color: #2c3e50;
|
|
351
|
-
padding: 10px 15px;
|
|
352
|
-
border-radius: 5px;
|
|
353
|
-
font-size: 14px;
|
|
354
|
-
font-weight: bold;
|
|
355
|
-
display: flex;
|
|
356
|
-
align-items: center;
|
|
357
|
-
min-width: 80px;
|
|
358
|
-
justify-content: center;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
183
|
/* Animations */
|
|
362
184
|
@keyframes fadeIn {
|
|
363
185
|
from {
|
|
@@ -381,17 +203,12 @@
|
|
|
381
203
|
}
|
|
382
204
|
}
|
|
383
205
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
.fullscreen-btn {
|
|
391
|
-
font-size: 12px;
|
|
392
|
-
padding: 6px 10px;
|
|
393
|
-
}
|
|
394
|
-
}
|
|
206
|
+
/* Responsive adjustments */
|
|
207
|
+
@media (max-width: 768px) {
|
|
208
|
+
.mermaid {
|
|
209
|
+
margin: 1rem 0;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
395
212
|
</style>
|
|
396
213
|
</head>
|
|
397
214
|
|
|
@@ -407,403 +224,71 @@
|
|
|
407
224
|
<p><a href="https://github.com/rayraycodes/rails-accessibility-testing" style="color: white;">GitHub</a></p>
|
|
408
225
|
</footer>
|
|
409
226
|
|
|
410
|
-
<!-- Mermaid.js for diagram rendering -
|
|
411
|
-
<script
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
227
|
+
<!-- Mermaid.js for diagram rendering - Use regular script for GitHub Pages compatibility -->
|
|
228
|
+
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
|
|
229
|
+
<script>
|
|
230
|
+
// Initialize Mermaid when loaded
|
|
231
|
+
(function() {
|
|
232
|
+
function initMermaidLib() {
|
|
233
|
+
if (typeof mermaid !== 'undefined') {
|
|
234
|
+
mermaid.initialize({
|
|
235
|
+
startOnLoad: false, // We'll call run() manually
|
|
236
|
+
theme: 'default',
|
|
237
|
+
securityLevel: 'loose',
|
|
238
|
+
flowchart: { useMaxWidth: true },
|
|
239
|
+
sequence: { useMaxWidth: true },
|
|
240
|
+
gantt: { useMaxWidth: true }
|
|
241
|
+
});
|
|
242
|
+
window.mermaid = mermaid;
|
|
243
|
+
return true;
|
|
244
|
+
}
|
|
245
|
+
return false;
|
|
428
246
|
}
|
|
429
|
-
|
|
430
|
-
const overlay = document.createElement('div');
|
|
431
|
-
overlay.id = 'diagram-fullscreen-overlay';
|
|
432
|
-
overlay.className = 'diagram-fullscreen-overlay';
|
|
433
|
-
overlay.setAttribute('role', 'dialog');
|
|
434
|
-
overlay.setAttribute('aria-modal', 'true');
|
|
435
|
-
overlay.setAttribute('aria-label', 'Fullscreen diagram viewer');
|
|
436
|
-
|
|
437
|
-
// Zoom controls
|
|
438
|
-
const zoomControls = document.createElement('div');
|
|
439
|
-
zoomControls.className = 'zoom-controls';
|
|
440
|
-
|
|
441
|
-
const zoomOutBtn = document.createElement('button');
|
|
442
|
-
zoomOutBtn.className = 'zoom-btn';
|
|
443
|
-
zoomOutBtn.textContent = '−';
|
|
444
|
-
zoomOutBtn.setAttribute('aria-label', 'Zoom out');
|
|
445
|
-
zoomOutBtn.onclick = zoomOut;
|
|
446
|
-
|
|
447
|
-
const zoomLevel = document.createElement('div');
|
|
448
|
-
zoomLevel.className = 'zoom-level';
|
|
449
|
-
zoomLevel.id = 'zoom-level-display';
|
|
450
|
-
zoomLevel.textContent = '100%';
|
|
451
|
-
|
|
452
|
-
const zoomInBtn = document.createElement('button');
|
|
453
|
-
zoomInBtn.className = 'zoom-btn';
|
|
454
|
-
zoomInBtn.textContent = '+';
|
|
455
|
-
zoomInBtn.setAttribute('aria-label', 'Zoom in');
|
|
456
|
-
zoomInBtn.onclick = zoomIn;
|
|
457
247
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
zoomControls.appendChild(zoomOutBtn);
|
|
465
|
-
zoomControls.appendChild(zoomLevel);
|
|
466
|
-
zoomControls.appendChild(zoomInBtn);
|
|
467
|
-
zoomControls.appendChild(resetBtn);
|
|
468
|
-
|
|
469
|
-
const closeBtn = document.createElement('button');
|
|
470
|
-
closeBtn.className = 'close-fullscreen-btn';
|
|
471
|
-
closeBtn.textContent = '✕ Close';
|
|
472
|
-
closeBtn.setAttribute('aria-label', 'Close fullscreen diagram');
|
|
473
|
-
closeBtn.onclick = closeFullscreen;
|
|
474
|
-
|
|
475
|
-
const content = document.createElement('div');
|
|
476
|
-
content.className = 'diagram-fullscreen-content';
|
|
477
|
-
|
|
478
|
-
overlay.appendChild(zoomControls);
|
|
479
|
-
overlay.appendChild(closeBtn);
|
|
480
|
-
overlay.appendChild(content);
|
|
481
|
-
document.body.appendChild(overlay);
|
|
482
|
-
|
|
483
|
-
// Close on overlay click (but not content click)
|
|
484
|
-
overlay.addEventListener('click', (e) => {
|
|
485
|
-
if (e.target === overlay) {
|
|
486
|
-
closeFullscreen();
|
|
487
|
-
}
|
|
488
|
-
});
|
|
489
|
-
|
|
490
|
-
// Close on Escape key
|
|
491
|
-
document.addEventListener('keydown', (e) => {
|
|
492
|
-
if (e.key === 'Escape' && overlay.classList.contains('active')) {
|
|
493
|
-
closeFullscreen();
|
|
494
|
-
}
|
|
495
|
-
});
|
|
496
|
-
|
|
497
|
-
// Keyboard shortcuts for zoom
|
|
498
|
-
document.addEventListener('keydown', (e) => {
|
|
499
|
-
if (overlay.classList.contains('active')) {
|
|
500
|
-
if (e.key === '+' || e.key === '=') {
|
|
501
|
-
e.preventDefault();
|
|
502
|
-
zoomIn();
|
|
503
|
-
} else if (e.key === '-') {
|
|
504
|
-
e.preventDefault();
|
|
505
|
-
zoomOut();
|
|
506
|
-
} else if (e.key === '0') {
|
|
507
|
-
e.preventDefault();
|
|
508
|
-
resetZoom();
|
|
248
|
+
// Try to initialize immediately
|
|
249
|
+
if (!initMermaidLib()) {
|
|
250
|
+
// If not loaded yet, wait for it
|
|
251
|
+
const checkInterval = setInterval(() => {
|
|
252
|
+
if (initMermaidLib()) {
|
|
253
|
+
clearInterval(checkInterval);
|
|
509
254
|
}
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
let startX = 0;
|
|
517
|
-
let startY = 0;
|
|
518
|
-
let currentX = 0;
|
|
519
|
-
let currentY = 0;
|
|
520
|
-
|
|
521
|
-
function initDrag(wrapper) {
|
|
522
|
-
wrapper.style.cursor = 'grab';
|
|
523
|
-
wrapper.style.userSelect = 'none';
|
|
524
|
-
|
|
525
|
-
wrapper.addEventListener('mousedown', (e) => {
|
|
526
|
-
if (e.button === 0) { // Left mouse button only
|
|
527
|
-
isDragging = true;
|
|
528
|
-
startX = e.clientX - currentX;
|
|
529
|
-
startY = e.clientY - currentY;
|
|
530
|
-
wrapper.style.cursor = 'grabbing';
|
|
531
|
-
}
|
|
532
|
-
});
|
|
533
|
-
|
|
534
|
-
document.addEventListener('mousemove', (e) => {
|
|
535
|
-
if (isDragging) {
|
|
536
|
-
e.preventDefault();
|
|
537
|
-
currentX = e.clientX - startX;
|
|
538
|
-
currentY = e.clientY - startY;
|
|
539
|
-
wrapper.style.transform = `scale(${currentZoom / 100}) translate(${currentX}px, ${currentY}px)`;
|
|
540
|
-
}
|
|
541
|
-
});
|
|
542
|
-
|
|
543
|
-
document.addEventListener('mouseup', () => {
|
|
544
|
-
if (isDragging) {
|
|
545
|
-
isDragging = false;
|
|
546
|
-
wrapper.style.cursor = 'grab';
|
|
547
|
-
}
|
|
548
|
-
});
|
|
549
|
-
|
|
550
|
-
// Touch support for mobile
|
|
551
|
-
let touchStartX = 0;
|
|
552
|
-
let touchStartY = 0;
|
|
553
|
-
|
|
554
|
-
wrapper.addEventListener('touchstart', (e) => {
|
|
555
|
-
if (e.touches.length === 1) {
|
|
556
|
-
isDragging = true;
|
|
557
|
-
touchStartX = e.touches[0].clientX - currentX;
|
|
558
|
-
touchStartY = e.touches[0].clientY - currentY;
|
|
559
|
-
}
|
|
560
|
-
});
|
|
561
|
-
|
|
562
|
-
document.addEventListener('touchmove', (e) => {
|
|
563
|
-
if (isDragging && e.touches.length === 1) {
|
|
564
|
-
e.preventDefault();
|
|
565
|
-
currentX = e.touches[0].clientX - touchStartX;
|
|
566
|
-
currentY = e.touches[0].clientY - touchStartY;
|
|
567
|
-
wrapper.style.transform = `scale(${currentZoom / 100}) translate(${currentX}px, ${currentY}px)`;
|
|
568
|
-
}
|
|
569
|
-
});
|
|
570
|
-
|
|
571
|
-
document.addEventListener('touchend', () => {
|
|
572
|
-
isDragging = false;
|
|
573
|
-
});
|
|
574
|
-
}
|
|
255
|
+
}, 50);
|
|
256
|
+
|
|
257
|
+
// Stop checking after 5 seconds
|
|
258
|
+
setTimeout(() => clearInterval(checkInterval), 5000);
|
|
259
|
+
}
|
|
260
|
+
})();
|
|
575
261
|
|
|
576
|
-
// Function to open diagram in fullscreen
|
|
577
|
-
function openFullscreen(diagramElement) {
|
|
578
|
-
const overlay = document.getElementById('diagram-fullscreen-overlay');
|
|
579
|
-
const content = overlay.querySelector('.diagram-fullscreen-content');
|
|
580
262
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
if (originalPre) {
|
|
585
|
-
const codeBlock = originalPre.querySelector('code.language-mermaid');
|
|
586
|
-
if (codeBlock) {
|
|
587
|
-
mermaidCode = codeBlock.textContent || codeBlock.innerText;
|
|
588
|
-
}
|
|
589
|
-
}
|
|
263
|
+
// Make processMermaidDiagrams available globally
|
|
264
|
+
window.processMermaidDiagrams = function() {
|
|
265
|
+
console.log('Processing Mermaid diagrams...');
|
|
590
266
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
for (const codeBlock of allCodeBlocks) {
|
|
595
|
-
const parentPre = codeBlock.closest('pre');
|
|
596
|
-
if (parentPre && parentPre.querySelector('.mermaid') === diagramElement) {
|
|
597
|
-
mermaidCode = codeBlock.textContent || codeBlock.innerText;
|
|
598
|
-
break;
|
|
599
|
-
}
|
|
600
|
-
}
|
|
267
|
+
if (typeof mermaid === 'undefined') {
|
|
268
|
+
console.error('Mermaid not loaded yet');
|
|
269
|
+
return;
|
|
601
270
|
}
|
|
602
271
|
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
// Create wrapper for zoom and drag functionality
|
|
606
|
-
const wrapper = document.createElement('div');
|
|
607
|
-
wrapper.id = 'diagram-zoom-wrapper';
|
|
608
|
-
wrapper.style.display = 'flex';
|
|
609
|
-
wrapper.style.alignItems = 'center';
|
|
610
|
-
wrapper.style.justifyContent = 'center';
|
|
611
|
-
wrapper.style.position = 'relative';
|
|
612
|
-
wrapper.style.width = 'fit-content';
|
|
613
|
-
wrapper.style.height = 'fit-content';
|
|
614
|
-
wrapper.style.minWidth = '100%';
|
|
615
|
-
wrapper.style.minHeight = '100%';
|
|
272
|
+
// Find all code blocks with mermaid language - try multiple selectors
|
|
273
|
+
let mermaidBlocks = document.querySelectorAll('code.language-mermaid, pre code.language-mermaid, code[class*="mermaid"], pre code[class*="language-mermaid"]');
|
|
616
274
|
|
|
617
|
-
// If
|
|
618
|
-
if (
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
// Re-render with Mermaid
|
|
628
|
-
mermaid.run({ nodes: [mermaidDiv] }).then(() => {
|
|
629
|
-
const svg = mermaidDiv.querySelector('svg');
|
|
630
|
-
if (svg) {
|
|
631
|
-
svg.style.display = 'block';
|
|
632
|
-
svg.style.visibility = 'visible';
|
|
275
|
+
// If none found, check all code blocks for mermaid syntax
|
|
276
|
+
if (mermaidBlocks.length === 0) {
|
|
277
|
+
console.log('No mermaid language blocks found, checking all code blocks for mermaid syntax...');
|
|
278
|
+
const allCodeBlocks = document.querySelectorAll('pre code');
|
|
279
|
+
const foundBlocks = [];
|
|
280
|
+
allCodeBlocks.forEach(block => {
|
|
281
|
+
const code = block.textContent || block.innerText;
|
|
282
|
+
if (code.trim().match(/^(graph|sequenceDiagram|flowchart|classDiagram|stateDiagram|erDiagram|gantt|pie|gitgraph|journey)/)) {
|
|
283
|
+
foundBlocks.push(block);
|
|
633
284
|
}
|
|
634
285
|
});
|
|
635
|
-
|
|
636
|
-
// Fallback: clone the existing diagram
|
|
637
|
-
const clone = diagramElement.cloneNode(true);
|
|
638
|
-
clone.style.display = 'block';
|
|
639
|
-
clone.style.visibility = 'visible';
|
|
640
|
-
clone.style.opacity = '1';
|
|
641
|
-
wrapper.appendChild(clone);
|
|
286
|
+
mermaidBlocks = foundBlocks;
|
|
642
287
|
}
|
|
643
288
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
// Ensure content can scroll to show entire diagram
|
|
647
|
-
content.style.overflow = 'auto';
|
|
648
|
-
content.style.display = 'flex';
|
|
649
|
-
content.style.alignItems = 'center';
|
|
650
|
-
content.style.justifyContent = 'center';
|
|
651
|
-
|
|
652
|
-
// Reset zoom and position
|
|
653
|
-
currentZoom = 100;
|
|
654
|
-
currentX = 0;
|
|
655
|
-
currentY = 0;
|
|
656
|
-
wrapper.style.transform = 'scale(1) translate(0px, 0px)';
|
|
657
|
-
wrapper.style.transformOrigin = 'center center';
|
|
658
|
-
updateZoomLevel(100);
|
|
659
|
-
|
|
660
|
-
// Initialize drag functionality
|
|
661
|
-
initDrag(wrapper);
|
|
662
|
-
|
|
663
|
-
// Show overlay
|
|
664
|
-
overlay.classList.add('active');
|
|
665
|
-
document.body.style.overflow = 'hidden';
|
|
666
|
-
|
|
667
|
-
// Ensure visibility and center after rendering
|
|
668
|
-
setTimeout(() => {
|
|
669
|
-
wrapper.style.display = 'flex';
|
|
670
|
-
wrapper.style.visibility = 'visible';
|
|
671
|
-
wrapper.style.opacity = '1';
|
|
672
|
-
|
|
673
|
-
const mermaidEl = wrapper.querySelector('.mermaid');
|
|
674
|
-
if (mermaidEl) {
|
|
675
|
-
mermaidEl.style.display = 'block';
|
|
676
|
-
mermaidEl.style.visibility = 'visible';
|
|
677
|
-
mermaidEl.style.opacity = '1';
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
const svg = wrapper.querySelector('svg');
|
|
681
|
-
if (svg) {
|
|
682
|
-
svg.style.display = 'block';
|
|
683
|
-
svg.style.visibility = 'visible';
|
|
684
|
-
svg.style.opacity = '1';
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
// Center scroll position
|
|
688
|
-
setTimeout(() => {
|
|
689
|
-
if (content.scrollHeight > content.clientHeight) {
|
|
690
|
-
content.scrollTop = (content.scrollHeight - content.clientHeight) / 2;
|
|
691
|
-
}
|
|
692
|
-
if (content.scrollWidth > content.clientWidth) {
|
|
693
|
-
content.scrollLeft = (content.scrollWidth - content.clientWidth) / 2;
|
|
694
|
-
}
|
|
695
|
-
}, 200);
|
|
696
|
-
}, 300);
|
|
697
|
-
|
|
698
|
-
// Focus on close button for accessibility
|
|
699
|
-
const closeBtn = overlay.querySelector('.close-fullscreen-btn');
|
|
700
|
-
closeBtn.focus();
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
// Zoom functionality
|
|
704
|
-
let currentZoom = 100;
|
|
705
|
-
const minZoom = 25;
|
|
706
|
-
const maxZoom = 500;
|
|
707
|
-
const zoomStep = 25;
|
|
708
|
-
|
|
709
|
-
function zoomIn() {
|
|
710
|
-
if (currentZoom < maxZoom) {
|
|
711
|
-
currentZoom = Math.min(currentZoom + zoomStep, maxZoom);
|
|
712
|
-
applyZoom();
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
function zoomOut() {
|
|
717
|
-
if (currentZoom > minZoom) {
|
|
718
|
-
currentZoom = Math.max(currentZoom - zoomStep, minZoom);
|
|
719
|
-
applyZoom();
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
function resetZoom() {
|
|
724
|
-
currentZoom = 100;
|
|
725
|
-
currentX = 0;
|
|
726
|
-
currentY = 0;
|
|
727
|
-
const wrapper = document.getElementById('diagram-zoom-wrapper');
|
|
728
|
-
if (wrapper) {
|
|
729
|
-
wrapper.style.transform = 'scale(1) translate(0px, 0px)';
|
|
730
|
-
updateZoomLevel(100);
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
function applyZoom() {
|
|
735
|
-
const wrapper = document.getElementById('diagram-zoom-wrapper');
|
|
736
|
-
if (wrapper) {
|
|
737
|
-
// Preserve current position when zooming
|
|
738
|
-
wrapper.style.transform = `scale(${currentZoom / 100}) translate(${currentX}px, ${currentY}px)`;
|
|
739
|
-
updateZoomLevel(currentZoom);
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
function updateZoomLevel(level) {
|
|
744
|
-
const zoomLevelEl = document.getElementById('zoom-level-display');
|
|
745
|
-
if (zoomLevelEl) {
|
|
746
|
-
zoomLevelEl.textContent = `${level}%`;
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
// Function to close fullscreen
|
|
751
|
-
function closeFullscreen() {
|
|
752
|
-
const overlay = document.getElementById('diagram-fullscreen-overlay');
|
|
753
|
-
overlay.classList.remove('active');
|
|
754
|
-
document.body.style.overflow = '';
|
|
755
|
-
// Reset zoom for next time
|
|
756
|
-
currentZoom = 100;
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
// Make functions global for button onclick
|
|
760
|
-
window.closeFullscreen = closeFullscreen;
|
|
761
|
-
window.zoomIn = zoomIn;
|
|
762
|
-
window.zoomOut = zoomOut;
|
|
763
|
-
window.resetZoom = resetZoom;
|
|
764
|
-
|
|
765
|
-
// Function to wrap diagrams in containers with fullscreen buttons
|
|
766
|
-
function wrapDiagramsWithButtons() {
|
|
767
|
-
const diagrams = document.querySelectorAll('.mermaid');
|
|
768
|
-
|
|
769
|
-
diagrams.forEach((diagram, index) => {
|
|
770
|
-
// Skip if already wrapped
|
|
771
|
-
if (diagram.parentElement.classList.contains('mermaid-container')) {
|
|
772
|
-
return;
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
// Create container
|
|
776
|
-
const container = document.createElement('div');
|
|
777
|
-
container.className = 'mermaid-container';
|
|
778
|
-
|
|
779
|
-
// Create fullscreen button
|
|
780
|
-
const btn = document.createElement('button');
|
|
781
|
-
btn.className = 'fullscreen-btn';
|
|
782
|
-
btn.setAttribute('aria-label', `View diagram ${index + 1} in fullscreen`);
|
|
783
|
-
btn.innerHTML = `
|
|
784
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
785
|
-
<path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"></path>
|
|
786
|
-
</svg>
|
|
787
|
-
<span>Fullscreen</span>
|
|
788
|
-
`;
|
|
789
|
-
|
|
790
|
-
btn.onclick = () => openFullscreen(diagram);
|
|
791
|
-
|
|
792
|
-
// Wrap diagram
|
|
793
|
-
diagram.parentNode.insertBefore(container, diagram);
|
|
794
|
-
container.appendChild(diagram);
|
|
795
|
-
container.appendChild(btn);
|
|
796
|
-
});
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
// Function to process Mermaid diagrams
|
|
800
|
-
function processMermaidDiagrams() {
|
|
801
|
-
// Find all code blocks with mermaid language
|
|
802
|
-
const mermaidBlocks = document.querySelectorAll('code.language-mermaid, pre code.language-mermaid');
|
|
289
|
+
console.log('Found', mermaidBlocks.length, 'Mermaid code blocks');
|
|
803
290
|
|
|
804
291
|
if (mermaidBlocks.length > 0) {
|
|
805
|
-
console.log('Found', mermaidBlocks.length, 'Mermaid diagram blocks');
|
|
806
|
-
|
|
807
292
|
// Process each block
|
|
808
293
|
mermaidBlocks.forEach((block, index) => {
|
|
809
294
|
// Get the parent pre element if it exists
|
|
@@ -811,6 +296,7 @@
|
|
|
811
296
|
if (preElement && preElement.tagName === 'PRE') {
|
|
812
297
|
// Get the mermaid code
|
|
813
298
|
const mermaidCode = block.textContent || block.innerText;
|
|
299
|
+
console.log('Processing Mermaid block', index + 1, ':', mermaidCode.substring(0, 50) + '...');
|
|
814
300
|
|
|
815
301
|
// Create a div for Mermaid to render into
|
|
816
302
|
const mermaidDiv = document.createElement('div');
|
|
@@ -823,18 +309,23 @@
|
|
|
823
309
|
});
|
|
824
310
|
|
|
825
311
|
// Run Mermaid to render all diagrams
|
|
312
|
+
console.log('Running Mermaid render...');
|
|
826
313
|
mermaid.run().then(() => {
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
314
|
+
console.log('Mermaid rendering complete');
|
|
315
|
+
}).catch((err) => {
|
|
316
|
+
console.error('Mermaid rendering error:', err);
|
|
830
317
|
});
|
|
831
318
|
} else {
|
|
832
319
|
// Fallback: look for pre > code blocks and check if they contain mermaid syntax
|
|
320
|
+
console.log('No mermaid language blocks found, checking all code blocks...');
|
|
833
321
|
const allCodeBlocks = document.querySelectorAll('pre code');
|
|
322
|
+
let foundMermaid = false;
|
|
323
|
+
|
|
834
324
|
allCodeBlocks.forEach((codeBlock) => {
|
|
835
325
|
const code = codeBlock.textContent || codeBlock.innerText;
|
|
836
326
|
// Check if it looks like mermaid code (starts with graph, sequenceDiagram, etc.)
|
|
837
327
|
if (code.trim().match(/^(graph|sequenceDiagram|flowchart|classDiagram|stateDiagram|erDiagram|gantt|pie|gitgraph|journey)/)) {
|
|
328
|
+
foundMermaid = true;
|
|
838
329
|
const preElement = codeBlock.parentElement;
|
|
839
330
|
if (preElement && preElement.tagName === 'PRE') {
|
|
840
331
|
const mermaidDiv = document.createElement('div');
|
|
@@ -846,22 +337,38 @@
|
|
|
846
337
|
});
|
|
847
338
|
|
|
848
339
|
// Run Mermaid after processing
|
|
849
|
-
if (document.querySelectorAll('.mermaid').length > 0) {
|
|
340
|
+
if (foundMermaid && document.querySelectorAll('.mermaid').length > 0) {
|
|
341
|
+
console.log('Running Mermaid render (fallback)...');
|
|
850
342
|
mermaid.run().then(() => {
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
343
|
+
console.log('Mermaid rendering complete (fallback)');
|
|
344
|
+
}).catch((err) => {
|
|
345
|
+
console.error('Mermaid rendering error (fallback):', err);
|
|
854
346
|
});
|
|
347
|
+
} else {
|
|
348
|
+
console.log('No Mermaid diagrams found to render');
|
|
855
349
|
}
|
|
856
350
|
}
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
// Wait for Mermaid to load, then process diagrams
|
|
354
|
+
function waitForMermaidAndProcess() {
|
|
355
|
+
if (typeof mermaid !== 'undefined' && typeof window.processMermaidDiagrams === 'function') {
|
|
356
|
+
// Wait a bit for Jekyll/Kramdown to finish processing
|
|
357
|
+
setTimeout(() => {
|
|
358
|
+
window.processMermaidDiagrams();
|
|
359
|
+
}, 300);
|
|
360
|
+
} else {
|
|
361
|
+
// Mermaid not loaded yet, wait and try again
|
|
362
|
+
setTimeout(waitForMermaidAndProcess, 100);
|
|
363
|
+
}
|
|
857
364
|
}
|
|
858
365
|
|
|
859
366
|
// Process diagrams when DOM is ready
|
|
860
367
|
if (document.readyState === 'loading') {
|
|
861
|
-
document.addEventListener('DOMContentLoaded',
|
|
368
|
+
document.addEventListener('DOMContentLoaded', waitForMermaidAndProcess);
|
|
862
369
|
} else {
|
|
863
|
-
// DOM already loaded,
|
|
864
|
-
|
|
370
|
+
// DOM already loaded, wait for Mermaid
|
|
371
|
+
waitForMermaidAndProcess();
|
|
865
372
|
}
|
|
866
373
|
</script>
|
|
867
374
|
</body>
|