summaryrefslogtreecommitdiff
path: root/packages/frontend/src/scripts
diff options
context:
space:
mode:
authorKagami Sascha Rosylight <saschanaz@outlook.com>2023-02-25 20:04:48 +0100
committerGitHub <noreply@github.com>2023-02-25 20:04:48 +0100
commitb468330ed944cd2aefb93183786855e990bd3df3 (patch)
treeaae515a3d90bc6646854ea718c054540b2b654e9 /packages/frontend/src/scripts
parentAdd test (diff)
parentrefactor(frontend): fix eslint error (#10084) (diff)
downloadmisskey-b468330ed944cd2aefb93183786855e990bd3df3.tar.gz
misskey-b468330ed944cd2aefb93183786855e990bd3df3.tar.bz2
misskey-b468330ed944cd2aefb93183786855e990bd3df3.zip
Merge branch 'develop' into mkusername-empty
Diffstat (limited to 'packages/frontend/src/scripts')
-rw-r--r--packages/frontend/src/scripts/get-note-menu.ts138
-rw-r--r--packages/frontend/src/scripts/get-user-menu.ts13
-rw-r--r--packages/frontend/src/scripts/get-user-name.ts2
-rw-r--r--packages/frontend/src/scripts/hpml/index.ts2
-rw-r--r--packages/frontend/src/scripts/hpml/type-checker.ts4
-rw-r--r--packages/frontend/src/scripts/scroll.ts16
-rw-r--r--packages/frontend/src/scripts/search.ts63
-rw-r--r--packages/frontend/src/scripts/use-document-visibility.ts19
8 files changed, 109 insertions, 148 deletions
diff --git a/packages/frontend/src/scripts/get-note-menu.ts b/packages/frontend/src/scripts/get-note-menu.ts
index 48b740f4c3..9c0ff3d1b2 100644
--- a/packages/frontend/src/scripts/get-note-menu.ts
+++ b/packages/frontend/src/scripts/get-note-menu.ts
@@ -9,6 +9,7 @@ import copyToClipboard from '@/scripts/copy-to-clipboard';
import { url } from '@/config';
import { noteActions } from '@/store';
import { miLocalStorage } from '@/local-storage';
+import { getUserMenu } from '@/scripts/get-user-menu';
export function getNoteMenu(props: {
note: misskey.entities.Note;
@@ -99,66 +100,6 @@ export function getNoteMenu(props: {
});
}
- 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);
-
- claimAchievement('noteClipped1');
- os.apiWithDialog('clips/add-note', { clipId: clip.id, noteId: appearNote.id });
- },
- }, null, ...clips.map(clip => ({
- text: clip.name,
- action: () => {
- claimAchievement('noteClipped1');
- 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;
@@ -200,7 +141,7 @@ export function getNoteMenu(props: {
props.translating.value = true;
const res = await os.api('notes/translate', {
noteId: appearNote.id,
- targetLang: miLocalStorage.getItem('lang') || navigator.language,
+ targetLang: miLocalStorage.getItem('lang') ?? navigator.language,
});
props.translating.value = false;
props.translation.value = res;
@@ -240,7 +181,7 @@ export function getNoteMenu(props: {
icon: 'ti ti-external-link',
text: i18n.ts.showOnRemote,
action: () => {
- window.open(appearNote.url || appearNote.uri, '_blank');
+ window.open(appearNote.url ?? appearNote.uri, '_blank');
},
} : undefined,
{
@@ -264,9 +205,67 @@ export function getNoteMenu(props: {
action: () => toggleFavorite(true),
}),
{
+ type: 'parent',
icon: 'ti ti-paperclip',
text: i18n.ts.clip,
- action: () => clip(),
+ children: async () => {
+ const clips = await os.api('clips/list');
+ return [{
+ 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);
+
+ claimAchievement('noteClipped1');
+ os.apiWithDialog('clips/add-note', { clipId: clip.id, noteId: appearNote.id });
+ },
+ }, null, ...clips.map(clip => ({
+ text: clip.name,
+ action: () => {
+ claimAchievement('noteClipped1');
+ 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,
+ });
+ }
+ },
+ );
+ },
+ }))];
+ },
},
statePromise.then(state => state.isMutedThread ? {
icon: 'ti ti-message-off',
@@ -286,6 +285,15 @@ export function getNoteMenu(props: {
text: i18n.ts.pin,
action: () => togglePin(true),
} : undefined,
+ appearNote.userId !== $i.id ? {
+ type: 'parent',
+ icon: 'ti ti-user',
+ text: i18n.ts.user,
+ children: async () => {
+ const user = await os.api('users/show', { userId: appearNote.userId });
+ return getUserMenu(user);
+ },
+ } : undefined,
/*
...($i.isModerator || $i.isAdmin ? [
null,
@@ -302,7 +310,7 @@ export function getNoteMenu(props: {
icon: 'ti ti-exclamation-circle',
text: i18n.ts.reportAbuse,
action: () => {
- const u = appearNote.url || appearNote.uri || `${url}/notes/${appearNote.id}`;
+ 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`,
@@ -344,7 +352,7 @@ export function getNoteMenu(props: {
icon: 'ti ti-external-link',
text: i18n.ts.showOnRemote,
action: () => {
- window.open(appearNote.url || appearNote.uri, '_blank');
+ window.open(appearNote.url ?? appearNote.uri, '_blank');
},
} : undefined]
.filter(x => x !== undefined);
diff --git a/packages/frontend/src/scripts/get-user-menu.ts b/packages/frontend/src/scripts/get-user-menu.ts
index 557b257f62..69d0ed085d 100644
--- a/packages/frontend/src/scripts/get-user-menu.ts
+++ b/packages/frontend/src/scripts/get-user-menu.ts
@@ -1,4 +1,5 @@
import { defineAsyncComponent } from 'vue';
+import * as misskey from 'misskey-js';
import { i18n } from '@/i18n';
import copyToClipboard from '@/scripts/copy-to-clipboard';
import { host } from '@/config';
@@ -8,7 +9,7 @@ import { $i, iAmModerator } from '@/account';
import { mainRouter } from '@/router';
import { Router } from '@/nirax';
-export function getUserMenu(user, router: Router = mainRouter) {
+export function getUserMenu(user: misskey.entities.UserDetailed, router: Router = mainRouter) {
const meId = $i ? $i.id : null;
async function pushList() {
@@ -102,6 +103,8 @@ export function getUserMenu(user, router: Router = mainRouter) {
}
async function invalidateFollow() {
+ if (!await getConfirmed(i18n.ts.breakFollowConfirm)) return;
+
os.apiWithDialog('following/invalidate', {
userId: user.id,
}).then(() => {
@@ -113,7 +116,7 @@ export function getUserMenu(user, router: Router = mainRouter) {
icon: 'ti ti-at',
text: i18n.ts.copyUsername,
action: () => {
- copyToClipboard(`@${user.username}@${user.host || host}`);
+ copyToClipboard(`@${user.username}@${user.host ?? host}`);
},
}, {
icon: 'ti ti-info-circle',
@@ -166,12 +169,6 @@ export function getUserMenu(user, router: Router = mainRouter) {
if (iAmModerator) {
menu = menu.concat([null, {
- icon: 'ti ti-user-exclamation',
- text: i18n.ts.moderation,
- action: () => {
- router.push('/user-info/' + user.id + '#moderation');
- },
- }, {
icon: 'ti ti-badges',
text: i18n.ts.roles,
action: async () => {
diff --git a/packages/frontend/src/scripts/get-user-name.ts b/packages/frontend/src/scripts/get-user-name.ts
index d499ea0203..4daf203e06 100644
--- a/packages/frontend/src/scripts/get-user-name.ts
+++ b/packages/frontend/src/scripts/get-user-name.ts
@@ -1,3 +1,3 @@
export default function(user: { name?: string | null, username: string }): string {
- return user.name || user.username;
+ return user.name === '' ? user.username : user.name ?? user.username;
}
diff --git a/packages/frontend/src/scripts/hpml/index.ts b/packages/frontend/src/scripts/hpml/index.ts
index 5c07a08315..587c6a36c8 100644
--- a/packages/frontend/src/scripts/hpml/index.ts
+++ b/packages/frontend/src/scripts/hpml/index.ts
@@ -58,7 +58,7 @@ export class HpmlScope {
constructor(layerdStates: HpmlScope['layerdStates'], name?: HpmlScope['name']) {
this.layerdStates = layerdStates;
- this.name = name || 'anonymous';
+ this.name = name ?? 'anonymous';
}
@autobind
diff --git a/packages/frontend/src/scripts/hpml/type-checker.ts b/packages/frontend/src/scripts/hpml/type-checker.ts
index 24c9ed8bcb..692826fc90 100644
--- a/packages/frontend/src/scripts/hpml/type-checker.ts
+++ b/packages/frontend/src/scripts/hpml/type-checker.ts
@@ -63,7 +63,7 @@ export class HpmlTypeChecker {
@autobind
public getExpectedType(v: Expr, slot: number): Type {
- const def = funcDefs[v.type || ''];
+ const def = funcDefs[v.type ?? ''];
if (def == null) {
throw new Error('Unknown type: ' + v.type);
}
@@ -107,7 +107,7 @@ export class HpmlTypeChecker {
return pageVar.type;
}
- const envVar = envVarsDef[v.value || ''];
+ const envVar = envVarsDef[v.value ?? ''];
if (envVar !== undefined) {
return envVar;
}
diff --git a/packages/frontend/src/scripts/scroll.ts b/packages/frontend/src/scripts/scroll.ts
index e3d9dc00c2..a002f02b5a 100644
--- a/packages/frontend/src/scripts/scroll.ts
+++ b/packages/frontend/src/scripts/scroll.ts
@@ -10,7 +10,7 @@ export function getScrollContainer(el: HTMLElement | null): HTMLElement | null {
}
}
-export function getStickyTop(el: HTMLElement, container: HTMLElement | null = null, top: number = 0) {
+export function getStickyTop(el: HTMLElement, container: HTMLElement | null = null, top = 0) {
if (!el.parentElement) return top;
const data = el.dataset.stickyContainerHeaderHeight;
const newTop = data ? Number(data) + top : top;
@@ -23,14 +23,14 @@ export function getScrollPosition(el: HTMLElement | null): number {
return container == null ? window.scrollY : container.scrollTop;
}
-export function onScrollTop(el: HTMLElement, cb: () => unknown, tolerance: number = 1, once: boolean = false) {
+export function onScrollTop(el: HTMLElement, cb: () => unknown, tolerance = 1, once = false) {
// とりあえず評価してみる
if (isTopVisible(el)) {
cb();
if (once) return null;
}
- const container = getScrollContainer(el) || window;
+ const container = getScrollContainer(el) ?? window;
const onScroll = ev => {
if (!document.body.contains(el)) return;
@@ -45,7 +45,7 @@ export function onScrollTop(el: HTMLElement, cb: () => unknown, tolerance: numbe
return removeListener;
}
-export function onScrollBottom(el: HTMLElement, cb: () => unknown, tolerance: number = 1, once: boolean = false) {
+export function onScrollBottom(el: HTMLElement, cb: () => unknown, tolerance = 1, once = false) {
const container = getScrollContainer(el);
// とりあえず評価してみる
@@ -54,7 +54,7 @@ export function onScrollBottom(el: HTMLElement, cb: () => unknown, tolerance: nu
if (once) return null;
}
- const containerOrWindow = container || window;
+ const containerOrWindow = container ?? window;
const onScroll = ev => {
if (!document.body.contains(el)) return;
if (isBottomVisible(el, 1, container)) {
@@ -104,12 +104,12 @@ export function scrollToBottom(
} else {
window.scroll({
top: (el.scrollHeight - window.innerHeight + getStickyTop(el, container) + (window.innerWidth <= 500 ? 96 : 0)) || 0,
- ...options
+ ...options,
});
}
}
-export function isTopVisible(el: HTMLElement, tolerance: number = 1): boolean {
+export function isTopVisible(el: HTMLElement, tolerance = 1): boolean {
const scrollTop = getScrollPosition(el);
return scrollTop <= tolerance;
}
@@ -124,6 +124,6 @@ export function getBodyScrollHeight() {
return Math.max(
document.body.scrollHeight, document.documentElement.scrollHeight,
document.body.offsetHeight, document.documentElement.offsetHeight,
- document.body.clientHeight, document.documentElement.clientHeight
+ document.body.clientHeight, document.documentElement.clientHeight,
);
}
diff --git a/packages/frontend/src/scripts/search.ts b/packages/frontend/src/scripts/search.ts
deleted file mode 100644
index 69f1586b77..0000000000
--- a/packages/frontend/src/scripts/search.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-import * as os from '@/os';
-import { i18n } from '@/i18n';
-import { mainRouter } from '@/router';
-
-export async function search() {
- const { canceled, result: query } = await os.inputText({
- title: i18n.ts.search,
- });
- if (canceled || query == null || query === '') return;
-
- const q = query.trim();
-
- if (q.startsWith('@') && !q.includes(' ')) {
- mainRouter.push(`/${q}`);
- return;
- }
-
- if (q.startsWith('#')) {
- mainRouter.push(`/tags/${encodeURIComponent(q.substr(1))}`);
- return;
- }
-
- // like 2018/03/12
- if (/^[0-9]{4}\/[0-9]{2}\/[0-9]{2}/.test(q.replace(/-/g, '/'))) {
- const date = new Date(q.replace(/-/g, '/'));
-
- // 日付しか指定されてない場合、例えば 2018/03/12 ならユーザーは
- // 2018/03/12 のコンテンツを「含む」結果になることを期待するはずなので
- // 23時間59分進める(そのままだと 2018/03/12 00:00:00 「まで」の
- // 結果になってしまい、2018/03/12 のコンテンツは含まれない)
- if (q.replace(/-/g, '/').match(/^[0-9]{4}\/[0-9]{2}\/[0-9]{2}$/)) {
- date.setHours(23, 59, 59, 999);
- }
-
- // TODO
- //v.$root.$emit('warp', date);
- os.alert({
- icon: 'ti ti-history',
- iconOnly: true, autoClose: true,
- });
- return;
- }
-
- if (q.startsWith('https://')) {
- const promise = os.api('ap/show', {
- uri: q,
- });
-
- os.promiseDialog(promise, null, null, i18n.ts.fetchingAsApObject);
-
- const res = await promise;
-
- if (res.type === 'User') {
- mainRouter.push(`/@${res.object.username}@${res.object.host}`);
- } else if (res.type === 'Note') {
- mainRouter.push(`/notes/${res.object.id}`);
- }
-
- return;
- }
-
- mainRouter.push(`/search?q=${encodeURIComponent(q)}`);
-}
diff --git a/packages/frontend/src/scripts/use-document-visibility.ts b/packages/frontend/src/scripts/use-document-visibility.ts
new file mode 100644
index 0000000000..47e91dd937
--- /dev/null
+++ b/packages/frontend/src/scripts/use-document-visibility.ts
@@ -0,0 +1,19 @@
+import { onMounted, onUnmounted, ref, Ref } from 'vue';
+
+export function useDocumentVisibility(): Ref<DocumentVisibilityState> {
+ const visibility = ref(document.visibilityState);
+
+ const onChange = (): void => {
+ visibility.value = document.visibilityState;
+ };
+
+ onMounted(() => {
+ document.addEventListener('visibilitychange', onChange);
+ });
+
+ onUnmounted(() => {
+ document.removeEventListener('visibilitychange', onChange);
+ });
+
+ return visibility;
+}