Compare commits

..

11 Commits

Author SHA1 Message Date
f1047f1ce5 10.87.5 2019-02-20 16:35:36 +09:00
9beddc941a 返信が遷移後も残り続ける問題を修正 2019-02-20 16:35:00 +09:00
3a6a01d2d6 New Crowdin translations (#4328)
* New translations ja-JP.yml (Catalan)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Portuguese)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (Dutch)

* New translations ja-JP.yml (Norwegian)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Chinese Simplified)
2019-02-20 16:27:04 +09:00
e0e4bdbdbc Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2019-02-20 16:14:39 +09:00
b3daf79b6a Update CHANGELOG.md 2019-02-20 16:14:31 +09:00
81aa21915b Fix #4329 (#4330)
* Create xml.ts

* Update well-known.ts

* Update well-known.ts

* Fix typo

* Update well-known.ts

* Update well-known.ts
2019-02-20 16:13:43 +09:00
5aadd80243 Update CHANGELOG.md 2019-02-20 13:41:55 +09:00
23350b1cbc 🎨 2019-02-20 13:41:31 +09:00
daff0977cb Resolve #747 2019-02-20 13:38:48 +09:00
c1e7d56ff8 Fix bug 2019-02-20 10:15:06 +09:00
61aef56f83 🎨 2019-02-20 10:14:11 +09:00
29 changed files with 221 additions and 119 deletions

View File

@ -1,6 +1,13 @@
ChangeLog
=========
10.87.5
----------
* モバイル版でも連携サービスを表示するように
* webfingerのacceptが反映されない問題を修正
* 返信が遷移後も残り続ける問題を修正
* デザインの調整
10.87.4
----------
* フォローリクエストを許可するときにエラーになる問題を修正

View File

@ -1353,6 +1353,7 @@ desktop/views/pages/user/user.header.vue:
following: "フォロー"
followers: "フォロワー"
is-bot: "このアカウントはBotです"
no-description: "自己紹介はありません"
years-old: "{age}歳"
year: "年"
month: "月"

View File

@ -1353,6 +1353,7 @@ desktop/views/pages/user/user.header.vue:
following: "フォロー"
followers: "フォロワー"
is-bot: "このアカウントはBotです"
no-description: "自己紹介はありません"
years-old: "{age}歳"
year: "年"
month: "月"

View File

@ -1353,6 +1353,7 @@ desktop/views/pages/user/user.header.vue:
following: "Following"
followers: "Followers"
is-bot: "This account is a Bot"
no-description: "自己紹介はありません"
years-old: "{age} years old"
year: "/"
month: "/"

View File

@ -1353,6 +1353,7 @@ desktop/views/pages/user/user.header.vue:
following: "フォロー"
followers: "フォロワー"
is-bot: "このアカウントはBotです"
no-description: "自己紹介はありません"
years-old: "{age}歳"
year: "年"
month: "月"

View File

@ -1353,6 +1353,7 @@ desktop/views/pages/user/user.header.vue:
following: "Suit"
followers: "Abonné·e·s"
is-bot: "Ce compte est un Bot"
no-description: "自己紹介はありません"
years-old: "{age} ans"
year: "/"
month: "/"

View File

@ -1353,6 +1353,7 @@ desktop/views/pages/user/user.header.vue:
following: "フォロー"
followers: "フォロワー"
is-bot: "このアカウントはBotです"
no-description: "自己紹介はありません"
years-old: "{age}歳"
year: "年"
month: "月"

View File

@ -1353,6 +1353,7 @@ desktop/views/pages/user/user.header.vue:
following: "フォロー"
followers: "フォロワー"
is-bot: "このアカウントはBotや"
no-description: "自己紹介はありません"
years-old: "{age}歳"
year: "年"
month: "月"

View File

@ -214,7 +214,7 @@ common/views/pages/explore.vue:
recently-registered-users: "신규 사용자"
popular-tags: "인기 태그"
federated: "연합"
explore: "{host} 탐색"
explore: "{host}을(를) 탐색"
users-info: "현재 {users} 사용자가 등록되어 있습니다"
common/views/components/user-list.vue:
no-users: "사용자가 없습니다"
@ -1353,6 +1353,7 @@ desktop/views/pages/user/user.header.vue:
following: "팔로잉"
followers: "팔로워"
is-bot: "이 계정은 Bot입니다"
no-description: "자기소개가 없습니다"
years-old: "{age}세"
year: "년"
month: "월"

View File

@ -1353,6 +1353,7 @@ desktop/views/pages/user/user.header.vue:
following: "フォロー"
followers: "フォロワー"
is-bot: "このアカウントはBotです"
no-description: "自己紹介はありません"
years-old: "{age}歳"
year: "年"
month: "月"

View File

@ -1353,6 +1353,7 @@ desktop/views/pages/user/user.header.vue:
following: "Følger"
followers: "フォロワー"
is-bot: "このアカウントはBotです"
no-description: "自己紹介はありません"
years-old: "{age}歳"
year: "年"
month: "月"

View File

@ -1353,6 +1353,7 @@ desktop/views/pages/user/user.header.vue:
following: "Śledzeni"
followers: "Śledzący"
is-bot: "To konto jest botem"
no-description: "自己紹介はありません"
years-old: "{age} lat"
year: "/"
month: "/"

View File

@ -1353,6 +1353,7 @@ desktop/views/pages/user/user.header.vue:
following: "フォロー"
followers: "フォロワー"
is-bot: "このアカウントはBotです"
no-description: "自己紹介はありません"
years-old: "{age}歳"
year: "年"
month: "月"

View File

@ -1353,6 +1353,7 @@ desktop/views/pages/user/user.header.vue:
following: "フォロー"
followers: "フォロワー"
is-bot: "このアカウントはBotです"
no-description: "自己紹介はありません"
years-old: "{age}歳"
year: "年"
month: "月"

View File

@ -1353,6 +1353,7 @@ desktop/views/pages/user/user.header.vue:
following: "关注中"
followers: "关注者"
is-bot: "这个账户是Bot"
no-description: "没有自我介绍"
years-old: "{age}岁"
year: "年"
month: "月"

View File

@ -1,7 +1,7 @@
{
"name": "misskey",
"author": "syuilo <i@syuilo.com>",
"version": "10.87.4",
"version": "10.87.5",
"codename": "nighthike",
"repository": {
"type": "git",

View File

@ -0,0 +1,44 @@
<template>
<a class="zxrjzpcj" :href="url" :class="service" target="_blank">
<fa :icon="icon" size="lg" fixed-width /><span>{{ text }}</span>
</a>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
props: ['url', 'text', 'icon', 'service']
});
</script>
<style lang="stylus" scoped>
.zxrjzpcj
padding 6px 8px 6px 6px
border-radius 32px
&:hover
text-decoration none
&.twitter
color #fff
background #1da1f3
&:hover
background #0c87cf
&.github
color #fff
background #171515
&:hover
background #000
&.discord
color #fff
background #7289da
&:hover
background #4968ce
</style>

View File

@ -0,0 +1,26 @@
<template>
<div class="nbogcrmo" :v-if="user.twitter || user.github || user.discord">
<x-integration v-if="user.twitter" service="twitter" :url="`https://twitter.com/${user.twitter.screenName}`" :text="user.twitter.screenName" :icon="['fab', 'twitter']"/>
<x-integration v-if="user.github" service="github" :url="`https://github.com/${user.github.login}`" :text="user.github.login" :icon="['fab', 'github']"/>
<x-integration v-if="user.discord" service="discord" :url="`https://discordapp.com/users/${user.discord.id}`" :text="`${user.discord.username}#${user.discord.discriminator}`" :icon="['fab', 'discord']"/>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import XIntegration from './integrations.integration.vue';
export default Vue.extend({
components: {
XIntegration
},
props: ['user']
});
</script>
<style lang="stylus" scoped>
.nbogcrmo
> *
margin-right 10px
</style>

View File

@ -9,7 +9,7 @@
</div>
</ui-container>
<ui-container :body-togglable="true" ref="tags">
<ui-container :body-togglable="true" :expanded="tag == null" ref="tags">
<template #header><fa :icon="faHashtag" fixed-width/>{{ $t('popular-tags') }}</template>
<div class="vxjfqztj">

View File

@ -30,6 +30,10 @@ export default Vue.extend({
type: Boolean,
default: false
},
expanded: {
type: Boolean,
default: true
},
},
inject: {
inDeck: {
@ -38,7 +42,7 @@ export default Vue.extend({
},
data() {
return {
showBody: true
showBody: this.expanded
};
},
methods: {

View File

@ -23,6 +23,7 @@
<div class="description">
<mfm v-if="user.description" :text="user.description" :is-note="false" :author="user" :i="$store.state.i" :custom-emojis="user.emojis"/>
<p v-else class="empty">{{ $t('no-description') }}</p>
<x-integrations :user="user" style="margin-top:16px;"/>
</div>
<div class="fields" v-if="user.fields">
<dl class="field" v-for="(field, i) in user.fields" :key="i">
@ -52,9 +53,13 @@ import Vue from 'vue';
import i18n from '../../../../i18n';
import * as age from 's-age';
import XUserMenu from '../../../../common/views/components/user-menu.vue';
import XIntegrations from '../../../../common/views/components/integrations.vue';
export default Vue.extend({
i18n: i18n('desktop/views/pages/user/user.header.vue'),
components: {
XIntegrations
},
props: ['user'],
computed: {
style(): any {
@ -215,6 +220,8 @@ export default Vue.extend({
color var(--text)
> .description
font-size 15px
> .empty
margin 0
opacity 0.5
@ -251,6 +258,7 @@ export default Vue.extend({
margin-top 16px
padding-top 16px
border-top solid 1px var(--faceDivider)
font-size 15px
&:empty
display none

View File

@ -1,6 +1,5 @@
<template>
<div class="lnctpgve">
<x-integrations :user="user" v-if="user.twitter || user.github || user.discord"/>
<mk-note-detail v-for="n in user.pinnedNotes" :key="n.id" :note="n" :compact="true"/>
<!--<mk-calendar @chosen="warp" :start="new Date(user.createdAt)"/>-->
<div class="activity">
@ -17,11 +16,8 @@
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../../i18n';
import parseAcct from '../../../../../../misc/acct/parse';
import Progress from '../../../../common/scripts/loading';
import XTimeline from './user.timeline.vue';
import XPhotos from './user.photos.vue';
import XIntegrations from './user.integrations.vue';
import XActivity from '../../../../common/views/components/activity.vue';
export default Vue.extend({
@ -29,7 +25,6 @@ export default Vue.extend({
components: {
XTimeline,
XPhotos,
XIntegrations,
XActivity
},
props: {

View File

@ -1,14 +0,0 @@
<template>
<a :href="url" :class="service" target="_blank">
<fa :icon="icon" size="lg" fixed-width />
<div>{{ text }}</div>
</a>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
props: ['url', 'text', 'icon', 'service']
});
</script>

View File

@ -1,66 +0,0 @@
<template>
<div class="usertwitxxxgithxxdiscxxxintegrat" :v-if="user.twitter || user.github || user.discord">
<x-integration v-if="user.twitter" service="twitter" :url="`https://twitter.com/${user.twitter.screenName}`" :text="user.twitter.screenName" :icon="['fab', 'twitter']"/>
<x-integration v-if="user.github" service="github" :url="`https://github.com/${user.github.login}`" :text="user.github.login" :icon="['fab', 'github']"/>
<x-integration v-if="user.discord" service="discord" :url="`https://discordapp.com/users/${user.discord.id}`" :text="`${user.discord.username}#${user.discord.discriminator}`" :icon="['fab', 'discord']"/>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import XIntegration from './user.integrations.integration.vue';
export default Vue.extend({
components: {
XIntegration
},
props: ['user']
});
</script>
<style lang="stylus" scoped>
.usertwitxxxgithxxdiscxxxintegrat
display flex
> a
display flex
flex 1
align-items center
padding 16px
box-shadow var(--shadow)
border-radius var(--round)
&:not(:last-child)
margin-right 16px
&:hover
text-decoration none
> div
padding-left .2em
line-height 1.3em
flex 1 0
word-wrap anywhere
&.twitter
color #fff
background #1da1f3
&:hover
background #0c87cf
&.github
color #fff
background #171515
&:hover
background #000
&.discord
color #fff
background #7289da
&:hover
background #4968ce
</style>

View File

@ -122,19 +122,23 @@ export default Vue.extend({
};
},
mounted() {
// Get replies
if (!this.compact) {
watch: {
note() {
this.fetchReplies();
}
},
methods: {
fetchReplies() {
if (this.compact) return;
this.$root.api('notes/replies', {
noteId: this.appearNote.id,
limit: 8
}).then(replies => {
this.replies = replies;
});
}
},
},
methods: {
fetchConversation() {
this.conversationFetching = true;

View File

@ -30,10 +30,14 @@ export default Vue.extend({
type: Boolean,
default: false
},
expanded: {
type: Boolean,
default: true
},
},
data() {
return {
showBody: true
showBody: this.expanded
};
},
methods: {

View File

@ -23,6 +23,7 @@
</div>
<div class="description">
<mfm v-if="user.description" :text="user.description" :is-note="false" :author="user" :i="$store.state.i" :custom-emojis="user.emojis"/>
<x-integrations :user="user" style="margin:24px 0;"/>
</div>
<div class="fields" v-if="user.fields">
<dl class="field" v-for="(field, i) in user.fields" :key="i">
@ -86,11 +87,13 @@ import Progress from '../../../../common/scripts/loading';
import XUserMenu from '../../../../common/views/components/user-menu.vue';
import XHome from './home.vue';
import { getStaticImageUrl } from '../../../../common/scripts/get-static-image-url';
import XIntegrations from '../../../../common/views/components/integrations.vue';
export default Vue.extend({
i18n: i18n('mobile/views/pages/user.vue'),
components: {
XHome
XHome,
XIntegrations
},
data() {
return {
@ -245,6 +248,12 @@ export default Vue.extend({
margin 8px 0
color var(--mobileUserPageDescription)
@media (max-width 450px)
font-size 15px
@media (max-width 400px)
font-size 14px
> .fields
margin 8px 0

41
src/prelude/xml.ts Normal file
View File

@ -0,0 +1,41 @@
const map: Record<string, string> = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
'\'': '&apos;'
};
const beginingOfCDATA = '<![CDATA[';
const endOfCDATA = ']]>';
export function escapeValue(x: string): string {
let insideOfCDATA = false;
let builder = '';
for (
let i = 0;
i < x.length;
) {
if (insideOfCDATA) {
if (x.slice(i, i + beginingOfCDATA.length) === beginingOfCDATA) {
insideOfCDATA = true;
i += beginingOfCDATA.length;
} else {
builder += x[i++];
}
} else {
if (x.slice(i, i + endOfCDATA.length) === endOfCDATA) {
insideOfCDATA = false;
i += endOfCDATA.length;
} else {
const b = x[i++];
builder += map[b] || b;
}
}
}
return builder;
}
export function escapeAttribute(x: string): string {
return Object.entries(map).reduce((a, [k, v]) => a.replace(k, v), x);
}

View File

@ -6,27 +6,37 @@ import parseAcct from '../misc/acct/parse';
import User from '../models/user';
import Acct from '../misc/acct/type';
import { links } from './nodeinfo';
import { escapeAttribute, escapeValue } from '../prelude/xml';
// Init router
const router = new Router();
const XRD = (...x: { element: string, value?: string, attributes?: Record<string, string> }[]) =>
`<?xml version="1.0" encoding="UTF-8"?><XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">${x.map(({ element, value, attributes }) =>
`<${
Object.entries(typeof attributes === 'object' && attributes || {}).reduce((a, [k, v]) => `${a} ${k}="${escapeAttribute(v)}"`, element)
}${
typeof value === 'string' ? `>${escapeValue(value)}</${element}` : '/'
}>`).reduce((a, c) => a + c, '')}</XRD>`;
const webFingerPath = '/.well-known/webfinger';
const jrd = 'application/jrd+json';
const xrd = 'application/xrd+xml';
router.get('/.well-known/host-meta', async ctx => {
ctx.set('Content-Type', 'application/xrd+xml');
ctx.body = `<?xml version="1.0" encoding="UTF-8"?>
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
<Link rel="lrdd" type="application/xrd+xml" template="${config.url}${webFingerPath}?resource={uri}"/>
</XRD>
`;
ctx.set('Content-Type', xrd);
ctx.body = XRD({ element: 'Link', attributes: {
type: xrd,
template: `${config.url}${webFingerPath}?resource={uri}`
}});
});
router.get('/.well-known/host-meta.json', async ctx => {
ctx.set('Content-Type', 'application/jrd+json');
ctx.set('Content-Type', jrd);
ctx.body = {
links: [{
rel: 'lrdd',
type: 'application/xrd+xml',
type: jrd,
template: `${config.url}${webFingerPath}?resource={uri}`
}]
};
@ -75,22 +85,38 @@ router.get(webFingerPath, async ctx => {
return;
}
ctx.body = {
subject: `acct:${user.username}@${config.host}`,
links: [{
rel: 'self',
type: 'application/activity+json',
href: `${config.url}/users/${user._id}`
}, {
rel: 'http://webfinger.net/rel/profile-page',
type: 'text/html',
href: `${config.url}/@${user.username}`
}, {
rel: 'http://ostatus.org/schema/1.0/subscribe',
template: `${config.url}/authorize-follow?acct={uri}`
}]
const subject = `acct:${user.username}@${config.host}`;
const self = {
rel: 'self',
type: 'application/activity+json',
href: `${config.url}/users/${user._id}`
};
const profilePage = {
rel: 'http://webfinger.net/rel/profile-page',
type: 'text/html',
href: `${config.url}/@${user.username}`
};
const subscribe = {
rel: 'http://ostatus.org/schema/1.0/subscribe',
template: `${config.url}/authorize-follow?acct={uri}`
};
if (ctx.accepts(jrd, xrd) === xrd) {
ctx.body = XRD(
{ element: 'Subject', value: subject },
{ element: 'Link', attributes: self },
{ element: 'Link', attributes: profilePage },
{ element: 'Link', attributes: subscribe });
ctx.type = xrd;
} else {
ctx.body = {
subject,
links: [self, profilePage, subscribe]
};
ctx.type = jrd;
}
ctx.vary('Accept');
ctx.set('Cache-Control', 'public, max-age=180');
});