Compare commits

...

39 Commits

Author SHA1 Message Date
syuilo
f00f5cbed1 10.29.0 2018-10-20 15:51:47 +09:00
syuilo
c4e8cabae9 ファイル作成APIにforceオプションを実装 2018-10-20 15:50:13 +09:00
Dr. Gutfuck LLC
1729d05e8c Localized mark all as read message (#2956)
* Localized read-all message

* Fixed some weirdness:   src/client/app/init.ts

* Unfucked server api stuff (sorry lol):   src/server/api/endpoints/i/read_all_unread_notes.ts

* Clean up
2018-10-20 15:46:01 +09:00
syuilo
770fb46ca7 Improve usability 2018-10-20 15:41:27 +09:00
syuilo
a3c4e54bc0 🎨 2018-10-20 15:37:17 +09:00
syuilo
b8a77fbada Show image info in tooltip 2018-10-20 15:21:24 +09:00
Dr. Gutfuck LLC
c2663529c1 Localized BSoD messages. (#2953)
* Added VSCode workspace files to :   .gitignore

* Localized Blue Screen of Death:   locales/ja-JP.yml
Localized Blue Screen of Death:   src/client/app/init.ts
2018-10-20 11:57:23 +09:00
syuilo
9df74a02b6 Fix bug 2018-10-20 11:24:02 +09:00
syuilo
71c9964e19 Fix bug and clean up 2018-10-20 11:19:27 +09:00
syuilo
ae2e47f6a9 Merge pull request #2950 from syuilo/l10n_develop
New Crowdin translations
2018-10-20 09:45:44 +09:00
syuilo
1524d35f66 New translations ja-JP.yml (English) 2018-10-20 09:41:11 +09:00
syuilo
845be966a0 10.28.0 2018-10-20 09:39:56 +09:00
syuilo
80818d79eb Fix bug 2018-10-20 09:38:36 +09:00
syuilo
cb9b3c00dd Use router-link instead of a to improve usability 2018-10-20 09:34:34 +09:00
syuilo
b3997fb5df New translations ja-JP.yml (Norwegian) 2018-10-20 09:33:07 +09:00
syuilo
09dde6b78a New translations ja-JP.yml (Dutch) 2018-10-20 09:32:57 +09:00
syuilo
3345d3ab35 New translations ja-JP.yml (Japanese, Kansai) 2018-10-20 09:32:51 +09:00
syuilo
366be7bbdd New translations ja-JP.yml (Spanish) 2018-10-20 09:32:47 +09:00
syuilo
7008ea66f8 New translations ja-JP.yml (Russian) 2018-10-20 09:32:43 +09:00
syuilo
70f881e989 New translations ja-JP.yml (Portuguese) 2018-10-20 09:32:38 +09:00
syuilo
94d2355089 New translations ja-JP.yml (Polish) 2018-10-20 09:32:33 +09:00
syuilo
dfbe48b25b New translations ja-JP.yml (Korean) 2018-10-20 09:32:29 +09:00
syuilo
931cb38b54 New translations ja-JP.yml (Italian) 2018-10-20 09:32:23 +09:00
syuilo
e5fd34f94e New translations ja-JP.yml (German) 2018-10-20 09:32:17 +09:00
syuilo
c638d7eb48 New translations ja-JP.yml (French) 2018-10-20 09:32:12 +09:00
syuilo
7e96384618 New translations ja-JP.yml (English) 2018-10-20 09:32:08 +09:00
syuilo
829cb99f5b New translations ja-JP.yml (Chinese Simplified) 2018-10-20 09:32:04 +09:00
syuilo
1f93c99304 New translations ja-JP.yml (Catalan) 2018-10-20 09:32:00 +09:00
syuilo
dbb7c756cd Fix bug 2018-10-20 09:31:56 +09:00
syuilo
13f381710c Validate param 2018-10-20 09:31:52 +09:00
syuilo
70897c0e9a 🎨 2018-10-20 09:28:48 +09:00
syuilo
f51d1c5264 Fix test 2018-10-20 09:14:16 +09:00
syuilo
70d0937aab Fix #2949 2018-10-20 09:03:04 +09:00
syuilo
7d1ab6102f 10.27.0 2018-10-20 08:04:52 +09:00
syuilo
77ddd778be ハッシュタグもデッキ内ナビゲーションするように 2018-10-20 08:03:45 +09:00
syuilo
890ecb693f Improve 2018-10-20 07:28:01 +09:00
syuilo
209fe7dcaf Improve deck usability 2018-10-20 07:21:22 +09:00
syuilo
e0d6f7c7c4 RP --> RN 2018-10-20 07:01:09 +09:00
syuilo
5d3fe9599b Improve performance 2018-10-20 06:42:19 +09:00
40 changed files with 236 additions and 55 deletions

1
.gitignore vendored
View File

@@ -16,3 +16,4 @@ api-docs.json
/redis
/mongo
/elasticsearch
*.code-workspace

View File

@@ -115,6 +115,9 @@ common:
reduce-motion: "UIの動きを減らす"
this-setting-is-this-device-only: "このデバイスのみ"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "引き分け"
my-turn: "あなたのターンです"

View File

@@ -115,6 +115,9 @@ common:
reduce-motion: "Animationen der Benutzeroberfläche reduzieren"
this-setting-is-this-device-only: "Nur auf diesem Gerät"
do-not-use-in-production: 'Dies ist eine Entwicklungsversion. Nicht in einer Produktionsumgebung verwenden.'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "Unentschieden"
my-turn: "Du bist am Zug"

View File

@@ -115,6 +115,9 @@ common:
reduce-motion: "Reduce motion in UI"
this-setting-is-this-device-only: "Only for this device"
do-not-use-in-production: 'As this is for development, do not use this in production.'
error:
title: 'Something happened :('
retry: 'Retry'
reversi:
drawn: "Draw"
my-turn: "Your turn"
@@ -747,7 +750,7 @@ desktop/views/components/settings.vue:
api-via-stream-desc: "API request is performed via the WebSocket connection instead of native fetch API (for better performance). This setting is stored in the browser."
deck-nav: "デッキ内ナビゲーション"
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
deck-default: "デッキをデフォルトのUIにする"
deck-default: "Use Deck as default UI"
display: "Design and display"
customize: "Customize home layout"
wallpaper: "Wallpaper"

View File

@@ -115,6 +115,9 @@ common:
reduce-motion: "UIの動きを減らす"
this-setting-is-this-device-only: "このデバイスのみ"
do-not-use-in-production: 'Esto está en desarrollo, no usarlo para producción.'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "Empatado"
my-turn: "Mi turno"

View File

@@ -115,6 +115,9 @@ common:
reduce-motion: "Réduire les animations dans linterface utilisateur"
this-setting-is-this-device-only: "Uniquement sur cet appareil"
do-not-use-in-production: 'Il sagit dune version de développement. Ne pas utiliser dans un environnement de production.'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "Partie nulle"
my-turn: "Cest votre tour"

View File

@@ -115,6 +115,9 @@ common:
reduce-motion: "UIの動きを減らす"
this-setting-is-this-device-only: "このデバイスのみ"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "引き分け"
my-turn: "あなたのターンです"

View File

@@ -25,6 +25,15 @@ common:
application-authorization: "アプリの連携"
close: "閉じる"
do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。"
BSoD:
fatal-error: ":( 致命的な問題が発生しました。"
update-browser-os: "お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。"
error-code: "エラーコード"
browser-version: "ブラウザ バージョン"
client-version: "クライアント バージョン"
email-support: "問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。"
thanks: "Thank you for using Misskey."
got-it: "わかった"
customization-tips:
title: "カスタマイズのヒント"
@@ -124,6 +133,10 @@ common:
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "引き分け"
my-turn: "あなたのターンです"

View File

@@ -115,6 +115,9 @@ common:
reduce-motion: "UI、動き過ぎや、静かにしてや"
this-setting-is-this-device-only: "このデバイスのみ"
do-not-use-in-production: '開発ビルドや。本番環境で使わんといて!知らんで!'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "おあいこ"
my-turn: "あんさんのターンや"

View File

@@ -115,6 +115,9 @@ common:
reduce-motion: "UIの動きを減らす"
this-setting-is-this-device-only: "이 장치만"
do-not-use-in-production: '이것은 개발 빌드입니다. 프로덕션 환경에서 사용하지 마십시오.'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "무승부"
my-turn: "당신의 차례입니다"

View File

@@ -115,6 +115,9 @@ common:
reduce-motion: "UIの動きを減らす"
this-setting-is-this-device-only: "このデバイスのみ"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "引き分け"
my-turn: "あなたのターンです"

View File

@@ -115,6 +115,9 @@ common:
reduce-motion: "UIの動きを減らす"
this-setting-is-this-device-only: "このデバイスのみ"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "引き分け"
my-turn: "あなたのターンです"

View File

@@ -115,6 +115,9 @@ common:
reduce-motion: "UIの動きを減らす"
this-setting-is-this-device-only: "このデバイスのみ"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "Remis"
my-turn: "Twoja kolej"

View File

@@ -115,6 +115,9 @@ common:
reduce-motion: "UIの動きを減らす"
this-setting-is-this-device-only: "このデバイスのみ"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "Empatado"
my-turn: "Seu turno"

View File

@@ -115,6 +115,9 @@ common:
reduce-motion: "UIの動きを減らす"
this-setting-is-this-device-only: "このデバイスのみ"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "引き分け"
my-turn: "あなたのターンです"

View File

@@ -115,6 +115,9 @@ common:
reduce-motion: "UIの動きを減らす"
this-setting-is-this-device-only: "このデバイスのみ"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
error:
title: '問題が発生しました'
retry: 'やり直す'
reversi:
drawn: "引き分け"
my-turn: "あなたのターンです"

View File

@@ -1,8 +1,8 @@
{
"name": "misskey",
"author": "syuilo <i@syuilo.com>",
"version": "10.26.0",
"clientVersion": "1.0.10762",
"version": "10.29.0",
"clientVersion": "1.0.10801",
"codename": "nighthike",
"main": "./built/index.js",
"private": true,

View File

@@ -67,10 +67,10 @@ export default {
// flatten
const reservedKeys = concat(actions.map(a => a.patterns));
el.dataset.reservedKeys = JSON.stringify(reservedKeys);
el._misskey_reservedKeys = reservedKeys;
el._keyHandler = (e: KeyboardEvent) => {
const targetReservedKeys = JSON.parse(document.activeElement ? ((document.activeElement as any).dataset || {}).reservedKeys || '[]' : '[]');
const targetReservedKeys = document.activeElement ? ((document.activeElement as any)._misskey_reservedKeys || []) : [];
if (document.activeElement && ignoreElemens.some(el => document.activeElement.matches(el))) return;
for (const action of actions) {

View File

@@ -114,10 +114,9 @@ export default Vue.component('misskey-flavored-markdown', {
}
case 'mention': {
return (createElement as any)('a', {
return (createElement as any)('router-link', {
attrs: {
href: `${url}/${token.canonical}`,
target: '_blank',
to: `/${token.canonical}`,
dataIsMe: (this as any).i && getAcct((this as any).i) == getAcct(token),
style: 'color:var(--mfmMention);'
},
@@ -129,10 +128,9 @@ export default Vue.component('misskey-flavored-markdown', {
}
case 'hashtag': {
return [createElement('a', {
return [createElement('router-link', {
attrs: {
href: `${url}/tags/${encodeURIComponent(token.hashtag)}`,
target: '_blank',
to: `/tags/${encodeURIComponent(token.hashtag)}`,
style: 'color:var(--mfmHashtag);'
}
}, token.content)];

View File

@@ -66,7 +66,7 @@ init(async (launch) => {
{ path: '/i/drive/folder/:folder', component: MkDrive },
{ path: '/selectdrive', component: MkSelectDrive },
{ path: '/search', component: MkSearch },
{ path: '/tags/:tag', component: MkTag },
{ path: '/tags/:tag', name: 'tag', component: MkTag },
{ path: '/share', component: MkShare },
{ path: '/reversi/:game?', component: MkReversi },
{ path: '/@:user', name: 'user', component: MkUser },

View File

@@ -35,7 +35,7 @@
<span v-if="appearNote.isHidden" style="opacity: 0.5">%i18n:@private%</span>
<a class="reply" v-if="appearNote.reply">%fa:reply%</a>
<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i" :class="$style.text"/>
<a class="rp" v-if="appearNote.renote">RP:</a>
<a class="rp" v-if="appearNote.renote">RN:</a>
</div>
<div class="files" v-if="appearNote.files.length > 0">
<mk-media-list :media-list="appearNote.files"/>

View File

@@ -4,9 +4,9 @@
<slot name="empty" v-if="notes.length == 0 && !fetching && requestInitPromise == null"></slot>
<div v-if="!fetching && requestInitPromise != null">
<p>%i18n:@error%</p>
<button @click="resolveInitPromise">%i18n:@retry%</button>
<div v-if="!fetching && requestInitPromise != null" class="error">
<p>%fa:exclamation-triangle% %i18n:common.error.title%</p>
<ui-button @click="resolveInitPromise">%i18n:common.error.retry%</ui-button>
</div>
<div class="placeholder" v-if="fetching">
@@ -215,6 +215,13 @@ export default Vue.extend({
> *
transition transform .3s ease, opacity .3s ease
> .error
max-width 300px
margin 0 auto
padding 16px
text-align center
color var(--text)
> .placeholder
padding 32px
opacity 0.3

View File

@@ -5,7 +5,7 @@
<span v-if="note.deletedAt" style="opacity: 0.5">%i18n:@deleted%</span>
<a class="reply" v-if="note.replyId">%fa:reply%</a>
<misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i"/>
<a class="rp" v-if="note.renoteId" :href="`/notes/${note.renoteId}`">RP: ...</a>
<a class="rp" v-if="note.renoteId" :href="`/notes/${note.renoteId}`">RN: ...</a>
</div>
<details v-if="note.files.length > 0">
<summary>({{ '%i18n:@media-count%'.replace('{}', note.files.length) }})</summary>

View File

@@ -0,0 +1,37 @@
<template>
<x-column>
<span slot="header">
%fa:hashtag%<span>{{ tag }}</span>
</span>
<x-hashtag-tl :tag-tl="tagTl"/>
</x-column>
</template>
<script lang="ts">
import Vue from 'vue';
import XColumn from './deck.column.vue';
import XHashtagTl from './deck.hashtag-tl.vue';
export default Vue.extend({
components: {
XColumn,
XHashtagTl
},
props: {
tag: {
type: String,
required: true
}
},
computed: {
tagTl(): any {
return {
query: [[this.tag]]
};
}
}
});
</script>

View File

@@ -47,14 +47,16 @@ export default Vue.extend({
mounted() {
if (this.connection) this.connection.close();
this.connection = (this as any).os.stream.connectToChannel('hashtag', this.tagTl.query);
this.connection = (this as any).os.stream.connectToChannel('hashtag', {
q: this.tagTl.query
});
this.connection.on('note', this.onNote);
this.fetch();
},
beforeDestroy() {
this.connection.close();
this.connection.dispose();
},
methods: {

View File

@@ -8,9 +8,9 @@
</template>
</div>
<div v-if="!fetching && requestInitPromise != null">
<p>%i18n:@error%</p>
<button @click="resolveInitPromise">%i18n:@retry%</button>
<div v-if="!fetching && requestInitPromise != null" class="error">
<p>%fa:exclamation-triangle% %i18n:common.error.title%</p>
<ui-button @click="resolveInitPromise">%i18n:common.error.retry%</ui-button>
</div>
<!-- トランジションを有効にするとなぜかメモリリークする -->
@@ -226,6 +226,13 @@ export default Vue.extend({
> *
transition transform .3s ease, opacity .3s ease
> .error
max-width 300px
margin 0 auto
padding 16px
text-align center
color var(--text)
> .placeholder
padding 16px
opacity 0.3

View File

@@ -8,6 +8,7 @@
<div class="is-remote" v-if="user.host != null">%fa:exclamation-triangle% %i18n:@is-remote%<a :href="user.url || user.uri" target="_blank">%i18n:@view-remote%</a></div>
<header :style="bannerStyle">
<div>
<button class="menu" @click="menu" ref="menu">%fa:ellipsis-h%</button>
<mk-follow-button v-if="$store.getters.isSignedIn && user.id != $store.state.i.id" :user="user" class="follow"/>
<mk-avatar class="avatar" :user="user" :disable-preview="true"/>
<span class="name">{{ user | userName }}</span>
@@ -26,7 +27,12 @@
</div>
</div>
<div class="images" v-if="images.length > 0">
<router-link v-for="image in images" :style="`background-image: url(${image.thumbnailUrl})`" :key="`${image.id}:${image._note.id}`" :to="image._note | notePage"></router-link>
<router-link v-for="image in images"
:style="`background-image: url(${image.thumbnailUrl})`"
:key="`${image.id}:${image._note.id}`"
:to="image._note | notePage"
:title="`${image.name}\n${(new Date(image.createdAt)).toLocaleString()}`"
></router-link>
</div>
<div class="tl">
<x-notes ref="timeline" :more="existMore ? fetchMoreNotes : null"/>
@@ -41,6 +47,9 @@ import parseAcct from '../../../../../../misc/acct/parse';
import XColumn from './deck.column.vue';
import XNotes from './deck.notes.vue';
import XNote from '../../components/note.vue';
import Menu from '../../../../common/views/components/menu.vue';
import MkUserListsWindow from '../../components/user-lists-window.vue';
import Ok from '../../../../common/views/components/ok.vue';
import { concat } from '../../../../../../prelude/array';
const fetchLimit = 10;
@@ -161,6 +170,30 @@ export default Vue.extend({
return promise;
},
menu() {
let menu = [{
icon: '%fa:list%',
text: '%i18n:@push-to-a-list%',
action: () => {
const w = (this as any).os.new(MkUserListsWindow);
w.$once('choosen', async list => {
w.close();
await (this as any).api('users/lists/push', {
listId: list.id,
userId: this.user.id
});
(this as any).os.new(Ok);
});
}
}];
this.os.new(Menu, {
source: this.$refs.menu,
compact: false,
items: menu
});
}
}
});
</script>
@@ -191,6 +224,14 @@ export default Vue.extend({
color #fff
text-align center
> .menu
position absolute
top 8px
left 8px
padding 8px
font-size 16px
text-shadow 0 0 8px #000
> .follow
position absolute
top 16px

View File

@@ -1,6 +1,6 @@
<template>
<mk-ui :class="$style.root">
<div class="qlvquzbjribqcaozciifydkngcwtyzje" :style="style" :class="{ center: $store.state.device.deckColumnAlign == 'center' }" v-hotkey.global="keymap">
<div class="qlvquzbjribqcaozciifydkngcwtyzje" ref="body" :style="style" :class="{ center: $store.state.device.deckColumnAlign == 'center' }" v-hotkey.global="keymap">
<template v-for="ids in layout">
<div v-if="ids.length > 1" class="folder">
<template v-for="id, i in ids">
@@ -12,6 +12,7 @@
<template v-if="temporaryColumn">
<x-user-column v-if="temporaryColumn.type == 'user'" :acct="temporaryColumn.acct" :key="temporaryColumn.acct"/>
<x-note-column v-else-if="temporaryColumn.type == 'note'" :note-id="temporaryColumn.noteId" :key="temporaryColumn.noteId"/>
<x-hashtag-column v-else-if="temporaryColumn.type == 'tag'" :tag="temporaryColumn.tag" :key="temporaryColumn.tag"/>
</template>
<button ref="add" @click="add" title="%i18n:common.deck.add-column%">%fa:plus%</button>
</div>
@@ -25,6 +26,7 @@ import Menu from '../../../../common/views/components/menu.vue';
import MkUserListsWindow from '../../components/user-lists-window.vue';
import XUserColumn from './deck.user-column.vue';
import XNoteColumn from './deck.note-column.vue';
import XHashtagColumn from './deck.hashtag-column.vue';
import * as uuid from 'uuid';
@@ -32,7 +34,8 @@ export default Vue.extend({
components: {
XColumnCore,
XUserColumn,
XNoteColumn
XNoteColumn,
XHashtagColumn
},
computed: {
@@ -64,6 +67,19 @@ export default Vue.extend({
}
},
watch: {
temporaryColumn() {
if (this.temporaryColumn != null) {
this.$nextTick(() => {
this.$refs.body.scrollTo({
left: this.$refs.body.scrollWidth - this.$refs.body.clientWidth,
behavior: 'smooth'
});
});
}
}
},
provide() {
return {
getColumnVm: this.getColumnVm
@@ -149,6 +165,15 @@ export default Vue.extend({
}
});
return true;
} else if (to.name == 'tag') {
this.$store.commit('device/set', {
key: 'deckTemporaryColumn',
value: {
type: 'tag',
tag: to.params.tag
}
});
return true;
}
},

View File

@@ -9,11 +9,11 @@
</p>
</div>
<div class="action-form">
<button class="mute ui" @click="user.isMuted ? unmute() : mute()" v-if="$store.state.i.id != user.id">
<ui-button @click="user.isMuted ? unmute() : mute()" v-if="$store.state.i.id != user.id">
<span v-if="user.isMuted">%fa:eye% %i18n:@unmute%</span>
<span v-if="!user.isMuted">%fa:eye-slash% %i18n:@mute%</span>
</button>
<button class="mute ui" @click="list">%fa:list% %i18n:@push-to-a-list%</button>
</ui-button>
<ui-button @click="list">%fa:list% %i18n:@push-to-a-list%</ui-button>
</div>
</div>
</template>

View File

@@ -216,15 +216,15 @@ function panic(e) {
document.documentElement.style.background = '#1269e2';
document.body.innerHTML =
'<div id="error">'
+ '<h1>:( 致命的な問題が発生しました。</h1>'
+ '<p>お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。</p>'
+ '<h1>%i18n.common.BSoD.fatal-error%</h1>'
+ '<p>%i18n.common.BSoD.update-browser-os%</p>'
+ '<hr>'
+ `<p>エラーコード: ${e.toString()}</p>`
+ `<p>ブラウザ バージョン: ${navigator.userAgent}</p>`
+ `<p>クライアント バージョン: ${version}</p>`
+ `<p>%i18n.common.BSoD.error-code%: ${e.toString()}</p>`
+ `<p>%i18n.common.BSoD.browser-version%: ${navigator.userAgent}</p>`
+ `<p>%i18n.common.BSoD.client-version%: ${version}</p>`
+ '<hr>'
+ '<p>問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。</p>'
+ '<p>Thank you for using Misskey.</p>'
+ '<p>%i18n.common.BSoD.email-support%</p>'
+ '<p>%i18n.common.BSoD.thanks%</p>'
+ '</div>';
// TODO: Report the bug

View File

@@ -244,10 +244,10 @@ export default class MiOS extends EventEmitter {
this.store.dispatch('login', me);
fetched();
} else {
this.initStream();
// Finish init
callback();
this.initStream();
}
});
}

View File

@@ -31,7 +31,7 @@
<span v-if="appearNote.isHidden" style="opacity: 0.5">(%i18n:@private%)</span>
<a class="reply" v-if="appearNote.reply">%fa:reply%</a>
<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i" :class="$style.text"/>
<a class="rp" v-if="appearNote.renote != null">RP:</a>
<a class="rp" v-if="appearNote.renote != null">RN:</a>
</div>
<div class="files" v-if="appearNote.files.length > 0">
<mk-media-list :media-list="appearNote.files"/>

View File

@@ -5,7 +5,7 @@
<span v-if="note.deletedAt" style="opacity: 0.5">(%i18n:@deleted%)</span>
<a class="reply" v-if="note.replyId">%fa:reply%</a>
<misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i"/>
<a class="rp" v-if="note.renoteId">RP: ...</a>
<a class="rp" v-if="note.renoteId">RN: ...</a>
</div>
<details v-if="note.files.length > 0">
<summary>({{ '%i18n:@media-count%'.replace('{}', note.files.length) }})</summary>

View File

@@ -9,9 +9,9 @@ export type TextElementHashtag = {
};
export default function(text: string, i: number) {
if (!(/^\s#[^\s\.,]+/.test(text) || (i == 0 && /^#[^\s\.,]+/.test(text)))) return null;
if (!(/^\s#[^\s\.,!\?]+/.test(text) || (i == 0 && /^#[^\s\.,!\?]+/.test(text)))) return null;
const isHead = text.startsWith('#');
const hashtag = text.match(/^\s?#[^\s\.,]+/)[0];
const hashtag = text.match(/^\s?#[^\s\.,!\?]+/)[0];
const res: any[] = !isHead ? [{
type: 'text',
content: text[0]

View File

@@ -38,9 +38,9 @@ const summarize = (note: any): string => {
// Renoteのとき
if (note.renoteId) {
if (note.renote) {
summary += ` RP: ${summarize(note.renote)}`;
summary += ` RN: ${summarize(note.renote)}`;
} else {
summary += ' RP: ...';
summary += ' RN: ...';
}
}

View File

@@ -31,19 +31,23 @@ export const meta = {
}
}),
isSensitive: $.bool.optional.nullable.note({
default: null,
isSensitive: $.bool.optional.note({
default: false,
desc: {
'ja-JP': 'このメディアが「閲覧注意」(NSFW)かどうか',
'en-US': 'Whether this media is NSFW'
}
}),
force: $.bool.optional.note({
default: false,
desc: {
'ja-JP': 'true にすると、同じハッシュを持つファイルが既にアップロードされていても強制的にファイルを作成します。',
}
})
}
};
/**
* Create a file
*/
export default async (file: any, params: any, user: ILocalUser): Promise<any> => {
if (file == null) {
throw 'file is required';
@@ -76,7 +80,7 @@ export default async (file: any, params: any, user: ILocalUser): Promise<any> =>
try {
// Create file
const driveFile = await create(user, file.path, name, null, ps.folderId, false, false, null, null, ps.isSensitive);
const driveFile = await create(user, file.path, name, null, ps.folderId, ps.force, false, null, null, ps.isSensitive);
cleanup();

View File

@@ -4,7 +4,8 @@ import NoteUnread from '../../../../models/note-unread';
export const meta = {
desc: {
'ja-JP': '未読の投稿をすべて既読にします。'
'ja-JP': '未読の投稿をすべて既読にします。',
'en-US': 'Mark all messages as read.'
},
requireCredential: true,

View File

@@ -15,6 +15,8 @@ export default class extends Channel {
const q: Array<string[]> = params.q;
if (q == null) return;
// Subscribe stream
this.subscriber.on('hashtag', async note => {
const matched = q.some(tags => tags.every(tag => note.tags.map((t: string) => t.toLowerCase()).includes(tag.toLowerCase())));

View File

@@ -1,6 +1,5 @@
import autobind from 'autobind-decorator';
import * as websocket from 'websocket';
import * as debug from 'debug';
import User, { IUser } from '../../../models/user';
import readNotification from '../common/read-notification';
@@ -12,8 +11,6 @@ import Channel from './channel';
import channels from './channels';
import { EventEmitter } from 'events';
const log = debug('misskey');
/**
* Main stream connection
*/
@@ -147,7 +144,6 @@ export default class Connection {
@autobind
private onChannelConnectRequested(payload: any) {
const { channel, id, params, pong } = payload;
log(`CH CONNECT: ${id} ${channel} by @${this.user.username}`);
this.connectChannel(id, params, channel, pong);
}
@@ -157,7 +153,6 @@ export default class Connection {
@autobind
private onChannelDisconnectRequested(payload: any) {
const { id } = payload;
log(`CH DISCONNECT: ${id} by @${this.user.username}`);
this.disconnectChannel(id);
}

View File

@@ -122,6 +122,12 @@ describe('Text', () => {
{ type: 'hashtag', content: '#piyo', hashtag: 'piyo' },
{ type: 'text', content: '.' }
], tokens2);
const tokens3 = analyze('#Foo!');
assert.deepEqual([
{ type: 'hashtag', content: '#Foo', hashtag: 'Foo' },
{ type: 'text', content: '!' },
], tokens3);
});
it('quote', () => {