fix: resolve critical JavaScript syntax errors in md-render --edit
Fix broken edit mode that prevented content rendering due to: - Unescaped newline literals causing JavaScript string syntax errors - Inconsistent brace escaping in f-string templates - Template literal syntax issues with variable interpolation The edit mode now properly renders content AND provides editing capabilities. Also added html-inject-editing command for standalone HTML enhancement with graceful fallback options. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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]
|
||||
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: <input>-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 </body> tag
|
||||
body_close_pattern = r'</body>'
|
||||
if re.search(body_close_pattern, html_content, re.IGNORECASE):
|
||||
enhanced = re.sub(
|
||||
body_close_pattern,
|
||||
f'{enhancement_script}\n</body>',
|
||||
html_content,
|
||||
flags=re.IGNORECASE
|
||||
)
|
||||
return enhanced
|
||||
|
||||
# Fallback: inject before closing </html> tag
|
||||
html_close_pattern = r'</html>'
|
||||
if re.search(html_close_pattern, html_content, re.IGNORECASE):
|
||||
enhanced = re.sub(
|
||||
html_close_pattern,
|
||||
f'{enhancement_script}\n</html>',
|
||||
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 = """
|
||||
<style id="markitect-fallback-styles">
|
||||
.markitect-edit-fallback {
|
||||
border: 2px dashed #ffa500;
|
||||
background-color: #fff3cd;
|
||||
padding: 10px;
|
||||
margin: 5px 0;
|
||||
border-radius: 4px;
|
||||
cursor: text;
|
||||
}
|
||||
.markitect-edit-fallback:hover {
|
||||
background-color: #ffeaa7;
|
||||
border-color: #e17055;
|
||||
}
|
||||
.markitect-edit-fallback[contenteditable="true"] {
|
||||
border-color: #00b894;
|
||||
background-color: #d1f2eb;
|
||||
outline: none;
|
||||
}
|
||||
.markitect-fallback-header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #fd7f00;
|
||||
color: white;
|
||||
padding: 8px 15px;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
font-size: 14px;
|
||||
z-index: 10000;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
.markitect-fallback-warning {
|
||||
background: #e74c3c;
|
||||
color: white;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
margin: 10px 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
}
|
||||
body { margin-top: 50px !important; }
|
||||
</style>
|
||||
"""
|
||||
|
||||
script_content = f"""
|
||||
{fallback_css}
|
||||
|
||||
<script>
|
||||
(function() {{
|
||||
'use strict';
|
||||
|
||||
// Configuration
|
||||
const CONFIG = {{
|
||||
editorTheme: '{editor_theme}',
|
||||
keyboardShortcuts: {str(keyboard_shortcuts).lower()},
|
||||
fallbackMode: '{fallback_mode}'
|
||||
}};
|
||||
|
||||
// State management
|
||||
let editingState = {{
|
||||
isEditMode: false,
|
||||
currentEditElement: null,
|
||||
originalContent: new Map(),
|
||||
hasErrors: false,
|
||||
cdnLoaded: false
|
||||
}};
|
||||
|
||||
// Graceful enhancement entry point
|
||||
function initializeEditingEnhancement() {{
|
||||
console.log('[MarkiTect] Initializing editing enhancement...');
|
||||
|
||||
// Step 1: Try to load external dependencies
|
||||
loadExternalDependencies()
|
||||
.then(() => {{
|
||||
console.log('[MarkiTect] External libraries loaded successfully');
|
||||
editingState.cdnLoaded = true;
|
||||
initializeFullEditor();
|
||||
}})
|
||||
.catch((error) => {{
|
||||
console.warn('[MarkiTect] CDN loading failed:', error);
|
||||
editingState.hasErrors = true;
|
||||
|
||||
if (CONFIG.fallbackMode === 'graceful') {{
|
||||
initializeFallbackEditor();
|
||||
}} else if (CONFIG.fallbackMode === 'minimal') {{
|
||||
showMinimalFallback();
|
||||
}} else {{
|
||||
showNoFallback();
|
||||
}}
|
||||
}});
|
||||
}}
|
||||
|
||||
// Load external dependencies (marked.js, etc.)
|
||||
function loadExternalDependencies() {{
|
||||
return new Promise((resolve, reject) => {{
|
||||
// Check if marked is already available
|
||||
if (typeof marked !== 'undefined') {{
|
||||
resolve();
|
||||
return;
|
||||
}}
|
||||
|
||||
// Try to load marked.js from CDN
|
||||
const script = document.createElement('script');
|
||||
script.src = 'https://cdn.jsdelivr.net/npm/marked/marked.min.js';
|
||||
|
||||
// Timeout after 5 seconds
|
||||
const timeout = setTimeout(() => {{
|
||||
reject(new Error('CDN loading timeout'));
|
||||
}}, 5000);
|
||||
|
||||
script.onload = () => {{
|
||||
clearTimeout(timeout);
|
||||
if (typeof marked !== 'undefined') {{
|
||||
resolve();
|
||||
}} else {{
|
||||
reject(new Error('marked.js loaded but not available'));
|
||||
}}
|
||||
}};
|
||||
|
||||
script.onerror = () => {{
|
||||
clearTimeout(timeout);
|
||||
reject(new Error('Failed to load marked.js'));
|
||||
}};
|
||||
|
||||
document.head.appendChild(script);
|
||||
}});
|
||||
}}
|
||||
|
||||
// Full editor with all features
|
||||
function initializeFullEditor() {{
|
||||
console.log('[MarkiTect] Initializing full editor...');
|
||||
|
||||
addFloatingHeader('✨ Full Edit Mode Active - Click any section to edit');
|
||||
makeContentEditable();
|
||||
|
||||
if (CONFIG.keyboardShortcuts) {{
|
||||
setupKeyboardShortcuts();
|
||||
}}
|
||||
}}
|
||||
|
||||
// Fallback editor with basic functionality
|
||||
function initializeFallbackEditor() {{
|
||||
console.log('[MarkiTect] Initializing fallback editor...');
|
||||
|
||||
addFloatingHeader('⚠️ Fallback Edit Mode - Limited functionality (CDN failed)', 'warning');
|
||||
makeContentEditableBasic();
|
||||
}}
|
||||
|
||||
// Minimal mode with just error reporting
|
||||
function showMinimalFallback() {{
|
||||
console.log('[MarkiTect] Showing minimal fallback...');
|
||||
|
||||
addFloatingHeader('❌ Edit Mode Unavailable - Network issues detected', 'error');
|
||||
addErrorMessage('Editing capabilities could not be loaded due to network restrictions. Document is read-only.');
|
||||
}}
|
||||
|
||||
// No fallback mode
|
||||
function showNoFallback() {{
|
||||
console.log('[MarkiTect] No fallback mode - editing disabled');
|
||||
// Silent failure - no editing capabilities
|
||||
}}
|
||||
|
||||
// Add floating header for status
|
||||
function addFloatingHeader(message, type = 'info') {{
|
||||
const header = document.createElement('div');
|
||||
header.className = 'markitect-fallback-header';
|
||||
header.innerHTML = `
|
||||
<span>${{message}}</span>
|
||||
<button onclick="this.parentElement.style.display='none'" style="float: right; background: none; border: none; color: white; cursor: pointer;">×</button>
|
||||
`;
|
||||
document.body.insertBefore(header, document.body.firstChild);
|
||||
}}
|
||||
|
||||
// Add error message to content
|
||||
function addErrorMessage(message) {{
|
||||
const errorDiv = document.createElement('div');
|
||||
errorDiv.className = 'markitect-fallback-warning';
|
||||
errorDiv.innerHTML = `
|
||||
<strong>Editing Unavailable:</strong> ${{message}}
|
||||
<br><small>This document remains fully readable. Editing requires JavaScript and network access.</small>
|
||||
`;
|
||||
|
||||
const firstElement = document.body.firstElementChild;
|
||||
if (firstElement) {{
|
||||
document.body.insertBefore(errorDiv, firstElement.nextSibling);
|
||||
}} else {{
|
||||
document.body.appendChild(errorDiv);
|
||||
}}
|
||||
}}
|
||||
|
||||
// Make content editable with full markdown support
|
||||
function makeContentEditable() {{
|
||||
const sections = document.querySelectorAll('h1, h2, h3, h4, h5, h6, p, blockquote, pre, ul, ol, li');
|
||||
|
||||
sections.forEach((section, index) => {{
|
||||
section.classList.add('markitect-section-editable');
|
||||
section.setAttribute('data-section-id', index);
|
||||
section.addEventListener('click', handleSectionClick);
|
||||
section.style.cursor = 'pointer';
|
||||
section.title = 'Click to edit this section';
|
||||
}});
|
||||
}}
|
||||
|
||||
// Basic contenteditable fallback
|
||||
function makeContentEditableBasic() {{
|
||||
const sections = document.querySelectorAll('h1, h2, h3, h4, h5, h6, p, blockquote');
|
||||
|
||||
sections.forEach((section, index) => {{
|
||||
section.classList.add('markitect-edit-fallback');
|
||||
section.setAttribute('contenteditable', 'true');
|
||||
section.setAttribute('data-section-id', index);
|
||||
section.title = 'Basic editing mode - formatting may be limited';
|
||||
|
||||
// Store original content
|
||||
editingState.originalContent.set(index, section.innerHTML);
|
||||
|
||||
// Add simple save/restore on blur
|
||||
section.addEventListener('blur', () => {{
|
||||
// Basic validation - could be enhanced
|
||||
if (section.innerText.trim() === '') {{
|
||||
section.innerHTML = editingState.originalContent.get(index);
|
||||
}}
|
||||
}});
|
||||
}});
|
||||
}}
|
||||
|
||||
// Handle section click for full editor
|
||||
function handleSectionClick(event) {{
|
||||
const section = event.target.closest('.markitect-section-editable');
|
||||
if (!section) return;
|
||||
|
||||
const sectionId = section.getAttribute('data-section-id');
|
||||
|
||||
if (editingState.currentEditElement && editingState.currentEditElement !== section) {{
|
||||
// Cancel current edit if clicking on different section
|
||||
const currentId = editingState.currentEditElement.getAttribute('data-section-id');
|
||||
cancelEdit(currentId);
|
||||
}}
|
||||
|
||||
if (!section.querySelector('textarea')) {{
|
||||
startEditing(section, sectionId);
|
||||
}}
|
||||
}}
|
||||
|
||||
// Start editing a section
|
||||
function startEditing(section, sectionId) {{
|
||||
editingState.originalContent.set(sectionId, section.innerHTML);
|
||||
editingState.currentEditElement = section;
|
||||
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.value = htmlToMarkdown(section.innerHTML);
|
||||
textarea.style.cssText = `
|
||||
width: 100%;
|
||||
min-height: 100px;
|
||||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
||||
font-size: 14px;
|
||||
border: 2px solid #007acc;
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
background: #f8f9fa;
|
||||
resize: vertical;
|
||||
`;
|
||||
|
||||
const controls = document.createElement('div');
|
||||
controls.style.cssText = 'margin-top: 5px;';
|
||||
controls.innerHTML = `
|
||||
<button onclick="markitectApplyEdit('${{sectionId}}')" style="margin-right: 5px;">Apply</button>
|
||||
<button onclick="markitectCancelEdit('${{sectionId}}')" style="margin-right: 5px;">Cancel</button>
|
||||
<small style="color: #666;">Ctrl+Enter to apply, Esc to cancel</small>
|
||||
`;
|
||||
|
||||
section.innerHTML = '';
|
||||
section.appendChild(textarea);
|
||||
section.appendChild(controls);
|
||||
textarea.focus();
|
||||
|
||||
// Keyboard shortcuts for editing
|
||||
textarea.addEventListener('keydown', (e) => {{
|
||||
if (e.ctrlKey && e.key === 'Enter') {{
|
||||
e.preventDefault();
|
||||
applyEdit(sectionId);
|
||||
}} else if (e.key === 'Escape') {{
|
||||
e.preventDefault();
|
||||
cancelEdit(sectionId);
|
||||
}}
|
||||
}});
|
||||
}}
|
||||
|
||||
// Apply edit
|
||||
function applyEdit(sectionId) {{
|
||||
const section = document.querySelector(`[data-section-id="${{sectionId}}"]`);
|
||||
const textarea = section.querySelector('textarea');
|
||||
|
||||
if (textarea && editingState.cdnLoaded && typeof marked !== 'undefined') {{
|
||||
// Full markdown rendering
|
||||
section.innerHTML = marked.parse(textarea.value);
|
||||
}} else if (textarea) {{
|
||||
// Basic text with line breaks
|
||||
section.innerHTML = textarea.value.replace(/\\n/g, '<br>');
|
||||
}}
|
||||
|
||||
editingState.currentEditElement = null;
|
||||
makeContentEditable(); // Re-attach click handlers
|
||||
}}
|
||||
|
||||
// Cancel edit
|
||||
function cancelEdit(sectionId) {{
|
||||
const section = document.querySelector(`[data-section-id="${{sectionId}}"]`);
|
||||
section.innerHTML = editingState.originalContent.get(sectionId);
|
||||
editingState.currentEditElement = null;
|
||||
makeContentEditable(); // Re-attach click handlers
|
||||
}}
|
||||
|
||||
// Global functions for button clicks
|
||||
window.markitectApplyEdit = applyEdit;
|
||||
window.markitectCancelEdit = cancelEdit;
|
||||
|
||||
// Simple HTML to Markdown conversion
|
||||
function htmlToMarkdown(html) {{
|
||||
return html
|
||||
.replace(/<h([1-6])[^>]*>(.*?)<\\/h[1-6]>/gi, (match, level, text) => {{
|
||||
return '#'.repeat(parseInt(level)) + ' ' + text.replace(/<[^>]*>/g, '') + '\\\\n\\\\n';
|
||||
}})
|
||||
.replace(/<p[^>]*>(.*?)<\\/p>/gi, '$1\\\\n\\\\n')
|
||||
.replace(/<strong[^>]*>(.*?)<\\/strong>/gi, '**$1**')
|
||||
.replace(/<em[^>]*>(.*?)<\\/em>/gi, '*$1*')
|
||||
.replace(/<code[^>]*>(.*?)<\\/code>/gi, '`$1`')
|
||||
.replace(/<br[^>]*>/gi, '\\\\n')
|
||||
.replace(/<[^>]*>/g, '')
|
||||
.trim();
|
||||
}}
|
||||
|
||||
// Setup keyboard shortcuts
|
||||
function setupKeyboardShortcuts() {{
|
||||
document.addEventListener('keydown', (e) => {{
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 's') {{
|
||||
e.preventDefault();
|
||||
saveDocument();
|
||||
}}
|
||||
}});
|
||||
}}
|
||||
|
||||
// Save document functionality
|
||||
function saveDocument() {{
|
||||
const content = extractMarkdownContent();
|
||||
const blob = new Blob([content], {{ type: 'text/markdown' }});
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = 'edited-document.md';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
}}
|
||||
|
||||
// Extract markdown content from current document
|
||||
function extractMarkdownContent() {{
|
||||
const sections = document.querySelectorAll('[data-section-id]');
|
||||
let content = '';
|
||||
|
||||
sections.forEach(section => {{
|
||||
content += htmlToMarkdown(section.innerHTML) + '\\\\n\\\\n';
|
||||
}});
|
||||
|
||||
return content.trim();
|
||||
}}
|
||||
|
||||
// Initialize when DOM is ready
|
||||
if (document.readyState === 'loading') {{
|
||||
document.addEventListener('DOMContentLoaded', initializeEditingEnhancement);
|
||||
}} else {{
|
||||
initializeEditingEnhancement();
|
||||
}}
|
||||
|
||||
}})();
|
||||
</script>
|
||||
"""
|
||||
|
||||
return script_content
|
||||
Reference in New Issue
Block a user