From: Thomas Walker Lynch Date: Mon, 1 Jun 2026 09:15:32 +0000 (+0000) Subject: endnotes and some new styling tags X-Git-Url: https://git.reasoningtechnology.com/?a=commitdiff_plain;h=6fdf52087b527124a88819d6e7cc7c63979b0dfd;p=RT-style-JS_public endnotes and some new styling tags --- diff --git a/RT-style-JS_public.tar b/RT-style-JS_public.tar new file mode 100644 index 0000000..3967e2d Binary files /dev/null and b/RT-style-JS_public.tar differ diff --git a/developer/authored/RT/element/citation.js b/developer/authored/RT/element/citation.js new file mode 100644 index 0000000..5c725f6 --- /dev/null +++ b/developer/authored/RT/element/citation.js @@ -0,0 +1,56 @@ +window.StyleRT = window.StyleRT || {}; + +window.StyleRT.citation = function(){ + const citations = document.querySelectorAll('rt-cite'); + if(citations.length === 0) return; + + const article = document.querySelector('rt-article'); + if(!article) return; + + // 1. Ensure the H1 is a direct child of the article so the TOC can see it + let endnotesHeader = document.getElementById('endnotes-header'); + if (!endnotesHeader) { + endnotesHeader = document.createElement('h1'); + endnotesHeader.id = 'endnotes-header'; + endnotesHeader.innerText = 'Endnotes'; + article.appendChild(endnotesHeader); + } + + // 2. Locate or generate the endnotes list container + let endnoteContainer = document.querySelector('rt-endnotes'); + if(!endnoteContainer) { + endnoteContainer = document.createElement('rt-endnotes'); + article.appendChild(endnoteContainer); + } + + // 3. Ensure the list structure exists + if(!endnoteContainer.querySelector('ol')) { + endnoteContainer.innerHTML = '
    '; + } + + const list = endnoteContainer.querySelector('ol'); + + // Process each inline citation + citations.forEach((cite, index) => { + const refNum = index + 1; + const refText = cite.getAttribute('ref') || cite.innerHTML; + + // Transform the inline tag into a superscript link + cite.innerHTML = `[${refNum}]`; + cite.style.cursor = 'pointer'; + cite.style.color = 'var(--rt-brand-link)'; + cite.style.textDecoration = 'none'; + + // Append the corresponding entry into the endnotes list + const li = document.createElement('li'); + li.id = `note-${refNum}`; + li.innerHTML = `${refText} `; + list.appendChild(li); + }); + + // Style the container + endnoteContainer.style.display = 'block'; + endnoteContainer.style.marginTop = '1rem'; + endnoteContainer.style.borderTop = '1px solid var(--rt-surface-3)'; + endnoteContainer.style.paddingTop = '1rem'; +}; diff --git a/developer/authored/RT/element/constraint.js b/developer/authored/RT/element/constraint.js new file mode 100644 index 0000000..dc4b596 --- /dev/null +++ b/developer/authored/RT/element/constraint.js @@ -0,0 +1,13 @@ +// developer/authored/RT/element/constraint.js +window.StyleRT = window.StyleRT || {}; + +window.StyleRT.constraint = function(){ + document.querySelectorAll('rt-constraint').forEach( (el) => { + el.style.display = 'block'; + el.style.borderLeft = '4px solid var(--rt-state-warning)'; + el.style.backgroundColor = 'var(--rt-surface-1)'; + el.style.padding = '1rem'; + el.style.margin = '1.5rem 0'; + el.style.color = 'var(--rt-content-main)'; + }); +}; diff --git a/developer/authored/RT/element/crossref.js b/developer/authored/RT/element/crossref.js new file mode 100644 index 0000000..f0b2c60 --- /dev/null +++ b/developer/authored/RT/element/crossref.js @@ -0,0 +1,15 @@ +// developer/authored/RT/element/crossref.js +window.StyleRT = window.StyleRT || {}; + +window.StyleRT.crossref = function(){ + document.querySelectorAll('rt-crossref').forEach( (el) => { + el.style.color = 'var(--rt-brand-link)'; + el.style.textDecoration = 'underline'; + el.style.cursor = 'pointer'; + el.style.fontWeight = '500'; + + // Note: To make this fully context-aware across soft limits, + // this module will eventually need to hook into the page + // registry built by paginate_by_element.js. + }); +}; diff --git a/developer/authored/RT/element/symbol.js b/developer/authored/RT/element/symbol.js new file mode 100644 index 0000000..748ad75 --- /dev/null +++ b/developer/authored/RT/element/symbol.js @@ -0,0 +1,10 @@ +// developer/authored/RT/element/symbol.js +window.StyleRT = window.StyleRT || {}; + +window.StyleRT.symbol = function(){ + document.querySelectorAll('rt-symbol').forEach( (el) => { + el.style.fontFamily = '"Courier New", Courier, monospace'; + el.style.fontWeight = '600'; + el.style.padding = '0 0.1em'; + }); +}; diff --git a/developer/authored/RT/layout/article_tech_ref.js b/developer/authored/RT/layout/article_tech_ref.js index 0ac7fec..a663f0f 100644 --- a/developer/authored/RT/layout/article_tech_ref.js +++ b/developer/authored/RT/layout/article_tech_ref.js @@ -32,6 +32,7 @@ let is_layout_locked = true; // 5. Declare Dependencies + RT.include('RT/element/citation'); RT.include('RT/core/utility'); RT.include('RT/element/math'); RT.include('RT/element/code'); @@ -39,10 +40,18 @@ RT.include('RT/element/TOC'); RT.include('RT/element/title'); RT.include('RT/element/theme_selector'); + RT.include('RT/element/symbol'); + RT.include('RT/element/constraint'); + RT.include('RT/element/crossref'); + + RT.include('RT/layout/paginate_by_element'); RT.include('RT/layout/page_fixed_glow'); + RT.include('RT/layout/paginate_by_element'); + RT.include('RT/core/body_visibility_visible'); + // 6. The Typography Layout RT.article = function(){ RT.config = RT.config || {}; @@ -175,16 +184,20 @@ }; // 7. The Execution Sequence - function run_semantics() { - debug.log('scroll', `4. run_semantics starting.`); + function run_semantics(){ + debug.log('scroll' ,`4. run_semantics starting.`); if(RT.theme) RT.theme(); + if(RT.citation) RT.citation(); RT.article(); if(RT.title) RT.title(); if(RT.term) RT.term(); if(RT.math) RT.math(); if(RT.code) RT.code(); + if(RT.symbol) RT.symbol(); + if(RT.constraint) RT.constraint(); + if(RT.crossref) RT.crossref(); - if(window.MathJax && MathJax.Hub && MathJax.Hub.Queue){ + if( window.MathJax && MathJax.Hub && MathJax.Hub.Queue ){ MathJax.Hub.Queue( ["Typeset" ,MathJax.Hub] ,run_layout ); }else{ run_layout(); diff --git a/developer/authored/RT/tool/to_pdf2.py b/developer/authored/RT/tool/to_pdf2.py new file mode 100644 index 0000000..a493d27 --- /dev/null +++ b/developer/authored/RT/tool/to_pdf2.py @@ -0,0 +1,479 @@ +import re +import os +import glob +from weasyprint import HTML + +def process_rt_html(html_str, out_file): + # Fix escaped dollar signs + html_str = html_str.replace('\\$', '$') + + # Remove hardcoded page breaks that cause blank pages + html_str = re.sub(r']*["\']>\s*', '', html_str, flags=re.IGNORECASE) + + css = """ + + """ + + # Inject CSS + html_str = html_str.replace("", css + "") + + # Process Title Block + title_match = re.search(r']+)>(.*?)', html_str, re.DOTALL | re.IGNORECASE) + if title_match: + attrs = title_match.group(1) + title = re.search(r'title="(.*?)"', attrs).group(1) if 'title="' in attrs else 'Document' + author = re.search(r'author="(.*?)"', attrs).group(1) if 'author="' in attrs else '' + date = re.search(r'date="(.*?)"', attrs).group(1) if 'date="' in attrs else '' + copyright_txt = re.search(r'copyright="(.*?)"', attrs).group(1) if 'copyright="' in attrs else '' + + title_block = f''' +
    +

    {title}

    +
    {author} | {date}
    + +
    + ''' + html_str = html_str[:title_match.start()] + title_block + html_str[title_match.end():] + + # Process TOC + toc_match = re.search(r'', html_str, re.IGNORECASE) + if toc_match: + level = toc_match.group(1) + headings = [] + if '-' in level: + headings = re.findall(r'(.*?)', html_str, re.IGNORECASE) + else: + headings = re.findall(rf'(.*?)', html_str, re.IGNORECASE) + + toc_html = '
    Table of Contents
      ' + for lvl, text in headings: + # exclude COVER SHEET from TOC + if "COVER SHEET" in text: + continue + toc_html += f'
    • {text}
    • ' + toc_html += '
    ' + + html_str = html_str[:toc_match.start()] + toc_html + html_str[toc_match.end():] + + # Term Replacement (First occurrence) + seen_terms = set() + def term_replace(match): + text = match.group(1) + l_text = text.lower() + if l_text not in seen_terms: + seen_terms.add(l_text) + return f'{text}' + else: + return f'{text}' + + html_str = re.sub(r'(.*?)', term_replace, html_str) + + # Neologism Replacement (First occurrence) + seen_neos = set() + def neo_replace(match): + text = match.group(1) + l_text = text.lower() + if l_text not in seen_neos: + seen_neos.add(l_text) + return f'{text}' + else: + return f'{text}' + + html_str = re.sub(r'(.*?)', neo_replace, html_str) + + HTML(string=html_str).write_pdf(out_file) + +# Locate the uploaded file +uploaded_files = glob.glob('/mnt/data/user_uploads/*abstract.html') +if not uploaded_files: + uploaded_files = glob.glob('/mnt/data/uploads/*abstract.html') +if not uploaded_files: + # Look for it anywhere under /mnt/data + for root, dirs, files in os.walk('/mnt/data'): + for file in files: + if file == 'abstract.html': + uploaded_files.append(os.path.join(root, file)) + +if uploaded_files: + filepath = uploaded_files[0] + with open(filepath, 'r', encoding='utf-8') as f: + html_content = f.read() + process_rt_html(html_content, 'abstract.pdf') + print("PDF successfully generated.") +else: + print("Could not find abstract.html in the data directory.") + +Code output +Traceback (most recent call last): + File "", line 1, in + import bs4 +ModuleNotFoundError: No module named 'bs4' + +Python +import re +import os +import glob +from weasyprint import HTML + +def process_rt_html(html_str, out_file): + html_str = html_str.replace('\\$', '$') + html_str = re.sub(r']*["\']>\s*', '', html_str, flags=re.IGNORECASE) + + css = """ + + """ + + html_str = html_str.replace("", css + "") + + title_match = re.search(r']+)>(.*?)', html_str, re.DOTALL | re.IGNORECASE) + if title_match: + attrs = title_match.group(1) + title = re.search(r'title="(.*?)"', attrs).group(1) if 'title="' in attrs else 'Document' + author = re.search(r'author="(.*?)"', attrs).group(1) if 'author="' in attrs else '' + date = re.search(r'date="(.*?)"', attrs).group(1) if 'date="' in attrs else '' + copyright_txt = re.search(r'copyright="(.*?)"', attrs).group(1) if 'copyright="' in attrs else '' + + title_block = f''' +
    +

    {title}

    +
    {author} | {date}
    + +
    + ''' + html_str = html_str[:title_match.start()] + title_block + html_str[title_match.end():] + + toc_match = re.search(r'', html_str, re.IGNORECASE) + if toc_match: + level = toc_match.group(1) + headings = [] + if '-' in level: + headings = re.findall(r'(.*?)', html_str, re.IGNORECASE) + else: + headings = re.findall(rf'(.*?)', html_str, re.IGNORECASE) + + toc_html = '
    Table of Contents
      ' + for lvl, text in headings: + if "COVER SHEET" in text: + continue + toc_html += f'
    • {text}
    • ' + toc_html += '
    ' + + # Add page break AFTER the TOC instead of before it + toc_html += '
    ' + + html_str = html_str[:toc_match.start()] + toc_html + html_str[toc_match.end():] + + seen_terms = set() + def term_replace(match): + text = match.group(1) + l_text = text.lower() + if l_text not in seen_terms: + seen_terms.add(l_text) + return f'{text}' + else: + return f'{text}' + + html_str = re.sub(r'(.*?)', term_replace, html_str) + + seen_neos = set() + def neo_replace(match): + text = match.group(1) + l_text = text.lower() + if l_text not in seen_neos: + seen_neos.add(l_text) + return f'{text}' + else: + return f'{text}' + + html_str = re.sub(r'(.*?)', neo_replace, html_str) + + HTML(string=html_str).write_pdf(out_file) + +uploaded_files = glob.glob('/mnt/data/user_uploads/*abstract.html') +if not uploaded_files: + uploaded_files = glob.glob('/mnt/data/uploads/*abstract.html') +if not uploaded_files: + for root, dirs, files in os.walk('/mnt/data'): + for file in files: + if file == 'abstract.html': + uploaded_files.append(os.path.join(root, file)) + +if uploaded_files: + filepath = uploaded_files[0] + with open(filepath, 'r', encoding='utf-8') as f: + html_content = f.read() + + # One last aggressive check to ensure we absolutely strip ANY style="page-break..." strings + # in case the earlier regex missed a specific formatting + html_content = re.sub(r'style="[^"]*page-break-after:\s*always;?[^"]*"', '', html_content, flags=re.IGNORECASE) + + process_rt_html(html_content, 'abstract_no_gap.pdf') + print("PDF successfully generated.") +else: + print("Could not find abstract.html in the data directory.")