JSFiddle - React, Tailwind, and code Playground
by int32_t
HTML
<p id="r1">before <ruby>A <ruby>base<rt>inner-ruby</ruby><rt>outer-<ruby>ruby<rt>ruby-of-ruby</ruby></rt> base2<rt>inner-2</ruby> <ruby>base3<rt>ruby3</ruby> after</p>
<div id="console"></div>
CSS
p {
font-size:40px;
}
ruby {
background-color: rgba(238,255,238,0.9);
}
rt {
background-color: rgba(255,238,238,0.8);
}
#console {
white-space: pre;
font-family: monospace;
font-size: 14px;
}
JavaScript
function formatLevel(rt_context) {
return `${rt_context.map(d => d.max - d.current + 1).join(',')}`;
}
function buildChunkList(ifc) {
let chunk_list = [];
let chunk_text = '';
let current = ifc.firstChild;
let ruby_depth = 0;
let max_ruby_depth = 0;
let rt_context = [];
let level_list = [];
let parent_chunk = null;
let parent_chunk_stack = [];
let base_last_chunk_stack = [];
const pushBaseChunk = (ct, rd, rc, cl) => {
if (rc.length > 0) {
cl.push({t:ct, l:`L${formatLevel(rc)}`});
} else if (rd == 0) {
cl.push({t:ct, l:'*'});
} else {
cl.push({t:ct, l:'L0'});
}
return cl[cl.length - 1];
};
const addLink = (from, to) => {
from[to.l] = to;
};
while (current) {
if (current.nodeType == Node.ELEMENT_NODE) {
if (current.firstChild) {
if (current.tagName == 'RT') {
const new_base_chunk = pushBaseChunk(chunk_text, ruby_depth, rt_context, chunk_list);
chunk_text = '';
addLink(parent_chunk, new_base_chunk);
base_last_chunk_stack.push(new_base_chunk);
parent_chunk = parent_chunk_stack.pop();
rt_context.push({max:max_ruby_depth, current:ruby_depth});
const level = formatLevel(rt_context);
if (!level_list.includes(level))
level_list.push(level);
max_ruby_depth = 0;
ruby_depth = 0;
} else if (current.tagName == 'RUBY') {
if (chunk_text.length > 0) {
const new_chunk = pushBaseChunk(chunk_text, ruby_depth, rt_context, chunk_list);
chunk_text = '';
if (parent_chunk)
addLink(parent_chunk, new_chunk);
parent_chunk = new_chunk;
}
// Save to use it on <rt>.
parent_chunk_stack.push(parent_chunk);
if (ruby_depth == 0) {
max_ruby_depth = 1;
}
++ruby_depth;
max_ruby_depth = Math.max(ruby_depth, max_ruby_depth);
}
...