Convert.ist: NEW

 <!DOCTYPE html>

<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Ultimate DOCX Generator (1000% Perfection)</title>
  <!-- Dependencies (loaded from CDN) -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.0.5/purify.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.js"></script>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.css">
  <style>
    :root {
      --primary: #2563eb;
      --primary-dark: #1e40af;
      --bg: #f8fafc;
      --text: #1e293b;
      --success: #10b981;
      --error: #ef4444;
      --warning: #f59e0b;
      --sidebar: #e2e8f0;
    }
    @media (prefers-color-scheme: dark) {
      :root {
        --bg: #0f172a;
        --text: #f8fafc;
        --sidebar: #1e293b;
      }
    }
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    body {
      font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
      line-height: 1.6;
      background: var(--bg);
      color: var(--text);
      min-height: 100vh;
    }
    .container {
      display: grid;
      grid-template-columns: 250px 1fr;
      min-height: 100vh;
    }
    .sidebar {
      background: var(--sidebar);
      padding: 1.5rem;
      border-right: 1px solid rgba(0,0,0,0.1);
    }
    .main-content {
      padding: 2rem;
      overflow-x: hidden;
    }
    h1 {
      color: var(--primary);
      margin-bottom: 1.5rem;
      text-align: center;
    }
    .editor-container {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 1.5rem;
    }
    @media (max-width: 1024px) {
      .editor-container {
        grid-template-columns: 1fr;
      }
    }
    @media (max-width: 768px) {
      .container {
        grid-template-columns: 1fr;
      }
      .sidebar {
        display: none;
      }
    }
    .toolbar {
      display: flex;
      gap: 0.5rem;
      flex-wrap: wrap;
      margin-bottom: 1rem;
      padding: 0.5rem;
      background: var(--sidebar);
      border-radius: 8px;
    }
    button {
      background: var(--primary);
      color: white;
      border: none;
      padding: 0.5rem 1rem;
      border-radius: 6px;
      cursor: pointer;
      font-size: 0.9rem;
      transition: all 0.2s;
      display: flex;
      align-items: center;
      gap: 0.3rem;
    }
    button:hover {
      background: var(--primary-dark);
      transform: translateY(-1px);
    }
    button:active {
      transform: translateY(0);
    }
    button.secondary {
      background: var(--sidebar);
      color: var(--text);
      border: 1px solid var(--primary);
    }
    button.secondary:hover {
      background: var(--primary);
      color: white;
    }
    #editor {
      min-height: 500px;
      border: 2px solid var(--primary);
      border-radius: 8px;
      padding: 1rem;
      background: white;
      color: black;
      outline: none;
      overflow-y: auto;
    }
    #preview {
      min-height: 500px;
      border: 2px solid var(--primary);
      border-radius: 8px;
      padding: 1rem;
      background: var(--bg);
      overflow-y: auto;
    }
    .convert-btn {
      width: 100%;
      padding: 1rem;
      margin-top: 1.5rem;
      font-weight: bold;
      background: var(--success);
    }
    .convert-btn:hover {
      background: #059669;
    }
    .loading {
      display: none;
      text-align: center;
      margin: 1rem 0;
    }
    .toast {
      position: fixed;
      bottom: 1rem;
      right: 1rem;
      padding: 1rem;
      background: var(--success);
      color: white;
      border-radius: 8px;
      display: none;
      box-shadow: 0 4px 12px rgba(0,0,0,0.15);
      z-index: 1000;
    }
    .error {
      background: var(--error) !important;
    }
    .warning {
      background: var(--warning) !important;
    }
    .sidebar-section {
      margin-bottom: 1.5rem;
    }
    .sidebar-title {
      font-weight: bold;
      margin-bottom: 0.5rem;
      color: var(--primary);
      display: flex;
      align-items: center;
      gap: 0.5rem;
    }
    .sidebar-menu {
      list-style: none;
    }
    .sidebar-menu li {
      margin-bottom: 0.3rem;
    }
    .sidebar-menu button {
      width: 100%;
      text-align: left;
      justify-content: flex-start;
    }
    .feature-badge {
      background: var(--primary-dark);
      color: white;
      padding: 0.2rem 0.5rem;
      border-radius: 12px;
      font-size: 0.7rem;
      margin-left: 0.5rem;
    }
    .template-preview {
      width: 100%;
      height: 100px;
      background: white;
      border: 1px solid #ddd;
      margin-bottom: 0.5rem;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      transition: all 0.2s;
    }
    .template-preview:hover {
      transform: scale(1.02);
      box-shadow: 0 4px 8px rgba(0,0,0,0.1);
    }
    .tab-buttons {
      display: flex;
      margin-bottom: 1rem;
    }
    .tab-button {
      border-radius: 0;
      border-bottom: 3px solid transparent;
    }
    .tab-button.active {
      border-bottom: 3px solid var(--primary-dark);
    }
    .tab-content {
      display: none;
    }
    .tab-content.active {
      display: block;
    }
    .settings-option {
      margin-bottom: 1rem;
    }
    .settings-option label {
      display: block;
      margin-bottom: 0.3rem;
      font-weight: 500;
    }
    .settings-option select, .settings-option input {
      width: 100%;
      padding: 0.5rem;
      border-radius: 4px;
      border: 1px solid #ddd;
    }
    .progress-bar {
      width: 100%;
      height: 10px;
      background: #e2e8f0;
      border-radius: 5px;
      margin-top: 0.5rem;
      overflow: hidden;
    }
    .progress-fill {
      height: 100%;
      background: var(--primary);
      width: 0%;
      transition: width 0.3s;
    }
    .ai-prompt {
      display: flex;
      gap: 0.5rem;
      margin-top: 1rem;
    }
    .ai-prompt input {
      flex-grow: 1;
      padding: 0.5rem;
      border-radius: 4px;
      border: 1px solid #ddd;
    }
    .ai-prompt button {
      white-space: nowrap;
    }
    .watermark-toggle {
      display: flex;
      align-items: center;
      gap: 0.5rem;
    }
    .toggle-switch {
      position: relative;
      display: inline-block;
      width: 50px;
      height: 24px;
    }
    .toggle-switch input {
      opacity: 0;
      width: 0;
      height: 0;
    }
    .slider {
      position: absolute;
      cursor: pointer;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background-color: #ccc;
      transition: .4s;
      border-radius: 24px;
    }
    .slider:before {
      position: absolute;
      content: "";
      height: 16px;
      width: 16px;
      left: 4px;
      bottom: 4px;
      background-color: white;
      transition: .4s;
      border-radius: 50%;
    }
    input:checked + .slider {
      background-color: var(--success);
    }
    input:checked + .slider:before {
      transform: translateX(26px);
    }
    .autocomplete-suggestion {
      position: absolute;
      background: #f1f5f9;
      border: 1px solid var(--primary);
      border-radius: 4px;
      padding: 0.5rem;
      z-index: 10;
      color: var(--text);
      font-size: 0.9rem;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="sidebar">
      <div class="sidebar-section">
        <h2 class="sidebar-title">Document Tools</h2>
        <ul class="sidebar-menu">
          <li><button onclick="newDocument()"><span>🆕</span> New Document</button></li>
          <li><button onclick="loadDocument()"><span>📂</span> Load DOCX</button></li>
          <li><button onclick="generateDOCX()" class="convert-btn"><span>💾</span> Save as DOCX</button></li>
          <li><button onclick="printDocument()"><span>🖨️</span> Print</button></li>
        </ul>
      </div>
      
      <div class="sidebar-section">
        <h2 class="sidebar-title">Templates <span class="feature-badge">PRO</span></h2>
        <div class="template-preview" onclick="applyTemplate('report')">
          Business Report
        </div>
        <div class="template-preview" onclick="applyTemplate('letter')">
          Formal Letter
        </div>
        <div class="template-preview" onclick="applyTemplate('resume')">
          Resume/CV
        </div>
      </div>
      
      <div class="sidebar-section">
        <h2 class="sidebar-title">AI Assistant <span class="feature-badge">BETA</span></h2>
        <div class="ai-prompt">
          <input type="text" id="aiPrompt" placeholder="Improve this text...">
          <button onclick="generateWithAI()">Go</button>
        </div>
      </div>
      
      <div class="sidebar-section">
        <h2 class="sidebar-title">Document Stats</h2>
        <div id="documentStats">
          <p>Words: <span id="wordCount">0</span></p>
          <p>Characters: <span id="charCount">0</span></p>
          <p>Pages: <span id="pageCount">0</span></p>
        </div>
      </div>
    </div>
    
    <div class="main-content">
      <h1>Ultimate DOCX Generator <span class="feature-badge">1000% PERFECTION</span></h1>
      
      <div class="tab-buttons">
        <button class="tab-button active" onclick="openTab('editTab')">Editor</button>
        <button class="tab-button" onclick="openTab('previewTab')">Preview</button>
        <button class="tab-button" onclick="openTab('settingsTab')">Settings</button>
      </div>
      
      <div id="editTab" class="tab-content active">
        <div class="toolbar">
          <button onclick="formatText('bold')"><span>🔊</span> Bold</button>
          <button onclick="formatText('italic')"><span>🔊</span> Italic</button>
          <button onclick="formatText('underline')"><span>🔊</span> Underline</button>
          <button onclick="formatText('heading1')"><span>🔊</span> H1</button>
          <button onclick="formatText('heading2')"><span>🔊</span> H2</button>
          <button onclick="formatText('bullet')"><span>🔊</span> Bullets</button>
          <button onclick="formatText('numbered')"><span>🔊</span> Numbers</button>
          <button onclick="formatText('quote')"><span>🔊</span> Quote</button>
          <button onclick="insertImage()"><span>🖼️</span> Image</button>
          <button onclick="insertChart()"><span>📊</span> Chart</button>
          <button onclick="insertTable()"><span>🔊</span> Table</button>
          <button onclick="insertEquation()"><span>🔊</span> Equation</button>
          <button onclick="insertLink()"><span>🔗</span> Link</button>
        </div>
        <div id="editor" contenteditable="true">
          <h1>My Perfect Document</h1>
          <p>Start typing here to create your professional document...</p>
        </div>
      </div>
      
      <div id="previewTab" class="tab-content">
        <div id="preview"></div>
      </div>
      
      <div id="settingsTab" class="tab-content">
        <div class="settings-option">
          <label for="pageSize">Page Size:</label>
          <select id="pageSize">
            <option value="A4">A4 (210 × 297 mm)</option>
            <option value="Letter">Letter (8.5 × 11 in)</option>
            <option value="Legal">Legal (8.5 × 14 in)</option>
          </select>
        </div>
        
        <div class="settings-option">
          <label for="pageOrientation">Page Orientation:</label>
          <select id="pageOrientation">
            <option value="portrait">Portrait</option>
            <option value="landscape">Landscape</option>
          </select>
        </div>
        
        <div class="settings-option">
          <label for="marginSize">Margin Size:</label>
          <select id="marginSize">
            <option value="normal">Normal (1 in)</option>
            <option value="narrow">Narrow (0.5 in)</option>
            <option value="wide">Wide (1.5 in)</option>
          </select>
        </div>
        
        <div class="settings-option">
          <div class="watermark-toggle">
            <label>Add Watermark:</label>
            <label class="toggle-switch">
              <input type="checkbox" id="watermarkToggle">
              <span class="slider"></span>
            </label>
          </div>
          <input type="text" id="watermarkText" placeholder="Watermark text" style="margin-top: 0.5rem;" disabled>
        </div>
        
        <div class="settings-option">
          <div class="watermark-toggle">
            <label>Enable AI Autocomplete:</label>
            <label class="toggle-switch">
              <input type="checkbox" id="autocompleteToggle">
              <span class="slider"></span>
            </label>
          </div>
        </div>
        
        <div class="settings-option">
          <label for="documentTheme">Document Theme:</label>
          <select id="documentTheme">
            <option value="default">Default</option>
            <option value="professional">Professional</option>
            <option value="modern">Modern</option>
            <option value="elegant">Elegant</option>
          </select>
        </div>
        
        <button onclick="applySettings()" style="margin-top: 1rem;">Apply Settings</button>
      </div>
      
      <div class="loading" id="loading">
        <div>Generating your perfect document...</div>
        <div class="progress-bar">
          <div class="progress-fill" id="progressFill"></div>
        </div>
        <div id="progress">0%</div>
      </div>
      
      <div class="toast" id="toast">DOCX Generated Successfully!</div>
    </div>
  </div>

  <script>
    // ===== GLOBAL VARIABLES ===== //
    const editor = document.getElementById('editor');
    const preview = document.getElementById('preview');
    let images = [];
    let charts = [];
    let tables = [];
    let currentTemplate = null;
    let isAutocompleteEnabled = false;
    
    // Document settings
    const documentSettings = {
      pageSize: 'A4',
      orientation: 'portrait',
      margins: 'normal',
      watermark: false,
      watermarkText: '',
      theme: 'default'
    };

    // ===== INITIALIZATION ===== //
    document.addEventListener('DOMContentLoaded', function() {
      updatePreview();
      updateStats();
      
      // Set up event listeners
      editor.addEventListener('input', function() {
        updatePreview();
        updateStats();
      });
      
      // Watermark toggle
      document.getElementById('watermarkToggle').addEventListener('change', function() {
        const watermarkText = document.getElementById('watermarkText');
        watermarkText.disabled = !this.checked;
        documentSettings.watermark = this.checked;
      });
      
      // AI Autocomplete toggle
      document.getElementById('autocompleteToggle').addEventListener('change', function() {
        isAutocompleteEnabled = this.checked;
        showToast(`AI Autocomplete ${isAutocompleteEnabled ? 'enabled' : 'disabled'}`);
      });
      
      // Load any saved settings from localStorage
      loadSettings();
    });

    // ===== DOCUMENT FUNCTIONS ===== //
    function newDocument() {
      if (confirm('Are you sure you want to create a new document? Any unsaved changes will be lost.')) {
        editor.innerHTML = '<h1>New Document</h1><p>Start typing here...</p>';
        images = [];
        charts = [];
        tables = [];
        currentTemplate = null;
        updatePreview();
        showToast('New document created');
      }
    }
    
    function loadDocument() {
      const input = document.createElement('input');
      input.type = 'file';
      input.accept = '.docx';
      input.onchange = e => {
        const file = e.target.files[0];
        if (!file) return;
        
        showLoading('Loading document...');
        
        // Placeholder for DOCX parsing
        setTimeout(() => {
          editor.innerHTML = '<h1>Loaded Document</h1><p>DOCX loading would be implemented here with proper parsing...</p>';
          hideLoading();
          showToast('Document loaded (simulated)');
        }, 1500);
      };
      input.click();
    }
    
    function printDocument() {
      const printWindow = window.open('', '', 'width=800,height=600');
      printWindow.document.write(`
        <html>
          <head>
            <title>Print Document</title>
            <style>
              body { font-family: Arial; line-height: 1.6; padding: 20px; }
              img { max-width: 100%; }
            </style>
          </head>
          <body>
            ${preview.innerHTML}
            <script>
              setTimeout(() => {
                window.print();
                window.close();
              }, 200);
            </script>
          </body>
        </html>
      `);
      printWindow.document.close();
    }
    
    function applyTemplate(template) {
      currentTemplate = template;
      let content = '';
      
      switch(template) {
        case 'report':
          content = `
            <h1>Business Report</h1>
            <h2>Executive Summary</h2>
            <p>This report summarizes the key findings of our analysis...</p>
            <h2>Findings</h2>
            <ul>
              <li>Key finding 1</li>
              <li>Key finding 2</li>
              <li>Key finding 3</li>
            </ul>
            <h2>Recommendations</h2>
            <ol>
              <li>Recommended action 1</li>
              <li>Recommended action 2</li>
            </ol>
          `;
          break;
        case 'letter':
          content = `
            <p style="text-align:right;">[Your Address]<br>[Date]</p>
            <p>[Recipient Name]<br>[Recipient Address]</p>
            <p>Dear [Name],</p>
            <p>I am writing to you regarding...</p>
            <p>Sincerely,<br>[Your Name]</p>
          `;
          break;
        case 'resume':
          content = `
            <h1 style="text-align:center;">[Your Name]</h1>
            <p style="text-align:center;">[Your Contact Information]</p>
            <h2>Professional Summary</h2>
            <p>Experienced professional with skills in...</p>
            <h2>Work Experience</h2>
            <p><strong>[Job Title]</strong> at [Company]<br>
            [Dates]<br>
            [Description]</p>
            <h2>Education</h2>
            <p><strong>[Degree]</strong> from [University]<br>
            [Year]</p>
          `;
          break;
      }
      
      editor.innerHTML = content;
      showToast(`"${template}" template applied`);
    }

    // ===== EDITOR FUNCTIONS ===== //
    function formatText(command) {
      if (command === 'heading1') document.execCommand('formatBlock', false, 'h1');
      else if (command === 'heading2') document.execCommand('formatBlock', false, 'h2');
      else if (command === 'bullet') document.execCommand('insertUnorderedList');
      else if (command === 'numbered') document.execCommand('insertOrderedList');
      else if (command === 'quote') document.execCommand('formatBlock', false, 'blockquote');
      else document.execCommand(command, false, null);
      
      editor.focus();
    }
    
    function insertImage() {
      const input = document.createElement('input');
      input.type = 'file';
      input.accept = 'image/*';
      input.onchange = async (e) => {
        const file = e.target.files[0];
        if (!file) return;
        
        try {
          const img = await createImageBitmap(file);
          images.push({
            file,
            width: img.width,
            height: img.height,
            alt: file.name
          });
          
          const imgElem = document.createElement('img');
          imgElem.src = URL.createObjectURL(file);
          imgElem.style.maxWidth = '100%';
          imgElem.style.height = 'auto';
          imgElem.alt = file.name;
          
          if (window.getSelection) {
            const selection = window.getSelection();
            if (selection.rangeCount) {
              const range = selection.getRangeAt(0);
              range.deleteContents();
              range.insertNode(imgElem);
              
              if (!imgElem.nextElementSibling || imgElem.nextElementSibling.tagName !== 'P') {
                const p = document.createElement('p');
                p.innerHTML = '<br>';
                imgElem.parentNode.insertBefore(p, imgElem.nextSibling);
              }
            }
          } else {
            editor.appendChild(imgElem);
          }
          
          showToast('Image inserted');
        } catch (error) {
          showToast('Error loading image: ' + error.message, true);
        }
      };
      input.click();
    }
    
    function insertChart() {
      const chartId = 'chart-' + Date.now();
      const chartContainer = document.createElement('div');
      chartContainer.className = 'chart-container';
      chartContainer.style.margin = '20px 0';
      
      const canvas = document.createElement('canvas');
      canvas.id = chartId;
      canvas.width = 500;
      canvas.height = 300;
      chartContainer.appendChild(canvas);
      
      if (window.getSelection) {
        const selection = window.getSelection();
        if (selection.rangeCount) {
          const range = selection.getRangeAt(0);
          range.deleteContents();
          range.insertNode(chartContainer);
        }
      } else {
        editor.appendChild(chartContainer);
      }
      
      const ctx = canvas.getContext('2d');
      const chart = new Chart(ctx, {
        type: 'bar',
        data: {
          labels: ['Q1', 'Q2', 'Q3', 'Q4'],
          datasets: [{
            label: 'Sales',
            data: [120, 190, 300, 250],
            backgroundColor: [
              'rgba(255, 99, 132, 0.2)',
              'rgba(54, 162, 235, 0.2)',
              'rgba(255, 206, 86, 0.2)',
              'rgba(75, 192, 192, 0.2)'
            ],
            borderColor: [
              'rgba(255, 99, 132, 1)',
              'rgba(54, 162, 235, 1)',
              'rgba(255, 206, 86, 1)',
              'rgba(75, 192, 192, 1)'
            ],
            borderWidth: 1
          }]
        },
        options: {
          responsive: false,
          plugins: {
            title: {
              display: true,
              text: 'Sales by Quarter'
            }
          }
        }
      });
      
      charts.push({
        id: chartId,
        chart: chart
      });
      
      showToast('Chart inserted. Right-click to edit data.');
    }
    
    function insertTable() {
      const rows = prompt('Number of rows:', '3');
      const cols = prompt('Number of columns:', '3');
      
      if (rows && cols) {
        const table = document.createElement('table');
        table.style.width = '100%';
        table.style.borderCollapse = 'collapse';
        table.style.margin = '10px 0';
        
        for (let i = 0; i < parseInt(rows); i++) {
          const tr = document.createElement('tr');
          
          for (let j = 0; j < parseInt(cols); j++) {
            const td = document.createElement('td');
            td.style.border = '1px solid #ddd';
            td.style.padding = '8px';
            td.innerHTML = i === 0 ? '<strong>Header</strong>' : 'Cell';
            tr.appendChild(td);
          }
          
          table.appendChild(tr);
        }
        
        if (window.getSelection) {
          const selection = window.getSelection();
          if (selection.rangeCount) {
            const range = selection.getRangeAt(0);
            range.deleteContents();
            range.insertNode(table);
          }
        } else {
          editor.appendChild(table);
        }
        
        tables.push(table);
        showToast('Table inserted');
      }
    }
    
    function insertEquation() {
      const equation = prompt('Enter LaTeX equation (e.g., E=mc^2):', '\\frac{a}{b}');
      if (equation) {
        const eqElem = document.createElement('div');
        eqElem.style.textAlign = 'center';
        eqElem.style.margin = '15px 0';
        eqElem.innerHTML = `$$${equation}$$`;
        
        if (window.getSelection) {
          const selection = window.getSelection();
          if (selection.rangeCount) {
            const range = selection.getRangeAt(0);
            range.deleteContents();
            range.insertNode(eqElem);
          }
        } else {
          editor.appendChild(eqElem);
        }
        
        renderMathInPreview();
        showToast('Equation inserted');
      }
    }
    
    function insertLink() {
      const url = prompt('Enter URL:', 'https://');
      if (url) {
        const text = prompt('Enter link text:', url);
        document.execCommand('createLink', false, url);
        
        if (text && text !== url) {
          const selection = window.getSelection();
          if (selection.rangeCount) {
            const range = selection.getRangeAt(0);
            range.deleteContents();
            range.insertNode(document.createTextNode(text));
            
            document.execCommand('createLink', false, url);
          }
        }
        
        showToast('Link inserted');
      }
    }
    
    function generateWithAI() {
      const prompt = document.getElementById('aiPrompt').value;
      if (!prompt.trim()) {
        showToast('Please enter an AI prompt', true);
        return;
      }
      
      showLoading('AI is generating content...');
      
      setTimeout(() => {
        const aiResponses = [
          "Based on your request, here's an improved version of your content...",
          "The AI suggests the following enhancements to your document...",
          "After analyzing your text, the AI recommends these changes...",
          "Here's a professionally rewritten version of your content...",
          "The AI has generated this content based on your prompt..."
        ];
        
        const randomResponse = aiResponses[Math.floor(Math.random() * aiResponses.length)];
        const p = document.createElement('p');
        p.innerHTML = `<strong>AI Suggestion:</strong> ${randomResponse}`;
        p.style.color = 'var(--primary)';
        p.style.margin = '15px 0';
        
        editor.appendChild(p);
        hideLoading();
        showToast('AI content generated (simulated)');
      }, 2000);
    }

    // ===== AI AUTOCOMPLETE ===== //
    editor.addEventListener('input', function(e) {
      if (!isAutocompleteEnabled) return;

      const selection = window.getSelection();
      if (!selection.rangeCount) return;

      const range = selection.getRangeAt(0);
      const text = editor.innerText;
      const words = text.trim().split(/\s+/);
      const lastWord = words[words.length - 1];

      const existingSuggestion = document.querySelector('.autocomplete-suggestion');
      if (existingSuggestion) existingSuggestion.remove();

      let suggestion = '';
      if (lastWord.toLowerCase() === 'dear') {
        suggestion = 'Dear [Name], I hope this message finds you well.';
      } else if (lastWord.toLowerCase() === 'summary') {
        suggestion = 'Summary: This document outlines key findings and recommendations.';
      }

      if (suggestion) {
        const suggestionBox = document.createElement('div');
        suggestionBox.className = 'autocomplete-suggestion';
        suggestionBox.textContent = suggestion;
        
        const rect = range.getBoundingClientRect();
        suggestionBox.style.left = `${rect.left}px`;
        suggestionBox.style.top = `${rect.bottom + window.scrollY}px`;
        
        suggestionBox.tabIndex = 0;
        suggestionBox.addEventListener('keydown', (e) => {
          if (e.key === 'Tab') {
            e.preventDefault();
            insertTextAtCursor(suggestion);
            suggestionBox.remove();
          }
        });
        
        document.body.appendChild(suggestionBox);
        suggestionBox.focus();
      }
    });

    function insertTextAtCursor(text) {
      const selection = window.getSelection();
      if (selection.rangeCount) {
        const range = selection.getRangeAt(0);
        range.deleteContents();
        range.insertNode(document.createTextNode(text));
        range.collapse(false);
        selection.removeAllRanges();
        selection.addRange(range);
      }
    }

    // ===== PREVIEW & STATS FUNCTIONS ===== //
    function updatePreview() {
      preview.innerHTML = DOMPurify.sanitize(editor.innerHTML, {
        ALLOWED_TAGS: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'ul', 'ol', 'li', 'strong', 'em', 'u', 'blockquote', 'img', 'table', 'tr', 'td', 'th', 'a', 'div', 'span'],
        ALLOWED_ATTR: ['style', 'src', 'href', 'alt', 'width', 'height']
      });
      
      renderMathInPreview();
      
      preview.querySelectorAll('img').forEach(img => {
        img.style.maxWidth = '100%';
        img.style.height = 'auto';
      });
      
      preview.querySelectorAll('table').forEach(table => {
        table.style.width = '100%';
        table.style.borderCollapse = 'collapse';
        table.style.margin = '10px 0';
        table.querySelectorAll('td, th').forEach(cell => {
          cell.style.border = '1px solid #ddd';
          cell.style.padding = '8px';
        });
      });
    }
    
    function renderMathInPreview() {
      preview.querySelectorAll('.katex').forEach(el => el.remove());
      
      const elements = preview.querySelectorAll('div');
      elements.forEach(el => {
        if (el.textContent.startsWith('$$') && el.textContent.endsWith('$$')) {
          try {
            katex.render(el.textContent.slice(2, -2), el, {
              displayMode: true,
              throwOnError: false
            });
          } catch (e) {
            console.warn('KaTeX error:', e);
          }
        }
      });
    }
    
    function updateStats() {
      const text = editor.innerText || editor.textContent;
      
      const wordCount = text.trim() === '' ? 0 : text.trim().split(/\s+/).length;
      document.getElementById('wordCount').textContent = wordCount;
      
      document.getElementById('charCount').textContent = text.length;
      
      const pageCount = Math.ceil(wordCount / 500);
      document.getElementById('pageCount').textContent = pageCount;
    }

    // ===== DOCX GENERATION ===== //
    async function generateDOCX() {
      showLoading('Generating DOCX...');
      
      try {
        const zip = new JSZip();
        
        updateSettingsFromForm();
        
        zip.file('[Content_Types].xml', generateContentTypes());
        zip.file('_rels/.rels', generateRels());
        zip.file('word/document.xml', generateDocumentXML());
        zip.file('word/styles.xml', generateStylesXML());
        zip.file('word/_rels/document.xml.rels', generateDocumentRels());
        zip.file('word/settings.xml', generateSettingsXML());
        
        images.forEach((img, i) => {
          const ext = img.file.name.split('.').pop();
          zip.file(`word/media/image${i+1}.${ext}`, img.file);
        });
        
        let progress = 0;
        const progressInterval = setInterval(() => {
          progress += Math.random() * 10;
          if (progress > 90) progress = 90;
          updateProgress(progress);
        }, 200);
        
        const blob = await zip.generateAsync({
          type: 'blob',
          compression: 'DEFLATE',
          compressionOptions: { level: 9 }
        }, metadata => {
          updateProgress(90 + (metadata.percent / 10));
        });
        
        clearInterval(progressInterval);
        updateProgress(100);
        
        saveAs(blob, generateFilename());
        showToast('DOCX generated successfully!');
        
        saveSettings();
      } catch (error) {
        showToast('Error generating DOCX: ' + error.message, true);
        console.error(error);
      } finally {
        hideLoading();
      }
    }
    
    function generateFilename() {
      let filename = 'document';
      
      const h1s = editor.getElementsByTagName('h1');
      if (h1s.length > 0) {
        filename = h1s[0].textContent.trim().toLowerCase().replace(/\s+/g, '-');
        filename = filename.replace(/[^a-z0-9-]/g, '');
      }
      
      if (currentTemplate) {
        filename += `-${currentTemplate}`;
      }
      
      const today = new Date();
      filename += `-${today.getFullYear()}-${today.getMonth()+1}-${today.getDate()}`;
      
      return `${filename}.docx`;
    }
    
    function generateContentTypes() {
      let content = `<?xml version="1.0" encoding="UTF-8"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
  <Default Extension="xml" ContentType="application/xml"/>
  <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
  <Default Extension="png" ContentType="image/png"/>
  <Default Extension="jpeg" ContentType="image/jpeg"/>
  <Default Extension="jpg" ContentType="image/jpeg"/>
  <Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
  <Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/>
  <Override PartName="/word/settings.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml"/>`;
      
      if (charts.length > 0) {
        content += `
  <Override PartName="/word/charts/chart1.xml" ContentType="application/vnd.openxmlformats-officedocument.drawingml.chart+xml"/>`;
      }
      
      content += `
</Types>`;
      
      return content;
    }
    
    function generateRels() {
      return `<?xml version="1.0" encoding="UTF-8"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
  <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
</Relationships>`;
    }
    
    function generateDocumentXML() {
      let content = DOMPurify.sanitize(editor.innerHTML, {
        ALLOWED_TAGS: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'ul', 'ol', 'li', 'strong', 'em', 'u', 'blockquote', 'img', 'table', 'tr', 'td', 'th', 'a', 'div', 'span'],
        ALLOWED_ATTR: ['style', 'src', 'href', 'alt', 'width', 'height']
      });
      
      content = content
        .replace(/<h1>/g, '<w:p><w:pPr><w:pStyle w:val="Heading1"/></w:pPr><w:r><w:t>')
        .replace(/<\/h1>/g, '</w:t></w:r></w:p>')
        .replace(/<h2>/g, '<w:p><w:pPr><w:pStyle w:val="Heading2"/></w:pPr><w:r><w:t>')
        .replace(/<\/h2>/g, '</w:t></w:r></w:p>')
        .replace(/<strong>/g, '<w:r><w:rPr><w:b/></w:rPr><w:t>')
        .replace(/<\/strong>/g, '</w:t></w:r>')
        .replace(/<em>/g, '<w:r><w:rPr><w:i/></w:rPr><w:t>')
        .replace(/<\/em>/g, '</w:t></w:r>')
        .replace(/<u>/g, '<w:r><w:rPr><w:u w:val="single"/></w:rPr><w:t>')
        .replace(/<\/u>/g, '</w:t></w:r>')
        .replace(/<p>/g, '<w:p><w:r><w:t>')
        .replace(/<\/p>/g, '</w:t></w:r></w:p>')
        .replace(/<li>/g, '<w:p><w:pPr><w:numPr><w:ilvl w:val="0"/><w:numId w:val="1"/></w:numPr></w:pPr><w:r><w:t>')
        .replace(/<\/li>/g, '</w:t></w:r></w:p>');
      
      images.forEach((img, i) => {
        const ext = img.file.name.split('.').pop();
        content = content.replace(
          new RegExp(`<img[^>]*src=["'][^"']*${img.file.name}[^"']*["'][^>]*>`, 'g'),
          `<w:p><w:r><w:drawing><wp:inline distT="0" distB="0" distL="0" distR="0">
            <wp:extent cx="${img.width * 9525}" cy="${img.height * 9525}"/>
            <wp:docPr id="1" name="Picture ${i+1}"/>
            <wp:cNvGraphicFramePr><a:graphicFrameLocks noChangeAspect="1"/></wp:cNvGraphicFramePr>
            <a:graphic><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
              <pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
                <pic:nvPicPr><pic:cNvPr id="0" name="Picture ${i+1}"/><pic:cNvPicPr/></pic:nvPicPr>
                <pic:blipFill><a:blip r:embed="rIdImage${i+1}"/><a:stretch><a:fillRect/></a:stretch></pic:blipFill>
                <pic:spPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="${img.width * 9525}" cy="${img.height * 9525}"/></a:xfrm>
                <a:prstGeom prst="rect"><a:avLst/></a:prstGeom></pic:spPr>
              </pic:pic>
            </a:graphicData></a:graphic>
          </wp:inline></w:drawing></w:r></w:p>`
        );
      });
      
      let watermarkContent = '';
      if (documentSettings.watermark && documentSettings.watermarkText) {
        watermarkContent = `
          <w:p>
            <w:pPr>
              <w:pStyle w:val="Watermark"/>
            </w:pPr>
          </w:p>`;
      }
      
      return `<?xml version="1.0" encoding="UTF-8"?>
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
            xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
            xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
            xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
            xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
  <w:body>
    ${watermarkContent}
    ${content}
    <w:sectPr>
      <w:pgSz w:w="${getPageWidth()}" w:h="${getPageHeight()}"/>
      <w:pgMar w:top="${getMarginSize()}" w:right="${getMarginSize()}" w:bottom="${getMarginSize()}" w:left="${getMarginSize()}"/>
      <w:cols w:space="720"/>
    </w:sectPr>
  </w:body>
</w:document>`;
    }
    
    function getPageWidth() {
      if (documentSettings.pageSize === 'Letter') {
        return documentSettings.orientation === 'portrait' ? 12240 : 15840;
      } else if (documentSettings.pageSize === 'Legal') {
        return documentSettings.orientation === 'portrait' ? 12240 : 20160;
      }
      return documentSettings.orientation === 'portrait' ? 11906 : 16838;
    }
    
    function getPageHeight() {
      if (documentSettings.pageSize === 'Letter') {
        return documentSettings.orientation === 'portrait' ? 15840 : 12240;
      } else if (documentSettings.pageSize === 'Legal') {
        return documentSettings.orientation === 'portrait' ? 20160 : 12240;
      }
      return documentSettings.orientation === 'portrait' ? 16838 : 11906;
    }
    
    function getMarginSize() {
      switch(documentSettings.margins) {
        case 'narrow': return 720;
        case 'wide': return 2160;
        default: return 1440;
      }
    }
    
    function generateStylesXML() {
      let watermarkStyle = '';
      if (documentSettings.watermark && documentSettings.watermarkText) {
        watermarkStyle = `
          <w:style w:type="paragraph" w:customStyle="1" w:styleId="Watermark">
            <w:name w:val="Watermark"/>
            <w:basedOn w:val="Normal"/>
            <w:rsid w:val="00FFFFFF"/>
            <w:pPr>
              <w:spacing w:after="0" w:line="1" w:lineRule="auto"/>
            </w:pPr>
            <w:rPr>
              <w:color w:val="CCCCCC"/>
              <w:sz w:val="72"/>
              <w:szCs w:val="72"/>
            </w:rPr>
          </w:style>`;
      }
      
      return `<?xml version="1.0" encoding="UTF-8"?>
<w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
  <w:docDefaults>
    <w:rPrDefault>
      <w:rPr>
        <w:rFonts w:asciiTheme="minorHAnsi" w:eastAsiaTheme="minorHAnsi" w:hAnsiTheme="minorHAnsi" w:cstheme="minorBidi"/>
        <w:sz w:val="22"/>
        <w:szCs w:val="22"/>
        <w:lang w:val="en-US" w:eastAsia="en-US" w:bidi="ar-SA"/>
      </w:rPr>
    </w:rPrDefault>
    <w:pPrDefault>
      <w:pPr>
        <w:spacing w:after="200" w:line="276" w:lineRule="auto"/>
      </w:pPr>
    </w:pPrDefault>
  </w:docDefaults>
  
  <w:style w:type="paragraph" w:styleId="Normal">
    <w:name w:val="Normal"/>
    <w:qFormat/>
  </w:style>
  
  <w:style w:type="paragraph" w:styleId="Heading1">
    <w:name w:val="heading 1"/>
    <w:basedOn w:val="Normal"/>
    <w:next w:val="Normal"/>
    <w:qFormat/>
    <w:pPr>
      <w:keepNext/>
      <w:spacing w:before="480" w:after="120"/>
      <w:outlineLvl w:val="0"/>
    </w:pPr>
    <w:rPr>
      <w:b/>
      <w:bCs/>
      <w:sz w:val="32"/>
      <w:szCs w:val="32"/>
    </w:rPr>
  </w:style>
  
  <w:style w:type="paragraph" w:styleId="Heading2">
    <w:name w:val="heading 2"/>
    <w:basedOn w:val="Normal"/>
    <w:next w:val="Normal"/>
    <w:qFormat/>
    <w:pPr>
      <w:keepNext/>
      <w:spacing w:before="360" w:after="60"/>
      <w:outlineLvl w:val="1"/>
    </w:pPr>
    <w:rPr>
      <w:b/>
      <w:bCs/>
      <w:sz w:val="26"/>
      <w:szCs w:val="26"/>
    </w:rPr>
  </w:style>
  
  ${watermarkStyle}
</w:styles>`;
    }
    
    function generateDocumentRels() {
      let rels = `<?xml version="1.0" encoding="UTF-8"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">`;
      
      images.forEach((img, i) => {
        const ext = img.file.name.split('.').pop();
        rels += `
  <Relationship Id="rIdImage${i+1}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/image${i+1}.${ext}"/>`;
      });
      
      rels += `
</Relationships>`;
      
      return rels;
    }
    
    function generateSettingsXML() {
      return `<?xml version="1.0" encoding="UTF-8"?>
<w:settings xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
  <w:zoom w:percent="100"/>
  <w:proofState w:grammar="clean" w:spelling="clean"/>
  <w:defaultTabStop w:val="720"/>
  <w:characterSpacingControl w:val="doNotCompress"/>
  <w:compat>
    <w:compatSetting w:name="compatibilityMode" w:uri="http://schemas.microsoft.com/office/word" w:val="15"/>
  </w:compat>
</w:settings>`;
    }

    // ===== SETTINGS FUNCTIONS ===== //
    function updateSettingsFromForm() {
      documentSettings.pageSize = document.getElementById('pageSize').value;
      documentSettings.orientation = document.getElementById('pageOrientation').value;
      documentSettings.margins = document.getElementById('marginSize').value;
      documentSettings.watermark = document.getElementById('watermarkToggle').checked;
      documentSettings.watermarkText = document.getElementById('watermarkText').value;
      documentSettings.theme = document.getElementById('documentTheme').value;
    }
    
    function applySettings() {
      updateSettingsFromForm();
      showToast('Document settings applied');
    }
    
    function saveSettings() {
      localStorage.setItem('docxGeneratorSettings', JSON.stringify(documentSettings));
    }
    
    function loadSettings() {
      const savedSettings = localStorage.getItem('docxGeneratorSettings');
      if (savedSettings) {
        Object.assign(documentSettings, JSON.parse(savedSettings));
        
        document.getElementById('pageSize').value = documentSettings.pageSize;
        document.getElementById('pageOrientation').value = documentSettings.orientation;
        document.getElementById('marginSize').value = documentSettings.margins;
        document.getElementById('watermarkToggle').checked = documentSettings.watermark;
        document.getElementById('watermarkText').value = documentSettings.watermarkText || '';
        document.getElementById('watermarkText').disabled = !documentSettings.watermark;
        document.getElementById('documentTheme').value = documentSettings.theme;
      }
    }

    // ===== UI HELPER FUNCTIONS ===== //
    function openTab(tabId) {
      document.querySelectorAll('.tab-content').forEach(tab => {
        tab.classList.remove('active');
      });
      
      document.querySelectorAll('.tab-button').forEach(button => {
        button.classList.remove('active');
      });
      
      document.getElementById(tabId).classList.add('active');
      
      event.currentTarget.classList.add('active');
      
      if (tabId === 'previewTab') {
        updatePreview();
      }
    }
    
    function showLoading(message = 'Processing...') {
      const loading = document.getElementById('loading');
      loading.firstElementChild.textContent = message;
      loading.style.display = 'block';
      updateProgress(0);
    }
    
    function hideLoading() {
      document.getElementById('loading').style.display = 'none';
    }
    
    function updateProgress(percent) {
      document.getElementById('progressFill').style.width = `${percent}%`;
      document.getElementById('progress').textContent = `${Math.round(percent)}%`;
    }
    
    function showToast(message, isError = false, isWarning = false) {
      const toast = document.getElementById('toast');
      toast.textContent = message;
      toast.className = 'toast';
      
      if (isError) {
        toast.classList.add('error');
      } else if (isWarning) {
        toast.classList.add('warning');
      }
      
      toast.style.display = 'block';
      setTimeout(() => {
        toast.style.display = 'none';
      }, 3000);
    }
  </script>
</body>
</html>

Comments

Popular posts from this blog

Convert: NEW