mirror of
https://codeberg.org/yeentown/barkey.git
synced 2025-05-16 02:26:57 +00:00
View MR for information: https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/866 Closes #605 Approved-by: Hazelnoot <acomputerdog@gmail.com> Approved-by: Marie <github@yuugi.dev>
This commit is contained in:
commit
2928ccf1e4
3 changed files with 183 additions and 5 deletions
|
@ -230,6 +230,67 @@ export class MfmService {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'rp': break;
|
||||||
|
case 'rt': {
|
||||||
|
appendChildren(node.childNodes);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'ruby': {
|
||||||
|
if (node.childNodes) {
|
||||||
|
/*
|
||||||
|
we get:
|
||||||
|
```
|
||||||
|
<ruby>
|
||||||
|
some text <rp>(</rp> <rt>annotation</rt> <rp>)</rp>
|
||||||
|
more text <rt>more annotation<rt>
|
||||||
|
</ruby>
|
||||||
|
```
|
||||||
|
|
||||||
|
and we want to produce:
|
||||||
|
```
|
||||||
|
$[ruby $[group some text] annotation]
|
||||||
|
$[ruby $[group more text] more annotation]
|
||||||
|
```
|
||||||
|
|
||||||
|
that `group` is a hack, because when the `ruby` render
|
||||||
|
sees just text inside the `$[ruby]`, it splits on
|
||||||
|
whitespace, considers the first "word" to be the main
|
||||||
|
content, and the rest the annotation
|
||||||
|
|
||||||
|
with that `group`, we force it to consider the whole
|
||||||
|
group as the main content
|
||||||
|
|
||||||
|
(note that the `rp` are to be ignored, they only exist
|
||||||
|
for browsers who don't understand ruby)
|
||||||
|
*/
|
||||||
|
let nonRtNodes = [];
|
||||||
|
// scan children, ignore `rp`, split on `rt`
|
||||||
|
for (const child of node.childNodes) {
|
||||||
|
if (treeAdapter.isTextNode(child)) {
|
||||||
|
nonRtNodes.push(child);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!treeAdapter.isElementNode(child)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (child.nodeName === 'rp') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (child.nodeName === 'rt') {
|
||||||
|
text += '$[ruby $[group ';
|
||||||
|
appendChildren(nonRtNodes);
|
||||||
|
text += '] ';
|
||||||
|
analyze(child);
|
||||||
|
text += '] ';
|
||||||
|
nonRtNodes = [];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
nonRtNodes.push(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default: // includes inline elements
|
default: // includes inline elements
|
||||||
{
|
{
|
||||||
appendChildren(node.childNodes);
|
appendChildren(node.childNodes);
|
||||||
|
@ -348,6 +409,14 @@ export class MfmService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hack for ruby, should never be needed because we should
|
||||||
|
// never send this out to other instances
|
||||||
|
case 'group': {
|
||||||
|
const el = doc.createElement('span');
|
||||||
|
appendChildren(node.children, el);
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
return fnDefault(node);
|
return fnDefault(node);
|
||||||
}
|
}
|
||||||
|
@ -526,11 +595,65 @@ export class MfmService {
|
||||||
},
|
},
|
||||||
|
|
||||||
async fn(node) {
|
async fn(node) {
|
||||||
|
switch (node.props.name) {
|
||||||
|
case 'group': { // hack for ruby
|
||||||
|
const el = doc.createElement('span');
|
||||||
|
await appendChildren(node.children, el);
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
case 'ruby': {
|
||||||
|
if (node.children.length === 1) {
|
||||||
|
const child = node.children[0];
|
||||||
|
const text = child.type === 'text' ? child.props.text : '';
|
||||||
|
const rubyEl = doc.createElement('ruby');
|
||||||
|
const rtEl = doc.createElement('rt');
|
||||||
|
|
||||||
|
const rpStartEl = doc.createElement('rp');
|
||||||
|
rpStartEl.appendChild(doc.createTextNode('('));
|
||||||
|
const rpEndEl = doc.createElement('rp');
|
||||||
|
rpEndEl.appendChild(doc.createTextNode(')'));
|
||||||
|
|
||||||
|
rubyEl.appendChild(doc.createTextNode(text.split(' ')[0]));
|
||||||
|
rtEl.appendChild(doc.createTextNode(text.split(' ')[1]));
|
||||||
|
rubyEl.appendChild(rpStartEl);
|
||||||
|
rubyEl.appendChild(rtEl);
|
||||||
|
rubyEl.appendChild(rpEndEl);
|
||||||
|
return rubyEl;
|
||||||
|
} else {
|
||||||
|
const rt = node.children.at(-1);
|
||||||
|
|
||||||
|
if (!rt) {
|
||||||
|
const el = doc.createElement('span');
|
||||||
|
await appendChildren(node.children, el);
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
|
||||||
|
const text = rt.type === 'text' ? rt.props.text : '';
|
||||||
|
const rubyEl = doc.createElement('ruby');
|
||||||
|
const rtEl = doc.createElement('rt');
|
||||||
|
|
||||||
|
const rpStartEl = doc.createElement('rp');
|
||||||
|
rpStartEl.appendChild(doc.createTextNode('('));
|
||||||
|
const rpEndEl = doc.createElement('rp');
|
||||||
|
rpEndEl.appendChild(doc.createTextNode(')'));
|
||||||
|
|
||||||
|
await appendChildren(node.children.slice(0, node.children.length - 1), rubyEl);
|
||||||
|
rtEl.appendChild(doc.createTextNode(text.trim()));
|
||||||
|
rubyEl.appendChild(rpStartEl);
|
||||||
|
rubyEl.appendChild(rtEl);
|
||||||
|
rubyEl.appendChild(rpEndEl);
|
||||||
|
return rubyEl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
const el = doc.createElement('span');
|
const el = doc.createElement('span');
|
||||||
el.textContent = '*';
|
el.textContent = '*';
|
||||||
await appendChildren(node.children, el);
|
await appendChildren(node.children, el);
|
||||||
el.textContent += '*';
|
el.textContent += '*';
|
||||||
return el;
|
return el;
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
blockCode(node) {
|
blockCode(node) {
|
||||||
|
|
|
@ -45,6 +45,50 @@ describe('MfmService', () => {
|
||||||
const output = '<p><pre><code><p>Hello, world!</p></code></pre></p>';
|
const output = '<p><pre><code><p>Hello, world!</p></code></pre></p>';
|
||||||
assert.equal(mfmService.toHtml(mfm.parse(input)), output);
|
assert.equal(mfmService.toHtml(mfm.parse(input)), output);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('ruby', () => {
|
||||||
|
const input = '$[ruby some text ignore me]';
|
||||||
|
const output = '<p><ruby>some<rp>(</rp><rt>text</rt><rp>)</rp></ruby></p>';
|
||||||
|
assert.equal(mfmService.toHtml(mfm.parse(input)), output);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('ruby2', () => {
|
||||||
|
const input = '$[ruby *some text* ignore me]';
|
||||||
|
const output = '<p><ruby><i>some text</i><rp>(</rp><rt>ignore me</rt><rp>)</rp></ruby></p>';
|
||||||
|
assert.equal(mfmService.toHtml(mfm.parse(input)), output);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('ruby 3', () => {
|
||||||
|
const input = '$[ruby $[group *some* text] ignore me]';
|
||||||
|
const output = '<p><ruby><span><i>some</i> text</span><rp>(</rp><rt>ignore me</rt><rp>)</rp></ruby></p>';
|
||||||
|
assert.equal(mfmService.toHtml(mfm.parse(input)), output);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('toMastoApiHtml', () => {
|
||||||
|
test('br', async () => {
|
||||||
|
const input = 'foo\nbar\nbaz';
|
||||||
|
const output = '<p><span>foo<br>bar<br>baz</span></p>';
|
||||||
|
assert.equal(await mfmService.toMastoApiHtml(mfm.parse(input)), output);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('br alt', async () => {
|
||||||
|
const input = 'foo\r\nbar\rbaz';
|
||||||
|
const output = '<p><span>foo<br>bar<br>baz</span></p>';
|
||||||
|
assert.equal(await mfmService.toMastoApiHtml(mfm.parse(input)), output);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('escape', async () => {
|
||||||
|
const input = '```\n<p>Hello, world!</p>\n```';
|
||||||
|
const output = '<p><pre><code><p>Hello, world!</p></code></pre></p>';
|
||||||
|
assert.equal(await mfmService.toMastoApiHtml(mfm.parse(input)), output);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('ruby', async () => {
|
||||||
|
const input = '$[ruby $[group *some* text] ignore me]';
|
||||||
|
const output = '<p><ruby><span><span>*some*</span><span> text</span></span><rp>(</rp><rt>ignore me</rt><rp>)</rp></ruby></p>';
|
||||||
|
assert.equal(await mfmService.toMastoApiHtml(mfm.parse(input)), output);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('fromHtml', () => {
|
describe('fromHtml', () => {
|
||||||
|
@ -115,5 +159,12 @@ describe('MfmService', () => {
|
||||||
test('hashtag', () => {
|
test('hashtag', () => {
|
||||||
assert.deepStrictEqual(mfmService.fromHtml('<p>a <a href="https://example.com/tags/a">#a</a> d</p>', ['#a']), 'a #a d');
|
assert.deepStrictEqual(mfmService.fromHtml('<p>a <a href="https://example.com/tags/a">#a</a> d</p>', ['#a']), 'a #a d');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('ruby', () => {
|
||||||
|
assert.deepStrictEqual(
|
||||||
|
mfmService.fromHtml('<ruby> <i>some</i> text <rp>(</rp><rt>ignore me</rt><rp>)</rp> and <rt>more</rt></ruby>'),
|
||||||
|
'$[ruby $[group <i>some</i> text ] ignore me] $[ruby $[group and ] more]'
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -358,6 +358,10 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
|
||||||
return h('ruby', {}, [...genEl(token.children.slice(0, token.children.length - 1), scale), h('rt', text.trim())]);
|
return h('ruby', {}, [...genEl(token.children.slice(0, token.children.length - 1), scale), h('rt', text.trim())]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case 'group': { // this is mostly a hack for the insides of `ruby`
|
||||||
|
style = '';
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'unixtime': {
|
case 'unixtime': {
|
||||||
const child = token.children[0];
|
const child = token.children[0];
|
||||||
const unixtime = parseInt(child.type === 'text' ? child.props.text : '');
|
const unixtime = parseInt(child.type === 'text' ? child.props.text : '');
|
||||||
|
|
Loading…
Add table
Reference in a new issue