diff --git a/packages/backend/src/misc/is-quote.ts b/packages/backend/src/misc/is-quote.ts deleted file mode 100644 index 779f548b0..000000000 --- a/packages/backend/src/misc/is-quote.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Note } from '@/models/entities/note.js'; - -export default function(note: Note): boolean { - return note.renoteId != null && (note.text != null || note.hasPoll || (note.fileIds != null && note.fileIds.length > 0)); -} diff --git a/packages/backend/src/misc/renote.ts b/packages/backend/src/misc/renote.ts new file mode 100644 index 000000000..e4b8c06e1 --- /dev/null +++ b/packages/backend/src/misc/renote.ts @@ -0,0 +1,5 @@ +import { Note } from '@/models/entities/note.js'; + +export function isPureRenote(note: Note): boolean { + return note.renoteId != null && note.text == null && (renote.fileIds == null || renote.fileIds.length === 0) && !note.hasPoll; +} diff --git a/packages/backend/src/server/activitypub/outbox.ts b/packages/backend/src/server/activitypub/outbox.ts index fb631d3c7..a0f641855 100644 --- a/packages/backend/src/server/activitypub/outbox.ts +++ b/packages/backend/src/server/activitypub/outbox.ts @@ -15,6 +15,7 @@ import { makePaginationQuery } from '../api/common/make-pagination-query.js'; import { setResponseType } from '../activitypub.js'; import checkFetch from '@/remote/activitypub/check-fetch.js'; import { fetchMeta } from '@/misc/fetch-meta.js'; +import { isPureRenote } from '@/misc/renote.js'; export default async (ctx: Router.RouterContext) => { const verify = await checkFetch(ctx.req); @@ -113,10 +114,10 @@ export default async (ctx: Router.RouterContext) => { * @param note Note */ export async function packActivity(note: Note): Promise { - if (note.renoteId && note.text == null && !note.hasPoll && (note.fileIds == null || note.fileIds.length === 0)) { + if (isPureRenote(note)) { const renote = await Notes.findOneByOrFail({ id: note.renoteId }); return renderAnnounce(renote.uri ? renote.uri : `${config.url}/notes/${renote.id}`, note); + } else { + return renderCreate(await renderNote(note, false), note); } - - return renderCreate(await renderNote(note, false), note); } diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts index 2f3d47c12..38d2f9cef 100644 --- a/packages/backend/src/server/api/endpoints/notes/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/create.ts @@ -10,6 +10,7 @@ import { noteVisibilities } from '../../../../types.js'; import { ApiError } from '../../error.js'; import define from '../../define.js'; import { getNote } from '../../common/getters.js'; +import { isPureRenote } from '@/misc/renote.js'; export const meta = { tags: ['notes'], @@ -201,7 +202,7 @@ export default define(meta, paramDef, async (ps, user) => { throw e; }); - if (renote.renoteId && !renote.text && !renote.fileIds && !renote.hasPoll) { + if (isPureRenote(renote)) { throw new ApiError(meta.errors.cannotReRenote); } @@ -230,7 +231,7 @@ export default define(meta, paramDef, async (ps, user) => { throw e; }); - if (reply.renoteId && !reply.text && !reply.fileIds && !reply.hasPoll) { + if (isPureRenote(reply)) { throw new ApiError(meta.errors.cannotReplyToPureRenote); } diff --git a/packages/backend/src/services/note/delete.ts b/packages/backend/src/services/note/delete.ts index 496320016..54ba5c6cb 100644 --- a/packages/backend/src/services/note/delete.ts +++ b/packages/backend/src/services/note/delete.ts @@ -14,6 +14,7 @@ import { deliverToFollowers, deliverToUser } from '@/remote/activitypub/deliver- import { countSameRenotes } from '@/misc/count-same-renotes.js'; import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc.js'; import { deliverToRelays } from '../relay.js'; +import { isPureRenote } from '@/misc/renote.js'; /** * 投稿を削除します。 @@ -43,7 +44,7 @@ export default async function(user: { id: User['id']; uri: User['uri']; host: Us let renote: Note | null = null; // if deletd note is renote - if (note.renoteId && note.text == null && !note.hasPoll && (note.fileIds == null || note.fileIds.length === 0)) { + if (isPureRenote(note)) { renote = await Notes.findOneBy({ id: note.renoteId, }); diff --git a/packages/client/src/components/file-type-icon.vue b/packages/client/src/components/file-type-icon.vue deleted file mode 100644 index 11d28188c..000000000 --- a/packages/client/src/components/file-type-icon.vue +++ /dev/null @@ -1,15 +0,0 @@ - - - diff --git a/packages/client/src/components/form/textarea.vue b/packages/client/src/components/form/textarea.vue index e4bd26706..844d708b9 100644 --- a/packages/client/src/components/form/textarea.vue +++ b/packages/client/src/components/form/textarea.vue @@ -12,7 +12,7 @@ :readonly="readonly" :placeholder="placeholder" :pattern="pattern" - :autocomplete="autocomplete" + :autocomplete="autocomplete ? 'on' : 'off'" :spellcheck="spellcheck" @focus="focused = true" @blur="focused = false" @@ -62,34 +62,40 @@ const props = withDefaults(defineProps<{ manualSave: false, }); -const { modelValue, autofocus } = toRefs(props); +const { modelValue } = toRefs(props); // modelValue is read only, so a separate ref is needed. const v = $ref(modelValue.value); -const focused = $ref(false); -const changed = $ref(false); -const invalid = $ref(false); -const filled = computed(() => modelValue.value !== '' && modelValue.value != null); -const inputEl = $ref(null); +let focused = $ref(false); +let changed = $ref(false); +let invalid = $ref(false); +let inputEl: HTMLTextAreaElement | null = $ref(null); -const focus = () => inputEl.focus(); -const onInput = evt => { +const filled = computed(() => modelValue.value !== '' && modelValue.value != null); + +const focus = (): void => { + inputEl?.focus(); +}; + +const onInput = (evt: HTMLInputEvent): void => { changed = true; emit('change', evt); }; -const onKeydown = (evt: KeyboardEvent) => { + +const onKeydown = (evt: KeyboardEvent): void => { emit('keydown', evt); if (evt.code === 'Enter') { emit('enter'); } }; -const updated = () => { + +const updated = (): void => { changed = false; emit('update:modelValue', v); }; const debouncedUpdated = debounce(1000, updated); -watch(modelValue, newValue => { +watch(modelValue, () => { if (!props.manualSave) { if (props.debounce) { debouncedUpdated(); @@ -98,15 +104,12 @@ watch(modelValue, newValue => { } } - invalid = inputEl.validity.badInput; + invalid = inputEl?.validity.badInput ?? false; }); - onMounted(() => { nextTick(() => { - if (props.autofocus) { - inputEl.focus(); - } + if (props.autofocus) focus(); }); }); diff --git a/packages/client/src/components/image-viewer.vue b/packages/client/src/components/image-viewer.vue deleted file mode 100644 index 7bc88399e..000000000 --- a/packages/client/src/components/image-viewer.vue +++ /dev/null @@ -1,77 +0,0 @@ - - - - - diff --git a/packages/client/src/components/ui/hr.vue b/packages/client/src/components/ui/hr.vue deleted file mode 100644 index 0cb5b4887..000000000 --- a/packages/client/src/components/ui/hr.vue +++ /dev/null @@ -1,17 +0,0 @@ - - - - - diff --git a/packages/client/src/components/ui/modal.vue b/packages/client/src/components/ui/modal.vue index 9f3618367..2305a0279 100644 --- a/packages/client/src/components/ui/modal.vue +++ b/packages/client/src/components/ui/modal.vue @@ -31,7 +31,7 @@ type ModalTypes = 'popup' | 'dialog' | 'dialog:top' | 'drawer'; const props = withDefaults(defineProps<{ manualShowing?: boolean | null; anchor?: { x: string; y: string; }; - src?: HTMLElement | null; + src?: HTMLElement; preferType?: ModalTypes | 'auto'; zPriority?: 'low' | 'middle' | 'high'; noOverlap?: boolean; diff --git a/packages/client/src/directives/follow-append.ts b/packages/client/src/directives/follow-append.ts deleted file mode 100644 index b0e99628b..000000000 --- a/packages/client/src/directives/follow-append.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Directive } from 'vue'; -import { getScrollContainer, getScrollPosition } from '@/scripts/scroll'; - -export default { - mounted(src, binding, vn) { - if (binding.value === false) return; - - let isBottom = true; - - const container = getScrollContainer(src)!; - container.addEventListener('scroll', () => { - const pos = getScrollPosition(container); - const viewHeight = container.clientHeight; - const height = container.scrollHeight; - isBottom = (pos + viewHeight > height - 32); - }, { passive: true }); - container.scrollTop = container.scrollHeight; - - const ro = new ResizeObserver((entries, observer) => { - if (isBottom) { - const height = container.scrollHeight; - container.scrollTop = height; - } - }); - - ro.observe(src); - - // TODO: 新たにプロパティを作るのをやめMapを使う - src._ro_ = ro; - }, - - unmounted(src, binding, vn) { - if (src._ro_) src._ro_.unobserve(src); - } -} as Directive; diff --git a/packages/client/src/pages/emojis.category.vue b/packages/client/src/pages/emojis.category.vue index 6d915c584..9b4c38842 100644 --- a/packages/client/src/pages/emojis.category.vue +++ b/packages/client/src/pages/emojis.category.vue @@ -1,98 +1,46 @@ -