merge: Call note_view_interruptor for all notes (!1154)
View MR for information: https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/1154 Approved-by: Hazelnoot <acomputerdog@gmail.com> Approved-by: dakkar <dakkar@thenautilus.net>
This commit is contained in:
commit
071dd085c7
9 changed files with 78 additions and 100 deletions
|
|
@ -180,7 +180,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, inject, onMounted, ref, useTemplateRef, watch, provide } from 'vue';
|
||||
import { computed, inject, ref, useTemplateRef, watch, provide } from 'vue';
|
||||
import * as mfm from 'mfm-js';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { isLink } from '@@/js/is-link.js';
|
||||
|
|
@ -231,7 +231,7 @@ import { instance, isEnabledUrlPreview, policies } from '@/instance.js';
|
|||
import { focusPrev, focusNext } from '@/utility/focus.js';
|
||||
import { getAppearNote } from '@/utility/get-appear-note.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import { getPluginHandlers } from '@/plugin.js';
|
||||
import { setupNoteViewInterruptors } from '@/plugin.js';
|
||||
import { DI } from '@/di.js';
|
||||
import { useRouter } from '@/router.js';
|
||||
import SkMutedNote from '@/components/SkMutedNote.vue';
|
||||
|
|
@ -270,26 +270,6 @@ function noteclick(id: string) {
|
|||
}
|
||||
}
|
||||
|
||||
// plugin
|
||||
const noteViewInterruptors = getPluginHandlers('note_view_interruptor');
|
||||
if (noteViewInterruptors.length > 0) {
|
||||
onMounted(async () => {
|
||||
let result: Misskey.entities.Note | null = deepClone(note.value);
|
||||
for (const interruptor of noteViewInterruptors) {
|
||||
try {
|
||||
result = await interruptor.handler(result!) as Misskey.entities.Note | null;
|
||||
if (result === null) {
|
||||
isDeleted.value = true;
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
note.value = result as Misskey.entities.Note;
|
||||
});
|
||||
}
|
||||
|
||||
const isRenote = Misskey.note.isPureRenote(note.value);
|
||||
|
||||
const rootEl = useTemplateRef('rootEl');
|
||||
|
|
@ -394,6 +374,8 @@ const keymap = {
|
|||
},
|
||||
} as const satisfies Keymap;
|
||||
|
||||
setupNoteViewInterruptors(note, isDeleted);
|
||||
|
||||
provide(DI.mfmEmojiReactCallback, (reaction) => {
|
||||
sound.playMisskeySfx('reaction');
|
||||
misskeyApi('notes/reactions/create', {
|
||||
|
|
|
|||
|
|
@ -281,7 +281,7 @@ import { boostMenuItems, computeRenoteTooltip } from '@/utility/boost-quote.js';
|
|||
import { instance, isEnabledUrlPreview, policies } from '@/instance.js';
|
||||
import { getAppearNote } from '@/utility/get-appear-note.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import { getPluginHandlers } from '@/plugin.js';
|
||||
import { setupNoteViewInterruptors } from '@/plugin.js';
|
||||
import { DI } from '@/di.js';
|
||||
import SkMutedNote from '@/components/SkMutedNote.vue';
|
||||
import SkNoteTranslation from '@/components/SkNoteTranslation.vue';
|
||||
|
|
@ -300,26 +300,6 @@ const inChannel = inject('inChannel', null);
|
|||
|
||||
const note = ref(deepClone(props.note));
|
||||
|
||||
// plugin
|
||||
const noteViewInterruptors = getPluginHandlers('note_view_interruptor');
|
||||
if (noteViewInterruptors.length > 0) {
|
||||
onMounted(async () => {
|
||||
let result: Misskey.entities.Note | null = deepClone(note.value);
|
||||
for (const interruptor of noteViewInterruptors) {
|
||||
try {
|
||||
result = await interruptor.handler(result!) as Misskey.entities.Note | null;
|
||||
if (result === null) {
|
||||
isDeleted.value = true;
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
note.value = result as Misskey.entities.Note;
|
||||
});
|
||||
}
|
||||
|
||||
const isRenote = Misskey.note.isPureRenote(note.value);
|
||||
|
||||
const rootEl = useTemplateRef('rootEl');
|
||||
|
|
@ -355,6 +335,8 @@ const renoteTooltip = computeRenoteTooltip(appearNote);
|
|||
|
||||
const { muted, threadMuted, noteMuted } = checkMutes(appearNote);
|
||||
|
||||
setupNoteViewInterruptors(note, isDeleted);
|
||||
|
||||
watch(() => props.expandAllCws, (expandAllCws) => {
|
||||
if (expandAllCws !== showContent.value) showContent.value = expandAllCws;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ import MkCwButton from '@/components/MkCwButton.vue';
|
|||
import MkButton from '@/components/MkButton.vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import { setupNoteViewInterruptors } from '@/plugin.js';
|
||||
import { deepClone } from '@/utility/clone.js';
|
||||
|
||||
const props = defineProps<{
|
||||
note: Misskey.entities.Note & {
|
||||
|
|
@ -49,7 +51,13 @@ const props = defineProps<{
|
|||
const showContent = ref(prefer.s.uncollapseCW);
|
||||
const isDeleted = ref(false);
|
||||
|
||||
const mergedCW = computed(() => computeMergedCw(props.note));
|
||||
const note = ref(deepClone(props.note));
|
||||
|
||||
const mergedCW = computed(() => computeMergedCw(note.value));
|
||||
|
||||
if (!note.value.isSchedule) {
|
||||
setupNoteViewInterruptors(note, null);
|
||||
}
|
||||
|
||||
const emit = defineEmits<{
|
||||
(ev: 'editScheduleNote'): void;
|
||||
|
|
@ -63,7 +71,7 @@ async function deleteScheduleNote() {
|
|||
cancelText: i18n.ts.cancel,
|
||||
});
|
||||
if (canceled) return;
|
||||
await os.apiWithDialog('notes/schedule/delete', { noteId: props.note.id })
|
||||
await os.apiWithDialog('notes/schedule/delete', { noteId: note.value.id })
|
||||
.then(() => {
|
||||
isDeleted.value = true;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -115,6 +115,8 @@ import { useNoteCapture } from '@/use/use-note-capture.js';
|
|||
import SkMutedNote from '@/components/SkMutedNote.vue';
|
||||
import { instance, policies } from '@/instance';
|
||||
import { getAppearNote } from '@/utility/get-appear-note';
|
||||
import { setupNoteViewInterruptors } from '@/plugin.js';
|
||||
import { deepClone } from '@/utility/clone.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
note: Misskey.entities.Note;
|
||||
|
|
@ -129,7 +131,9 @@ const props = withDefaults(defineProps<{
|
|||
onDeleteCallback: undefined,
|
||||
});
|
||||
|
||||
const appearNote = computed(() => getAppearNote(props.note));
|
||||
const note = ref(deepClone(props.note));
|
||||
|
||||
const appearNote = computed(() => getAppearNote(note.value));
|
||||
|
||||
const canRenote = computed(() => ['public', 'home'].includes(appearNote.value.visibility) || appearNote.value.userId === $i?.id);
|
||||
|
||||
|
|
@ -158,13 +162,15 @@ const pleaseLoginContext = computed<OpenOnRemoteOptions>(() => ({
|
|||
|
||||
const currentClip = inject<Ref<Misskey.entities.Clip> | null>('currentClip', null);
|
||||
|
||||
setupNoteViewInterruptors(note, isDeleted);
|
||||
|
||||
async function addReplyTo(replyNote: Misskey.entities.Note) {
|
||||
replies.value.unshift(replyNote);
|
||||
appearNote.value.repliesCount += 1;
|
||||
}
|
||||
|
||||
async function removeReply(id: Misskey.entities.Note['id']) {
|
||||
const replyIdx = replies.value.findIndex(note => note.id === id);
|
||||
const replyIdx = replies.value.findIndex(reply => reply.id === id);
|
||||
if (replyIdx >= 0) {
|
||||
replies.value.splice(replyIdx, 1);
|
||||
appearNote.value.repliesCount -= 1;
|
||||
|
|
@ -250,11 +256,11 @@ function like(): void {
|
|||
}
|
||||
}
|
||||
|
||||
function undoReact(note): void {
|
||||
const oldReaction = note.myReaction;
|
||||
function undoReact(targetNote: Misskey.entities.Note): void {
|
||||
const oldReaction = targetNote.myReaction;
|
||||
if (!oldReaction) return;
|
||||
misskeyApi('notes/reactions/delete', {
|
||||
noteId: note.id,
|
||||
noteId: targetNote.id,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ Displays a note in the Sharkey style. Used to show the "main" note in a given co
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, inject, onMounted, ref, useTemplateRef, watch, provide } from 'vue';
|
||||
import { computed, inject, ref, useTemplateRef, watch, provide } from 'vue';
|
||||
import * as mfm from 'mfm-js';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { isLink } from '@@/js/is-link.js';
|
||||
|
|
@ -232,7 +232,7 @@ import { instance, isEnabledUrlPreview, policies } from '@/instance.js';
|
|||
import { focusPrev, focusNext } from '@/utility/focus.js';
|
||||
import { getAppearNote } from '@/utility/get-appear-note.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import { getPluginHandlers } from '@/plugin.js';
|
||||
import { setupNoteViewInterruptors } from '@/plugin.js';
|
||||
import { DI } from '@/di.js';
|
||||
import { useRouter } from '@/router.js';
|
||||
import SkMutedNote from '@/components/SkMutedNote.vue';
|
||||
|
|
@ -271,26 +271,6 @@ function noteclick(id: string) {
|
|||
}
|
||||
}
|
||||
|
||||
// plugin
|
||||
const noteViewInterruptors = getPluginHandlers('note_view_interruptor');
|
||||
if (noteViewInterruptors.length > 0) {
|
||||
onMounted(async () => {
|
||||
let result: Misskey.entities.Note | null = deepClone(note.value);
|
||||
for (const interruptor of noteViewInterruptors) {
|
||||
try {
|
||||
result = await interruptor.handler(result!) as Misskey.entities.Note | null;
|
||||
if (result === null) {
|
||||
isDeleted.value = true;
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
note.value = result as Misskey.entities.Note;
|
||||
});
|
||||
}
|
||||
|
||||
const isRenote = Misskey.note.isPureRenote(note.value);
|
||||
|
||||
const rootEl = useTemplateRef('rootEl');
|
||||
|
|
@ -395,6 +375,8 @@ const keymap = {
|
|||
},
|
||||
} as const satisfies Keymap;
|
||||
|
||||
setupNoteViewInterruptors(note, isDeleted);
|
||||
|
||||
provide(DI.mfmEmojiReactCallback, (reaction) => {
|
||||
sound.playMisskeySfx('reaction');
|
||||
misskeyApi('notes/reactions/create', {
|
||||
|
|
|
|||
|
|
@ -287,7 +287,7 @@ import { boostMenuItems, computeRenoteTooltip } from '@/utility/boost-quote.js';
|
|||
import { instance, isEnabledUrlPreview, policies } from '@/instance.js';
|
||||
import { getAppearNote } from '@/utility/get-appear-note.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import { getPluginHandlers } from '@/plugin.js';
|
||||
import { setupNoteViewInterruptors } from '@/plugin.js';
|
||||
import { DI } from '@/di.js';
|
||||
import SkMutedNote from '@/components/SkMutedNote.vue';
|
||||
import SkNoteTranslation from '@/components/SkNoteTranslation.vue';
|
||||
|
|
@ -306,26 +306,6 @@ const inChannel = inject('inChannel', null);
|
|||
|
||||
const note = ref(deepClone(props.note));
|
||||
|
||||
// plugin
|
||||
const noteViewInterruptors = getPluginHandlers('note_view_interruptor');
|
||||
if (noteViewInterruptors.length > 0) {
|
||||
onMounted(async () => {
|
||||
let result: Misskey.entities.Note | null = deepClone(note.value);
|
||||
for (const interruptor of noteViewInterruptors) {
|
||||
try {
|
||||
result = await interruptor.handler(result!) as Misskey.entities.Note | null;
|
||||
if (result === null) {
|
||||
isDeleted.value = true;
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
note.value = result as Misskey.entities.Note;
|
||||
});
|
||||
}
|
||||
|
||||
const isRenote = Misskey.note.isPureRenote(note.value);
|
||||
|
||||
const rootEl = useTemplateRef('rootEl');
|
||||
|
|
@ -362,6 +342,8 @@ const renoteTooltip = computeRenoteTooltip(appearNote);
|
|||
|
||||
const { muted, threadMuted, noteMuted } = checkMutes(appearNote);
|
||||
|
||||
setupNoteViewInterruptors(note, isDeleted);
|
||||
|
||||
watch(() => props.expandAllCws, (expandAllCws) => {
|
||||
if (expandAllCws !== showContent.value) showContent.value = expandAllCws;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ import MkNoteHeader from '@/components/MkNoteHeader.vue';
|
|||
import MkSubNoteContent from '@/components/MkSubNoteContent.vue';
|
||||
import MkCwButton from '@/components/MkCwButton.vue';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import { setupNoteViewInterruptors } from '@/plugin.js';
|
||||
import { deepClone } from '@/utility/clone.js';
|
||||
|
||||
const props = defineProps<{
|
||||
note: Misskey.entities.Note;
|
||||
|
|
@ -40,7 +42,11 @@ const props = defineProps<{
|
|||
|
||||
let showContent = ref(prefer.s.uncollapseCW);
|
||||
|
||||
const mergedCW = computed(() => computeMergedCw(props.note));
|
||||
const note = ref(deepClone(props.note));
|
||||
|
||||
const mergedCW = computed(() => computeMergedCw(note.value));
|
||||
|
||||
setupNoteViewInterruptors(note, null);
|
||||
|
||||
watch(() => props.expandAllCws, (expandAllCws) => {
|
||||
if (expandAllCws !== showContent.value) showContent.value = expandAllCws;
|
||||
|
|
|
|||
|
|
@ -127,6 +127,8 @@ import { useNoteCapture } from '@/use/use-note-capture.js';
|
|||
import SkMutedNote from '@/components/SkMutedNote.vue';
|
||||
import { instance, policies } from '@/instance';
|
||||
import { getAppearNote } from '@/utility/get-appear-note';
|
||||
import { setupNoteViewInterruptors } from '@/plugin.js';
|
||||
import { deepClone } from '@/utility/clone.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
note: Misskey.entities.Note;
|
||||
|
|
@ -146,7 +148,9 @@ const props = withDefaults(defineProps<{
|
|||
onDeleteCallback: undefined,
|
||||
});
|
||||
|
||||
const appearNote = computed(() => getAppearNote(props.note));
|
||||
const note = ref(deepClone(props.note));
|
||||
|
||||
const appearNote = computed(() => getAppearNote(note.value));
|
||||
|
||||
const canRenote = computed(() => ['public', 'home'].includes(appearNote.value.visibility) || appearNote.value.userId === $i?.id);
|
||||
const hideLine = computed(() => props.detail);
|
||||
|
|
@ -176,13 +180,15 @@ const pleaseLoginContext = computed<OpenOnRemoteOptions>(() => ({
|
|||
|
||||
const currentClip = inject<Ref<Misskey.entities.Clip> | null>('currentClip', null);
|
||||
|
||||
setupNoteViewInterruptors(note, isDeleted);
|
||||
|
||||
async function addReplyTo(replyNote: Misskey.entities.Note) {
|
||||
replies.value.unshift(replyNote);
|
||||
appearNote.value.repliesCount += 1;
|
||||
}
|
||||
|
||||
async function removeReply(id: Misskey.entities.Note['id']) {
|
||||
const replyIdx = replies.value.findIndex(note => note.id === id);
|
||||
const replyIdx = replies.value.findIndex(reply => reply.id === id);
|
||||
if (replyIdx >= 0) {
|
||||
replies.value.splice(replyIdx, 1);
|
||||
appearNote.value.repliesCount -= 1;
|
||||
|
|
@ -268,11 +274,11 @@ function like(): void {
|
|||
}
|
||||
}
|
||||
|
||||
function undoReact(note): void {
|
||||
const oldReaction = note.myReaction;
|
||||
function undoReact(targetNote: Misskey.entities.Note): void {
|
||||
const oldReaction = targetNote.myReaction;
|
||||
if (!oldReaction) return;
|
||||
misskeyApi('notes/reactions/delete', {
|
||||
noteId: note.id,
|
||||
noteId: targetNote.id,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { ref, defineAsyncComponent } from 'vue';
|
||||
import { ref, defineAsyncComponent, onMounted } from 'vue';
|
||||
import { Interpreter, Parser, utils, values } from '@syuilo/aiscript';
|
||||
import { compareVersions } from 'compare-versions';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
|
@ -15,6 +15,7 @@ import { misskeyApi } from '@/utility/misskey-api.js';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import { warningExternalWebsite } from '@/utility/warning-external-website.js';
|
||||
import { deepClone } from '@/utility/clone.js';
|
||||
|
||||
export type Plugin = {
|
||||
installId: string;
|
||||
|
|
@ -435,3 +436,26 @@ function createPluginEnv(opts: { plugin: Plugin; storageKey: string }): Record<s
|
|||
export function getPluginHandlers<K extends keyof HandlerDef>(type: K): HandlerDef[K][] {
|
||||
return pluginHandlers.filter((x): x is PluginHandler<K> => x.type === type).map(x => x.ctx);
|
||||
}
|
||||
|
||||
export function setupNoteViewInterruptors(note, isDeleted) {
|
||||
const noteViewInterruptors = getPluginHandlers('note_view_interruptor');
|
||||
if (noteViewInterruptors.length > 0) {
|
||||
onMounted(async () => {
|
||||
let result: Misskey.entities.Note | null = deepClone(note.value);
|
||||
for (const interruptor of noteViewInterruptors) {
|
||||
try {
|
||||
result = await interruptor.handler(result!) as Misskey.entities.Note | null;
|
||||
if (result === null) {
|
||||
if (isDeleted !== null) {
|
||||
isDeleted.value = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
note.value = result as Misskey.entities.Note;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue