Merge remote-tracking branch 'misskey-original/develop' into develop
# Conflicts: # locales/en-US.yml # locales/index.d.ts # locales/ja-JP.yml # package.json # packages/backend/src/server/api/endpoints/notes/create.ts # packages/frontend/src/components/MkDrive.file.vue # packages/frontend/src/components/MkNote.vue # packages/frontend/src/components/MkNoteHeader.vue # packages/frontend/src/components/MkPostForm.vue # packages/frontend/src/components/MkReactionsViewer.reaction.vue # packages/frontend/src/components/MkUserSetupDialog.vue # packages/frontend/src/pages/timeline.tutorial.vue # packages/frontend/src/pages/timeline.vue # packages/misskey-js/etc/misskey-js.api.md
This commit is contained in:
commit
cb1005811d
106 changed files with 2036 additions and 963 deletions
|
|
@ -100,7 +100,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {inject, watch, nextTick, onMounted, defineAsyncComponent, computed, ref} from 'vue';
|
||||
import { inject, watch, nextTick, onMounted, defineAsyncComponent , computed, ref , provide } from 'vue';
|
||||
import * as mfm from 'mfm-js';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import insertTextAtCursor from 'insert-text-at-cursor';
|
||||
|
|
@ -139,31 +139,38 @@ let gamingType = computed(defaultStore.makeGetterSetter('gamingType'));
|
|||
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
reply?: Misskey.entities.Note;
|
||||
renote?: Misskey.entities.Note;
|
||||
channel?: Misskey.entities.Channel; // TODO
|
||||
mention?: Misskey.entities.User;
|
||||
specified?: Misskey.entities.User;
|
||||
initialText?: string;
|
||||
initialVisibility?: (typeof Misskey.noteVisibilities)[number];
|
||||
initialFiles?: Misskey.entities.DriveFile[];
|
||||
initialLocalOnly?: boolean;
|
||||
initialVisibleUsers?: Misskey.entities.User[];
|
||||
initialNote?: Misskey.entities.Note;
|
||||
instant?: boolean;
|
||||
fixed?: boolean;
|
||||
autofocus?: boolean;
|
||||
freezeAfterPosted?: boolean;
|
||||
updateMode?: boolean;
|
||||
reply?: Misskey.entities.Note;
|
||||
renote?: Misskey.entities.Note;
|
||||
channel?: Misskey.entities.Channel; // TODO
|
||||
mention?: Misskey.entities.User;
|
||||
specified?: Misskey.entities.User;
|
||||
initialText?: string;
|
||||
initialVisibility?: (typeof Misskey.noteVisibilities)[number];
|
||||
initialFiles?: Misskey.entities.DriveFile[];
|
||||
initialLocalOnly?: boolean;
|
||||
initialVisibleUsers?: Misskey.entities.User[];
|
||||
initialNote?: Misskey.entities.Note;
|
||||
instant?: boolean;
|
||||
fixed?: boolean;
|
||||
autofocus?: boolean;
|
||||
freezeAfterPosted?: boolean;
|
||||
mock?: boolean;
|
||||
updateMode?: boolean;
|
||||
}>(), {
|
||||
initialVisibleUsers: () => [],
|
||||
autofocus: true,
|
||||
mock: false,
|
||||
});
|
||||
|
||||
provide('mock', props.mock);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(ev: 'posted'): void;
|
||||
(ev: 'cancel'): void;
|
||||
(ev: 'esc'): void;
|
||||
|
||||
// Mock用
|
||||
(ev: 'fileChangeSensitive', fileId: string, to: boolean): void;
|
||||
}>();
|
||||
|
||||
const textareaEl = $shallowRef<HTMLTextAreaElement | null>(null);
|
||||
|
|
@ -251,7 +258,7 @@ const maxTextLength = $computed((): number => {
|
|||
});
|
||||
|
||||
const canPost = $computed((): boolean => {
|
||||
return !posting && !posted &&
|
||||
return !props.mock && !posting && !posted &&
|
||||
(1 <= textLength || 1 <= files.length || !!poll || !!props.renote) &&
|
||||
(textLength <= maxTextLength) &&
|
||||
(!poll || poll.choices.length >= 2);
|
||||
|
|
@ -304,6 +311,10 @@ if (props.reply && props.reply.text != null) {
|
|||
}
|
||||
}
|
||||
|
||||
if ($i?.isSilenced && visibility === 'public') {
|
||||
visibility = 'home';
|
||||
}
|
||||
|
||||
if (props.channel) {
|
||||
visibility = 'public';
|
||||
localOnly = true; // TODO: チャンネルが連合するようになった折には消す
|
||||
|
|
@ -408,7 +419,7 @@ function focus() {
|
|||
}
|
||||
|
||||
function chooseFileFrom(ev) {
|
||||
selectFiles(ev.currentTarget ?? ev.target, i18n.ts.attachFile).then(files_ => {
|
||||
if (props.mock) return;selectFiles(ev.currentTarget ?? ev.target, i18n.ts.attachFile).then(files_ => {
|
||||
for (const file of files_) {
|
||||
files.push(file);
|
||||
}
|
||||
|
|
@ -420,7 +431,10 @@ function detachFile(id) {
|
|||
}
|
||||
|
||||
function updateFileSensitive(file, sensitive) {
|
||||
files[files.findIndex(x => x.id === file.id)].isSensitive = sensitive;
|
||||
if (props.mock) {
|
||||
emit('fileChangeSensitive', file.id, sensitive);
|
||||
}
|
||||
files[files.findIndex(x => x.id === file.id)].isSensitive = sensitive;
|
||||
}
|
||||
|
||||
function updateFileName(file, name) {
|
||||
|
|
@ -432,7 +446,7 @@ function replaceFile(file: Misskey.entities.DriveFile, newFile: Misskey.entities
|
|||
}
|
||||
|
||||
function upload(file: File, name?: string): void {
|
||||
uploadFile(file, defaultStore.state.uploadFolder, name).then(res => {
|
||||
if (props.mock) return;uploadFile(file, defaultStore.state.uploadFolder, name).then(res => {
|
||||
files.push(res);
|
||||
});
|
||||
}
|
||||
|
|
@ -446,7 +460,7 @@ function setVisibility() {
|
|||
|
||||
os.popup(defineAsyncComponent(() => import('@/components/MkVisibilityPicker.vue')), {
|
||||
currentVisibility: visibility,
|
||||
localOnly: localOnly,
|
||||
isSilenced: $i?.isSilenced,localOnly: localOnly,
|
||||
src: visibilityButton,
|
||||
}, {
|
||||
changeVisibility: v => {
|
||||
|
|
@ -557,7 +571,7 @@ function onCompositionEnd(ev: CompositionEvent) {
|
|||
}
|
||||
|
||||
async function onPaste(ev: ClipboardEvent) {
|
||||
for (const { item, i } of Array.from(ev.clipboardData.items, (item, i) => ({ item, i }))) {
|
||||
if (props.mock) return;for (const { item, i } of Array.from(ev.clipboardData.items, (item, i) => ({ item, i }))) {
|
||||
if (item.kind === 'file') {
|
||||
const file = item.getAsFile();
|
||||
const lio = file.name.lastIndexOf('.');
|
||||
|
|
@ -641,7 +655,7 @@ function onDrop(ev): void {
|
|||
}
|
||||
|
||||
function saveDraft() {
|
||||
if (props.instant) return;
|
||||
if (props.instant || props.mock) return;
|
||||
|
||||
const draftData = JSON.parse(miLocalStorage.getItem('drafts') ?? '{}');
|
||||
|
||||
|
|
@ -670,7 +684,13 @@ function deleteDraft() {
|
|||
}
|
||||
|
||||
async function post(ev?: MouseEvent) {
|
||||
if (ev) {
|
||||
if (useCw && (cw == null || cw.trim() === '')) {
|
||||
os.alert({
|
||||
type: 'error',
|
||||
text: i18n.ts.cwNotationRequired,
|
||||
});
|
||||
return;
|
||||
}if (ev) {
|
||||
const el = ev.currentTarget ?? ev.target;
|
||||
const rect = el.getBoundingClientRect();
|
||||
const x = rect.left + (el.offsetWidth / 2);
|
||||
|
|
@ -678,7 +698,7 @@ async function post(ev?: MouseEvent) {
|
|||
os.popup(MkRippleEffect, { x, y }, {}, 'end');
|
||||
}
|
||||
|
||||
const annoying =
|
||||
if (props.mock) return;const annoying =
|
||||
text.includes('$[x2') ||
|
||||
text.includes('$[x3') ||
|
||||
text.includes('$[x4') ||
|
||||
|
|
@ -850,7 +870,7 @@ function showActions(ev) {
|
|||
let postAccount = $ref<Misskey.entities.UserDetailed | null>(null);
|
||||
|
||||
function openAccountMenu(ev: MouseEvent) {
|
||||
openAccountMenu_({
|
||||
if (props.mock) return;openAccountMenu_({
|
||||
withExtraOperation: false,
|
||||
includeCurrentAccount: true,
|
||||
active: postAccount != null ? postAccount.id : $i.id,
|
||||
|
|
@ -880,7 +900,7 @@ onMounted(() => {
|
|||
|
||||
nextTick(() => {
|
||||
// 書きかけの投稿を復元
|
||||
if (!props.instant && !props.mention && !props.specified) {
|
||||
if (!props.instant && !props.mention && !props.specified && !props.mock) {
|
||||
const draft = JSON.parse(miLocalStorage.getItem('drafts') ?? '{}')[draftKey];
|
||||
if (draft) {
|
||||
text = draft.data.text;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue