diff --git a/CHANGELOG_CHERRYPICK.md b/CHANGELOG_CHERRYPICK.md index 8443f28dd1..96eb84e62c 100644 --- a/CHANGELOG_CHERRYPICK.md +++ b/CHANGELOG_CHERRYPICK.md @@ -16,6 +16,7 @@ - 클라이언트: Enter 키를 눌러 보내기 옵션 추가 - 클라이언트: 서버와 연결이 끊어졌을 때 경고를 표시하지 않는 옵션 추가 - 클라이언트: (friendly) 모바일 환경에서 서버와 연결이 끊어졌을 때 표시되는 경고창의 UI 개선 +- 클라이언트: 미디어 우클릭 방지 기능 추가 ## 12.x.x-cp-2.x.x (unreleased)_legacy diff --git a/locales/en-US.yml b/locales/en-US.yml index 35111d9804..676cae3d6c 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -1,5 +1,6 @@ --- _lang_: "English" +disableRightClick: "Prohibit right click" useEnterToSend: "Press Enter to send" useEnterToSendDescription: "When the option is enabled, you can use the Shift+Enter key for line break." headlineMisskey: "A network connected by notes" diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 681dac1c8d..45025e5569 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1,5 +1,6 @@ _lang_: "日本語" +disableRightClick: "右クリックを禁止" useEnterToSend: "Enterキーを押して送信" useEnterToSendDescription: "オプションを有効にすると、行替えはShift+Enterキーでできます。" headlineMisskey: "ノートでつながるネットワーク" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index be5bb8fb1c..f4ab2bed07 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -1,5 +1,6 @@ --- _lang_: "한국어" +disableRightClick: "우클릭 방지" useEnterToSend: "Enter 키를 눌러 보내기" useEnterToSendDescription: "옵션을 활성화하면 줄 바꿈은 Shift + Enter 키로 할 수 있어요." headlineMisskey: "노트로 연결되는 네트워크" diff --git a/packages/backend/migration/1629387925000-disableRightClick.js b/packages/backend/migration/1629387925000-disableRightClick.js new file mode 100644 index 0000000000..24dd4fef74 --- /dev/null +++ b/packages/backend/migration/1629387925000-disableRightClick.js @@ -0,0 +1,13 @@ + + +export class disableRightClick1629387925000 { + constructor() { + this.name = 'disableRightClick1629387925000'; + } + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "note" ADD "disableRightClick" boolean NOT NULL DEFAULT false`); + } + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "note" DROP COLUMN "disableRIghtClick"`); + } +} diff --git a/packages/backend/src/models/entities/note.ts b/packages/backend/src/models/entities/note.ts index 0ffeb85f69..566b42c7a9 100644 --- a/packages/backend/src/models/entities/note.ts +++ b/packages/backend/src/models/entities/note.ts @@ -86,6 +86,11 @@ export class Note { }) public localOnly: boolean; + @Column('boolean', { + default: false, + }) + public disableRightClick: boolean; + @Column('smallint', { default: 0, }) diff --git a/packages/backend/src/models/repositories/note.ts b/packages/backend/src/models/repositories/note.ts index 3fefab0319..70cde225bc 100644 --- a/packages/backend/src/models/repositories/note.ts +++ b/packages/backend/src/models/repositories/note.ts @@ -234,6 +234,7 @@ export const NoteRepository = db.getRepository(Note).extend({ visibility: note.visibility, localOnly: note.localOnly || undefined, visibleUserIds: note.visibility === 'specified' ? note.visibleUserIds : undefined, + disableRightClick: note.disableRightClick || undefined, renoteCount: note.renoteCount, repliesCount: note.repliesCount, reactions: convertLegacyReactions(note.reactions), diff --git a/packages/backend/src/models/schema/note.ts b/packages/backend/src/models/schema/note.ts index cdf4b9a544..53691ebe25 100644 --- a/packages/backend/src/models/schema/note.ts +++ b/packages/backend/src/models/schema/note.ts @@ -52,6 +52,10 @@ export const packedNoteSchema = { optional: true, nullable: true, ref: 'Note', }, + disableRightClick: { + type: 'boolean', + optional: true, nullable: false, + }, isHidden: { type: 'boolean', optional: true, nullable: false, diff --git a/packages/backend/src/remote/activitypub/models/note.ts b/packages/backend/src/remote/activitypub/models/note.ts index 5d63f2605a..490235718b 100644 --- a/packages/backend/src/remote/activitypub/models/note.ts +++ b/packages/backend/src/remote/activitypub/models/note.ts @@ -253,6 +253,7 @@ export async function createNote(value: string | IObject, resolver?: Resolver, s cw, text, localOnly: false, + disableRightClick: false, visibility, visibleUsers, apMentions, diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts index a133294169..8f6a3e8dce 100644 --- a/packages/backend/src/server/api/endpoints/notes/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/create.ts @@ -90,6 +90,7 @@ export const paramDef = { text: { type: 'string', maxLength: MAX_NOTE_TEXT_LENGTH, nullable: true }, cw: { type: 'string', nullable: true, maxLength: 100 }, localOnly: { type: 'boolean', default: false }, + disableRightClick: { type: 'boolean', default: false }, noExtractMentions: { type: 'boolean', default: false }, noExtractHashtags: { type: 'boolean', default: false }, noExtractEmojis: { type: 'boolean', default: false }, @@ -261,6 +262,7 @@ export default define(meta, paramDef, async (ps, user) => { renote, cw: ps.cw, localOnly: ps.localOnly, + disableRightClick: ps.disableRightClick, visibility: ps.visibility, visibleUsers, channel, diff --git a/packages/backend/src/services/note/create.ts b/packages/backend/src/services/note/create.ts index e2bf9d5b59..da9b86317d 100644 --- a/packages/backend/src/services/note/create.ts +++ b/packages/backend/src/services/note/create.ts @@ -114,6 +114,7 @@ type Option = { files?: DriveFile[] | null; poll?: IPoll | null; localOnly?: boolean | null; + disableRightClick?: boolean | null; cw?: string | null; visibility?: string; visibleUsers?: MinimumUser[] | null; @@ -146,6 +147,7 @@ export default async (user: { id: User['id']; username: User['username']; host: if (data.createdAt == null) data.createdAt = new Date(); if (data.visibility == null) data.visibility = 'public'; if (data.localOnly == null) data.localOnly = false; + if (data.disableRightClick == null) data.disableRightClick = false; if (data.channel != null) data.visibility = 'public'; if (data.channel != null) data.visibleUsers = []; if (data.channel != null) data.localOnly = true; @@ -520,6 +522,7 @@ async function insertNote(user: { id: User['id']; host: User['host']; }, data: O emojis, userId: user.id, localOnly: data.localOnly!, + disableRightClick: data.disableRightClick!, visibility: data.visibility as any, visibleUserIds: data.visibility === 'specified' ? data.visibleUsers diff --git a/packages/client/src/components/note-detailed.vue b/packages/client/src/components/note-detailed.vue index f590c640da..e248c788fc 100644 --- a/packages/client/src/components/note-detailed.vue +++ b/packages/client/src/components/note-detailed.vue @@ -67,7 +67,8 @@
- + +
diff --git a/packages/client/src/components/note.vue b/packages/client/src/components/note.vue index 19ac338c3d..f493f48452 100644 --- a/packages/client/src/components/note.vue +++ b/packages/client/src/components/note.vue @@ -56,7 +56,8 @@
- + +
diff --git a/packages/client/src/components/post-form.vue b/packages/client/src/components/post-form.vue index c7d329228c..038d06a75d 100644 --- a/packages/client/src/components/post-form.vue +++ b/packages/client/src/components/post-form.vue @@ -53,6 +53,7 @@ + @@ -149,6 +150,7 @@ let quoteId = $ref(null); let hasNotSpecifiedMentions = $ref(false); let recentHashtags = $ref(JSON.parse(localStorage.getItem('hashtags') || '[]')); let imeText = $ref(''); +let disableRightClick = $ref(false); const typing = throttle(3000, () => { if (props.channel) { @@ -294,6 +296,7 @@ function watchForDraft() { watch($$(text), () => saveDraft()); watch($$(useCw), () => saveDraft()); watch($$(cw), () => saveDraft()); + watch($$(disableRightClick), () => saveDraft()); watch($$(poll), () => saveDraft()); watch($$(files), () => saveDraft(), { deep: true }); watch($$(visibility), () => saveDraft()); @@ -542,6 +545,7 @@ function saveDraft() { text: text, useCw: useCw, cw: cw, + disableRightClick: disableRightClick, visibility: visibility, localOnly: localOnly, files: files, @@ -572,6 +576,7 @@ async function post() { localOnly: localOnly, visibility: visibility, visibleUserIds: visibility === 'specified' ? visibleUsers.map(u => u.id) : undefined, + disableRightClick: disableRightClick, }; if (withHashtags && hashtags && hashtags.trim() !== '') { @@ -682,6 +687,7 @@ onMounted(() => { text = draft.data.text; useCw = draft.data.useCw; cw = draft.data.cw; + disableRightClick = draft.data.disableRightClick; visibility = draft.data.visibility; localOnly = draft.data.localOnly; files = (draft.data.files || []).filter(draftFile => draftFile); @@ -709,6 +715,7 @@ onMounted(() => { visibility = init.visibility; localOnly = init.localOnly; quoteId = init.renote ? init.renote.id : null; + disableRightClick = init.disableRightClick != null; } nextTick(() => watchForDraft()); diff --git a/packages/client/src/components/sub-note-content.vue b/packages/client/src/components/sub-note-content.vue index 25ab883f40..7571979f32 100644 --- a/packages/client/src/components/sub-note-content.vue +++ b/packages/client/src/components/sub-note-content.vue @@ -9,6 +9,7 @@
({{ $t('withNFiles', { n: note.files.length }) }}) +