Merge remote-tracking branch 'upstream/develop' into shigusegubu

* upstream/develop: (37 commits)
  Match users using startsWith instead of match.
  Match emoji using startsWith instead of match.
  remove-unused-settings
  Preserve subject in replies.
  Don't use nsfw clickthrough if the post is collapsed by default.
  correct /static/config.json decoding
  save /api/statusnet/config.json connection
  rename apiStatusnetConfigSitePleromafe to apiConfig
  fix typo
  Add a checkbox for marking a post's attachments as NSFW
  When a post with a subject is collapsed, hide its attachments.
  Make interface language configurable from settings
  attachment: add support for rendering alt text on images
  Don't hide replies when inConversation.
  Fix indentation
  Remove old implementation of isReply.
  Add settings for changing the visibility of replies in the timeline.
  Update Russian translations
  update
  fixed error not displaying for 500 error.
  ...
This commit is contained in:
Henry Jameson 2018-08-27 14:32:55 +03:00
commit 16ec650b71
23 changed files with 392 additions and 168 deletions

View file

@ -63,6 +63,7 @@
"html-webpack-plugin": "^2.8.1", "html-webpack-plugin": "^2.8.1",
"http-proxy-middleware": "^0.17.2", "http-proxy-middleware": "^0.17.2",
"inject-loader": "^2.0.1", "inject-loader": "^2.0.1",
"iso-639-1": "^2.0.3",
"isparta-loader": "^2.0.0", "isparta-loader": "^2.0.0",
"json-loader": "^0.5.4", "json-loader": "^0.5.4",
"karma": "^1.3.0", "karma": "^1.3.0",

View file

@ -20,6 +20,10 @@ export default {
data: () => ({ data: () => ({
mobileActivePanel: 'timeline' mobileActivePanel: 'timeline'
}), }),
created () {
// Load the locale from the storage
this.$i18n.locale = this.$store.state.config.interfaceLanguage
},
computed: { computed: {
currentUser () { return this.$store.state.users.currentUser }, currentUser () { return this.$store.state.users.currentUser },
background () { background () {
@ -29,7 +33,7 @@ export default {
style () { return { 'background-image': `url(${this.background})` } }, style () { return { 'background-image': `url(${this.background})` } },
sitename () { return this.$store.state.config.name }, sitename () { return this.$store.state.config.name },
chat () { return this.$store.state.chat.channel.state === 'joined' }, chat () { return this.$store.state.chat.channel.state === 'joined' },
showWhoToFollowPanel () { return this.$store.state.config.showWhoToFollowPanel }, suggestionsEnabled () { return this.$store.state.config.suggestionsEnabled },
showInstanceSpecificPanel () { return this.$store.state.config.showInstanceSpecificPanel } showInstanceSpecificPanel () { return this.$store.state.config.showInstanceSpecificPanel }
}, },
methods: { methods: {

View file

@ -63,8 +63,6 @@ button{
box-shadow: 0px 0px 2px black; box-shadow: 0px 0px 2px black;
font-size: 14px; font-size: 14px;
font-family: sans-serif; font-family: sans-serif;
min-width: 10em;
min-height: 2em;
&:hover { &:hover {
box-shadow: 0px 0px 4px rgba(255, 255, 255, 0.3); box-shadow: 0px 0px 4px rgba(255, 255, 255, 0.3);

View file

@ -24,7 +24,7 @@
<user-panel></user-panel> <user-panel></user-panel>
<nav-panel></nav-panel> <nav-panel></nav-panel>
<instance-specific-panel v-if="showInstanceSpecificPanel"></instance-specific-panel> <instance-specific-panel v-if="showInstanceSpecificPanel"></instance-specific-panel>
<who-to-follow-panel v-if="currentUser && showWhoToFollowPanel"></who-to-follow-panel> <who-to-follow-panel v-if="currentUser && suggestionsEnabled"></who-to-follow-panel>
<notifications v-if="currentUser"></notifications> <notifications v-if="currentUser"></notifications>
</div> </div>
</div> </div>

View file

@ -10,7 +10,7 @@
<a href="#" @click.prevent="toggleHidden()">Hide</a> <a href="#" @click.prevent="toggleHidden()">Hide</a>
</div> </div>
<a v-if="type === 'image' && !hidden" class="image-attachment" :href="attachment.url" target="_blank"> <a v-if="type === 'image' && !hidden" class="image-attachment" :href="attachment.url" target="_blank" :title="attachment.description">
<StillImage :class="{'small': isSmall}" referrerpolicy="no-referrer" :mimetype="attachment.mimetype" :src="attachment.large_thumb_url || attachment.url"/> <StillImage :class="{'small': isSmall}" referrerpolicy="no-referrer" :mimetype="attachment.mimetype" :src="attachment.large_thumb_url || attachment.url"/>
</a> </a>

View file

@ -0,0 +1,38 @@
<template>
<div>
<label for="interface-language-switcher" class='select'>
<select id="interface-language-switcher" v-model="language">
<option v-for="(langCode, i) in languageCodes" :value="langCode">
{{ languageNames[i] }}
</option>
</select>
<i class="icon-down-open"/>
</label>
</div>
</template>
<script>
import languagesObject from '../../i18n/messages'
import ISO6391 from 'iso-639-1'
import _ from 'lodash'
export default {
computed: {
languageCodes () {
return Object.keys(languagesObject)
},
languageNames () {
return _.map(this.languageCodes, ISO6391.getName)
},
language: {
get: function () { return this.$store.state.config.interfaceLanguage },
set: function (val) {
this.$store.dispatch('setOption', { name: 'interfaceLanguage', value: val })
this.$i18n.locale = val
}
}
}
}
</script>

View file

@ -34,6 +34,11 @@
@import '../../_variables.scss'; @import '../../_variables.scss';
.login-form { .login-form {
.btn {
min-height: 28px;
width: 10em;
}
.error { .error {
text-align: center; text-align: center;
} }

View file

@ -24,7 +24,8 @@ const PostStatusForm = {
'replyTo', 'replyTo',
'repliedUser', 'repliedUser',
'attentions', 'attentions',
'messageScope' 'messageScope',
'subject'
], ],
components: { components: {
MediaUpload MediaUpload
@ -52,7 +53,9 @@ const PostStatusForm = {
posting: false, posting: false,
highlighted: 0, highlighted: 0,
newStatus: { newStatus: {
spoilerText: this.subject,
status: statusText, status: statusText,
nsfw: false,
files: [], files: [],
visibility: this.messageScope || this.$store.state.users.currentUser.default_scope visibility: this.messageScope || this.$store.state.users.currentUser.default_scope
}, },
@ -72,7 +75,7 @@ const PostStatusForm = {
const firstchar = this.textAtCaret.charAt(0) const firstchar = this.textAtCaret.charAt(0)
if (firstchar === '@') { if (firstchar === '@') {
const matchedUsers = filter(this.users, (user) => (String(user.name + user.screen_name)).toUpperCase() const matchedUsers = filter(this.users, (user) => (String(user.name + user.screen_name)).toUpperCase()
.match(this.textAtCaret.slice(1).toUpperCase())) .startsWith(this.textAtCaret.slice(1).toUpperCase()))
if (matchedUsers.length <= 0) { if (matchedUsers.length <= 0) {
return false return false
} }
@ -86,7 +89,7 @@ const PostStatusForm = {
})) }))
} else if (firstchar === ':') { } else if (firstchar === ':') {
if (this.textAtCaret === ':') { return } if (this.textAtCaret === ':') { return }
const matchedEmoji = filter(this.emoji.concat(this.customEmoji), (emoji) => emoji.shortcode.match(this.textAtCaret.slice(1))) const matchedEmoji = filter(this.emoji.concat(this.customEmoji), (emoji) => emoji.shortcode.startsWith(this.textAtCaret.slice(1)))
if (matchedEmoji.length <= 0) { if (matchedEmoji.length <= 0) {
return false return false
} }
@ -204,6 +207,7 @@ const PostStatusForm = {
status: newStatus.status, status: newStatus.status,
spoilerText: newStatus.spoilerText || null, spoilerText: newStatus.spoilerText || null,
visibility: newStatus.visibility, visibility: newStatus.visibility,
sensitive: newStatus.nsfw,
media: newStatus.files, media: newStatus.files,
store: this.$store, store: this.$store,
inReplyToStatusId: this.replyTo inReplyToStatusId: this.replyTo

View file

@ -75,6 +75,11 @@
</div> </div>
</div> </div>
</div> </div>
<div class="upload_settings" v-if="newStatus.files.length > 0">
<input type="checkbox" id="filesSensitive" v-model="newStatus.nsfw">
<label for="filesSensitive" v-if="newStatus.nsfw">{{$t('post_status.attachments_sensitive')}}</label>
<label for="filesSensitive" v-else v-html="$t('post_status.attachments_not_sensitive')"></label>
</div>
</form> </form>
</div> </div>
</template> </template>
@ -107,6 +112,10 @@
padding: 0.5em; padding: 0.5em;
height: 32px; height: 32px;
button {
width: 10em;
}
p { p {
margin: 0.35em; margin: 0.35em;
padding: 0.35em; padding: 0.35em;

View file

@ -1,5 +1,6 @@
/* eslint-env browser */ /* eslint-env browser */
import StyleSwitcher from '../style_switcher/style_switcher.vue' import StyleSwitcher from '../style_switcher/style_switcher.vue'
import InterfaceLanguageSwitcher from '../interface_language_switcher/interface_language_switcher.vue'
import { filter, trim } from 'lodash' import { filter, trim } from 'lodash'
const settings = { const settings = {
@ -8,6 +9,7 @@ const settings = {
hideAttachmentsLocal: this.$store.state.config.hideAttachments, hideAttachmentsLocal: this.$store.state.config.hideAttachments,
hideAttachmentsInConvLocal: this.$store.state.config.hideAttachmentsInConv, hideAttachmentsInConvLocal: this.$store.state.config.hideAttachmentsInConv,
hideNsfwLocal: this.$store.state.config.hideNsfw, hideNsfwLocal: this.$store.state.config.hideNsfw,
replyVisibilityLocal: this.$store.state.config.replyVisibility,
loopVideoLocal: this.$store.state.config.loopVideo, loopVideoLocal: this.$store.state.config.loopVideo,
loopVideoSilentOnlyLocal: this.$store.state.config.loopVideoSilentOnly, loopVideoSilentOnlyLocal: this.$store.state.config.loopVideoSilentOnly,
muteWordsString: this.$store.state.config.muteWords.join('\n'), muteWordsString: this.$store.state.config.muteWords.join('\n'),
@ -27,7 +29,8 @@ const settings = {
} }
}, },
components: { components: {
StyleSwitcher StyleSwitcher,
InterfaceLanguageSwitcher
}, },
computed: { computed: {
user () { user () {
@ -44,6 +47,9 @@ const settings = {
hideNsfwLocal (value) { hideNsfwLocal (value) {
this.$store.dispatch('setOption', { name: 'hideNsfw', value }) this.$store.dispatch('setOption', { name: 'hideNsfw', value })
}, },
replyVisibilityLocal (value) {
this.$store.dispatch('setOption', { name: 'replyVisibility', value })
},
loopVideoLocal (value) { loopVideoLocal (value) {
this.$store.dispatch('setOption', { name: 'loopVideo', value }) this.$store.dispatch('setOption', { name: 'loopVideo', value })
}, },

View file

@ -38,6 +38,16 @@
<input type="checkbox" id="hoverPreview" v-model="hoverPreviewLocal"> <input type="checkbox" id="hoverPreview" v-model="hoverPreviewLocal">
<label for="hoverPreview">{{$t('settings.reply_link_preview')}}</label> <label for="hoverPreview">{{$t('settings.reply_link_preview')}}</label>
</li> </li>
<li>
<label for="replyVisibility" class="select">
<select id="replyVisibility" v-model="replyVisibilityLocal">
<option value="all" selected>{{$t('settings.reply_visibility_all')}}</option>
<option value="following">{{$t('settings.reply_visibility_following')}}</option>
<option value="self">{{$t('settings.reply_visibility_self')}}</option>
</select>
<i class="icon-down-open"/>
</label>
</li>
</ul> </ul>
</div> </div>
<div class="setting-item"> <div class="setting-item">
@ -74,6 +84,10 @@
</li> </li>
</ul> </ul>
</div> </div>
<div class="setting-item">
<h2>{{ $t('settings.interfaceLanguage') }}</h2>
<interface-language-switcher />
</div>
</div> </div>
</div> </div>
</template> </template>
@ -117,6 +131,8 @@
.btn { .btn {
margin-top: 1em; margin-top: 1em;
min-height: 28px;
width: 10em;
} }
} }
.setting-list { .setting-list {

View file

@ -83,7 +83,6 @@ const Status = {
return hits return hits
}, },
muted () { return !this.unmuted && (this.status.user.muted || this.muteWordHits.length > 0) }, muted () { return !this.unmuted && (this.status.user.muted || this.muteWordHits.length > 0) },
isReply () { return !!this.status.in_reply_to_status_id },
isFocused () { isFocused () {
// retweet or root of an expanded conversation // retweet or root of an expanded conversation
if (this.focused) { if (this.focused) {
@ -105,6 +104,48 @@ const Status = {
const lengthScore = this.status.statusnet_html.split(/<p|<br/).length + this.status.text.length / 80 const lengthScore = this.status.statusnet_html.split(/<p|<br/).length + this.status.text.length / 80
return lengthScore > 20 return lengthScore > 20
}, },
isReply () {
if (this.status.in_reply_to_status_id) {
return true
}
// For private replies where we can't see the OP, in_reply_to_status_id will be null.
// So instead, check that the post starts with a @mention.
if (this.status.visibility === 'private') {
var textBody = this.status.text
if (this.status.summary !== null) {
textBody = textBody.substring(this.status.summary.length, textBody.length)
}
return textBody.startsWith('@')
}
return false
},
hideReply () {
if (this.$store.state.config.replyVisibility === 'all') {
return false
}
if (this.inlineExpanded || this.expanded || this.inConversation || !this.isReply) {
return false
}
if (this.status.user.id === this.$store.state.users.currentUser.id) {
return false
}
if (this.status.activity_type === 'repeat') {
return false
}
var checkFollowing = this.$store.state.config.replyVisibility === 'following'
for (var i = 0; i < this.status.attentions.length; ++i) {
if (this.status.user.id === this.status.attentions[i].id) {
continue
}
if (checkFollowing && this.status.attentions[i].following) {
return false
}
if (this.status.attentions[i].id === this.$store.state.users.currentUser.id) {
return false
}
}
return this.status.attentions.length > 0
},
hideSubjectStatus () { hideSubjectStatus () {
if (this.tallStatus && !this.$store.state.config.collapseMessageWithSubject) { if (this.tallStatus && !this.$store.state.config.collapseMessageWithSubject) {
return false return false
@ -123,6 +164,21 @@ const Status = {
showingMore () { showingMore () {
return this.showingTall || (this.status.summary && this.expandingSubject) return this.showingTall || (this.status.summary && this.expandingSubject)
}, },
nsfwClickthrough () {
if (!this.status.nsfw) {
return false
}
if (this.status.summary && this.$store.state.config.collapseMessageWithSubject) {
return false
}
return true
},
replySubject () {
if (this.status.summary && !this.status.summary.match(/^re[: ]/i)) {
return 're: '.concat(this.status.summary)
}
return this.status.summary
},
attachmentSize () { attachmentSize () {
if ((this.$store.state.config.hideAttachments && !this.inConversation) || if ((this.$store.state.config.hideAttachments && !this.inConversation) ||
(this.$store.state.config.hideAttachmentsInConv && this.inConversation)) { (this.$store.state.config.hideAttachmentsInConv && this.inConversation)) {

View file

@ -1,5 +1,5 @@
<template> <template>
<div class="status-el" :class="[{ 'status-el_focused': isFocused }, { 'status-conversation': inlineExpanded }]"> <div class="status-el" v-if="!hideReply" :class="[{ 'status-el_focused': isFocused }, { 'status-conversation': inlineExpanded }]">
<template v-if="muted && !noReplyLinks"> <template v-if="muted && !noReplyLinks">
<div class="media status container muted"> <div class="media status container muted">
<small><router-link :to="{ name: 'user-profile', params: { id: status.user.id } }">{{status.user.screen_name}}</router-link></small> <small><router-link :to="{ name: 'user-profile', params: { id: status.user.id } }">{{status.user.screen_name}}</router-link></small>
@ -83,8 +83,8 @@
<a v-if="showingMore" href="#" class="status-unhider" @click.prevent="toggleShowMore">Show less</a> <a v-if="showingMore" href="#" class="status-unhider" @click.prevent="toggleShowMore">Show less</a>
</div> </div>
<div v-if='status.attachments' class='attachments media-body'> <div v-if='status.attachments && !hideSubjectStatus' class='attachments media-body'>
<attachment :size="attachmentSize" :status-id="status.id" :nsfw="status.nsfw" :attachment="attachment" v-for="attachment in status.attachments" :key="attachment.id"> <attachment :size="attachmentSize" :status-id="status.id" :nsfw="nsfwClickthrough" :attachment="attachment" v-for="attachment in status.attachments" :key="attachment.id">
</attachment> </attachment>
</div> </div>
@ -102,7 +102,7 @@
</div> </div>
<div class="container" v-if="replying"> <div class="container" v-if="replying">
<div class="reply-left"/> <div class="reply-left"/>
<post-status-form class="reply-body" :reply-to="status.id" :attentions="status.attentions" :repliedUser="status.user" :message-scope="status.visibility" v-on:posted="toggleReplying"/> <post-status-form class="reply-body" :reply-to="status.id" :attentions="status.attentions" :repliedUser="status.user" :message-scope="status.visibility" :subject="replySubject" v-on:posted="toggleReplying"/>
</div> </div>
</template> </template>
</div> </div>

View file

@ -105,8 +105,8 @@
<span>{{user.followers_count}}</span> <span>{{user.followers_count}}</span>
</div> </div>
</div> </div>
<p v-if="!hideBio && user.description_html" v-html="user.description_html"></p> <p v-if="!hideBio && user.description_html" class="profile-bio" v-html="user.description_html"></p>
<p v-else-if="!hideBio">{{ user.description }}</p> <p v-else-if="!hideBio" class="profile-bio">{{ user.description }}</p>
</div> </div>
</div> </div>
</template> </template>
@ -130,7 +130,11 @@
.profile-panel-body { .profile-panel-body {
word-wrap: break-word; word-wrap: break-word;
background: linear-gradient(to bottom, rgba(0, 0, 0, 0), $fallback--bg 80%); background: linear-gradient(to bottom, rgba(0, 0, 0, 0), $fallback--bg 80%);
background: linear-gradient(to bottom, rgba(0, 0, 0, 0), var(--bg, $fallback--bg) 80%) background: linear-gradient(to bottom, rgba(0, 0, 0, 0), var(--bg, $fallback--bg) 80%);
.profile-bio {
text-align: center;
}
} }
.user-info { .user-info {

View file

@ -1,5 +1,7 @@
function showWhoToFollow (panel, reply, aHost, aUser) { import apiService from '../../services/api/api.service.js'
var users = reply.ids
function showWhoToFollow (panel, reply) {
var users = reply
var cn var cn
var index = 0 var index = 0
var random = Math.floor(Math.random() * 10) var random = Math.floor(Math.random() * 10)
@ -7,12 +9,12 @@ function showWhoToFollow (panel, reply, aHost, aUser) {
var user var user
user = users[cn] user = users[cn]
var img var img
if (user.icon) { if (user.avatar) {
img = user.icon img = user.avatar
} else { } else {
img = '/images/avi.png' img = '/images/avi.png'
} }
var name = user.to_id var name = user.acct
if (index === 0) { if (index === 0) {
panel.img1 = img panel.img1 = img
panel.name1 = name panel.name1 = name
@ -52,27 +54,15 @@ function showWhoToFollow (panel, reply, aHost, aUser) {
} }
function getWhoToFollow (panel) { function getWhoToFollow (panel) {
var user = panel.$store.state.users.currentUser.screen_name var credentials = panel.$store.state.users.currentUser.credentials
if (user) { if (credentials) {
panel.name1 = 'Loading...' panel.name1 = 'Loading...'
panel.name2 = 'Loading...' panel.name2 = 'Loading...'
panel.name3 = 'Loading...' panel.name3 = 'Loading...'
var host = window.location.hostname apiService.suggestions({credentials: credentials})
var whoToFollowProvider = panel.$store.state.config.whoToFollowProvider .then((reply) => {
var url showWhoToFollow(panel, reply)
url = whoToFollowProvider.replace(/{{host}}/g, encodeURIComponent(host)) })
url = url.replace(/{{user}}/g, encodeURIComponent(user))
window.fetch(url, {mode: 'cors'}).then(function (response) {
if (response.ok) {
return response.json()
} else {
panel.name1 = ''
panel.name2 = ''
panel.name3 = ''
}
}).then(function (reply) {
showWhoToFollow(panel, reply, host, user)
})
} }
} }
@ -95,26 +85,26 @@ const WhoToFollowPanel = {
moreUrl: function () { moreUrl: function () {
var host = window.location.hostname var host = window.location.hostname
var user = this.user var user = this.user
var whoToFollowLink = this.$store.state.config.whoToFollowLink var suggestionsWeb = this.$store.state.config.suggestionsWeb
var url var url
url = whoToFollowLink.replace(/{{host}}/g, encodeURIComponent(host)) url = suggestionsWeb.replace(/{{host}}/g, encodeURIComponent(host))
url = url.replace(/{{user}}/g, encodeURIComponent(user)) url = url.replace(/{{user}}/g, encodeURIComponent(user))
return url return url
}, },
showWhoToFollowPanel () { suggestionsEnabled () {
return this.$store.state.config.showWhoToFollowPanel return this.$store.state.config.suggestionsEnabled
} }
}, },
watch: { watch: {
user: function (user, oldUser) { user: function (user, oldUser) {
if (this.showWhoToFollowPanel) { if (this.suggestionsEnabled) {
getWhoToFollow(this) getWhoToFollow(this)
} }
} }
}, },
mounted: mounted:
function () { function () {
if (this.showWhoToFollowPanel) { if (this.suggestionsEnabled) {
getWhoToFollow(this) getWhoToFollow(this)
} }
} }

View file

@ -3,7 +3,7 @@
<div class="panel panel-default base01-background"> <div class="panel panel-default base01-background">
<div class="panel-heading timeline-heading base02-background base04"> <div class="panel-heading timeline-heading base02-background base04">
<div class="title"> <div class="title">
Who to follow {{$t('who_to_follow.who_to_follow')}}
</div> </div>
</div> </div>
<div class="panel-body who-to-follow"> <div class="panel-body who-to-follow">
@ -11,7 +11,7 @@
<img v-bind:src="img1"/> <router-link :to="{ name: 'user-profile', params: { id: id1 } }">{{ name1 }}</router-link><br> <img v-bind:src="img1"/> <router-link :to="{ name: 'user-profile', params: { id: id1 } }">{{ name1 }}</router-link><br>
<img v-bind:src="img2"/> <router-link :to="{ name: 'user-profile', params: { id: id2 } }">{{ name2 }}</router-link><br> <img v-bind:src="img2"/> <router-link :to="{ name: 'user-profile', params: { id: id2 } }">{{ name2 }}</router-link><br>
<img v-bind:src="img3"/> <router-link :to="{ name: 'user-profile', params: { id: id3 } }">{{ name3 }}</router-link><br> <img v-bind:src="img3"/> <router-link :to="{ name: 'user-profile', params: { id: id3 } }">{{ name3 }}</router-link><br>
<img v-bind:src="$store.state.config.logo"> <a v-bind:href="moreUrl" target="_blank">More</a> <img v-bind:src="$store.state.config.logo"> <a v-bind:href="moreUrl" target="_blank">{{$t('who_to_follow.more')}}</a>
</p> </p>
</div> </div>
</div> </div>

View file

@ -325,6 +325,9 @@ const en = {
loop_video: 'Loop videos', loop_video: 'Loop videos',
loop_video_silent_only: 'Loop only videos without sound (i.e. Mastodon\'s "gifs")', loop_video_silent_only: 'Loop only videos without sound (i.e. Mastodon\'s "gifs")',
reply_link_preview: 'Enable reply-link preview on mouse hover', reply_link_preview: 'Enable reply-link preview on mouse hover',
reply_visibility_all: 'Show all replies',
reply_visibility_following: 'Only show replies directed at me or users I\'m following',
reply_visibility_self: 'Only show replies directed at me',
follow_import: 'Follow import', follow_import: 'Follow import',
import_followers_from_a_csv_file: 'Import follows from a csv file', import_followers_from_a_csv_file: 'Import follows from a csv file',
follows_imported: 'Follows imported! Processing them will take a while.', follows_imported: 'Follows imported! Processing them will take a while.',
@ -347,7 +350,8 @@ const en = {
default_vis: 'Default visibility scope', default_vis: 'Default visibility scope',
profile_tab: 'Profile', profile_tab: 'Profile',
security_tab: 'Security', security_tab: 'Security',
data_import_export_tab: 'Data Import / Export' data_import_export_tab: 'Data Import / Export',
interfaceLanguage: 'Interface language'
}, },
notifications: { notifications: {
notifications: 'Notifications', notifications: 'Notifications',
@ -381,6 +385,8 @@ const en = {
account_not_locked_warning: 'Your account is not {0}. Anyone can follow you to view your follower-only posts.', account_not_locked_warning: 'Your account is not {0}. Anyone can follow you to view your follower-only posts.',
account_not_locked_warning_link: 'locked', account_not_locked_warning_link: 'locked',
direct_warning: 'This post will only be visible to all the mentioned users.', direct_warning: 'This post will only be visible to all the mentioned users.',
attachments_sensitive: 'Attachments marked sensitive',
attachments_not_sensitive: 'Attachments <strong>not</strong> marked sensitive',
scope: { scope: {
public: 'Public - Post to public timelines', public: 'Public - Post to public timelines',
unlisted: 'Unlisted - Do not post to public timelines', unlisted: 'Unlisted - Do not post to public timelines',
@ -398,6 +404,10 @@ const en = {
}, },
user_profile: { user_profile: {
timeline_title: 'User Timeline' timeline_title: 'User Timeline'
},
who_to_follow: {
who_to_follow: 'Who to follow',
more: 'More'
} }
} }
@ -781,115 +791,147 @@ const ja = {
chat: 'ローカルチャット', chat: 'ローカルチャット',
timeline: 'タイムライン', timeline: 'タイムライン',
mentions: 'メンション', mentions: 'メンション',
public_tl: '公開タイムライン', public_tl: 'パブリックタイムライン',
twkn: '接続しているすべてのネットワーク' twkn: 'つながっているすべてのネットワーク',
friend_requests: 'Follow Requests'
}, },
user_card: { user_card: {
follows_you: 'フォローされました!', follows_you: 'フォローされました!',
following: 'フォロー', following: 'フォローしています',
follow: 'フォロー', follow: 'フォロー',
blocked: 'ブロック済み', blocked: 'ブロックしています',
block: 'ブロック', block: 'ブロック',
statuses: '投稿', statuses: 'ステータス',
mute: 'ミュート', mute: 'ミュート',
muted: 'ミュート済み', muted: 'ミュートしています!',
followers: 'フォロワー', followers: 'フォロワー',
followees: 'フォロー', followees: 'フォロー',
per_day: '/日', per_day: '/日',
remote_follow: 'リモートフォロー' remote_follow: 'リモートフォロー',
approve: 'Approve',
deny: 'Deny'
}, },
timeline: { timeline: {
show_new: '更新', show_new: 'よみこみ',
error_fetching: '更新の取得中にエラーが発生しました。', error_fetching: 'よみこみがエラーになりました。',
up_to_date: '最新', up_to_date: 'さいしん',
load_older: '古い投稿を読み込む', load_older: 'ふるいステータス',
conversation: '会話', conversation: 'スレッド',
collapse: '折り畳む', collapse: 'たたむ',
repeated: 'リピート' repeated: 'リピート'
}, },
settings: { settings: {
user_settings: 'ユーザー設定', user_settings: 'ユーザーせってい',
name_bio: '名前とプロフィール', name_bio: 'なまえとプロフィール',
name: '名前', name: 'なまえ',
bio: 'プロフィール', bio: 'プロフィール',
avatar: 'アバター', avatar: 'アバター',
current_avatar: 'あなたの現在のアバター', current_avatar: 'いまのアバター',
set_new_avatar: '新しいアバターを設定する', set_new_avatar: 'あたらしいアバターをせっていする',
profile_banner: 'プロフィールバナー', profile_banner: 'プロフィールバナー',
current_profile_banner: '現在のプロフィールバナー', current_profile_banner: 'いまのプロフィールバナー',
set_new_profile_banner: 'しいプロフィールバナーを設定する', set_new_profile_banner: 'あたらしいプロフィールバナーを設定する',
profile_background: 'プロフィールの背景', profile_background: 'プロフィールのバックグラウンド',
set_new_profile_background: '新しいプロフィールの背景を設定する', set_new_profile_background: 'あたらしいプロフィールのバックグラウンドをせっていする',
settings: '設定', settings: 'せってい',
theme: 'テーマ', theme: 'テーマ',
presets: 'プリセット', presets: 'プリセット',
theme_help: '16進数カラーコード (#aabbcc) を使用してカラーテーマをカスタマイズ出来ます。', theme_help: 'カラーテーマをカスタマイズできます。',
radii_help: 'インターフェースの縁の丸さを設定する。', radii_help: 'インターフェースのまるさをせっていする。',
background: '背景', background: 'バックグラウンド',
foreground: '前景', foreground: 'フォアグラウンド',
text: '文字', text: 'もじ',
links: 'リンク', links: 'リンク',
cBlue: '青 (返信, フォロー)', cBlue: 'あお (リプライ, フォロー)',
cRed: ' (キャンセル)', cRed: 'あか (キャンセル)',
cOrange: 'オレンジ (お気に入り)', cOrange: 'オレンジ (おきにいり)',
cGreen: '緑 (リツイート)', cGreen: 'みどり (リピート)',
btnRadius: 'ボタン', btnRadius: 'ボタン',
inputRadius: 'Input fields',
panelRadius: 'パネル', panelRadius: 'パネル',
avatarRadius: 'アバター', avatarRadius: 'アバター',
avatarAltRadius: 'アバター (通知)', avatarAltRadius: 'アバター (つうち)',
tooltipRadius: 'ツールチップ/アラート', tooltipRadius: 'ツールチップ/アラート',
attachmentRadius: 'ファイル', attachmentRadius: 'ファイル',
filtering: 'フィルタリング', filtering: 'フィルタリング',
filtering_explanation: 'これらの単語を含むすべてのものがミュートされます。1行に1つの単語を入力してください。', filtering_explanation: 'これらのことばをふくむすべてのものがミュートされます。1行に1つのことばをかいてください。',
attachments: 'ファイル', attachments: 'ファイル',
hide_attachments_in_tl: 'タイムラインのファイルをす。', hide_attachments_in_tl: 'タイムラインのファイルをかくす。',
hide_attachments_in_convo: '会話の中のファイルを隠す。', hide_attachments_in_convo: 'スレッドのファイルをかくす。',
nsfw_clickthrough: 'NSFWファイルの非表示を有効にする。', nsfw_clickthrough: 'NSFWなファイルをかくす。',
stop_gifs: 'カーソルを重ねた時にGIFを再生する。', stop_gifs: 'カーソルをかさねたとき、GIFをうごかす。',
autoload: '下にスクロールした時に自動で読み込むようにする。', autoload: 'したにスクロールしたとき、じどうてきによみこむ。',
streaming: '上までスクロールした時に自動でストリーミングされるようにする。', streaming: 'うえまでスクロールしたとき、じどうてきにストリーミングする。',
reply_link_preview: 'マウスカーソルを重ねた時に返信のプレビューを表示するようにする。', reply_link_preview: 'カーソルをかさねたとき、リプライのプレビューをみる。',
follow_import: 'フォローインポート', follow_import: 'フォローインポート',
import_followers_from_a_csv_file: 'CSVファイルからフォローをインポートする。', import_followers_from_a_csv_file: 'CSVファイルからフォローをインポートする。',
follows_imported: 'フォローがインポートされました!処理に少し時間がかかるかもしれません。', follows_imported: 'フォローがインポートされました! すこしじかんがかかるかもしれません。',
follow_import_error: 'フォロワーのインポート中にエラーが発生しました。' follow_import_error: 'フォローのインポートがエラーになりました。',
delete_account: 'アカウントをけす',
delete_account_description: 'あなたのアカウントとメッセージが、きえます。',
delete_account_instructions: 'ほんとうにアカウントをけしてもいいなら、パスワードをかいてください。',
delete_account_error: 'アカウントをけすことが、できなかったかもしれません。インスタンスのかんりしゃに、れんらくしてください。',
follow_export: 'フォローのエクスポート',
follow_export_processing: 'おまちください。まもなくファイルをダウンロードできます。',
follow_export_button: 'エクスポート',
change_password: 'パスワードをかえる',
current_password: 'いまのパスワード',
new_password: 'あたらしいパスワード',
confirm_new_password: 'あたらしいパスワードのかくにん',
changed_password: 'パスワードが、かわりました!',
change_password_error: 'パスワードをかえることが、できなかったかもしれません。',
lock_account_description: 'あなたがみとめたひとだけ、あなたのアカウントをフォローできます。'
}, },
notifications: { notifications: {
notifications: '通知', notifications: 'つうち',
read: '読んだ!', read: 'んだ!',
followed_you: 'フォローされました', followed_you: 'フォローされました',
favorited_you: 'あなたの投稿がお気に入りされました', favorited_you: 'あなたのステータスがおきにいりされました',
repeated_you: 'あなたの投稿がリピートされました' repeated_you: 'あなたのステータスがリピートされました'
}, },
login: { login: {
login: 'ログイン', login: 'ログイン',
username: 'ユーザー名', username: 'ユーザーめい',
placeholder: '例えば lain', placeholder: 'れい: lain',
password: 'パスワード', password: 'パスワード',
register: '登録', register: 'はじめる',
logout: 'ログアウト' logout: 'ログアウト'
}, },
registration: { registration: {
registration: '登録', registration: 'はじめる',
fullname: '表示名', fullname: 'スクリーンネーム',
email: 'Eメール', email: 'Eメール',
bio: 'プロフィール', bio: 'プロフィール',
password_confirm: 'パスワードの確認' password_confirm: 'パスワードのかくにん'
}, },
post_status: { post_status: {
posting: '投稿', posting: 'とうこう',
default: 'ちょうどL.A.に着陸しました。' content_warning: 'せつめい (かかなくてもよい)',
default: 'はねだくうこうに、つきました。',
account_not_locked_warning: 'あなたのアカウントは {0} ではありません。あなたをフォローすれば、だれでも、フォロワーげんていのステータスをよむことができます。',
account_not_locked_warning_link: 'ロックされたアカウント',
direct_warning: 'このステータスは、メンションされたユーザーだけが、よむことができます。',
scope: {
public: 'パブリック - パブリックタイムラインにとどきます。',
unlisted: 'アンリステッド - パブリックタイムラインにとどきません。',
private: 'フォロワーげんてい - フォロワーのみにとどきます。',
direct: 'ダイレクト - メンションされたユーザーのみにとどきます。'
}
}, },
finder: { finder: {
find_user: 'ユーザー検索', find_user: 'ユーザーをさがす',
error_fetching_user: 'ユーザー検索でエラーが発生しました' error_fetching_user: 'ユーザーけんさくがエラーになりました。'
}, },
general: { general: {
submit: '送信', submit: 'そうしん',
apply: '適用' apply: 'てきよう'
}, },
user_profile: { user_profile: {
timeline_title: 'ユーザータイムライン' timeline_title: 'ユーザータイムライン'
},
who_to_follow: {
who_to_follow: 'おすすめユーザー',
more: 'くわしく'
} }
} }
@ -1595,6 +1637,8 @@ const ru = {
set_new_profile_background: 'Загрузить новый фон профиля', set_new_profile_background: 'Загрузить новый фон профиля',
settings: 'Настройки', settings: 'Настройки',
theme: 'Тема', theme: 'Тема',
export_theme: 'Экспортировать текущую тему',
import_theme: 'Загрузить сохранённую тему',
presets: 'Пресеты', presets: 'Пресеты',
theme_help: 'Используйте шестнадцатеричные коды цветов (#rrggbb) для настройки темы.', theme_help: 'Используйте шестнадцатеричные коды цветов (#rrggbb) для настройки темы.',
radii_help: 'Округление краёв элементов интерфейса (в пикселях)', radii_help: 'Округление краёв элементов интерфейса (в пикселях)',
@ -1643,7 +1687,13 @@ const ru = {
confirm_new_password: 'Подтверждение нового пароля', confirm_new_password: 'Подтверждение нового пароля',
changed_password: 'Пароль изменён успешно.', changed_password: 'Пароль изменён успешно.',
change_password_error: 'Произошла ошибка при попытке изменить пароль.', change_password_error: 'Произошла ошибка при попытке изменить пароль.',
limited_availability: 'Не доступно в вашем браузере' lock_account_description: 'Аккаунт доступен только подтверждённым подписчикам',
limited_availability: 'Не доступно в вашем браузере',
profile_tab: 'Профиль',
security_tab: 'Безопасность',
data_import_export_tab: 'Импорт / Экспорт данных',
collapse_subject: 'Сворачивать посты с темой',
interfaceLanguage: 'Язык интерфейса'
}, },
notifications: { notifications: {
notifications: 'Уведомления', notifications: 'Уведомления',

View file

@ -49,6 +49,7 @@ const persistedStateOptions = {
'config.hideAttachments', 'config.hideAttachments',
'config.hideAttachmentsInConv', 'config.hideAttachmentsInConv',
'config.hideNsfw', 'config.hideNsfw',
'config.replyVisibility',
'config.autoLoad', 'config.autoLoad',
'config.hoverPreview', 'config.hoverPreview',
'config.streaming', 'config.streaming',
@ -59,6 +60,7 @@ const persistedStateOptions = {
'config.loopVideoSilentOnly', 'config.loopVideoSilentOnly',
'config.pauseOnUnfocused', 'config.pauseOnUnfocused',
'config.stopGifs', 'config.stopGifs',
'config.interfaceLanguage',
'users.lastLoginName', 'users.lastLoginName',
'statuses.notifications.maxSavedId' 'statuses.notifications.maxSavedId'
] ]
@ -78,6 +80,7 @@ const store = new Vuex.Store({
}) })
const i18n = new VueI18n({ const i18n = new VueI18n({
// By default, use the browser locale, we will update it if neccessary
locale: currentLocale, locale: currentLocale,
fallbackLocale: 'en', fallbackLocale: 'en',
messages messages
@ -92,65 +95,79 @@ window.fetch('/api/statusnet/config.json')
store.dispatch('setOption', { name: 'registrationOpen', value: (registrationClosed === '0') }) store.dispatch('setOption', { name: 'registrationOpen', value: (registrationClosed === '0') })
store.dispatch('setOption', { name: 'textlimit', value: parseInt(textlimit) }) store.dispatch('setOption', { name: 'textlimit', value: parseInt(textlimit) })
store.dispatch('setOption', { name: 'server', value: server }) store.dispatch('setOption', { name: 'server', value: server })
})
window.fetch('/static/config.json') var apiConfig = data.site.pleromafe
.then((res) => res.json())
.then((data) => {
const {theme, background, logo, showWhoToFollowPanel, whoToFollowProvider, whoToFollowLink, showInstanceSpecificPanel, scopeOptionsEnabled, collapseMessageWithSubject} = data
store.dispatch('setOption', { name: 'theme', value: theme })
store.dispatch('setOption', { name: 'background', value: background })
store.dispatch('setOption', { name: 'logo', value: logo })
store.dispatch('setOption', { name: 'showWhoToFollowPanel', value: showWhoToFollowPanel })
store.dispatch('setOption', { name: 'whoToFollowProvider', value: whoToFollowProvider })
store.dispatch('setOption', { name: 'whoToFollowLink', value: whoToFollowLink })
store.dispatch('setOption', { name: 'showInstanceSpecificPanel', value: showInstanceSpecificPanel })
store.dispatch('setOption', { name: 'scopeOptionsEnabled', value: scopeOptionsEnabled })
store.dispatch('setOption', { name: 'collapseMessageWithSubject', value: collapseMessageWithSubject })
if (data['chatDisabled']) {
store.dispatch('disableChat')
}
const routes = [ window.fetch('/static/config.json')
{ name: 'root', .then((res) => res.json())
path: '/', .then((data) => {
redirect: to => { var staticConfig = data
var redirectRootLogin = data['redirectRootLogin']
var redirectRootNoLogin = data['redirectRootNoLogin']
return (store.state.users.currentUser ? redirectRootLogin : redirectRootNoLogin) || '/main/all'
}},
{ path: '/main/all', component: PublicAndExternalTimeline },
{ path: '/main/public', component: PublicTimeline },
{ path: '/main/friends', component: FriendsTimeline },
{ path: '/tag/:tag', component: TagTimeline },
{ name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } },
{ name: 'user-profile', path: '/users/:id', component: UserProfile },
{ name: 'mentions', path: '/:username/mentions', component: Mentions },
{ name: 'settings', path: '/settings', component: Settings },
{ name: 'registration', path: '/registration', component: Registration },
{ name: 'registration', path: '/registration/:token', component: Registration },
{ name: 'friend-requests', path: '/friend-requests', component: FollowRequests },
{ name: 'user-settings', path: '/user-settings', component: UserSettings }
]
const router = new VueRouter({ var theme = (apiConfig.theme || staticConfig.theme)
mode: 'history', var background = (apiConfig.background || staticConfig.background)
routes, var logo = (apiConfig.logo || staticConfig.logo)
scrollBehavior: (to, from, savedPosition) => { var redirectRootNoLogin = (apiConfig.redirectRootNoLogin || staticConfig.redirectRootNoLogin)
if (to.matched.some(m => m.meta.dontScroll)) { var redirectRootLogin = (apiConfig.redirectRootLogin || staticConfig.redirectRootLogin)
return false var chatDisabled = (apiConfig.chatDisabled || staticConfig.chatDisabled)
} var showWhoToFollowPanel = (apiConfig.showWhoToFollowPanel || staticConfig.showWhoToFollowPanel)
return savedPosition || { x: 0, y: 0 } var whoToFollowProvider = (apiConfig.whoToFollowProvider || staticConfig.whoToFollowProvider)
var whoToFollowLink = (apiConfig.whoToFollowLink || staticConfig.whoToFollowLink)
var showInstanceSpecificPanel = (apiConfig.showInstanceSpecificPanel || staticConfig.showInstanceSpecificPanel)
var scopeOptionsEnabled = (apiConfig.scopeOptionsEnabled || staticConfig.scopeOptionsEnabled)
var collapseMessageWithSubject = (apiConfig.collapseMessageWithSubject || staticConfig.collapseMessageWithSubject)
store.dispatch('setOption', { name: 'theme', value: theme })
store.dispatch('setOption', { name: 'background', value: background })
store.dispatch('setOption', { name: 'logo', value: logo })
store.dispatch('setOption', { name: 'showWhoToFollowPanel', value: showWhoToFollowPanel })
store.dispatch('setOption', { name: 'whoToFollowProvider', value: whoToFollowProvider })
store.dispatch('setOption', { name: 'whoToFollowLink', value: whoToFollowLink })
store.dispatch('setOption', { name: 'showInstanceSpecificPanel', value: showInstanceSpecificPanel })
store.dispatch('setOption', { name: 'scopeOptionsEnabled', value: scopeOptionsEnabled })
store.dispatch('setOption', { name: 'collapseMessageWithSubject', value: collapseMessageWithSubject })
if (chatDisabled) {
store.dispatch('disableChat')
} }
})
/* eslint-disable no-new */ const routes = [
new Vue({ { name: 'root',
router, path: '/',
store, redirect: to => {
i18n, return (store.state.users.currentUser ? redirectRootLogin : redirectRootNoLogin) || '/main/all'
el: '#app', }},
render: h => h(App) { path: '/main/all', component: PublicAndExternalTimeline },
{ path: '/main/public', component: PublicTimeline },
{ path: '/main/friends', component: FriendsTimeline },
{ path: '/tag/:tag', component: TagTimeline },
{ name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } },
{ name: 'user-profile', path: '/users/:id', component: UserProfile },
{ name: 'mentions', path: '/:username/mentions', component: Mentions },
{ name: 'settings', path: '/settings', component: Settings },
{ name: 'registration', path: '/registration', component: Registration },
{ name: 'registration', path: '/registration/:token', component: Registration },
{ name: 'friend-requests', path: '/friend-requests', component: FollowRequests },
{ name: 'user-settings', path: '/user-settings', component: UserSettings }
]
const router = new VueRouter({
mode: 'history',
routes,
scrollBehavior: (to, from, savedPosition) => {
if (to.matched.some(m => m.meta.dontScroll)) {
return false
}
return savedPosition || { x: 0, y: 0 }
}
})
/* eslint-disable no-new */
new Vue({
router,
store,
i18n,
el: '#app',
render: h => h(App)
})
}) })
}) })
@ -192,3 +209,11 @@ window.fetch('/instance/panel.html')
.then((html) => { .then((html) => {
store.dispatch('setOption', { name: 'instanceSpecificPanelContent', value: html }) store.dispatch('setOption', { name: 'instanceSpecificPanelContent', value: html })
}) })
window.fetch('/nodeinfo/2.0.json')
.then((res) => res.json())
.then((data) => {
const suggestions = data.metadata.suggestions
store.dispatch('setOption', { name: 'suggestionsEnabled', value: suggestions.enabled })
store.dispatch('setOption', { name: 'suggestionsWeb', value: suggestions.web })
})

View file

@ -1,6 +1,8 @@
import { set, delete as del } from 'vue' import { set, delete as del } from 'vue'
import StyleSetter from '../services/style_setter/style_setter.js' import StyleSetter from '../services/style_setter/style_setter.js'
const browserLocale = (window.navigator.language || 'en').split('-')[0]
const defaultState = { const defaultState = {
name: 'Pleroma FE', name: 'Pleroma FE',
colors: {}, colors: {},
@ -15,8 +17,10 @@ const defaultState = {
hoverPreview: true, hoverPreview: true,
pauseOnUnfocused: true, pauseOnUnfocused: true,
stopGifs: false, stopGifs: false,
replyVisibility: 'all',
muteWords: [], muteWords: [],
highlight: {} highlight: {},
interfaceLanguage: browserLocale
} }
const config = { const config = {

View file

@ -37,6 +37,7 @@ const CHANGE_PASSWORD_URL = '/api/pleroma/change_password'
const FOLLOW_REQUESTS_URL = '/api/pleroma/friend_requests' const FOLLOW_REQUESTS_URL = '/api/pleroma/friend_requests'
const APPROVE_USER_URL = '/api/pleroma/friendships/approve' const APPROVE_USER_URL = '/api/pleroma/friendships/approve'
const DENY_USER_URL = '/api/pleroma/friendships/deny' const DENY_USER_URL = '/api/pleroma/friendships/deny'
const SUGGESTIONS_URL = '/api/v1/suggestions'
import { each, map } from 'lodash' import { each, map } from 'lodash'
import 'whatwg-fetch' import 'whatwg-fetch'
@ -372,7 +373,7 @@ const unretweet = ({ id, credentials }) => {
}) })
} }
const postStatus = ({credentials, status, spoilerText, visibility, mediaIds, inReplyToStatusId}) => { const postStatus = ({credentials, status, spoilerText, visibility, sensitive, mediaIds, inReplyToStatusId}) => {
const idsText = mediaIds.join(',') const idsText = mediaIds.join(',')
const form = new FormData() const form = new FormData()
@ -380,6 +381,7 @@ const postStatus = ({credentials, status, spoilerText, visibility, mediaIds, inR
form.append('source', 'Pleroma FE') form.append('source', 'Pleroma FE')
if (spoilerText) form.append('spoiler_text', spoilerText) if (spoilerText) form.append('spoiler_text', spoilerText)
if (visibility) form.append('visibility', visibility) if (visibility) form.append('visibility', visibility)
if (sensitive) form.append('sensitive', sensitive)
form.append('media_ids', idsText) form.append('media_ids', idsText)
if (inReplyToStatusId) { if (inReplyToStatusId) {
form.append('in_reply_to_status_id', inReplyToStatusId) form.append('in_reply_to_status_id', inReplyToStatusId)
@ -454,6 +456,12 @@ const fetchMutes = ({credentials}) => {
}).then((data) => data.json()) }).then((data) => data.json())
} }
const suggestions = ({credentials}) => {
return fetch(SUGGESTIONS_URL, {
headers: authHeaders(credentials)
}).then((data) => data.json())
}
const apiService = { const apiService = {
verifyCredentials, verifyCredentials,
fetchTimeline, fetchTimeline,
@ -487,7 +495,8 @@ const apiService = {
changePassword, changePassword,
fetchFollowRequests, fetchFollowRequests,
approveUser, approveUser,
denyUser denyUser,
suggestions
} }
export default apiService export default apiService

View file

@ -25,6 +25,7 @@ const fetchAndUpdate = ({store, credentials, older = false}) => {
.then((notifications) => { .then((notifications) => {
update({store, notifications, older}) update({store, notifications, older})
}, () => store.dispatch('setNotificationsError', { value: true })) }, () => store.dispatch('setNotificationsError', { value: true }))
.catch(() => store.dispatch('setNotificationsError', { value: true }))
} }
const startFetching = ({credentials, store}) => { const startFetching = ({credentials, store}) => {

View file

@ -1,10 +1,10 @@
import { map } from 'lodash' import { map } from 'lodash'
import apiService from '../api/api.service.js' import apiService from '../api/api.service.js'
const postStatus = ({ store, status, spoilerText, visibility, media = [], inReplyToStatusId = undefined }) => { const postStatus = ({ store, status, spoilerText, visibility, sensitive, media = [], inReplyToStatusId = undefined }) => {
const mediaIds = map(media, 'id') const mediaIds = map(media, 'id')
return apiService.postStatus({credentials: store.state.users.currentUser.credentials, status, spoilerText, visibility, mediaIds, inReplyToStatusId}) return apiService.postStatus({credentials: store.state.users.currentUser.credentials, status, spoilerText, visibility, sensitive, mediaIds, inReplyToStatusId})
.then((data) => data.json()) .then((data) => data.json())
.then((data) => { .then((data) => {
if (!data.error) { if (!data.error) {

View file

@ -3081,6 +3081,10 @@ isexe@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
iso-639-1@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/iso-639-1/-/iso-639-1-2.0.3.tgz#72dd3448ac5629c271628c5ac566369428d6ccd0"
isobject@^2.0.0: isobject@^2.0.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"