From: Thomas Walker Lynch Date: Mon, 22 Jun 2026 08:28:36 +0000 (+0000) Subject: adding build component to developer/authored/RT, renaming project to RT-style X-Git-Url: https://git.reasoningtechnology.com/sitemap.xml?a=commitdiff_plain;h=87b1664a0e2f12c0792c0ebd8dc450b150a3f24c;p=RT-style adding build component to developer/authored/RT, renaming project to RT-style --- diff --git a/README.md b/README.md index 07a4dcd..d899fee 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# RT-style-JS_public +# RT-style A JavaScript based layout, themes, and semantic elements for HTML documents. Used for documents on RT projects. @@ -77,7 +77,7 @@ With the bootstrap script in place alongside the HTML file, the document authori

Introduction

- This is a demonstration of the RT-style-JS_public engine in action. + This is a demonstration of the RT-style engine in action.

@@ -89,7 +89,7 @@ With the bootstrap script in place alongside the HTML file, the document authori If the project utilizes the **Harmony** skeleton, these paths map directly to standard locations: * `` is `shared/`. -* `` is `shared/third_party/RT-style-JS_public`. +* `` is `shared/third_party/RT-style`. * The `setup.js` script is placed in the role-specific document folder (e.g., `administrator/document/setup.js`). * `` is `../../` (stepping up out of `document/` and `administrator/` back to the root). diff --git a/administrator/document/how-to_release.html b/administrator/document/how-to_release.html index 888d414..e2e8a60 100644 --- a/administrator/document/how-to_release.html +++ b/administrator/document/how-to_release.html @@ -3,10 +3,16 @@ Release howto - + diff --git a/administrator/document/setup.js b/administrator/document/setup.js deleted file mode 100644 index de1173d..0000000 --- a/administrator/document/setup.js +++ /dev/null @@ -1,4 +0,0 @@ -window.RT_REPO_ROOT = "../../"; -document.write(''); -document.write(''); -document.write(''); diff --git a/administrator/tool/html_to_v31 b/administrator/tool/html_to_v31 new file mode 100755 index 0000000..b1aba38 --- /dev/null +++ b/administrator/tool/html_to_v31 @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# -*- mode: python; coding: utf-8; python-indent-offset: 2; indent-tabs-mode: nil -*- +""" +html_update_to_3-1 + +Replaces specific StyleRT script blocks with RT 3.1 loader blocks using +literal string replacement. +""" + +import sys ,os + +OLD_BLOCK = \ +""" + """ + +NEW_BLOCK = \ +""" + """ + +def process_file(file_path: str) -> None: + try: + with open(file_path ,"r" ,encoding="utf-8") as f: + content = f.read() + except Exception as e: + print(f"Error reading {file_path}: {e}" ,file=sys.stderr) + return + + # Normalize line endings to ensure a match across environments + normalized_content = content.replace("\r\n" ,"\n") + normalized_old = OLD_BLOCK.replace("\r\n" ,"\n") + + if( normalized_old in normalized_content ): + new_content = normalized_content.replace(normalized_old ,NEW_BLOCK) + with open(file_path ,"w" ,encoding="utf-8") as f: + f.write(new_content) + print(f"Updated: {file_path}") + else: + print(f"Target lines not found in: {file_path}") + +def CLI() -> None: + args = sys.argv[1:] + + if( not args or "-h" in args or "--help" in args ): + print("Usage: html_update_to_3-1 ") + sys.exit(0) + + for TM_f in args: + process_file(TM_f) + +if __name__ == "__main__": + CLI() diff --git a/developer/authored/ExampleGreet.make/Greeter.lib.c b/developer/authored/ExampleGreet.make/Greeter.lib.c new file mode 100644 index 0000000..1d23879 --- /dev/null +++ b/developer/authored/ExampleGreet.make/Greeter.lib.c @@ -0,0 +1,20 @@ +#ifndef ExampleGreet·Greeter·ONCE +#define ExampleGreet·Greeter·ONCE + +#include "Math.lib.c" + +void ExampleGreet·Greeter·hello_loop(int count); + +#ifdef ExampleGreet·Greeter + #include + + void ExampleGreet·Greeter·hello_loop(int count){ + for(int TM = 0; TM < count; ++TM){ + int current_count = ExampleGreet·Math·add(TM ,1); + printf("Hello iteration: %d\n" ,current_count); + } + } + +#endif // ExampleGreet·Greeter + +#endif // ExampleGreet·Greeter·ONCE diff --git a/developer/authored/ExampleGreet.make/Math.lib.c b/developer/authored/ExampleGreet.make/Math.lib.c new file mode 100644 index 0000000..6f1880e --- /dev/null +++ b/developer/authored/ExampleGreet.make/Math.lib.c @@ -0,0 +1,12 @@ +#ifndef ExampleGreet·Math·ONCE +#define ExampleGreet·Math·ONCE + +int ExampleGreet·Math·add(int a ,int b); + +#ifdef ExampleGreet·Math + int ExampleGreet·Math·add(int a ,int b){ + return a + b; + } +#endif // ExampleGreet·Math + +#endif // ExampleGreet·Math·ONCE diff --git a/developer/authored/ExampleGreet.make/hello.CLI.c b/developer/authored/ExampleGreet.make/hello.CLI.c new file mode 100644 index 0000000..684e2a7 --- /dev/null +++ b/developer/authored/ExampleGreet.make/hello.CLI.c @@ -0,0 +1,20 @@ +#include +#include + +#include "Math.lib.c" +#include "Greeter.lib.c" + +void CLI(void){ + int base_count = ExampleGreet·Math·add(1 ,2); + printf("Calculated base loop count: %d\n" ,base_count); + ExampleGreet·Greeter·hello_loop(base_count); +} + +int main(int argc ,char **argv){ + (void)argc; + (void)argv; + + CLI(); + + return EXIT_SUCCESS; +} diff --git a/developer/authored/RT.copy/core/block_visibility_during_layout.js b/developer/authored/RT.copy/core/block_visibility_during_layout.js new file mode 100644 index 0000000..8513f01 --- /dev/null +++ b/developer/authored/RT.copy/core/block_visibility_during_layout.js @@ -0,0 +1,19 @@ +// block_visibility_during_layout.js + +// 1. Hide the document immediately upon execution in the +document.documentElement.style.visibility = "hidden"; + +// 2. Define the restoration function +const restore_visibility = function() { + document.documentElement.style.visibility = ""; + document.removeEventListener("RT_layout_complete", restore_visibility); + window.removeEventListener("load", restore_visibility); +}; + +// 3. Listen for a specific completion signal from the layout engine +document.addEventListener("RT_layout_complete", restore_visibility); + +// 4. Structural Safety Net: If the layout engine fails or is never loaded, +// restore visibility on the final window 'load' event so the page doesn't remain blank. +window.addEventListener("load", restore_visibility); + diff --git a/developer/authored/RT.copy/core/loader.js b/developer/authored/RT.copy/core/loader.js new file mode 100644 index 0000000..5334d08 --- /dev/null +++ b/developer/authored/RT.copy/core/loader.js @@ -0,0 +1,22 @@ +window.RT = window.RT || {}; + +window.RT.load = function(module_path){ + let target_module = module_path; + + if(target_module === 'theme'){ + let saved_theme = localStorage.getItem('RT_theme_preference'); + if(!saved_theme){ + saved_theme = 'dark_gold'; + localStorage.setItem('RT_theme_preference', saved_theme); + } + target_module = 'theme/' + saved_theme; + } + + let resolved_path = window.RT.dirpr_library + '/' + target_module; + + if(!resolved_path.endsWith('.js')){ + resolved_path = resolved_path + '.js'; + } + + document.write(''); +}; diff --git a/developer/authored/RT.copy/core/utility.js b/developer/authored/RT.copy/core/utility.js new file mode 100644 index 0000000..d6f2ddd --- /dev/null +++ b/developer/authored/RT.copy/core/utility.js @@ -0,0 +1,109 @@ +/* + General utilities for the RT Style library. +*/ + +window.RT = window.RT || {}; + +// --- DEBUG SYSTEM --- +window.RT.debug = { + + // all debug messages enabled +/* + active_tokens: new Set([ + 'style', 'layout', 'pagination' + ,'selector', 'config', 'error' + ,'term' + ,'scroll' + ]), + + active_tokens: new Set([ + 'term' + ]), +*/ + + active_tokens: new Set([ + ]), + + log: function(token, message) { + if (this.active_tokens.has(token)) { + console.log(`[RT:${token}]`, message); + } + }, + + warn: function(token, message) { + if (this.active_tokens.has(token)) { + console.warn(`[RT:${token}]`, message); + } + }, + + error: function(token, message) { + console.error(`[RT:${token}] CRITICAL:`, message); + }, + + enable: function(token) { this.active_tokens.add(token); console.log(`Enabled: ${token}`); }, + disable: function(token) { this.active_tokens.delete(token); console.log(`Disabled: ${token}`); } +}; + +// --- UTILITIES --- +window.RT.utility = { + // --- FONT PHYSICS --- + measure_ink_ratio: function(target_font, ref_font = null) { + const debug = window.RT.debug; + debug.log('layout', `Measuring ink ratio for ${target_font}`); + + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + + if (!ref_font) { + const bodyStyle = window.getComputedStyle(document.body); + ref_font = bodyStyle.fontFamily; + } + + const get_metrics = (font) => { + ctx.font = '100px ' + font; + const metrics = ctx.measureText('M'); + return { + ascent: metrics.actualBoundingBoxAscent, + descent: metrics.actualBoundingBoxDescent + }; + }; + + const ref_m = get_metrics(ref_font); + const target_m = get_metrics(target_font); + + const ratio = ref_m.ascent / target_m.ascent; + + return { + ratio: ratio, + baseline_diff: ref_m.descent - target_m.descent + }; + }, + + // --- COLOR PHYSICS --- + is_color_light: function(color_string) { + // 1. HSL Check + if (color_string.startsWith('hsl')) { + const numbers = color_string.match(/\d+/g); + if (numbers && numbers.length >= 3) { + const lightness = parseInt(numbers[2]); + return lightness > 50; + } + } + + // 2. RGB Check + const rgb = color_string.match(/\d+/g); + if (!rgb) { + return true; + } + + const r = parseInt(rgb[0]); + const g = parseInt(rgb[1]); + const b = parseInt(rgb[2]); + const luma = (r * 299 + g * 587 + b * 114) / 1000; + return luma > 128; + }, + + is_block_content: function(element) { + return element.textContent.trim().includes('\n'); + } +}; diff --git a/developer/authored/RT.copy/document/RT0 b/developer/authored/RT.copy/document/RT0 new file mode 120000 index 0000000..2a6dec2 --- /dev/null +++ b/developer/authored/RT.copy/document/RT0 @@ -0,0 +1 @@ +/home/Thomas/subu_data/developer/project/RT-style-JS_public/shared/linked-project/RT-style-JS_public/consumer/release/RT \ No newline at end of file diff --git a/developer/authored/RT.copy/document/style_manual.html b/developer/authored/RT.copy/document/style_manual.html new file mode 100644 index 0000000..3ceb591 --- /dev/null +++ b/developer/authored/RT.copy/document/style_manual.html @@ -0,0 +1,420 @@ + + + + + RT Style System: Reference Manual + + + + + + + + + + + + + + Table of custom tags + +

Style tag reference

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TagDescription
<RT-article>Article container.
<RT-title> + Title block and metadata. +
<RT-TOC>Compiles TOC.
<RT-index>Compiles an alphabetical glossary of defined terms.
<RT-term>Conventional term.
<RT-term-em>Forces emphasis for a term even after first occurrence.
<RT-neologism>Project specific term.
<RT-neologism-em>Forces emphasis for a neologism even after first occurrence.
<RT-code>Code span or code block.
<RT-math>Inline or block math.
<RT-footnote>Inline text to be extracted and rendered at the bottom of the page.
<RT-cite>Bibliographic citation marker.
<RT-ref>Dynamic cross reference to another element in the document.
<RT-page>Automatically inserted pagination container.
<RT-chapter>Chapter heading with implied page break.
<RT-page-break>Explicit page break directive. Must be explicitly closed.
+ + Architecture overview +

+ The RT Style System is a client-side, JavaScript-driven publishing framework designed to turn raw HTML into high-readability technical documentation. Unlike standard CSS frameworks, RT uses JavaScript to handle complex layout tasks like ink-ratio balancing and dynamic pagination. +

+ +

Pulling style files into a document

+

Put `setup.js` in the directory, and include it at the top of the document, + `setup.js` points at the style files and is installation specific.

+ + + Semantic tags +

+ The system relies on a specific set of custom tags in the RT- namespace to separate meaning from presentation. +

+ +

Terminology

+ +

Conventional terms

+

+ Use <RT-term> for standard, industry accepted technical terms. The system decorates only the first occurrence of each unique term so that the first appearance functions as a definition point, and later appearances do not overload the page with styling. +

+ + + The Singleton Pattern restricts instantiation... + + +

+ Renders as: The Singleton Pattern restricts instantiation... +

+ +

Neologisms

+

+ Use <RT-neologism> for terms invented specifically for the current document or project. Neologisms are styled more strongly than conventional terms, visually distinguishing "jargon you should know" from "jargon we invented." +

+ + + We define the Hyper Tape as a construct... + + +

+ Renders as: We define the Hyper Tape as a construct... +

+ +

First occurrence rule

+

+ The term system is intentionally conservative. For the tags <RT-term> and <RT-neologism>, only the first occurrence of a unique term is decorated. Subsequent mentions are rendered as normal prose. +

+ +

+ Uniqueness is tracked by normalizing the term text (trimmed, then lowercased). This means that Symbol and symbol count as the same term. +

+ +

Forced emphasis variants

+

+ Sometimes a later mention of a term should be emphasized again. For that purpose, the system provides explicit emphasis tags: +

+ +
    +
  • <RT-term-em>
  • +
  • <RT-neologism-em>
  • +
+ +

+ These variants are always decorated, even if the term appeared earlier. +

+ +

Automatic definition anchors

+

+ For first occurrences, the term module automatically assigns an id attribute if one does not already exist. This establishes stable anchors for future indexing and linking. +

+ + + We define a Symbol as... + + +

+ The first occurrence will be given an id similar to def-symbol. For neologisms, an additional marker is used, for example def-neo-hyper-tape. +

+ +

Technical content

+ +

Code

+

+ Use <RT-code>. If placed inline, it acts like a span. If placed as a block (with newlines), it acts like a pre formatted block with a theme aware border. +

+ + + # Block Code Example + def hello(): + return "World" + + +

Mathematics

+

+ Use <RT-math>. The system auto detects if it is a block equation or inline variable and wraps it in MathJax delimiters. +

+

+ Inline: Let x be the input. +

+

+ Block: +

+ + f(x) = \sum_{i=0}^{n} x_i + + +

References, citations, and indexing

+ +

Footnotes

+

+ Use <RT-footnote> to author footnote content directly inline with the text it references. During the layout phase, the pagination engine extracts the text, replaces the element with an invisible structural marker, and compiles a formatted footnote container at the bottom of the active <RT-page>. +

+ +

Citations

+

+ Use <RT-cite> with the ref attribute to insert bibliographic citations. This ensures formatting remains consistent and separates citation data from standard prose. +

+ + ... formalized as Basic Law V . + + +

Dynamic cross referencing

+

+ A person authoring a technical document frequently refers back to tables, equations, or previous sections. Use <RT-ref target="element-id"> to link to specific content. This tag dynamically retrieves the numbering or caption of the target element, maintaining correct references even if preceding elements shift during editing. +

+ +

Glossary indexing

+

+ Use <RT-index> at the end of the document to compile a glossary. Similar to the TOC compiler, this tag scans the DOM for automatic definition anchors produced by the term module and generates an alphabetized list of defined terms and neologisms. +

+ + Navigation and layout + +

Automatic table of contents

+

+ Use <RT-TOC> to insert a compiled table of contents. The tag scans the document forward from its current position to collect headings. +

+ +

Explicit mode

+

+ Use the level="N" attribute to target a specific heading depth. +

+
    +
  • <RT-TOC level="1">: Collects all <h1> elements until the end of the document. Best for the main document index.
  • +
  • <RT-TOC level="2">: Collects all <h2> elements until it encounters the next <h1>. Best for chapter summaries.
  • +
+ +

Implicit mode

+

+ If no level is specified, the TOC scans backwards to find the nearest heading (for example H1) and assumes you want to collect children one level deeper (for example H2). +

+

+ Note: Implicit mode can fail if placed before the first heading of a section. Use explicit levels for robust results. +

+ +

The title block

+

+ Use <RT-title> as the first element in your <body> (before the article container). This tag produces a standardized, styled header block with the document title and metadata. +

+ +

Attributes

+
    +
  • title (Required): The main heading of the document.
  • +
  • author (Optional): The author's name. Renders in a bold accent color.
  • +
  • date (Optional): The publication or revision date.
  • +
+ +

Example

+ + + + + +

+ Renders as: A centered, high contrast H1 followed by a serif styled metadata row containing the author and date. +

+ +

The article container

+

+ The root element must be <RT-article>. This is the boundary for the pagination logic. +

+ +

Pagination

+

+ The script paginate_by_element.js scans the article. It calculates the height of every element (including margins) and bundles them into <RT-page> elements. +

+

+ Soft Limit Pagination: The system attempts to keep headers with their following paragraphs. It will break a page early rather than stranding a header at the bottom. +

+ +

Manual page breaks and chapters

+

+ A person can assert explicit control over the layout engine using the <RT-page-break></RT-page-break> tag. This tag forces the engine to close the current page and push all subsequent content to the top of the next page. Standard HTML5 parsing requires this custom tag to be explicitly closed; self-closing syntax will fail. +

+

+ For major document divisions, use <RT-chapter>. The semantic processor translates this tag into an <RT-page-break> followed by an <h1 class="RT-chapter">. This ensures the chapter starts on a new page, inherits standard typography, and is automatically indexed by the TOC engine. +

+ + Debugging + +

Debug tokens

+

+ RT provides a lightweight debug logging system in utility.js. Logging is controlled by a set of active debug tokens. Each log message is assigned a token, and the message prints only if that token is enabled. +

+ +

+ Examples of common tokens include style, layout, pagination, selector, config, and term. +

+ +

How logging is gated

+

+ Normal log and warning output are gated. The methods debug.log(token,message) and debug.warn(token,message) will print only when the token exists in debug.active_tokens. +

+ +

+ This prevents the console from being flooded during normal use, while still allowing deep visibility during development. +

+ +

Errors are always printed

+

+ Errors are treated differently. The method debug.error(token,message) always prints, regardless of token state. These messages represent failures that require attention. +

+ +

Enabling and disabling tokens

+

+ Tokens are enabled or disabled in two ways: by editing the active_tokens set in utility.js, or at runtime by calling: +

+ + + window.RT.debug.enable('term') + window.RT.debug.disable('term') + + +

+ For example, the term system (RT_term.js) uses the term token. When that token is enabled, the module will print messages describing how terms were detected and which term definitions were assigned IDs. +

+ + Themes +

+ The system supports hot swapping themes by changing the script import in the head. +

+
    +
  • Dark: style/theme_dark_gold.js (Default)
  • +
  • Light: style/theme_light_gold.js
  • +
+ + Manifest + + 2. utility.js (Math/Color physics) + 3. article_tech_ref.js (Typography and CSS injection) + 4. RT_code.js (Code block logic) + 5. RT_math.js (MathJax wrapper) + 6. RT_term.js (Term styling) + 7. RT_TOC.js (Navigation generator) + 8. paginate_by_element.js (Page splitter) + 9. page_fixed_glow.js (Visual page container) + + + RT conventions +

Headings are first letter capitalized. Remaining words are as they would be in English prose.

+ + Exercises + +
    +
  1. +

    + Term occurrences: If an author tags a word with <RT-term> five times in a document, how many times will the term be visually decorated by the styling engine? How does a person force the engine to decorate a later occurrence? +

    +
  2. +
  3. +

    + Term normalization: A person writes <RT-term>Parse Tree</RT-term> in paragraph one, and <RT-term>parse tree</RT-term> in paragraph two. Will the system assign a definition anchor to the second occurrence? +

    +
  4. +
  5. +

    + TOC compilation: What happens if a person places an <RT-TOC> tag without a level attribute before the first heading of a section? +

    +
  6. +
  7. +

    + Code and math formatting: How does the RT system determine whether to render an <RT-code> or <RT-math> element inline with the text versus as a standalone block? +

    +
  8. +
  9. +

    + Pagination logic: When the script bundles elements into an <RT-page> container, how does the soft limit pagination handle a heading that falls at the very bottom of the page capacity? +

    +
  10. +
+ +
+ + diff --git a/developer/authored/RT.copy/element/TOC.js b/developer/authored/RT.copy/element/TOC.js new file mode 100644 index 0000000..2f3bc6f --- /dev/null +++ b/developer/authored/RT.copy/element/TOC.js @@ -0,0 +1,162 @@ +/* + Processes tags. + Populates each with headings found below it. + + Attributes: + level="N" : Explicitly sets the target heading level (1-6). + e.g., level="1" collects H1s. level="2" collects H2s. + Stops collecting if it hits a heading of (level - 1) or higher. + + Default (No attribute): + Context Aware. Looks backwards for the nearest heading H(N). + Targets H(N+1). Stops at the next H(N). + +First heading 1 1 + First heading 2 2 + Next heading 2 2 +Next heading 2 3 + +*/ + +window.RT = window.RT || {}; + +window.RT.TOC = function(){ + const debug = window.RT.debug || { log: function(){} }; + const TOC_seq = document.querySelectorAll('rt-toc'); + + TOC_seq.forEach( (container ,TOC_index) => { + container.style.display = 'block'; + + // 1. Parse attribute: single number N or range A-B + const attr_val = container.getAttribute('level'); + let start_level, end_level; + + if (attr_val) { + const rangeMatch = attr_val.match(/^(\d)-(\d)$/); + if (rangeMatch) { + const a = parseInt(rangeMatch[1]); + const b = parseInt(rangeMatch[2]); + if (a >= 1 && a <= 6 && b >= 1 && b <= 6 && a <= b) { + start_level = a; + end_level = b; + if (debug.log) debug.log('TOC', `TOC #${TOC_index} range: H${a}-H${b}`); + } else { + if (debug.log) debug.log('TOC', `Invalid range "${attr_val}" → implicit mode`); + } + } else { + const single = parseInt(attr_val); + if (!isNaN(single) && single >= 1 && single <= 6) { + start_level = single; + end_level = single; + if (debug.log) debug.log('TOC', `TOC #${TOC_index} single level: H${single}`); + } else { + if (debug.log) debug.log('TOC', `Invalid level "${attr_val}" → implicit mode`); + } + } + } + + // 2. Implicit mode (no attribute or invalid) + if (start_level === undefined || end_level === undefined) { + let context_level = 0; + let prev = container.previousElementSibling; + while (prev) { + const match = prev.tagName.match(/^H([1-6])$/); + if (match) { + context_level = parseInt(match[1]); + break; + } + prev = prev.previousElementSibling; + } + const target_level = Math.min(context_level + 1, 6); + start_level = target_level; + end_level = target_level; + if (debug.log) debug.log('TOC', `TOC #${TOC_index} implicit target: H${target_level}`); + } + + // 3. Collect all matching headings until a higher-level heading stops us + const headings = []; + let next_el = container.nextElementSibling; + while (next_el) { + const match = next_el.tagName.match(/^H([1-6])$/); + if (match) { + const found_level = parseInt(match[1]); + + // Stop if we hit a heading that is a parent of the lowest level we collect + if (found_level < start_level) break; + + // Collect if within the requested range + if (found_level >= start_level && found_level <= end_level) { + // Ensure it has an id + if (!next_el.id) { + next_el.id = `TOC-ref-${TOC_index}-${found_level}-${headings.length}`; + } + headings.push({ el: next_el, level: found_level }); + } + } + next_el = next_el.nextElementSibling; + } + + // 4. Build the container (title + list) + container.innerHTML = ''; + const title = document.createElement('h1'); + title.textContent = start_level === 1 ? 'Table of Contents' : 'Section Contents'; + title.style.textAlign = 'center'; + container.appendChild(title); + + if (headings.length === 0) return; // nothing to show + + // Top-level list + const topList = document.createElement('ul'); + topList.style.listStyle = 'none'; + topList.style.paddingLeft = '0'; + container.appendChild(topList); + + // Stack of
    elements; index 0 = top-level list + const listStack = [topList]; + + for (const item of headings) { + // Depth relative to start_level + const depth = item.level - start_level; // 0 = top-level, 1 = sub-level, etc. + + // Ensure we have the correct nesting depth + while (listStack.length - 1 > depth) { + // Pop until we are at the right depth + listStack.pop(); + } + + // If we need to go deeper, open new sub-lists inside the last
  • + while (listStack.length - 1 < depth) { + const parentList = listStack[listStack.length - 1]; + const lastLi = parentList.lastElementChild; + if (lastLi) { + const subList = document.createElement('ul'); + subList.style.listStyle = 'none'; + subList.style.paddingLeft = '1.5rem'; // indentation for nested items + lastLi.appendChild(subList); + listStack.push(subList); + } else { + // No parent
  • yet – stay at current depth (flatten) + break; + } + } + + // Create the
  • for this heading + const li = document.createElement('li'); + li.style.marginBottom = '0.5rem'; + + const a = document.createElement('a'); + a.href = `#${item.el.id}`; + a.textContent = item.el.textContent; + a.style.textDecoration = 'none'; + a.style.color = 'inherit'; + a.style.display = 'block'; + + a.onmouseover = () => a.style.color = 'var(--rt-brand-primary)'; + a.onmouseout = () => a.style.color = 'inherit'; + + li.appendChild(a); + // Add to the current deepest list + listStack[listStack.length - 1].appendChild(li); + } + }); +}; diff --git a/developer/authored/RT.copy/element/chapter.js b/developer/authored/RT.copy/element/chapter.js new file mode 100644 index 0000000..42ba956 --- /dev/null +++ b/developer/authored/RT.copy/element/chapter.js @@ -0,0 +1,32 @@ +/* + Processes tags. + Transforms the tag into an followed by an

    with the RT-chapter class. +*/ +window.RT = window.RT || {}; + +window.RT.chapter = function(){ + const debug = window.RT.debug || { log: function(){} }; + + document.querySelectorAll('RT-chapter').forEach( (el ,index) => { + if(debug.log) debug.log('chapter' ,`Processing chapter ${index + 1}`); + + const brk = document.createElement('RT-page-break'); + const h1 = document.createElement('h1'); + + h1.innerHTML = el.innerHTML; + + if(el.className){ + h1.className = el.className; + } + h1.classList.add('RT-chapter'); + + Array.from(el.attributes).forEach( (attr) => { + if(attr.name !== 'class'){ + h1.setAttribute(attr.name ,attr.value); + } + }); + + el.parentNode.insertBefore(brk ,el); + el.replaceWith(h1); + }); +}; diff --git a/developer/authored/RT.copy/element/code.js b/developer/authored/RT.copy/element/code.js new file mode 100644 index 0000000..0a97f16 --- /dev/null +++ b/developer/authored/RT.copy/element/code.js @@ -0,0 +1,129 @@ +/* + Processes tags. + Uses the central config or CSS variables from the theme. + + Removes common indent from lines of code. +*/ +function code() { + const RT = window.RT; + const U = RT.utility; + const debug = RT.debug; + + debug.log('code', 'Starting render cycle.'); + + const metrics = U.measure_ink_ratio('monospace'); + + document.querySelectorAll('rt-code').forEach((el) => { + el.style.fontFamily = 'monospace'; + + const computed = window.getComputedStyle(el); + const accent = computed.getPropertyValue('--rt-accent').trim() || 'gold'; + + const is_block = U.is_block_content(el); + const parentColor = computed.color; + const is_text_light = U.is_color_light(parentColor); + + const alpha = is_block ? 0.08 : 0.15; + const overlay = is_text_light ? `rgba(255,255,255,${alpha})` : `rgba(0,0,0,${alpha})`; + const text_color = is_text_light ? '#ffffff' : '#000000'; + + el.style.backgroundColor = overlay; + + if (is_block) { + el.style.display = 'block'; + + // --- Tag-Relative Auto-Dedent Logic --- + + // 1. Get Tag Indentation (The Anchor) + let tagIndent = ''; + const prevNode = el.previousSibling; + if (prevNode && prevNode.nodeType === 3) { + const prevText = prevNode.nodeValue; + const lastNewLineIndex = prevText.lastIndexOf('\n'); + if (lastNewLineIndex !== -1) { + tagIndent = prevText.substring(lastNewLineIndex + 1); + } else if (/^\s*$/.test(prevText)) { + tagIndent = prevText; + } + } + + // 2. Calculate Common Leading Whitespace from Content + const rawLines = el.textContent.split('\n'); + + // Filter out empty lines for calculation purposes so they don't break the logic + const contentLines = rawLines.filter(line => line.trim().length > 0); + + let commonIndent = null; + + if (contentLines.length > 0) { + // Assume the first line sets the standard + const firstMatch = contentLines[0].match(/^\s*/); + commonIndent = firstMatch ? firstMatch[0] : ''; + + // Reduce the commonIndent if subsequent lines have LESS indentation + for (let i = 1; i < contentLines.length; i++) { + const line = contentLines[i]; + // Determine how much of commonIndent this line shares + let j = 0; + while (j < commonIndent.length && j < line.length && commonIndent[j] === line[j]) { + j++; + } + commonIndent = commonIndent.substring(0, j); + if (commonIndent.length === 0) break; // Optimization + } + } else { + commonIndent = ''; + } + + // 3. Process Content + // Rule: Only strip if the Common Indent contains the Tag Indent (Safety Check) + // This handles the Emacs case: Tag is " ", Common is " ". " " starts with " ". + // We strip " ", leaving the code flush left. + let finalString = ''; + + if (commonIndent.length > 0 && commonIndent.startsWith(tagIndent)) { + const cleanedLines = rawLines.map(line => { + // Strip the common indent from valid lines + return line.startsWith(commonIndent) ? line.replace(commonIndent, '') : line; + }); + + // Remove artifact lines (first/last empty lines) + if (cleanedLines.length > 0 && cleanedLines[0].length === 0) { + cleanedLines.shift(); + } + if (cleanedLines.length > 0 && cleanedLines[cleanedLines.length - 1].trim().length === 0) { + cleanedLines.pop(); + } + finalString = cleanedLines.join('\n'); + } else { + // Fallback: Code is to the left of the tag or weirdly formatted. + // Just trim the wrapper newlines. + finalString = el.textContent.trim(); + } + + el.textContent = finalString; + // --- End Indentation Logic --- + + el.style.whiteSpace = 'pre'; + el.style.fontSize = (parseFloat(computed.fontSize) * metrics.ratio * 0.95) + 'px'; + el.style.padding = '1.2rem'; + el.style.margin = '1.5rem 0'; + el.style.borderLeft = `4px solid ${accent}`; + el.style.color = 'inherit'; + } else { + el.style.display = 'inline'; + const exactPx = parseFloat(computed.fontSize) * metrics.ratio * 1.0; + el.style.fontSize = exactPx + 'px'; + el.style.padding = '0.1rem 0.35rem'; + el.style.borderRadius = '3px'; + const offsetPx = metrics.baseline_diff * (exactPx / 100); + el.style.verticalAlign = offsetPx + 'px'; + el.style.color = text_color; + } + }); + + debug.log('code', 'Render cycle complete.'); +} + +window.RT = window.RT || {}; +window.RT.code = code; diff --git a/developer/authored/RT.copy/element/constraint.js b/developer/authored/RT.copy/element/constraint.js new file mode 100644 index 0000000..c33b7b0 --- /dev/null +++ b/developer/authored/RT.copy/element/constraint.js @@ -0,0 +1,13 @@ +// developer/authored/RT/element/constraint.js +window.RT = window.RT || {}; + +window.RT.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.copy/element/crossref.js b/developer/authored/RT.copy/element/crossref.js new file mode 100644 index 0000000..aaea2bc --- /dev/null +++ b/developer/authored/RT.copy/element/crossref.js @@ -0,0 +1,15 @@ +// developer/authored/RT/element/crossref.js +window.RT = window.RT || {}; + +window.RT.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.copy/element/endnote.js b/developer/authored/RT.copy/element/endnote.js new file mode 100644 index 0000000..dd887b3 --- /dev/null +++ b/developer/authored/RT.copy/element/endnote.js @@ -0,0 +1,55 @@ +window.RT = window.RT || {}; + +window.RT.end_note = 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; + + 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.copy/element/math.js b/developer/authored/RT.copy/element/math.js new file mode 100644 index 0000000..51d86a7 --- /dev/null +++ b/developer/authored/RT.copy/element/math.js @@ -0,0 +1,35 @@ +/* + Processes tags. + JavaScript: math() + HTML Tag: (parsed as rt-math) +*/ +function math(){ + // querySelector treats 'rt-math' as case-insensitive for the tag + document.querySelectorAll('rt-math').forEach(el => { + if (el.textContent.startsWith('$')) return; + + const is_block = el.parentElement.tagName === 'DIV' || + el.textContent.includes('\n') || + el.parentElement.childNodes.length === 1; + + const delimiter = is_block ? '$$' : '$'; + el.style.display = is_block ? 'block' : 'inline'; + el.textContent = `${delimiter}${el.textContent.trim()}${delimiter}`; + }); + + // MathJax must find its config at window.MathJax + window.MathJax = { + tex: { + inlineMath: [['$', '$']], + displayMath: [['$$', '$$']] + } + }; + + const script = document.createElement('script'); + script.src = 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js'; + script.async = true; + document.head.appendChild(script); +} + +window.RT = window.RT || {}; +window.RT.math = math; diff --git a/developer/authored/RT.copy/element/symbol.js b/developer/authored/RT.copy/element/symbol.js new file mode 100644 index 0000000..7199fda --- /dev/null +++ b/developer/authored/RT.copy/element/symbol.js @@ -0,0 +1,10 @@ +// developer/authored/RT/element/symbol.js +window.RT = window.RT || {}; + +window.RT.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.copy/element/term.js b/developer/authored/RT.copy/element/term.js new file mode 100644 index 0000000..1cc779c --- /dev/null +++ b/developer/authored/RT.copy/element/term.js @@ -0,0 +1,107 @@ +/* + Processes and tags. + - Styles only the first occurrence of a unique term/neologism. + - The "-em" variants (e.g., ) are always styled. + - Automatically generates IDs for first occurrences for future indexing. +*/ + +window.RT = window.RT || {}; + +window.RT.term = function() { + const RT = window.RT; + + const debug = RT.debug || { + log: function() {} + ,warn: function() {} + ,error: function() {} + }; + + const DEBUG_TOKEN_S = 'term'; + + try { + // Track seen terms so only the first occurrence is decorated + const seen_terms_dpa = new Set(); + + const apply_style = (el, is_neologism_b) => { + el.style.fontStyle = 'italic'; + el.style.fontWeight = is_neologism_b ? '600' : '500'; + el.style.color = is_neologism_b + ? 'var(--rt-brand-secondary)' + : 'var(--rt-brand-primary)'; + el.style.paddingRight = '0.1em'; // Compensation for italic slant + el.style.display = 'inline'; + }; + + const clear_style = (el) => { + el.style.fontStyle = 'normal'; + el.style.color = 'inherit'; + el.style.fontWeight = 'inherit'; + el.style.paddingRight = ''; + el.style.display = ''; + }; + + const selector_s = [ + 'rt-term' + ,'rt-term-em' + ,'rt-neologism' + ,'rt-neologism-em' + ].join(','); + + const tags_dpa = document.querySelectorAll(selector_s); + + debug.log(DEBUG_TOKEN_S, `Scanning ${tags_dpa.length} term tags`); + + tags_dpa.forEach(el => { + const tag_name_s = el.tagName.toLowerCase(); + const is_neologism_b = tag_name_s.includes('neologism'); + const is_explicit_em_b = tag_name_s.endsWith('-em'); + + const term_text_raw_s = (el.textContent || '').trim(); + if (!term_text_raw_s.length) { + debug.warn(DEBUG_TOKEN_S, `Empty term tag encountered: <${tag_name_s}>`); + return; + } + + // Normalize text for uniqueness tracking + const term_norm_s = term_text_raw_s.toLowerCase(); + + // Slug for ID generation (simple + stable) + const slug_s = term_norm_s.replace(/\s+/g, '-'); + + const is_first_occurrence_b = !seen_terms_dpa.has(term_norm_s); + + if (is_explicit_em_b || is_first_occurrence_b) { + apply_style(el, is_neologism_b); + + if (!is_explicit_em_b && is_first_occurrence_b) { + seen_terms_dpa.add(term_norm_s); + + if (!el.id) { + el.id = `def-${is_neologism_b ? 'neo-' : ''}${slug_s}`; + debug.log( + DEBUG_TOKEN_S + ,`First occurrence: "${term_norm_s}" -> id="${el.id}"` + ); + } else { + debug.log( + DEBUG_TOKEN_S + ,`First occurrence: "${term_norm_s}" (existing id="${el.id}")` + ); + } + } else if (is_explicit_em_b) { + debug.log( + DEBUG_TOKEN_S + ,`Emphasized occurrence: "${term_norm_s}" (<${tag_name_s}>)` + ); + } + } else { + // Subsequent mentions render as normal prose + clear_style(el); + } + }); + + debug.log(DEBUG_TOKEN_S, `Unique terms defined: ${seen_terms_dpa.size}`); + } catch (e) { + debug.error('error', `term failed: ${e && e.message ? e.message : String(e)}`); + } +}; diff --git a/developer/authored/RT.copy/element/theme_selector.js b/developer/authored/RT.copy/element/theme_selector.js new file mode 100644 index 0000000..05759d2 --- /dev/null +++ b/developer/authored/RT.copy/element/theme_selector.js @@ -0,0 +1,27 @@ +class ThemeSelector extends HTMLElement{ + connectedCallback(){ + let current_theme = localStorage.getItem('RT_theme_preference'); + if(!current_theme){ + current_theme = 'dark_gold'; + } + + this.innerHTML = ` +
      + Theme Selection
      +
      + +
      + `; + + this.addEventListener( 'change' ,(e) => { + localStorage.setItem('RT_theme_preference' ,e.target.value); + location.reload(); + } ); + } +} + +customElements.define('rt-theme-selector' ,ThemeSelector); diff --git a/developer/authored/RT.copy/element/title.js b/developer/authored/RT.copy/element/title.js new file mode 100644 index 0000000..bfb8d4e --- /dev/null +++ b/developer/authored/RT.copy/element/title.js @@ -0,0 +1,72 @@ +/* + Processes tags. + Generates a standard document header block. + + Usage: + +*/ +window.RT = window.RT || {}; + +window.RT.title = function() { + const debug = window.RT.debug || { log: function(){} }; + + document.querySelectorAll('rt-title').forEach(el => { + const title = el.getAttribute('title') || 'Untitled Document'; + const author = el.getAttribute('author'); + const date = el.getAttribute('date'); + const copyright = el.getAttribute('copyright'); + + if (debug.log) debug.log('title', `Generating title block: ${title}`); + + // Container + const container = document.createElement('div'); + container.style.textAlign = 'center'; + container.style.marginBottom = '3rem'; + container.style.marginTop = '2rem'; + container.style.borderBottom = '1px solid var(--rt-border-default)'; + container.style.paddingBottom = '1.5rem'; + + // Main Title (H1) + const h1 = document.createElement('h1'); + h1.textContent = title; + h1.style.margin = '0 0 0.8rem 0'; + h1.style.border = 'none'; // Override standard H1 border + h1.style.padding = '0'; + h1.style.color = 'var(--rt-brand-primary)'; + h1.style.fontSize = '2.5em'; + h1.style.lineHeight = '1.1'; + h1.style.letterSpacing = '-0.03em'; + + container.appendChild(h1); + + // Metadata Row (Author | Date) + if (author || date) { + const meta = document.createElement('div'); + meta.style.color = 'var(--rt-content-muted)'; + meta.style.fontStyle = 'italic'; + meta.style.fontSize = '1.1em'; + meta.style.fontFamily = '"Georgia", "Times New Roman", serif'; // Classy serif + + const parts = []; + if (author) parts.push(`${author}`); + if (date) parts.push(date); + + meta.innerHTML = parts.join('  —  '); + container.appendChild(meta); + } + + // Copyright Row + if (copyright) { + const copy_div = document.createElement('div'); + copy_div.style.color = 'var(--rt-content-muted)'; + copy_div.style.fontSize = '0.9em'; + copy_div.style.marginTop = '0.5rem'; + // Automatically injects the copyright symbol + copy_div.innerHTML = `© ${copyright}`; + container.appendChild(copy_div); + } + + // Replace the raw tag with the generated block + el.replaceWith(container); + }); +}; diff --git a/developer/authored/RT.copy/layout/article_tech_ref.js b/developer/authored/RT.copy/layout/article_tech_ref.js new file mode 100644 index 0000000..fc7034b --- /dev/null +++ b/developer/authored/RT.copy/layout/article_tech_ref.js @@ -0,0 +1,295 @@ +// debug messages don't work here, because core/utility isn't loaded until after the function runs. +(function(){ + const RT = window.RT = window.RT || {}; + const debug = RT.debug || { log: function(){} }; + + debug.log('scroll', "1. Initializing script."); + + // 1. Intercept native history restoration immediately + if ('scrollRestoration' in history) { + history.scrollRestoration = 'manual'; + debug.log('scroll', "2. history.scrollRestoration set to manual."); + } + + // 2. Read coordinate from memory before any layout shifts occur + const raw_target = sessionStorage.getItem('RT_saved_y'); + const target_y = raw_target !== null ? parseInt(raw_target, 10) : 0; + + // 3. Determine if the execution is a page reload + let is_reload = false; + if (window.performance) { + const nav_entries = performance.getEntriesByType("navigation"); + if (nav_entries.length > 0) { + is_reload = (nav_entries[0].type === "reload"); + } else if (performance.navigation) { + is_reload = (performance.navigation.type === 1); + } + } + + debug.log('scroll', `3. Target Y: ${target_y} | Is Reload: ${is_reload}`); + + // 4. The Lock + let is_layout_locked = true; + + // Helper to ensure we only signal completion once + function unlock_layout() { + if (!is_layout_locked) return; + is_layout_locked = false; + debug.log('scroll', "10. Layout fully unlocked. Emitting completion signal."); + document.dispatchEvent(new Event("RT_layout_complete")); + } + + // 5. Declare Dependencies + RT.load('element/chapter'); + RT.load('element/endnote'); + RT.load('element/math'); + RT.load('element/code'); + RT.load('element/term'); + RT.load('element/TOC'); + RT.load('element/title'); + RT.load('element/theme_selector'); + RT.load('element/symbol'); + RT.load('element/constraint'); + RT.load('element/crossref'); + + RT.load('layout/paginate_by_element'); + RT.load('layout/page_fixed_glow'); + + // 6. The Typography Layout + RT.article = function(){ + RT.config = RT.config || {}; + RT.config.article = { + font_family: '"Noto Sans", "Segoe UI", "Helvetica Neue", sans-serif' + ,line_height: "1.8" + ,font_size: "16px" + ,font_weight: "400" + ,max_width: "820px" + ,margin: "0 auto" + }; + + if( RT.config.theme && RT.config.theme.meta_is_dark === false ){ + RT.config.article.font_weight = "600"; + } + + const conf = RT.config.article; + const article_seq = document.querySelectorAll("RT-article"); + + if(article_seq.length === 0) return; + + for(let i = 0; i < article_seq.length; i++){ + let style = article_seq[i].style; + style.display = "block"; + style.fontFamily = conf.font_family; + style.fontSize = conf.font_size; + style.lineHeight = conf.line_height; + style.fontWeight = conf.font_weight; + style.maxWidth = conf.max_width; + style.margin = conf.margin; + style.padding = "0 20px"; + style.color = "var(--rt-content-main)"; + } + + window.RT = window.RT || {}; + window.RT.config = window.RT.config || {}; + window.RT.config.page = window.RT.config.page || {}; + window.RT.config.page.height_limit = 900; + + const style_node = document.createElement("style"); + style_node.innerHTML = ` + body, html, rt-article { + overflow-anchor: none !important; + } + + rt-article { + font-family: 'Noto Sans JP', Arial, sans-serif; + background-color: var(--rt-surface-0); + color: var(--rt-content-main); + max-width: 46.875rem !important; + box-sizing: border-box !important; + } + + rt-article:not(:has(rt-page)) { + padding: 3rem !important; + } + + rt-article:has(rt-page) { + padding: 0 !important; + } + + rt-article rt-page { + position: relative; + display: block; + padding: 3rem; + margin: 1.25rem auto; + background-color: var(--rt-surface-0); + box-shadow: 0 0 0.625rem var(--rt-brand-primary); + } + + rt-article h1 { + font-size: 1.5rem; + text-align: center; + color: var(--rt-brand-primary); + font-weight: 500; + margin-top: 1.5rem; + line-height: 1.15; + } + rt-article h2 { + font-size: 1.25rem; + color: var(--rt-brand-secondary); + text-align: left; + margin-top: 2rem; + margin-left: 0; + } + rt-article h3 { + font-size: 1.125rem; + color: var(--rt-brand-tertiary); + text-align: left; + margin-top: 1.5rem; + margin-left: 4ch; + } + rt-article h4 { + font-size: 1.05rem; + color: var(--rt-content-main); + font-weight: 600; + text-align: left; + margin-top: 1.25rem; + margin-left: 8ch; + } + + rt-article p, + rt-article ul, + rt-article ol { + color: var(--rt-content-main); + text-align: justify; + margin-bottom: 1rem; + margin-left: 0; + } + rt-article li { + margin-bottom: 0.5rem; + } + + rt-article rt-code { + font-family: 'Courier New', Courier, monospace; + background-color: var(--rt-surface-code); + padding: 0.125rem 0.25rem; + color: var(--rt-content-main); + } + + rt-article img { + max-width: 100%; + height: auto; + display: block; + margin: 1.5rem auto; + } + `; + document.head.appendChild(style_node); + }; + + // 7. The Execution Sequence + function run_semantics(){ + debug.log('scroll' ,`4. run_semantics starting.`); + if(RT.theme) RT.theme(); + if(RT.endnote) RT.endnote(); + 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 ){ + MathJax.Hub.Queue( ["Typeset" ,MathJax.Hub] ,run_layout ); + }else{ + run_layout(); + } + } + + function run_layout() { + debug.log('scroll', `5. run_layout starting.`); + + if(RT.chapter) RT.chapter(); + if(RT.TOC) RT.TOC(); + if(RT.paginate_by_element) RT.paginate_by_element(); + if(RT.page) RT.page(); + + debug.log('scroll', `6. Pagination complete.`); + + let final_target = target_y; + let use_hash = false; + + if (window.location.hash && !is_reload) { + const hash_target = document.getElementById(window.location.hash.substring(1)); + if (hash_target) { + use_hash = true; + } + } + + debug.log('scroll', `7. Commencing viewport enforce loop. Mode: ${use_hash ? 'HASH' : 'Y-COORDINATE'}`); + enforce_scroll(final_target, use_hash, 0); + } + + // 8. The Enforcer Logic + function enforce_scroll(target, use_hash, attempts) { + if (attempts > 15) { + debug.log('scroll', "8. Scroll enforcement timed out. Unlocking."); + unlock_layout(); + return; + } + + if (use_hash) { + const hash_target = document.getElementById(window.location.hash.substring(1)); + if (hash_target) { + hash_target.scrollIntoView(); + debug.log('scroll', `8a. Attempt ${attempts}: Scrolled to Hash Target. Y is now ${window.scrollY}`); + } + } else { + window.scrollTo(0, target); + debug.log('scroll', `8b. Attempt ${attempts}: Scrolled to Y=${target}. Current Y is ${window.scrollY}`); + } + + let is_successful = false; + if (use_hash) { + is_successful = true; + } else { + is_successful = (Math.abs(window.scrollY - target) < 5 || target === 0); + } + + if (is_successful && document.body.scrollHeight > 1000) { + debug.log('scroll', `9. Viewport anchored successfully.`); + + setTimeout(() => { + if (!use_hash && Math.abs(window.scrollY - target) >= 5) { + debug.log('scroll', `9a. Browser late-stage rebellion detected. Re-enforcing.`); + enforce_scroll(target, use_hash, attempts + 1); + } else { + unlock_layout(); + } + }, 100); + } else { + setTimeout(() => enforce_scroll(target, use_hash, attempts + 1), 50); + } + } + + // 9. The Ledger + let scroll_timer; + window.addEventListener('scroll', () => { + if (is_layout_locked) return; + clearTimeout(scroll_timer); + scroll_timer = setTimeout(() => { + sessionStorage.setItem('RT_saved_y', window.scrollY); + debug.log('scroll', `X. User stopped scrolling. Saved Y: ${window.scrollY}`); + }, 200); + }, { passive: true }); + + window.addEventListener('beforeunload', () => { + is_layout_locked = true; + debug.log('scroll', "Y. Page unloading. Scroll listener locked."); + }); + + // 10. Bind to DOM Ready + document.addEventListener('DOMContentLoaded', run_semantics); + +})(); + diff --git a/developer/authored/RT.copy/layout/memo_State.js b/developer/authored/RT.copy/layout/memo_State.js new file mode 100644 index 0000000..5609705 --- /dev/null +++ b/developer/authored/RT.copy/layout/memo_State.js @@ -0,0 +1,70 @@ +/* + + + + + + + +*/ + +(function(){ + const RT = window.RT = window.RT || {}; + + // 1. Declare Dependencies + RT.load('core/utility'); + RT.load('element/title'); + RT.load('element/term'); + RT.load('element/TOC'); + RT.load('core/body_visibility_visible'); + + // 2. The Typography Layout + RT.memo_state_dept = function(){ + const body = document.body; + const html = document.documentElement; + + // Force strict print colors regardless of user system settings + html.style.backgroundColor = "white"; + body.style.backgroundColor = "white"; + body.style.color = "black"; + + // Target the new semantic tag + const memo_seq = document.querySelectorAll("RT-memo"); + if(memo_seq.length === 0) return; + + for(let i = 0; i < memo_seq.length; i++){ + let style = memo_seq[i].style; + style.display = "block"; + style.fontFamily = '"Times New Roman", Times, serif'; + style.fontSize = "12pt"; + style.lineHeight = "1.15"; + // 8.5 inch standard width minus 1-inch margins on each side + style.maxWidth = "6.5in"; + style.margin = "1in auto"; + style.padding = "0"; + style.textAlign = "left"; + style.color = "black"; + } + }; + + // 3. The Execution Sequence + const run_semantics = function(){ + RT.memo_state_dept(); + + if(RT.title) RT.title(); + if(RT.term) RT.term(); + if(RT.TOC) RT.TOC(); + + run_layout(); + }; + + const run_layout = function(){ + if(RT.body_visibility_visible) RT.body_visibility_visible(); + }; + + // 4. Bind to DOM Ready + document.addEventListener('DOMContentLoaded' ,run_semantics); + +})(); diff --git a/developer/authored/RT.copy/layout/page_fixed_glow.js b/developer/authored/RT.copy/layout/page_fixed_glow.js new file mode 100644 index 0000000..6ef8819 --- /dev/null +++ b/developer/authored/RT.copy/layout/page_fixed_glow.js @@ -0,0 +1,83 @@ +/* + Page Layout: Fixed Glow + Standard: Theme 1.0 + Description: A variable-height container with a glowing border effect that matches the active theme. +*/ +(function(){ + const RT = window.RT = window.RT || {}; + + RT.page = function() { + RT.config = RT.config || {}; + + // Default Configuration + const defaults = { + width: "100%" + ,min_height: "15rem" // Replaces fixed height + ,padding: "3rem" + ,margin: "4rem auto" + + ,bg_color: "var(--rt-surface-0)" + ,border_color: "var(--rt-brand-primary)" + ,text_color: "var(--rt-brand-primary)" + + ,shadow: "drop-shadow(0px 0px 15px var(--rt-brand-primary))" + }; + + RT.config.page = Object.assign({}, defaults, RT.config.page || {}); + + const conf = RT.config.page; + const style_id = 'rt-page-fixed-glow'; + + if (!document.getElementById(style_id)) { + const style_el = document.createElement('style'); + style_el.id = style_id; + + style_el.textContent = ` + /* Reset page counter on the article container */ + rt-article { + counter-reset: rt-page-counter; + } + + rt-page { + display: block; + position: relative; + box-sizing: border-box; + overflow: hidden; + + /* Dimensions */ + width: ${conf.width}; + min-height: ${conf.min_height}; + margin: ${conf.margin}; + padding: ${conf.padding}; + + /* Theming */ + background-color: ${conf.bg_color}; + border: 1px solid ${conf.border_color}; + + /* The "Glow" Effect */ + filter: ${conf.shadow}; + + /* Counter Increment */ + counter-increment: rt-page-counter; + } + + /* Page Numbering */ + rt-page::after { + content: "Page " counter(rt-page-counter); + position: absolute; + bottom: 1.5rem; + right: 3rem; + + font-family: "Noto Sans", sans-serif; + font-size: 0.9rem; + font-weight: bold; + + color: ${conf.text_color}; + opacity: 0.8; + pointer-events: none; + } + `; + document.head.appendChild(style_el); + } + }; +})(); diff --git a/developer/authored/RT.copy/layout/paginate_by_element.js b/developer/authored/RT.copy/layout/paginate_by_element.js new file mode 100644 index 0000000..aca2122 --- /dev/null +++ b/developer/authored/RT.copy/layout/paginate_by_element.js @@ -0,0 +1,399 @@ +window.RT.paginate_by_element = function () { + const RT = window.RT; + const debug = RT.debug || { log: function(){}, error: function(){} }; + const page_conf = (RT.config && RT.config.page) ? RT.config.page : {}; + const page_height_limit = page_conf.height_limit || 1000; + + let measureContainer = null; + + // ========================================================= + // 1. DOM Measurement Utilities + // ========================================================= + function getElHeight(el) { + const wasInDOM = el.parentNode !== null; + if (!wasInDOM) document.body.appendChild(el); + const rect = el.getBoundingClientRect(); + const style = window.getComputedStyle(el); + const margin = parseFloat(style.marginTop) + parseFloat(style.marginBottom); + if (!wasInDOM) el.remove(); + return (rect.height || 0) + (margin || 0); + } + + function getMeasureContainer() { + if (measureContainer && measureContainer.parentNode) return measureContainer; + const article = document.querySelector('RT-article'); + if (!article) { + const temp = document.createElement('div'); + temp.style.visibility = 'hidden'; + temp.style.position = 'absolute'; + temp.style.width = '100%'; + document.body.appendChild(temp); + measureContainer = temp; + return temp; + } + const container = document.createElement('div'); + const articleStyle = window.getComputedStyle(article); + container.style.visibility = 'hidden'; + container.style.position = 'absolute'; + container.style.width = articleStyle.width; + container.style.fontFamily = articleStyle.fontFamily; + container.style.fontSize = articleStyle.fontSize; + container.style.lineHeight = articleStyle.lineHeight; + container.style.fontWeight = articleStyle.fontWeight; + document.body.appendChild(container); + measureContainer = container; + return container; + } + + function measureFragment(frag) { + const container = getMeasureContainer(); + container.appendChild(frag); + const h = getElHeight(frag); + container.removeChild(frag); + return h; + } + + // ========================================================= + // STEP 1: PREPARE FOOTNOTES (Strip and tag) + // ========================================================= + const article_seq = document.querySelectorAll('RT-article'); + if (article_seq.length === 0) { + debug.error('pagination', 'No elements found. Pagination aborted.'); + return; + } + + const footnote_registry = {}; + let footnote_counter = 1; + + Array.from(article_seq).forEach(article => { + // Bulletproof extraction: immune to XML/HTML case-sensitivity parsing quirks + const all_nodes = Array.from(article.querySelectorAll('*')); + const raw_footnotes = all_nodes.filter(node => node.tagName.toLowerCase() === 'rt-footnote'); + + raw_footnotes.forEach(fn => { + const id = footnote_counter++; + footnote_registry[id] = fn.innerHTML; // Save the payload + + // Trim any standard HTML whitespace immediately preceding the tag + const prev = fn.previousSibling; + if (prev && prev.nodeType === Node.TEXT_NODE) { + prev.textContent = prev.textContent.replace(/\s+$/, ''); + } + + // Replace with a zero-height marker that rides along with the text + const marker = document.createElement('rt-fn-marker'); + marker.setAttribute('data-id', id); + + if (fn.parentNode) { + fn.parentNode.replaceChild(marker, fn); + } + }); + }); + + // ========================================================= + // Splitting Logic (Clean and undisturbed) + // ========================================================= + function isSplittable(el) { + const tag = el.tagName; + if (tag === 'UL' || tag === 'OL') { + const items = Array.from(el.children).filter(c => c.tagName === 'LI'); + if (items.length === 0) return null; + + const itemHeights = items.map(li => getElHeight(li)); + const emptyClone = el.cloneNode(false); + const overhead = getElHeight(emptyClone); + + el._splitInfo = { type: 'list', itemHeights, overhead, offset: 0 }; + return makeListSplitter(el, el._splitInfo); + } + + if (tag === 'TABLE') { + const thead = el.querySelector('thead'); + const tbody = el.querySelector('tbody'); + const rows = tbody ? Array.from(tbody.rows) : Array.from(el.rows); + if (rows.length === 0) return null; + + const theadHeight = thead ? getElHeight(thead) : 0; + const rowHeights = rows.map(row => getElHeight(row)); + + const emptyClone = el.cloneNode(false); + if (thead) emptyClone.appendChild(thead.cloneNode(true)); + emptyClone.appendChild(document.createElement('tbody')); + const overhead = getElHeight(emptyClone) - theadHeight; + + el._splitInfo = { type: 'table', rowHeights, overhead, theadHeight, offset: 0 }; + return makeTableSplitter(el, el._splitInfo); + } + return null; + } + + function makeListSplitter(el, info) { + return (remaining) => { + const children = Array.from(el.children).filter(c => c.tagName === 'LI'); + const start = info.offset; + + let bestCount = 0; + let bestHeight = 0; + const tempList = el.cloneNode(false); + + for (let i = 0; i < children.length; i++) { + const itemClone = children[i].cloneNode(true); + tempList.appendChild(itemClone); + const fragHeight = measureFragment(tempList); + if (fragHeight <= remaining) { + bestCount = i + 1; + bestHeight = fragHeight; + } else { + tempList.removeChild(itemClone); + break; + } + } + + if (bestCount === 0) return { first: null, rest: el, firstHeight: 0 }; + + const first = el.cloneNode(false); + for (let i = 0; i < bestCount; i++) { + first.appendChild(children[i].cloneNode(true)); + } + + let rest = null; + if (bestCount < children.length) { + rest = el.cloneNode(false); + for (let i = bestCount; i < children.length; i++) { + rest.appendChild(children[i].cloneNode(true)); + } + + if (el.tagName === 'OL') { + const currentStart = parseInt(el.getAttribute('start'), 10) || 1; + rest.setAttribute('start', currentStart + bestCount); + } + + rest._splitInfo = { + type: 'list', + itemHeights: info.itemHeights, + overhead: info.overhead, + offset: start + bestCount + }; + } + + return { first, rest, firstHeight: bestHeight }; + }; + } + + function makeTableSplitter(el, info) { + const thead = el.querySelector('thead'); + const createShell = () => { + const shell = el.cloneNode(false); + if (thead) shell.appendChild(thead.cloneNode(true)); + const newTbody = document.createElement('tbody'); + shell.appendChild(newTbody); + return shell; + }; + + return (remaining) => { + const tbody = el.querySelector('tbody'); + const rows = tbody ? Array.from(tbody.rows) : Array.from(el.rows); + const start = info.offset; + + let bestCount = 0; + let bestHeight = 0; + const tempTable = createShell(); + const tempBody = tempTable.querySelector('tbody'); + + for (let i = 0; i < rows.length; i++) { + tempBody.appendChild(rows[i].cloneNode(true)); + const h = measureFragment(tempTable); + if (h <= remaining) { + bestCount = i + 1; + bestHeight = h; + } else { + tempBody.removeChild(tempBody.lastChild); + break; + } + } + + if (bestCount === 0) return { first: null, rest: el, firstHeight: 0 }; + + const first = createShell(); + const firstBody = first.querySelector('tbody'); + for (let i = 0; i < bestCount; i++) { + firstBody.appendChild(rows[i].cloneNode(true)); + } + + let rest = null; + if (bestCount < rows.length) { + rest = createShell(); + const restBody = rest.querySelector('tbody'); + for (let i = bestCount; i < rows.length; i++) { + restBody.appendChild(rows[i].cloneNode(true)); + } + + rest._splitInfo = { + type: 'table', + rowHeights: info.rowHeights, + overhead: info.overhead, + theadHeight: info.theadHeight, + offset: start + bestCount + }; + } + + return { first, rest, firstHeight: bestHeight }; + }; + } + + // ========================================================= + // STEP 2: NORMAL PAGINATOR + // ========================================================= + function paginateArticle(article) { + const raw_element_seq = Array.from(article.children).filter(el => + !['SCRIPT', 'STYLE', 'RT-PAGE'].includes(el.tagName) + ); + + if (raw_element_seq.length === 0) return; + + const page_seq = []; + let current_batch_seq = []; + let current_h = 0; + let i = 0; + + while (i < raw_element_seq.length) { + const el = raw_element_seq[i]; + const splitter = isSplittable(el); + + if (splitter) { + const remaining = page_height_limit - current_h; + const { first, rest, firstHeight } = splitter(remaining); + + if (first) { + current_batch_seq.push(first); + current_h += firstHeight; + + if (rest) { + raw_element_seq.splice(i, 1, rest); + } else { + raw_element_seq.splice(i, 1); + } + } else { + if (current_batch_seq.length === 0) { + const frame = document.createElement('rt-scroll-frame'); + frame.style.display = 'block'; + frame.style.overflowY = 'auto'; + frame.style.maxHeight = page_height_limit + 'px'; + frame.appendChild(el); + current_batch_seq.push(frame); + i++; + } else { + page_seq.push(current_batch_seq); + current_batch_seq = []; + current_h = 0; + raw_element_seq[i] = rest || el; + } + } + continue; + } + + + // --- Ordinary (non-splittable) element --- + const h = getElHeight(el); + const is_RT_page_break = el.tagName && el.tagName.toLowerCase() === 'rt-page-break'; + + if( (is_RT_page_break || current_h + h > page_height_limit) && current_batch_seq.length > 0 ){ + let backtrack_seq = []; + let backtrack_h = 0; + + while (current_batch_seq.length > 0) { + const last = current_batch_seq[current_batch_seq.length - 1]; + if (!/^H[1-6]/.test(last.tagName)) break; + const popped = current_batch_seq.pop(); + backtrack_seq.unshift(popped); + backtrack_h += getElHeight(popped); + } + + if (current_batch_seq.length > 0) { + page_seq.push(current_batch_seq); + current_batch_seq = backtrack_seq; + current_h = backtrack_h; + } else { + page_seq.push(backtrack_seq); + current_batch_seq = []; + current_h = 0; + } + } + + current_batch_seq.push(el); + current_h += h; + i++; + } + + if (current_batch_seq.length > 0) { + page_seq.push(current_batch_seq); + } + + // Rebuild article with wrappers + article.innerHTML = ''; + let p = 0; + while (p < page_seq.length) { + const batch = page_seq[p]; + const page_el = document.createElement('rt-page'); + page_el.id = `page-${p + 1}`; + batch.forEach(item => page_el.appendChild(item)); + article.appendChild(page_el); + p++; + } + } + + // Execute pagination + Array.from(article_seq).forEach(article => paginateArticle(article)); + + // ========================================================= + // STEP 3: RESOLVE FOOTNOTES & EXPAND PAGES + // ========================================================= + Array.from(article_seq).forEach(article => { + const rendered_pages = article.querySelectorAll('rt-page'); + + Array.from(rendered_pages).forEach(page => { + // Bulletproof extraction for the markers + const all_page_nodes = Array.from(page.querySelectorAll('*')); + const markers = all_page_nodes.filter(node => node.tagName.toLowerCase() === 'rt-fn-marker'); + + if (markers.length === 0) return; + + // Construct the footer block for this page + const fn_container = document.createElement('div'); + fn_container.className = 'rt-footnote-container'; + fn_container.style.borderTop = '1px solid var(--rt-border-default)'; + fn_container.style.marginTop = '2rem'; + fn_container.style.paddingTop = '1rem'; + fn_container.style.fontSize = '0.9em'; + + markers.forEach(marker => { + const id = marker.getAttribute('data-id'); + const html = footnote_registry[id]; + + // Replace the invisible marker with the visible naked superscript link + const sup = document.createElement('sup'); + sup.innerHTML = `${id}`; + + if (marker.parentNode) { + marker.parentNode.replaceChild(sup, marker); + } + + // Append the actual text to the footer with a clean, print-ready number format + const fn_line = document.createElement('div'); + fn_line.id = `fn-${id}`; + fn_line.style.marginBottom = '0.5rem'; + fn_line.innerHTML = `${id}.${html}`; + fn_container.appendChild(fn_line); + }); + + // Attach the footer. The page organically stretches to fit. + page.appendChild(fn_container); + }); + }); + + // Cleanup + if (measureContainer && measureContainer.parentNode) { + measureContainer.remove(); + measureContainer = null; + } +}; diff --git a/developer/authored/RT.copy/theme/dark_gold.js b/developer/authored/RT.copy/theme/dark_gold.js new file mode 100644 index 0000000..9550a98 --- /dev/null +++ b/developer/authored/RT.copy/theme/dark_gold.js @@ -0,0 +1,115 @@ +/* + Theme: Inverse Wheat (Dark) + Standard: Theme 1.0 + Description: High contrast Amber on Deep Charcoal. +*/ +( function(){ + const RT = window.RT = window.RT || {}; + + RT.theme = function(){ + RT.config = RT.config || {}; + + // THEME 1.0 DATA CONTRACT + RT.config.theme = { + meta_is_dark: true + ,meta_name: "Inverse Wheat" + + // --- SURFACES (Depth & Container Hierarchy) --- + ,surface_0: "hsl(0, 0%, 5%)" // App Background (Deepest) + ,surface_1: "hsl(0, 0%, 10%)" // Sidebar / Nav / Panels + ,surface_2: "hsl(0, 0%, 14%)" // Cards / Floating Elements + ,surface_3: "hsl(0, 0%, 18%)" // Modals / Dropdowns / Popovers + ,surface_input: "hsl(0, 0%, 12%)" // Form Inputs + ,surface_code: "hsl(0, 0%, 11%)" // Code Block Background + ,surface_select: "hsl(45, 100%, 15%)" // Text Selection Highlight + + // --- CONTENT (Text & Icons) --- + ,content_main: "hsl(50, 60%, 85%)" // Primary Reading Text + ,content_muted: "hsl(36, 15%, 60%)" // Metadata, subtitles + ,content_subtle: "hsl(36, 10%, 40%)" // Placeholders, disabled states + ,content_inverse: "hsl(0, 0%, 5%)" // Text on high-contrast buttons + + // --- BRAND & ACTION (The "Wheat" Identity) --- + ,brand_primary: "hsl(45, 100%, 50%)" // Main Action / H1 / Focus Ring + ,brand_secondary: "hsl(38, 90%, 65%)" // Secondary Buttons / H2 + ,brand_tertiary: "hsl(30, 60%, 70%)" // Accents / H3 + ,brand_link: "hsl(48, 100%, 50%)" // Hyperlinks (High Visibility) + + // --- BORDERS & DIVIDERS --- + ,border_faint: "hsl(36, 20%, 15%)" // Subtle separation + ,border_default: "hsl(36, 20%, 25%)" // Standard Card Borders + ,border_strong: "hsl(36, 20%, 40%)" // Active states / Inputs + + // --- STATE & FEEDBACK (Earth Tones) --- + ,state_success: "hsl(100, 50%, 45%)" // Olive Green + ,state_warning: "hsl(35, 90%, 55%)" // Burnt Orange + ,state_error: "hsl(0, 60%, 55%)" // Brick Red + ,state_info: "hsl(200, 40%, 55%)" // Slate Blue + + // --- SYNTAX HIGHLIGHTING (For Code) --- + ,syntax_keyword: "hsl(35, 100%, 65%)" // Orange + ,syntax_string: "hsl(75, 50%, 60%)" // Sage Green + ,syntax_func: "hsl(45, 90%, 70%)" // Light Gold + ,syntax_comment: "hsl(36, 15%, 45%)" // Brown/Gray + }; + + // --- APPLY THEME --- + const palette = RT.config.theme; + const body = document.body; + const html = document.documentElement; + + // 1. Paint Base + html.style.backgroundColor = palette.surface_0; + body.style.backgroundColor = palette.surface_0; + body.style.color = palette.content_main; + + // 2. Export Variables (Standardization) + const s = body.style; + for (const [key, value] of Object.entries(palette)) { + s.setProperty(`--rt-${key.replace(/_/g, '-')}`, value); + } + + + // 3. Global Overrides + const style_id = 'rt-global-overrides'; + if (!document.getElementById(style_id)) { + const style = document.createElement('style'); + style.id = style_id; + style.textContent = ` + ::selection { background: var(--rt-surface-select); color: var(--rt-brand-primary); } + ::-moz-selection { background: var(--rt-surface-select); color: var(--rt-brand-primary); } + + ::-webkit-scrollbar { width: 12px; } + ::-webkit-scrollbar-track { background: var(--rt-surface-0); } + ::-webkit-scrollbar-thumb { + background: var(--rt-border-default); + border: 2px solid var(--rt-surface-0); + border-radius: 8px; + } + ::-webkit-scrollbar-thumb:hover { background: var(--rt-brand-secondary); } + + /* --- Citation & Endnote Styling --- */ + rt-cite a, .rt-inline-cite a, rt-endnotes a { + color: var(--rt-brand-link); + text-decoration: none; + } + rt-cite a:hover, .rt-inline-cite a:hover, rt-endnotes a:hover { + text-decoration: underline; + } + rt-cite, .rt-inline-cite { + font-size: 1em; + vertical-align: baseline; + padding: 0 0.15em; + } + + /* --- Image Inversion for Diagrams --- */ + img.rt-diagram { + filter: invert(1) hue-rotate(180deg); + } + `; + + document.head.appendChild(style); + } + }; + +} )(); diff --git a/developer/authored/RT.copy/theme/light.js b/developer/authored/RT.copy/theme/light.js new file mode 100644 index 0000000..d0e80eb --- /dev/null +++ b/developer/authored/RT.copy/theme/light.js @@ -0,0 +1,70 @@ +/* + Theme: Classic Wheat (Light) + Standard: Theme 1.0 + Description: Warm paper tones with Burnt Orange accents. +*/ +( function(){ + const RT = window.RT = window.RT || {}; + + RT.theme_light = function(){ + RT.config = RT.config || {}; + + // THEME 1.0 DATA CONTRACT + RT.config.theme = { + meta_is_dark: false + ,meta_name: "Classic Wheat" + + // --- SURFACES --- + ,surface_0: "hsl(40, 30%, 94%)" // App Background (Cream/Linen) + ,surface_1: "hsl(40, 25%, 90%)" // Sidebar (Slightly darker beige) + ,surface_2: "hsl(40, 20%, 98%)" // Cards (Lighter, almost white) + ,surface_3: "hsl(0, 0%, 100%)" // Modals (Pure White) + ,surface_input: "hsl(40, 20%, 98%)" // Form Inputs + ,surface_code: "hsl(40, 15%, 90%)" // Code Block Background + ,surface_select: "hsl(45, 100%, 85%)" // Text Selection Highlight + + // --- CONTENT --- + ,content_main: "hsl(30, 20%, 20%)" // Deep Umber (Not Black) + ,content_muted: "hsl(30, 15%, 45%)" // Medium Brown + ,content_subtle: "hsl(30, 10%, 65%)" // Light Brown/Gray + ,content_inverse: "hsl(40, 30%, 94%)" // Text on dark buttons + + // --- BRAND & ACTION --- + ,brand_primary: "hsl(30, 90%, 35%)" // Burnt Orange (Action) + ,brand_secondary: "hsl(35, 70%, 45%)" // Rust / Gold + ,brand_tertiary: "hsl(25, 60%, 55%)" // Copper + ,brand_link: "hsl(30, 100%, 35%)" // Link Color + + // --- BORDERS --- + ,border_faint: "hsl(35, 20%, 85%)" + ,border_default: "hsl(35, 20%, 75%)" + ,border_strong: "hsl(35, 20%, 55%)" + + // --- STATE & FEEDBACK --- + ,state_success: "hsl(100, 40%, 40%)" // Forest Green + ,state_warning: "hsl(30, 90%, 50%)" // Persimmon + ,state_error: "hsl(0, 60%, 45%)" // Crimson + ,state_info: "hsl(200, 50%, 45%)" // Navy Blue + + // --- SYNTAX --- + ,syntax_keyword: "hsl(20, 90%, 45%)" // Rust + ,syntax_string: "hsl(100, 35%, 35%)" // Ivy Green + ,syntax_func: "hsl(300, 30%, 40%)" // Muted Purple + ,syntax_comment: "hsl(35, 10%, 60%)" // Light Brown + }; + + // --- APPLY THEME --- + const palette = RT.config.theme; + const body = document.body; + const html = document.documentElement; + + html.style.backgroundColor = palette.surface_0; + body.style.backgroundColor = palette.surface_0; + body.style.color = palette.content_main; + + const s = body.style; + for (const [key, value] of Object.entries(palette)) { + s.setProperty(`--rt-${key.replace(/_/g, '-')}`, value); + } + }; +} )(); diff --git a/developer/authored/RT.copy/theme/light_gold.js b/developer/authored/RT.copy/theme/light_gold.js new file mode 100644 index 0000000..3136934 --- /dev/null +++ b/developer/authored/RT.copy/theme/light_gold.js @@ -0,0 +1,103 @@ +/* + Theme: Golden Wheat (Light) - "Spanish Gold Edition" + File: style/theme-light-gold.js + Standard: Theme 1.0 + Description: Light Parchment background with Oxblood Red ink. +*/ +( function(){ + const RT = window.RT = window.RT || {}; + + RT.theme = function(){ + RT.config = RT.config || {}; + + RT.config.theme = { + meta_is_dark: false + ,meta_name: "Golden Wheat (Yellow)" + + // --- SURFACES (Light Parchment) --- + // Shifted lightness up to 94% for a "whiter" feel that still holds the yellow tint. + ,surface_0: "hsl(48, 50%, 94%)" // Main Page: Fine Parchment + ,surface_1: "hsl(48, 40%, 90%)" // Panels: Slightly darker + ,surface_2: "hsl(48, 30%, 97%)" // Cards: Very light + ,surface_3: "hsl(0, 0%, 100%)" // Popups + ,surface_input: "hsl(48, 20%, 96%)" + ,surface_code: "hsl(48, 25%, 88%)" // Distinct Code BG + ,surface_select: "hsl(10, 70%, 85%)" // Red Highlight + + // --- CONTENT (Deep Ink) --- + ,content_main: "hsl(10, 25%, 7%)" // Deep Warm Black (Ink) + ,content_muted: "hsl(10, 15%, 35%)" // Dark Grey-Red + ,content_subtle: "hsl(10, 10%, 55%)" + ,content_inverse: "hsl(48, 50%, 90%)" + + // --- BRAND & ACTION (The Red Spectrum) --- + ,brand_primary: "hsl(12, 85%, 30%)" // H1 (Deep Oxblood) + ,brand_secondary: "hsl(10, 80%, 35%)" // H2 (Garnet) + ,brand_tertiary: "hsl(8, 70%, 40%)" // H3 (Brick) + ,brand_link: "hsl(12, 90%, 35%)" // Link + + // --- BORDERS --- + ,border_faint: "hsl(45, 30%, 80%)" + ,border_default: "hsl(45, 30%, 70%)" // Pencil Grey + ,border_strong: "hsl(12, 50%, 40%)" + + // --- STATE --- + ,state_success: "hsl(120, 40%, 30%)" + ,state_warning: "hsl(25, 90%, 45%)" + ,state_error: "hsl(0, 75%, 35%)" + ,state_info: "hsl(210, 60%, 40%)" + + // --- SYNTAX --- + ,syntax_keyword: "hsl(0, 75%, 35%)" + ,syntax_string: "hsl(100, 35%, 25%)" + ,syntax_func: "hsl(15, 85%, 35%)" + ,syntax_comment: "hsl(45, 20%, 50%)" + }; + + // --- APPLY THEME --- + const palette = RT.config.theme; + const body = document.body; + const html = document.documentElement; + + html.style.backgroundColor = palette.surface_0; + body.style.backgroundColor = palette.surface_0; + body.style.color = palette.content_main; + + const s = body.style; + for (const [key, value] of Object.entries(palette)) { + s.setProperty(`--rt-${key.replace(/_/g, '-')}`, value); + } + + // Global overrides + const style_id = 'rt-global-overrides'; + if (!document.getElementById(style_id)) { + const style = document.createElement('style'); + style.id = style_id; + style.textContent = ` + ::selection { background: var(--rt-surface-select); color: var(--rt-brand-primary); } + ::-moz-selection { background: var(--rt-surface-select); color: var(--rt-brand-primary); } + + ::-webkit-scrollbar { width: 12px; } + ::-webkit-scrollbar-track { background: var(--rt-surface-0); } + ::-webkit-scrollbar-thumb { + background: var(--rt-border-default); + border: 2px solid var(--rt-surface-0); + border-radius: 8px; + } + ::-webkit-scrollbar-thumb:hover { background: var(--rt-brand-secondary); } + + rt-article p, rt-article li { + text-shadow: 0px 0px 0.5px rgba(0,0,0, 0.2); + } + + .MathJax, .MathJax_Display, .mjx-chtml { + color: var(--rt-content-main) !important; + fill: var(--rt-content-main) !important; + stroke: var(--rt-content-main) !important; + } + `; + document.head.appendChild(style); + } + }; + +} )(); diff --git a/developer/authored/RT.copy/tool/to_pdf.py b/developer/authored/RT.copy/tool/to_pdf.py new file mode 100644 index 0000000..177f7bd --- /dev/null +++ b/developer/authored/RT.copy/tool/to_pdf.py @@ -0,0 +1,167 @@ +import os +import glob +import base64 +import re +from weasyprint import HTML + +# Find the image file +img_path = None +for search_dir in ['/mnt/data', '/tmp', '.']: + for root, dirs, files in os.walk(search_dir): + if 'money_circle.jpeg' in files: + img_path = os.path.join(root, 'money_circle.jpeg') + break + if img_path: + break + +img_b64 = "" +if img_path: + with open(img_path, "rb") as f: + img_b64 = base64.b64encode(f.read()).decode('utf-8') + +html_content = """ + + + + + On Cybersecurity and Commonsense + + + + +""" + +# String replacements (hyphens, 'may', 'just') +html_content = html_content.replace('—', '-') +html_content = re.sub(r'\bmay\b', 'can', html_content) +html_content = re.sub(r'\bMay\b', 'Can', html_content) +html_content = re.sub(r'\bjust\b', 'merely', html_content) +html_content = re.sub(r'\bJust\b', 'Merely', html_content) + +# Title block replacement +title_match = re.search(r'\s*', html_content, re.IGNORECASE | re.DOTALL) +if title_match: + title, author, date, copyright_text = title_match.groups() + if not copyright_text.startswith('©') and not copyright_text.startswith('©'): + copyright_text = f"© {copyright_text}" + + title_html = f''' +
      +

      {title}

      +

      {author}

      +

      {date}

      + +
      + ''' + html_content = html_content[:title_match.start()] + title_html + html_content[title_match.end():] + +# TOC replacement +headings = re.findall(r'(.*?)', html_content, re.IGNORECASE) +toc_html = '

      Table of Contents

        ' +for idx, (level, _, id_val, text) in enumerate(headings): + if not id_val: + id_val = f"heading-{idx}" + html_content = re.sub(f'{text}', f'{text}', html_content, count=1) + toc_html += f'
      • {text}
      • ' +toc_html += '
      ' + +html_content = re.sub(r']*>', toc_html, html_content, flags=re.IGNORECASE) + +# Image replacement +if img_b64: + html_content = re.sub(r'src="money_circle\.jpeg"', f'src="data:image/jpeg;base64,{img_b64}" class="content-image"', html_content) + +# Custom tags +html_content = re.sub(r'', '
      ', html_content, flags=re.IGNORECASE) +html_content = re.sub(r'', '
      ', html_content, flags=re.IGNORECASE) +html_content = re.sub(r'', '', html_content, flags=re.IGNORECASE) +html_content = re.sub(r'', '', html_content, flags=re.IGNORECASE) +html_content = re.sub(r'', '', html_content, flags=re.IGNORECASE) +html_content = re.sub(r'', '', html_content, flags=re.IGNORECASE) +html_content = re.sub(r'', '', html_content, flags=re.IGNORECASE) +html_content = re.sub(r'', '', html_content, flags=re.IGNORECASE) + +def replace_rt_math(m): + content = m.group(1) + if '\n' in content: + return f'
      {content}
      ' + return f'{content}' + +def replace_rt_code(m): + content = m.group(1) + if '\n' in content: + return f'
      {content}
      ' + return f'{content}' + +html_content = re.sub(r'(.*?)', replace_rt_math, html_content, flags=re.IGNORECASE | re.DOTALL) +html_content = re.sub(r'(.*?)', replace_rt_code, html_content, flags=re.IGNORECASE | re.DOTALL) + +css_styles = """ + @page { + size: letter; + margin: 25mm 20mm; + background-color: #FAFAFA; + @bottom-center { + content: counter(page); + font-family: 'Georgia', serif; + font-size: 10pt; + color: #555; + } + } + body { + margin: 0; + padding: 0; + font-family: 'Georgia', serif; + font-size: 11pt; + line-height: 1.6; + color: #2c3e50; + background-color: #FAFAFA; + } + *, *::before, *::after { box-sizing: border-box; } + + h1, h2, h3, h4 { + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; + color: #1A365D; + page-break-after: avoid; + } + h1 { font-size: 20pt; margin-top: 1.5em; margin-bottom: 0.5em; border-bottom: 2px solid #E2E8F0; padding-bottom: 0.2em; } + h2 { font-size: 16pt; margin-top: 1.5em; margin-bottom: 0.5em; } + p { margin-bottom: 1em; text-align: justify; } + ul, ol { margin-bottom: 1em; padding-left: 2em; } + li { margin-bottom: 0.5em; } + + .title-block { text-align: center; margin-bottom: 4em; padding: 2em 0; border-bottom: 3px solid #1A365D; } + .title-block h1 { font-size: 26pt; border: none; margin-top: 0; margin-bottom: 0.5em; color: #0F2040; } + .title-block .meta-author { font-size: 14pt; font-weight: bold; margin: 0.2em 0; } + .title-block .meta-date { font-size: 12pt; color: #555; font-style: italic; margin: 0.2em 0; } + .title-block .meta-copyright { font-size: 10pt; color: #777; margin-top: 1em; } + + .toc-block { background-color: #F0F4F8; padding: 20px; border-radius: 5px; margin-bottom: 3em; page-break-after: always; } + .toc-block h2 { margin-top: 0; border: none; } + .toc-block ul { list-style-type: none; padding-left: 0; } + .toc-h1 { font-weight: bold; margin-top: 0.8em; } + .toc-h2 { padding-left: 1.5em; font-size: 0.95em; } + .toc-block a { text-decoration: none; color: #2c3e50; } + + .rt-term { font-weight: bold; color: #2980B9; } + .rt-term-em { font-weight: bold; font-style: italic; color: #2980B9; } + .rt-neologism { font-variant: small-caps; font-weight: bold; color: #C0392B; } + .rt-code-inline { font-family: 'Courier New', Courier, monospace; background-color: #EAECEE; padding: 2px 4px; border-radius: 3px; font-size: 0.9em; } + .rt-code-block { font-family: 'Courier New', Courier, monospace; background-color: #F4F6F7; padding: 15px; border-left: 4px solid #7F8C8D; border-radius: 3px; font-size: 0.9em; overflow-x: auto; white-space: pre-wrap; } + + .math { font-family: 'Times New Roman', serif; font-style: italic; font-weight: bold; color: #2C3E50; } + .math-block { text-align: center; margin: 1.5em 0; font-size: 1.2em; background-color: #F9EBEA; padding: 10px; border-radius: 5px; } + .math-inline { font-size: 1.05em; } + + table { width: 100%; border-collapse: collapse; margin: 2em 0; } + th, td { padding: 10px; text-align: left; vertical-align: top; } + th { background-color: #1A365D; color: white; font-weight: bold; } + tr { border-bottom: 1px solid #ddd; } + hr { border: 0; border-top: 1px solid #eee; } + + .content-image { display: block; max-width: 90%; margin: 2em auto; border: 1px solid #ccc; box-shadow: 0 4px 8px rgba(0,0,0,0.1); } +""" + +final_html = f"{html_content}" +HTML(string=final_html).write_pdf("White_Paper_Cybersecurity_Legislation.pdf") +print("Success") diff --git a/developer/authored/RT.copy/tool/to_pdf2.py b/developer/authored/RT.copy/tool/to_pdf2.py new file mode 100644 index 0000000..a493d27 --- /dev/null +++ b/developer/authored/RT.copy/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.") diff --git a/developer/authored/RT/core/block_visibility_during_layout.js b/developer/authored/RT/core/block_visibility_during_layout.js deleted file mode 100644 index 8513f01..0000000 --- a/developer/authored/RT/core/block_visibility_during_layout.js +++ /dev/null @@ -1,19 +0,0 @@ -// block_visibility_during_layout.js - -// 1. Hide the document immediately upon execution in the -document.documentElement.style.visibility = "hidden"; - -// 2. Define the restoration function -const restore_visibility = function() { - document.documentElement.style.visibility = ""; - document.removeEventListener("RT_layout_complete", restore_visibility); - window.removeEventListener("load", restore_visibility); -}; - -// 3. Listen for a specific completion signal from the layout engine -document.addEventListener("RT_layout_complete", restore_visibility); - -// 4. Structural Safety Net: If the layout engine fails or is never loaded, -// restore visibility on the final window 'load' event so the page doesn't remain blank. -window.addEventListener("load", restore_visibility); - diff --git a/developer/authored/RT/core/loader.js b/developer/authored/RT/core/loader.js deleted file mode 100644 index 5334d08..0000000 --- a/developer/authored/RT/core/loader.js +++ /dev/null @@ -1,22 +0,0 @@ -window.RT = window.RT || {}; - -window.RT.load = function(module_path){ - let target_module = module_path; - - if(target_module === 'theme'){ - let saved_theme = localStorage.getItem('RT_theme_preference'); - if(!saved_theme){ - saved_theme = 'dark_gold'; - localStorage.setItem('RT_theme_preference', saved_theme); - } - target_module = 'theme/' + saved_theme; - } - - let resolved_path = window.RT.dirpr_library + '/' + target_module; - - if(!resolved_path.endsWith('.js')){ - resolved_path = resolved_path + '.js'; - } - - document.write(''); -}; diff --git a/developer/authored/RT/core/utility.js b/developer/authored/RT/core/utility.js deleted file mode 100644 index d6f2ddd..0000000 --- a/developer/authored/RT/core/utility.js +++ /dev/null @@ -1,109 +0,0 @@ -/* - General utilities for the RT Style library. -*/ - -window.RT = window.RT || {}; - -// --- DEBUG SYSTEM --- -window.RT.debug = { - - // all debug messages enabled -/* - active_tokens: new Set([ - 'style', 'layout', 'pagination' - ,'selector', 'config', 'error' - ,'term' - ,'scroll' - ]), - - active_tokens: new Set([ - 'term' - ]), -*/ - - active_tokens: new Set([ - ]), - - log: function(token, message) { - if (this.active_tokens.has(token)) { - console.log(`[RT:${token}]`, message); - } - }, - - warn: function(token, message) { - if (this.active_tokens.has(token)) { - console.warn(`[RT:${token}]`, message); - } - }, - - error: function(token, message) { - console.error(`[RT:${token}] CRITICAL:`, message); - }, - - enable: function(token) { this.active_tokens.add(token); console.log(`Enabled: ${token}`); }, - disable: function(token) { this.active_tokens.delete(token); console.log(`Disabled: ${token}`); } -}; - -// --- UTILITIES --- -window.RT.utility = { - // --- FONT PHYSICS --- - measure_ink_ratio: function(target_font, ref_font = null) { - const debug = window.RT.debug; - debug.log('layout', `Measuring ink ratio for ${target_font}`); - - const canvas = document.createElement('canvas'); - const ctx = canvas.getContext('2d'); - - if (!ref_font) { - const bodyStyle = window.getComputedStyle(document.body); - ref_font = bodyStyle.fontFamily; - } - - const get_metrics = (font) => { - ctx.font = '100px ' + font; - const metrics = ctx.measureText('M'); - return { - ascent: metrics.actualBoundingBoxAscent, - descent: metrics.actualBoundingBoxDescent - }; - }; - - const ref_m = get_metrics(ref_font); - const target_m = get_metrics(target_font); - - const ratio = ref_m.ascent / target_m.ascent; - - return { - ratio: ratio, - baseline_diff: ref_m.descent - target_m.descent - }; - }, - - // --- COLOR PHYSICS --- - is_color_light: function(color_string) { - // 1. HSL Check - if (color_string.startsWith('hsl')) { - const numbers = color_string.match(/\d+/g); - if (numbers && numbers.length >= 3) { - const lightness = parseInt(numbers[2]); - return lightness > 50; - } - } - - // 2. RGB Check - const rgb = color_string.match(/\d+/g); - if (!rgb) { - return true; - } - - const r = parseInt(rgb[0]); - const g = parseInt(rgb[1]); - const b = parseInt(rgb[2]); - const luma = (r * 299 + g * 587 + b * 114) / 1000; - return luma > 128; - }, - - is_block_content: function(element) { - return element.textContent.trim().includes('\n'); - } -}; diff --git a/developer/authored/RT/document/RT0 b/developer/authored/RT/document/RT0 deleted file mode 120000 index 2a6dec2..0000000 --- a/developer/authored/RT/document/RT0 +++ /dev/null @@ -1 +0,0 @@ -/home/Thomas/subu_data/developer/project/RT-style-JS_public/shared/linked-project/RT-style-JS_public/consumer/release/RT \ No newline at end of file diff --git a/developer/authored/RT/document/style_manual.html b/developer/authored/RT/document/style_manual.html deleted file mode 100644 index 61e0d74..0000000 --- a/developer/authored/RT/document/style_manual.html +++ /dev/null @@ -1,419 +0,0 @@ - - - - - RT Style System: Reference Manual - - - - - - - - - - - - - Table of custom tags - -

      Style tag reference

      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      TagDescription
      <RT-article>Article container.
      <RT-title> - Title block and metadata. -
      <RT-TOC>Compiles TOC.
      <RT-index>Compiles an alphabetical glossary of defined terms.
      <RT-term>Conventional term.
      <RT-term-em>Forces emphasis for a term even after first occurrence.
      <RT-neologism>Project specific term.
      <RT-neologism-em>Forces emphasis for a neologism even after first occurrence.
      <RT-code>Code span or code block.
      <RT-math>Inline or block math.
      <RT-footnote>Inline text to be extracted and rendered at the bottom of the page.
      <RT-cite>Bibliographic citation marker.
      <RT-ref>Dynamic cross reference to another element in the document.
      <RT-page>Automatically inserted pagination container.
      <RT-chapter>Chapter heading with implied page break.
      <RT-page-break>Explicit page break directive. Must be explicitly closed.
      - - Architecture overview -

      - The RT Style System is a client-side, JavaScript-driven publishing framework designed to turn raw HTML into high-readability technical documentation. Unlike standard CSS frameworks, RT uses JavaScript to handle complex layout tasks like ink-ratio balancing and dynamic pagination. -

      - -

      Pulling style files into a document

      -

      Put `setup.js` in the directory, and include it at the top of the document, - `setup.js` points at the style files and is installation specific.

      - - - Semantic tags -

      - The system relies on a specific set of custom tags in the RT- namespace to separate meaning from presentation. -

      - -

      Terminology

      - -

      Conventional terms

      -

      - Use <RT-term> for standard, industry accepted technical terms. The system decorates only the first occurrence of each unique term so that the first appearance functions as a definition point, and later appearances do not overload the page with styling. -

      - - - The Singleton Pattern restricts instantiation... - - -

      - Renders as: The Singleton Pattern restricts instantiation... -

      - -

      Neologisms

      -

      - Use <RT-neologism> for terms invented specifically for the current document or project. Neologisms are styled more strongly than conventional terms, visually distinguishing "jargon you should know" from "jargon we invented." -

      - - - We define the Hyper Tape as a construct... - - -

      - Renders as: We define the Hyper Tape as a construct... -

      - -

      First occurrence rule

      -

      - The term system is intentionally conservative. For the tags <RT-term> and <RT-neologism>, only the first occurrence of a unique term is decorated. Subsequent mentions are rendered as normal prose. -

      - -

      - Uniqueness is tracked by normalizing the term text (trimmed, then lowercased). This means that Symbol and symbol count as the same term. -

      - -

      Forced emphasis variants

      -

      - Sometimes a later mention of a term should be emphasized again. For that purpose, the system provides explicit emphasis tags: -

      - -
        -
      • <RT-term-em>
      • -
      • <RT-neologism-em>
      • -
      - -

      - These variants are always decorated, even if the term appeared earlier. -

      - -

      Automatic definition anchors

      -

      - For first occurrences, the term module automatically assigns an id attribute if one does not already exist. This establishes stable anchors for future indexing and linking. -

      - - - We define a Symbol as... - - -

      - The first occurrence will be given an id similar to def-symbol. For neologisms, an additional marker is used, for example def-neo-hyper-tape. -

      - -

      Technical content

      - -

      Code

      -

      - Use <RT-code>. If placed inline, it acts like a span. If placed as a block (with newlines), it acts like a pre formatted block with a theme aware border. -

      - - - # Block Code Example - def hello(): - return "World" - - -

      Mathematics

      -

      - Use <RT-math>. The system auto detects if it is a block equation or inline variable and wraps it in MathJax delimiters. -

      -

      - Inline: Let x be the input. -

      -

      - Block: -

      - - f(x) = \sum_{i=0}^{n} x_i - - -

      References, citations, and indexing

      - -

      Footnotes

      -

      - Use <RT-footnote> to author footnote content directly inline with the text it references. During the layout phase, the pagination engine extracts the text, replaces the element with an invisible structural marker, and compiles a formatted footnote container at the bottom of the active <RT-page>. -

      - -

      Citations

      -

      - Use <RT-cite> with the ref attribute to insert bibliographic citations. This ensures formatting remains consistent and separates citation data from standard prose. -

      - - ... formalized as Basic Law V . - - -

      Dynamic cross referencing

      -

      - A person authoring a technical document frequently refers back to tables, equations, or previous sections. Use <RT-ref target="element-id"> to link to specific content. This tag dynamically retrieves the numbering or caption of the target element, maintaining correct references even if preceding elements shift during editing. -

      - -

      Glossary indexing

      -

      - Use <RT-index> at the end of the document to compile a glossary. Similar to the TOC compiler, this tag scans the DOM for automatic definition anchors produced by the term module and generates an alphabetized list of defined terms and neologisms. -

      - - Navigation and layout - -

      Automatic table of contents

      -

      - Use <RT-TOC> to insert a compiled table of contents. The tag scans the document forward from its current position to collect headings. -

      - -

      Explicit mode

      -

      - Use the level="N" attribute to target a specific heading depth. -

      -
        -
      • <RT-TOC level="1">: Collects all <h1> elements until the end of the document. Best for the main document index.
      • -
      • <RT-TOC level="2">: Collects all <h2> elements until it encounters the next <h1>. Best for chapter summaries.
      • -
      - -

      Implicit mode

      -

      - If no level is specified, the TOC scans backwards to find the nearest heading (for example H1) and assumes you want to collect children one level deeper (for example H2). -

      -

      - Note: Implicit mode can fail if placed before the first heading of a section. Use explicit levels for robust results. -

      - -

      The title block

      -

      - Use <RT-title> as the first element in your <body> (before the article container). This tag produces a standardized, styled header block with the document title and metadata. -

      - -

      Attributes

      -
        -
      • title (Required): The main heading of the document.
      • -
      • author (Optional): The author's name. Renders in a bold accent color.
      • -
      • date (Optional): The publication or revision date.
      • -
      - -

      Example

      - - - - - -

      - Renders as: A centered, high contrast H1 followed by a serif styled metadata row containing the author and date. -

      - -

      The article container

      -

      - The root element must be <RT-article>. This is the boundary for the pagination logic. -

      - -

      Pagination

      -

      - The script paginate_by_element.js scans the article. It calculates the height of every element (including margins) and bundles them into <RT-page> elements. -

      -

      - Soft Limit Pagination: The system attempts to keep headers with their following paragraphs. It will break a page early rather than stranding a header at the bottom. -

      - -

      Manual page breaks and chapters

      -

      - A person can assert explicit control over the layout engine using the <RT-page-break></RT-page-break> tag. This tag forces the engine to close the current page and push all subsequent content to the top of the next page. Standard HTML5 parsing requires this custom tag to be explicitly closed; self-closing syntax will fail. -

      -

      - For major document divisions, use <RT-chapter>. The semantic processor translates this tag into an <RT-page-break> followed by an <h1 class="RT-chapter">. This ensures the chapter starts on a new page, inherits standard typography, and is automatically indexed by the TOC engine. -

      - - Debugging - -

      Debug tokens

      -

      - RT provides a lightweight debug logging system in utility.js. Logging is controlled by a set of active debug tokens. Each log message is assigned a token, and the message prints only if that token is enabled. -

      - -

      - Examples of common tokens include style, layout, pagination, selector, config, and term. -

      - -

      How logging is gated

      -

      - Normal log and warning output are gated. The methods debug.log(token,message) and debug.warn(token,message) will print only when the token exists in debug.active_tokens. -

      - -

      - This prevents the console from being flooded during normal use, while still allowing deep visibility during development. -

      - -

      Errors are always printed

      -

      - Errors are treated differently. The method debug.error(token,message) always prints, regardless of token state. These messages represent failures that require attention. -

      - -

      Enabling and disabling tokens

      -

      - Tokens are enabled or disabled in two ways: by editing the active_tokens set in utility.js, or at runtime by calling: -

      - - - window.RT.debug.enable('term') - window.RT.debug.disable('term') - - -

      - For example, the term system (RT_term.js) uses the term token. When that token is enabled, the module will print messages describing how terms were detected and which term definitions were assigned IDs. -

      - - Themes -

      - The system supports hot swapping themes by changing the script import in the head. -

      -
        -
      • Dark: style/theme_dark_gold.js (Default)
      • -
      • Light: style/theme_light_gold.js
      • -
      - - Manifest - - 2. utility.js (Math/Color physics) - 3. article_tech_ref.js (Typography and CSS injection) - 4. RT_code.js (Code block logic) - 5. RT_math.js (MathJax wrapper) - 6. RT_term.js (Term styling) - 7. RT_TOC.js (Navigation generator) - 8. paginate_by_element.js (Page splitter) - 9. page_fixed_glow.js (Visual page container) - - - RT conventions -

      Headings are first letter capitalized. Remaining words are as they would be in English prose.

      - - Exercises - -
        -
      1. -

        - Term occurrences: If an author tags a word with <RT-term> five times in a document, how many times will the term be visually decorated by the styling engine? How does a person force the engine to decorate a later occurrence? -

        -
      2. -
      3. -

        - Term normalization: A person writes <RT-term>Parse Tree</RT-term> in paragraph one, and <RT-term>parse tree</RT-term> in paragraph two. Will the system assign a definition anchor to the second occurrence? -

        -
      4. -
      5. -

        - TOC compilation: What happens if a person places an <RT-TOC> tag without a level attribute before the first heading of a section? -

        -
      6. -
      7. -

        - Code and math formatting: How does the RT system determine whether to render an <RT-code> or <RT-math> element inline with the text versus as a standalone block? -

        -
      8. -
      9. -

        - Pagination logic: When the script bundles elements into an <RT-page> container, how does the soft limit pagination handle a heading that falls at the very bottom of the page capacity? -

        -
      10. -
      - -
      - - diff --git a/developer/authored/RT/element/TOC.js b/developer/authored/RT/element/TOC.js deleted file mode 100644 index 2f3bc6f..0000000 --- a/developer/authored/RT/element/TOC.js +++ /dev/null @@ -1,162 +0,0 @@ -/* - Processes tags. - Populates each with headings found below it. - - Attributes: - level="N" : Explicitly sets the target heading level (1-6). - e.g., level="1" collects H1s. level="2" collects H2s. - Stops collecting if it hits a heading of (level - 1) or higher. - - Default (No attribute): - Context Aware. Looks backwards for the nearest heading H(N). - Targets H(N+1). Stops at the next H(N). - -First heading 1 1 - First heading 2 2 - Next heading 2 2 -Next heading 2 3 - -*/ - -window.RT = window.RT || {}; - -window.RT.TOC = function(){ - const debug = window.RT.debug || { log: function(){} }; - const TOC_seq = document.querySelectorAll('rt-toc'); - - TOC_seq.forEach( (container ,TOC_index) => { - container.style.display = 'block'; - - // 1. Parse attribute: single number N or range A-B - const attr_val = container.getAttribute('level'); - let start_level, end_level; - - if (attr_val) { - const rangeMatch = attr_val.match(/^(\d)-(\d)$/); - if (rangeMatch) { - const a = parseInt(rangeMatch[1]); - const b = parseInt(rangeMatch[2]); - if (a >= 1 && a <= 6 && b >= 1 && b <= 6 && a <= b) { - start_level = a; - end_level = b; - if (debug.log) debug.log('TOC', `TOC #${TOC_index} range: H${a}-H${b}`); - } else { - if (debug.log) debug.log('TOC', `Invalid range "${attr_val}" → implicit mode`); - } - } else { - const single = parseInt(attr_val); - if (!isNaN(single) && single >= 1 && single <= 6) { - start_level = single; - end_level = single; - if (debug.log) debug.log('TOC', `TOC #${TOC_index} single level: H${single}`); - } else { - if (debug.log) debug.log('TOC', `Invalid level "${attr_val}" → implicit mode`); - } - } - } - - // 2. Implicit mode (no attribute or invalid) - if (start_level === undefined || end_level === undefined) { - let context_level = 0; - let prev = container.previousElementSibling; - while (prev) { - const match = prev.tagName.match(/^H([1-6])$/); - if (match) { - context_level = parseInt(match[1]); - break; - } - prev = prev.previousElementSibling; - } - const target_level = Math.min(context_level + 1, 6); - start_level = target_level; - end_level = target_level; - if (debug.log) debug.log('TOC', `TOC #${TOC_index} implicit target: H${target_level}`); - } - - // 3. Collect all matching headings until a higher-level heading stops us - const headings = []; - let next_el = container.nextElementSibling; - while (next_el) { - const match = next_el.tagName.match(/^H([1-6])$/); - if (match) { - const found_level = parseInt(match[1]); - - // Stop if we hit a heading that is a parent of the lowest level we collect - if (found_level < start_level) break; - - // Collect if within the requested range - if (found_level >= start_level && found_level <= end_level) { - // Ensure it has an id - if (!next_el.id) { - next_el.id = `TOC-ref-${TOC_index}-${found_level}-${headings.length}`; - } - headings.push({ el: next_el, level: found_level }); - } - } - next_el = next_el.nextElementSibling; - } - - // 4. Build the container (title + list) - container.innerHTML = ''; - const title = document.createElement('h1'); - title.textContent = start_level === 1 ? 'Table of Contents' : 'Section Contents'; - title.style.textAlign = 'center'; - container.appendChild(title); - - if (headings.length === 0) return; // nothing to show - - // Top-level list - const topList = document.createElement('ul'); - topList.style.listStyle = 'none'; - topList.style.paddingLeft = '0'; - container.appendChild(topList); - - // Stack of
        elements; index 0 = top-level list - const listStack = [topList]; - - for (const item of headings) { - // Depth relative to start_level - const depth = item.level - start_level; // 0 = top-level, 1 = sub-level, etc. - - // Ensure we have the correct nesting depth - while (listStack.length - 1 > depth) { - // Pop until we are at the right depth - listStack.pop(); - } - - // If we need to go deeper, open new sub-lists inside the last
      • - while (listStack.length - 1 < depth) { - const parentList = listStack[listStack.length - 1]; - const lastLi = parentList.lastElementChild; - if (lastLi) { - const subList = document.createElement('ul'); - subList.style.listStyle = 'none'; - subList.style.paddingLeft = '1.5rem'; // indentation for nested items - lastLi.appendChild(subList); - listStack.push(subList); - } else { - // No parent
      • yet – stay at current depth (flatten) - break; - } - } - - // Create the
      • for this heading - const li = document.createElement('li'); - li.style.marginBottom = '0.5rem'; - - const a = document.createElement('a'); - a.href = `#${item.el.id}`; - a.textContent = item.el.textContent; - a.style.textDecoration = 'none'; - a.style.color = 'inherit'; - a.style.display = 'block'; - - a.onmouseover = () => a.style.color = 'var(--rt-brand-primary)'; - a.onmouseout = () => a.style.color = 'inherit'; - - li.appendChild(a); - // Add to the current deepest list - listStack[listStack.length - 1].appendChild(li); - } - }); -}; diff --git a/developer/authored/RT/element/chapter.js b/developer/authored/RT/element/chapter.js deleted file mode 100644 index 42ba956..0000000 --- a/developer/authored/RT/element/chapter.js +++ /dev/null @@ -1,32 +0,0 @@ -/* - Processes tags. - Transforms the tag into an followed by an

        with the RT-chapter class. -*/ -window.RT = window.RT || {}; - -window.RT.chapter = function(){ - const debug = window.RT.debug || { log: function(){} }; - - document.querySelectorAll('RT-chapter').forEach( (el ,index) => { - if(debug.log) debug.log('chapter' ,`Processing chapter ${index + 1}`); - - const brk = document.createElement('RT-page-break'); - const h1 = document.createElement('h1'); - - h1.innerHTML = el.innerHTML; - - if(el.className){ - h1.className = el.className; - } - h1.classList.add('RT-chapter'); - - Array.from(el.attributes).forEach( (attr) => { - if(attr.name !== 'class'){ - h1.setAttribute(attr.name ,attr.value); - } - }); - - el.parentNode.insertBefore(brk ,el); - el.replaceWith(h1); - }); -}; diff --git a/developer/authored/RT/element/code.js b/developer/authored/RT/element/code.js deleted file mode 100644 index 0a97f16..0000000 --- a/developer/authored/RT/element/code.js +++ /dev/null @@ -1,129 +0,0 @@ -/* - Processes tags. - Uses the central config or CSS variables from the theme. - - Removes common indent from lines of code. -*/ -function code() { - const RT = window.RT; - const U = RT.utility; - const debug = RT.debug; - - debug.log('code', 'Starting render cycle.'); - - const metrics = U.measure_ink_ratio('monospace'); - - document.querySelectorAll('rt-code').forEach((el) => { - el.style.fontFamily = 'monospace'; - - const computed = window.getComputedStyle(el); - const accent = computed.getPropertyValue('--rt-accent').trim() || 'gold'; - - const is_block = U.is_block_content(el); - const parentColor = computed.color; - const is_text_light = U.is_color_light(parentColor); - - const alpha = is_block ? 0.08 : 0.15; - const overlay = is_text_light ? `rgba(255,255,255,${alpha})` : `rgba(0,0,0,${alpha})`; - const text_color = is_text_light ? '#ffffff' : '#000000'; - - el.style.backgroundColor = overlay; - - if (is_block) { - el.style.display = 'block'; - - // --- Tag-Relative Auto-Dedent Logic --- - - // 1. Get Tag Indentation (The Anchor) - let tagIndent = ''; - const prevNode = el.previousSibling; - if (prevNode && prevNode.nodeType === 3) { - const prevText = prevNode.nodeValue; - const lastNewLineIndex = prevText.lastIndexOf('\n'); - if (lastNewLineIndex !== -1) { - tagIndent = prevText.substring(lastNewLineIndex + 1); - } else if (/^\s*$/.test(prevText)) { - tagIndent = prevText; - } - } - - // 2. Calculate Common Leading Whitespace from Content - const rawLines = el.textContent.split('\n'); - - // Filter out empty lines for calculation purposes so they don't break the logic - const contentLines = rawLines.filter(line => line.trim().length > 0); - - let commonIndent = null; - - if (contentLines.length > 0) { - // Assume the first line sets the standard - const firstMatch = contentLines[0].match(/^\s*/); - commonIndent = firstMatch ? firstMatch[0] : ''; - - // Reduce the commonIndent if subsequent lines have LESS indentation - for (let i = 1; i < contentLines.length; i++) { - const line = contentLines[i]; - // Determine how much of commonIndent this line shares - let j = 0; - while (j < commonIndent.length && j < line.length && commonIndent[j] === line[j]) { - j++; - } - commonIndent = commonIndent.substring(0, j); - if (commonIndent.length === 0) break; // Optimization - } - } else { - commonIndent = ''; - } - - // 3. Process Content - // Rule: Only strip if the Common Indent contains the Tag Indent (Safety Check) - // This handles the Emacs case: Tag is " ", Common is " ". " " starts with " ". - // We strip " ", leaving the code flush left. - let finalString = ''; - - if (commonIndent.length > 0 && commonIndent.startsWith(tagIndent)) { - const cleanedLines = rawLines.map(line => { - // Strip the common indent from valid lines - return line.startsWith(commonIndent) ? line.replace(commonIndent, '') : line; - }); - - // Remove artifact lines (first/last empty lines) - if (cleanedLines.length > 0 && cleanedLines[0].length === 0) { - cleanedLines.shift(); - } - if (cleanedLines.length > 0 && cleanedLines[cleanedLines.length - 1].trim().length === 0) { - cleanedLines.pop(); - } - finalString = cleanedLines.join('\n'); - } else { - // Fallback: Code is to the left of the tag or weirdly formatted. - // Just trim the wrapper newlines. - finalString = el.textContent.trim(); - } - - el.textContent = finalString; - // --- End Indentation Logic --- - - el.style.whiteSpace = 'pre'; - el.style.fontSize = (parseFloat(computed.fontSize) * metrics.ratio * 0.95) + 'px'; - el.style.padding = '1.2rem'; - el.style.margin = '1.5rem 0'; - el.style.borderLeft = `4px solid ${accent}`; - el.style.color = 'inherit'; - } else { - el.style.display = 'inline'; - const exactPx = parseFloat(computed.fontSize) * metrics.ratio * 1.0; - el.style.fontSize = exactPx + 'px'; - el.style.padding = '0.1rem 0.35rem'; - el.style.borderRadius = '3px'; - const offsetPx = metrics.baseline_diff * (exactPx / 100); - el.style.verticalAlign = offsetPx + 'px'; - el.style.color = text_color; - } - }); - - debug.log('code', 'Render cycle complete.'); -} - -window.RT = window.RT || {}; -window.RT.code = code; diff --git a/developer/authored/RT/element/constraint.js b/developer/authored/RT/element/constraint.js deleted file mode 100644 index c33b7b0..0000000 --- a/developer/authored/RT/element/constraint.js +++ /dev/null @@ -1,13 +0,0 @@ -// developer/authored/RT/element/constraint.js -window.RT = window.RT || {}; - -window.RT.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 deleted file mode 100644 index aaea2bc..0000000 --- a/developer/authored/RT/element/crossref.js +++ /dev/null @@ -1,15 +0,0 @@ -// developer/authored/RT/element/crossref.js -window.RT = window.RT || {}; - -window.RT.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/endnote.js b/developer/authored/RT/element/endnote.js deleted file mode 100644 index dd887b3..0000000 --- a/developer/authored/RT/element/endnote.js +++ /dev/null @@ -1,55 +0,0 @@ -window.RT = window.RT || {}; - -window.RT.end_note = 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; - - 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/math.js b/developer/authored/RT/element/math.js deleted file mode 100644 index 51d86a7..0000000 --- a/developer/authored/RT/element/math.js +++ /dev/null @@ -1,35 +0,0 @@ -/* - Processes tags. - JavaScript: math() - HTML Tag: (parsed as rt-math) -*/ -function math(){ - // querySelector treats 'rt-math' as case-insensitive for the tag - document.querySelectorAll('rt-math').forEach(el => { - if (el.textContent.startsWith('$')) return; - - const is_block = el.parentElement.tagName === 'DIV' || - el.textContent.includes('\n') || - el.parentElement.childNodes.length === 1; - - const delimiter = is_block ? '$$' : '$'; - el.style.display = is_block ? 'block' : 'inline'; - el.textContent = `${delimiter}${el.textContent.trim()}${delimiter}`; - }); - - // MathJax must find its config at window.MathJax - window.MathJax = { - tex: { - inlineMath: [['$', '$']], - displayMath: [['$$', '$$']] - } - }; - - const script = document.createElement('script'); - script.src = 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js'; - script.async = true; - document.head.appendChild(script); -} - -window.RT = window.RT || {}; -window.RT.math = math; diff --git a/developer/authored/RT/element/symbol.js b/developer/authored/RT/element/symbol.js deleted file mode 100644 index 7199fda..0000000 --- a/developer/authored/RT/element/symbol.js +++ /dev/null @@ -1,10 +0,0 @@ -// developer/authored/RT/element/symbol.js -window.RT = window.RT || {}; - -window.RT.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/element/term.js b/developer/authored/RT/element/term.js deleted file mode 100644 index 1cc779c..0000000 --- a/developer/authored/RT/element/term.js +++ /dev/null @@ -1,107 +0,0 @@ -/* - Processes and tags. - - Styles only the first occurrence of a unique term/neologism. - - The "-em" variants (e.g., ) are always styled. - - Automatically generates IDs for first occurrences for future indexing. -*/ - -window.RT = window.RT || {}; - -window.RT.term = function() { - const RT = window.RT; - - const debug = RT.debug || { - log: function() {} - ,warn: function() {} - ,error: function() {} - }; - - const DEBUG_TOKEN_S = 'term'; - - try { - // Track seen terms so only the first occurrence is decorated - const seen_terms_dpa = new Set(); - - const apply_style = (el, is_neologism_b) => { - el.style.fontStyle = 'italic'; - el.style.fontWeight = is_neologism_b ? '600' : '500'; - el.style.color = is_neologism_b - ? 'var(--rt-brand-secondary)' - : 'var(--rt-brand-primary)'; - el.style.paddingRight = '0.1em'; // Compensation for italic slant - el.style.display = 'inline'; - }; - - const clear_style = (el) => { - el.style.fontStyle = 'normal'; - el.style.color = 'inherit'; - el.style.fontWeight = 'inherit'; - el.style.paddingRight = ''; - el.style.display = ''; - }; - - const selector_s = [ - 'rt-term' - ,'rt-term-em' - ,'rt-neologism' - ,'rt-neologism-em' - ].join(','); - - const tags_dpa = document.querySelectorAll(selector_s); - - debug.log(DEBUG_TOKEN_S, `Scanning ${tags_dpa.length} term tags`); - - tags_dpa.forEach(el => { - const tag_name_s = el.tagName.toLowerCase(); - const is_neologism_b = tag_name_s.includes('neologism'); - const is_explicit_em_b = tag_name_s.endsWith('-em'); - - const term_text_raw_s = (el.textContent || '').trim(); - if (!term_text_raw_s.length) { - debug.warn(DEBUG_TOKEN_S, `Empty term tag encountered: <${tag_name_s}>`); - return; - } - - // Normalize text for uniqueness tracking - const term_norm_s = term_text_raw_s.toLowerCase(); - - // Slug for ID generation (simple + stable) - const slug_s = term_norm_s.replace(/\s+/g, '-'); - - const is_first_occurrence_b = !seen_terms_dpa.has(term_norm_s); - - if (is_explicit_em_b || is_first_occurrence_b) { - apply_style(el, is_neologism_b); - - if (!is_explicit_em_b && is_first_occurrence_b) { - seen_terms_dpa.add(term_norm_s); - - if (!el.id) { - el.id = `def-${is_neologism_b ? 'neo-' : ''}${slug_s}`; - debug.log( - DEBUG_TOKEN_S - ,`First occurrence: "${term_norm_s}" -> id="${el.id}"` - ); - } else { - debug.log( - DEBUG_TOKEN_S - ,`First occurrence: "${term_norm_s}" (existing id="${el.id}")` - ); - } - } else if (is_explicit_em_b) { - debug.log( - DEBUG_TOKEN_S - ,`Emphasized occurrence: "${term_norm_s}" (<${tag_name_s}>)` - ); - } - } else { - // Subsequent mentions render as normal prose - clear_style(el); - } - }); - - debug.log(DEBUG_TOKEN_S, `Unique terms defined: ${seen_terms_dpa.size}`); - } catch (e) { - debug.error('error', `term failed: ${e && e.message ? e.message : String(e)}`); - } -}; diff --git a/developer/authored/RT/element/theme_selector.js b/developer/authored/RT/element/theme_selector.js deleted file mode 100644 index 05759d2..0000000 --- a/developer/authored/RT/element/theme_selector.js +++ /dev/null @@ -1,27 +0,0 @@ -class ThemeSelector extends HTMLElement{ - connectedCallback(){ - let current_theme = localStorage.getItem('RT_theme_preference'); - if(!current_theme){ - current_theme = 'dark_gold'; - } - - this.innerHTML = ` -
          - Theme Selection
          -
          - -
          - `; - - this.addEventListener( 'change' ,(e) => { - localStorage.setItem('RT_theme_preference' ,e.target.value); - location.reload(); - } ); - } -} - -customElements.define('rt-theme-selector' ,ThemeSelector); diff --git a/developer/authored/RT/element/title.js b/developer/authored/RT/element/title.js deleted file mode 100644 index bfb8d4e..0000000 --- a/developer/authored/RT/element/title.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - Processes tags. - Generates a standard document header block. - - Usage: - -*/ -window.RT = window.RT || {}; - -window.RT.title = function() { - const debug = window.RT.debug || { log: function(){} }; - - document.querySelectorAll('rt-title').forEach(el => { - const title = el.getAttribute('title') || 'Untitled Document'; - const author = el.getAttribute('author'); - const date = el.getAttribute('date'); - const copyright = el.getAttribute('copyright'); - - if (debug.log) debug.log('title', `Generating title block: ${title}`); - - // Container - const container = document.createElement('div'); - container.style.textAlign = 'center'; - container.style.marginBottom = '3rem'; - container.style.marginTop = '2rem'; - container.style.borderBottom = '1px solid var(--rt-border-default)'; - container.style.paddingBottom = '1.5rem'; - - // Main Title (H1) - const h1 = document.createElement('h1'); - h1.textContent = title; - h1.style.margin = '0 0 0.8rem 0'; - h1.style.border = 'none'; // Override standard H1 border - h1.style.padding = '0'; - h1.style.color = 'var(--rt-brand-primary)'; - h1.style.fontSize = '2.5em'; - h1.style.lineHeight = '1.1'; - h1.style.letterSpacing = '-0.03em'; - - container.appendChild(h1); - - // Metadata Row (Author | Date) - if (author || date) { - const meta = document.createElement('div'); - meta.style.color = 'var(--rt-content-muted)'; - meta.style.fontStyle = 'italic'; - meta.style.fontSize = '1.1em'; - meta.style.fontFamily = '"Georgia", "Times New Roman", serif'; // Classy serif - - const parts = []; - if (author) parts.push(`${author}`); - if (date) parts.push(date); - - meta.innerHTML = parts.join('  —  '); - container.appendChild(meta); - } - - // Copyright Row - if (copyright) { - const copy_div = document.createElement('div'); - copy_div.style.color = 'var(--rt-content-muted)'; - copy_div.style.fontSize = '0.9em'; - copy_div.style.marginTop = '0.5rem'; - // Automatically injects the copyright symbol - copy_div.innerHTML = `© ${copyright}`; - container.appendChild(copy_div); - } - - // Replace the raw tag with the generated block - el.replaceWith(container); - }); -}; diff --git a/developer/authored/RT/layout/article_tech_ref.js b/developer/authored/RT/layout/article_tech_ref.js deleted file mode 100644 index fc7034b..0000000 --- a/developer/authored/RT/layout/article_tech_ref.js +++ /dev/null @@ -1,295 +0,0 @@ -// debug messages don't work here, because core/utility isn't loaded until after the function runs. -(function(){ - const RT = window.RT = window.RT || {}; - const debug = RT.debug || { log: function(){} }; - - debug.log('scroll', "1. Initializing script."); - - // 1. Intercept native history restoration immediately - if ('scrollRestoration' in history) { - history.scrollRestoration = 'manual'; - debug.log('scroll', "2. history.scrollRestoration set to manual."); - } - - // 2. Read coordinate from memory before any layout shifts occur - const raw_target = sessionStorage.getItem('RT_saved_y'); - const target_y = raw_target !== null ? parseInt(raw_target, 10) : 0; - - // 3. Determine if the execution is a page reload - let is_reload = false; - if (window.performance) { - const nav_entries = performance.getEntriesByType("navigation"); - if (nav_entries.length > 0) { - is_reload = (nav_entries[0].type === "reload"); - } else if (performance.navigation) { - is_reload = (performance.navigation.type === 1); - } - } - - debug.log('scroll', `3. Target Y: ${target_y} | Is Reload: ${is_reload}`); - - // 4. The Lock - let is_layout_locked = true; - - // Helper to ensure we only signal completion once - function unlock_layout() { - if (!is_layout_locked) return; - is_layout_locked = false; - debug.log('scroll', "10. Layout fully unlocked. Emitting completion signal."); - document.dispatchEvent(new Event("RT_layout_complete")); - } - - // 5. Declare Dependencies - RT.load('element/chapter'); - RT.load('element/endnote'); - RT.load('element/math'); - RT.load('element/code'); - RT.load('element/term'); - RT.load('element/TOC'); - RT.load('element/title'); - RT.load('element/theme_selector'); - RT.load('element/symbol'); - RT.load('element/constraint'); - RT.load('element/crossref'); - - RT.load('layout/paginate_by_element'); - RT.load('layout/page_fixed_glow'); - - // 6. The Typography Layout - RT.article = function(){ - RT.config = RT.config || {}; - RT.config.article = { - font_family: '"Noto Sans", "Segoe UI", "Helvetica Neue", sans-serif' - ,line_height: "1.8" - ,font_size: "16px" - ,font_weight: "400" - ,max_width: "820px" - ,margin: "0 auto" - }; - - if( RT.config.theme && RT.config.theme.meta_is_dark === false ){ - RT.config.article.font_weight = "600"; - } - - const conf = RT.config.article; - const article_seq = document.querySelectorAll("RT-article"); - - if(article_seq.length === 0) return; - - for(let i = 0; i < article_seq.length; i++){ - let style = article_seq[i].style; - style.display = "block"; - style.fontFamily = conf.font_family; - style.fontSize = conf.font_size; - style.lineHeight = conf.line_height; - style.fontWeight = conf.font_weight; - style.maxWidth = conf.max_width; - style.margin = conf.margin; - style.padding = "0 20px"; - style.color = "var(--rt-content-main)"; - } - - window.RT = window.RT || {}; - window.RT.config = window.RT.config || {}; - window.RT.config.page = window.RT.config.page || {}; - window.RT.config.page.height_limit = 900; - - const style_node = document.createElement("style"); - style_node.innerHTML = ` - body, html, rt-article { - overflow-anchor: none !important; - } - - rt-article { - font-family: 'Noto Sans JP', Arial, sans-serif; - background-color: var(--rt-surface-0); - color: var(--rt-content-main); - max-width: 46.875rem !important; - box-sizing: border-box !important; - } - - rt-article:not(:has(rt-page)) { - padding: 3rem !important; - } - - rt-article:has(rt-page) { - padding: 0 !important; - } - - rt-article rt-page { - position: relative; - display: block; - padding: 3rem; - margin: 1.25rem auto; - background-color: var(--rt-surface-0); - box-shadow: 0 0 0.625rem var(--rt-brand-primary); - } - - rt-article h1 { - font-size: 1.5rem; - text-align: center; - color: var(--rt-brand-primary); - font-weight: 500; - margin-top: 1.5rem; - line-height: 1.15; - } - rt-article h2 { - font-size: 1.25rem; - color: var(--rt-brand-secondary); - text-align: left; - margin-top: 2rem; - margin-left: 0; - } - rt-article h3 { - font-size: 1.125rem; - color: var(--rt-brand-tertiary); - text-align: left; - margin-top: 1.5rem; - margin-left: 4ch; - } - rt-article h4 { - font-size: 1.05rem; - color: var(--rt-content-main); - font-weight: 600; - text-align: left; - margin-top: 1.25rem; - margin-left: 8ch; - } - - rt-article p, - rt-article ul, - rt-article ol { - color: var(--rt-content-main); - text-align: justify; - margin-bottom: 1rem; - margin-left: 0; - } - rt-article li { - margin-bottom: 0.5rem; - } - - rt-article rt-code { - font-family: 'Courier New', Courier, monospace; - background-color: var(--rt-surface-code); - padding: 0.125rem 0.25rem; - color: var(--rt-content-main); - } - - rt-article img { - max-width: 100%; - height: auto; - display: block; - margin: 1.5rem auto; - } - `; - document.head.appendChild(style_node); - }; - - // 7. The Execution Sequence - function run_semantics(){ - debug.log('scroll' ,`4. run_semantics starting.`); - if(RT.theme) RT.theme(); - if(RT.endnote) RT.endnote(); - 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 ){ - MathJax.Hub.Queue( ["Typeset" ,MathJax.Hub] ,run_layout ); - }else{ - run_layout(); - } - } - - function run_layout() { - debug.log('scroll', `5. run_layout starting.`); - - if(RT.chapter) RT.chapter(); - if(RT.TOC) RT.TOC(); - if(RT.paginate_by_element) RT.paginate_by_element(); - if(RT.page) RT.page(); - - debug.log('scroll', `6. Pagination complete.`); - - let final_target = target_y; - let use_hash = false; - - if (window.location.hash && !is_reload) { - const hash_target = document.getElementById(window.location.hash.substring(1)); - if (hash_target) { - use_hash = true; - } - } - - debug.log('scroll', `7. Commencing viewport enforce loop. Mode: ${use_hash ? 'HASH' : 'Y-COORDINATE'}`); - enforce_scroll(final_target, use_hash, 0); - } - - // 8. The Enforcer Logic - function enforce_scroll(target, use_hash, attempts) { - if (attempts > 15) { - debug.log('scroll', "8. Scroll enforcement timed out. Unlocking."); - unlock_layout(); - return; - } - - if (use_hash) { - const hash_target = document.getElementById(window.location.hash.substring(1)); - if (hash_target) { - hash_target.scrollIntoView(); - debug.log('scroll', `8a. Attempt ${attempts}: Scrolled to Hash Target. Y is now ${window.scrollY}`); - } - } else { - window.scrollTo(0, target); - debug.log('scroll', `8b. Attempt ${attempts}: Scrolled to Y=${target}. Current Y is ${window.scrollY}`); - } - - let is_successful = false; - if (use_hash) { - is_successful = true; - } else { - is_successful = (Math.abs(window.scrollY - target) < 5 || target === 0); - } - - if (is_successful && document.body.scrollHeight > 1000) { - debug.log('scroll', `9. Viewport anchored successfully.`); - - setTimeout(() => { - if (!use_hash && Math.abs(window.scrollY - target) >= 5) { - debug.log('scroll', `9a. Browser late-stage rebellion detected. Re-enforcing.`); - enforce_scroll(target, use_hash, attempts + 1); - } else { - unlock_layout(); - } - }, 100); - } else { - setTimeout(() => enforce_scroll(target, use_hash, attempts + 1), 50); - } - } - - // 9. The Ledger - let scroll_timer; - window.addEventListener('scroll', () => { - if (is_layout_locked) return; - clearTimeout(scroll_timer); - scroll_timer = setTimeout(() => { - sessionStorage.setItem('RT_saved_y', window.scrollY); - debug.log('scroll', `X. User stopped scrolling. Saved Y: ${window.scrollY}`); - }, 200); - }, { passive: true }); - - window.addEventListener('beforeunload', () => { - is_layout_locked = true; - debug.log('scroll', "Y. Page unloading. Scroll listener locked."); - }); - - // 10. Bind to DOM Ready - document.addEventListener('DOMContentLoaded', run_semantics); - -})(); - diff --git a/developer/authored/RT/layout/memo_State.js b/developer/authored/RT/layout/memo_State.js deleted file mode 100644 index 5609705..0000000 --- a/developer/authored/RT/layout/memo_State.js +++ /dev/null @@ -1,70 +0,0 @@ -/* - - - - - - - -*/ - -(function(){ - const RT = window.RT = window.RT || {}; - - // 1. Declare Dependencies - RT.load('core/utility'); - RT.load('element/title'); - RT.load('element/term'); - RT.load('element/TOC'); - RT.load('core/body_visibility_visible'); - - // 2. The Typography Layout - RT.memo_state_dept = function(){ - const body = document.body; - const html = document.documentElement; - - // Force strict print colors regardless of user system settings - html.style.backgroundColor = "white"; - body.style.backgroundColor = "white"; - body.style.color = "black"; - - // Target the new semantic tag - const memo_seq = document.querySelectorAll("RT-memo"); - if(memo_seq.length === 0) return; - - for(let i = 0; i < memo_seq.length; i++){ - let style = memo_seq[i].style; - style.display = "block"; - style.fontFamily = '"Times New Roman", Times, serif'; - style.fontSize = "12pt"; - style.lineHeight = "1.15"; - // 8.5 inch standard width minus 1-inch margins on each side - style.maxWidth = "6.5in"; - style.margin = "1in auto"; - style.padding = "0"; - style.textAlign = "left"; - style.color = "black"; - } - }; - - // 3. The Execution Sequence - const run_semantics = function(){ - RT.memo_state_dept(); - - if(RT.title) RT.title(); - if(RT.term) RT.term(); - if(RT.TOC) RT.TOC(); - - run_layout(); - }; - - const run_layout = function(){ - if(RT.body_visibility_visible) RT.body_visibility_visible(); - }; - - // 4. Bind to DOM Ready - document.addEventListener('DOMContentLoaded' ,run_semantics); - -})(); diff --git a/developer/authored/RT/layout/page_fixed_glow.js b/developer/authored/RT/layout/page_fixed_glow.js deleted file mode 100644 index 6ef8819..0000000 --- a/developer/authored/RT/layout/page_fixed_glow.js +++ /dev/null @@ -1,83 +0,0 @@ -/* - Page Layout: Fixed Glow - Standard: Theme 1.0 - Description: A variable-height container with a glowing border effect that matches the active theme. -*/ -(function(){ - const RT = window.RT = window.RT || {}; - - RT.page = function() { - RT.config = RT.config || {}; - - // Default Configuration - const defaults = { - width: "100%" - ,min_height: "15rem" // Replaces fixed height - ,padding: "3rem" - ,margin: "4rem auto" - - ,bg_color: "var(--rt-surface-0)" - ,border_color: "var(--rt-brand-primary)" - ,text_color: "var(--rt-brand-primary)" - - ,shadow: "drop-shadow(0px 0px 15px var(--rt-brand-primary))" - }; - - RT.config.page = Object.assign({}, defaults, RT.config.page || {}); - - const conf = RT.config.page; - const style_id = 'rt-page-fixed-glow'; - - if (!document.getElementById(style_id)) { - const style_el = document.createElement('style'); - style_el.id = style_id; - - style_el.textContent = ` - /* Reset page counter on the article container */ - rt-article { - counter-reset: rt-page-counter; - } - - rt-page { - display: block; - position: relative; - box-sizing: border-box; - overflow: hidden; - - /* Dimensions */ - width: ${conf.width}; - min-height: ${conf.min_height}; - margin: ${conf.margin}; - padding: ${conf.padding}; - - /* Theming */ - background-color: ${conf.bg_color}; - border: 1px solid ${conf.border_color}; - - /* The "Glow" Effect */ - filter: ${conf.shadow}; - - /* Counter Increment */ - counter-increment: rt-page-counter; - } - - /* Page Numbering */ - rt-page::after { - content: "Page " counter(rt-page-counter); - position: absolute; - bottom: 1.5rem; - right: 3rem; - - font-family: "Noto Sans", sans-serif; - font-size: 0.9rem; - font-weight: bold; - - color: ${conf.text_color}; - opacity: 0.8; - pointer-events: none; - } - `; - document.head.appendChild(style_el); - } - }; -})(); diff --git a/developer/authored/RT/layout/paginate_by_element.js b/developer/authored/RT/layout/paginate_by_element.js deleted file mode 100644 index aca2122..0000000 --- a/developer/authored/RT/layout/paginate_by_element.js +++ /dev/null @@ -1,399 +0,0 @@ -window.RT.paginate_by_element = function () { - const RT = window.RT; - const debug = RT.debug || { log: function(){}, error: function(){} }; - const page_conf = (RT.config && RT.config.page) ? RT.config.page : {}; - const page_height_limit = page_conf.height_limit || 1000; - - let measureContainer = null; - - // ========================================================= - // 1. DOM Measurement Utilities - // ========================================================= - function getElHeight(el) { - const wasInDOM = el.parentNode !== null; - if (!wasInDOM) document.body.appendChild(el); - const rect = el.getBoundingClientRect(); - const style = window.getComputedStyle(el); - const margin = parseFloat(style.marginTop) + parseFloat(style.marginBottom); - if (!wasInDOM) el.remove(); - return (rect.height || 0) + (margin || 0); - } - - function getMeasureContainer() { - if (measureContainer && measureContainer.parentNode) return measureContainer; - const article = document.querySelector('RT-article'); - if (!article) { - const temp = document.createElement('div'); - temp.style.visibility = 'hidden'; - temp.style.position = 'absolute'; - temp.style.width = '100%'; - document.body.appendChild(temp); - measureContainer = temp; - return temp; - } - const container = document.createElement('div'); - const articleStyle = window.getComputedStyle(article); - container.style.visibility = 'hidden'; - container.style.position = 'absolute'; - container.style.width = articleStyle.width; - container.style.fontFamily = articleStyle.fontFamily; - container.style.fontSize = articleStyle.fontSize; - container.style.lineHeight = articleStyle.lineHeight; - container.style.fontWeight = articleStyle.fontWeight; - document.body.appendChild(container); - measureContainer = container; - return container; - } - - function measureFragment(frag) { - const container = getMeasureContainer(); - container.appendChild(frag); - const h = getElHeight(frag); - container.removeChild(frag); - return h; - } - - // ========================================================= - // STEP 1: PREPARE FOOTNOTES (Strip and tag) - // ========================================================= - const article_seq = document.querySelectorAll('RT-article'); - if (article_seq.length === 0) { - debug.error('pagination', 'No elements found. Pagination aborted.'); - return; - } - - const footnote_registry = {}; - let footnote_counter = 1; - - Array.from(article_seq).forEach(article => { - // Bulletproof extraction: immune to XML/HTML case-sensitivity parsing quirks - const all_nodes = Array.from(article.querySelectorAll('*')); - const raw_footnotes = all_nodes.filter(node => node.tagName.toLowerCase() === 'rt-footnote'); - - raw_footnotes.forEach(fn => { - const id = footnote_counter++; - footnote_registry[id] = fn.innerHTML; // Save the payload - - // Trim any standard HTML whitespace immediately preceding the tag - const prev = fn.previousSibling; - if (prev && prev.nodeType === Node.TEXT_NODE) { - prev.textContent = prev.textContent.replace(/\s+$/, ''); - } - - // Replace with a zero-height marker that rides along with the text - const marker = document.createElement('rt-fn-marker'); - marker.setAttribute('data-id', id); - - if (fn.parentNode) { - fn.parentNode.replaceChild(marker, fn); - } - }); - }); - - // ========================================================= - // Splitting Logic (Clean and undisturbed) - // ========================================================= - function isSplittable(el) { - const tag = el.tagName; - if (tag === 'UL' || tag === 'OL') { - const items = Array.from(el.children).filter(c => c.tagName === 'LI'); - if (items.length === 0) return null; - - const itemHeights = items.map(li => getElHeight(li)); - const emptyClone = el.cloneNode(false); - const overhead = getElHeight(emptyClone); - - el._splitInfo = { type: 'list', itemHeights, overhead, offset: 0 }; - return makeListSplitter(el, el._splitInfo); - } - - if (tag === 'TABLE') { - const thead = el.querySelector('thead'); - const tbody = el.querySelector('tbody'); - const rows = tbody ? Array.from(tbody.rows) : Array.from(el.rows); - if (rows.length === 0) return null; - - const theadHeight = thead ? getElHeight(thead) : 0; - const rowHeights = rows.map(row => getElHeight(row)); - - const emptyClone = el.cloneNode(false); - if (thead) emptyClone.appendChild(thead.cloneNode(true)); - emptyClone.appendChild(document.createElement('tbody')); - const overhead = getElHeight(emptyClone) - theadHeight; - - el._splitInfo = { type: 'table', rowHeights, overhead, theadHeight, offset: 0 }; - return makeTableSplitter(el, el._splitInfo); - } - return null; - } - - function makeListSplitter(el, info) { - return (remaining) => { - const children = Array.from(el.children).filter(c => c.tagName === 'LI'); - const start = info.offset; - - let bestCount = 0; - let bestHeight = 0; - const tempList = el.cloneNode(false); - - for (let i = 0; i < children.length; i++) { - const itemClone = children[i].cloneNode(true); - tempList.appendChild(itemClone); - const fragHeight = measureFragment(tempList); - if (fragHeight <= remaining) { - bestCount = i + 1; - bestHeight = fragHeight; - } else { - tempList.removeChild(itemClone); - break; - } - } - - if (bestCount === 0) return { first: null, rest: el, firstHeight: 0 }; - - const first = el.cloneNode(false); - for (let i = 0; i < bestCount; i++) { - first.appendChild(children[i].cloneNode(true)); - } - - let rest = null; - if (bestCount < children.length) { - rest = el.cloneNode(false); - for (let i = bestCount; i < children.length; i++) { - rest.appendChild(children[i].cloneNode(true)); - } - - if (el.tagName === 'OL') { - const currentStart = parseInt(el.getAttribute('start'), 10) || 1; - rest.setAttribute('start', currentStart + bestCount); - } - - rest._splitInfo = { - type: 'list', - itemHeights: info.itemHeights, - overhead: info.overhead, - offset: start + bestCount - }; - } - - return { first, rest, firstHeight: bestHeight }; - }; - } - - function makeTableSplitter(el, info) { - const thead = el.querySelector('thead'); - const createShell = () => { - const shell = el.cloneNode(false); - if (thead) shell.appendChild(thead.cloneNode(true)); - const newTbody = document.createElement('tbody'); - shell.appendChild(newTbody); - return shell; - }; - - return (remaining) => { - const tbody = el.querySelector('tbody'); - const rows = tbody ? Array.from(tbody.rows) : Array.from(el.rows); - const start = info.offset; - - let bestCount = 0; - let bestHeight = 0; - const tempTable = createShell(); - const tempBody = tempTable.querySelector('tbody'); - - for (let i = 0; i < rows.length; i++) { - tempBody.appendChild(rows[i].cloneNode(true)); - const h = measureFragment(tempTable); - if (h <= remaining) { - bestCount = i + 1; - bestHeight = h; - } else { - tempBody.removeChild(tempBody.lastChild); - break; - } - } - - if (bestCount === 0) return { first: null, rest: el, firstHeight: 0 }; - - const first = createShell(); - const firstBody = first.querySelector('tbody'); - for (let i = 0; i < bestCount; i++) { - firstBody.appendChild(rows[i].cloneNode(true)); - } - - let rest = null; - if (bestCount < rows.length) { - rest = createShell(); - const restBody = rest.querySelector('tbody'); - for (let i = bestCount; i < rows.length; i++) { - restBody.appendChild(rows[i].cloneNode(true)); - } - - rest._splitInfo = { - type: 'table', - rowHeights: info.rowHeights, - overhead: info.overhead, - theadHeight: info.theadHeight, - offset: start + bestCount - }; - } - - return { first, rest, firstHeight: bestHeight }; - }; - } - - // ========================================================= - // STEP 2: NORMAL PAGINATOR - // ========================================================= - function paginateArticle(article) { - const raw_element_seq = Array.from(article.children).filter(el => - !['SCRIPT', 'STYLE', 'RT-PAGE'].includes(el.tagName) - ); - - if (raw_element_seq.length === 0) return; - - const page_seq = []; - let current_batch_seq = []; - let current_h = 0; - let i = 0; - - while (i < raw_element_seq.length) { - const el = raw_element_seq[i]; - const splitter = isSplittable(el); - - if (splitter) { - const remaining = page_height_limit - current_h; - const { first, rest, firstHeight } = splitter(remaining); - - if (first) { - current_batch_seq.push(first); - current_h += firstHeight; - - if (rest) { - raw_element_seq.splice(i, 1, rest); - } else { - raw_element_seq.splice(i, 1); - } - } else { - if (current_batch_seq.length === 0) { - const frame = document.createElement('rt-scroll-frame'); - frame.style.display = 'block'; - frame.style.overflowY = 'auto'; - frame.style.maxHeight = page_height_limit + 'px'; - frame.appendChild(el); - current_batch_seq.push(frame); - i++; - } else { - page_seq.push(current_batch_seq); - current_batch_seq = []; - current_h = 0; - raw_element_seq[i] = rest || el; - } - } - continue; - } - - - // --- Ordinary (non-splittable) element --- - const h = getElHeight(el); - const is_RT_page_break = el.tagName && el.tagName.toLowerCase() === 'rt-page-break'; - - if( (is_RT_page_break || current_h + h > page_height_limit) && current_batch_seq.length > 0 ){ - let backtrack_seq = []; - let backtrack_h = 0; - - while (current_batch_seq.length > 0) { - const last = current_batch_seq[current_batch_seq.length - 1]; - if (!/^H[1-6]/.test(last.tagName)) break; - const popped = current_batch_seq.pop(); - backtrack_seq.unshift(popped); - backtrack_h += getElHeight(popped); - } - - if (current_batch_seq.length > 0) { - page_seq.push(current_batch_seq); - current_batch_seq = backtrack_seq; - current_h = backtrack_h; - } else { - page_seq.push(backtrack_seq); - current_batch_seq = []; - current_h = 0; - } - } - - current_batch_seq.push(el); - current_h += h; - i++; - } - - if (current_batch_seq.length > 0) { - page_seq.push(current_batch_seq); - } - - // Rebuild article with wrappers - article.innerHTML = ''; - let p = 0; - while (p < page_seq.length) { - const batch = page_seq[p]; - const page_el = document.createElement('rt-page'); - page_el.id = `page-${p + 1}`; - batch.forEach(item => page_el.appendChild(item)); - article.appendChild(page_el); - p++; - } - } - - // Execute pagination - Array.from(article_seq).forEach(article => paginateArticle(article)); - - // ========================================================= - // STEP 3: RESOLVE FOOTNOTES & EXPAND PAGES - // ========================================================= - Array.from(article_seq).forEach(article => { - const rendered_pages = article.querySelectorAll('rt-page'); - - Array.from(rendered_pages).forEach(page => { - // Bulletproof extraction for the markers - const all_page_nodes = Array.from(page.querySelectorAll('*')); - const markers = all_page_nodes.filter(node => node.tagName.toLowerCase() === 'rt-fn-marker'); - - if (markers.length === 0) return; - - // Construct the footer block for this page - const fn_container = document.createElement('div'); - fn_container.className = 'rt-footnote-container'; - fn_container.style.borderTop = '1px solid var(--rt-border-default)'; - fn_container.style.marginTop = '2rem'; - fn_container.style.paddingTop = '1rem'; - fn_container.style.fontSize = '0.9em'; - - markers.forEach(marker => { - const id = marker.getAttribute('data-id'); - const html = footnote_registry[id]; - - // Replace the invisible marker with the visible naked superscript link - const sup = document.createElement('sup'); - sup.innerHTML = `${id}`; - - if (marker.parentNode) { - marker.parentNode.replaceChild(sup, marker); - } - - // Append the actual text to the footer with a clean, print-ready number format - const fn_line = document.createElement('div'); - fn_line.id = `fn-${id}`; - fn_line.style.marginBottom = '0.5rem'; - fn_line.innerHTML = `${id}.${html}`; - fn_container.appendChild(fn_line); - }); - - // Attach the footer. The page organically stretches to fit. - page.appendChild(fn_container); - }); - }); - - // Cleanup - if (measureContainer && measureContainer.parentNode) { - measureContainer.remove(); - measureContainer = null; - } -}; diff --git a/developer/authored/RT/theme/dark_gold.js b/developer/authored/RT/theme/dark_gold.js deleted file mode 100644 index 9550a98..0000000 --- a/developer/authored/RT/theme/dark_gold.js +++ /dev/null @@ -1,115 +0,0 @@ -/* - Theme: Inverse Wheat (Dark) - Standard: Theme 1.0 - Description: High contrast Amber on Deep Charcoal. -*/ -( function(){ - const RT = window.RT = window.RT || {}; - - RT.theme = function(){ - RT.config = RT.config || {}; - - // THEME 1.0 DATA CONTRACT - RT.config.theme = { - meta_is_dark: true - ,meta_name: "Inverse Wheat" - - // --- SURFACES (Depth & Container Hierarchy) --- - ,surface_0: "hsl(0, 0%, 5%)" // App Background (Deepest) - ,surface_1: "hsl(0, 0%, 10%)" // Sidebar / Nav / Panels - ,surface_2: "hsl(0, 0%, 14%)" // Cards / Floating Elements - ,surface_3: "hsl(0, 0%, 18%)" // Modals / Dropdowns / Popovers - ,surface_input: "hsl(0, 0%, 12%)" // Form Inputs - ,surface_code: "hsl(0, 0%, 11%)" // Code Block Background - ,surface_select: "hsl(45, 100%, 15%)" // Text Selection Highlight - - // --- CONTENT (Text & Icons) --- - ,content_main: "hsl(50, 60%, 85%)" // Primary Reading Text - ,content_muted: "hsl(36, 15%, 60%)" // Metadata, subtitles - ,content_subtle: "hsl(36, 10%, 40%)" // Placeholders, disabled states - ,content_inverse: "hsl(0, 0%, 5%)" // Text on high-contrast buttons - - // --- BRAND & ACTION (The "Wheat" Identity) --- - ,brand_primary: "hsl(45, 100%, 50%)" // Main Action / H1 / Focus Ring - ,brand_secondary: "hsl(38, 90%, 65%)" // Secondary Buttons / H2 - ,brand_tertiary: "hsl(30, 60%, 70%)" // Accents / H3 - ,brand_link: "hsl(48, 100%, 50%)" // Hyperlinks (High Visibility) - - // --- BORDERS & DIVIDERS --- - ,border_faint: "hsl(36, 20%, 15%)" // Subtle separation - ,border_default: "hsl(36, 20%, 25%)" // Standard Card Borders - ,border_strong: "hsl(36, 20%, 40%)" // Active states / Inputs - - // --- STATE & FEEDBACK (Earth Tones) --- - ,state_success: "hsl(100, 50%, 45%)" // Olive Green - ,state_warning: "hsl(35, 90%, 55%)" // Burnt Orange - ,state_error: "hsl(0, 60%, 55%)" // Brick Red - ,state_info: "hsl(200, 40%, 55%)" // Slate Blue - - // --- SYNTAX HIGHLIGHTING (For Code) --- - ,syntax_keyword: "hsl(35, 100%, 65%)" // Orange - ,syntax_string: "hsl(75, 50%, 60%)" // Sage Green - ,syntax_func: "hsl(45, 90%, 70%)" // Light Gold - ,syntax_comment: "hsl(36, 15%, 45%)" // Brown/Gray - }; - - // --- APPLY THEME --- - const palette = RT.config.theme; - const body = document.body; - const html = document.documentElement; - - // 1. Paint Base - html.style.backgroundColor = palette.surface_0; - body.style.backgroundColor = palette.surface_0; - body.style.color = palette.content_main; - - // 2. Export Variables (Standardization) - const s = body.style; - for (const [key, value] of Object.entries(palette)) { - s.setProperty(`--rt-${key.replace(/_/g, '-')}`, value); - } - - - // 3. Global Overrides - const style_id = 'rt-global-overrides'; - if (!document.getElementById(style_id)) { - const style = document.createElement('style'); - style.id = style_id; - style.textContent = ` - ::selection { background: var(--rt-surface-select); color: var(--rt-brand-primary); } - ::-moz-selection { background: var(--rt-surface-select); color: var(--rt-brand-primary); } - - ::-webkit-scrollbar { width: 12px; } - ::-webkit-scrollbar-track { background: var(--rt-surface-0); } - ::-webkit-scrollbar-thumb { - background: var(--rt-border-default); - border: 2px solid var(--rt-surface-0); - border-radius: 8px; - } - ::-webkit-scrollbar-thumb:hover { background: var(--rt-brand-secondary); } - - /* --- Citation & Endnote Styling --- */ - rt-cite a, .rt-inline-cite a, rt-endnotes a { - color: var(--rt-brand-link); - text-decoration: none; - } - rt-cite a:hover, .rt-inline-cite a:hover, rt-endnotes a:hover { - text-decoration: underline; - } - rt-cite, .rt-inline-cite { - font-size: 1em; - vertical-align: baseline; - padding: 0 0.15em; - } - - /* --- Image Inversion for Diagrams --- */ - img.rt-diagram { - filter: invert(1) hue-rotate(180deg); - } - `; - - document.head.appendChild(style); - } - }; - -} )(); diff --git a/developer/authored/RT/theme/light.js b/developer/authored/RT/theme/light.js deleted file mode 100644 index d0e80eb..0000000 --- a/developer/authored/RT/theme/light.js +++ /dev/null @@ -1,70 +0,0 @@ -/* - Theme: Classic Wheat (Light) - Standard: Theme 1.0 - Description: Warm paper tones with Burnt Orange accents. -*/ -( function(){ - const RT = window.RT = window.RT || {}; - - RT.theme_light = function(){ - RT.config = RT.config || {}; - - // THEME 1.0 DATA CONTRACT - RT.config.theme = { - meta_is_dark: false - ,meta_name: "Classic Wheat" - - // --- SURFACES --- - ,surface_0: "hsl(40, 30%, 94%)" // App Background (Cream/Linen) - ,surface_1: "hsl(40, 25%, 90%)" // Sidebar (Slightly darker beige) - ,surface_2: "hsl(40, 20%, 98%)" // Cards (Lighter, almost white) - ,surface_3: "hsl(0, 0%, 100%)" // Modals (Pure White) - ,surface_input: "hsl(40, 20%, 98%)" // Form Inputs - ,surface_code: "hsl(40, 15%, 90%)" // Code Block Background - ,surface_select: "hsl(45, 100%, 85%)" // Text Selection Highlight - - // --- CONTENT --- - ,content_main: "hsl(30, 20%, 20%)" // Deep Umber (Not Black) - ,content_muted: "hsl(30, 15%, 45%)" // Medium Brown - ,content_subtle: "hsl(30, 10%, 65%)" // Light Brown/Gray - ,content_inverse: "hsl(40, 30%, 94%)" // Text on dark buttons - - // --- BRAND & ACTION --- - ,brand_primary: "hsl(30, 90%, 35%)" // Burnt Orange (Action) - ,brand_secondary: "hsl(35, 70%, 45%)" // Rust / Gold - ,brand_tertiary: "hsl(25, 60%, 55%)" // Copper - ,brand_link: "hsl(30, 100%, 35%)" // Link Color - - // --- BORDERS --- - ,border_faint: "hsl(35, 20%, 85%)" - ,border_default: "hsl(35, 20%, 75%)" - ,border_strong: "hsl(35, 20%, 55%)" - - // --- STATE & FEEDBACK --- - ,state_success: "hsl(100, 40%, 40%)" // Forest Green - ,state_warning: "hsl(30, 90%, 50%)" // Persimmon - ,state_error: "hsl(0, 60%, 45%)" // Crimson - ,state_info: "hsl(200, 50%, 45%)" // Navy Blue - - // --- SYNTAX --- - ,syntax_keyword: "hsl(20, 90%, 45%)" // Rust - ,syntax_string: "hsl(100, 35%, 35%)" // Ivy Green - ,syntax_func: "hsl(300, 30%, 40%)" // Muted Purple - ,syntax_comment: "hsl(35, 10%, 60%)" // Light Brown - }; - - // --- APPLY THEME --- - const palette = RT.config.theme; - const body = document.body; - const html = document.documentElement; - - html.style.backgroundColor = palette.surface_0; - body.style.backgroundColor = palette.surface_0; - body.style.color = palette.content_main; - - const s = body.style; - for (const [key, value] of Object.entries(palette)) { - s.setProperty(`--rt-${key.replace(/_/g, '-')}`, value); - } - }; -} )(); diff --git a/developer/authored/RT/theme/light_gold.js b/developer/authored/RT/theme/light_gold.js deleted file mode 100644 index 3136934..0000000 --- a/developer/authored/RT/theme/light_gold.js +++ /dev/null @@ -1,103 +0,0 @@ -/* - Theme: Golden Wheat (Light) - "Spanish Gold Edition" - File: style/theme-light-gold.js - Standard: Theme 1.0 - Description: Light Parchment background with Oxblood Red ink. -*/ -( function(){ - const RT = window.RT = window.RT || {}; - - RT.theme = function(){ - RT.config = RT.config || {}; - - RT.config.theme = { - meta_is_dark: false - ,meta_name: "Golden Wheat (Yellow)" - - // --- SURFACES (Light Parchment) --- - // Shifted lightness up to 94% for a "whiter" feel that still holds the yellow tint. - ,surface_0: "hsl(48, 50%, 94%)" // Main Page: Fine Parchment - ,surface_1: "hsl(48, 40%, 90%)" // Panels: Slightly darker - ,surface_2: "hsl(48, 30%, 97%)" // Cards: Very light - ,surface_3: "hsl(0, 0%, 100%)" // Popups - ,surface_input: "hsl(48, 20%, 96%)" - ,surface_code: "hsl(48, 25%, 88%)" // Distinct Code BG - ,surface_select: "hsl(10, 70%, 85%)" // Red Highlight - - // --- CONTENT (Deep Ink) --- - ,content_main: "hsl(10, 25%, 7%)" // Deep Warm Black (Ink) - ,content_muted: "hsl(10, 15%, 35%)" // Dark Grey-Red - ,content_subtle: "hsl(10, 10%, 55%)" - ,content_inverse: "hsl(48, 50%, 90%)" - - // --- BRAND & ACTION (The Red Spectrum) --- - ,brand_primary: "hsl(12, 85%, 30%)" // H1 (Deep Oxblood) - ,brand_secondary: "hsl(10, 80%, 35%)" // H2 (Garnet) - ,brand_tertiary: "hsl(8, 70%, 40%)" // H3 (Brick) - ,brand_link: "hsl(12, 90%, 35%)" // Link - - // --- BORDERS --- - ,border_faint: "hsl(45, 30%, 80%)" - ,border_default: "hsl(45, 30%, 70%)" // Pencil Grey - ,border_strong: "hsl(12, 50%, 40%)" - - // --- STATE --- - ,state_success: "hsl(120, 40%, 30%)" - ,state_warning: "hsl(25, 90%, 45%)" - ,state_error: "hsl(0, 75%, 35%)" - ,state_info: "hsl(210, 60%, 40%)" - - // --- SYNTAX --- - ,syntax_keyword: "hsl(0, 75%, 35%)" - ,syntax_string: "hsl(100, 35%, 25%)" - ,syntax_func: "hsl(15, 85%, 35%)" - ,syntax_comment: "hsl(45, 20%, 50%)" - }; - - // --- APPLY THEME --- - const palette = RT.config.theme; - const body = document.body; - const html = document.documentElement; - - html.style.backgroundColor = palette.surface_0; - body.style.backgroundColor = palette.surface_0; - body.style.color = palette.content_main; - - const s = body.style; - for (const [key, value] of Object.entries(palette)) { - s.setProperty(`--rt-${key.replace(/_/g, '-')}`, value); - } - - // Global overrides - const style_id = 'rt-global-overrides'; - if (!document.getElementById(style_id)) { - const style = document.createElement('style'); - style.id = style_id; - style.textContent = ` - ::selection { background: var(--rt-surface-select); color: var(--rt-brand-primary); } - ::-moz-selection { background: var(--rt-surface-select); color: var(--rt-brand-primary); } - - ::-webkit-scrollbar { width: 12px; } - ::-webkit-scrollbar-track { background: var(--rt-surface-0); } - ::-webkit-scrollbar-thumb { - background: var(--rt-border-default); - border: 2px solid var(--rt-surface-0); - border-radius: 8px; - } - ::-webkit-scrollbar-thumb:hover { background: var(--rt-brand-secondary); } - - rt-article p, rt-article li { - text-shadow: 0px 0px 0.5px rgba(0,0,0, 0.2); - } - - .MathJax, .MathJax_Display, .mjx-chtml { - color: var(--rt-content-main) !important; - fill: var(--rt-content-main) !important; - stroke: var(--rt-content-main) !important; - } - `; - document.head.appendChild(style); - } - }; - -} )(); diff --git a/developer/authored/RT/tool/to_pdf.py b/developer/authored/RT/tool/to_pdf.py deleted file mode 100644 index 177f7bd..0000000 --- a/developer/authored/RT/tool/to_pdf.py +++ /dev/null @@ -1,167 +0,0 @@ -import os -import glob -import base64 -import re -from weasyprint import HTML - -# Find the image file -img_path = None -for search_dir in ['/mnt/data', '/tmp', '.']: - for root, dirs, files in os.walk(search_dir): - if 'money_circle.jpeg' in files: - img_path = os.path.join(root, 'money_circle.jpeg') - break - if img_path: - break - -img_b64 = "" -if img_path: - with open(img_path, "rb") as f: - img_b64 = base64.b64encode(f.read()).decode('utf-8') - -html_content = """ - - - - - On Cybersecurity and Commonsense - - - - -""" - -# String replacements (hyphens, 'may', 'just') -html_content = html_content.replace('—', '-') -html_content = re.sub(r'\bmay\b', 'can', html_content) -html_content = re.sub(r'\bMay\b', 'Can', html_content) -html_content = re.sub(r'\bjust\b', 'merely', html_content) -html_content = re.sub(r'\bJust\b', 'Merely', html_content) - -# Title block replacement -title_match = re.search(r'\s*', html_content, re.IGNORECASE | re.DOTALL) -if title_match: - title, author, date, copyright_text = title_match.groups() - if not copyright_text.startswith('©') and not copyright_text.startswith('©'): - copyright_text = f"© {copyright_text}" - - title_html = f''' -
          -

          {title}

          -

          {author}

          -

          {date}

          - -
          - ''' - html_content = html_content[:title_match.start()] + title_html + html_content[title_match.end():] - -# TOC replacement -headings = re.findall(r'(.*?)', html_content, re.IGNORECASE) -toc_html = '

          Table of Contents

            ' -for idx, (level, _, id_val, text) in enumerate(headings): - if not id_val: - id_val = f"heading-{idx}" - html_content = re.sub(f'{text}', f'{text}', html_content, count=1) - toc_html += f'
          • {text}
          • ' -toc_html += '
          ' - -html_content = re.sub(r']*>', toc_html, html_content, flags=re.IGNORECASE) - -# Image replacement -if img_b64: - html_content = re.sub(r'src="money_circle\.jpeg"', f'src="data:image/jpeg;base64,{img_b64}" class="content-image"', html_content) - -# Custom tags -html_content = re.sub(r'', '
          ', html_content, flags=re.IGNORECASE) -html_content = re.sub(r'', '
          ', html_content, flags=re.IGNORECASE) -html_content = re.sub(r'', '', html_content, flags=re.IGNORECASE) -html_content = re.sub(r'', '', html_content, flags=re.IGNORECASE) -html_content = re.sub(r'', '', html_content, flags=re.IGNORECASE) -html_content = re.sub(r'', '', html_content, flags=re.IGNORECASE) -html_content = re.sub(r'', '', html_content, flags=re.IGNORECASE) -html_content = re.sub(r'', '', html_content, flags=re.IGNORECASE) - -def replace_rt_math(m): - content = m.group(1) - if '\n' in content: - return f'
          {content}
          ' - return f'{content}' - -def replace_rt_code(m): - content = m.group(1) - if '\n' in content: - return f'
          {content}
          ' - return f'{content}' - -html_content = re.sub(r'(.*?)', replace_rt_math, html_content, flags=re.IGNORECASE | re.DOTALL) -html_content = re.sub(r'(.*?)', replace_rt_code, html_content, flags=re.IGNORECASE | re.DOTALL) - -css_styles = """ - @page { - size: letter; - margin: 25mm 20mm; - background-color: #FAFAFA; - @bottom-center { - content: counter(page); - font-family: 'Georgia', serif; - font-size: 10pt; - color: #555; - } - } - body { - margin: 0; - padding: 0; - font-family: 'Georgia', serif; - font-size: 11pt; - line-height: 1.6; - color: #2c3e50; - background-color: #FAFAFA; - } - *, *::before, *::after { box-sizing: border-box; } - - h1, h2, h3, h4 { - font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; - color: #1A365D; - page-break-after: avoid; - } - h1 { font-size: 20pt; margin-top: 1.5em; margin-bottom: 0.5em; border-bottom: 2px solid #E2E8F0; padding-bottom: 0.2em; } - h2 { font-size: 16pt; margin-top: 1.5em; margin-bottom: 0.5em; } - p { margin-bottom: 1em; text-align: justify; } - ul, ol { margin-bottom: 1em; padding-left: 2em; } - li { margin-bottom: 0.5em; } - - .title-block { text-align: center; margin-bottom: 4em; padding: 2em 0; border-bottom: 3px solid #1A365D; } - .title-block h1 { font-size: 26pt; border: none; margin-top: 0; margin-bottom: 0.5em; color: #0F2040; } - .title-block .meta-author { font-size: 14pt; font-weight: bold; margin: 0.2em 0; } - .title-block .meta-date { font-size: 12pt; color: #555; font-style: italic; margin: 0.2em 0; } - .title-block .meta-copyright { font-size: 10pt; color: #777; margin-top: 1em; } - - .toc-block { background-color: #F0F4F8; padding: 20px; border-radius: 5px; margin-bottom: 3em; page-break-after: always; } - .toc-block h2 { margin-top: 0; border: none; } - .toc-block ul { list-style-type: none; padding-left: 0; } - .toc-h1 { font-weight: bold; margin-top: 0.8em; } - .toc-h2 { padding-left: 1.5em; font-size: 0.95em; } - .toc-block a { text-decoration: none; color: #2c3e50; } - - .rt-term { font-weight: bold; color: #2980B9; } - .rt-term-em { font-weight: bold; font-style: italic; color: #2980B9; } - .rt-neologism { font-variant: small-caps; font-weight: bold; color: #C0392B; } - .rt-code-inline { font-family: 'Courier New', Courier, monospace; background-color: #EAECEE; padding: 2px 4px; border-radius: 3px; font-size: 0.9em; } - .rt-code-block { font-family: 'Courier New', Courier, monospace; background-color: #F4F6F7; padding: 15px; border-left: 4px solid #7F8C8D; border-radius: 3px; font-size: 0.9em; overflow-x: auto; white-space: pre-wrap; } - - .math { font-family: 'Times New Roman', serif; font-style: italic; font-weight: bold; color: #2C3E50; } - .math-block { text-align: center; margin: 1.5em 0; font-size: 1.2em; background-color: #F9EBEA; padding: 10px; border-radius: 5px; } - .math-inline { font-size: 1.05em; } - - table { width: 100%; border-collapse: collapse; margin: 2em 0; } - th, td { padding: 10px; text-align: left; vertical-align: top; } - th { background-color: #1A365D; color: white; font-weight: bold; } - tr { border-bottom: 1px solid #ddd; } - hr { border: 0; border-top: 1px solid #eee; } - - .content-image { display: block; max-width: 90%; margin: 2em auto; border: 1px solid #ccc; box-shadow: 0 4px 8px rgba(0,0,0,0.1); } -""" - -final_html = f"{html_content}" -HTML(string=final_html).write_pdf("White_Paper_Cybersecurity_Legislation.pdf") -print("Success") diff --git a/developer/authored/RT/tool/to_pdf2.py b/developer/authored/RT/tool/to_pdf2.py deleted file mode 100644 index a493d27..0000000 --- a/developer/authored/RT/tool/to_pdf2.py +++ /dev/null @@ -1,479 +0,0 @@ -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.") diff --git a/developer/document/RT-code-format-Lisp.html b/developer/document/RT-code-format-Lisp.html index edbed6b..888e5fe 100644 --- a/developer/document/RT-code-format-Lisp.html +++ b/developer/document/RT-code-format-Lisp.html @@ -3,10 +3,16 @@ RT Code Format: Lisp Addendum - + diff --git a/developer/document/RT-code-format.html b/developer/document/RT-code-format.html index 8260a9f..e4924fa 100644 --- a/developer/document/RT-code-format.html +++ b/developer/document/RT-code-format.html @@ -3,10 +3,16 @@ RT code format conventions - + diff --git a/developer/document/naming_file-and-directory.html b/developer/document/naming_file-and-directory.html index c4bd65c..7fb7619 100644 --- a/developer/document/naming_file-and-directory.html +++ b/developer/document/naming_file-and-directory.html @@ -3,10 +3,16 @@ File and directory naming conventions - + diff --git a/developer/document/setup.js b/developer/document/setup.js deleted file mode 100644 index 77ec522..0000000 --- a/developer/document/setup.js +++ /dev/null @@ -1,4 +0,0 @@ -window.RT_REPO_ROOT = "../../"; -document.write(''); -document.write(''); -document.write(''); diff --git a/developer/document/single-file_C-module-and-namespace.html b/developer/document/single-file_C-module-and-namespace.html index 23af5f8..930f028 100644 --- a/developer/document/single-file_C-module-and-namespace.html +++ b/developer/document/single-file_C-module-and-namespace.html @@ -3,10 +3,16 @@ C modules, namespaces, and the build lifecycle - + diff --git a/developer/made/.gitkeep b/developer/made/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/developer/tool/.gitkeep b/developer/tool/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/developer/tool/build b/developer/tool/build new file mode 100755 index 0000000..547fc4c --- /dev/null +++ b/developer/tool/build @@ -0,0 +1,123 @@ +#!/usr/bin/env python3 +# -*- mode: python; coding: utf-8; python-indent-offset: 2; indent-tabs-mode: nil -*- +""" +developer/tool/build - Build Orchestrator Wrapper + +This script acts as the primary entry point for staging the project. +It parses colon-separated arguments mapping specific namespaces to their +intended build arguments. + +It enforces the structural convention where authored directories must +be named .. The script delegates execution to +developer/tool/build_component/. +""" + +import sys, os, subprocess, fnmatch +from typing import Dict, Tuple + +def check_environment() -> None: + setup_must_be = "developer/tool/setup" + current_setup = os.environ.get("SETUP", "") + if current_setup != setup_must_be: + print(f"developer/tool/build:: error: must be run in the {setup_must_be} environment", file=sys.stderr) + sys.exit(1) + +def get_namespaces() -> Dict[str, Tuple[str, str]]: + authored_dir = os.path.join(os.environ.get("REPO_HOME", "."), "developer", "authored") + if not os.path.isdir(authored_dir): + return {} + + namespaces = {} + for TM_item in os.listdir(authored_dir): + path = os.path.join(authored_dir, TM_item) + if os.path.isdir(path) and not TM_item.startswith("."): + parts = TM_item.rsplit(".", 1) + if len(parts) == 2: + ns = parts[0] + tool = parts[1] + namespaces[ns] = (tool, TM_item) + else: + print(f"(warning) Ignoring '{TM_item}': directory lacks the required . suffix.", file=sys.stderr) + + return dict(sorted(namespaces.items())) + +def print_usage(namespaces: Dict[str, Tuple[str, str]]) -> None: + print("Usage: build [[:]*]*\n") + print("Arguments are passed directly to the component specified by the directory suffix.\n") + + print("Available namespaces:") + if namespaces: + for TM_ns, (TM_tool, TM_raw_dir) in namespaces.items(): + print(f" {TM_ns:<20} (Component: {TM_tool}, Dir: {TM_raw_dir})") + else: + print(" (No conforming namespaces currently found in authored/)") + + print("\nExamples:") + print(" build (Displays this usage message)") + print(" build ExampleGreet (Executes 'all' via its assigned component)") + print(" build Ex*:library RT:all:information (Batch execution with pattern matching)") + print(" build \"*:clean\" (Cleans all namespaces. Quotes prevent Bash expansion)") + +def run_build(argument: str, namespace: str, tool: str, raw_dir: str) -> None: + tool_path = os.path.join("tool", "build_component", tool) + + if not os.path.isfile(tool_path) or not os.access(tool_path, os.X_OK): + print(f"error: Build component '{tool}' for namespace '{namespace}' is missing or not executable at {tool_path}", file=sys.stderr) + sys.exit(1) + + env = os.environ.copy() + env["NAMESPACE"] = namespace + env["NAMESPACE_DIR"] = raw_dir + + tool_cmd = [tool_path, argument] + + try: + subprocess.run(tool_cmd, env=env, check=True) + except subprocess.CalledProcessError as e: + print(f"Build component '{tool}' failed for namespace '{namespace}' with exit code {e.returncode}", file=sys.stderr) + sys.exit(e.returncode) + +def CLI() -> None: + check_environment() + + repo_home = os.environ.get("REPO_HOME", ".") + dev_dir = os.path.join(repo_home, "developer") + os.chdir(dev_dir) + + args = sys.argv[1:] + namespaces = get_namespaces() + + if not args or args[0] in ["usage", "help", "-h", "--help"]: + print_usage(namespaces) + sys.exit(0) + + matched_any = False + ns_keys = list(namespaces.keys()) + + for TM_arg in args: + parts = TM_arg.split(":") + pattern = parts[0] + arguments = parts[1:] + + if not arguments: + arguments = ["all"] + + matches = fnmatch.filter(ns_keys, pattern) + + if not matches: + print(f"(warning) Pattern '{pattern}' matched no namespaces.", file=sys.stderr) + continue + + matched_any = True + for TM_ns in matches: + tool, raw_dir = namespaces[TM_ns] + for TM_argument in arguments: + run_build(TM_argument, TM_ns, tool, raw_dir) + + if not matched_any: + sys.exit(1) + + print("build done.") + +if __name__ == "__main__": + CLI() diff --git a/developer/tool/build_component/copy b/developer/tool/build_component/copy new file mode 100755 index 0000000..f4bbd5a --- /dev/null +++ b/developer/tool/build_component/copy @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# developer/tool/copy + +set -euo pipefail +CMD="${1:-all}" + +if [ "$CMD" = "clean" ]; then + rm -rf "scratchpad/made/$NAMESPACE" + echo "copy: Cleaned scratchpad/made/$NAMESPACE" +elif [ "$CMD" = "all" ]; then + mkdir -p "scratchpad/made" + cp -au "authored/$NAMESPACE_DIR" "scratchpad/made/$NAMESPACE" + echo "copy: Staged $NAMESPACE_DIR -> scratchpad/made/$NAMESPACE" +else + echo "copy: Unrecognized command '$CMD'" + exit 1 +fi diff --git a/developer/tool/build_component/make b/developer/tool/build_component/make new file mode 100755 index 0000000..30fb82d --- /dev/null +++ b/developer/tool/build_component/make @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# developer/tool/build_component/make + +set -euo pipefail +CMD="${1:-all}" + +# The GNU Make orchestrator expects C_SOURCE_DIR to point to the raw directory +export C_SOURCE_DIR="authored/$NAMESPACE_DIR" +export KMOD_SOURCE_DIR="authored/$NAMESPACE_DIR" + +# Isolate build products into their specific namespace directory +export LIBRARY_DIR="scratchpad/made/$NAMESPACE" +export MACHINE_DIR="scratchpad/made/$NAMESPACE" + +/bin/make -f tool/build_component/makefile "$CMD" diff --git a/developer/tool/build_component/makefile b/developer/tool/build_component/makefile new file mode 100644 index 0000000..7914c0b --- /dev/null +++ b/developer/tool/build_component/makefile @@ -0,0 +1,55 @@ +# developer/tool/build_component/makefile +.SUFFIXES: +.EXPORT_ALL_VARIABLES: + +RT_MAKEFILE_DP := $(REPO_HOME)/shared/tool/makefile + +.PHONY: usage +usage: + @printf "Usage: make [usage|version|information|all|lib|CLI|kmod|clean]\n" + +.PHONY: version +version: + @printf "local ----------------------------------------\n" + @echo tool/makefile version 2.0 + @printf "Harmony.mk ----------------------------------------\n" + @$(MAKE) -f $(RT_MAKEFILE_DP)/Harmony.mk version + @printf "target_kernel-module.mk ----------------------------------------\n" + @$(MAKE) -f $(RT_MAKEFILE_DP)/target_kernel-module.mk version + +.PHONY: information +information: + @printf "local ----------------------------------------\n" + -@echo CURDIR='$(CURDIR)' + @echo REPO_HOME="$(REPO_HOME)" + @echo NAMESPACE="$(NAMESPACE)" + @echo C_SOURCE_DIR="$(C_SOURCE_DIR)" + @echo KMOD_BUILD_DIR="/lib/modules/$(shell uname -r)/build" + @echo CURDIR="$(CURDIR)" + @printf "Harmony.mk ----------------------------------------\n" + @$(MAKE) -f $(RT_MAKEFILE_DP)/Harmony.mk information + @printf "target_kernel-module.mk ----------------------------------------\n" + @$(MAKE) -f $(RT_MAKEFILE_DP)/target_kernel-module.mk information + +.PHONY: all +all: library CLI kmod + +.PHONY: library lib +library lib: + @$(MAKE) -f $(RT_MAKEFILE_DP)/Harmony.mk library + +.PHONY: CLI +CLI: + @$(MAKE) -f $(RT_MAKEFILE_DP)/Harmony.mk CLI + +.PHONY: kmod +kmod: + @$(MAKE) -f $(RT_MAKEFILE_DP)/target_kernel-module.mk kmod + +.PHONY: clean +clean: + @printf "local ----------------------------------------\n" + @printf "Harmony.mk ----------------------------------------\n" + @$(MAKE) -f $(RT_MAKEFILE_DP)/Harmony.mk clean + @printf "target_kernel-module.mk ----------------------------------------\n" + @$(MAKE) -f $(RT_MAKEFILE_DP)/target_kernel-module.mk clean diff --git a/developer/tool/do-all b/developer/tool/do-all deleted file mode 100755 index 2350fd8..0000000 --- a/developer/tool/do-all +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash -script_afp=$(realpath "${BASH_SOURCE[0]}") - -# input guards - - setup_must_be="developer/tool/setup" - if [ "$SETUP" != "$setup_must_be" ]; then - echo "$(script_fp):: error: must be run in the $setup_must_be environment" - exit 1 - fi - -set -e -set -x - - cd "$REPO_HOME"/developer || exit 1 - # /bin/make -f tool/makefile $@ - - scratchpad clear - make - release clean - release write - -set +x -echo "$(script_fn) done." diff --git a/developer/tool/do_all b/developer/tool/do_all deleted file mode 100755 index 2350fd8..0000000 --- a/developer/tool/do_all +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash -script_afp=$(realpath "${BASH_SOURCE[0]}") - -# input guards - - setup_must_be="developer/tool/setup" - if [ "$SETUP" != "$setup_must_be" ]; then - echo "$(script_fp):: error: must be run in the $setup_must_be environment" - exit 1 - fi - -set -e -set -x - - cd "$REPO_HOME"/developer || exit 1 - # /bin/make -f tool/makefile $@ - - scratchpad clear - make - release clean - release write - -set +x -echo "$(script_fn) done." diff --git a/developer/tool/make b/developer/tool/make deleted file mode 100755 index b7e181b..0000000 --- a/developer/tool/make +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/env python3 -# -*- mode: python; coding: utf-8; python-indent-offset: 2; indent-tabs-mode: nil -*- -""" -developer/tool/make - Build Orchestrator Wrapper - -This script acts as the primary entry point for compiling the project. -It parses colon-separated arguments mapping specific namespace patterns -(including file globs) to their intended build commands. - -A program developer can modify this script to add custom pre-build checks, -custom argument parsing, or project-specific routing logic. -""" - -import sys ,os ,subprocess ,fnmatch -from typing import List - -def check_environment() -> None: - setup_must_be = "developer/tool/setup" - current_setup = os.environ.get("SETUP" ,"") - if( current_setup != setup_must_be ): - print(f"developer/tool/make:: error: must be run in the {setup_must_be} environment" ,file=sys.stderr) - sys.exit(1) - -def get_namespaces() -> List[str]: - authored_dir = os.path.join(os.environ.get("REPO_HOME" ,".") ,"developer" ,"authored") - if( not os.path.isdir(authored_dir) ): - return [] - - namespaces = [] - for TM_name in os.listdir(authored_dir): - path = os.path.join(authored_dir ,TM_name) - if( os.path.isdir(path) and not TM_name.startswith(".") ): - namespaces.append(TM_name) - namespaces.sort() - return namespaces - -def print_usage() -> None: - print("Usage: make [[:]*]*\n") - print("Commands:") - print(" all Build library, CLI, and kmod (Default)") - print(" library Build only the library archives") - print(" CLI Build only the CLI executables") - print(" kmod Build kernel modules") - print(" clean Remove build artifacts") - print(" information Display build environment variables\n") - - print("Available namespaces:") - namespaces = get_namespaces() - if( namespaces ): - for TM_ns in namespaces: - print(f" {TM_ns}") - else: - print(" (No namespaces currently found in authored/)") - - print("\nExamples:") - print(" make (Displays this usage message)") - print(" make ExampleGreet (Builds 'all' for ExampleGreet)") - print(" make Ex*:library G*:all:information (Builds 'library' for Ex*, 'all' and 'information' for G*)") - print(" make \"*:clean\" (Cleans all namespaces. Quotes prevent Bash expansion)") - -def run_make(cmd: str ,namespace: str) -> None: - env = os.environ.copy() - env["NAMESPACE"] = namespace - - make_cmd = ["/bin/make" ,"-f" ,"tool/makefile" ,cmd] - - try: - subprocess.run(make_cmd ,env=env ,check=True) - except subprocess.CalledProcessError as e: - print(f"make failed for namespace '{namespace}' with exit code {e.returncode}" ,file=sys.stderr) - sys.exit(e.returncode) - -def CLI() -> None: - check_environment() - - repo_home = os.environ.get("REPO_HOME" ,".") - dev_dir = os.path.join(repo_home ,"developer") - os.chdir(dev_dir) - - args = sys.argv[1:] - - if( not args or args[0] in ["usage" ,"help" ,"-h" ,"--help"] ): - print_usage() - sys.exit(0) - - namespaces = get_namespaces() - matched_any = False - - for TM_arg in args: - parts = TM_arg.split(":") - pattern = parts[0] - commands = parts[1:] - - if( not commands ): - commands = ["all"] - - matches = fnmatch.filter(namespaces ,pattern) - - if( not matches ): - print(f"(warning) Pattern '{pattern}' matched no namespaces." ,file=sys.stderr) - continue - - matched_any = True - for TM_ns in matches: - for TM_cmd in commands: - run_make(TM_cmd ,TM_ns) - - if( not matched_any ): - sys.exit(1) - - print("make done.") - -if __name__ == "__main__": - CLI() diff --git a/developer/tool/makefile b/developer/tool/makefile deleted file mode 100644 index 070c6ca..0000000 --- a/developer/tool/makefile +++ /dev/null @@ -1,61 +0,0 @@ -# developer/tool/makefile - Orchestrator (Hybrid) -.SUFFIXES: -.EXPORT_ALL_VARIABLES: - -RT_MAKEFILE_DP := $(REPO_HOME)/shared/tool/makefile - -# If a namespace is provided, update the source directory -ifneq ($(NAMESPACE),) - C_SOURCE_DIR := authored/$(NAMESPACE) - export C_SOURCE_DIR -endif - -.PHONY: usage -usage: - @printf "Usage: make [usage|version|information|all|lib|CLI|kmod|clean]\n" - -.PHONY: version -version: - @printf "local ----------------------------------------\n" - @echo tool/makefile version 2.0 - @printf "Harmony.mk ----------------------------------------\n" - @$(MAKE) -f $(RT_MAKEFILE_DP)/Harmony.mk version - @printf "target_kernel-module.mk ----------------------------------------\n" - @$(MAKE) -f $(RT_MAKEFILE_DP)/target_kernel-module.mk version - -.PHONY: information -information: - @printf "local ----------------------------------------\n" - -@echo CURDIR='$(CURDIR)' - @echo REPO_HOME="$(REPO_HOME)" - @echo NAMESPACE="$(NAMESPACE)" - @echo C_SOURCE_DIR="$(C_SOURCE_DIR)" - @echo KMOD_BUILD_DIR="/lib/modules/$(shell uname -r)/build" - @echo CURDIR="$(CURDIR)" - @printf "Harmony.mk ----------------------------------------\n" - @$(MAKE) -f $(RT_MAKEFILE_DP)/Harmony.mk information - @printf "target_kernel-module.mk ----------------------------------------\n" - @$(MAKE) -f $(RT_MAKEFILE_DP)/target_kernel-module.mk information - -.PHONY: all -all: library CLI kmod - -.PHONY: library lib -library lib: - @$(MAKE) -f $(RT_MAKEFILE_DP)/Harmony.mk library - -.PHONY: CLI -CLI: - @$(MAKE) -f $(RT_MAKEFILE_DP)/Harmony.mk CLI - -.PHONY: kmod -kmod: - @$(MAKE) -f $(RT_MAKEFILE_DP)/target_kernel-module.mk kmod - -.PHONY: clean -clean: - @printf "local ----------------------------------------\n" - @printf "Harmony.mk ----------------------------------------\n" - @$(MAKE) -f $(RT_MAKEFILE_DP)/Harmony.mk clean - @printf "target_kernel-module.mk ----------------------------------------\n" - @$(MAKE) -f $(RT_MAKEFILE_DP)/target_kernel-module.mk clean diff --git a/document/.gitkeep b/document/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/document/RT-semantic-HTML-tags.html b/document/RT-semantic-HTML-tags.html index defa81a..73d479a 100644 --- a/document/RT-semantic-HTML-tags.html +++ b/document/RT-semantic-HTML-tags.html @@ -3,10 +3,16 @@ RT semantic HTML tags - + diff --git a/document/install_standalone.md b/document/install_standalone.md index 26586b0..95e0ccf 100644 --- a/document/install_standalone.md +++ b/document/install_standalone.md @@ -1,12 +1,12 @@ -The `Harmony` skeletong is setup to use `RT-style-JS_public`, it only requires that the `RT-style-JS_public` be installed to the side, at the same directory level, as the `Harmony` project. +The `Harmony` skeletong is setup to use `RT-style`, it only requires that the `RT-style` be installed to the side, at the same directory level, as the `Harmony` project. -`RT-style-JS_public` can be used with a standalone html document +`RT-style` can be used with a standalone html document 1. cd to the directory with the standalone document -2. install RT-style-JS_public - 1.1 git clone https://github.com/Thomas-Walker-Lynch/RT-style-JS_public.git - 1.2 enter RT-style-JS: +2. install RT-style + 1.1 git clone https://github.com/Thomas-Walker-Lynch/RT-style.git + 1.2 enter RT-style: > bash > . setup developer > make @@ -21,15 +21,15 @@ The `Harmony` skeletong is setup to use `RT-style-JS_public`, it only requires t window.RT_REPO_ROOT = "../"; document.write(''); - document.write(''); - document.write(''); + document.write(''); + document.write(''); -------------------------------------------------------------------------------- dictionary_style-directory.js 2026-05-20T06:49:14Z window.StyleRT_namespaces = { - "RT": "RT-style-JS_public/consumer/release/RT" + "RT": "RT-style/consumer/release/RT" ,"Project": "style" }; diff --git a/document/introduction_Harmony.html b/document/introduction_Harmony.html index 7d35941..b1d89d0 100644 --- a/document/introduction_Harmony.html +++ b/document/introduction_Harmony.html @@ -3,10 +3,16 @@ Introduction to Harmony - + @@ -262,7 +268,7 @@

          - Currently, our developers write documents directly in HTML using the RT semantic tags. See the RT-style-JS_public project and the documentation there. A common approach is to copy another document and the setup.js file, then to type over the top of that other document. Only one setup.js file is used per directory. Be sure to edit the relative root path found at the top of setup.js. Plain text, emacs org, and mark down have all been used in prior versions of Harmony. + Currently, our developers write documents directly in HTML using the RT semantic tags. See the RT-style project and the documentation there. A common approach is to copy another document and the setup.js file, then to type over the top of that other document. Only one setup.js file is used per directory. Be sure to edit the relative root path found at the top of setup.js. Plain text, emacs org, and mark down have all been used in prior versions of Harmony.

          Untracked directories

          @@ -348,7 +354,7 @@ │ ├── made │ ├── dictionary_style-directory.js │ ├── third_party - │ │ ├── RT-style-JS_public -> ../../../RT-style-JS_public/ + │ │ ├── RT-style -> ../../../RT-style/ │ │ └── upstream │ └── tool │ ├── scratchpad diff --git a/document/role-and-workflow_product-development.html b/document/role-and-workflow_product-development.html index 149624b..e3e55d6 100644 --- a/document/role-and-workflow_product-development.html +++ b/document/role-and-workflow_product-development.html @@ -3,10 +3,16 @@ Product development roles and workflow - + diff --git a/document/role-and-workflow_product-maintenance.html b/document/role-and-workflow_product-maintenance.html index 6063077..3a97e1b 100644 --- a/document/role-and-workflow_product-maintenance.html +++ b/document/role-and-workflow_product-maintenance.html @@ -3,10 +3,16 @@ Product maintenance roles and workflow - + diff --git a/document/setup.js b/document/setup.js deleted file mode 100644 index 65d8522..0000000 --- a/document/setup.js +++ /dev/null @@ -1,4 +0,0 @@ -window.RT_REPO_ROOT = "../"; -document.write(''); -document.write(''); -document.write(''); diff --git a/document/style/rt_dark_doc.css b/document/style/rt_dark_doc.css deleted file mode 100644 index bac4fbf..0000000 --- a/document/style/rt_dark_doc.css +++ /dev/null @@ -1,44 +0,0 @@ - - body { - font-family: 'Noto Sans JP', Arial, sans-serif; - background-color: hsl(0, 0%, 0%); - color: hsl(42, 100%, 80%); - padding: 2rem; - } - .page { - padding: 3rem; - margin: 1.25rem auto; - max-width: 46.875rem; - background-color: hsl(0, 0%, 0%); - box-shadow: 0 0 0.625rem hsl(42, 100%, 50%); - } - h1 { - font-size: 1.5rem; - text-align: center; - color: hsl(42, 100%, 84%); - text-transform: uppercase; - margin-top: 1.5rem; - } - h2 { - font-size: 1.25rem; - color: hsl(42, 100%, 84%); - text-align: center; - margin-top: 2rem; - } - h3 { - font-size: 1.125rem; - color: hsl(42, 100%, 75%); - margin-top: 1.5rem; - } - p, li { - color: hsl(42, 100%, 90%); - text-align: justify; - margin-bottom: 1rem; - } - code { - font-family: 'Courier New', Courier, monospace; - background-color: hsl(0, 0%, 25%); - padding: 0.125rem 0.25rem; - color: hsl(42, 100%, 90%); - } - diff --git a/setup b/setup index 7603f3e..a249e2e 100644 --- a/setup +++ b/setup @@ -44,8 +44,10 @@ fi # setup the role # export ROLE="${1}" + export ROLE_HOME="$REPO_HOME/$ROLE" + echo ROLE_HOME "$ROLE_HOME" - tool="${REPO_HOME}/${ROLE}/tool" + tool="${ROLE_HOME}/tool" if [[ ":${PATH}:" != *":${tool}:"* ]]; then export PATH="${tool}:${PATH}" fi diff --git a/shared/document/setup.js b/shared/document/setup.js deleted file mode 100644 index de1173d..0000000 --- a/shared/document/setup.js +++ /dev/null @@ -1,4 +0,0 @@ -window.RT_REPO_ROOT = "../../"; -document.write(''); -document.write(''); -document.write(''); diff --git a/shared/tool/link-RT b/shared/tool/link-RT index 0e15005..dbaccf1 100755 --- a/shared/tool/link-RT +++ b/shared/tool/link-RT @@ -13,7 +13,7 @@ def run(): repo_home = Path(repo_home_env) # Define the canonical target location - target_src = repo_home / 'shared' / 'linked-project' / 'RT-style-JS_public' / 'consumer' / 'release' / 'RT' + target_src = repo_home / 'shared' / 'linked-project' / 'RT-style' / 'consumer' / 'release' / 'RT' # Determine the destination directory if len(sys.argv) > 1: diff --git a/shared/tool/setup b/shared/tool/setup index 6cfc738..76983e7 100644 --- a/shared/tool/setup +++ b/shared/tool/setup @@ -77,41 +77,6 @@ umask 0077 export PATH -#-------------------------------------------------------------------------------- -# used by release scripts -# - install_file() { - if [ "$#" -lt 3 ]; then - echo "env::install_file usage: install_file ... " - return 1 - fi - - perms="${@: -1}" # Last argument is permissions - target_dp="${@: -2:1}" # Second-to-last argument is the target directory - sources=("${@:1:$#-2}") # All other arguments are source files - - if [ ! -d "$target_dp" ]; then - echo "env::install_file no install done: target directory '$target_dp' does not exist." - return 1 - fi - - for source_fp in "${sources[@]}"; do - if [ ! -f "$source_fp" ]; then - echo "env::install_file: source file '$source_fp' does not exist." - return 1 - fi - - target_file="$target_dp/$(basename "$source_fp")" - - if ! install -m "$perms" "$source_fp" "$target_file"; then - echo "env::install_file: Failed to install $(basename "$source_fp") to $target_dp" - return 1 - fi - done - } - - export -f install_file - # -------------------------------------------------------------------------------- # closing # diff --git a/shared/tool/version b/shared/tool/version index 91c6751..0ab04ad 100755 --- a/shared/tool/version +++ b/shared/tool/version @@ -1,4 +1,4 @@ -echo "RT-style-JS_public v3.1 2026-06-20 10:39:27 Z" +echo "RT-style v3.1 2026-06-20 10:39:27 Z" echo "Harmony v3.3 2026-06-21 13:20:18 Z"