-
+
+
-
-
diff --git a/packages/frontend/src/components/MkPoll.vue b/packages/frontend/src/components/MkPoll.vue
index 2d3ec45bca..359ee08812 100644
--- a/packages/frontend/src/components/MkPoll.vue
+++ b/packages/frontend/src/components/MkPoll.vue
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
- -
+
-
@@ -40,7 +40,9 @@ import { i18n } from '@/i18n.js';
const props = defineProps<{
noteId: string;
- poll: NonNullable;
+ multiple: NonNullable['multiple'];
+ expiresAt: NonNullable['expiresAt'];
+ choices: NonNullable['choices'];
readOnly?: boolean;
emojiUrls?: Record;
author?: Misskey.entities.UserLite;
@@ -48,9 +50,9 @@ const props = defineProps<{
const remaining = ref(-1);
-const total = computed(() => sum(props.poll.choices.map(x => x.votes)));
+const total = computed(() => sum(props.choices.map(x => x.votes)));
const closed = computed(() => remaining.value === 0);
-const isVoted = computed(() => !props.poll.multiple && props.poll.choices.some(c => c.isVoted));
+const isVoted = computed(() => !props.multiple && props.choices.some(c => c.isVoted));
const timer = computed(() => i18n.tsx._poll[
remaining.value >= 86400 ? 'remainingDays' :
remaining.value >= 3600 ? 'remainingHours' :
@@ -70,9 +72,9 @@ const pleaseLoginContext = computed(() => ({
}));
// 期限付きアンケート
-if (props.poll.expiresAt) {
+if (props.expiresAt) {
const tick = () => {
- remaining.value = Math.floor(Math.max(new Date(props.poll.expiresAt!).getTime() - Date.now(), 0) / 1000);
+ remaining.value = Math.floor(Math.max(new Date(props.expiresAt!).getTime() - Date.now(), 0) / 1000);
if (remaining.value === 0) {
showResult.value = true;
}
@@ -91,7 +93,7 @@ const vote = async (id) => {
const { canceled } = await os.confirm({
type: 'question',
- text: i18n.tsx.voteConfirm({ choice: props.poll.choices[id].text }),
+ text: i18n.tsx.voteConfirm({ choice: props.choices[id].text }),
});
if (canceled) return;
@@ -99,7 +101,7 @@ const vote = async (id) => {
noteId: props.noteId,
choice: id,
});
- if (!showResult.value) showResult.value = !props.poll.multiple;
+ if (!showResult.value) showResult.value = !props.multiple;
};
diff --git a/packages/frontend/src/components/MkPopupMenu.vue b/packages/frontend/src/components/MkPopupMenu.vue
index 232cc005e1..4942ffe232 100644
--- a/packages/frontend/src/components/MkPopupMenu.vue
+++ b/packages/frontend/src/components/MkPopupMenu.vue
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
-
+
@@ -19,7 +19,7 @@ defineProps<{
items: MenuItem[];
align?: 'center' | string;
width?: number;
- src?: HTMLElement | null;
+ anchorElement?: HTMLElement | null;
returnFocusTo?: HTMLElement | null;
}>();
diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue
index 1b96dec7e2..ce98078412 100644
--- a/packages/frontend/src/components/MkPostForm.vue
+++ b/packages/frontend/src/components/MkPostForm.vue
@@ -71,7 +71,7 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ maxTextLength - textLength }}
-
+
@@ -120,14 +120,13 @@ import { formatTimeString } from '@/utility/format-time-string.js';
import { Autocomplete } from '@/utility/autocomplete.js';
import * as os from '@/os.js';
import { misskeyApi } from '@/utility/misskey-api.js';
-import { selectFiles } from '@/utility/select-file.js';
+import { selectFiles } from '@/utility/drive.js';
import { store } from '@/store.js';
import MkInfo from '@/components/MkInfo.vue';
import { i18n } from '@/i18n.js';
import { instance } from '@/instance.js';
import { ensureSignin, notesCount, incNotesCount } from '@/i.js';
import { getAccounts, openAccountMenu as openAccountMenu_ } from '@/accounts.js';
-import { uploadFile } from '@/utility/upload.js';
import { deepClone } from '@/utility/clone.js';
import MkRippleEffect from '@/components/MkRippleEffect.vue';
import { miLocalStorage } from '@/local-storage.js';
@@ -138,6 +137,7 @@ import { prefer } from '@/preferences.js';
import { getPluginHandlers } from '@/plugin.js';
import { DI } from '@/di.js';
import { globalEvents } from '@/events.js';
+import { checkDragDataType, getDragData } from '@/drag-and-drop.js';
const $i = ensureSignin();
@@ -459,18 +459,6 @@ function updateFileName(file, name) {
files.value[files.value.findIndex(x => x.id === file.id)].name = name;
}
-function replaceFile(file: Misskey.entities.DriveFile, newFile: Misskey.entities.DriveFile): void {
- files.value[files.value.findIndex(x => x.id === file.id)] = newFile;
-}
-
-function upload(file: File, name?: string): void {
- if (props.mock) return;
-
- uploadFile(file, prefer.s.uploadFolder, name).then(res => {
- files.value.push(res);
- });
-}
-
function setVisibility() {
if (props.channel) {
visibility.value = 'public';
@@ -482,7 +470,7 @@ function setVisibility() {
currentVisibility: visibility.value,
isSilenced: $i.isSilenced,
localOnly: localOnly.value,
- src: visibilityButton.value,
+ anchorElement: visibilityButton.value,
...(props.reply ? { isReplyVisibilitySpecified: props.reply.visibility === 'specified' } : {}),
}, {
changeVisibility: v => {
@@ -651,16 +639,25 @@ async function onPaste(ev: ClipboardEvent) {
if (props.mock) return;
if (!ev.clipboardData) return;
+ let pastedFiles: File[] = [];
for (const { item, i } of Array.from(ev.clipboardData.items, (data, x) => ({ item: data, i: x }))) {
if (item.kind === 'file') {
const file = item.getAsFile();
if (!file) continue;
const lio = file.name.lastIndexOf('.');
const ext = lio >= 0 ? file.name.slice(lio) : '';
- const formatted = `${formatTimeString(new Date(file.lastModified), pastedFileName).replace(/{{number}}/g, `${i + 1}`)}${ext}`;
- upload(file, formatted);
+ const formattedName = `${formatTimeString(new Date(file.lastModified), pastedFileName).replace(/{{number}}/g, `${i + 1}`)}${ext}`;
+ const renamedFile = new File([file], formattedName, { type: file.type });
+ pastedFiles.push(renamedFile);
}
}
+ if (pastedFiles.length > 0) {
+ ev.preventDefault();
+ os.launchUploader(pastedFiles, {}).then(driveFiles => {
+ files.value.push(...driveFiles);
+ });
+ return;
+ }
const paste = ev.clipboardData.getData('text');
@@ -693,7 +690,9 @@ async function onPaste(ev: ClipboardEvent) {
const fileName = formatTimeString(new Date(), pastedFileName).replace(/{{number}}/g, '0');
const file = new File([paste], `${fileName}.txt`, { type: 'text/plain' });
- upload(file, `${fileName}.txt`);
+ os.launchUploader([file], {}).then(driveFiles => {
+ files.value.push(...driveFiles);
+ });
});
}
}
@@ -701,8 +700,7 @@ async function onPaste(ev: ClipboardEvent) {
function onDragover(ev) {
if (!ev.dataTransfer.items[0]) return;
const isFile = ev.dataTransfer.items[0].kind === 'file';
- const isDriveFile = ev.dataTransfer.types[0] === _DATA_TRANSFER_DRIVE_FILE_;
- if (isFile || isDriveFile) {
+ if (isFile || checkDragDataType(ev, ['driveFiles'])) {
ev.preventDefault();
draghover.value = true;
switch (ev.dataTransfer.effectAllowed) {
@@ -738,16 +736,19 @@ function onDrop(ev: DragEvent): void {
// ファイルだったら
if (ev.dataTransfer && ev.dataTransfer.files.length > 0) {
ev.preventDefault();
- for (const x of Array.from(ev.dataTransfer.files)) upload(x);
+ os.launchUploader(Array.from(ev.dataTransfer.files), {}).then(driveFiles => {
+ files.value.push(...driveFiles);
+ });
return;
}
//#region ドライブのファイル
- const driveFile = ev.dataTransfer?.getData(_DATA_TRANSFER_DRIVE_FILE_);
- if (driveFile != null && driveFile !== '') {
- const file = JSON.parse(driveFile);
- files.value.push(file);
- ev.preventDefault();
+ {
+ const droppedData = getDragData(ev, 'driveFiles');
+ if (droppedData != null) {
+ files.value.push(...droppedData);
+ ev.preventDefault();
+ }
}
//#endregion
}
@@ -884,12 +885,15 @@ async function post(ev?: MouseEvent) {
}
posting.value = true;
- misskeyApi('notes/create', postData, token).then(() => {
+ misskeyApi('notes/create', postData, token).then((res) => {
if (props.freezeAfterPosted) {
posted.value = true;
} else {
clear();
}
+
+ globalEvents.emit('notePosted', res.createdNote);
+
nextTick(() => {
deleteDraft();
emit('posted');
diff --git a/packages/frontend/src/components/MkPostFormAttaches.vue b/packages/frontend/src/components/MkPostFormAttaches.vue
index e8404cbd4f..dd594ef7f1 100644
--- a/packages/frontend/src/components/MkPostFormAttaches.vue
+++ b/packages/frontend/src/components/MkPostFormAttaches.vue
@@ -43,6 +43,7 @@ import { misskeyApi } from '@/utility/misskey-api.js';
import { i18n } from '@/i18n.js';
import { prefer } from '@/preferences.js';
import { DI } from '@/di.js';
+import { globalEvents } from '@/events.js';
const Sortable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default));
@@ -58,7 +59,6 @@ const emit = defineEmits<{
(ev: 'detach', id: string): void;
(ev: 'changeSensitive', file: Misskey.entities.DriveFile, isSensitive: boolean): void;
(ev: 'changeName', file: Misskey.entities.DriveFile, newName: string): void;
- (ev: 'replaceFile', file: Misskey.entities.DriveFile, newFile: Misskey.entities.DriveFile): void;
}>();
let menuShowing = false;
@@ -82,12 +82,13 @@ async function detachAndDeleteMedia(file: Misskey.entities.DriveFile) {
type: 'warning',
text: i18n.tsx.driveFileDeleteConfirm({ name: file.name }),
});
-
if (canceled) return;
- os.apiWithDialog('drive/files/delete', {
+ await os.apiWithDialog('drive/files/delete', {
fileId: file.id,
});
+
+ globalEvents.emit('driveFilesDeleted', [file]);
}
function toggleSensitive(file) {
@@ -142,13 +143,6 @@ async function describe(file: Misskey.entities.DriveFile) {
});
}
-async function crop(file: Misskey.entities.DriveFile): Promise {
- if (mock) return;
-
- const newFile = await os.cropImage(file, { aspectRatio: NaN });
- emit('replaceFile', file, newFile);
-}
-
function showFileMenu(file: Misskey.entities.DriveFile, ev: MouseEvent | KeyboardEvent): void {
if (menuShowing) return;
@@ -172,10 +166,6 @@ function showFileMenu(file: Misskey.entities.DriveFile, ev: MouseEvent | Keyboar
if (isImage) {
menuItems.push({
- text: i18n.ts.cropImage,
- icon: 'ti ti-crop',
- action: () : void => { crop(file); },
- }, {
text: i18n.ts.preview,
icon: 'ti ti-photo-search',
action: () => {
diff --git a/packages/frontend/src/components/MkPreview.vue b/packages/frontend/src/components/MkPreview.vue
index d8dfbd1655..6c7bf6be6b 100644
--- a/packages/frontend/src/components/MkPreview.vue
+++ b/packages/frontend/src/components/MkPreview.vue
@@ -18,8 +18,8 @@ SPDX-License-Identifier: AGPL-3.0-only
Pleroma
- This is
- the button
+ This is
+ the button