summaryrefslogtreecommitdiff
path: root/packages/frontend/src/scripts/get-note-menu.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/frontend/src/scripts/get-note-menu.ts')
-rw-r--r--packages/frontend/src/scripts/get-note-menu.ts341
1 files changed, 341 insertions, 0 deletions
diff --git a/packages/frontend/src/scripts/get-note-menu.ts b/packages/frontend/src/scripts/get-note-menu.ts
new file mode 100644
index 0000000000..7656770894
--- /dev/null
+++ b/packages/frontend/src/scripts/get-note-menu.ts
@@ -0,0 +1,341 @@
+import { defineAsyncComponent, Ref, inject } from 'vue';
+import * as misskey from 'misskey-js';
+import { pleaseLogin } from './please-login';
+import { $i } from '@/account';
+import { i18n } from '@/i18n';
+import { instance } from '@/instance';
+import * as os from '@/os';
+import copyToClipboard from '@/scripts/copy-to-clipboard';
+import { url } from '@/config';
+import { noteActions } from '@/store';
+import { notePage } from '@/filters/note';
+
+export function getNoteMenu(props: {
+ note: misskey.entities.Note;
+ menuButton: Ref<HTMLElement>;
+ translation: Ref<any>;
+ translating: Ref<boolean>;
+ isDeleted: Ref<boolean>;
+ currentClipPage?: Ref<misskey.entities.Clip>;
+}) {
+ const isRenote = (
+ props.note.renote != null &&
+ props.note.text == null &&
+ props.note.fileIds.length === 0 &&
+ props.note.poll == null
+ );
+
+ const appearNote = isRenote ? props.note.renote as misskey.entities.Note : props.note;
+
+ function del(): void {
+ os.confirm({
+ type: 'warning',
+ text: i18n.ts.noteDeleteConfirm,
+ }).then(({ canceled }) => {
+ if (canceled) return;
+
+ os.api('notes/delete', {
+ noteId: appearNote.id,
+ });
+ });
+ }
+
+ function delEdit(): void {
+ os.confirm({
+ type: 'warning',
+ text: i18n.ts.deleteAndEditConfirm,
+ }).then(({ canceled }) => {
+ if (canceled) return;
+
+ os.api('notes/delete', {
+ noteId: appearNote.id,
+ });
+
+ os.post({ initialNote: appearNote, renote: appearNote.renote, reply: appearNote.reply, channel: appearNote.channel });
+ });
+ }
+
+ function toggleFavorite(favorite: boolean): void {
+ os.apiWithDialog(favorite ? 'notes/favorites/create' : 'notes/favorites/delete', {
+ noteId: appearNote.id,
+ });
+ }
+
+ function toggleThreadMute(mute: boolean): void {
+ os.apiWithDialog(mute ? 'notes/thread-muting/create' : 'notes/thread-muting/delete', {
+ noteId: appearNote.id,
+ });
+ }
+
+ function copyContent(): void {
+ copyToClipboard(appearNote.text);
+ os.success();
+ }
+
+ function copyLink(): void {
+ copyToClipboard(`${url}/notes/${appearNote.id}`);
+ os.success();
+ }
+
+ function togglePin(pin: boolean): void {
+ os.apiWithDialog(pin ? 'i/pin' : 'i/unpin', {
+ noteId: appearNote.id,
+ }, undefined, null, res => {
+ if (res.id === '72dab508-c64d-498f-8740-a8eec1ba385a') {
+ os.alert({
+ type: 'error',
+ text: i18n.ts.pinLimitExceeded,
+ });
+ }
+ });
+ }
+
+ async function clip(): Promise<void> {
+ const clips = await os.api('clips/list');
+ os.popupMenu([{
+ icon: 'ti ti-plus',
+ text: i18n.ts.createNew,
+ action: async () => {
+ const { canceled, result } = await os.form(i18n.ts.createNewClip, {
+ name: {
+ type: 'string',
+ label: i18n.ts.name,
+ },
+ description: {
+ type: 'string',
+ required: false,
+ multiline: true,
+ label: i18n.ts.description,
+ },
+ isPublic: {
+ type: 'boolean',
+ label: i18n.ts.public,
+ default: false,
+ },
+ });
+ if (canceled) return;
+
+ const clip = await os.apiWithDialog('clips/create', result);
+
+ os.apiWithDialog('clips/add-note', { clipId: clip.id, noteId: appearNote.id });
+ },
+ }, null, ...clips.map(clip => ({
+ text: clip.name,
+ action: () => {
+ os.promiseDialog(
+ os.api('clips/add-note', { clipId: clip.id, noteId: appearNote.id }),
+ null,
+ async (err) => {
+ if (err.id === '734806c4-542c-463a-9311-15c512803965') {
+ const confirm = await os.confirm({
+ type: 'warning',
+ text: i18n.t('confirmToUnclipAlreadyClippedNote', { name: clip.name }),
+ });
+ if (!confirm.canceled) {
+ os.apiWithDialog('clips/remove-note', { clipId: clip.id, noteId: appearNote.id });
+ if (props.currentClipPage?.value.id === clip.id) props.isDeleted.value = true;
+ }
+ } else {
+ os.alert({
+ type: 'error',
+ text: err.message + '\n' + err.id,
+ });
+ }
+ },
+ );
+ },
+ }))], props.menuButton.value, {
+ }).then(focus);
+ }
+
+ async function unclip(): Promise<void> {
+ os.apiWithDialog('clips/remove-note', { clipId: props.currentClipPage.value.id, noteId: appearNote.id });
+ props.isDeleted.value = true;
+ }
+
+ async function promote(): Promise<void> {
+ const { canceled, result: days } = await os.inputNumber({
+ title: i18n.ts.numberOfDays,
+ });
+
+ if (canceled) return;
+
+ os.apiWithDialog('admin/promo/create', {
+ noteId: appearNote.id,
+ expiresAt: Date.now() + (86400000 * days),
+ });
+ }
+
+ function share(): void {
+ navigator.share({
+ title: i18n.t('noteOf', { user: appearNote.user.name }),
+ text: appearNote.text,
+ url: `${url}/notes/${appearNote.id}`,
+ });
+ }
+ function notedetails(): void {
+ os.pageWindow(`/notes/${appearNote.id}`);
+ }
+ async function translate(): Promise<void> {
+ if (props.translation.value != null) return;
+ props.translating.value = true;
+ const res = await os.api('notes/translate', {
+ noteId: appearNote.id,
+ targetLang: localStorage.getItem('lang') || navigator.language,
+ });
+ props.translating.value = false;
+ props.translation.value = res;
+ }
+
+ let menu;
+ if ($i) {
+ const statePromise = os.api('notes/state', {
+ noteId: appearNote.id,
+ });
+
+ menu = [
+ ...(
+ props.currentClipPage?.value.userId === $i.id ? [{
+ icon: 'ti ti-backspace',
+ text: i18n.ts.unclip,
+ danger: true,
+ action: unclip,
+ }, null] : []
+ ), {
+ icon: 'ti ti-external-link',
+ text: i18n.ts.details,
+ action: notedetails,
+ }, {
+ icon: 'ti ti-copy',
+ text: i18n.ts.copyContent,
+ action: copyContent,
+ }, {
+ icon: 'ti ti-link',
+ text: i18n.ts.copyLink,
+ action: copyLink,
+ }, (appearNote.url || appearNote.uri) ? {
+ icon: 'ti ti-external-link',
+ text: i18n.ts.showOnRemote,
+ action: () => {
+ window.open(appearNote.url || appearNote.uri, '_blank');
+ },
+ } : undefined,
+ {
+ icon: 'ti ti-share',
+ text: i18n.ts.share,
+ action: share,
+ },
+ instance.translatorAvailable ? {
+ icon: 'ti ti-language-hiragana',
+ text: i18n.ts.translate,
+ action: translate,
+ } : undefined,
+ null,
+ statePromise.then(state => state.isFavorited ? {
+ icon: 'ti ti-star-off',
+ text: i18n.ts.unfavorite,
+ action: () => toggleFavorite(false),
+ } : {
+ icon: 'ti ti-star',
+ text: i18n.ts.favorite,
+ action: () => toggleFavorite(true),
+ }),
+ {
+ icon: 'ti ti-paperclip',
+ text: i18n.ts.clip,
+ action: () => clip(),
+ },
+ statePromise.then(state => state.isMutedThread ? {
+ icon: 'ti ti-message-off',
+ text: i18n.ts.unmuteThread,
+ action: () => toggleThreadMute(false),
+ } : {
+ icon: 'ti ti-message-off',
+ text: i18n.ts.muteThread,
+ action: () => toggleThreadMute(true),
+ }),
+ appearNote.userId === $i.id ? ($i.pinnedNoteIds || []).includes(appearNote.id) ? {
+ icon: 'ti ti-pinned-off',
+ text: i18n.ts.unpin,
+ action: () => togglePin(false),
+ } : {
+ icon: 'ti ti-pin',
+ text: i18n.ts.pin,
+ action: () => togglePin(true),
+ } : undefined,
+ /*
+ ...($i.isModerator || $i.isAdmin ? [
+ null,
+ {
+ icon: 'fas fa-bullhorn',
+ text: i18n.ts.promote,
+ action: promote
+ }]
+ : []
+ ),*/
+ ...(appearNote.userId !== $i.id ? [
+ null,
+ {
+ icon: 'ti ti-exclamation-circle',
+ text: i18n.ts.reportAbuse,
+ action: () => {
+ const u = appearNote.url || appearNote.uri || `${url}/notes/${appearNote.id}`;
+ os.popup(defineAsyncComponent(() => import('@/components/MkAbuseReportWindow.vue')), {
+ user: appearNote.user,
+ initialComment: `Note: ${u}\n-----\n`,
+ }, {}, 'closed');
+ },
+ }]
+ : []
+ ),
+ ...(appearNote.userId === $i.id || $i.isModerator || $i.isAdmin ? [
+ null,
+ appearNote.userId === $i.id ? {
+ icon: 'ti ti-edit',
+ text: i18n.ts.deleteAndEdit,
+ action: delEdit,
+ } : undefined,
+ {
+ icon: 'ti ti-trash',
+ text: i18n.ts.delete,
+ danger: true,
+ action: del,
+ }]
+ : []
+ )]
+ .filter(x => x !== undefined);
+ } else {
+ menu = [{
+ icon: 'ti ti-external-link',
+ text: i18n.ts.detailed,
+ action: openDetail,
+ }, {
+ icon: 'ti ti-copy',
+ text: i18n.ts.copyContent,
+ action: copyContent,
+ }, {
+ icon: 'ti ti-link',
+ text: i18n.ts.copyLink,
+ action: copyLink,
+ }, (appearNote.url || appearNote.uri) ? {
+ icon: 'ti ti-external-link',
+ text: i18n.ts.showOnRemote,
+ action: () => {
+ window.open(appearNote.url || appearNote.uri, '_blank');
+ },
+ } : undefined]
+ .filter(x => x !== undefined);
+ }
+
+ if (noteActions.length > 0) {
+ menu = menu.concat([null, ...noteActions.map(action => ({
+ icon: 'ti ti-plug',
+ text: action.title,
+ action: () => {
+ action.handler(appearNote);
+ },
+ }))]);
+ }
+
+ return menu;
+}