diff --git a/markitect/document_manager.py b/markitect/document_manager.py index c22031df..c847bdc5 100644 --- a/markitect/document_manager.py +++ b/markitect/document_manager.py @@ -574,35 +574,35 @@ class DocumentManager: const sections = content.querySelectorAll('.markitect-section-editable'); let reconstructed = ''; - sections.forEach(section => { + sections.forEach(section => {{ const tagName = section.tagName.toLowerCase(); const text = section.textContent.trim(); - if (tagName.startsWith('h')) { + if (tagName.startsWith('h')) {{ const level = parseInt(tagName.charAt(1)); - reconstructed += '#'.repeat(level) + ' ' + text + '\n\n'; - } else if (tagName === 'p') { - reconstructed += text + '\n\n'; - } else if (tagName === 'blockquote') { - reconstructed += '> ' + text + '\n\n'; - } else if (tagName === 'pre') { - reconstructed += '```\n' + text + '\n```\n\n'; - } else if (tagName === 'ul') { + reconstructed += '#'.repeat(level) + ' ' + text + '\\n\\n'; + }} else if (tagName === 'p') {{ + reconstructed += text + '\\n\\n'; + }} else if (tagName === 'blockquote') {{ + reconstructed += '> ' + text + '\\n\\n'; + }} else if (tagName === 'pre') {{ + reconstructed += '```\\n' + text + '\\n```\\n\\n'; + }} else if (tagName === 'ul') {{ const items = section.querySelectorAll('li'); - items.forEach(item => { - reconstructed += '- ' + item.textContent.trim() + '\n'; - }); - reconstructed += '\n'; - } else if (tagName === 'ol') { + items.forEach(item => {{ + reconstructed += '- ' + item.textContent.trim() + '\\n'; + }}); + reconstructed += '\\n'; + }} else if (tagName === 'ol') {{ const items = section.querySelectorAll('li'); - items.forEach((item, index) => { - reconstructed += `${index + 1}. ` + item.textContent.trim() + '\n'; - }); - reconstructed += '\n'; - } else { - reconstructed += text + '\n\n'; - } - }); + items.forEach((item, index) => {{ + reconstructed += (index + 1) + '. ' + item.textContent.trim() + '\\n'; + }}); + reconstructed += '\\n'; + }} else {{ + reconstructed += text + '\\n\\n'; + }} + }}); return reconstructed.trim(); } diff --git a/markitect/plugins/builtin/markdown_commands.py b/markitect/plugins/builtin/markdown_commands.py index 456c8f38..6467fbe4 100644 --- a/markitect/plugins/builtin/markdown_commands.py +++ b/markitect/plugins/builtin/markdown_commands.py @@ -1501,7 +1501,8 @@ class MarkdownCommandsPlugin(CommandPlugin): 'md-explode': md_explode_command, 'md-implode': md_implode_command, 'md-package': md_package_command, - 'md-transclude': md_transclude_command + 'md-transclude': md_transclude_command, + 'html-inject-editing': html_inject_editing } @@ -2980,4 +2981,545 @@ class FilenameDecoder: def decode_batch(self, filenames): """Process multiple filenames in batch.""" - return [self.decode(filename) for filename in filenames] \ No newline at end of file + return [self.decode(filename) for filename in filenames] + + +# ============================================================================== +# HTML Editing Injection Command - Graceful Enhancement System +# ============================================================================== + +@click.command() +@click.argument('html_file', type=click.Path(exists=True)) +@click.option('--output', '-o', type=click.Path(), + help='Output HTML file with editing capabilities (default: -editable.html)') +@click.option('--editor-theme', default='github', + type=click.Choice(['github', 'monokai', 'tomorrow', 'dark']), + help='Editor theme for edit mode (default: github)') +@click.option('--keyboard-shortcuts', is_flag=True, default=True, + help='Enable keyboard shortcuts in edit mode') +@click.option('--fallback-mode', type=click.Choice(['graceful', 'minimal', 'none']), + default='graceful', help='Fallback strategy when JavaScript fails') +@click.option('--backup/--no-backup', default=True, + help='Create backup of original file') +@click.option('--dry-run', is_flag=True, + help='Show what would be done without making changes') +@click.pass_context +def html_inject_editing(ctx, html_file, output, editor_theme, keyboard_shortcuts, + fallback_mode, backup, dry_run): + """ + Inject editing capabilities into existing HTML files. + + This command adds JavaScript editing functionality to any HTML file + containing markdown content. It provides graceful fallback when + JavaScript fails, ensuring the document remains readable. + + HTML_FILE: Path to the HTML file to enhance with editing capabilities + + Fallback modes: + graceful - Full fallback with basic editing via contenteditable + minimal - Fallback to read-only with error messages + none - No fallback, editing simply won't work if JS fails + + Examples: + markitect html-inject-editing document.html + markitect html-inject-editing doc.html --output doc-editable.html + markitect html-inject-editing page.html --fallback-mode minimal --no-backup + """ + config = ctx.obj or {} + + try: + input_path = Path(html_file) + + # Determine output path + if output: + output_path = Path(output) + else: + # Create name like "document-editable.html" + stem = input_path.stem + suffix = input_path.suffix + output_path = input_path.parent / f"{stem}-editable{suffix}" + + if dry_run: + click.echo(f"🔍 Would inject editing capabilities into: {input_path}") + click.echo(f"📝 Would create enhanced file: {output_path}") + click.echo(f"🎨 Editor theme: {editor_theme}") + click.echo(f"⌨️ Keyboard shortcuts: {'enabled' if keyboard_shortcuts else 'disabled'}") + click.echo(f"🛡️ Fallback mode: {fallback_mode}") + if backup: + backup_path = input_path.parent / f"{input_path.stem}.backup{input_path.suffix}" + click.echo(f"💾 Would create backup: {backup_path}") + return + + # Create backup if requested + if backup and not output: + backup_path = input_path.parent / f"{input_path.stem}.backup{input_path.suffix}" + backup_path.write_text(input_path.read_text(encoding='utf-8'), encoding='utf-8') + click.echo(f"💾 Created backup: {backup_path}") + + # Read original HTML + html_content = input_path.read_text(encoding='utf-8') + + # Inject editing capabilities + enhanced_html = inject_editing_capabilities( + html_content=html_content, + editor_theme=editor_theme, + keyboard_shortcuts=keyboard_shortcuts, + fallback_mode=fallback_mode + ) + + # Write enhanced HTML + output_path.parent.mkdir(parents=True, exist_ok=True) + output_path.write_text(enhanced_html, encoding='utf-8') + + click.echo(f"✨ Enhanced HTML with editing capabilities: {output_path}") + click.echo(f"🎨 Editor theme: {editor_theme}") + click.echo(f"🛡️ Fallback mode: {fallback_mode}") + + if config.get('verbose', False): + click.echo(f"⌨️ Keyboard shortcuts: {'enabled' if keyboard_shortcuts else 'disabled'}") + click.echo(f"📄 Original size: {len(html_content)} chars") + click.echo(f"📄 Enhanced size: {len(enhanced_html)} chars") + + except Exception as e: + click.echo(f"Error injecting editing capabilities: {e}", err=True) + raise click.Abort() + + +def inject_editing_capabilities(html_content: str, editor_theme: str = 'github', + keyboard_shortcuts: bool = True, + fallback_mode: str = 'graceful') -> str: + """ + Inject editing capabilities into HTML content with graceful fallback. + + This function adds editing functionality that degrades gracefully: + 1. Full editing if JavaScript loads successfully + 2. Basic contenteditable if CDN fails but DOM works + 3. Read-only mode with clear error messages if everything fails + """ + import re + + # Generate the editing enhancement script + enhancement_script = generate_editing_enhancement_script( + editor_theme=editor_theme, + keyboard_shortcuts=keyboard_shortcuts, + fallback_mode=fallback_mode + ) + + # Try to inject before closing tag + body_close_pattern = r'' + if re.search(body_close_pattern, html_content, re.IGNORECASE): + enhanced = re.sub( + body_close_pattern, + f'{enhancement_script}\n', + html_content, + flags=re.IGNORECASE + ) + return enhanced + + # Fallback: inject before closing tag + html_close_pattern = r'' + if re.search(html_close_pattern, html_content, re.IGNORECASE): + enhanced = re.sub( + html_close_pattern, + f'{enhancement_script}\n', + html_content, + flags=re.IGNORECASE + ) + return enhanced + + # Last fallback: append to end of content + return html_content + '\n' + enhancement_script + + +def generate_editing_enhancement_script(editor_theme: str = 'github', + keyboard_shortcuts: bool = True, + fallback_mode: str = 'graceful') -> str: + """ + Generate the JavaScript enhancement script with graceful fallback. + + This creates a self-contained script that: + 1. Attempts to load required libraries from CDN + 2. Falls back gracefully if CDN fails + 3. Provides basic editing even without external dependencies + """ + + fallback_css = """ + + """ + + script_content = f""" + {fallback_css} + + + """ + + return script_content \ No newline at end of file