Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(frontend): ピン留め or 履歴に表示されるカスタム絵文字がサーバから削除されるとリアクションが出来なくなる #13486

Merged
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@

-->

## 202x.x.x (unreleased)

### General
-

### Client
- Fix: 絵文字関係の不具合を修正 (#13485)
- 履歴に残っている or ピン留めされた絵文字がコントロールパネルより削除されていた際にリアクションデッキが表示できなくなる
- Unicode絵文字が履歴に残っている or ピン留めされているとリアクションデッキが表示できなくなる

### Server
-

## 2024.3.0

### General
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/components/MkAutocomplete.vue
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ const emojiDb = computed(() => {
unicodeEmojiDB.push({
emoji: emoji,
name: k,
aliasOf: getEmojiName(emoji)!,
aliasOf: getEmojiName(emoji),
url: char2path(emoji),
});
}
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/components/MkEmojiPicker.section.vue
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ const shown = ref(!!props.initialShown);
function computeButtonTitle(ev: MouseEvent): void {
const elm = ev.target as HTMLElement;
const emoji = elm.dataset.emoji as string;
elm.title = getEmojiName(emoji) ?? emoji;
elm.title = getEmojiName(emoji);
}

function nestedChosen(emoji: any, ev: MouseEvent) {
Expand Down
13 changes: 8 additions & 5 deletions packages/frontend/src/components/MkEmojiPicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ watch(q, () => {
searchResultUnicode.value = Array.from(searchUnicode());
});

function canReact(emoji: Misskey.entities.EmojiSimple | UnicodeEmojiDef): boolean {
function canReact(emoji: Misskey.entities.EmojiSimple | UnicodeEmojiDef | string): boolean {
return !props.targetNote || checkReactionPermissions($i!, props.targetNote, emoji);
}

Expand All @@ -378,19 +378,22 @@ function getKey(emoji: string | Misskey.entities.EmojiSimple | UnicodeEmojiDef):
return typeof emoji === 'string' ? emoji : 'char' in emoji ? emoji.char : `:${emoji.name}:`;
}

function getDef(emoji: string) {
function getDef(emoji: string): string | Misskey.entities.EmojiSimple | UnicodeEmojiDef {
if (emoji.includes(':')) {
return customEmojisMap.get(emoji.replace(/:/g, ''))!;
// カスタム絵文字が存在する場合はその情報を持つオブジェクトを返し、
// サーバの管理画面から削除された等で情報が見つからない場合は名前の文字列をそのまま返しておく(undefinedを返すとエラーになるため)
const name = emoji.replaceAll(':', '');
return customEmojisMap.get(name) ?? emoji;
} else {
return getUnicodeEmoji(emoji)!;
return getUnicodeEmoji(emoji);
}
}

/** @see MkEmojiPicker.section.vue */
function computeButtonTitle(ev: MouseEvent): void {
const elm = ev.target as HTMLElement;
const emoji = elm.dataset.emoji as string;
elm.title = getEmojiName(emoji) ?? emoji;
elm.title = getEmojiName(emoji);
}

function chosen(emoji: any, ev?: MouseEvent) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ function getReactionName(reaction: string): string {
if (trimLocal.startsWith(':')) {
return trimLocal;
}
return getEmojiName(reaction) ?? reaction;
return getEmojiName(reaction);
}
</script>

Expand Down
5 changes: 2 additions & 3 deletions packages/frontend/src/components/global/MkEmoji.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only

<script lang="ts" setup>
import { computed, inject } from 'vue';
import { char2twemojiFilePath, char2fluentEmojiFilePath } from '@/scripts/emoji-base.js';
import { char2fluentEmojiFilePath, char2twemojiFilePath } from '@/scripts/emoji-base.js';
import { defaultStore } from '@/store.js';
import { colorizeEmoji, getEmojiName } from '@/scripts/emojilist.js';
import * as os from '@/os.js';
Expand All @@ -34,8 +34,7 @@ const colorizedNativeEmoji = computed(() => colorizeEmoji(props.emoji));

// Searching from an array with 2000 items for every emoji felt like too energy-consuming, so I decided to do it lazily on pointerenter
function computeTitle(event: PointerEvent): void {
const title = getEmojiName(props.emoji as string) ?? props.emoji as string;
(event.target as HTMLElement).title = title;
(event.target as HTMLElement).title = getEmojiName(props.emoji);
}

function onClick(ev: MouseEvent) {
Expand Down
10 changes: 5 additions & 5 deletions packages/frontend/src/scripts/check-reaction-permissions.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import * as Misskey from 'misskey-js';
import { UnicodeEmojiDef } from './emojilist.js';

export function checkReactionPermissions(me: Misskey.entities.MeDetailed, note: Misskey.entities.Note, emoji: Misskey.entities.EmojiSimple | UnicodeEmojiDef): boolean {
if ('char' in emoji) return true; // UnicodeEmojiDefなら常にリアクション可能
export function checkReactionPermissions(me: Misskey.entities.MeDetailed, note: Misskey.entities.Note, emoji: Misskey.entities.EmojiSimple | UnicodeEmojiDef | string): boolean {
if (typeof emoji === 'string') return true; // UnicodeEmojiDefにも無い絵文字であれば文字列で来る。Unicode絵文字であることには変わりないので常にリアクション可能とする;
if ('char' in emoji) return true; // UnicodeEmojiDefなら常にリアクション可能

emoji = emoji as Misskey.entities.EmojiSimple;
const roleIdsThatCanBeUsedThisEmojiAsReaction = emoji.roleIdsThatCanBeUsedThisEmojiAsReaction ?? [];
return !(emoji.localOnly && note.user.host !== me.host)
const roleIdsThatCanBeUsedThisEmojiAsReaction = emoji.roleIdsThatCanBeUsedThisEmojiAsReaction ?? [];
return !(emoji.localOnly && note.user.host !== me.host)
&& !(emoji.isSensitive && (note.reactionAcceptance === 'nonSensitiveOnly' || note.reactionAcceptance === 'nonSensitiveOnlyForLocalLikeOnlyForRemote'))
&& (roleIdsThatCanBeUsedThisEmojiAsReaction.length === 0 || me.roles.some(role => roleIdsThatCanBeUsedThisEmojiAsReaction.includes(role.id)));
}
20 changes: 14 additions & 6 deletions packages/frontend/src/scripts/emojilist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,29 @@ for (let i = 0; i < emojilist.length; i++) {

export const emojiCharByCategory = _charGroupByCategory;

export function getUnicodeEmoji(char: string): UnicodeEmojiDef | null {
export function getUnicodeEmoji(char: string): UnicodeEmojiDef | string {
// Colorize it because emojilist.json assumes that
return unicodeEmojisMap.get(colorizeEmoji(char)) ?? unicodeEmojisMap.get(char) ?? null;
return unicodeEmojisMap.get(colorizeEmoji(char))
// カラースタイル絵文字がjsonに無い場合はテキストスタイル絵文字にフォールバックする
?? unicodeEmojisMap.get(char)
// それでも見つからない場合はそのまま返す(絵文字情報がjsonに無い場合、このフォールバックが無いとレンダリングに失敗する)
?? char;
}

export function getEmojiName(char: string): string | null {
export function getEmojiName(char: string): string {
// Colorize it because emojilist.json assumes that
const idx = _indexByChar.get(colorizeEmoji(char));
if (idx == null) {
return null;
const idx = _indexByChar.get(colorizeEmoji(char)) ?? _indexByChar.get(char);
if (idx === undefined) {
// 絵文字情報がjsonに無い場合は名前の取得が出来ないのでそのまま返すしか無い
return char;
} else {
return emojilist[idx].name;
}
}

/**
* テキストスタイル絵文字(U+260Eなどの1文字で表現される絵文字)をカラースタイル絵文字に変換します(VS16:U+FE0Fを付与)。
*/
export function colorizeEmoji(char: string) {
return char.length === 1 ? `${char}\uFE0F` : char;
}
Expand Down
Loading