Toowired commited on
Commit
f982ac7
·
verified ·
1 Parent(s): c1a840b

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +229 -56
index.html CHANGED
@@ -560,9 +560,12 @@
560
  <!-- PDF.js library for PDF support -->
561
  <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.12.313/pdf.min.js"></script>
562
 
 
 
 
563
  <script>
564
  document.addEventListener('DOMContentLoaded', () => {
565
- // Enhanced DOM Elements
566
  const apiKeyInput = document.getElementById('apiKey');
567
  const saveKeyBtn = document.getElementById('saveKeyBtn');
568
  const uploadBtn = document.getElementById('uploadBtn');
@@ -588,7 +591,7 @@
588
  const readingProgress = document.getElementById('readingProgress');
589
  const currentPositionMarker = document.getElementById('currentPositionMarker');
590
 
591
- // New feature elements
592
  const darkModeToggle = document.getElementById('darkModeToggle');
593
  const addBookmarkBtn = document.getElementById('addBookmarkBtn');
594
  const showBookmarksBtn = document.getElementById('showBookmarksBtn');
@@ -602,6 +605,41 @@
602
  let wordsPerMinute = 150; // Average reading speed
603
  let isBookmarkPanelOpen = false;
604
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
605
  // Caching & Smart Processing System
606
  class TTSCache {
607
  constructor() {
@@ -1450,51 +1488,168 @@
1450
  // Download functionality
1451
  initDownloadFeature();
1452
 
1453
- // Initialize Audio Library
1454
- document.getElementById('openLibraryBtn').addEventListener('click', () => {
1455
- document.getElementById('audioLibraryPanel').classList.add('open');
1456
- });
1457
-
1458
- document.getElementById('closeAudioLibrary').addEventListener('click', () => {
1459
- document.getElementById('audioLibraryPanel').classList.remove('open');
1460
- });
1461
-
1462
- document.getElementById('saveToLibraryBtn').addEventListener('click', saveToLibrary);
1463
- document.getElementById('clearLibraryBtn').addEventListener('click', () => {
1464
- if (confirm('Clear entire audio library? This cannot be undone.')) {
1465
- audioLibrary.clearLibrary();
1466
- showToast('Library cleared', 'success');
1467
  }
1468
- });
1469
-
1470
- document.getElementById('exportLibraryBtn').addEventListener('click', () => {
1471
- audioLibrary.exportLibrary();
1472
- });
1473
-
1474
- // Initialize Budget System
1475
- document.getElementById('openBudgetBtn').addEventListener('click', () => {
1476
- document.getElementById('costBudgetPanel').classList.add('open');
1477
- budgetManager.updateBudgetDisplay();
1478
- });
1479
-
1480
- document.getElementById('closeBudgetPanel').addEventListener('click', () => {
1481
- document.getElementById('costBudgetPanel').classList.remove('open');
1482
- });
1483
-
1484
- document.getElementById('monthlyBudget').addEventListener('change', (e) => {
1485
- budgetManager.setMonthlyBudget(parseFloat(e.target.value) || 0);
1486
- });
1487
-
1488
- document.getElementById('alertThreshold').addEventListener('input', (e) => {
1489
- budgetManager.setAlertThreshold(parseInt(e.target.value));
1490
- document.getElementById('alertThresholdValue').textContent = `${e.target.value}%`;
1491
- });
1492
-
1493
- // Initialize cache system
1494
- ttsCache.init();
1495
-
1496
- // Update library display
1497
- audioLibrary.updateLibraryDisplay();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1498
  }
1499
 
1500
  // Dark Mode Implementation
@@ -1950,7 +2105,7 @@
1950
  }
1951
  }
1952
 
1953
- // Toast notifications
1954
  function showToast(message, type = 'success', duration = 3000) {
1955
  const toast = document.createElement('div');
1956
  toast.className = `toast ${type}`;
@@ -1963,10 +2118,13 @@
1963
  }, duration);
1964
  }
1965
 
1966
- // Add slideOut animation
1967
- const style = document.createElement('style');
1968
- style.textContent = '@keyframes slideOut { from { transform: translateX(0); opacity: 1; } to { transform: translateX(100%); opacity: 0; } }';
1969
- document.head.appendChild(style);
 
 
 
1970
 
1971
  // API Key Management
1972
  saveKeyBtn.addEventListener('click', async () => {
@@ -2813,12 +2971,20 @@
2813
 
2814
  // Word document reader (.doc/.docx)
2815
  function readWordDocument(file) {
 
 
 
 
 
 
2816
  const reader = new FileReader();
2817
  reader.onload = async (e) => {
2818
  try {
2819
  // Use mammoth to convert docx to text
2820
  const result = await mammoth.extractRawText({arrayBuffer: e.target.result});
2821
  setDocumentContent(result.value);
 
 
2822
 
2823
  if (result.messages.length > 0) {
2824
  console.warn('Word processing warnings:', result.messages);
@@ -2826,10 +2992,12 @@
2826
  } catch (error) {
2827
  console.error('Error reading Word document:', error);
2828
  showToast('Error reading Word document. Please try saving as a different format.', 'error');
 
2829
  }
2830
  };
2831
  reader.onerror = () => {
2832
  showToast('Error reading Word document', 'error');
 
2833
  };
2834
  reader.readAsArrayBuffer(file);
2835
  }
@@ -3290,12 +3458,17 @@
3290
  return SmartTextProcessor.optimizeChunks(text, maxChunkSize);
3291
  }
3292
 
3293
- // Event listeners
3294
- refreshVoicesBtn.addEventListener('click', loadVoices);
3295
- languageSelect.addEventListener('change', loadVoices);
3296
 
3297
- // Initialize the application
3298
- init();
 
 
 
 
 
3299
  });
3300
  </script>
3301
  </body>
 
560
  <!-- PDF.js library for PDF support -->
561
  <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.12.313/pdf.min.js"></script>
562
 
563
+ <!-- Mammoth library for Word document support -->
564
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/mammoth/1.4.2/mammoth.browser.min.js"></script>
565
+
566
  <script>
567
  document.addEventListener('DOMContentLoaded', () => {
568
+ // Enhanced DOM Elements with null checks
569
  const apiKeyInput = document.getElementById('apiKey');
570
  const saveKeyBtn = document.getElementById('saveKeyBtn');
571
  const uploadBtn = document.getElementById('uploadBtn');
 
591
  const readingProgress = document.getElementById('readingProgress');
592
  const currentPositionMarker = document.getElementById('currentPositionMarker');
593
 
594
+ // New feature elements with null checks
595
  const darkModeToggle = document.getElementById('darkModeToggle');
596
  const addBookmarkBtn = document.getElementById('addBookmarkBtn');
597
  const showBookmarksBtn = document.getElementById('showBookmarksBtn');
 
605
  let wordsPerMinute = 150; // Average reading speed
606
  let isBookmarkPanelOpen = false;
607
 
608
+ // Add missing functions
609
+ function formatFileSize(bytes) {
610
+ if (bytes === 0) return '0 Bytes';
611
+ const k = 1024;
612
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
613
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
614
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
615
+ }
616
+
617
+ function updateBookmarkCount() {
618
+ if (bookmarkCount) {
619
+ bookmarkCount.textContent = bookmarks.length.toString();
620
+ }
621
+ }
622
+
623
+ function removeBookmark(id) {
624
+ bookmarks = bookmarks.filter(b => b.id !== id);
625
+ localStorage.setItem('bookmarks', JSON.stringify(bookmarks));
626
+ renderBookmarks();
627
+ updateBookmarkCount();
628
+ showToast('Bookmark removed', 'success', 1000);
629
+ }
630
+
631
+ // Voice preset functions (needed for onclick handlers)
632
+ window.voicePresets = {
633
+ loadPreset: function(id) {
634
+ console.log('Voice preset loading not yet implemented');
635
+ showToast('Voice presets feature coming soon', 'info');
636
+ },
637
+ deletePreset: function(id) {
638
+ console.log('Voice preset deletion not yet implemented');
639
+ showToast('Voice presets feature coming soon', 'info');
640
+ }
641
+ };
642
+
643
  // Caching & Smart Processing System
644
  class TTSCache {
645
  constructor() {
 
1488
  // Download functionality
1489
  initDownloadFeature();
1490
 
1491
+ // Enhanced Initialize function with proper error handling
1492
+ function init() {
1493
+ try {
1494
+ // Load saved API key
1495
+ if (apiKey) {
1496
+ apiKeyInput.value = apiKey;
1497
+ // Only load voices if we have elements
1498
+ if (voiceGrid && languageSelect) {
1499
+ loadVoices();
1500
+ }
 
 
 
 
1501
  }
1502
+
1503
+ // Set PDF.js worker path
1504
+ if (typeof pdfjsLib !== 'undefined') {
1505
+ pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.12.313/pdf.worker.min.js';
1506
+ }
1507
+
1508
+ // Initialize AudioContext on user interaction
1509
+ document.addEventListener('click', initAudioContext, { once: true });
1510
+
1511
+ // API Key visibility toggle
1512
+ const toggleKeyVisibility = document.getElementById('toggleKeyVisibility');
1513
+ const eyeIcon = document.getElementById('eyeIcon');
1514
+
1515
+ if (toggleKeyVisibility && eyeIcon && apiKeyInput) {
1516
+ toggleKeyVisibility.addEventListener('click', () => {
1517
+ if (apiKeyInput.type === 'password') {
1518
+ apiKeyInput.type = 'text';
1519
+ eyeIcon.className = 'fas fa-eye-slash';
1520
+ } else {
1521
+ apiKeyInput.type = 'password';
1522
+ eyeIcon.className = 'fas fa-eye';
1523
+ }
1524
+ });
1525
+ }
1526
+
1527
+ // Dark mode initialization
1528
+ if (darkModeToggle) {
1529
+ initDarkMode();
1530
+ }
1531
+
1532
+ // Keyboard shortcuts
1533
+ initKeyboardShortcuts();
1534
+
1535
+ // Bookmark system
1536
+ if (addBookmarkBtn && showBookmarksBtn) {
1537
+ initBookmarkSystem();
1538
+ }
1539
+
1540
+ // Progress indicator
1541
+ if (progressContainer) {
1542
+ initProgressIndicator();
1543
+ }
1544
+
1545
+ // Download functionality
1546
+ if (downloadBtn) {
1547
+ initDownloadFeature();
1548
+ }
1549
+
1550
+ // Initialize Audio Library
1551
+ const openLibraryBtn = document.getElementById('openLibraryBtn');
1552
+ const closeAudioLibrary = document.getElementById('closeAudioLibrary');
1553
+ const saveToLibraryBtn = document.getElementById('saveToLibraryBtn');
1554
+ const clearLibraryBtn = document.getElementById('clearLibraryBtn');
1555
+ const exportLibraryBtn = document.getElementById('exportLibraryBtn');
1556
+
1557
+ if (openLibraryBtn) {
1558
+ openLibraryBtn.addEventListener('click', () => {
1559
+ const panel = document.getElementById('audioLibraryPanel');
1560
+ if (panel) panel.classList.add('open');
1561
+ });
1562
+ }
1563
+
1564
+ if (closeAudioLibrary) {
1565
+ closeAudioLibrary.addEventListener('click', () => {
1566
+ const panel = document.getElementById('audioLibraryPanel');
1567
+ if (panel) panel.classList.remove('open');
1568
+ });
1569
+ }
1570
+
1571
+ if (saveToLibraryBtn) {
1572
+ saveToLibraryBtn.addEventListener('click', saveToLibrary);
1573
+ }
1574
+
1575
+ if (clearLibraryBtn) {
1576
+ clearLibraryBtn.addEventListener('click', () => {
1577
+ if (confirm('Clear entire audio library? This cannot be undone.')) {
1578
+ audioLibrary.clearLibrary();
1579
+ showToast('Library cleared', 'success');
1580
+ }
1581
+ });
1582
+ }
1583
+
1584
+ if (exportLibraryBtn) {
1585
+ exportLibraryBtn.addEventListener('click', () => {
1586
+ audioLibrary.exportLibrary();
1587
+ });
1588
+ }
1589
+
1590
+ // Initialize Budget System
1591
+ const openBudgetBtn = document.getElementById('openBudgetBtn');
1592
+ const closeBudgetPanel = document.getElementById('closeBudgetPanel');
1593
+ const monthlyBudget = document.getElementById('monthlyBudget');
1594
+ const alertThreshold = document.getElementById('alertThreshold');
1595
+
1596
+ if (openBudgetBtn) {
1597
+ openBudgetBtn.addEventListener('click', () => {
1598
+ const panel = document.getElementById('costBudgetPanel');
1599
+ if (panel) {
1600
+ panel.classList.add('open');
1601
+ budgetManager.updateBudgetDisplay();
1602
+ }
1603
+ });
1604
+ }
1605
+
1606
+ if (closeBudgetPanel) {
1607
+ closeBudgetPanel.addEventListener('click', () => {
1608
+ const panel = document.getElementById('costBudgetPanel');
1609
+ if (panel) panel.classList.remove('open');
1610
+ });
1611
+ }
1612
+
1613
+ if (monthlyBudget) {
1614
+ monthlyBudget.addEventListener('change', (e) => {
1615
+ budgetManager.setMonthlyBudget(parseFloat(e.target.value) || 0);
1616
+ });
1617
+ }
1618
+
1619
+ if (alertThreshold) {
1620
+ alertThreshold.addEventListener('input', (e) => {
1621
+ budgetManager.setAlertThreshold(parseInt(e.target.value));
1622
+ const thresholdValue = document.getElementById('alertThresholdValue');
1623
+ if (thresholdValue) {
1624
+ thresholdValue.textContent = `${e.target.value}%`;
1625
+ }
1626
+ });
1627
+ }
1628
+
1629
+ // Initialize cache system
1630
+ if (typeof ttsCache !== 'undefined') {
1631
+ ttsCache.init();
1632
+ }
1633
+
1634
+ // Update library display
1635
+ if (typeof audioLibrary !== 'undefined') {
1636
+ audioLibrary.updateLibraryDisplay();
1637
+ }
1638
+
1639
+ // Update bookmark count
1640
+ updateBookmarkCount();
1641
+
1642
+ // Cost breakdown modal
1643
+ const showCostBreakdown = document.getElementById('showCostBreakdown');
1644
+ if (showCostBreakdown) {
1645
+ showCostBreakdown.addEventListener('click', showCostBreakdownModal);
1646
+ }
1647
+
1648
+ } catch (error) {
1649
+ console.error('Error during initialization:', error);
1650
+ showToast('Some features may not work properly. Please refresh the page.', 'error');
1651
+ }
1652
+ }
1653
  }
1654
 
1655
  // Dark Mode Implementation
 
2105
  }
2106
  }
2107
 
2108
+ // Toast notifications function (moved up for early definition)
2109
  function showToast(message, type = 'success', duration = 3000) {
2110
  const toast = document.createElement('div');
2111
  toast.className = `toast ${type}`;
 
2118
  }, duration);
2119
  }
2120
 
2121
+ // Add slideOut animation style if not exists
2122
+ if (!document.querySelector('style[data-toast-styles]')) {
2123
+ const style = document.createElement('style');
2124
+ style.setAttribute('data-toast-styles', 'true');
2125
+ style.textContent = '@keyframes slideOut { from { transform: translateX(0); opacity: 1; } to { transform: translateX(100%); opacity: 0; } }';
2126
+ document.head.appendChild(style);
2127
+ }
2128
 
2129
  // API Key Management
2130
  saveKeyBtn.addEventListener('click', async () => {
 
2971
 
2972
  // Word document reader (.doc/.docx)
2973
  function readWordDocument(file) {
2974
+ // Check if mammoth library is available
2975
+ if (typeof mammoth === 'undefined') {
2976
+ showToast('Word document support not available. Mammoth library not loaded.', 'error');
2977
+ return;
2978
+ }
2979
+
2980
  const reader = new FileReader();
2981
  reader.onload = async (e) => {
2982
  try {
2983
  // Use mammoth to convert docx to text
2984
  const result = await mammoth.extractRawText({arrayBuffer: e.target.result});
2985
  setDocumentContent(result.value);
2986
+ showFileProgress(file.name, 'success');
2987
+ showToast(`Loaded Word document: ${formatFileSize(file.size)}`, 'success');
2988
 
2989
  if (result.messages.length > 0) {
2990
  console.warn('Word processing warnings:', result.messages);
 
2992
  } catch (error) {
2993
  console.error('Error reading Word document:', error);
2994
  showToast('Error reading Word document. Please try saving as a different format.', 'error');
2995
+ showFileProgress(file.name, 'error');
2996
  }
2997
  };
2998
  reader.onerror = () => {
2999
  showToast('Error reading Word document', 'error');
3000
+ showFileProgress(file.name, 'error');
3001
  };
3002
  reader.readAsArrayBuffer(file);
3003
  }
 
3458
  return SmartTextProcessor.optimizeChunks(text, maxChunkSize);
3459
  }
3460
 
3461
+ // Event listeners for main functionality
3462
+ if (refreshVoicesBtn) refreshVoicesBtn.addEventListener('click', loadVoices);
3463
+ if (languageSelect) languageSelect.addEventListener('change', loadVoices);
3464
 
3465
+ // Initialize everything when DOM is ready
3466
+ if (document.readyState === 'loading') {
3467
+ document.addEventListener('DOMContentLoaded', init);
3468
+ } else {
3469
+ // DOM is already loaded
3470
+ init();
3471
+ }
3472
  });
3473
  </script>
3474
  </body>