Merge branch 'develop' into pizzax-indexeddb

This commit is contained in:
tamaina
2022-05-28 01:31:23 +09:00
340 changed files with 9589 additions and 9298 deletions

View File

@@ -1,11 +1,11 @@
export function byteify(data: string, encoding: 'ascii' | 'base64' | 'hex') {
export function byteify(string: string, encoding: 'ascii' | 'base64' | 'hex') {
switch (encoding) {
case 'ascii':
return Uint8Array.from(data, c => c.charCodeAt(0));
return Uint8Array.from(string, c => c.charCodeAt(0));
case 'base64':
return Uint8Array.from(
atob(
data
string
.replace(/-/g, '+')
.replace(/_/g, '/')
),
@@ -13,7 +13,7 @@ export function byteify(data: string, encoding: 'ascii' | 'base64' | 'hex') {
);
case 'hex':
return new Uint8Array(
data
string
.match(/.{1,2}/g)
.map(byte => parseInt(byte, 16))
);

View File

@@ -1,5 +1,5 @@
import { nextTick, Ref, ref } from 'vue';
import * as getCaretCoordinates from 'textarea-caret';
import { nextTick, Ref, ref, defineAsyncComponent } from 'vue';
import getCaretCoordinates from 'textarea-caret';
import { toASCII } from 'punycode/';
import { popup } from '@/os';
@@ -74,21 +74,21 @@ export class Autocomplete {
emojiIndex,
mfmTagIndex);
if (max == -1) {
if (max === -1) {
this.close();
return;
}
const isMention = mentionIndex != -1;
const isHashtag = hashtagIndex != -1;
const isMfmTag = mfmTagIndex != -1;
const isEmoji = emojiIndex != -1 && text.split(/:[a-z0-9_+\-]+:/).pop()!.includes(':');
const isMention = mentionIndex !== -1;
const isHashtag = hashtagIndex !== -1;
const isMfmTag = mfmTagIndex !== -1;
const isEmoji = emojiIndex !== -1 && text.split(/:[a-z0-9_+\-]+:/).pop()!.includes(':');
let opened = false;
if (isMention) {
const username = text.substr(mentionIndex + 1);
if (username != '' && username.match(/^[a-zA-Z0-9_]+$/)) {
if (username !== '' && username.match(/^[a-zA-Z0-9_]+$/)) {
this.open('user', username);
opened = true;
} else if (username === '') {
@@ -130,7 +130,7 @@ export class Autocomplete {
* サジェストを提示します。
*/
private async open(type: string, q: string | null) {
if (type != this.currentType) {
if (type !== this.currentType) {
this.close();
}
if (this.opening) return;
@@ -157,7 +157,7 @@ export class Autocomplete {
const _y = ref(y);
const _q = ref(q);
const { dispose } = await popup(import('@/components/autocomplete.vue'), {
const { dispose } = await popup(defineAsyncComponent(() => import('@/components/autocomplete.vue')), {
textarea: this.textarea,
close: this.close,
type: type,
@@ -201,7 +201,7 @@ export class Autocomplete {
const caret = this.textarea.selectionStart;
if (type == 'user') {
if (type === 'user') {
const source = this.text;
const before = source.substr(0, caret);
@@ -219,7 +219,7 @@ export class Autocomplete {
const pos = trimmedBefore.length + (acct.length + 2);
this.textarea.setSelectionRange(pos, pos);
});
} else if (type == 'hashtag') {
} else if (type === 'hashtag') {
const source = this.text;
const before = source.substr(0, caret);
@@ -235,7 +235,7 @@ export class Autocomplete {
const pos = trimmedBefore.length + (value.length + 2);
this.textarea.setSelectionRange(pos, pos);
});
} else if (type == 'emoji') {
} else if (type === 'emoji') {
const source = this.text;
const before = source.substr(0, caret);
@@ -251,7 +251,7 @@ export class Autocomplete {
const pos = trimmedBefore.length + value.length;
this.textarea.setSelectionRange(pos, pos);
});
} else if (type == 'mfmTag') {
} else if (type === 'mfmTag') {
const source = this.text;
const before = source.substr(0, caret);

View File

@@ -2,7 +2,7 @@ export default (parent, child, checkSame = true) => {
if (checkSame && parent === child) return true;
let node = child.parentNode;
while (node) {
if (node == parent) return true;
if (node === parent) return true;
node = node.parentNode;
}
return false;

View File

@@ -8,4 +8,4 @@ export type UnicodeEmojiDef = {
}
// initial converted from https://github.com/muan/emojilib/commit/242fe68be86ed6536843b83f7e32f376468b38fb
export const emojilist = require('../emojilist.json') as UnicodeEmojiDef[];
export const emojilist = (await import('../emojilist.json')).default as UnicodeEmojiDef[];

View File

@@ -1,5 +1,5 @@
export function extractAvgColorFromBlurhash(hash: string) {
return typeof hash == 'string'
return typeof hash === 'string'
? '#' + [...hash.slice(2, 6)]
.map(x => '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~'.indexOf(x))
.reduce((a, c) => a * 83 + c, 0)

View File

@@ -3,5 +3,5 @@ import { get } from '@/scripts/idb-proxy';
export async function getAccountFromId(id: string) {
const accounts = await get('accounts') as { token: string; id: string; }[];
if (!accounts) console.log('Accounts are not recorded');
return accounts.find(e => e.id === id);
return accounts.find(account => account.id === id);
}

View File

@@ -1,10 +0,0 @@
// スクリプトサイズがデカい
//import * as crypto from 'crypto';
export default (data: ArrayBuffer) => {
//const buf = new Buffer(data);
//const hash = crypto.createHash('md5');
//hash.update(buf);
//return hash.digest('hex');
return '';
};

View File

@@ -1,4 +1,4 @@
import { Ref } from 'vue';
import { defineAsyncComponent, Ref } from 'vue';
import * as misskey from 'misskey-js';
import { $i } from '@/account';
import { i18n } from '@/i18n';
@@ -83,8 +83,8 @@ export function getNoteMenu(props: {
function togglePin(pin: boolean): void {
os.apiWithDialog(pin ? 'i/pin' : 'i/unpin', {
noteId: appearNote.id
}, undefined, null, e => {
if (e.id === '72dab508-c64d-498f-8740-a8eec1ba385a') {
}, undefined, null, res => {
if (res.id === '72dab508-c64d-498f-8740-a8eec1ba385a') {
os.alert({
type: 'error',
text: i18n.ts.pinLimitExceeded
@@ -209,7 +209,7 @@ export function getNoteMenu(props: {
text: i18n.ts.clip,
action: () => clip()
},
(appearNote.userId != $i.id) ? statePromise.then(state => state.isWatching ? {
(appearNote.userId !== $i.id) ? statePromise.then(state => state.isWatching ? {
icon: 'fas fa-eye-slash',
text: i18n.ts.unwatch,
action: () => toggleWatch(false)
@@ -227,7 +227,7 @@ export function getNoteMenu(props: {
text: i18n.ts.muteThread,
action: () => toggleThreadMute(true)
}),
appearNote.userId == $i.id ? ($i.pinnedNoteIds || []).includes(appearNote.id) ? {
appearNote.userId === $i.id ? ($i.pinnedNoteIds || []).includes(appearNote.id) ? {
icon: 'fas fa-thumbtack',
text: i18n.ts.unpin,
action: () => togglePin(false)
@@ -246,14 +246,14 @@ export function getNoteMenu(props: {
}]
: []
),*/
...(appearNote.userId != $i.id ? [
...(appearNote.userId !== $i.id ? [
null,
{
icon: 'fas fa-exclamation-circle',
text: i18n.ts.reportAbuse,
action: () => {
const u = appearNote.url || appearNote.uri || `${url}/notes/${appearNote.id}`;
os.popup(import('@/components/abuse-report-window.vue'), {
os.popup(defineAsyncComponent(() => import('@/components/abuse-report-window.vue')), {
user: appearNote.user,
initialComment: `Note: ${u}\n-----\n`
}, {}, 'closed');
@@ -261,9 +261,9 @@ export function getNoteMenu(props: {
}]
: []
),
...(appearNote.userId == $i.id || $i.isModerator || $i.isAdmin ? [
...(appearNote.userId === $i.id || $i.isModerator || $i.isAdmin ? [
null,
appearNote.userId == $i.id ? {
appearNote.userId === $i.id ? {
icon: 'fas fa-edit',
text: i18n.ts.deleteAndEdit,
action: delEdit

View File

@@ -24,7 +24,7 @@ export const getNoteSummary = (note: misskey.entities.Note): string => {
}
// ファイルが添付されているとき
if ((note.files || []).length != 0) {
if ((note.files || []).length !== 0) {
summary += ` (${i18n.t('withNFiles', { n: note.files.length })})`;
}

View File

@@ -6,6 +6,7 @@ import * as os from '@/os';
import { userActions } from '@/store';
import { router } from '@/router';
import { $i, iAmModerator } from '@/account';
import { defineAsyncComponent } from 'vue';
export function getUserMenu(user) {
const meId = $i ? $i.id : null;
@@ -127,7 +128,7 @@ export function getUserMenu(user) {
}
function reportAbuse() {
os.popup(import('@/components/abuse-report-window.vue'), {
os.popup(defineAsyncComponent(() => import('@/components/abuse-report-window.vue')), {
user: user,
}, {}, 'closed');
}
@@ -168,7 +169,7 @@ export function getUserMenu(user) {
action: () => {
os.post({ specified: user });
}
}, meId != user.id ? {
}, meId !== user.id ? {
type: 'link',
icon: 'fas fa-comments',
text: i18n.ts.startMessaging,
@@ -177,13 +178,13 @@ export function getUserMenu(user) {
icon: 'fas fa-list-ul',
text: i18n.ts.addToList,
action: pushList
}, meId != user.id ? {
}, meId !== user.id ? {
icon: 'fas fa-users',
text: i18n.ts.inviteToGroup,
action: inviteGroup
} : undefined] as any;
if ($i && meId != user.id) {
if ($i && meId !== user.id) {
menu = menu.concat([null, {
icon: user.isMuted ? 'fas fa-eye' : 'fas fa-eye-slash',
text: user.isMuted ? i18n.ts.unmute : i18n.ts.mute,

View File

@@ -53,34 +53,34 @@ const parseKeymap = (keymap: Keymap) => Object.entries(keymap).map(([patterns, c
const ignoreElemens = ['input', 'textarea'];
function match(e: KeyboardEvent, patterns: Action['patterns']): boolean {
const key = e.code.toLowerCase();
function match(ev: KeyboardEvent, patterns: Action['patterns']): boolean {
const key = ev.code.toLowerCase();
return patterns.some(pattern => pattern.which.includes(key) &&
pattern.ctrl === e.ctrlKey &&
pattern.shift === e.shiftKey &&
pattern.alt === e.altKey &&
!e.metaKey
pattern.ctrl === ev.ctrlKey &&
pattern.shift === ev.shiftKey &&
pattern.alt === ev.altKey &&
!ev.metaKey
);
}
export const makeHotkey = (keymap: Keymap) => {
const actions = parseKeymap(keymap);
return (e: KeyboardEvent) => {
return (ev: KeyboardEvent) => {
if (document.activeElement) {
if (ignoreElemens.some(el => document.activeElement!.matches(el))) return;
if (document.activeElement.attributes['contenteditable']) return;
}
for (const action of actions) {
const matched = match(e, action.patterns);
const matched = match(ev, action.patterns);
if (matched) {
if (!action.allowRepeat && e.repeat) return;
if (!action.allowRepeat && ev.repeat) return;
e.preventDefault();
e.stopPropagation();
action.callback(e);
ev.preventDefault();
ev.stopPropagation();
action.callback(ev);
break;
}
}

View File

@@ -85,7 +85,7 @@ export class Hpml {
public eval() {
try {
this.vars.value = this.evaluateVars();
} catch (e) {
} catch (err) {
//this.onError(e);
}
}
@@ -103,7 +103,7 @@ export class Hpml {
public callAiScript(fn: string) {
try {
if (this.aiscript) this.aiscript.execFn(this.aiscript.scope.get(fn), []);
} catch (e) {}
} catch (err) {}
}
@autobind
@@ -185,7 +185,7 @@ export class Hpml {
if (this.aiscript) {
try {
return utils.valToJs(this.aiscript.scope.get(expr.value));
} catch (e) {
} catch (err) {
return null;
}
} else {
@@ -194,7 +194,7 @@ export class Hpml {
}
// Define user function
if (expr.type == 'fn') {
if (expr.type === 'fn') {
return {
slots: expr.value.slots.map(x => x.name),
exec: (slotArg: Record<string, any>) => {

View File

@@ -1,9 +1,9 @@
import * as tinycolor from 'tinycolor2';
import tinycolor from 'tinycolor2';
import { Hpml } from './evaluator';
import { values, utils } from '@syuilo/aiscript';
import { Fn, HpmlScope } from '.';
import { Expr } from './expr';
import * as seedrandom from 'seedrandom';
import seedrandom from 'seedrandom';
/* TODO: https://www.chartjs.org/docs/latest/configuration/canvas-background.html#color
// https://stackoverflow.com/questions/38493564/chart-area-background-color-chartjs

View File

@@ -13,8 +13,8 @@ let idbAvailable = typeof window !== 'undefined' ? !!window.indexedDB : true;
if (idbAvailable) {
try {
await iset('idb-test', 'test');
} catch (e) {
console.error('idb error', e);
} catch (err) {
console.error('idb error', err);
idbAvailable = false;
}
}

View File

@@ -25,12 +25,12 @@ export async function lookupUser() {
_notFound = true;
}
};
usernamePromise.then(show).catch(e => {
if (e.code === 'NO_SUCH_USER') {
usernamePromise.then(show).catch(err => {
if (err.code === 'NO_SUCH_USER') {
notFound();
}
});
idPromise.then(show).catch(e => {
idPromise.then(show).catch(err => {
notFound();
});
}

View File

@@ -1,14 +1,21 @@
import { defineAsyncComponent } from 'vue';
import { $i } from '@/account';
import { i18n } from '@/i18n';
import { alert } from '@/os';
import { popup } from '@/os';
export function pleaseLogin() {
export function pleaseLogin(path?: string) {
if ($i) return;
alert({
title: i18n.ts.signinRequired,
text: null
});
popup(defineAsyncComponent(() => import('@/components/signin-dialog.vue')), {
autoSet: true,
message: i18n.ts.signinRequired
}, {
cancelled: () => {
if (path) {
window.location.href = path;
}
},
}, 'closed');
throw new Error('signin required');
}

View File

@@ -1,4 +1,4 @@
import { Ref, ref } from 'vue';
import { defineAsyncComponent, Ref, ref } from 'vue';
import { popup } from '@/os';
class ReactionPicker {
@@ -12,7 +12,7 @@ class ReactionPicker {
}
public async init() {
await popup(import('@/components/emoji-picker-dialog.vue'), {
await popup(defineAsyncComponent(() => import('@/components/emoji-picker-dialog.vue')), {
src: this.src,
asReactionPicker: true,
manualShowing: this.manualShowing

View File

@@ -19,10 +19,10 @@ function select(src: any, label: string | null, multiple: boolean): Promise<Driv
Promise.all(promises).then(driveFiles => {
res(multiple ? driveFiles : driveFiles[0]);
}).catch(e => {
}).catch(err => {
os.alert({
type: 'error',
text: e
text: err
});
});
@@ -54,9 +54,9 @@ function select(src: any, label: string | null, multiple: boolean): Promise<Driv
const marker = Math.random().toString(); // TODO: UUIDとか使う
const connection = stream.useChannel('main');
connection.on('urlUploadFinished', data => {
if (data.marker === marker) {
res(multiple ? [data.file] : data.file);
connection.on('urlUploadFinished', urlResponse => {
if (urlResponse.marker === marker) {
res(multiple ? [urlResponse.file] : urlResponse.file);
connection.dispose();
}
});

View File

@@ -1,5 +1,5 @@
import { globalEvents } from '@/events';
import * as tinycolor from 'tinycolor2';
import tinycolor from 'tinycolor2';
export type Theme = {
id: string;
@@ -10,29 +10,29 @@ export type Theme = {
props: Record<string, string>;
};
export const lightTheme: Theme = require('@/themes/_light.json5');
export const darkTheme: Theme = require('@/themes/_dark.json5');
export const lightTheme: Theme = await import('@/themes/_light.json5');
export const darkTheme: Theme = await import('@/themes/_dark.json5');
export const themeProps = Object.keys(lightTheme.props).filter(key => !key.startsWith('X'));
export const builtinThemes = [
require('@/themes/l-light.json5'),
require('@/themes/l-coffee.json5'),
require('@/themes/l-apricot.json5'),
require('@/themes/l-rainy.json5'),
require('@/themes/l-vivid.json5'),
require('@/themes/l-cherry.json5'),
require('@/themes/l-sushi.json5'),
await import('@/themes/l-light.json5'),
await import('@/themes/l-coffee.json5'),
await import('@/themes/l-apricot.json5'),
await import('@/themes/l-rainy.json5'),
await import('@/themes/l-vivid.json5'),
await import('@/themes/l-cherry.json5'),
await import('@/themes/l-sushi.json5'),
require('@/themes/d-dark.json5'),
require('@/themes/d-persimmon.json5'),
require('@/themes/d-astro.json5'),
require('@/themes/d-future.json5'),
require('@/themes/d-botanical.json5'),
require('@/themes/d-cherry.json5'),
require('@/themes/d-ice.json5'),
require('@/themes/d-pumpkin.json5'),
require('@/themes/d-black.json5'),
await import('@/themes/d-dark.json5'),
await import('@/themes/d-persimmon.json5'),
await import('@/themes/d-astro.json5'),
await import('@/themes/d-future.json5'),
await import('@/themes/d-botanical.json5'),
await import('@/themes/d-cherry.json5'),
await import('@/themes/d-ice.json5'),
await import('@/themes/d-pumpkin.json5'),
await import('@/themes/d-black.json5'),
] as Theme[];
let timeout = null;

View File

@@ -33,13 +33,13 @@ export function uploadFile(
name?: string,
keepOriginal: boolean = defaultStore.state.keepOriginalUploading
): Promise<Misskey.entities.DriveFile> {
if (folder && typeof folder == 'object') folder = folder.id;
if (folder && typeof folder === 'object') folder = folder.id;
return new Promise((resolve, reject) => {
const id = Math.random().toString();
const reader = new FileReader();
reader.onload = async (e) => {
reader.onload = async (ev) => {
const ctx = reactive<Uploading>({
id: id,
name: name || file.name || 'untitled',
@@ -64,24 +64,24 @@ export function uploadFile(
try {
resizedImage = await readAndCompressImage(file, config);
ctx.name = file.type !== imgConfig.mimeType ? `${ctx.name}.${mimeTypeMap[compressTypeMap[file.type].mimeType]}` : ctx.name;
} catch (e) {
console.error('Failed to resize image', e);
} catch (err) {
console.error('Failed to resize image', err);
}
}
const data = new FormData();
data.append('i', $i.token);
data.append('force', 'true');
data.append('file', resizedImage || file);
data.append('name', ctx.name);
if (folder) data.append('folderId', folder);
const formData = new FormData();
formData.append('i', $i.token);
formData.append('force', 'true');
formData.append('file', resizedImage || file);
formData.append('name', ctx.name);
if (folder) formData.append('folderId', folder);
const xhr = new XMLHttpRequest();
xhr.open('POST', apiUrl + '/drive/files/create', true);
xhr.onload = (ev) => {
if (xhr.status !== 200 || ev.target == null || ev.target.response == null) {
// TODO: 消すのではなくて再送できるようにしたい
uploads.value = uploads.value.filter(x => x.id != id);
uploads.value = uploads.value.filter(x => x.id !== id);
alert({
type: 'error',
@@ -97,17 +97,17 @@ export function uploadFile(
resolve(driveFile);
uploads.value = uploads.value.filter(x => x.id != id);
uploads.value = uploads.value.filter(x => x.id !== id);
};
xhr.upload.onprogress = e => {
if (e.lengthComputable) {
ctx.progressMax = e.total;
ctx.progressValue = e.loaded;
xhr.upload.onprogress = ev => {
if (ev.lengthComputable) {
ctx.progressMax = ev.total;
ctx.progressValue = ev.loaded;
}
};
xhr.send(data);
xhr.send(formData);
};
reader.readAsArrayBuffer(file);
});

View File

@@ -4,7 +4,7 @@ export function query(obj: {}): string {
.reduce((a, [k, v]) => (a[k] = v, a), {} as Record<string, any>);
return Object.entries(params)
.map((e) => `${e[0]}=${encodeURIComponent(e[1])}`)
.map((p) => `${p[0]}=${encodeURIComponent(p[1])}`)
.join('&');
}

View File

@@ -11,8 +11,8 @@ export function useNoteCapture(props: {
const note = props.note;
const connection = $i ? stream : null;
function onStreamNoteUpdated(data): void {
const { type, id, body } = data;
function onStreamNoteUpdated(noteData): void {
const { type, id, body } = noteData;
if (id !== note.value.id) return;