diff --git a/terminal-to-html.html b/terminal-to-html.html index 39a8f4a..718ed52 100644 --- a/terminal-to-html.html +++ b/terminal-to-html.html @@ -443,6 +443,69 @@

Terminal to HTML

return div.innerHTML; } +function findDuplicateBlocks(html, minLines = 10) { + const lines = html.split('\n'); + const duplicates = []; + + // Find all duplicate blocks of minLines or more consecutive lines + for (let blockSize = minLines; blockSize <= Math.floor(lines.length / 2); blockSize++) { + for (let i = 0; i <= lines.length - blockSize; i++) { + const block = lines.slice(i, i + blockSize).join('\n'); + + // Check if this block appears later in the content + for (let j = i + blockSize; j <= lines.length - blockSize; j++) { + const compareBlock = lines.slice(j, j + blockSize).join('\n'); + + if (block === compareBlock) { + // Check if this duplicate is already tracked or overlaps with a larger one + const isDuplicate = duplicates.some(d => + (j >= d.startLine && j < d.startLine + d.lineCount) || + (j + blockSize > d.startLine && j < d.startLine + d.lineCount) + ); + + if (!isDuplicate) { + duplicates.push({ + startLine: j, + lineCount: blockSize, + originalStartLine: i + }); + } + } + } + } + } + + // Sort by start line descending (so we can remove from end to beginning) + duplicates.sort((a, b) => b.startLine - a.startLine); + + // Merge overlapping duplicates, keeping the larger ones + const merged = []; + for (const dup of duplicates) { + const overlaps = merged.some(m => + (dup.startLine >= m.startLine && dup.startLine < m.startLine + m.lineCount) || + (dup.startLine + dup.lineCount > m.startLine && dup.startLine < m.startLine + m.lineCount) + ); + if (!overlaps) { + merged.push(dup); + } + } + + return merged; +} + +function removeDuplicateBlocks(html, duplicates) { + const lines = html.split('\n'); + + // Sort duplicates by startLine descending to remove from end first + const sortedDups = [...duplicates].sort((a, b) => b.startLine - a.startLine); + + for (const dup of sortedDups) { + lines.splice(dup.startLine, dup.lineCount); + } + + return lines.join('\n'); +} + function wrapInHtmlDocument(content) { return ` @@ -641,6 +704,7 @@

Terminal to HTML

HTML Code

+ @@ -687,6 +751,34 @@

HTML Code

checkGithubAuth(); + // Check for duplicate blocks and show deduplicate button if found + const deduplicateBtn = document.getElementById('deduplicateBtn'); + let currentDuplicates = findDuplicateBlocks(fullHtml); + + if (currentDuplicates.length > 0) { + deduplicateBtn.textContent = `Remove ${currentDuplicates.length} duplicate block${currentDuplicates.length > 1 ? 's' : ''}`; + deduplicateBtn.style.display = 'inline-block'; + } + + deduplicateBtn.addEventListener('click', () => { + fullHtml = removeDuplicateBlocks(fullHtml, currentDuplicates); + htmlOutputTextarea.value = fullHtml; + + // Update preview + const previewContainer = document.querySelector('.preview-container'); + if (previewContainer) { + previewContainer.innerHTML = fullHtml; + } + + // Re-check for remaining duplicates + currentDuplicates = findDuplicateBlocks(fullHtml); + if (currentDuplicates.length > 0) { + deduplicateBtn.textContent = `Remove ${currentDuplicates.length} duplicate block${currentDuplicates.length > 1 ? 's' : ''}`; + } else { + deduplicateBtn.style.display = 'none'; + } + }); + // Create preview section const previewSection = document.createElement('div'); previewSection.className = 'section';