1
0
Fork 0
forked from gitea/nas

Merge remote-tracking branch 'parent/main' into kb_migration

This commit is contained in:
KMY 2023-08-24 09:58:54 +09:00
commit adfa3524fc
38 changed files with 294 additions and 184 deletions

View file

@ -105,6 +105,21 @@ describe('computeHashtagBarForStatus', () => {
);
});
it('handles server-side normalized tags with accentuated characters', () => {
const status = createStatus(
'<p>Text</p><p><a href="test">#éaa</a> <a href="test">#Éaa</a></p>',
['eaa'], // The server may normalize the hashtags in the `tags` attribute
);
const { hashtagsInBar, statusContentProps } =
computeHashtagBarForStatus(status);
expect(hashtagsInBar).toEqual(['Éaa']);
expect(statusContentProps.statusContent).toMatchInlineSnapshot(
`"<p>Text</p>"`,
);
});
it('does not display in bar a hashtag in content with a case difference', () => {
const status = createStatus(
'<p>Text <a href="test">#Éaa</a></p><p><a href="test">#éaa</a></p>',

View file

@ -23,8 +23,9 @@ export type StatusLike = Record<{
}>;
function normalizeHashtag(hashtag: string) {
if (hashtag && hashtag.startsWith('#')) return hashtag.slice(1);
else return hashtag;
return (
hashtag && hashtag.startsWith('#') ? hashtag.slice(1) : hashtag
).normalize('NFKC');
}
function isNodeLinkHashtag(element: Node): element is HTMLLinkElement {
@ -70,9 +71,16 @@ function uniqueHashtagsWithCaseHandling(hashtags: string[]) {
}
// Create the collator once, this is much more efficient
const collator = new Intl.Collator(undefined, { sensitivity: 'accent' });
const collator = new Intl.Collator(undefined, {
sensitivity: 'base', // we use this to emulate the ASCII folding done on the server-side, hopefuly more efficiently
});
function localeAwareInclude(collection: string[], value: string) {
return collection.find((item) => collator.compare(item, value) === 0);
const normalizedValue = value.normalize('NFKC');
return !!collection.find(
(item) => collator.compare(item.normalize('NFKC'), normalizedValue) === 0,
);
}
// We use an intermediate function here to make it easier to test
@ -121,11 +129,13 @@ export function computeHashtagBarForStatus(status: StatusLike): {
// try to see if the last line is only hashtags
let onlyHashtags = true;
const normalizedTagNames = tagNames.map((tag) => tag.normalize('NFKC'));
Array.from(lastChild.childNodes).forEach((node) => {
if (isNodeLinkHashtag(node) && node.textContent) {
const normalized = normalizeHashtag(node.textContent);
if (!localeAwareInclude(tagNames, normalized)) {
if (!localeAwareInclude(normalizedTagNames, normalized)) {
// stop here, this is not a real hashtag, so consider it as text
onlyHashtags = false;
return;
@ -140,12 +150,14 @@ export function computeHashtagBarForStatus(status: StatusLike): {
}
});
const hashtagsInBar = tagNames.filter(
(tag) =>
// the tag does not appear at all in the status content, it is an out-of-band tag
!localeAwareInclude(contentHashtags, tag) &&
!localeAwareInclude(lastLineHashtags, tag),
);
const hashtagsInBar = tagNames.filter((tag) => {
const normalizedTag = tag.normalize('NFKC');
// the tag does not appear at all in the status content, it is an out-of-band tag
return (
!localeAwareInclude(contentHashtags, normalizedTag) &&
!localeAwareInclude(lastLineHashtags, normalizedTag)
);
});
const isOnlyOneLine = contentWithoutLastLine.content.childElementCount === 0;
const hasMedia = status.get('media_attachments').size > 0;
@ -204,7 +216,7 @@ const HashtagBar: React.FC<{
<div className='hashtag-bar'>
{revealedHashtags.map((hashtag) => (
<Link key={hashtag} to={`/tags/${hashtag}`}>
#{hashtag}
#<span>{hashtag}</span>
</Link>
))}

View file

@ -583,6 +583,7 @@ class Status extends ImmutablePureComponent {
}
const {statusContentProps, hashtagBar} = getHashtagBarForStatus(status);
const expanded = !status.get('hidden')
return (
<HotKeys handlers={handlers}>
@ -611,7 +612,7 @@ class Status extends ImmutablePureComponent {
<StatusContent
status={status}
onClick={this.handleClick}
expanded={!status.get('hidden')}
expanded={expanded}
onExpandedToggle={this.handleExpandedToggle}
onTranslate={this.handleTranslate}
collapsible
@ -621,7 +622,7 @@ class Status extends ImmutablePureComponent {
{(!isCardMediaWithSensitive || !status.get('hidden')) && media}
{hashtagBar}
{expanded && hashtagBar}
{emojiReactionsBar}