commit: 21989c673ee3690f17ed3095e9fbc51501791c02
parent: 42f428d90e87315107dd20975548a5bd63dc2d53
Author: HJ <30-hj@users.noreply.git.pleroma.social>
Date: Tue, 29 Oct 2019 07:41:29 +0000
Merge branch 'settings-refactor' into 'develop'
Settings refactor
See merge request pleroma/pleroma-fe!960
Diffstat:
36 files changed, 401 insertions(+), 649 deletions(-)
diff --git a/src/App.js b/src/App.js
@@ -45,7 +45,7 @@ export default {
}),
created () {
// Load the locale from the storage
- this.$i18n.locale = this.$store.state.config.interfaceLanguage
+ this.$i18n.locale = this.$store.getters.mergedConfig.interfaceLanguage
window.addEventListener('resize', this.updateMobileState)
},
destroyed () {
@@ -93,7 +93,7 @@ export default {
suggestionsEnabled () { return this.$store.state.instance.suggestionsEnabled },
showInstanceSpecificPanel () {
return this.$store.state.instance.showInstanceSpecificPanel &&
- !this.$store.state.config.hideISP &&
+ !this.$store.getters.mergedConfig.hideISP &&
this.$store.state.instance.instanceSpecificPanelContent
},
showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel },
diff --git a/src/components/attachment/attachment.js b/src/components/attachment/attachment.js
@@ -16,8 +16,8 @@ const Attachment = {
data () {
return {
nsfwImage: this.$store.state.instance.nsfwCensorImage || nsfwImage,
- hideNsfwLocal: this.$store.state.config.hideNsfw,
- preloadImage: this.$store.state.config.preloadImage,
+ hideNsfwLocal: this.$store.getters.mergedConfig.hideNsfw,
+ preloadImage: this.$store.getters.mergedConfig.preloadImage,
loading: false,
img: fileTypeService.fileType(this.attachment.mimetype) === 'image' && document.createElement('img'),
modalOpen: false,
@@ -58,7 +58,7 @@ const Attachment = {
}
},
openModal (event) {
- const modalTypes = this.$store.state.config.playVideosInModal
+ const modalTypes = this.$store.getters.mergedConfig.playVideosInModal
? ['image', 'video']
: ['image']
if (fileTypeService.fileMatchesSomeType(modalTypes, this.attachment) ||
@@ -71,7 +71,7 @@ const Attachment = {
}
},
toggleHidden (event) {
- if (this.$store.state.config.useOneClickNsfw && !this.showHidden) {
+ if (this.$store.getters.mergedConfig.useOneClickNsfw && !this.showHidden) {
this.openModal(event)
return
}
diff --git a/src/components/checkbox/checkbox.vue b/src/components/checkbox/checkbox.vue
@@ -1,13 +1,22 @@
<template>
- <label class="checkbox">
+ <label
+ class="checkbox"
+ :class="{ disabled, indeterminate }"
+ >
<input
type="checkbox"
+ :disabled="disabled"
:checked="checked"
:indeterminate.prop="indeterminate"
@change="$emit('change', $event.target.checked)"
>
<i class="checkbox-indicator" />
- <span v-if="!!$slots.default"><slot /></span>
+ <span
+ class="label"
+ v-if="!!$slots.default"
+ >
+ <slot />
+ </span>
</label>
</template>
@@ -17,7 +26,11 @@ export default {
prop: 'checked',
event: 'change'
},
- props: ['checked', 'indeterminate']
+ props: [
+ 'checked',
+ 'indeterminate',
+ 'disabled'
+ ]
}
</script>
@@ -27,12 +40,16 @@ export default {
.checkbox {
position: relative;
display: inline-block;
- padding-left: 1.2em;
min-height: 1.2em;
+ &-indicator {
+ position: relative;
+ padding-left: 1.2em;
+ }
+
&-indicator::before {
position: absolute;
- left: 0;
+ right: 0;
top: 0;
display: block;
content: '✔';
@@ -54,6 +71,17 @@ export default {
box-sizing: border-box;
}
+ &.disabled {
+ .checkbox-indicator::before,
+ .label {
+ opacity: .5;
+ }
+ .label {
+ color: $fallback--faint;
+ color: var(--faint, $fallback--faint);
+ }
+ }
+
input[type=checkbox] {
display: none;
@@ -68,9 +96,6 @@ export default {
color: var(--text, $fallback--text);
}
- &:disabled + .checkbox-indicator::before {
- opacity: .5;
- }
}
& > span {
diff --git a/src/components/emoji_input/emoji_input.js b/src/components/emoji_input/emoji_input.js
@@ -99,7 +99,7 @@ const EmojiInput = {
},
computed: {
padEmoji () {
- return this.$store.state.config.padEmoji
+ return this.$store.getters.mergedConfig.padEmoji
},
suggestions () {
const firstchar = this.textAtCaret.charAt(0)
diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js
@@ -1,3 +1,4 @@
+import Checkbox from '../checkbox/checkbox.vue'
const filterByKeyword = (list, keyword = '') => {
return list.filter(x => x.displayText.includes(keyword))
@@ -13,7 +14,6 @@ const EmojiPicker = {
},
data () {
return {
- labelKey: String(Math.random() * 100000),
keyword: '',
activeGroup: 'custom',
showingStickers: false,
@@ -22,7 +22,8 @@ const EmojiPicker = {
}
},
components: {
- StickerPicker: () => import('../sticker_picker/sticker_picker.vue')
+ StickerPicker: () => import('../sticker_picker/sticker_picker.vue'),
+ Checkbox
},
methods: {
onEmoji (emoji) {
diff --git a/src/components/emoji_picker/emoji_picker.scss b/src/components/emoji_picker/emoji_picker.scss
@@ -14,10 +14,6 @@
padding: 7px;
line-height: normal;
}
- .keep-open-label {
- padding: 0 7px;
- display: flex;
- }
.heading {
display: flex;
diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue
@@ -75,22 +75,10 @@
</span>
</div>
</div>
- <div
- class="keep-open"
- >
- <input
- :id="labelKey + 'keep-open'"
- v-model="keepOpen"
- type="checkbox"
- >
- <label
- class="keep-open-label"
- :for="labelKey + 'keep-open'"
- >
- <div class="keep-open-label-text">
- {{ $t('emoji.keep_open') }}
- </div>
- </label>
+ <div class="keep-open">
+ <Checkbox v-model="keepOpen">
+ {{ $t('emoji.keep_open') }}
+ </Checkbox>
</div>
</div>
<div
diff --git a/src/components/favorite_button/favorite_button.js b/src/components/favorite_button/favorite_button.js
@@ -1,10 +1,9 @@
+import { mapGetters } from 'vuex'
+
const FavoriteButton = {
props: ['status', 'loggedIn'],
data () {
return {
- hidePostStatsLocal: typeof this.$store.state.config.hidePostStats === 'undefined'
- ? this.$store.state.instance.hidePostStats
- : this.$store.state.config.hidePostStats,
animated: false
}
},
@@ -28,7 +27,8 @@ const FavoriteButton = {
'icon-star': this.status.favorited,
'animate-spin': this.animated
}
- }
+ },
+ ...mapGetters(['mergedConfig'])
}
}
diff --git a/src/components/favorite_button/favorite_button.vue b/src/components/favorite_button/favorite_button.vue
@@ -6,7 +6,7 @@
:title="$t('tool_tip.favorite')"
@click.prevent="favorite()"
/>
- <span v-if="!hidePostStatsLocal && status.fave_num > 0">{{ status.fave_num }}</span>
+ <span v-if="!mergedConfig.hidePostStats && status.fave_num > 0">{{ status.fave_num }}</span>
</div>
<div v-else>
<i
@@ -14,7 +14,7 @@
class="button-icon favorite-button"
:title="$t('tool_tip.favorite')"
/>
- <span v-if="!hidePostStatsLocal && status.fave_num > 0">{{ status.fave_num }}</span>
+ <span v-if="!mergedConfig.hidePostStats && status.fave_num > 0">{{ status.fave_num }}</span>
</div>
</template>
diff --git a/src/components/gallery/gallery.js b/src/components/gallery/gallery.js
@@ -29,7 +29,7 @@ const Gallery = {
return rows
},
useContainFit () {
- return this.$store.state.config.useContainFit
+ return this.$store.getters.mergedConfig.useContainFit
}
},
methods: {
diff --git a/src/components/interface_language_switcher/interface_language_switcher.vue b/src/components/interface_language_switcher/interface_language_switcher.vue
@@ -40,7 +40,7 @@ export default {
},
language: {
- get: function () { return this.$store.state.config.interfaceLanguage },
+ get: function () { return this.$store.getters.mergedConfig.interfaceLanguage },
set: function (val) {
this.$store.dispatch('setOption', { name: 'interfaceLanguage', value: val })
this.$i18n.locale = val
diff --git a/src/components/mobile_nav/mobile_nav.js b/src/components/mobile_nav/mobile_nav.js
@@ -63,7 +63,7 @@ const MobileNav = {
this.$refs.notifications.markAsSeen()
},
onScroll ({ target: { scrollTop, clientHeight, scrollHeight } }) {
- if (this.$store.state.config.autoLoad && scrollTop + clientHeight >= scrollHeight) {
+ if (this.$store.getters.mergedConfig.autoLoad && scrollTop + clientHeight >= scrollHeight) {
this.$refs.notifications.fetchOlderNotifications()
}
}
diff --git a/src/components/mobile_post_status_button/mobile_post_status_button.js b/src/components/mobile_post_status_button/mobile_post_status_button.js
@@ -30,7 +30,7 @@ const MobilePostStatusButton = {
return this.autohideFloatingPostButton && (this.hidden || this.inputActive)
},
autohideFloatingPostButton () {
- return !!this.$store.state.config.autohideFloatingPostButton
+ return !!this.$store.getters.mergedConfig.autohideFloatingPostButton
}
},
watch: {
diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js
@@ -39,7 +39,7 @@ const Notification = {
return highlightClass(this.notification.from_profile)
},
userStyle () {
- const highlight = this.$store.state.config.highlight
+ const highlight = this.$store.getters.mergedConfig.highlight
const user = this.notification.from_profile
return highlightStyle(highlight[user.screen_name])
},
diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js
@@ -7,6 +7,8 @@ import fileTypeService from '../../services/file_type/file_type.service.js'
import { findOffset } from '../../services/offset_finder/offset_finder.service.js'
import { reject, map, uniqBy } from 'lodash'
import suggestor from '../emoji_input/suggestor.js'
+import { mapGetters } from 'vuex'
+import Checkbox from '../checkbox/checkbox.vue'
const buildMentionsString = ({ user, attentions = [] }, currentUser) => {
let allAttentions = [...attentions]
@@ -35,7 +37,8 @@ const PostStatusForm = {
MediaUpload,
EmojiInput,
PollForm,
- ScopeSelector
+ ScopeSelector,
+ Checkbox
},
mounted () {
this.resize(this.$refs.textarea)
@@ -50,9 +53,7 @@ const PostStatusForm = {
const preset = this.$route.query.message
let statusText = preset || ''
- const scopeCopy = typeof this.$store.state.config.scopeCopy === 'undefined'
- ? this.$store.state.instance.scopeCopy
- : this.$store.state.config.scopeCopy
+ const { scopeCopy } = this.$store.getters.mergedConfig
if (this.replyTo) {
const currentUser = this.$store.state.users.currentUser
@@ -63,9 +64,7 @@ const PostStatusForm = {
? this.copyMessageScope
: this.$store.state.users.currentUser.default_scope
- const contentType = typeof this.$store.state.config.postContentType === 'undefined'
- ? this.$store.state.instance.postContentType
- : this.$store.state.config.postContentType
+ const { postContentType: contentType } = this.$store.getters.mergedConfig
return {
dropFiles: [],
@@ -94,10 +93,7 @@ const PostStatusForm = {
return this.$store.state.users.currentUser.default_scope
},
showAllScopes () {
- const minimalScopesMode = typeof this.$store.state.config.minimalScopesMode === 'undefined'
- ? this.$store.state.instance.minimalScopesMode
- : this.$store.state.config.minimalScopesMode
- return !minimalScopesMode
+ return !this.mergedConfig.minimalScopesMode
},
emojiUserSuggestor () {
return suggestor({
@@ -145,13 +141,7 @@ const PostStatusForm = {
return this.$store.state.instance.minimalScopesMode
},
alwaysShowSubject () {
- if (typeof this.$store.state.config.alwaysShowSubjectInput !== 'undefined') {
- return this.$store.state.config.alwaysShowSubjectInput
- } else if (typeof this.$store.state.instance.alwaysShowSubjectInput !== 'undefined') {
- return this.$store.state.instance.alwaysShowSubjectInput
- } else {
- return true
- }
+ return this.mergedConfig.alwaysShowSubjectInput
},
postFormats () {
return this.$store.state.instance.postFormats || []
@@ -164,13 +154,14 @@ const PostStatusForm = {
this.$store.state.instance.pollLimits.max_options >= 2
},
hideScopeNotice () {
- return this.$store.state.config.hideScopeNotice
+ return this.$store.getters.mergedConfig.hideScopeNotice
},
pollContentError () {
return this.pollFormVisible &&
this.newStatus.poll &&
this.newStatus.poll.error
- }
+ },
+ ...mapGetters(['mergedConfig'])
},
methods: {
postStatus (newStatus) {
diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue
@@ -261,12 +261,9 @@
v-if="newStatus.files.length > 0"
class="upload_settings"
>
- <input
- id="filesSensitive"
- v-model="newStatus.nsfw"
- type="checkbox"
- >
- <label for="filesSensitive">{{ $t('post_status.attachments_sensitive') }}</label>
+ <Checkbox v-model="newStatus.nsfw">
+ {{ $t('post_status.attachments_sensitive') }}
+ </Checkbox>
</div>
</form>
</div>
diff --git a/src/components/retweet_button/retweet_button.js b/src/components/retweet_button/retweet_button.js
@@ -1,10 +1,9 @@
+import { mapGetters } from 'vuex'
+
const RetweetButton = {
props: ['status', 'loggedIn', 'visibility'],
data () {
return {
- hidePostStatsLocal: typeof this.$store.state.config.hidePostStats === 'undefined'
- ? this.$store.state.instance.hidePostStats
- : this.$store.state.config.hidePostStats,
animated: false
}
},
@@ -28,7 +27,8 @@ const RetweetButton = {
'retweeted-empty': !this.status.repeated,
'animate-spin': this.animated
}
- }
+ },
+ ...mapGetters(['mergedConfig'])
}
}
diff --git a/src/components/retweet_button/retweet_button.vue b/src/components/retweet_button/retweet_button.vue
@@ -7,7 +7,7 @@
:title="$t('tool_tip.repeat')"
@click.prevent="retweet()"
/>
- <span v-if="!hidePostStatsLocal && status.repeat_num > 0">{{ status.repeat_num }}</span>
+ <span v-if="!mergedConfig.hidePostStats && status.repeat_num > 0">{{ status.repeat_num }}</span>
</template>
<template v-else>
<i
@@ -23,7 +23,7 @@
class="button-icon icon-retweet"
:title="$t('tool_tip.repeat')"
/>
- <span v-if="!hidePostStatsLocal && status.repeat_num > 0">{{ status.repeat_num }}</span>
+ <span v-if="!mergedConfig.hidePostStats && status.repeat_num > 0">{{ status.repeat_num }}</span>
</div>
</template>
diff --git a/src/components/settings/settings.js b/src/components/settings/settings.js
@@ -5,88 +5,22 @@ import TabSwitcher from '../tab_switcher/tab_switcher.js'
import StyleSwitcher from '../style_switcher/style_switcher.vue'
import InterfaceLanguageSwitcher from '../interface_language_switcher/interface_language_switcher.vue'
import { extractCommit } from '../../services/version/version.service'
+import { instanceDefaultProperties, defaultState as configDefaultState } from '../../modules/config.js'
+import Checkbox from '../checkbox/checkbox.vue'
const pleromaFeCommitUrl = 'https://git.pleroma.social/pleroma/pleroma-fe/commit/'
const pleromaBeCommitUrl = 'https://git.pleroma.social/pleroma/pleroma/commit/'
+const multiChoiceProperties = [
+ 'postContentType',
+ 'subjectLineBehavior'
+]
+
const settings = {
data () {
- const user = this.$store.state.config
const instance = this.$store.state.instance
return {
- hideAttachmentsLocal: user.hideAttachments,
- padEmojiLocal: user.padEmoji,
- hideAttachmentsInConvLocal: user.hideAttachmentsInConv,
- maxThumbnails: user.maxThumbnails,
- hideNsfwLocal: user.hideNsfw,
- useOneClickNsfw: user.useOneClickNsfw,
- hideISPLocal: user.hideISP,
- preloadImage: user.preloadImage,
-
- hidePostStatsLocal: typeof user.hidePostStats === 'undefined'
- ? instance.hidePostStats
- : user.hidePostStats,
- hidePostStatsDefault: this.$t('settings.values.' + instance.hidePostStats),
-
- hideUserStatsLocal: typeof user.hideUserStats === 'undefined'
- ? instance.hideUserStats
- : user.hideUserStats,
- hideUserStatsDefault: this.$t('settings.values.' + instance.hideUserStats),
-
- hideFilteredStatusesLocal: typeof user.hideFilteredStatuses === 'undefined'
- ? instance.hideFilteredStatuses
- : user.hideFilteredStatuses,
- hideFilteredStatusesDefault: this.$t('settings.values.' + instance.hideFilteredStatuses),
-
- notificationVisibilityLocal: user.notificationVisibility,
- replyVisibilityLocal: user.replyVisibility,
- loopVideoLocal: user.loopVideo,
- muteWordsString: user.muteWords.join('\n'),
- autoLoadLocal: user.autoLoad,
- streamingLocal: user.streaming,
- pauseOnUnfocusedLocal: user.pauseOnUnfocused,
- hoverPreviewLocal: user.hoverPreview,
- autohideFloatingPostButtonLocal: user.autohideFloatingPostButton,
-
- hideMutedPostsLocal: typeof user.hideMutedPosts === 'undefined'
- ? instance.hideMutedPosts
- : user.hideMutedPosts,
- hideMutedPostsDefault: this.$t('settings.values.' + instance.hideMutedPosts),
-
- collapseMessageWithSubjectLocal: typeof user.collapseMessageWithSubject === 'undefined'
- ? instance.collapseMessageWithSubject
- : user.collapseMessageWithSubject,
- collapseMessageWithSubjectDefault: this.$t('settings.values.' + instance.collapseMessageWithSubject),
-
- subjectLineBehaviorLocal: typeof user.subjectLineBehavior === 'undefined'
- ? instance.subjectLineBehavior
- : user.subjectLineBehavior,
- subjectLineBehaviorDefault: instance.subjectLineBehavior,
-
- postContentTypeLocal: typeof user.postContentType === 'undefined'
- ? instance.postContentType
- : user.postContentType,
- postContentTypeDefault: instance.postContentType,
-
- alwaysShowSubjectInputLocal: typeof user.alwaysShowSubjectInput === 'undefined'
- ? instance.alwaysShowSubjectInput
- : user.alwaysShowSubjectInput,
- alwaysShowSubjectInputDefault: this.$t('settings.values.' + instance.alwaysShowSubjectInput),
-
- scopeCopyLocal: typeof user.scopeCopy === 'undefined'
- ? instance.scopeCopy
- : user.scopeCopy,
- scopeCopyDefault: this.$t('settings.values.' + instance.scopeCopy),
-
- minimalScopesModeLocal: typeof user.minimalScopesMode === 'undefined'
- ? instance.minimalScopesMode
- : user.minimalScopesMode,
- minimalScopesModeDefault: this.$t('settings.values.' + instance.minimalScopesMode),
-
- stopGifs: user.stopGifs,
- webPushNotificationsLocal: user.webPushNotifications,
- loopVideoSilentOnlyLocal: user.loopVideosSilentOnly,
loopSilentAvailable:
// Firefox
Object.getOwnPropertyDescriptor(HTMLVideoElement.prototype, 'mozHasAudio') ||
@@ -94,8 +28,6 @@ const settings = {
Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype, 'webkitAudioDecodedByteCount') ||
// Future spec, still not supported in Nightly 63 as of 08/2018
Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype, 'audioTracks'),
- playVideosInModal: user.playVideosInModal,
- useContainFit: user.useContainFit,
backendVersion: instance.backendVersion,
frontendVersion: instance.frontendVersion
@@ -104,7 +36,8 @@ const settings = {
components: {
TabSwitcher,
StyleSwitcher,
- InterfaceLanguageSwitcher
+ InterfaceLanguageSwitcher,
+ Checkbox
},
computed: {
user () {
@@ -122,116 +55,56 @@ const settings = {
},
backendVersionLink () {
return pleromaBeCommitUrl + extractCommit(this.backendVersion)
+ },
+ // Getting localized values for instance-default properties
+ ...instanceDefaultProperties
+ .filter(key => multiChoiceProperties.includes(key))
+ .map(key => [
+ key + 'DefaultValue',
+ function () {
+ return this.$store.getters.instanceDefaultConfig[key]
+ }
+ ])
+ .reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}),
+ ...instanceDefaultProperties
+ .filter(key => !multiChoiceProperties.includes(key))
+ .map(key => [
+ key + 'LocalizedValue',
+ function () {
+ return this.$t('settings.values.' + this.$store.getters.instanceDefaultConfig[key])
+ }
+ ])
+ .reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}),
+ // Generating computed values for vuex properties
+ ...Object.keys(configDefaultState)
+ .map(key => [key, {
+ get () { return this.$store.getters.mergedConfig[key] },
+ set (value) {
+ this.$store.dispatch('setOption', { name: key, value })
+ }
+ }])
+ .reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}),
+ // Special cases (need to transform values)
+ muteWordsString: {
+ get () { return this.$store.getters.mergedConfig.muteWords.join('\n') },
+ set (value) {
+ this.$store.dispatch('setOption', {
+ name: 'muteWords',
+ value: filter(value.split('\n'), (word) => trim(word).length > 0)
+ })
+ }
}
},
+ // Updating nested properties
watch: {
- hideAttachmentsLocal (value) {
- this.$store.dispatch('setOption', { name: 'hideAttachments', value })
- },
- padEmojiLocal (value) {
- this.$store.dispatch('setOption', { name: 'padEmoji', value })
- },
- hideAttachmentsInConvLocal (value) {
- this.$store.dispatch('setOption', { name: 'hideAttachmentsInConv', value })
- },
- hidePostStatsLocal (value) {
- this.$store.dispatch('setOption', { name: 'hidePostStats', value })
- },
- hideUserStatsLocal (value) {
- this.$store.dispatch('setOption', { name: 'hideUserStats', value })
- },
- hideFilteredStatusesLocal (value) {
- this.$store.dispatch('setOption', { name: 'hideFilteredStatuses', value })
- },
- hideNsfwLocal (value) {
- this.$store.dispatch('setOption', { name: 'hideNsfw', value })
- },
- useOneClickNsfw (value) {
- this.$store.dispatch('setOption', { name: 'useOneClickNsfw', value })
- },
- preloadImage (value) {
- this.$store.dispatch('setOption', { name: 'preloadImage', value })
- },
- hideISPLocal (value) {
- this.$store.dispatch('setOption', { name: 'hideISP', value })
- },
- 'notificationVisibilityLocal.likes' (value) {
- this.$store.dispatch('setOption', { name: 'notificationVisibility', value: this.$store.state.config.notificationVisibility })
- },
- 'notificationVisibilityLocal.follows' (value) {
- this.$store.dispatch('setOption', { name: 'notificationVisibility', value: this.$store.state.config.notificationVisibility })
- },
- 'notificationVisibilityLocal.repeats' (value) {
- this.$store.dispatch('setOption', { name: 'notificationVisibility', value: this.$store.state.config.notificationVisibility })
- },
- 'notificationVisibilityLocal.mentions' (value) {
- this.$store.dispatch('setOption', { name: 'notificationVisibility', value: this.$store.state.config.notificationVisibility })
- },
- replyVisibilityLocal (value) {
- this.$store.dispatch('setOption', { name: 'replyVisibility', value })
- },
- loopVideoLocal (value) {
- this.$store.dispatch('setOption', { name: 'loopVideo', value })
- },
- loopVideoSilentOnlyLocal (value) {
- this.$store.dispatch('setOption', { name: 'loopVideoSilentOnly', value })
- },
- autoLoadLocal (value) {
- this.$store.dispatch('setOption', { name: 'autoLoad', value })
- },
- streamingLocal (value) {
- this.$store.dispatch('setOption', { name: 'streaming', value })
- },
- pauseOnUnfocusedLocal (value) {
- this.$store.dispatch('setOption', { name: 'pauseOnUnfocused', value })
- },
- hoverPreviewLocal (value) {
- this.$store.dispatch('setOption', { name: 'hoverPreview', value })
- },
- autohideFloatingPostButtonLocal (value) {
- this.$store.dispatch('setOption', { name: 'autohideFloatingPostButton', value })
- },
- muteWordsString (value) {
- value = filter(value.split('\n'), (word) => trim(word).length > 0)
- this.$store.dispatch('setOption', { name: 'muteWords', value })
- },
- hideMutedPostsLocal (value) {
- this.$store.dispatch('setOption', { name: 'hideMutedPosts', value })
- },
- collapseMessageWithSubjectLocal (value) {
- this.$store.dispatch('setOption', { name: 'collapseMessageWithSubject', value })
- },
- scopeCopyLocal (value) {
- this.$store.dispatch('setOption', { name: 'scopeCopy', value })
- },
- alwaysShowSubjectInputLocal (value) {
- this.$store.dispatch('setOption', { name: 'alwaysShowSubjectInput', value })
- },
- subjectLineBehaviorLocal (value) {
- this.$store.dispatch('setOption', { name: 'subjectLineBehavior', value })
- },
- postContentTypeLocal (value) {
- this.$store.dispatch('setOption', { name: 'postContentType', value })
- },
- minimalScopesModeLocal (value) {
- this.$store.dispatch('setOption', { name: 'minimalScopesMode', value })
- },
- stopGifs (value) {
- this.$store.dispatch('setOption', { name: 'stopGifs', value })
- },
- webPushNotificationsLocal (value) {
- this.$store.dispatch('setOption', { name: 'webPushNotifications', value })
- if (value) this.$store.dispatch('registerPushNotifications')
- },
- playVideosInModal (value) {
- this.$store.dispatch('setOption', { name: 'playVideosInModal', value })
- },
- useContainFit (value) {
- this.$store.dispatch('setOption', { name: 'useContainFit', value })
- },
- maxThumbnails (value) {
- value = this.maxThumbnails = Math.floor(Math.max(value, 0))
- this.$store.dispatch('setOption', { name: 'maxThumbnails', value })
+ notificationVisibility: {
+ handler (value) {
+ this.$store.dispatch('setOption', {
+ name: 'notificationVisibility',
+ value: this.$store.getters.mergedConfig.notificationVisibility
+ })
+ },
+ deep: true
}
}
}
diff --git a/src/components/settings/settings.vue b/src/components/settings/settings.vue
@@ -36,12 +36,9 @@
<interface-language-switcher />
</li>
<li v-if="instanceSpecificPanelPresent">
- <input
- id="hideISP"
- v-model="hideISPLocal"
- type="checkbox"
- >
- <label for="hideISP">{{ $t('settings.hide_isp') }}</label>
+ <Checkbox v-model="hideISP">
+ {{ $t('settings.hide_isp') }}
+ </Checkbox>
</li>
</ul>
</div>
@@ -49,58 +46,42 @@
<h2>{{ $t('nav.timeline') }}</h2>
<ul class="setting-list">
<li>
- <input
- id="hideMutedPosts"
- v-model="hideMutedPostsLocal"
- type="checkbox"
- >
- <label for="hideMutedPosts">{{ $t('settings.hide_muted_posts') }} {{ $t('settings.instance_default', { value: hideMutedPostsDefault }) }}</label>
+ <Checkbox v-model="hideMutedPosts">
+ {{ $t('settings.hide_muted_posts') }} {{ $t('settings.instance_default', { value: hideMutedPostsLocalizedValue }) }}
+ </Checkbox>
</li>
<li>
- <input
- id="collapseMessageWithSubject"
- v-model="collapseMessageWithSubjectLocal"
- type="checkbox"
- >
- <label for="collapseMessageWithSubject">{{ $t('settings.collapse_subject') }} {{ $t('settings.instance_default', { value: collapseMessageWithSubjectDefault }) }}</label>
+ <Checkbox v-model="collapseMessageWithSubject">
+ {{ $t('settings.collapse_subject') }} {{ $t('settings.instance_default', { value: collapseMessageWithSubjectLocalizedValue }) }}
+ </Checkbox>
</li>
<li>
- <input
- id="streaming"
- v-model="streamingLocal"
- type="checkbox"
- >
- <label for="streaming">{{ $t('settings.streaming') }}</label>
+ <Checkbox v-model="streaming">
+ {{ $t('settings.streaming') }}
+ </Checkbox>
<ul
class="setting-list suboptions"
- :class="[{disabled: !streamingLocal}]"
+ :class="[{disabled: !streaming}]"
>
<li>
- <input
- id="pauseOnUnfocused"
- v-model="pauseOnUnfocusedLocal"
- :disabled="!streamingLocal"
- type="checkbox"
+ <Checkbox
+ v-model="pauseOnUnfocused"
+ :disabled="!streaming"
>
- <label for="pauseOnUnfocused">{{ $t('settings.pause_on_unfocused') }}</label>
+ {{ $t('settings.pause_on_unfocused') }}
+ </Checkbox>
</li>
</ul>
</li>
<li>
- <input
- id="autoload"
- v-model="autoLoadLocal"
- type="checkbox"
- >
- <label for="autoload">{{ $t('settings.autoload') }}</label>
+ <Checkbox v-model="autoLoad">
+ {{ $t('settings.autoload') }}
+ </Checkbox>
</li>
<li>
- <input
- id="hoverPreview"
- v-model="hoverPreviewLocal"
- type="checkbox"
- >
- <label for="hoverPreview">{{ $t('settings.reply_link_preview') }}</label>
+ <Checkbox v-model="hoverPreview">
+ {{ $t('settings.reply_link_preview') }}
+ </Checkbox>
</li>
</ul>
</div>
@@ -109,24 +90,14 @@
<h2>{{ $t('settings.composing') }}</h2>
<ul class="setting-list">
<li>
- <input
- id="scopeCopy"
- v-model="scopeCopyLocal"
- type="checkbox"
- >
- <label for="scopeCopy">
- {{ $t('settings.scope_copy') }} {{ $t('settings.instance_default', { value: scopeCopyDefault }) }}
- </label>
+ <Checkbox v-model="scopeCopy">
+ {{ $t('settings.scope_copy') }} {{ $t('settings.instance_default', { value: scopeCopyLocalizedValue }) }}
+ </Checkbox>
</li>
<li>
- <input
- id="subjectHide"
- v-model="alwaysShowSubjectInputLocal"
- type="checkbox"
- >
- <label for="subjectHide">
- {{ $t('settings.subject_input_always_show') }} {{ $t('settings.instance_default', { value: alwaysShowSubjectInputDefault }) }}
- </label>
+ <Checkbox v-model="alwaysShowSubjectInput">
+ {{ $t('settings.subject_input_always_show') }} {{ $t('settings.instance_default', { value: alwaysShowSubjectInputLocalizedValue }) }}
+ </Checkbox>
</li>
<li>
<div>
@@ -137,19 +108,19 @@
>
<select
id="subjectLineBehavior"
- v-model="subjectLineBehaviorLocal"
+ v-model="subjectLineBehavior"
>
<option value="email">
{{ $t('settings.subject_line_email') }}
- {{ subjectLineBehaviorDefault == 'email' ? $t('settings.instance_default_simple') : '' }}
+ {{ subjectLineBehaviorDefaultValue == 'email' ? $t('settings.instance_default_simple') : '' }}
</option>
<option value="masto">
{{ $t('settings.subject_line_mastodon') }}
- {{ subjectLineBehaviorDefault == 'mastodon' ? $t('settings.instance_default_simple') : '' }}
+ {{ subjectLineBehaviorDefaultValue == 'mastodon' ? $t('settings.instance_default_simple') : '' }}
</option>
<option value="noop">
{{ $t('settings.subject_line_noop') }}
- {{ subjectLineBehaviorDefault == 'noop' ? $t('settings.instance_default_simple') : '' }}
+ {{ subjectLineBehaviorDefaultValue == 'noop' ? $t('settings.instance_default_simple') : '' }}
</option>
</select>
<i class="icon-down-open" />
@@ -165,7 +136,7 @@
>
<select
id="postContentType"
- v-model="postContentTypeLocal"
+ v-model="postContentType"
>
<option
v-for="postFormat in postFormats"
@@ -173,7 +144,7 @@
:value="postFormat"
>
{{ $t(`post_status.content_type["${postFormat}"]`) }}
- {{ postContentTypeDefault === postFormat ? $t('settings.instance_default_simple') : '' }}
+ {{ postContentTypeDefaultValue === postFormat ? $t('settings.instance_default_simple') : '' }}
</option>
</select>
<i class="icon-down-open" />
@@ -181,30 +152,19 @@
</div>
</li>
<li>
- <input
- id="minimalScopesMode"
- v-model="minimalScopesModeLocal"
- type="checkbox"
- >
- <label for="minimalScopesMode">
- {{ $t('settings.minimal_scopes_mode') }} {{ $t('settings.instance_default', { value: minimalScopesModeDefault }) }}
- </label>
+ <Checkbox v-model="minimalScopesMode">
+ {{ $t('settings.minimal_scopes_mode') }} {{ $t('settings.instance_default', { value: minimalScopesModeLocalizedValue }) }}
+ </Checkbox>
</li>
<li>
- <input
- id="autohideFloatingPostButton"
- v-model="autohideFloatingPostButtonLocal"
- type="checkbox"
- >
- <label for="autohideFloatingPostButton">{{ $t('settings.autohide_floating_post_button') }}</label>
+ <Checkbox v-model="autohideFloatingPostButton">
+ {{ $t('settings.autohide_floating_post_button') }}
+ </Checkbox>
</li>
<li>
- <input
- id="padEmoji"
- v-model="padEmojiLocal"
- type="checkbox"
- >
- <label for="padEmoji">{{ $t('settings.pad_emoji') }}</label>
+ <Checkbox v-model="padEmoji">
+ {{ $t('settings.pad_emoji') }}
+ </Checkbox>
</li>
</ul>
</div>
@@ -213,23 +173,19 @@
<h2>{{ $t('settings.attachments') }}</h2>
<ul class="setting-list">
<li>
- <input
- id="hideAttachments"
- v-model="hideAttachmentsLocal"
- type="checkbox"
- >
- <label for="hideAttachments">{{ $t('settings.hide_attachments_in_tl') }}</label>
+ <Checkbox v-model="hideAttachments">
+ {{ $t('settings.hide_attachments_in_tl') }}
+ </Checkbox>
</li>
<li>
- <input
- id="hideAttachmentsInConv"
- v-model="hideAttachmentsInConvLocal"
- type="checkbox"
- >
- <label for="hideAttachmentsInConv">{{ $t('settings.hide_attachments_in_convo') }}</label>
+ <Checkbox v-model="hideAttachmentsInConv">
+ {{ $t('settings.hide_attachments_in_convo') }}
+ </Checkbox>
</li>
<li>
- <label for="maxThumbnails">{{ $t('settings.max_thumbnails') }}</label>
+ <label for="maxThumbnails">
+ {{ $t('settings.max_thumbnails') }}
+ </label>
<input
id="maxThumbnails"
v-model.number="maxThumbnails"
@@ -240,60 +196,48 @@
>
</li>
<li>
- <input
- id="hideNsfw"
- v-model="hideNsfwLocal"
- type="checkbox"
- >
- <label for="hideNsfw">{{ $t('settings.nsfw_clickthrough') }}</label>
+ <Checkbox v-model="hideNsfw">
+ {{ $t('settings.nsfw_clickthrough') }}
+ </Checkbox>
</li>
<ul class="setting-list suboptions">
<li>
- <input
- id="preloadImage"
+ <Checkbox
v-model="preloadImage"
- :disabled="!hideNsfwLocal"
- type="checkbox"
+ :disabled="!hideNsfw"
>
- <label for="preloadImage">{{ $t('settings.preload_images') }}</label>
+ {{ $t('settings.preload_images') }}
+ </Checkbox>
</li>
<li>
- <input
- id="useOneClickNsfw"
+ <Checkbox
v-model="useOneClickNsfw"
- :disabled="!hideNsfwLocal"
- type="checkbox"
+ :disabled="!hideNsfw"
>
- <label for="useOneClickNsfw">{{ $t('settings.use_one_click_nsfw') }}</label>
+ {{ $t('settings.use_one_click_nsfw') }}
+ </Checkbox>
</li>
</ul>
<li>
- <input
- id="stopGifs"
- v-model="stopGifs"
- type="checkbox"
- >
- <label for="stopGifs">{{ $t('settings.stop_gifs') }}</label>
+ <Checkbox v-model="stopGifs">
+ {{ $t('settings.stop_gifs') }}
+ </Checkbox>
</li>
<li>
- <input
- id="loopVideo"
- v-model="loopVideoLocal"
- type="checkbox"
- >
- <label for="loopVideo">{{ $t('settings.loop_video') }}</label>
+ <Checkbox v-model="loopVideo">
+ {{ $t('settings.loop_video') }}
+ </Checkbox>
<ul
class="setting-list suboptions"
- :class="[{disabled: !streamingLocal}]"
+ :class="[{disabled: !streaming}]"
>
<li>
- <input
- id="loopVideoSilentOnly"
- v-model="loopVideoSilentOnlyLocal"
- :disabled="!loopVideoLocal || !loopSilentAvailable"
- type="checkbox"
+ <Checkbox
+ v-model="loopVideoSilentOnly"
+ :disabled="!loopVideo || !loopSilentAvailable"
>
- <label for="loopVideoSilentOnly">{{ $t('settings.loop_video_silent_only') }}</label>
+ {{ $t('settings.loop_video_silent_only') }}
+ </Checkbox>
<div
v-if="!loopSilentAvailable"
class="unavailable"
@@ -304,20 +248,14 @@
</ul>
</li>
<li>
- <input
- id="playVideosInModal"
- v-model="playVideosInModal"
- type="checkbox"
- >
- <label for="playVideosInModal">{{ $t('settings.play_videos_in_modal') }}</label>
+ <Checkbox v-model="playVideosInModal">
+ {{ $t('settings.play_videos_in_modal') }}
+ </Checkbox>
</li>
<li>
- <input
- id="useContainFit"
- v-model="useContainFit"
- type="checkbox"
- >
- <label for="useContainFit">{{ $t('settings.use_contain_fit') }}</label>
+ <Checkbox v-model="useContainFit">
+ {{ $t('settings.use_contain_fit') }}
+ </Checkbox>
</li>
</ul>
</div>
@@ -326,14 +264,9 @@
<h2>{{ $t('settings.notifications') }}</h2>
<ul class="setting-list">
<li>
- <input
- id="webPushNotifications"
- v-model="webPushNotificationsLocal"
- type="checkbox"
- >
- <label for="webPushNotifications">
+ <Checkbox v-model="webPushNotifications">
{{ $t('settings.enable_web_push_notifications') }}
- </label>
+ </Checkbox>
</li>
</ul>
</div>
@@ -351,44 +284,24 @@
<span class="label">{{ $t('settings.notification_visibility') }}</span>
<ul class="option-list">
<li>
- <input
- id="notification-visibility-likes"
- v-model="notificationVisibilityLocal.likes"
- type="checkbox"
- >
- <label for="notification-visibility-likes">
+ <Checkbox v-model="notificationVisibility.likes">
{{ $t('settings.notification_visibility_likes') }}
- </label>
+ </Checkbox>
</li>
<li>
- <input
- id="notification-visibility-repeats"
- v-model="notificationVisibilityLocal.repeats"
- type="checkbox"
- >
- <label for="notification-visibility-repeats">
+ <Checkbox v-model="notificationVisibility.repeats">
{{ $t('settings.notification_visibility_repeats') }}
- </label>
+ </Checkbox>
</li>
<li>
- <input
- id="notification-visibility-follows"
- v-model="notificationVisibilityLocal.follows"
- type="checkbox"
- >
- <label for="notification-visibility-follows">
+ <Checkbox v-model="notificationVisibility.follows">
{{ $t('settings.notification_visibility_follows') }}
- </label>
+ </Checkbox>
</li>
<li>
- <input
- id="notification-visibility-mentions"
- v-model="notificationVisibilityLocal.mentions"
- type="checkbox"
- >
- <label for="notification-visibility-mentions">
+ <Checkbox v-model="notificationVisibility.mentions">
{{ $t('settings.notification_visibility_mentions') }}
- </label>
+ </Checkbox>
</li>
</ul>
</div>
@@ -400,7 +313,7 @@
>
<select
id="replyVisibility"
- v-model="replyVisibilityLocal"
+ v-model="replyVisibility"
>
<option
value="all"
@@ -413,24 +326,14 @@
</label>
</div>
<div>
- <input
- id="hidePostStats"
- v-model="hidePostStatsLocal"
- type="checkbox"
- >
- <label for="hidePostStats">
- {{ $t('settings.hide_post_stats') }} {{ $t('settings.instance_default', { value: hidePostStatsDefault }) }}
- </label>
+ <Checkbox v-model="hidePostStats">
+ {{ $t('settings.hide_post_stats') }} {{ $t('settings.instance_default', { value: hidePostStatsLocalizedValue }) }}
+ </Checkbox>
</div>
<div>
- <input
- id="hideUserStats"
- v-model="hideUserStatsLocal"
- type="checkbox"
- >
- <label for="hideUserStats">
- {{ $t('settings.hide_user_stats') }} {{ $t('settings.instance_default', { value: hideUserStatsDefault }) }}
- </label>
+ <Checkbox v-model="hideUserStats">
+ {{ $t('settings.hide_user_stats') }} {{ $t('settings.instance_default', { value: hideUserStatsLocalizedValue }) }}
+ </Checkbox>
</div>
</div>
<div class="setting-item">
@@ -442,14 +345,9 @@
/>
</div>
<div>
- <input
- id="hideFilteredStatuses"
- v-model="hideFilteredStatusesLocal"
- type="checkbox"
- >
- <label for="hideFilteredStatuses">
- {{ $t('settings.hide_filtered_statuses') }} {{ $t('settings.instance_default', { value: hideFilteredStatusesDefault }) }}
- </label>
+ <Checkbox v-model="hideFilteredStatuses">
+ {{ $t('settings.hide_filtered_statuses') }} {{ $t('settings.instance_default', { value: hideFilteredStatusesLocalizedValue }) }}
+ </Checkbox>
</div>
</div>
</div>
diff --git a/src/components/status/status.js b/src/components/status/status.js
@@ -16,6 +16,7 @@ import fileType from 'src/services/file_type/file_type.service'
import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
import { mentionMatchesUrl, extractTagFromUrl } from 'src/services/matcher/matcher.service.js'
import { filter, unescape, uniqBy } from 'lodash'
+import { mapGetters } from 'vuex'
const Status = {
name: 'Status',
@@ -41,20 +42,16 @@ const Status = {
showingTall: this.inConversation && this.focused,
showingLongSubject: false,
error: null,
- expandingSubject: typeof this.$store.state.config.collapseMessageWithSubject === 'undefined'
- ? !this.$store.state.instance.collapseMessageWithSubject
- : !this.$store.state.config.collapseMessageWithSubject,
+ expandingSubject: !this.$store.getters.mergedConfig.collapseMessageWithSubject,
betterShadow: this.$store.state.interface.browserSupport.cssFilter
}
},
computed: {
localCollapseSubjectDefault () {
- return typeof this.$store.state.config.collapseMessageWithSubject === 'undefined'
- ? this.$store.state.instance.collapseMessageWithSubject
- : this.$store.state.config.collapseMessageWithSubject
+ return this.mergedConfig.collapseMessageWithSubject
},
muteWords () {
- return this.$store.state.config.muteWords
+ return this.mergedConfig.muteWords
},
repeaterClass () {
const user = this.statusoid.user
@@ -69,18 +66,18 @@ const Status = {
},
repeaterStyle () {
const user = this.statusoid.user
- const highlight = this.$store.state.config.highlight
+ const highlight = this.mergedConfig.highlight
return highlightStyle(highlight[user.screen_name])
},
userStyle () {
if (this.noHeading) return
const user = this.retweet ? (this.statusoid.retweeted_status.user) : this.statusoid.user
- const highlight = this.$store.state.config.highlight
+ const highlight = this.mergedConfig.highlight
return highlightStyle(highlight[user.screen_name])
},
hideAttachments () {
- return (this.$store.state.config.hideAttachments && !this.inConversation) ||
- (this.$store.state.config.hideAttachmentsInConv && this.inConversation)
+ return (this.mergedConfig.hideAttachments && !this.inConversation) ||
+ (this.mergedConfig.hideAttachmentsInConv && this.inConversation)
},
userProfileLink () {
return this.generateUserProfileLink(this.status.user.id, this.status.user.screen_name)
@@ -119,9 +116,7 @@ const Status = {
},
muted () { return !this.unmuted && ((!this.inProfile && this.status.user.muted) || (!this.inConversation && this.status.thread_muted) || this.muteWordHits.length > 0) },
hideFilteredStatuses () {
- return typeof this.$store.state.config.hideFilteredStatuses === 'undefined'
- ? this.$store.state.instance.hideFilteredStatuses
- : this.$store.state.config.hideFilteredStatuses
+ return this.mergedConfig.hideFilteredStatuses
},
hideStatus () {
return (this.hideReply || this.deleted) || (this.muted && this.hideFilteredStatuses)
@@ -162,7 +157,7 @@ const Status = {
}
},
hideReply () {
- if (this.$store.state.config.replyVisibility === 'all') {
+ if (this.mergedConfig.replyVisibility === 'all') {
return false
}
if (this.inConversation || !this.isReply) {
@@ -174,7 +169,7 @@ const Status = {
if (this.status.type === 'retweet') {
return false
}
- const checkFollowing = this.$store.state.config.replyVisibility === 'following'
+ const checkFollowing = this.mergedConfig.replyVisibility === 'following'
for (var i = 0; i < this.status.attentions.length; ++i) {
if (this.status.user.id === this.status.attentions[i].id) {
continue
@@ -219,9 +214,7 @@ const Status = {
replySubject () {
if (!this.status.summary) return ''
const decodedSummary = unescape(this.status.summary)
- const behavior = typeof this.$store.state.config.subjectLineBehavior === 'undefined'
- ? this.$store.state.instance.subjectLineBehavior
- : this.$store.state.config.subjectLineBehavior
+ const behavior = this.mergedConfig.subjectLineBehavior
const startsWithRe = decodedSummary.match(/^re[: ]/i)
if ((behavior !== 'noop' && startsWithRe) || behavior === 'masto') {
return decodedSummary
@@ -232,8 +225,8 @@ const Status = {
}
},
attachmentSize () {
- if ((this.$store.state.config.hideAttachments && !this.inConversation) ||
- (this.$store.state.config.hideAttachmentsInConv && this.inConversation) ||
+ if ((this.mergedConfig.hideAttachments && !this.inConversation) ||
+ (this.mergedConfig.hideAttachmentsInConv && this.inConversation) ||
(this.status.attachments.length > this.maxThumbnails)) {
return 'hide'
} else if (this.compact) {
@@ -245,7 +238,7 @@ const Status = {
if (this.attachmentSize === 'hide') {
return []
}
- return this.$store.state.config.playVideosInModal
+ return this.mergedConfig.playVideosInModal
? ['image', 'video']
: ['image']
},
@@ -260,7 +253,7 @@ const Status = {
)
},
maxThumbnails () {
- return this.$store.state.config.maxThumbnails
+ return this.mergedConfig.maxThumbnails
},
contentHtml () {
if (!this.status.summary_html) {
@@ -283,10 +276,9 @@ const Status = {
return this.status.tags.filter(tagObj => tagObj.hasOwnProperty('name')).map(tagObj => tagObj.name).join(' ')
},
hidePostStats () {
- return typeof this.$store.state.config.hidePostStats === 'undefined'
- ? this.$store.state.instance.hidePostStats
- : this.$store.state.config.hidePostStats
- }
+ return this.mergedConfig.hidePostStats
+ },
+ ...mapGetters(['mergedConfig'])
},
components: {
Attachment,
diff --git a/src/components/still-image/still-image.js b/src/components/still-image/still-image.js
@@ -8,7 +8,7 @@ const StillImage = {
],
data () {
return {
- stopGifs: this.$store.state.config.stopGifs
+ stopGifs: this.$store.getters.mergedConfig.stopGifs
}
},
computed: {
diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js
@@ -10,6 +10,7 @@ import ContrastRatio from '../contrast_ratio/contrast_ratio.vue'
import TabSwitcher from '../tab_switcher/tab_switcher.js'
import Preview from './preview.vue'
import ExportImport from '../export_import/export_import.vue'
+import Checkbox from '../checkbox/checkbox.vue'
// List of color values used in v1
const v1OnlyNames = [
@@ -27,7 +28,7 @@ export default {
data () {
return {
availableStyles: [],
- selected: this.$store.state.config.theme,
+ selected: this.$store.getters.mergedConfig.theme,
previewShadows: {},
previewColors: {},
@@ -111,7 +112,7 @@ export default {
})
},
mounted () {
- this.normalizeLocalState(this.$store.state.config.customTheme)
+ this.normalizeLocalState(this.$store.getters.mergedConfig.customTheme)
if (typeof this.shadowSelected === 'undefined') {
this.shadowSelected = this.shadowsAvailable[0]
}
@@ -338,7 +339,8 @@ export default {
FontControl,
TabSwitcher,
Preview,
- ExportImport
+ ExportImport,
+ Checkbox
},
methods: {
setCustomTheme () {
@@ -365,9 +367,9 @@ export default {
return version >= 1 || version <= 2
},
clearAll () {
- const state = this.$store.state.config.customTheme
+ const state = this.$store.getters.mergedConfig.customTheme
const version = state.colors ? 2 : 'l1'
- this.normalizeLocalState(this.$store.state.config.customTheme, version)
+ this.normalizeLocalState(this.$store.getters.mergedConfig.customTheme, version)
},
// Clears all the extra stuff when loading V1 theme
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
@@ -42,44 +42,29 @@
</div>
<div class="save-load-options">
<span class="keep-option">
- <input
- id="keep-color"
- v-model="keepColor"
- type="checkbox"
- >
- <label for="keep-color">{{ $t('settings.style.switcher.keep_color') }}</label>
+ <Checkbox v-model="keepColor">
+ {{ $t('settings.style.switcher.keep_color') }}
+ </Checkbox>
</span>
<span class="keep-option">
- <input
- id="keep-shadows"
- v-model="keepShadows"
- type="checkbox"
- >
- <label for="keep-shadows">{{ $t('settings.style.switcher.keep_shadows') }}</label>
+ <Checkbox v-model="keepShadows">
+ {{ $t('settings.style.switcher.keep_shadows') }}
+ </Checkbox>
</span>
<span class="keep-option">
- <input
- id="keep-opacity"
- v-model="keepOpacity"
- type="checkbox"
- >
- <label for="keep-opacity">{{ $t('settings.style.switcher.keep_opacity') }}</label>
+ <Checkbox v-model="keepOpacity">
+ {{ $t('settings.style.switcher.keep_opacity') }}
+ </Checkbox>
</span>
<span class="keep-option">
- <input
- id="keep-roundness"
- v-model="keepRoundness"
- type="checkbox"
- >
- <label for="keep-roundness">{{ $t('settings.style.switcher.keep_roundness') }}</label>
+ <Checkbox v-model="keepRoundness">
+ {{ $t('settings.style.switcher.keep_roundness') }}
+ </Checkbox>
</span>
<span class="keep-option">
- <input
- id="keep-fonts"
- v-model="keepFonts"
- type="checkbox"
- >
- <label for="keep-fonts">{{ $t('settings.style.switcher.keep_fonts') }}</label>
+ <Checkbox v-model="keepFonts">
+ {{ $t('settings.style.switcher.keep_fonts') }}
+ </Checkbox>
</span>
<p>{{ $t('settings.style.switcher.save_load_hint') }}</p>
</div>
diff --git a/src/components/timeline/timeline.js b/src/components/timeline/timeline.js
@@ -141,7 +141,7 @@ const Timeline = {
const bodyBRect = document.body.getBoundingClientRect()
const height = Math.max(bodyBRect.height, -(bodyBRect.y))
if (this.timeline.loading === false &&
- this.$store.state.config.autoLoad &&
+ this.$store.getters.mergedConfig.autoLoad &&
this.$el.offsetHeight > 0 &&
(window.innerHeight + window.pageYOffset) >= (height - 750)) {
this.fetchOlderStatuses()
@@ -153,7 +153,7 @@ const Timeline = {
},
watch: {
newStatusCount (count) {
- if (!this.$store.state.config.streaming) {
+ if (!this.$store.getters.mergedConfig.streaming) {
return
}
if (count > 0) {
@@ -162,7 +162,7 @@ const Timeline = {
const top = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0)
if (top < 15 &&
!this.paused &&
- !(this.unfocused && this.$store.state.config.pauseOnUnfocused)
+ !(this.unfocused && this.$store.getters.mergedConfig.pauseOnUnfocused)
) {
this.showNewStatuses()
} else {
diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js
@@ -6,6 +6,7 @@ import ModerationTools from '../moderation_tools/moderation_tools.vue'
import AccountActions from '../account_actions/account_actions.vue'
import { hex2rgb } from '../../services/color_convert/color_convert.js'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
+import { mapGetters } from 'vuex'
export default {
props: [
@@ -14,9 +15,6 @@ export default {
data () {
return {
followRequestInProgress: false,
- hideUserStatsLocal: typeof this.$store.state.config.hideUserStats === 'undefined'
- ? this.$store.state.instance.hideUserStats
- : this.$store.state.config.hideUserStats,
betterShadow: this.$store.state.interface.browserSupport.cssFilter
}
},
@@ -32,9 +30,9 @@ export default {
}]
},
style () {
- const color = this.$store.state.config.customTheme.colors
- ? this.$store.state.config.customTheme.colors.bg // v2
- : this.$store.state.config.colors.bg // v1
+ const color = this.$store.getters.mergedConfig.customTheme.colors
+ ? this.$store.getters.mergedConfig.customTheme.colors.bg // v2
+ : this.$store.getters.mergedConfig.colors.bg // v1
if (color) {
const rgb = (typeof color === 'string') ? hex2rgb(color) : color
@@ -66,21 +64,22 @@ export default {
},
userHighlightType: {
get () {
- const data = this.$store.state.config.highlight[this.user.screen_name]
+ const data = this.$store.getters.mergedConfig.highlight[this.user.screen_name]
return (data && data.type) || 'disabled'
},
set (type) {
- const data = this.$store.state.config.highlight[this.user.screen_name]
+ const data = this.$store.getters.mergedConfig.highlight[this.user.screen_name]
if (type !== 'disabled') {
this.$store.dispatch('setHighlight', { user: this.user.screen_name, color: (data && data.color) || '#FFFFFF', type })
} else {
this.$store.dispatch('setHighlight', { user: this.user.screen_name, color: undefined })
}
- }
+ },
+ ...mapGetters(['mergedConfig'])
},
userHighlightColor: {
get () {
- const data = this.$store.state.config.highlight[this.user.screen_name]
+ const data = this.$store.getters.mergedConfig.highlight[this.user.screen_name]
return data && data.color
},
set (color) {
@@ -93,7 +92,8 @@ export default {
const validRole = rights.admin || rights.moderator
const roleTitle = rights.admin ? 'admin' : 'moderator'
return validRole && roleTitle
- }
+ },
+ ...mapGetters(['mergedConfig'])
},
components: {
UserAvatar,
diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue
@@ -84,7 +84,7 @@
>{{ visibleRole }}</span>
<span v-if="user.locked"><i class="icon icon-lock" /></span>
<span
- v-if="!hideUserStatsLocal && !hideBio"
+ v-if="!mergedConfig.hideUserStats && !hideBio"
class="dailyAvg"
>{{ dailyAvg }} {{ $t('user_card.per_day') }}</span>
</div>
@@ -193,7 +193,7 @@
class="panel-body"
>
<div
- v-if="!hideUserStatsLocal && switcher"
+ v-if="!mergedConfig.hideUserStats && switcher"
class="user-counts"
>
<div
diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js
@@ -17,6 +17,7 @@ import Autosuggest from '../autosuggest/autosuggest.vue'
import Importer from '../importer/importer.vue'
import Exporter from '../exporter/exporter.vue'
import withSubscription from '../../hocs/with_subscription/with_subscription'
+import Checkbox from '../checkbox/checkbox.vue'
import Mfa from './mfa.vue'
const BlockList = withSubscription({
@@ -82,7 +83,8 @@ const UserSettings = {
ProgressButton,
Importer,
Exporter,
- Mfa
+ Mfa,
+ Checkbox
},
computed: {
user () {
diff --git a/src/components/user_settings/user_settings.vue b/src/components/user_settings/user_settings.vue
@@ -53,12 +53,9 @@
/>
</EmojiInput>
<p>
- <input
- id="account-locked"
- v-model="newLocked"
- type="checkbox"
- >
- <label for="account-locked">{{ $t('settings.lock_account_description') }}</label>
+ <Checkbox v-model="newLocked">
+ {{ $t('settings.lock_account_description') }}
+ </Checkbox>
</p>
<div>
<label for="default-vis">{{ $t('settings.default_vis') }}</label>
@@ -75,69 +72,52 @@
</div>
</div>
<p>
- <input
- id="account-no-rich-text"
- v-model="newNoRichText"
- type="checkbox"
- >
- <label for="account-no-rich-text">{{ $t('settings.no_rich_text_description') }}</label>
+ <Checkbox v-model="newNoRichText">
+ {{ $t('settings.no_rich_text_description') }}
+ </Checkbox>
</p>
<p>
- <input
- id="account-hide-follows"
- v-model="hideFollows"
- type="checkbox"
- >
- <label for="account-hide-follows">{{ $t('settings.hide_follows_description') }}</label>
+ <Checkbox v-model="hideFollows">
+ {{ $t('settings.hide_follows_description') }}
+ </Checkbox>
</p>
<p class="setting-subitem">
- <input
- id="account-hide-follows-count"
+ <Checkbox
v-model="hideFollowsCount"
- type="checkbox"
:disabled="!hideFollows"
- >
- <label for="account-hide-follows-count">{{ $t('settings.hide_follows_count_description') }}</label>
+ >
+ {{ $t('settings.hide_follows_count_description') }}
+ </Checkbox>
</p>
<p>
- <input
- id="account-hide-followers"
+ <Checkbox
v-model="hideFollowers"
- type="checkbox"
>
- <label for="account-hide-followers">{{ $t('settings.hide_followers_description') }}</label>
+ {{ $t('settings.hide_followers_description') }}
+ </Checkbox>
</p>
<p class="setting-subitem">
- <input
- id="account-hide-followers-count"
+ <Checkbox
v-model="hideFollowersCount"
- type="checkbox"
:disabled="!hideFollowers"
>
- <label for="account-hide-followers-count">{{ $t('settings.hide_followers_count_description') }}</label>
+ {{ $t('settings.hide_followers_count_description') }}
+ </Checkbox>
</p>
<p>
- <input
- id="account-show-role"
- v-model="showRole"
- type="checkbox"
- >
- <label
- v-if="role === 'admin'"
- for="account-show-role"
- >{{ $t('settings.show_admin_badge') }}</label>
- <label
- v-if="role === 'moderator'"
- for="account-show-role"
- >{{ $t('settings.show_moderator_badge') }}</label>
+ <Checkbox v-model="showRole">
+ <template v-if="role === 'admin'">
+ {{ $t('settings.show_admin_badge') }}
+ </template>
+ <template v-if="role === 'moderator'">
+ {{ $t('settings.show_moderator_badge') }}
+ </template>
+ </Checkbox>
</p>
<p>
- <input
- id="discoverable"
- v-model="discoverable"
- type="checkbox"
- >
- <label for="discoverable">{{ $t('settings.discoverable') }}</label>
+ <Checkbox v-model="discoverable">
+ {{ $t('settings.discoverable') }}
+ </Checkbox>
</p>
<button
:disabled="newName && newName.length === 0"
@@ -367,44 +347,24 @@
<span class="label">{{ $t('settings.notification_setting') }}</span>
<ul class="option-list">
<li>
- <input
- id="notification-setting-follows"
- v-model="notificationSettings.follows"
- type="checkbox"
- >
- <label for="notification-setting-follows">
+ <Checkbox v-model="notificationSettings.follows">
{{ $t('settings.notification_setting_follows') }}
- </label>
+ </Checkbox>
</li>
<li>
- <input
- id="notification-setting-followers"
- v-model="notificationSettings.followers"
- type="checkbox"
- >
- <label for="notification-setting-followers">
+ <Checkbox v-model="notificationSettings.followers">
{{ $t('settings.notification_setting_followers') }}
- </label>
+ </Checkbox>
</li>
<li>
- <input
- id="notification-setting-non-follows"
- v-model="notificationSettings.non_follows"
- type="checkbox"
- >
- <label for="notification-setting-non-follows">
+ <Checkbox v-model="notificationSettings.non_follows">
{{ $t('settings.notification_setting_non_follows') }}
- </label>
+ </Checkbox>
</li>
<li>
- <input
- id="notification-setting-non-followers"
- v-model="notificationSettings.non_followers"
- type="checkbox"
- >
- <label for="notification-setting-non-followers">
+ <Checkbox v-model="notificationSettings.non_followers">
{{ $t('settings.notification_setting_non_followers') }}
- </label>
+ </Checkbox>
</li>
</ul>
</div>
diff --git a/src/components/video_attachment/video_attachment.js b/src/components/video_attachment/video_attachment.js
@@ -3,7 +3,7 @@ const VideoAttachment = {
props: ['attachment', 'controls'],
data () {
return {
- loopVideo: this.$store.state.config.loopVideo
+ loopVideo: this.$store.getters.mergedConfig.loopVideo
}
},
methods: {
@@ -12,16 +12,16 @@ const VideoAttachment = {
if (typeof target.webkitAudioDecodedByteCount !== 'undefined') {
// non-zero if video has audio track
if (target.webkitAudioDecodedByteCount > 0) {
- this.loopVideo = this.loopVideo && !this.$store.state.config.loopVideoSilentOnly
+ this.loopVideo = this.loopVideo && !this.$store.getters.mergedConfig.loopVideoSilentOnly
}
} else if (typeof target.mozHasAudio !== 'undefined') {
// true if video has audio track
if (target.mozHasAudio) {
- this.loopVideo = this.loopVideo && !this.$store.state.config.loopVideoSilentOnly
+ this.loopVideo = this.loopVideo && !this.$store.getters.mergedConfig.loopVideoSilentOnly
}
} else if (typeof target.audioTracks !== 'undefined') {
if (target.audioTracks.length > 0) {
- this.loopVideo = this.loopVideo && !this.$store.state.config.loopVideoSilentOnly
+ this.loopVideo = this.loopVideo && !this.$store.getters.mergedConfig.loopVideoSilentOnly
}
}
}
diff --git a/src/modules/config.js b/src/modules/config.js
@@ -3,8 +3,9 @@ import { setPreset, applyTheme } from '../services/style_setter/style_setter.js'
const browserLocale = (window.navigator.language || 'en').split('-')[0]
-const defaultState = {
+export const defaultState = {
colors: {},
+ // bad name: actually hides posts of muted USERS
hideMutedPosts: undefined, // instance default
collapseMessageWithSubject: undefined, // instance default
padEmoji: true,
@@ -37,11 +38,37 @@ const defaultState = {
subjectLineBehavior: undefined, // instance default
alwaysShowSubjectInput: undefined, // instance default
postContentType: undefined, // instance default
- minimalScopesMode: undefined // instance default
+ minimalScopesMode: undefined, // instance default
+ // This hides statuses filtered via a word filter
+ hideFilteredStatuses: undefined, // instance default
+ playVideosInModal: false,
+ useOneClickNsfw: false,
+ useContainFit: false,
+ hidePostStats: undefined, // instance default
+ hideUserStats: undefined // instance default
}
+// caching the instance default properties
+export const instanceDefaultProperties = Object.entries(defaultState)
+ .filter(([key, value]) => value === undefined)
+ .map(([key, value]) => key)
+
const config = {
state: defaultState,
+ getters: {
+ mergedConfig (state, getters, rootState, rootGetters) {
+ const { instance } = rootState
+ return {
+ ...state,
+ ...instanceDefaultProperties
+ .map(key => [key, state[key] === undefined
+ ? instance[key]
+ : state[key]
+ ])
+ .reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {})
+ }
+ }
+ },
mutations: {
setOption (state, { name, value }) {
set(state, name, value)
diff --git a/src/modules/instance.js b/src/modules/instance.js
@@ -1,5 +1,6 @@
import { set } from 'vue'
import { setPreset } from '../services/style_setter/style_setter.js'
+import { instanceDefaultProperties } from './config.js'
const defaultState = {
// Stuff from static/config.json and apiConfig
@@ -72,6 +73,13 @@ const instance = {
}
}
},
+ getters: {
+ instanceDefaultConfig (state) {
+ return instanceDefaultProperties
+ .map(key => [key, state[key]])
+ .reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {})
+ }
+ },
actions: {
setInstanceOption ({ commit, dispatch }, { name, value }) {
commit('setInstanceOption', { name, value })
diff --git a/src/services/notifications_fetcher/notifications_fetcher.service.js b/src/services/notifications_fetcher/notifications_fetcher.service.js
@@ -8,11 +8,10 @@ const update = ({ store, notifications, older }) => {
const fetchAndUpdate = ({ store, credentials, older = false }) => {
const args = { credentials }
+ const { getters } = store
const rootState = store.rootState || store.state
const timelineData = rootState.statuses.notifications
- const hideMutedPosts = typeof rootState.config.hideMutedPosts === 'undefined'
- ? rootState.instance.hideMutedPosts
- : rootState.config.hideMutedPosts
+ const hideMutedPosts = getters.mergedConfig.hideMutedPosts
args['withMuted'] = !hideMutedPosts
diff --git a/src/services/timeline_fetcher/timeline_fetcher.service.js b/src/services/timeline_fetcher/timeline_fetcher.service.js
@@ -15,13 +15,21 @@ const update = ({ store, statuses, timeline, showImmediately, userId }) => {
})
}
-const fetchAndUpdate = ({ store, credentials, timeline = 'friends', older = false, showImmediately = false, userId = false, tag = false, until }) => {
+const fetchAndUpdate = ({
+ store,
+ credentials,
+ timeline = 'friends',
+ older = false,
+ showImmediately = false,
+ userId = false,
+ tag = false,
+ until
+}) => {
const args = { timeline, credentials }
const rootState = store.rootState || store.state
+ const { getters } = store
const timelineData = rootState.statuses.timelines[camelCase(timeline)]
- const hideMutedPosts = typeof rootState.config.hideMutedPosts === 'undefined'
- ? rootState.instance.hideMutedPosts
- : rootState.config.hideMutedPosts
+ const hideMutedPosts = getters.mergedConfig.hideMutedPosts
if (older) {
args['until'] = until || timelineData.minId
diff --git a/test/unit/specs/components/emoji_input.spec.js b/test/unit/specs/components/emoji_input.spec.js
@@ -12,8 +12,8 @@ const generateInput = (value, padEmoji = true) => {
},
mocks: {
$store: {
- state: {
- config: {
+ getters: {
+ mergedConfig: {
padEmoji
}
}
diff --git a/test/unit/specs/components/user_profile.spec.js b/test/unit/specs/components/user_profile.spec.js
@@ -18,7 +18,14 @@ const actions = {
}
const testGetters = {
- findUser: state => getters.findUser(state.users)
+ findUser: state => getters.findUser(state.users),
+ mergedConfig: state => ({
+ colors: '',
+ highlight: {},
+ customTheme: {
+ colors: []
+ }
+ })
}
const localUser = {
@@ -45,13 +52,6 @@ const externalProfileStore = new Vuex.Store({
interface: {
browserSupport: ''
},
- config: {
- colors: '',
- highlight: {},
- customTheme: {
- colors: []
- }
- },
instance: {
hideUserStats: true
},