mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 21:15:32 +09:00
fix(app): convert emoji shortcodes in a single transform pass (#3459)
This commit is contained in:
1 parent
3c8fe74660
commit
538b5d69bb
1 file changed
+54
-31
@@ -61,6 +61,12 @@ function findNextEmojiToken(text: string, startIndex: number): EmojiToken | null
|
|||||||
return surrogate.start < shortcode.start ? {...surrogate, surrogate: true} : {...shortcode, surrogate: false};
|
return surrogate.start < shortcode.start ? {...surrogate, surrogate: true} : {...shortcode, surrogate: false};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface EmojiTokenEdit {
|
||||||
|
start: number;
|
||||||
|
end: number;
|
||||||
|
replacement: ResolvedTypedEmoji | string;
|
||||||
|
}
|
||||||
|
|
||||||
function isEscapedAt(text: string, index: number): boolean {
|
function isEscapedAt(text: string, index: number): boolean {
|
||||||
let backslashes = 0;
|
let backslashes = 0;
|
||||||
let cursor = index - 1;
|
let cursor = index - 1;
|
||||||
@@ -80,30 +86,27 @@ function $convertEmojiShortcode(node: TextNode, resolve: ComposerEmojiResolver):
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const text = node.getTextContent();
|
const text = node.getTextContent();
|
||||||
|
const edits: Array<EmojiTokenEdit> = [];
|
||||||
let searchFrom = 0;
|
let searchFrom = 0;
|
||||||
|
let backticks = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
const match = findNextEmojiToken(text, searchFrom);
|
const match = findNextEmojiToken(text, searchFrom);
|
||||||
if (match == null) {
|
if (match == null) {
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
const codeMarkers = text.slice(0, match.start).match(/`/g);
|
for (let index = searchFrom; index < match.start; index++) {
|
||||||
if ((codeMarkers == null ? 0 : codeMarkers.length) % 2 === 1) {
|
if (text[index] === '`') {
|
||||||
return;
|
backticks += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
searchFrom = match.end;
|
||||||
|
if (backticks % 2 === 1) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (isEscapedAt(text, match.start)) {
|
if (isEscapedAt(text, match.start)) {
|
||||||
if (match.surrogate) {
|
if (match.surrogate) {
|
||||||
const shortcodeText = `:${match.name}:`;
|
edits.push({start: match.start, end: match.end, replacement: `:${match.name}:`});
|
||||||
const selection = $captureSelectionOffsets();
|
|
||||||
const nodeDisplayStart = $getComposerNodeDisplayStart(node);
|
|
||||||
const replaced = `${text.slice(0, match.start)}${shortcodeText}${text.slice(match.end)}`;
|
|
||||||
node.setTextContent(replaced);
|
|
||||||
if (selection != null) {
|
|
||||||
const adjusted = $adjustEmbedCaret(selection, nodeDisplayStart, match.start, match.end, shortcodeText.length);
|
|
||||||
$selectComposerRange(adjusted.anchor, adjusted.focus);
|
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
searchFrom = match.end;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const previous = match.start === 0 ? node.getPreviousSibling() : null;
|
const previous = match.start === 0 ? node.getPreviousSibling() : null;
|
||||||
@@ -143,27 +146,47 @@ function $convertEmojiShortcode(node: TextNode, resolve: ComposerEmojiResolver):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const resolved = resolve(match.name);
|
const resolved = resolve(match.name);
|
||||||
if (resolved == null) {
|
if (resolved != null) {
|
||||||
searchFrom = match.end;
|
edits.push({start: match.start, end: match.end, replacement: resolved});
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
const selection = $captureSelectionOffsets();
|
}
|
||||||
const nodeDisplayStart = $getComposerNodeDisplayStart(node);
|
if (edits.length === 0) {
|
||||||
const emojiNode =
|
|
||||||
resolved.kind === 'standard'
|
|
||||||
? $createComposerStandardEmojiNode(resolved.name, resolved.surrogate, resolved.url, resolved.display)
|
|
||||||
: $createComposerCustomEmojiNode(resolved.emojiId, resolved.animated, resolved.display, resolved.wire);
|
|
||||||
const segments = node.splitText(match.start, match.end);
|
|
||||||
const target = segments[match.start > 0 ? 1 : 0];
|
|
||||||
if (target == null) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let selection = $captureSelectionOffsets();
|
||||||
|
const nodeDisplayStart = $getComposerNodeDisplayStart(node);
|
||||||
|
for (let index = edits.length - 1; index >= 0; index--) {
|
||||||
|
const {start, end, replacement} = edits[index]!;
|
||||||
|
if (typeof replacement === 'string') {
|
||||||
|
node.spliceText(start, end - start, replacement);
|
||||||
|
} else {
|
||||||
|
const emojiNode =
|
||||||
|
replacement.kind === 'standard'
|
||||||
|
? $createComposerStandardEmojiNode(
|
||||||
|
replacement.name,
|
||||||
|
replacement.surrogate,
|
||||||
|
replacement.url,
|
||||||
|
replacement.display,
|
||||||
|
)
|
||||||
|
: $createComposerCustomEmojiNode(
|
||||||
|
replacement.emojiId,
|
||||||
|
replacement.animated,
|
||||||
|
replacement.display,
|
||||||
|
replacement.wire,
|
||||||
|
);
|
||||||
|
const target = node.splitText(start, end)[start > 0 ? 1 : 0];
|
||||||
|
if (target == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
target.replace(emojiNode);
|
target.replace(emojiNode);
|
||||||
if (selection != null) {
|
|
||||||
const adjusted = $adjustEmbedCaret(selection, nodeDisplayStart, match.start, match.end, resolved.display.length);
|
|
||||||
$selectComposerRange(adjusted.anchor, adjusted.focus);
|
|
||||||
}
|
}
|
||||||
return;
|
if (selection != null) {
|
||||||
|
const newLen = typeof replacement === 'string' ? replacement.length : replacement.display.length;
|
||||||
|
selection = $adjustEmbedCaret(selection, nodeDisplayStart, start, end, newLen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (selection != null) {
|
||||||
|
$selectComposerRange(selection.anchor, selection.focus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user