From: Thomas Walker Lynch Date: Wed, 5 Aug 2026 14:38:43 +0000 (+0000) Subject: working on section refactoring X-Git-Url: https://git.reasoningtechnology.com/%27%20%20%20window.RT.dirpr_library%20%20%20%27/Hindu-Arabic%20number%20fig%201.png?a=commitdiff_plain;h=0f1964c75166e442df7b6dfe698b24e8c1cde24f;p=RT-Style working on section refactoring --- diff --git a/developer/authored/Manuscript.copy/Layout/counter.js b/developer/authored/Manuscript.copy/Layout/counter.js index 270fb7c..6a94ae2 100644 --- a/developer/authored/Manuscript.copy/Layout/counter.js +++ b/developer/authored/Manuscript.copy/Layout/counter.js @@ -4,14 +4,14 @@ Supports 'scoped' and 'milestone' modes. Includes DOM continuation suspension architecture. */ -(function() { +(function(){ - if (!RT) { - console.error("RT not defined - was RT-Manuscript_make run?"); + if(!RT){ + console.error("RT not defined. Was RT-Manuscript_make run?"); return; } - if (!RT.Element) { - console.error("RT.Element not defined - was the state_manager run?"); + if(!RT.Element){ + console.error("RT.Element not defined. Was the state_manager run?"); return; } @@ -21,292 +21,312 @@ RT.dict_serial = RT.dict_serial || {}; RT.serial_id_allocator = RT.serial_id_allocator || 1; - class Count { - constructor() { + class Count{ + constructor(){ this.status = 'empty'; this.list = null; + this.names = null; } - reset() { + reset(){ this.status = 'preamble'; this.list = [0]; + this.names = ['']; } - reset(list) { - if (Array.isArray(list)) { + reset_with_lists(list ,names){ + if(Array.isArray(list)){ const is_natural = list.every(val => Number.isInteger(val) && val >= 0); - if (is_natural) { + if(is_natural){ this.list = list.length > 0 ? [...list] : null; - } else { + this.names = Array.isArray(names) && names.length === this.list.length ? [...names] : new Array(this.list.length).fill(''); + }else{ console.error("RT-Manuscript Layout Error: Counter list must contain only natural numbers."); this.list = null; + this.names = null; } - } else { + }else{ this.list = null; + this.names = null; } } - read(...path) { - if (path.length === 0) return undefined; + read(...path){ + if(path.length === 0) return undefined; const key = path[0]; - if (key === 'list') { - if (this.status === 'empty') { + if(key === 'list'){ + if(this.status === 'empty'){ console.error("RT-Manuscript Layout Error: Attempted to read 'list' from an empty Count object."); return null; } - if (!this.list) return null; + if(!this.list) return null; - if (path[1] === 'short') { - return this.list.slice(0, -1); - } + if(path[1] === 'short') return this.list.slice(0 ,-1); return [...this.list]; } - - if (key === 'status') { - return this.status; + + if(key === 'name'){ + if(this.status === 'empty' || !this.names) return ''; + if(path[1] === 'short'){ + return this.names.length > 1 ? this.names[this.names.length - 2] : ''; + } + return this.names[this.names.length - 1] || ''; } + + if(key === 'status') return this.status; return undefined; } - write(key, value) { - if (key === 'status') { + write(key ,value){ + if(key === 'status'){ this.status = value; - } else if (key === 'list') { - if (Array.isArray(value)) { + }else if(key === 'list'){ + if(Array.isArray(value)){ const is_natural = value.every(val => Number.isInteger(val) && val >= 0); - if (is_natural) { + if(is_natural){ this.list = value.length > 0 ? [...value] : null; - } else { + }else{ console.error("RT-Manuscript Layout Error: Counter list must contain only natural numbers."); this.list = null; } - } else { + }else{ this.list = null; } - } else if (key === 'Count' || key === 'count') { + }else if(key === 'Count' || key === 'count'){ const source_count = value instanceof Count ? value : (value && value.count instanceof Count ? value.count : null); - if (source_count) { + if(source_count){ this.status = source_count.status; this.list = source_count.list ? [...source_count.list] : null; - } else { + }else{ console.error("RT-Manuscript Layout Error: Invalid object provided to write('Count')."); } } } - increment() { - if (this.status === 'empty') { + increment(){ + if(this.status === 'empty'){ console.error("RT-Manuscript Layout Error: Attempted to increment an empty Count object."); return; } - if (this.list && this.list.length > 0) { + if(this.list && this.list.length > 0){ this.list[this.list.length - 1] += 1; + this.names[this.names.length - 1] = ''; } } - push(val) { - if (this.status === 'empty') { + push(val){ + if(this.status === 'empty'){ console.error("RT-Manuscript Layout Error: Attempted to push to an empty Count object."); return; } - if (!this.list) { + if(!this.list){ this.list = []; + this.names = []; } this.list.push(val); + this.names.push(''); } - pop() { - if (this.status === 'empty') { + pop(){ + if(this.status === 'empty'){ console.error("RT-Manuscript Layout Error: Attempted to pop from an empty Count object."); return undefined; } - if (this.list && this.list.length > 0) { + if(this.list && this.list.length > 0){ const val = this.list.pop(); - if (this.list.length === 0) { - this.list = null; + this.names.pop(); + if(this.list.length === 0){ + this.list = null; + this.names = null; } return val; } return undefined; } - clone() { + set_name(name){ + if(this.names && this.names.length > 0){ + this.names[this.names.length - 1] = name; + } + } + + clone(){ const c = new Count(); c.status = this.status; c.list = this.list ? [...this.list] : null; + c.names = this.names ? [...this.names] : null; return c; } } - class CounterMachine { - constructor(config) { + class CounterMachine{ + constructor(config){ this.count = new Count(); this.style = ['NaturalNumber']; this.separator = '.'; this.separator_placement = 'embedded'; this.mode = 'scoped'; - if (config) { - this.write(config); - } + if(config) this.write(config); } - read(...path) { - if (path.length === 0) return undefined; + read(...path){ + if(path.length === 0) return undefined; - if (path[0] === 'count') { - if (path.length === 1) { - return this.count.clone(); - } + if(path[0] === 'count'){ + if(path.length === 1) return this.count.clone(); return this.count.read(...path.slice(1)); } + + if(path[0] === 'name'){ + const status = this.count.read('status'); + if(status === 'empty') return ''; + if(this.mode === 'scoped' && status === 'between') return this.count.read('name' ,'short'); + return this.count.read('name'); + } - return path.reduce((acc, key) => (acc && acc[key] !== undefined) ? acc[key] : undefined, this); + return path.reduce((acc ,key) => (acc && acc[key] !== undefined) ? acc[key] : undefined ,this); } - write(dict) { - for (const [key, value] of Object.entries(dict)) { - if (key === 'style') { + write(dict){ + for(const [key ,value] of Object.entries(dict)){ + if(key === 'style'){ let parsed = Array.isArray(value) ? value : [value]; - if (parsed.length === 1 && parsed[0] === 'outline') { - parsed = ['Roman', 'Alpha', 'roman', 'alpha', 'CountingNumber']; + if(parsed.length === 1 && parsed[0] === 'outline'){ + parsed = ['Roman' ,'Alpha' ,'roman' ,'alpha' ,'CountingNumber']; } this.style = parsed; - } else if (key === 'Count' || key === 'count') { + }else if(key === 'Count' || key === 'count'){ const source_count = value instanceof CounterMachine ? value.count : (value instanceof Count ? value : null); - if (source_count) { + if(source_count){ this.count = source_count.clone(); - } else { + }else{ console.error("RT-Manuscript Layout Error: Invalid object provided to write('Count')."); } - } else { + }else{ this[key] = value; } } } - enter(first_step_val) { + enter(first_step_val){ const current_status = this.count.read('status'); - if (current_status === 'empty') { - this.count.write('status', 'preamble'); + if(current_status === 'empty'){ + this.count.write('status' ,'preamble'); this.count.push(first_step_val !== undefined ? first_step_val : 0); - } else if (current_status === 'preamble') { + }else if(current_status === 'preamble'){ this.count.push(0); - this.count.write('status', 'preamble'); - } else if (current_status === 'between') { + this.count.write('status' ,'preamble'); + }else if(current_status === 'between'){ this.count.increment(); - this.count.write('status', 'preamble'); + this.count.write('status' ,'preamble'); } } - exit() { + exit(){ const current_status = this.count.read('status'); - if (current_status === 'empty') { + if(current_status === 'empty'){ console.error("RT-Manuscript Layout Error: Attempted to exit an empty counter scope."); - } else if (current_status === 'preamble') { - this.count.write('status', 'between'); - } else if (current_status === 'between') { + }else if(current_status === 'preamble'){ + this.count.write('status' ,'between'); + }else if(current_status === 'between'){ this.count.pop(); - this.count.write('status', 'between'); + this.count.write('status' ,'between'); } } - to_string(count_obj) { - if (!count_obj) return ''; + to_string(count_obj){ + if(!count_obj) return ''; const status = count_obj.read('status'); - if (status === 'empty') { + if(status === 'empty'){ console.error("RT-Manuscript Layout Error: Attempted to output an uninitialized empty counter."); return '[Empty Counter]'; } let active_list; - if (this.mode === 'scoped' && status === 'between') { - active_list = count_obj.read('list', 'short'); - } else { + if(this.mode === 'scoped' && status === 'between'){ + active_list = count_obj.read('list' ,'short'); + }else{ active_list = count_obj.read('list'); } - if (!active_list || active_list.length === 0) { - return ''; - } + if(!active_list || active_list.length === 0) return ''; - const formatted_list = active_list.map((val, depth) => { + const formatted_list = active_list.map((val ,depth) => { const current_style = depth < this.style.length ? this.style[depth] : this.style[this.style.length - 1]; const method_name = `to_${current_style}`; return typeof this[method_name] === 'function' ? this[method_name](val) : this.to_NaturalNumber(val); }); let count_str = formatted_list.join(this.separator); - if (this.separator_placement === 'embedded-after') { - count_str += this.separator; - } + if(this.separator_placement === 'embedded-after') count_str += this.separator; return count_str; } - to_NaturalNumber(num) { return num.toString(); } - from_NaturalNumber(val) { - const n = parseInt(val, 10); + to_NaturalNumber(num){ return num.toString(); } + from_NaturalNumber(val){ + const n = parseInt(val ,10); return isNaN(n) ? 0 : n; } - to_CountingNumber(num) { return (num + 1).toString(); } - from_CountingNumber(val) { - const n = parseInt(val, 10); - return isNaN(n) ? 0 : Math.max(0, n - 1); + to_CountingNumber(num){ return (num + 1).toString(); } + from_CountingNumber(val){ + const n = parseInt(val ,10); + return isNaN(n) ? 0 : Math.max(0 ,n - 1); } - to_roman(num) { return this.to_Roman(num).toLowerCase(); } - from_roman(val) { return this.from_Roman(val.toUpperCase()); } + to_roman(num){ return this.to_Roman(num).toLowerCase(); } + from_roman(val){ return this.from_Roman(val.toUpperCase()); } - to_Roman(num) { + to_Roman(num){ let n = num + 1; - if (n < 1) return n.toString(); - const lookup = {M:1000, CM:900, D:500, CD:400, C:100, XC:90, L:50, XL:40, X:10, IX:9, V:5, IV:4, I:1}; + if(n < 1) return n.toString(); + const lookup = {M:1000 ,CM:900 ,D:500 ,CD:400 ,C:100 ,XC:90 ,L:50 ,XL:40 ,X:10 ,IX:9 ,V:5 ,IV:4 ,I:1}; let roman = ''; - for (let i in lookup) { - while (n >= lookup[i]) { + for(let i in lookup){ + while(n >= lookup[i]){ roman += i; n -= lookup[i]; } } return roman; } - from_Roman(val) { - if (!/^M*(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$/i.test(val)) return 0; - const lookup = {M:1000, CM:900, D:500, CD:400, C:100, XC:90, L:50, XL:40, X:10, IX:9, V:5, IV:4, I:1}; + from_Roman(val){ + if(!/^M*(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$/i.test(val)) return 0; + const lookup = {M:1000 ,CM:900 ,D:500 ,CD:400 ,C:100 ,XC:90 ,L:50 ,XL:40 ,X:10 ,IX:9 ,V:5 ,IV:4 ,I:1}; let temp = val.toUpperCase(); let num = 0; let i = 0; - while (i < temp.length) { - if (i + 1 < temp.length && lookup[temp.substring(i, i + 2)]) { - num += lookup[temp.substring(i, i + 2)]; + while(i < temp.length){ + if( i + 1 < temp.length && lookup[temp.substring(i ,i + 2)] ){ + num += lookup[temp.substring(i ,i + 2)]; i += 2; - } else { + }else{ num += lookup[temp[i]]; i++; } } - return Math.max(0, num - 1); + return Math.max(0 ,num - 1); } - to_Alpha(num) { return String.fromCharCode(65 + num); } - from_Alpha(val) { - if (/^[A-Z]$/.test(val)) return val.charCodeAt(0) - 65; + to_Alpha(num){ return String.fromCharCode(65 + num); } + from_Alpha(val){ + if(/^[A-Z]$/.test(val)) return val.charCodeAt(0) - 65; return 0; } - to_alpha(num) { return String.fromCharCode(97 + num); } - from_alpha(val) { - if (/^[a-z]$/.test(val)) return val.charCodeAt(0) - 97; + to_alpha(num){ return String.fromCharCode(97 + num); } + from_alpha(val){ + if(/^[a-z]$/.test(val)) return val.charCodeAt(0) - 97; return 0; } - clone() { + clone(){ const copy = new CounterMachine(); copy.count = this.count.clone(); copy.style = [...this.style]; @@ -317,38 +337,38 @@ } } - counter = function(){ + const counter = function(){ const debug = RT.Debug || { log: function(){} }; - if (debug.log) debug.log('counter', 'Processing counters'); + if(debug.log) debug.log('counter' ,'Processing counters'); const root_node = document.documentElement; - function walk(node) { - if (node.nodeType !== Node.ELEMENT_NODE) return; + function walk(node){ + if(node.nodeType !== Node.ELEMENT_NODE) return; - const tag = node.tagName.toLowerCase(); + const tag = (node.tagName || '').toLowerCase(); let machine_to_exit = null; - if (tag === 'rt·counter·make') { + if(tag === 'rt·counter·make'){ const name = node.getAttribute('counter'); - if (name) { + if(name){ const continues_id = node.getAttribute('continues'); - if (continues_id && RT.dict_serial[continues_id]) { + if(continues_id && RT.dict_serial[continues_id]){ RT.dict_instance[name] = RT.dict_serial[continues_id].clone(); - } else { + }else{ const style_attr = node.getAttribute('style'); const parsed_style = style_attr ? style_attr.split(',').map(s => s.trim()) : ['NaturalNumber']; RT.dict_instance[name] = new CounterMachine({ - style: parsed_style, - separator: node.getAttribute('separator') || '.', - separator_placement: node.getAttribute('separator-placement') || 'embedded', - mode: node.getAttribute('mode') || 'scoped' + style: parsed_style + ,separator: node.getAttribute('separator') || '.' + ,separator_placement: node.getAttribute('separator-placement') || 'embedded' + ,mode: node.getAttribute('mode') || 'scoped' }); const on_first_step_str = node.getAttribute('on-first-step'); - if (on_first_step_str) { + if(on_first_step_str){ const top_style = RT.dict_instance[name].style[0]; const method_name = `from_${top_style}`; const active_machine = RT.dict_instance[name]; @@ -361,50 +381,56 @@ } const serial = node.getAttribute('serial') || String(RT.serial_id_allocator++); - node.setAttribute('serial', serial); + node.setAttribute('serial' ,serial); RT.dict_serial[serial] = RT.dict_instance[name]; } - } else if (tag === 'rt·counter·step') { + + }else if(tag === 'rt·counter·step'){ const name = node.getAttribute('counter'); const is_continuation = node.getAttribute('continuation') === 'true'; - if (name && RT.dict_instance[name]) { + if(name && RT.dict_instance[name]){ const active_machine = RT.dict_instance[name]; - if (!is_continuation) { + if(!is_continuation){ active_machine.enter(active_machine.first_step_val); active_machine.first_step_val = undefined; + + const name_nodes = Array.from(node.children).filter(c => c.tagName && c.tagName.toLowerCase() === 'rt·name'); + if(name_nodes.length > 0){ + const step_name = name_nodes.map(n => n.innerHTML.trim()).join('
'); + active_machine.count.set_name(step_name); + } } machine_to_exit = active_machine; } - } else if (tag === 'rt·counter·snapshot') { + }else if(tag === 'rt·counter·snapshot'){ const counter_name = node.getAttribute('counter'); const snapshot_name = node.getAttribute('snapshot'); - if (counter_name && snapshot_name && RT.dict_instance[counter_name]) { + if(counter_name && snapshot_name && RT.dict_instance[counter_name]){ const active_machine = RT.dict_instance[counter_name]; - if (active_machine.read('count', 'status') === 'empty') { - console.error(`RT-Manuscript Layout Error: Attempted to snapshot an empty counter '${counter_name}' at snapshot '${snapshot_name}'. A step is required first.`); - } else { - RT.dict_snapshot[snapshot_name] = active_machine.clone(); + if(active_machine.read('count' ,'status') === 'empty'){ + console.error(`RT-Manuscript Layout Error: Attempted to snapshot an empty counter '${counter_name}' at snapshot '${snapshot_name}'. A step is required first.`); + }else{ + RT.dict_snapshot[snapshot_name] = active_machine.clone(); } } } let child = node.firstElementChild; - while (child) { + while(child){ walk(child); child = child.nextElementSibling; } - if (machine_to_exit) { + if(machine_to_exit){ const is_continued = node.getAttribute('continued') === 'true'; - if (!is_continued) { + if(!is_continued){ machine_to_exit.exit(); - } else { - // Cache the suspended state dynamically via the paginator's injected ID + }else{ const split_id = node.getAttribute('split-id'); - if (split_id) { + if(split_id){ RT.dict_serial[split_id] = machine_to_exit.clone(); } } @@ -415,33 +441,33 @@ const reads = root_node.querySelectorAll('RT·counter·read, rt·counter·read'); - for (let i = 0; i < reads.length; i++) { + for(let i = 0; i < reads.length; i++){ process_read_node(reads[i]); } - function process_read_node(node) { + function process_read_node(node){ const snapshot_name = node.getAttribute('snapshot'); const key = node.getAttribute('key') || 'count'; - if (snapshot_name && RT.dict_snapshot[snapshot_name]) { + if(snapshot_name && RT.dict_snapshot[snapshot_name]){ const snapshot_machine = RT.dict_snapshot[snapshot_name]; - if (key === 'count') { + if(key === 'count'){ const raw_state = snapshot_machine.read('count'); node.innerHTML = snapshot_machine.to_string(raw_state); - } else { + }else{ const keys = key.split('.'); const value = snapshot_machine.read(...keys); - if (value === null) { + if(value === null){ node.innerHTML = 'null'; - } else if (value !== undefined) { + }else if(value !== undefined){ node.innerHTML = Array.isArray(value) ? value.join(',') : value; - } else { + }else{ node.innerHTML = `[Missing key: ${key}]`; } } - } else { + }else{ node.innerHTML = `[Unknown snapshot: ${snapshot_name}]`; console.error(`RT-Manuscript Layout Error: failed. No snapshot named '${snapshot_name}' found.`); } diff --git a/tester/authored/Counter/test_5.html b/tester/authored/Counter/test_5.html new file mode 100644 index 0000000..e8459ca --- /dev/null +++ b/tester/authored/Counter/test_5.html @@ -0,0 +1,51 @@ + + + + + Counter Named Step Test + + + + + + + +

Page 1: Named Scope Initialization

+

This counter scope is assigned an internal name during evaluation. It is then severed.

+ + + + + Introduction to Systems Architecture + + +

Count: (Expected: I)

+

Name: (Expected: Introduction to Systems Architecture)

+ +

--- Issuing Forced Split Break ---

+ + +

Page 2: Continuation with Names

+ +

The state arrays, including the parallel name array, are successfully cloned across the page boundary.

+ +

Count: (Expected: I)

+

Name: (Expected: Introduction to Systems Architecture)

+ + + Theoretical Foundations + + +

Count: (Expected: I.A)

+

Name: (Expected: Theoretical Foundations)

+
+ +
+ +
+ +