mirror of
https://github.com/paricafe/misskey.git
synced 2024-11-26 05:16:43 -06:00
Merge branch 'develop'
This commit is contained in:
commit
1092532292
47 changed files with 160 additions and 58 deletions
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -73,6 +73,18 @@ mongodb:
|
||||||
8. master ブランチに戻す
|
8. master ブランチに戻す
|
||||||
9. enjoy
|
9. enjoy
|
||||||
|
|
||||||
|
11.11.0 (2019/05/05)
|
||||||
|
--------------------
|
||||||
|
### Improvements
|
||||||
|
* MisskeyPagesにリストから選択関数を追加
|
||||||
|
* MisskeyPagesに確率を指定できるテキストランダム選択関数を追加
|
||||||
|
* 外部サービス連携ログインリンクにアイコン追加
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* MisskeyPagesでifを入れ子にできなくなっていた問題を修正
|
||||||
|
* MisskeyPagesで数値入力を作成するとテキスト入力になる問題を修正
|
||||||
|
* 外部サービス連携に関する問題を修正
|
||||||
|
|
||||||
11.10.1 (2019/05/04)
|
11.10.1 (2019/05/04)
|
||||||
--------------------
|
--------------------
|
||||||
### Fixes
|
### Fixes
|
||||||
|
|
|
@ -1865,8 +1865,8 @@ pages:
|
||||||
font: "フォント"
|
font: "フォント"
|
||||||
fontSerif: "セリフ"
|
fontSerif: "セリフ"
|
||||||
fontSansSerif: "サンセリフ"
|
fontSansSerif: "サンセリフ"
|
||||||
set-eye-catchig-image: "アイキャッチ画像を設定"
|
set-eye-catching-image: "アイキャッチ画像を設定"
|
||||||
remove-eye-catchig-image: "アイキャッチ画像を削除"
|
remove-eye-catching-image: "アイキャッチ画像を削除"
|
||||||
choose-block: "ブロックを追加"
|
choose-block: "ブロックを追加"
|
||||||
select-type: "種類を選択"
|
select-type: "種類を選択"
|
||||||
enter-variable-name: "変数名を決めてください"
|
enter-variable-name: "変数名を決めてください"
|
||||||
|
@ -1941,6 +1941,7 @@ pages:
|
||||||
fn: "関数"
|
fn: "関数"
|
||||||
text: "テキスト操作"
|
text: "テキスト操作"
|
||||||
convert: "変換"
|
convert: "変換"
|
||||||
|
list: "リスト"
|
||||||
blocks:
|
blocks:
|
||||||
text: "テキスト"
|
text: "テキスト"
|
||||||
multiLineText: "テキスト(複数行)"
|
multiLineText: "テキスト(複数行)"
|
||||||
|
@ -2059,6 +2060,13 @@ pages:
|
||||||
_seedRandomPick:
|
_seedRandomPick:
|
||||||
arg1: "シード"
|
arg1: "シード"
|
||||||
arg2: "リスト"
|
arg2: "リスト"
|
||||||
|
DRPWPM: "確率付きリストからランダムに選択 (ユーザーごとに日替わり)"
|
||||||
|
_DRPWPM:
|
||||||
|
arg1: "テキストのリスト"
|
||||||
|
pick: "リストから選択"
|
||||||
|
_pick:
|
||||||
|
arg1: "リスト"
|
||||||
|
arg2: "位置"
|
||||||
number: "数値"
|
number: "数値"
|
||||||
stringToNumber: "テキストを数値に"
|
stringToNumber: "テキストを数値に"
|
||||||
_stringToNumber:
|
_stringToNumber:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"author": "syuilo <i@syuilo.com>",
|
"author": "syuilo <i@syuilo.com>",
|
||||||
"version": "11.10.1",
|
"version": "11.11.0",
|
||||||
"codename": "daybreak",
|
"codename": "daybreak",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
@ -34,7 +34,7 @@ body
|
||||||
.peg
|
.peg
|
||||||
display block
|
display block
|
||||||
position absolute
|
position absolute
|
||||||
right 0px
|
right 0
|
||||||
width 100px
|
width 100px
|
||||||
height 100%
|
height 100%
|
||||||
box-shadow 0 0 10px var(--primary), 0 0 5px var(--primary)
|
box-shadow 0 0 10px var(--primary), 0 0 5px var(--primary)
|
||||||
|
|
|
@ -98,7 +98,7 @@ export default Vue.extend({
|
||||||
margin 0 auto
|
margin 0 auto
|
||||||
text-align center
|
text-align center
|
||||||
background #fff
|
background #fff
|
||||||
box-shadow 0px 4px 16px rgba(#000, 0.2)
|
box-shadow 0 4px 16px rgba(#000, 0.2)
|
||||||
|
|
||||||
> .fetching
|
> .fetching
|
||||||
margin 0
|
margin 0
|
||||||
|
|
|
@ -52,7 +52,7 @@ function match(e: KeyboardEvent, patterns: action['patterns']): boolean {
|
||||||
pattern.ctrl == e.ctrlKey &&
|
pattern.ctrl == e.ctrlKey &&
|
||||||
pattern.shift == e.shiftKey &&
|
pattern.shift == e.shiftKey &&
|
||||||
pattern.alt == e.altKey &&
|
pattern.alt == e.altKey &&
|
||||||
e.metaKey == false
|
!e.metaKey
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,9 @@ export default function(me, settings, note) {
|
||||||
return (
|
return (
|
||||||
(!isMyNote && note.reply && includesMutedWords(note.reply.text)) ||
|
(!isMyNote && note.reply && includesMutedWords(note.reply.text)) ||
|
||||||
(!isMyNote && note.renote && includesMutedWords(note.renote.text)) ||
|
(!isMyNote && note.renote && includesMutedWords(note.renote.text)) ||
|
||||||
(settings.showMyRenotes === false && isMyNote && isPureRenote) ||
|
(!settings.showMyRenotes && isMyNote && isPureRenote) ||
|
||||||
(settings.showRenotedMyNotes === false && isPureRenote && note.renote.userId == me.id) ||
|
(!settings.showRenotedMyNotes && isPureRenote && note.renote.userId == me.id) ||
|
||||||
(settings.showLocalRenotes === false && isPureRenote && note.renote.user.host == null) ||
|
(!settings.showLocalRenotes && isPureRenote && note.renote.user.host == null) ||
|
||||||
(!isMyNote && includesMutedWords(note.text))
|
(!isMyNote && includesMutedWords(note.text))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ export default Vue.extend({
|
||||||
|
|
||||||
ms(): number {
|
ms(): number {
|
||||||
return this.now.getMilliseconds() * this.smooth;
|
return this.now.getMilliseconds() * this.smooth;
|
||||||
}
|
},
|
||||||
s(): number {
|
s(): number {
|
||||||
return this.now.getSeconds();
|
return this.now.getSeconds();
|
||||||
},
|
},
|
||||||
|
|
|
@ -202,7 +202,7 @@ export default Vue.extend({
|
||||||
left 0
|
left 0
|
||||||
z-index 1
|
z-index 1
|
||||||
width 100%
|
width 100%
|
||||||
box-shadow 0 0px 2px rgba(#000, 0.2)
|
box-shadow 0 0 2px rgba(#000, 0.2)
|
||||||
|
|
||||||
> .form
|
> .form
|
||||||
background rgba(0, 0, 0, 0.02)
|
background rgba(0, 0, 0, 0.02)
|
||||||
|
|
|
@ -14,7 +14,7 @@ import XImage from './els/page-editor.el.image.vue';
|
||||||
import XButton from './els/page-editor.el.button.vue';
|
import XButton from './els/page-editor.el.button.vue';
|
||||||
import XTextInput from './els/page-editor.el.text-input.vue';
|
import XTextInput from './els/page-editor.el.text-input.vue';
|
||||||
import XTextareaInput from './els/page-editor.el.textarea-input.vue';
|
import XTextareaInput from './els/page-editor.el.textarea-input.vue';
|
||||||
import XNumberInput from './els/page-editor.el.text-input.vue';
|
import XNumberInput from './els/page-editor.el.number-input.vue';
|
||||||
import XSwitch from './els/page-editor.el.switch.vue';
|
import XSwitch from './els/page-editor.el.switch.vue';
|
||||||
import XIf from './els/page-editor.el.if.vue';
|
import XIf from './els/page-editor.el.if.vue';
|
||||||
import XPost from './els/page-editor.el.post.vue';
|
import XPost from './els/page-editor.el.post.vue';
|
||||||
|
|
|
@ -36,10 +36,10 @@
|
||||||
</ui-select>
|
</ui-select>
|
||||||
|
|
||||||
<div class="eyeCatch">
|
<div class="eyeCatch">
|
||||||
<ui-button v-if="eyeCatchingImageId == null && !readonly" @click="setEyeCatchingImage()"><fa :icon="faPlus"/> {{ $t('set-eye-catchig-image') }}</ui-button>
|
<ui-button v-if="eyeCatchingImageId == null && !readonly" @click="setEyeCatchingImage()"><fa :icon="faPlus"/> {{ $t('set-eye-catching-image') }}</ui-button>
|
||||||
<div v-else-if="eyeCatchingImage">
|
<div v-else-if="eyeCatchingImage">
|
||||||
<img :src="eyeCatchingImage.url" :alt="eyeCatchingImage.name"/>
|
<img :src="eyeCatchingImage.url" :alt="eyeCatchingImage.name"/>
|
||||||
<ui-button @click="removeEyeCatchingImage()" v-if="!readonly"><fa :icon="faTrashAlt"/> {{ $t('remove-eye-catchig-image') }}</ui-button>
|
<ui-button @click="removeEyeCatchingImage()" v-if="!readonly"><fa :icon="faTrashAlt"/> {{ $t('remove-eye-catching-image') }}</ui-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -337,7 +337,7 @@ export default Vue.extend({
|
||||||
getScriptBlockList(type: string = null) {
|
getScriptBlockList(type: string = null) {
|
||||||
const list = [];
|
const list = [];
|
||||||
|
|
||||||
const blocks = blockDefs.filter(block => type === null || block.out === null || block.out === type);
|
const blocks = blockDefs.filter(block => type === null || block.out === null || block.out === type || typeof block.out === 'number');
|
||||||
|
|
||||||
for (const block of blocks) {
|
for (const block of blocks) {
|
||||||
const category = list.find(x => x.category === block.category);
|
const category = list.find(x => x.category === block.category);
|
||||||
|
|
|
@ -54,7 +54,11 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
document.cookie = `i=${this.$store.state.i.token}`;
|
if (!document.cookie.match(/i=(\w+)/)) {
|
||||||
|
document.cookie = `i=${this.$store.state.i.token}; path=/;` +
|
||||||
|
` domain=${document.location.hostname}; max-age=31536000;` +
|
||||||
|
(document.location.protocol.startsWith('https') ? ' secure' : '');
|
||||||
|
}
|
||||||
this.$watch('$store.state.i', () => {
|
this.$watch('$store.state.i', () => {
|
||||||
if (this.$store.state.i.twitter) {
|
if (this.$store.state.i.twitter) {
|
||||||
if (this.twitterForm) this.twitterForm.close();
|
if (this.twitterForm) this.twitterForm.close();
|
||||||
|
|
|
@ -273,7 +273,7 @@ export default Vue.extend({
|
||||||
|
|
||||||
import_() {
|
import_() {
|
||||||
(this.$refs.file as any).click();
|
(this.$refs.file as any).click();
|
||||||
}
|
},
|
||||||
|
|
||||||
export_() {
|
export_() {
|
||||||
const blob = new Blob([this.selectedThemeCode], {
|
const blob = new Blob([this.selectedThemeCode], {
|
||||||
|
|
|
@ -15,9 +15,9 @@
|
||||||
<template #prefix><fa icon="gavel"/></template>
|
<template #prefix><fa icon="gavel"/></template>
|
||||||
</ui-input>
|
</ui-input>
|
||||||
<ui-button type="submit" :disabled="signing">{{ signing ? $t('signing-in') : $t('@.signin') }}</ui-button>
|
<ui-button type="submit" :disabled="signing">{{ signing ? $t('signing-in') : $t('@.signin') }}</ui-button>
|
||||||
<p v-if="meta && meta.enableTwitterIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/twitter`">{{ $t('signin-with-twitter') }}</a></p>
|
<p v-if="meta && meta.enableTwitterIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/twitter`"><fa :icon="['fab', 'twitter']"/> {{ $t('signin-with-twitter') }}</a></p>
|
||||||
<p v-if="meta && meta.enableGithubIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/github`">{{ $t('signin-with-github') }}</a></p>
|
<p v-if="meta && meta.enableGithubIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/github`"><fa :icon="['fab', 'github']"/> {{ $t('signin-with-github') }}</a></p>
|
||||||
<p v-if="meta && meta.enableDiscordIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/discord`">{{ $t('signin-with-discord') /* TODO: Make these layouts better */ }}</a></p>
|
<p v-if="meta && meta.enableDiscordIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/discord`"><fa :icon="['fab', 'discord']"/> {{ $t('signin-with-discord') /* TODO: Make these layouts better */ }}</a></p>
|
||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -322,7 +322,7 @@ root(fill)
|
||||||
|
|
||||||
> .value
|
> .value
|
||||||
display block
|
display block
|
||||||
width 0%
|
width 0
|
||||||
height 100%
|
height 100%
|
||||||
background transparent
|
background transparent
|
||||||
border-radius 6px
|
border-radius 6px
|
||||||
|
|
|
@ -166,7 +166,7 @@ export default Vue.extend({
|
||||||
> .follow-button
|
> .follow-button
|
||||||
position absolute
|
position absolute
|
||||||
top 8px
|
top 8px
|
||||||
right 0px
|
right 0
|
||||||
|
|
||||||
> .more
|
> .more
|
||||||
display block
|
display block
|
||||||
|
|
|
@ -160,7 +160,7 @@ export default Vue.extend({
|
||||||
this.$emit('top');
|
this.$emit('top');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.$store.state.settings.fetchOnScroll !== false) {
|
if (this.$store.state.settings.fetchOnScroll) {
|
||||||
const current = this.$refs.body.scrollTop + this.$refs.body.clientHeight;
|
const current = this.$refs.body.scrollTop + this.$refs.body.clientHeight;
|
||||||
if (current > this.$refs.body.scrollHeight - 1) this.$emit('bottom');
|
if (current > this.$refs.body.scrollHeight - 1) this.$emit('bottom');
|
||||||
}
|
}
|
||||||
|
|
|
@ -205,7 +205,7 @@ export default Vue.extend({
|
||||||
top -32px
|
top -32px
|
||||||
left 0
|
left 0
|
||||||
right 0
|
right 0
|
||||||
width 0px
|
width 0
|
||||||
margin 0 auto
|
margin 0 auto
|
||||||
border-top solid 16px transparent
|
border-top solid 16px transparent
|
||||||
border-left solid 16px transparent
|
border-left solid 16px transparent
|
||||||
|
|
|
@ -102,7 +102,7 @@ class Autocomplete {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isHashtag && opened == false) {
|
if (isHashtag && !opened) {
|
||||||
const hashtag = text.substr(hashtagIndex + 1);
|
const hashtag = text.substr(hashtagIndex + 1);
|
||||||
if (!hashtag.includes(' ')) {
|
if (!hashtag.includes(' ')) {
|
||||||
this.open('hashtag', hashtag);
|
this.open('hashtag', hashtag);
|
||||||
|
@ -110,7 +110,7 @@ class Autocomplete {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isEmoji && opened == false) {
|
if (isEmoji && !opened) {
|
||||||
const emoji = text.substr(emojiIndex + 1);
|
const emoji = text.substr(emojiIndex + 1);
|
||||||
if (!emoji.includes(' ')) {
|
if (!emoji.includes(' ')) {
|
||||||
this.open('emoji', emoji);
|
this.open('emoji', emoji);
|
||||||
|
|
|
@ -47,7 +47,7 @@ class Script {
|
||||||
|
|
||||||
public interpolate(str: string) {
|
public interpolate(str: string) {
|
||||||
if (str == null) return null;
|
if (str == null) return null;
|
||||||
return str.replace(/\{(.+?)\}/g, match => {
|
return str.replace(/{(.+?)}/g, match => {
|
||||||
const v = this.vars[match.slice(1, -1).trim()];
|
const v = this.vars[match.slice(1, -1).trim()];
|
||||||
return v == null ? 'NULL' : v.toString();
|
return v == null ? 'NULL' : v.toString();
|
||||||
});
|
});
|
||||||
|
|
|
@ -750,12 +750,17 @@ export default Vue.extend({
|
||||||
bottom 0
|
bottom 0
|
||||||
animation-delay -1.0s
|
animation-delay -1.0s
|
||||||
|
|
||||||
@keyframes sk-rotate { 100% { transform: rotate(360deg); }}
|
@keyframes sk-rotate {
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes sk-bounce {
|
@keyframes sk-bounce {
|
||||||
0%, 100% {
|
0%, 100% {
|
||||||
transform: scale(0.0);
|
transform: scale(0.0);
|
||||||
} 50% {
|
}
|
||||||
|
50% {
|
||||||
transform: scale(1.0);
|
transform: scale(1.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,7 +181,7 @@ export default Vue.extend({
|
||||||
this.releaseQueue();
|
this.releaseQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.$store.state.settings.fetchOnScroll !== false) {
|
if (this.$store.state.settings.fetchOnScroll) {
|
||||||
const current = window.scrollY + window.innerHeight;
|
const current = window.scrollY + window.innerHeight;
|
||||||
if (current > document.body.offsetHeight - 8) this.fetchMore();
|
if (current > document.body.offsetHeight - 8) this.fetchMore();
|
||||||
}
|
}
|
||||||
|
|
|
@ -377,7 +377,7 @@ export default Vue.extend({
|
||||||
}, err => {
|
}, err => {
|
||||||
this.$root.dialog({
|
this.$root.dialog({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
title: this.$t('error')
|
title: this.$t('error'),
|
||||||
text: err.message
|
text: err.message
|
||||||
});
|
});
|
||||||
}, {
|
}, {
|
||||||
|
|
|
@ -480,7 +480,7 @@ export default Vue.extend({
|
||||||
&:focus
|
&:focus
|
||||||
&:not([data-is-modal])
|
&:not([data-is-modal])
|
||||||
> .body
|
> .body
|
||||||
box-shadow 0 0 0px 1px var(--primaryAlpha05), 0 2px 12px 0 var(--desktopWindowShadow)
|
box-shadow 0 0 0 1px var(--primaryAlpha05), 0 2px 12px 0 var(--desktopWindowShadow)
|
||||||
|
|
||||||
> .handle
|
> .handle
|
||||||
$size = 8px
|
$size = 8px
|
||||||
|
|
|
@ -352,7 +352,7 @@ export default Vue.extend({
|
||||||
padding 0 16px
|
padding 0 16px
|
||||||
line-height 48px
|
line-height 48px
|
||||||
background var(--faceHeader)
|
background var(--faceHeader)
|
||||||
box-shadow 0 1px 0px rgba(0, 0, 0, 0.1)
|
box-shadow 0 1px 0 rgba(0, 0, 0, 0.1)
|
||||||
|
|
||||||
& + div
|
& + div
|
||||||
max-height calc(100% - 48px)
|
max-height calc(100% - 48px)
|
||||||
|
|
|
@ -505,7 +505,7 @@ class WindowSystem extends EventEmitter {
|
||||||
function urlBase64ToUint8Array(base64String: string): Uint8Array {
|
function urlBase64ToUint8Array(base64String: string): Uint8Array {
|
||||||
const padding = '='.repeat((4 - base64String.length % 4) % 4);
|
const padding = '='.repeat((4 - base64String.length % 4) % 4);
|
||||||
const base64 = (base64String + padding)
|
const base64 = (base64String + padding)
|
||||||
.replace(/\-/g, '+')
|
.replace(/-/g, '+')
|
||||||
.replace(/_/g, '/');
|
.replace(/_/g, '/');
|
||||||
|
|
||||||
const rawData = window.atob(base64);
|
const rawData = window.atob(base64);
|
||||||
|
|
|
@ -83,7 +83,7 @@ export default Vue.extend({
|
||||||
hierarchyFolders: [],
|
hierarchyFolders: [],
|
||||||
selectedFiles: [],
|
selectedFiles: [],
|
||||||
info: null,
|
info: null,
|
||||||
connection: null
|
connection: null,
|
||||||
|
|
||||||
fetching: true,
|
fetching: true,
|
||||||
fetchingMoreFiles: false,
|
fetchingMoreFiles: false,
|
||||||
|
@ -385,7 +385,7 @@ export default Vue.extend({
|
||||||
|
|
||||||
createFolder() {
|
createFolder() {
|
||||||
this.$root.dialog({
|
this.$root.dialog({
|
||||||
title: this.$t('folder-name')
|
title: this.$t('folder-name'),
|
||||||
input: {
|
input: {
|
||||||
default: this.folder.name
|
default: this.folder.name
|
||||||
}
|
}
|
||||||
|
@ -415,7 +415,7 @@ export default Vue.extend({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.$root.dialog({
|
this.$root.dialog({
|
||||||
title: this.$t('folder-name')
|
title: this.$t('folder-name'),
|
||||||
input: {
|
input: {
|
||||||
default: this.folder.name
|
default: this.folder.name
|
||||||
}
|
}
|
||||||
|
@ -597,12 +597,17 @@ export default Vue.extend({
|
||||||
bottom 0
|
bottom 0
|
||||||
animation-delay -1.0s
|
animation-delay -1.0s
|
||||||
|
|
||||||
@keyframes sk-rotate { 100% { transform: rotate(360deg); }}
|
@keyframes sk-rotate {
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes sk-bounce {
|
@keyframes sk-bounce {
|
||||||
0%, 100% {
|
0%, 100% {
|
||||||
transform: scale(0.0);
|
transform: scale(0.0);
|
||||||
} 50% {
|
}
|
||||||
|
50% {
|
||||||
transform: scale(1.0);
|
transform: scale(1.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,7 +175,7 @@ export default Vue.extend({
|
||||||
this.releaseQueue();
|
this.releaseQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.$store.state.settings.fetchOnScroll !== false) {
|
if (this.$store.state.settings.fetchOnScroll) {
|
||||||
// 親要素が display none だったら弾く
|
// 親要素が display none だったら弾く
|
||||||
// https://github.com/syuilo/misskey/issues/1569
|
// https://github.com/syuilo/misskey/issues/1569
|
||||||
// http://d.hatena.ne.jp/favril/20091105/1257403319
|
// http://d.hatena.ne.jp/favril/20091105/1257403319
|
||||||
|
|
|
@ -115,7 +115,7 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
onScroll() {
|
onScroll() {
|
||||||
if (this.$store.state.settings.fetchOnScroll !== false) {
|
if (this.$store.state.settings.fetchOnScroll) {
|
||||||
// 親要素が display none だったら弾く
|
// 親要素が display none だったら弾く
|
||||||
// https://github.com/syuilo/misskey/issues/1569
|
// https://github.com/syuilo/misskey/issues/1569
|
||||||
// http://d.hatena.ne.jp/favril/20091105/1257403319
|
// http://d.hatena.ne.jp/favril/20091105/1257403319
|
||||||
|
|
|
@ -295,7 +295,7 @@ export default Vue.extend({
|
||||||
}, err => {
|
}, err => {
|
||||||
this.$root.dialog({
|
this.$root.dialog({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
title: this.$t('error')
|
title: this.$t('error'),
|
||||||
text: err.message
|
text: err.message
|
||||||
});
|
});
|
||||||
}, {
|
}, {
|
||||||
|
@ -341,7 +341,7 @@ export default Vue.extend({
|
||||||
|
|
||||||
post() {
|
post() {
|
||||||
this.posting = true;
|
this.posting = true;
|
||||||
const viaMobile = this.$store.state.settings.disableViaMobile !== true;
|
const viaMobile = !this.$store.state.settings.disableViaMobile;
|
||||||
this.$root.api('notes/create', {
|
this.$root.api('notes/create', {
|
||||||
text: this.text == '' ? undefined : this.text,
|
text: this.text == '' ? undefined : this.text,
|
||||||
fileIds: this.files.length > 0 ? this.files.map(f => f.id) : undefined,
|
fileIds: this.files.length > 0 ? this.files.map(f => f.id) : undefined,
|
||||||
|
|
|
@ -49,7 +49,7 @@ export default Vue.extend({
|
||||||
padding 0 8px
|
padding 0 8px
|
||||||
|
|
||||||
&.shadow
|
&.shadow
|
||||||
box-shadow 0 0px 8px rgba(0, 0, 0, 0.25)
|
box-shadow 0 0 8px rgba(0, 0, 0, 0.25)
|
||||||
|
|
||||||
&, *
|
&, *
|
||||||
user-select none
|
user-select none
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
input
|
input
|
||||||
min-width 0px
|
min-width 0
|
||||||
|
|
||||||
input:not([type])
|
input:not([type])
|
||||||
input[type='text']
|
input[type='text']
|
||||||
|
|
|
@ -126,7 +126,7 @@ export default (os: MiOS) => new Vuex.Store({
|
||||||
|
|
||||||
logout(ctx) {
|
logout(ctx) {
|
||||||
ctx.commit('updateI', null);
|
ctx.commit('updateI', null);
|
||||||
document.cookie = 'i=;';
|
document.cookie = `i=; max-age=0; domain=${document.location.hostname}`;
|
||||||
localStorage.removeItem('i');
|
localStorage.removeItem('i');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -129,7 +129,7 @@ export const mfmLanguage = P.createLanguage({
|
||||||
mention: () => {
|
mention: () => {
|
||||||
return P((input, i) => {
|
return P((input, i) => {
|
||||||
const text = input.substr(i);
|
const text = input.substr(i);
|
||||||
const match = text.match(/^@\w([\w-]*\w)?(?:@[\w\.\-]+\w)?/);
|
const match = text.match(/^@\w([\w-]*\w)?(?:@[\w.\-]+\w)?/);
|
||||||
if (!match) return P.makeFailure(i, 'not a mention');
|
if (!match) return P.makeFailure(i, 'not a mention');
|
||||||
if (input[i - 1] != null && input[i - 1].match(/[a-z0-9]/i)) return P.makeFailure(i, 'not a mention');
|
if (input[i - 1] != null && input[i - 1].match(/[a-z0-9]/i)) return P.makeFailure(i, 'not a mention');
|
||||||
return P.makeSuccess(i + match[0].length, match[0]);
|
return P.makeSuccess(i + match[0].length, match[0]);
|
||||||
|
@ -141,7 +141,7 @@ export const mfmLanguage = P.createLanguage({
|
||||||
},
|
},
|
||||||
hashtag: () => P((input, i) => {
|
hashtag: () => P((input, i) => {
|
||||||
const text = input.substr(i);
|
const text = input.substr(i);
|
||||||
const match = text.match(/^#([^\s\.,!\?'"#:\/\[\]【】]+)/i);
|
const match = text.match(/^#([^\s.,!?'"#:\/\[\]【】]+)/i);
|
||||||
if (!match) return P.makeFailure(i, 'not a hashtag');
|
if (!match) return P.makeFailure(i, 'not a hashtag');
|
||||||
let hashtag = match[1];
|
let hashtag = match[1];
|
||||||
hashtag = removeOrphanedBrackets(hashtag);
|
hashtag = removeOrphanedBrackets(hashtag);
|
||||||
|
|
|
@ -36,4 +36,4 @@ export function createTree(type: string, children: MfmForest, props: any): MfmTr
|
||||||
return T.createTree({ type, props }, children);
|
return T.createTree({ type, props }, children);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const urlRegex = /^https?:\/\/[\w\/:%#@\$&\?!\(\)\[\]~\.,=\+\-]+/;
|
export const urlRegex = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+/;
|
||||||
|
|
|
@ -64,7 +64,7 @@ export class ASEvaluator {
|
||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
private interpolate(str: string, scope: Scope) {
|
private interpolate(str: string, scope: Scope) {
|
||||||
return str.replace(/\{(.+?)\}/g, match => {
|
return str.replace(/{(.+?)}/g, match => {
|
||||||
const v = scope.getState(match.slice(1, -1).trim());
|
const v = scope.getState(match.slice(1, -1).trim());
|
||||||
return v == null ? 'NULL' : v.toString();
|
return v == null ? 'NULL' : v.toString();
|
||||||
});
|
});
|
||||||
|
@ -169,6 +169,7 @@ export class ASEvaluator {
|
||||||
stringToNumber: (a: string) => parseInt(a),
|
stringToNumber: (a: string) => parseInt(a),
|
||||||
numberToString: (a: number) => a.toString(),
|
numberToString: (a: number) => a.toString(),
|
||||||
splitStrByLine: (a: string) => a.split('\n'),
|
splitStrByLine: (a: string) => a.split('\n'),
|
||||||
|
pick: (list: any[], i: number) => list[i - 1],
|
||||||
random: (probability: number) => Math.floor(seedrandom(`${this.opts.randomSeed}:${block.id}`)() * 100) < probability,
|
random: (probability: number) => Math.floor(seedrandom(`${this.opts.randomSeed}:${block.id}`)() * 100) < probability,
|
||||||
rannum: (min: number, max: number) => min + Math.floor(seedrandom(`${this.opts.randomSeed}:${block.id}`)() * (max - min + 1)),
|
rannum: (min: number, max: number) => min + Math.floor(seedrandom(`${this.opts.randomSeed}:${block.id}`)() * (max - min + 1)),
|
||||||
randomPick: (list: any[]) => list[Math.floor(seedrandom(`${this.opts.randomSeed}:${block.id}`)() * list.length)],
|
randomPick: (list: any[]) => list[Math.floor(seedrandom(`${this.opts.randomSeed}:${block.id}`)() * list.length)],
|
||||||
|
@ -178,6 +179,27 @@ export class ASEvaluator {
|
||||||
seedRandom: (seed: any, probability: number) => Math.floor(seedrandom(seed)() * 100) < probability,
|
seedRandom: (seed: any, probability: number) => Math.floor(seedrandom(seed)() * 100) < probability,
|
||||||
seedRannum: (seed: any, min: number, max: number) => min + Math.floor(seedrandom(seed)() * (max - min + 1)),
|
seedRannum: (seed: any, min: number, max: number) => min + Math.floor(seedrandom(seed)() * (max - min + 1)),
|
||||||
seedRandomPick: (seed: any, list: any[]) => list[Math.floor(seedrandom(seed)() * list.length)],
|
seedRandomPick: (seed: any, list: any[]) => list[Math.floor(seedrandom(seed)() * list.length)],
|
||||||
|
DRPWPM: (list: string[]) => {
|
||||||
|
const xs = [];
|
||||||
|
let totalFactor = 0;
|
||||||
|
for (const x of list) {
|
||||||
|
const parts = x.split(' ');
|
||||||
|
const factor = parseInt(parts.pop()!, 10);
|
||||||
|
const text = parts.join(' ');
|
||||||
|
totalFactor += factor;
|
||||||
|
xs.push({ factor, text });
|
||||||
|
}
|
||||||
|
const r = seedrandom(`${day}:${block.id}`)() * totalFactor;
|
||||||
|
let stackedFactor = 0;
|
||||||
|
for (const x of xs) {
|
||||||
|
if (r >= stackedFactor && r <= x.factor) {
|
||||||
|
return x.text;
|
||||||
|
} else {
|
||||||
|
stackedFactor += x.factor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return xs[0].text;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const fnName = block.type;
|
const fnName = block.type;
|
||||||
|
|
|
@ -23,6 +23,7 @@ import {
|
||||||
faSortNumericUp,
|
faSortNumericUp,
|
||||||
faExchangeAlt,
|
faExchangeAlt,
|
||||||
faRecycle,
|
faRecycle,
|
||||||
|
faIndent,
|
||||||
} from '@fortawesome/free-solid-svg-icons';
|
} from '@fortawesome/free-solid-svg-icons';
|
||||||
import { faFlag } from '@fortawesome/free-regular-svg-icons';
|
import { faFlag } from '@fortawesome/free-regular-svg-icons';
|
||||||
|
|
||||||
|
@ -72,6 +73,7 @@ export const funcDefs: Record<string, { in: any[]; out: any; category: string; i
|
||||||
stringToNumber: { in: ['string'], out: 'number', category: 'convert', icon: faExchangeAlt, },
|
stringToNumber: { in: ['string'], out: 'number', category: 'convert', icon: faExchangeAlt, },
|
||||||
numberToString: { in: ['number'], out: 'string', category: 'convert', icon: faExchangeAlt, },
|
numberToString: { in: ['number'], out: 'string', category: 'convert', icon: faExchangeAlt, },
|
||||||
splitStrByLine: { in: ['string'], out: 'stringArray', category: 'convert', icon: faExchangeAlt, },
|
splitStrByLine: { in: ['string'], out: 'stringArray', category: 'convert', icon: faExchangeAlt, },
|
||||||
|
pick: { in: [null], out: null, category: 'list', icon: faIndent, },
|
||||||
rannum: { in: ['number', 'number'], out: 'number', category: 'random', icon: faDice, },
|
rannum: { in: ['number', 'number'], out: 'number', category: 'random', icon: faDice, },
|
||||||
dailyRannum: { in: ['number', 'number'], out: 'number', category: 'random', icon: faDice, },
|
dailyRannum: { in: ['number', 'number'], out: 'number', category: 'random', icon: faDice, },
|
||||||
seedRannum: { in: [null, 'number', 'number'], out: 'number', category: 'random', icon: faDice, },
|
seedRannum: { in: [null, 'number', 'number'], out: 'number', category: 'random', icon: faDice, },
|
||||||
|
@ -81,6 +83,7 @@ export const funcDefs: Record<string, { in: any[]; out: any; category: string; i
|
||||||
randomPick: { in: [0], out: 0, category: 'random', icon: faDice, },
|
randomPick: { in: [0], out: 0, category: 'random', icon: faDice, },
|
||||||
dailyRandomPick: { in: [0], out: 0, category: 'random', icon: faDice, },
|
dailyRandomPick: { in: [0], out: 0, category: 'random', icon: faDice, },
|
||||||
seedRandomPick: { in: [null, 0], out: 0, category: 'random', icon: faDice, },
|
seedRandomPick: { in: [null, 0], out: 0, category: 'random', icon: faDice, },
|
||||||
|
DRPWPM: { in: ['stringArray'], out: 'string', category: 'random', icon: faDice, }, // dailyRandomPickWithProbabilityMapping
|
||||||
};
|
};
|
||||||
|
|
||||||
export const literalDefs: Record<string, { out: any; category: string; icon: any; }> = {
|
export const literalDefs: Record<string, { out: any; category: string; icon: any; }> = {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { ulid } from 'ulid';
|
import { ulid } from 'ulid';
|
||||||
import { genAid } from './id/aid';
|
import { genAid } from './id/aid';
|
||||||
import { genMeid } from './id/meid';
|
import { genMeid } from './id/meid';
|
||||||
|
import { genMeidg } from './id/meidg';
|
||||||
import { genObjectId } from './id/object-id';
|
import { genObjectId } from './id/object-id';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
|
|
||||||
|
@ -12,6 +13,7 @@ export function genId(date?: Date): string {
|
||||||
switch (metohd) {
|
switch (metohd) {
|
||||||
case 'aid': return genAid(date);
|
case 'aid': return genAid(date);
|
||||||
case 'meid': return genMeid(date);
|
case 'meid': return genMeid(date);
|
||||||
|
case 'meidg': return genMeidg(date);
|
||||||
case 'ulid': return ulid(date.getTime());
|
case 'ulid': return ulid(date.getTime());
|
||||||
case 'objectid': return genObjectId(date);
|
case 'objectid': return genObjectId(date);
|
||||||
default: throw new Error('unknown id generation method');
|
default: throw new Error('unknown id generation method');
|
||||||
|
|
28
src/misc/id/meidg.ts
Normal file
28
src/misc/id/meidg.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
const CHARS = '0123456789abcdef';
|
||||||
|
|
||||||
|
// 4bit Fixed hex value 'g'
|
||||||
|
// 44bit UNIX Time ms in Hex
|
||||||
|
// 48bit Random value in Hex
|
||||||
|
|
||||||
|
function getTime(time: number) {
|
||||||
|
if (time < 0) time = 0;
|
||||||
|
if (time === 0) {
|
||||||
|
return CHARS[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return time.toString(16).padStart(11, CHARS[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRandom() {
|
||||||
|
let str = '';
|
||||||
|
|
||||||
|
for (let i = 0; i < 12; i++) {
|
||||||
|
str += CHARS[Math.floor(Math.random() * CHARS.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function genMeidg(date: Date): string {
|
||||||
|
return 'g' + getTime(date.getTime()) + getRandom();
|
||||||
|
}
|
|
@ -26,7 +26,7 @@ export class UserProfile {
|
||||||
public birthday: string | null;
|
public birthday: string | null;
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 1024, nullable: true,
|
length: 2048, nullable: true,
|
||||||
comment: 'The description (bio) of the User.'
|
comment: 'The description (bio) of the User.'
|
||||||
})
|
})
|
||||||
public description: string | null;
|
public description: string | null;
|
||||||
|
|
|
@ -128,6 +128,19 @@ export class UserRepository extends Repository<User> {
|
||||||
detail: true
|
detail: true
|
||||||
}),
|
}),
|
||||||
twoFactorEnabled: profile!.twoFactorEnabled,
|
twoFactorEnabled: profile!.twoFactorEnabled,
|
||||||
|
twitter: profile!.twitter ? {
|
||||||
|
id: profile!.twitterUserId,
|
||||||
|
screenName: profile!.twitterScreenName
|
||||||
|
} : null,
|
||||||
|
github: profile!.github ? {
|
||||||
|
id: profile!.githubId,
|
||||||
|
login: profile!.githubLogin
|
||||||
|
} : null,
|
||||||
|
discord: profile!.discord ? {
|
||||||
|
id: profile!.discordId,
|
||||||
|
username: profile!.discordUsername,
|
||||||
|
discriminator: profile!.discordDiscriminator
|
||||||
|
} : null,
|
||||||
} : {}),
|
} : {}),
|
||||||
|
|
||||||
...(opts.detail && meId === user.id ? {
|
...(opts.detail && meId === user.id ? {
|
||||||
|
@ -217,7 +230,7 @@ export class UserRepository extends Repository<User> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public isValidBirthday(birthday: string): boolean {
|
public isValidBirthday(birthday: string): boolean {
|
||||||
return typeof birthday == 'string' && /^([0-9]{4})\-([0-9]{2})-([0-9]{2})$/.test(birthday);
|
return typeof birthday == 'string' && /^([0-9]{4})-([0-9]{2})-([0-9]{2})$/.test(birthday);
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ export const meta = {
|
||||||
},
|
},
|
||||||
|
|
||||||
type: {
|
type: {
|
||||||
validator: $.optional.str.match(/^[a-zA-Z\/\-\*]+$/)
|
validator: $.optional.str.match(/^[a-zA-Z\/\-*]+$/)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ export const meta = {
|
||||||
},
|
},
|
||||||
|
|
||||||
type: {
|
type: {
|
||||||
validator: $.optional.str.match(/^[a-zA-Z\/\-\*]+$/)
|
validator: $.optional.str.match(/^[a-zA-Z\/\-*]+$/)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ for (const endpoint of endpoints) {
|
||||||
} else {
|
} else {
|
||||||
if (endpoint.name.includes('-')) {
|
if (endpoint.name.includes('-')) {
|
||||||
// 後方互換性のため
|
// 後方互換性のため
|
||||||
router.post(`/${endpoint.name.replace(/\-/g, '_')}`, handler.bind(null, endpoint));
|
router.post(`/${endpoint.name.replace(/-/g, '_')}`, handler.bind(null, endpoint));
|
||||||
}
|
}
|
||||||
router.post(`/${endpoint.name}`, handler.bind(null, endpoint));
|
router.post(`/${endpoint.name}`, handler.bind(null, endpoint));
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ export function convertSchemaToOpenApiSchema(schema: Schema) {
|
||||||
const res: any = schema;
|
const res: any = schema;
|
||||||
|
|
||||||
if (schema.type === 'object' && schema.properties) {
|
if (schema.type === 'object' && schema.properties) {
|
||||||
res.required = Object.entries(schema.properties).filter(([k, v]) => v.optional !== true).map(([k]) => k);
|
res.required = Object.entries(schema.properties).filter(([k, v]) => !v.optional).map(([k]) => k);
|
||||||
|
|
||||||
for (const k of Object.keys(schema.properties)) {
|
for (const k of Object.keys(schema.properties)) {
|
||||||
res.properties[k] = convertSchemaToOpenApiSchema(schema.properties[k]);
|
res.properties[k] = convertSchemaToOpenApiSchema(schema.properties[k]);
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
"radix": false,
|
"radix": false,
|
||||||
"ban-types": [
|
"ban-types": [
|
||||||
true,
|
true,
|
||||||
"Object"
|
["Object", "Use {} instead."]
|
||||||
],
|
],
|
||||||
"ban": [
|
"ban": [
|
||||||
true,
|
true,
|
||||||
|
|
|
@ -95,7 +95,7 @@ module.exports = {
|
||||||
loader: 'css-loader'
|
loader: 'css-loader'
|
||||||
}, postcss]
|
}, postcss]
|
||||||
}, {
|
}, {
|
||||||
test: /\.(eot|woff|woff2|svg|ttf)([\?]?.*)$/,
|
test: /\.(eot|woff|woff2|svg|ttf)([?]?.*)$/,
|
||||||
loader: 'url-loader'
|
loader: 'url-loader'
|
||||||
}, {
|
}, {
|
||||||
test: /\.json5$/,
|
test: /\.json5$/,
|
||||||
|
|
Loading…
Reference in a new issue