{% extends "base.html" %} {% block title %}{{ filename }} - Markdown Viewer{% endblock %} {% block header_content %}
{{ filename }} {{ file_info.size_human }} | {{ file_info.modified_human }}{% if not local_only %} ({{ source|default("local") }}{% if version %} v{{ version }}{% endif %}){% endif %}
{% endblock %} {% block content %} {% if yaml_meta %}
📋 Frontmatter
{% endif %}
{{ content|safe }}
{% if toc_headings %}
📑 Contents
{% endif %} {% endblock %} {% block extra_script %} // Store current file state window.currentFile = { name: "{{ filename }}", modified: {{ file_info.modified }}, source: "{{ source|default('local') }}", version: {% if version %}{{ version }}{% else %}null{% endif %} }; // jQuery-based copy functions $(document).ready(function() { window.copyHtmlContent = async function() { console.log('copyHtmlContent called'); const $btn = $('#copy-html-btn'); try { const url = `/api/file/${window.currentFile.name}/html?source=${window.currentFile.source}${window.currentFile.version ? '&version=' + window.currentFile.version : ''}`; const response = await fetch(url); if (!response.ok) throw new Error('Failed to fetch HTML content'); const data = await response.json(); // Combine front matter table and content HTML with comment separators const combinedHtml = '\n' + data.frontmatter_html + '\n\n' + '\n' + data.content_html; await navigator.clipboard.writeText(combinedHtml); const originalText = $btn.text(); $btn.text('✅ Copied!').css('background', '#28a745'); setTimeout(() => { $btn.text(originalText).css('background', ''); }, 2000); } catch (err) { console.error('Failed to copy HTML:', err); $btn.text('❌ Failed'); setTimeout(() => $btn.text('HTML'), 2000); } }; window.copyMarkdownContent = async function() { console.log('copyMarkdownContent called'); const $btn = $('#copy-markdown-btn'); try { const url = `/api/file/${window.currentFile.name}/markdown?source=${window.currentFile.source}${window.currentFile.version ? '&version=' + window.currentFile.version : ''}`; const response = await fetch(url); if (!response.ok) throw new Error('Failed to fetch markdown content'); const data = await response.json(); await navigator.clipboard.writeText(data.markdown); const originalText = $btn.text(); $btn.text('✅ Copied!').css('background', '#28a745'); setTimeout(() => { $btn.text(originalText).css('background', ''); }, 2000); } catch (err) { console.error('Failed to copy Markdown:', err); $btn.text('❌ Failed'); setTimeout(() => $btn.text('Markdown'), 2000); } }; }); // Version change function function changeVersion(newVersion) { const currentUrl = new URL(window.location); if (newVersion && newVersion !== '') { currentUrl.searchParams.set('version', newVersion); } else { currentUrl.searchParams.delete('version'); } window.location.href = currentUrl.toString(); } // Viewer page refresh function window.refreshViewer = async function() { try { const response = await fetch(`/api/file/${window.currentFile.name}/info`); const fileInfo = await response.json(); // Check if file has changed if (fileInfo.modified !== window.currentFile.modified) { // Fetch new content with source parameter const contentResponse = await fetch(`/api/file/${window.currentFile.name}/content?source=${window.currentFile.source}`); const contentData = await contentResponse.json(); // Update the content document.getElementById('markdown-content').innerHTML = contentData.html; // Update the stored state window.currentFile.modified = fileInfo.modified; // Update the header metadata document.querySelector('.file-meta').textContent = `${fileInfo.size_human} | ${fileInfo.modified_human}`; // Flash indication that content was updated const content = document.getElementById('markdown-content'); content.style.animation = 'contentUpdate 0.5s'; setTimeout(() => { content.style.animation = ''; }, 500); // Re-style note references after content update if (window.styleNoteReferences) { window.styleNoteReferences(); } // Re-add copy buttons after content update if (window.addCopyButtons) { window.addCopyButtons(); } // Re-generate table of contents after content update if (window.generateTableOfContents) { window.generateTableOfContents(); } // Re-initialize Mermaid diagrams after content update if (typeof mermaid !== 'undefined') { mermaid.init(undefined, document.querySelectorAll('.mermaid')); } // Re-add copy button functionality after content update if (window.setupCopyButtons) { window.setupCopyButtons(); } } } catch (error) { console.error('Error checking for updates:', error); } }; // Set up auto-refresh for viewer if (window.setupAutoRefresh) { window.setupAutoRefresh(window.refreshViewer); } // TOC functionality with jQuery $(document).ready(function() { $('#toc-toggle').on('click', function() { const $tocNav = $('#toc-nav'); const $tocContainer = $('#table-of-contents'); const isVisible = $tocNav.is(':visible'); if (isVisible) { $tocNav.hide(); $(this).text('+'); $tocContainer.addClass('collapsed'); } else { $tocNav.show(); $(this).text('−'); $tocContainer.removeClass('collapsed'); } }); // YAML metadata toggle functionality $('#yaml-toggle').on('click', function() { const $yamlContent = $('#yaml-content'); const $yamlContainer = $('#yaml-metadata'); const isVisible = $yamlContent.is(':visible'); if (isVisible) { $yamlContent.hide(); $(this).text('+'); $yamlContainer.addClass('collapsed'); } else { $yamlContent.show(); $(this).text('−'); $yamlContainer.removeClass('collapsed'); } }); // Smooth scroll for TOC links $('.toc-link').on('click', function(e) { e.preventDefault(); const targetId = $(this).attr('href').substring(1); const $target = $('#' + targetId); if ($target.length) { $target[0].scrollIntoView({ behavior: 'smooth', block: 'start' }); $target.addClass('toc-highlight'); setTimeout(() => $target.removeClass('toc-highlight'), 2000); } }); // Legacy setupCopyButtons function for refresh compatibility window.setupCopyButtons = function() { console.log('setupCopyButtons called - using onclick handlers'); }; }); {% endblock %}