RobinsAIWorld commited on
Commit
d1b354f
·
verified ·
1 Parent(s): ec39fd9

🐳 10/02 - 14:00 - They dont work, and still doesnt sync right and left

Browse files
Files changed (2) hide show
  1. index.html +2 -710
  2. script.js +6 -0
index.html CHANGED
@@ -180,713 +180,5 @@
180
  </div>
181
  </div>
182
 
183
- <script>
184
- document.addEventListener('DOMContentLoaded', function() {
185
- // Sample JSON data
186
- const sampleJSON = {
187
- "name": "John Doe",
188
- "age": 30,
189
- "isStudent": false,
190
- "address": {
191
- "street": "123 Main St",
192
- "city": "Anytown",
193
- "zipcode": "12345"
194
- },
195
- "hobbies": [
196
- "reading",
197
- "swimming",
198
- "coding"
199
- ],
200
- "contact": {
201
- "email": "john@example.com",
202
- "phone": "555-1234"
203
- }
204
- };
205
-
206
- // DOM elements
207
- const jsonEditor = document.getElementById('jsonEditor');
208
- const jsonOutput = document.getElementById('jsonOutput');
209
- const notification = document.getElementById('notification');
210
- const copyBtn = document.getElementById('copyBtn');
211
- const downloadBtn = document.getElementById('downloadBtn');
212
- const applyCodeBtn = document.getElementById('applyCodeBtn');
213
- const validationStatus = document.getElementById('validationStatus');
214
-
215
- // Create saved indicator
216
- const savedIndicator = document.createElement('div');
217
- savedIndicator.className = 'saved-indicator';
218
- savedIndicator.innerHTML = '<i class="fas fa-check-circle mr-2"></i>Saved';
219
- document.body.appendChild(savedIndicator);
220
-
221
- let isApplyingChanges = false;
222
-
223
- // Current state
224
- let jsonData = {};
225
- let history = [];
226
- let historyIndex = -1;
227
- const MAX_HISTORY = 50;
228
-
229
- // Track all editable fields for TAB navigation
230
- let editableFields = [];
231
- let currentFieldIndex = -1;
232
-
233
- // Layer colors for visual distinction
234
- const layerColors = [
235
- '#ef4444', '#f97316', '#eab308', '#22c55e',
236
- '#06b6d4', '#3b82f6', '#8b5cf6', '#ec4899'
237
- ];
238
-
239
- // Initialize with sample data
240
- loadJSON(sampleJSON);
241
-
242
- // Create hidden file input for opening files
243
- const fileInput = document.createElement('input');
244
- fileInput.type = 'file';
245
- fileInput.accept = 'application/json,.json';
246
- fileInput.style.display = 'none';
247
- document.body.appendChild(fileInput);
248
-
249
- // Open file functionality
250
- function openFile() {
251
- fileInput.click();
252
- }
253
-
254
- fileInput.addEventListener('change', (event) => {
255
- const file = event.target.files[0];
256
- if (file) {
257
- const reader = new FileReader();
258
- reader.onload = (e) => {
259
- try {
260
- const data = JSON.parse(e.target.result);
261
- loadJSON(data);
262
- showNotification('File loaded successfully!');
263
- } catch (error) {
264
- showNotification('Error loading file: Invalid JSON');
265
- }
266
- };
267
- reader.readAsText(file);
268
- }
269
- });
270
-
271
- document.getElementById('openBtn').addEventListener('click', openFile);
272
- document.getElementById('openBtn2').addEventListener('click', openFile);
273
-
274
- copyBtn.addEventListener('click', () => {
275
- jsonOutput.select();
276
- document.execCommand('copy');
277
- showNotification('JSON copied to clipboard!');
278
- });
279
-
280
- downloadBtn.addEventListener('click', () => {
281
- const blob = new Blob([jsonOutput.value], { type: 'application/json' });
282
- const url = URL.createObjectURL(blob);
283
- const a = document.createElement('a');
284
- a.href = url;
285
- a.download = 'data.json';
286
- document.body.appendChild(a);
287
- a.click();
288
- document.body.removeChild(a);
289
- URL.revokeObjectURL(url);
290
- showNotification('JSON file downloaded!');
291
- });
292
-
293
- // Load JSON data into the editor
294
- function loadJSON(data) {
295
- jsonData = JSON.parse(JSON.stringify(data));
296
- renderEditor();
297
- updateOutput();
298
- saveToHistory();
299
- }
300
-
301
- // Render the JSON editor
302
- function renderEditor() {
303
- jsonEditor.innerHTML = '';
304
- editableFields = [];
305
- currentFieldIndex = -1;
306
- renderElement(jsonEditor, jsonData, 0, 'root');
307
- }
308
-
309
- // Render a single JSON element (COMPLETE VERSION)
310
- function renderElement(container, data, depth, key, parentKey = 'root') {
311
- const layerClass = `lcars-layer-${Math.min(depth, 7)}`;
312
- const layerColor = layerColors[Math.min(depth, 7)];
313
-
314
- if (typeof data === 'object' && data !== null) {
315
- // Object or Array - render opening bracket and children
316
- const wrapper = document.createElement('div');
317
- wrapper.className = `json-item relative ${layerClass}`;
318
- wrapper.dataset.key = key;
319
- wrapper.dataset.parent = parentKey;
320
- wrapper.dataset.depth = depth;
321
- wrapper.dataset.layer = Math.min(depth, 7);
322
-
323
- // Layer indicator line (LCARS style)
324
- const layerIndicator = document.createElement('div');
325
- layerIndicator.className = 'layer-indicator';
326
- layerIndicator.style.left = `${depth * 24}px`;
327
- layerIndicator.style.background = layerColor;
328
- layerIndicator.style.boxShadow = `2px 0 8px ${layerColor}`;
329
- wrapper.appendChild(layerIndicator);
330
-
331
- const content = document.createElement('div');
332
- content.className = 'json-item-content flex items-start py-1';
333
- content.style.marginLeft = `${depth * 24 + 12}px`;
334
-
335
- // Key (for objects, not arrays)
336
- if (!Array.isArray(data) && key !== 'root') {
337
- const keySpan = document.createElement('span');
338
- keySpan.className = 'json-key';
339
- keySpan.textContent = `"${key}"`;
340
- keySpan.style.color = '#93c5fd';
341
- content.appendChild(keySpan);
342
-
343
- const colon = document.createElement('span');
344
- colon.textContent = ': ';
345
- colon.className = 'text-slate-500';
346
- content.appendChild(colon);
347
-
348
- // Make key editable
349
- keySpan.style.cursor = 'pointer';
350
- keySpan.addEventListener('click', (e) => {
351
- e.stopPropagation();
352
- makeEditable(keySpan, 'key', key, parentKey);
353
- });
354
- }
355
-
356
- // Value or children
357
- if (Array.isArray(data)) {
358
- // Array
359
- const bracket = document.createElement('span');
360
- bracket.className = `json-bracket bracket-layer-${Math.min(depth, 7)}`;
361
- bracket.textContent = '[';
362
- content.appendChild(bracket);
363
-
364
- wrapper.appendChild(content);
365
- container.appendChild(wrapper);
366
-
367
- // Render array items
368
- data.forEach((item, index) => {
369
- renderElement(container, item, depth + 1, index, key);
370
- });
371
-
372
- // Closing bracket
373
- const closingWrapper = document.createElement('div');
374
- closingWrapper.className = `json-item relative ${layerClass}`;
375
- closingWrapper.dataset.key = 'closing';
376
- closingWrapper.dataset.parent = key;
377
- closingWrapper.dataset.depth = depth;
378
- closingWrapper.dataset.layer = Math.min(depth, 7);
379
-
380
- const closingLayerIndicator = document.createElement('div');
381
- closingLayerIndicator.className = 'layer-indicator';
382
- closingLayerIndicator.style.left = `${depth * 24}px`;
383
- closingWrapper.appendChild(closingLayerIndicator);
384
-
385
- const closingContent = document.createElement('div');
386
- closingContent.className = 'json-item-content flex items-start py-1';
387
- closingContent.style.marginLeft = `${depth * 24 + 12}px`;
388
- const closingBracket = document.createElement('span');
389
- closingBracket.className = `json-bracket bracket-layer-${Math.min(depth, 7)}`;
390
- closingBracket.textContent = ']';
391
- closingContent.appendChild(closingBracket);
392
- closingWrapper.appendChild(closingContent);
393
- container.appendChild(closingWrapper);
394
- } else {
395
- // Object
396
- const bracket = document.createElement('span');
397
- bracket.className = `json-bracket bracket-layer-${Math.min(depth, 7)}`;
398
- bracket.textContent = '{';
399
- content.appendChild(bracket);
400
-
401
- wrapper.appendChild(content);
402
- container.appendChild(wrapper);
403
-
404
- // Render object properties
405
- Object.keys(data).forEach(propKey => {
406
- renderElement(container, data[propKey], depth + 1, propKey, key);
407
- });
408
-
409
- // Closing bracket
410
- const closingWrapper = document.createElement('div');
411
- closingWrapper.className = `json-item relative ${layerClass}`;
412
- closingWrapper.dataset.key = 'closing';
413
- closingWrapper.dataset.parent = key;
414
- closingWrapper.dataset.depth = depth;
415
- closingWrapper.dataset.layer = Math.min(depth, 7);
416
-
417
- const closingLayerIndicator = document.createElement('div');
418
- closingLayerIndicator.className = 'layer-indicator';
419
- closingLayerIndicator.style.left = `${depth * 24}px`;
420
- closingWrapper.appendChild(closingLayerIndicator);
421
-
422
- const closingContent = document.createElement('div');
423
- closingContent.className = 'json-item-content flex items-start py-1';
424
- closingContent.style.marginLeft = `${depth * 24 + 12}px`;
425
- const closingBracket = document.createElement('span');
426
- closingBracket.className = `json-bracket bracket-layer-${Math.min(depth, 7)}`;
427
- closingBracket.textContent = '}';
428
- closingContent.appendChild(closingBracket);
429
- closingWrapper.appendChild(closingContent);
430
- container.appendChild(closingWrapper);
431
- }
432
- } else {
433
- // Primitive value (string, number, boolean, null)
434
- const wrapper = document.createElement('div');
435
- wrapper.className = `json-item relative ${layerClass}`;
436
- wrapper.dataset.key = key;
437
- wrapper.dataset.parent = parentKey;
438
- wrapper.dataset.depth = depth;
439
- wrapper.dataset.layer = Math.min(depth, 7);
440
-
441
- // Layer indicator line
442
- const layerIndicator = document.createElement('div');
443
- layerIndicator.className = 'layer-indicator';
444
- layerIndicator.style.left = `${depth * 24}px`;
445
- layerIndicator.style.background = layerColor;
446
- layerIndicator.style.boxShadow = `2px 0 8px ${layerColor}`;
447
- wrapper.appendChild(layerIndicator);
448
-
449
- const content = document.createElement('div');
450
- content.className = 'json-item-content flex items-start py-1';
451
- content.style.marginLeft = `${depth * 24 + 12}px`;
452
-
453
- // Key
454
- if (key !== 'root') {
455
- const keySpan = document.createElement('span');
456
- keySpan.className = 'json-key';
457
- keySpan.textContent = `"${key}"`;
458
- keySpan.style.color = '#93c5fd';
459
- content.appendChild(keySpan);
460
-
461
- const colon = document.createElement('span');
462
- colon.textContent = ': ';
463
- colon.className = 'text-slate-500';
464
- content.appendChild(colon);
465
-
466
- // Make key editable
467
- keySpan.style.cursor = 'pointer';
468
- keySpan.addEventListener('click', (e) => {
469
- e.stopPropagation();
470
- makeEditable(keySpan, 'key', key, parentKey);
471
- });
472
- }
473
-
474
- // Value
475
- const valueSpan = document.createElement('span');
476
- valueSpan.className = 'json-value';
477
- if (typeof data === 'string') {
478
- valueSpan.textContent = `"${data}"`;
479
- valueSpan.style.color = '#6ee7b7';
480
- } else if (typeof data === 'number') {
481
- valueSpan.textContent = data;
482
- valueSpan.style.color = '#f472b6';
483
- } else if (typeof data === 'boolean') {
484
- valueSpan.textContent = data;
485
- valueSpan.style.color = '#fbbf24';
486
- } else if (data === null) {
487
- valueSpan.textContent = 'null';
488
- valueSpan.style.color = '#94a3b8';
489
- }
490
- content.appendChild(valueSpan);
491
-
492
- // Make value editable
493
- valueSpan.style.cursor = 'pointer';
494
- valueSpan.addEventListener('click', (e) => {
495
- e.stopPropagation();
496
- makeEditable(valueSpan, 'value', key, parentKey);
497
- });
498
-
499
- wrapper.appendChild(content);
500
- container.appendChild(wrapper);
501
- }
502
- }
503
-
504
- // Make an element editable
505
- function makeEditable(span, type, key, parentKey) {
506
- const currentValue = type === 'key' ? key : getValue(parentKey, key);
507
- let displayValue = type === 'key' ? currentValue : JSON.stringify(currentValue);
508
-
509
- // Remove quotes from display for editing
510
- if (displayValue.startsWith('"') && displayValue.endsWith('"')) {
511
- displayValue = displayValue.slice(1, -1);
512
- }
513
-
514
- const input = document.createElement('input');
515
- input.type = 'text';
516
- input.value = displayValue;
517
- input.className = `editable-field ${type}-input`;
518
-
519
- // Replace span with input
520
- span.parentNode.replaceChild(input, span);
521
- input.focus();
522
- input.select();
523
-
524
- // Save on blur or Enter
525
- const saveEdit = () => {
526
- const newValue = input.value.trim();
527
- input.parentNode.replaceChild(span, span);
528
-
529
- if (type === 'key') {
530
- // Rename the key
531
- if (newValue !== key) {
532
- renameKey(parentKey, key, newValue);
533
- }
534
- } else {
535
- // Update the value
536
- const parsedValue = parseValue(newValue);
537
- if (JSON.stringify(parsedValue) !== JSON.stringify(currentValue)) {
538
- updateValue(parentKey, key, parsedValue);
539
- }
540
- }
541
- };
542
-
543
- input.addEventListener('blur', saveEdit);
544
- input.addEventListener('keydown', (e) => {
545
- if (e.key === 'Enter') {
546
- e.preventDefault();
547
- input.blur();
548
- } else if (e.key === 'Tab') {
549
- e.preventDefault();
550
- const direction = e.shiftKey ? -1 : 1;
551
- navigateFields(direction);
552
- } else if (e.key === 'Shift+Enter' || (e.shiftKey && e.key === 'Enter')) {
553
- e.preventDefault();
554
- saveEdit();
555
- insertNewField({ key, parentKey });
556
- }
557
- });
558
- }
559
-
560
- // Navigate to next/previous editable field
561
- function navigateFields(direction) {
562
- // Find all editable spans
563
- const keys = jsonEditor.querySelectorAll('.json-key');
564
- const values = jsonEditor.querySelectorAll('.json-value');
565
- const allFields = [];
566
-
567
- keys.forEach(k => allFields.push({ element: k, type: 'key' }));
568
- values.forEach(v => allFields.push({ element: v, type: 'value' }));
569
-
570
- let currentIndex = -1;
571
- for (let i = 0; i < allFields.length; i++) {
572
- if (document.activeElement === allFields[i].element ||
573
- document.activeElement.parentNode === allFields[i].element.parentNode) {
574
- currentIndex = i;
575
- break;
576
- }
577
- }
578
-
579
- let nextIndex = currentIndex + direction;
580
- if (nextIndex < 0) nextIndex = allFields.length - 1;
581
- if (nextIndex >= allFields.length) nextIndex = 0;
582
-
583
- if (allFields[nextIndex]) {
584
- allFields[nextIndex].element.click();
585
- }
586
- }
587
-
588
- // Get nested value
589
- function getValue(parentKey, key) {
590
- if (parentKey === 'root') {
591
- return jsonData[key];
592
- }
593
- const parent = findElementByKey(jsonData, parentKey);
594
- if (parent && typeof parent === 'object') {
595
- return parent[key];
596
- }
597
- return undefined;
598
- }
599
-
600
- // Update a value
601
- function updateValue(parentKey, key, newValue) {
602
- if (parentKey === 'root') {
603
- jsonData[key] = newValue;
604
- } else {
605
- const parent = findElementByKey(jsonData, parentKey);
606
- if (parent && typeof parent === 'object') {
607
- parent[key] = newValue;
608
- }
609
- }
610
- renderEditor();
611
- updateOutput();
612
- saveToHistory();
613
- showSavedIndicator();
614
- }
615
-
616
- // Rename a key
617
- function renameKey(parentKey, oldKey, newKey) {
618
- if (parentKey === 'root') {
619
- jsonData[newKey] = jsonData[oldKey];
620
- delete jsonData[oldKey];
621
- } else {
622
- const parent = findElementByKey(jsonData, parentKey);
623
- if (parent && typeof parent === 'object' && !Array.isArray(parent)) {
624
- parent[newKey] = parent[oldKey];
625
- delete parent[oldKey];
626
- }
627
- }
628
- renderEditor();
629
- updateOutput();
630
- saveToHistory();
631
- showSavedIndicator();
632
- }
633
-
634
- // Insert a new field after the current one
635
- function insertNewField(currentFieldData) {
636
- const { key, parentKey } = currentFieldData;
637
-
638
- if (parentKey === 'root') {
639
- const keys = Object.keys(jsonData);
640
- const index = keys.indexOf(key);
641
- const newKey = 'newField';
642
-
643
- const newData = {};
644
- keys.forEach((k, i) => {
645
- newData[k] = jsonData[k];
646
- if (i === index) {
647
- newData[newKey] = '';
648
- }
649
- });
650
- if (index === -1 || index === keys.length - 1) {
651
- newData[newKey] = '';
652
- }
653
-
654
- jsonData = newData;
655
- } else {
656
- const parent = findElementByKey(jsonData, parentKey);
657
- if (parent && typeof parent === 'object' && !Array.isArray(parent)) {
658
- const keys = Object.keys(parent);
659
- const index = keys.indexOf(key);
660
- const newKey = 'newField';
661
-
662
- const newData = {};
663
- keys.forEach((k, i) => {
664
- newData[k] = parent[k];
665
- if (i === index) {
666
- newData[newKey] = '';
667
- }
668
- });
669
- if (index === -1 || index === keys.length - 1) {
670
- newData[newKey] = '';
671
- }
672
-
673
- Object.keys(parent).forEach(k => delete parent[k]);
674
- Object.assign(parent, newData);
675
- }
676
- }
677
-
678
- renderEditor();
679
- updateOutput();
680
- saveToHistory();
681
- showSavedIndicator();
682
- }
683
-
684
- // Parse a value from string to appropriate type
685
- function parseValue(value) {
686
- if (value === 'true') return true;
687
- if (value === 'false') return false;
688
- if (value === 'null') return null;
689
- if (!isNaN(value) && value.trim() !== '' && !isNaN(Number(value))) {
690
- return Number(value);
691
- }
692
- return value;
693
- }
694
-
695
- // Show saved indicator
696
- function showSavedIndicator() {
697
- savedIndicator.classList.add('show');
698
- setTimeout(() => {
699
- savedIndicator.classList.remove('show');
700
- }, 1500);
701
- }
702
-
703
- // Find an element by key in nested structure
704
- function findElementByKey(obj, key) {
705
- if (obj[key] !== undefined) return obj;
706
-
707
- for (let prop in obj) {
708
- if (typeof obj[prop] === 'object' && obj[prop] !== null) {
709
- const result = findElementByKey(obj[prop], key);
710
- if (result) return result;
711
- }
712
- }
713
-
714
- return null;
715
- }
716
-
717
- // Update JSON output
718
- function updateOutput() {
719
- if (isApplyingChanges) return;
720
- try {
721
- const jsonString = JSON.stringify(jsonData, null, 2);
722
- jsonOutput.value = jsonString;
723
- jsonOutput.style.borderColor = '#10b981';
724
- validationStatus.innerHTML = '<i class="fas fa-check-circle text-green-500"></i><span class="text-green-600">Valid JSON</span>';
725
- } catch (e) {
726
- jsonOutput.style.borderColor = '#ef4444';
727
- validationStatus.innerHTML = '<i class="fas fa-exclamation-circle text-red-500"></i><span class="text-red-600">Invalid JSON</span>';
728
- }
729
- }
730
-
731
- // Apply changes from code editor to visual editor
732
- function applyCodeChanges() {
733
- if (!jsonOutput.value.trim()) return false;
734
- try {
735
- const newData = JSON.parse(jsonOutput.value);
736
- isApplyingChanges = true;
737
- jsonData = JSON.parse(JSON.stringify(newData));
738
- renderEditor();
739
- updateOutput();
740
- saveToHistory();
741
- isApplyingChanges = false;
742
- showNotification('Changes applied successfully!');
743
- return true;
744
- } catch (e) {
745
- showNotification('Invalid JSON: ' + e.message);
746
- jsonOutput.style.borderColor = '#ef4444';
747
- validationStatus.innerHTML = '<i class="fas fa-exclamation-circle text-red-500"></i><span class="text-red-600">Invalid JSON</span>';
748
- return false;
749
- }
750
- }
751
-
752
- // Real-time validation of code editor
753
- jsonOutput.addEventListener('input', () => {
754
- try {
755
- JSON.parse(jsonOutput.value);
756
- jsonOutput.style.borderColor = '#10b981';
757
- validationStatus.innerHTML = '<i class="fas fa-check-circle text-green-500"></i><span class="text-green-600">Valid JSON</span>';
758
- } catch (e) {
759
- jsonOutput.style.borderColor = '#ef4444';
760
- validationStatus.innerHTML = '<i class="fas fa-exclamation-circle text-red-500"></i><span class="text-red-600">Invalid JSON</span>';
761
- }
762
- });
763
-
764
- // Apply button click
765
- applyCodeBtn.addEventListener('click', applyCodeChanges);
766
-
767
- // Auto-apply on Ctrl+Enter or Cmd+Enter
768
- jsonOutput.addEventListener('keydown', (e) => {
769
- if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
770
- e.preventDefault();
771
- applyCodeChanges();
772
- }
773
- });
774
-
775
- // Auto-apply on blur (when clicking away)
776
- jsonOutput.addEventListener('blur', () => {
777
- const autoSaveStatus = document.getElementById('autoSaveStatus');
778
- if (applyCodeChanges()) {
779
- autoSaveStatus.classList.remove('hidden');
780
- setTimeout(() => {
781
- autoSaveStatus.classList.add('hidden');
782
- }, 2000);
783
- }
784
- }, true);
785
-
786
- // Show notification
787
- function showNotification(message) {
788
- const notificationContent = notification.querySelector('p');
789
- notificationContent.textContent = message;
790
- notification.classList.add('show');
791
-
792
- setTimeout(() => {
793
- notification.classList.remove('show');
794
- }, 3000);
795
- }
796
-
797
- // Save to history for undo/redo
798
- function saveToHistory() {
799
- if (historyIndex < history.length - 1) {
800
- history = history.slice(0, historyIndex + 1);
801
- }
802
-
803
- if (history.length >= MAX_HISTORY) {
804
- history.shift();
805
- historyIndex--;
806
- }
807
-
808
- if (history.length > 0 && JSON.stringify(history[historyIndex]) === JSON.stringify(jsonData)) {
809
- return;
810
- }
811
-
812
- history.push(JSON.parse(JSON.stringify(jsonData)));
813
- historyIndex = history.length - 1;
814
- }
815
-
816
- // Undo action
817
- function undo() {
818
- if (historyIndex > 0) {
819
- historyIndex--;
820
- jsonData = JSON.parse(JSON.stringify(history[historyIndex]));
821
- renderEditor();
822
- updateOutput();
823
- showNotification('Undo successful');
824
- }
825
- }
826
-
827
- // Redo action
828
- function redo() {
829
- if (historyIndex < history.length - 1) {
830
- historyIndex++;
831
- jsonData = JSON.parse(JSON.stringify(history[historyIndex]));
832
- renderEditor();
833
- updateOutput();
834
- showNotification('Redo successful');
835
- }
836
- }
837
-
838
- // Event listeners for undo/redo
839
- document.getElementById('undoBtn').addEventListener('click', undo);
840
- document.getElementById('redoBtn').addEventListener('click', redo);
841
-
842
- // Paste in JSON output pane
843
- jsonOutput.addEventListener('paste', (e) => {
844
- e.preventDefault();
845
- const pasteHandler = (text) => {
846
- try {
847
- const data = JSON.parse(text);
848
- loadJSON(data);
849
- showNotification('JSON pasted and loaded successfully');
850
- } catch (parseError) {
851
- const start = jsonOutput.selectionStart;
852
- const end = jsonOutput.selectionEnd;
853
- const currentValue = jsonOutput.value;
854
- jsonOutput.value = currentValue.substring(0, start) + text + currentValue.substring(end);
855
- }
856
- };
857
-
858
- navigator.clipboard.readText().then(text => {
859
- pasteHandler(text);
860
- }).catch(err => {
861
- const text = (e.originalEvent || e).clipboardData.getData('text/plain');
862
- pasteHandler(text);
863
- });
864
- });
865
-
866
- // Format JSON
867
- document.getElementById('formatBtn').addEventListener('click', () => {
868
- updateOutput();
869
- showNotification('JSON formatted');
870
- });
871
-
872
- document.getElementById('formatBtn2').addEventListener('click', () => {
873
- updateOutput();
874
- showNotification('JSON formatted');
875
- });
876
-
877
- // Validate JSON
878
- document.getElementById('validateBtn').addEventListener('click', () => {
879
- try {
880
- JSON.parse(jsonOutput.value);
881
- showNotification('JSON is valid!');
882
- } catch (e) {
883
- showNotification('Invalid JSON: ' + e.message);
884
- }
885
- });
886
-
887
- document.getElementById('validateBtn2').addEventListener('click', () => {
888
- try {
889
- JSON.parse(jsonOutput.value);
890
- showNotification('JSON is valid!');
891
- } catch (e) {
892
- showNotification('Invalid JSON: ' + e.message);
 
180
  </div>
181
  </div>
182
 
183
+ <script src="script.js"></script>
184
+ </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
script.js CHANGED
@@ -772,4 +772,10 @@ document.addEventListener('DOMContentLoaded', function() {
772
  history.push(JSON.parse(JSON.stringify(jsonData)));
773
  historyIndex = history.length - 1;
774
  }
 
 
 
 
 
 
775
  });
 
772
  history.push(JSON.parse(JSON.stringify(jsonData)));
773
  historyIndex = history.length - 1;
774
  }
775
+
776
+ // Initialize on DOM ready
777
+ document.addEventListener('DOMContentLoaded', function() {
778
+ // Re-initialize with sample data
779
+ loadJSON(sampleJSON);
780
+ });
781
  });