Compare commits

...

3 Commits

Author SHA1 Message Date
Henry Jameson 02bf733328 ITS BOOTING 2021-03-11 19:25:50 +02:00
Henry Jameson d1ade90a1c Merge remote-tracking branch 'origin/develop' into vue3
* origin/develop: (320 commits)
  Apply 1 suggestion(s) to 1 file(s)
  Make it possible to localize user highlight options
  remove shoutbox test hacks
  fix shoutbox header, use custom scroll-to-bottom system, remove vue-chat-scroll, temporarily add chat test hack
  update changelog with 2.3.0
  change icons around
  Translated using Weblate (Japanese)
  Update timeline_quick_settings.js
  add screen_name_ui to tests
  separate screen_name and screen_name_ui with decoded punycode
  Update CHANGELOG.md
  add basic validation for statusless status notifications
  changelog mention
  fix chat unread badge
  update shelljs to get rid of warnings on build
  save a few characters
  focus input in emoji picker and react picker
  fix vue warnings
  add only to wording
  basic loggedin check for reply filtering
  ...
2021-03-11 18:00:25 +02:00
Henry Jameson b17768baa6 WIP attempts at using vue3 and co 2020-11-03 21:50:13 +02:00
24 changed files with 557 additions and 415 deletions

View File

@ -3,6 +3,7 @@ var config = require('../config')
var utils = require('./utils') var utils = require('./utils')
var projectRoot = path.resolve(__dirname, '../') var projectRoot = path.resolve(__dirname, '../')
var ServiceWorkerWebpackPlugin = require('serviceworker-webpack-plugin') var ServiceWorkerWebpackPlugin = require('serviceworker-webpack-plugin')
var { VueLoaderPlugin } = require('vue-loader')
var env = process.env.NODE_ENV var env = process.env.NODE_ENV
// check env & config/index.js to decide weither to enable CSS Sourcemaps for the // check env & config/index.js to decide weither to enable CSS Sourcemaps for the
@ -33,7 +34,7 @@ module.exports = {
path.join(__dirname, '../node_modules') path.join(__dirname, '../node_modules')
], ],
alias: { alias: {
'vue$': 'vue/dist/vue.runtime.common', vue: "@vue/runtime-dom",
'static': path.resolve(__dirname, '../static'), 'static': path.resolve(__dirname, '../static'),
'src': path.resolve(__dirname, '../src'), 'src': path.resolve(__dirname, '../src'),
'assets': path.resolve(__dirname, '../src/assets'), 'assets': path.resolve(__dirname, '../src/assets'),
@ -93,6 +94,7 @@ module.exports = {
new ServiceWorkerWebpackPlugin({ new ServiceWorkerWebpackPlugin({
entry: path.join(__dirname, '..', 'src/sw.js'), entry: path.join(__dirname, '..', 'src/sw.js'),
filename: 'sw-pleroma.js' filename: 'sw-pleroma.js'
}) }),
new VueLoaderPlugin()
] ]
} }

View File

@ -17,11 +17,12 @@
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "^7.7.6", "@babel/runtime": "^7.7.6",
"@chenfengyuan/vue-qrcode": "^1.0.0", "@chenfengyuan/vue-qrcode": "^2.0.0-beta",
"@fortawesome/fontawesome-svg-core": "^1.2.32", "@fortawesome/fontawesome-svg-core": "^1.2.32",
"@fortawesome/free-regular-svg-icons": "^5.15.1", "@fortawesome/free-regular-svg-icons": "^5.15.1",
"@fortawesome/free-solid-svg-icons": "^5.15.1", "@fortawesome/free-solid-svg-icons": "^5.15.1",
"@fortawesome/vue-fontawesome": "^2.0.0", "@fortawesome/vue-fontawesome": "^3.0.0-3",
"@vue/compiler-sfc": "^3.0.7",
"body-scroll-lock": "^2.6.4", "body-scroll-lock": "^2.6.4",
"chromatism": "^3.0.0", "chromatism": "^3.0.0",
"cropperjs": "^1.4.3", "cropperjs": "^1.4.3",
@ -30,15 +31,14 @@
"localforage": "^1.5.0", "localforage": "^1.5.0",
"parse-link-header": "^1.0.1", "parse-link-header": "^1.0.1",
"phoenix": "^1.3.0", "phoenix": "^1.3.0",
"portal-vue": "^2.1.4",
"punycode.js": "^2.1.0", "punycode.js": "^2.1.0",
"v-click-outside": "^2.1.1", "v-click-outside": "^2.1.1",
"vue": "^2.6.11", "vue": "^3.0.7",
"vue-i18n": "^7.3.2", "vue-i18n": "^9.0.0-beta.18",
"vue-router": "^3.0.1", "vue-router": "^4.0.5",
"vue-template-compiler": "^2.6.11", "vuelidate": "^0.7.6",
"vuelidate": "^0.7.4", "vuex": "^4.0.0",
"vuex": "^3.0.1" "qrcode": "^1.4.4"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.7.5", "@babel/core": "^7.7.5",
@ -48,7 +48,7 @@
"@ungap/event-target": "^0.1.0", "@ungap/event-target": "^0.1.0",
"@vue/babel-helper-vue-jsx-merge-props": "^1.0.0", "@vue/babel-helper-vue-jsx-merge-props": "^1.0.0",
"@vue/babel-plugin-transform-vue-jsx": "^1.1.2", "@vue/babel-plugin-transform-vue-jsx": "^1.1.2",
"@vue/test-utils": "^1.0.0-beta.26", "@vue/test-utils": "^2.0.0-beta.8",
"autoprefixer": "^6.4.0", "autoprefixer": "^6.4.0",
"babel-eslint": "^7.0.0", "babel-eslint": "^7.0.0",
"babel-loader": "^8.0.6", "babel-loader": "^8.0.6",
@ -109,7 +109,7 @@
"stylelint-config-standard": "^20.0.0", "stylelint-config-standard": "^20.0.0",
"stylelint-rscss": "^0.4.0", "stylelint-rscss": "^0.4.0",
"url-loader": "^1.1.2", "url-loader": "^1.1.2",
"vue-loader": "^14.0.0", "vue-loader": "^16.1.2",
"vue-style-loader": "^4.0.0", "vue-style-loader": "^4.0.0",
"webpack": "^4.0.0", "webpack": "^4.0.0",
"webpack-dev-middleware": "^3.6.0", "webpack-dev-middleware": "^3.6.0",

View File

@ -1,7 +1,13 @@
import Vue from 'vue' import { createApp } from 'vue'
import VueRouter from 'vue-router' import { createRouter, createWebHistory } from 'vue-router'
import routes from './routes' import VueClickOutside from 'v-click-outside'
import { FontAwesomeIcon, FontAwesomeLayers } from '@fortawesome/vue-fontawesome'
import App from '../App.vue' import App from '../App.vue'
import routes from './routes'
import VBodyScrollLock from 'src/directives/body_scroll_lock'
import { windowWidth } from '../services/window_utils/window_utils' import { windowWidth } from '../services/window_utils/window_utils'
import { getOrCreateApp, getClientToken } from '../services/new_api/oauth.js' import { getOrCreateApp, getClientToken } from '../services/new_api/oauth.js'
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js' import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
@ -366,25 +372,32 @@ const afterStoreSetup = async ({ store, i18n }) => {
getTOS({ store }) getTOS({ store })
getStickers({ store }) getStickers({ store })
const router = new VueRouter({ const router = createRouter({
mode: 'history', history: createWebHistory(),
routes: routes(store), routes: routes(store),
scrollBehavior: (to, _from, savedPosition) => { scrollBehavior: (to, _from, savedPosition) => {
if (to.matched.some(m => m.meta.dontScroll)) { if (to.matched.some(m => m.meta.dontScroll)) {
return false return false
} }
return savedPosition || { x: 0, y: 0 } return savedPosition || { left: 0, top: 0 }
} }
}) })
/* eslint-disable no-new */ const app = createApp(App)
return new Vue({
router, app.use(router)
store, app.use(store)
i18n, app.use(i18n)
el: '#app',
render: h => h(App) app.use(VueClickOutside)
}) app.use(VBodyScrollLock)
app.component('FAIcon', FontAwesomeIcon)
app.component('FALayers', FontAwesomeLayers)
app.mount('#app')
return app
} }
export default afterStoreSetup export default afterStoreSetup

View File

@ -1,8 +1,7 @@
import Vue from 'vue'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
import UserAvatar from '../user_avatar/user_avatar.vue' import UserAvatar from '../user_avatar/user_avatar.vue'
export default Vue.component('chat-title', { export default {
name: 'ChatTitle', name: 'ChatTitle',
components: { components: {
UserAvatar UserAvatar
@ -23,4 +22,4 @@ export default Vue.component('chat-title', {
return generateProfileLink(user.id, user.screen_name) return generateProfileLink(user.id, user.screen_name)
} }
} }
}) }

View File

@ -1,4 +1,3 @@
import { set } from 'vue'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
faChevronDown faChevronDown
@ -40,7 +39,7 @@ export default {
return this.dValue.family return this.dValue.family
}, },
set (v) { set (v) {
set(this.lValue, 'family', v) this.lValue.family = v
this.$emit('input', this.lValue) this.$emit('input', this.lValue)
} }
}, },

View File

@ -11,22 +11,24 @@
{{ $t('settings.settings') }} {{ $t('settings.settings') }}
</span> </span>
<transition name="fade"> <transition name="fade">
<template v-if="currentSaveStateNotice"> <template>
<div <template v-if="currentSaveStateNotice">
v-if="currentSaveStateNotice.error" <div
class="alert error" v-if="currentSaveStateNotice.error"
@click.prevent class="alert error"
> @click.prevent
{{ $t('settings.saving_err') }} >
</div> {{ $t('settings.saving_err') }}
</div>
<div <div
v-if="!currentSaveStateNotice.error" v-if="!currentSaveStateNotice.error"
class="alert transparent" class="alert transparent"
@click.prevent @click.prevent
> >
{{ $t('settings.saving_ok') }} {{ $t('settings.saving_ok') }}
</div> </div>
</template>
</template> </template>
</transition> </transition>
<button <button

View File

@ -1,4 +1,3 @@
import { set, delete as del } from 'vue'
import { import {
rgb2hex, rgb2hex,
hex2rgb, hex2rgb,
@ -314,9 +313,9 @@ export default {
}, },
set (val) { set (val) {
if (val) { if (val) {
set(this.shadowsLocal, this.shadowSelected, this.currentShadowFallback.map(_ => Object.assign({}, _))) this.shadowsLocal[this.shadowSelected] = this.currentShadowFallback.map(_ => Object.assign({}, _))
} else { } else {
del(this.shadowsLocal, this.shadowSelected) delete this.shadowsLocal[this.shadowSelected]
} }
} }
}, },
@ -328,7 +327,7 @@ export default {
return this.shadowsLocal[this.shadowSelected] return this.shadowsLocal[this.shadowSelected]
}, },
set (v) { set (v) {
set(this.shadowsLocal, this.shadowSelected, v) this.shadowsLocal[this.shadowSelected] = v
} }
}, },
themeValid () { themeValid () {
@ -546,7 +545,7 @@ export default {
.filter(_ => _.endsWith('ColorLocal') || _.endsWith('OpacityLocal')) .filter(_ => _.endsWith('ColorLocal') || _.endsWith('OpacityLocal'))
.filter(_ => !v1OnlyNames.includes(_)) .filter(_ => !v1OnlyNames.includes(_))
.forEach(key => { .forEach(key => {
set(this.$data, key, undefined) this.$data[key] = undefined
}) })
}, },
@ -554,7 +553,7 @@ export default {
Object.keys(this.$data) Object.keys(this.$data)
.filter(_ => _.endsWith('RadiusLocal')) .filter(_ => _.endsWith('RadiusLocal'))
.forEach(key => { .forEach(key => {
set(this.$data, key, undefined) this.$data[key] = undefined
}) })
}, },
@ -562,7 +561,7 @@ export default {
Object.keys(this.$data) Object.keys(this.$data)
.filter(_ => _.endsWith('OpacityLocal')) .filter(_ => _.endsWith('OpacityLocal'))
.forEach(key => { .forEach(key => {
set(this.$data, key, undefined) this.$data[key] = undefined
}) })
}, },

View File

@ -28,4 +28,4 @@
</div> </div>
</div> </div>
</template> </template>
<script src="./version_tab.js"> <script src="./version_tab.js" />

View File

@ -1,10 +1,9 @@
import Vue from 'vue'
import { mapState } from 'vuex' import { mapState } from 'vuex'
import { FontAwesomeIcon as FAIcon } from '@fortawesome/vue-fontawesome' import { FontAwesomeIcon as FAIcon } from '@fortawesome/vue-fontawesome'
import './tab_switcher.scss' import './tab_switcher.scss'
export default Vue.component('tab-switcher', { export default {
name: 'TabSwitcher', name: 'TabSwitcher',
props: { props: {
renderOnlyFocused: { renderOnlyFocused: {
@ -153,4 +152,4 @@ export default Vue.component('tab-switcher', {
</div> </div>
) )
} }
}) }

View File

@ -2,7 +2,7 @@
<div class="user-panel"> <div class="user-panel">
<div <div
v-if="signedIn" v-if="signedIn"
key="user-panel" key="user-panel-signed"
class="panel panel-default signed-in" class="panel panel-default signed-in"
> >
<UserCard <UserCard

View File

@ -1,4 +1,3 @@
import Vue from 'vue'
import isEmpty from 'lodash/isEmpty' import isEmpty from 'lodash/isEmpty'
import { getComponentProps } from '../../services/component_utils/component_utils' import { getComponentProps } from '../../services/component_utils/component_utils'
import './with_load_more.scss' import './with_load_more.scss'
@ -23,7 +22,7 @@ const withLoadMore = ({
const originalProps = Object.keys(getComponentProps(WrappedComponent)) const originalProps = Object.keys(getComponentProps(WrappedComponent))
const props = originalProps.filter(v => v !== childPropName).concat(additionalPropNames) const props = originalProps.filter(v => v !== childPropName).concat(additionalPropNames)
return Vue.component('withLoadMore', { return {
props, props,
data () { data () {
return { return {
@ -106,7 +105,7 @@ const withLoadMore = ({
</div> </div>
) )
} }
}) }
} }
export default withLoadMore export default withLoadMore

View File

@ -1,4 +1,3 @@
import Vue from 'vue'
import isEmpty from 'lodash/isEmpty' import isEmpty from 'lodash/isEmpty'
import { getComponentProps } from '../../services/component_utils/component_utils' import { getComponentProps } from '../../services/component_utils/component_utils'
import './with_subscription.scss' import './with_subscription.scss'
@ -22,7 +21,7 @@ const withSubscription = ({
const originalProps = Object.keys(getComponentProps(WrappedComponent)) const originalProps = Object.keys(getComponentProps(WrappedComponent))
const props = originalProps.filter(v => v !== childPropName).concat(additionalPropNames) const props = originalProps.filter(v => v !== childPropName).concat(additionalPropNames)
return Vue.component('withSubscription', { return {
props: [ props: [
...props, ...props,
'refresh' // boolean saying to force-fetch data whenever created 'refresh' // boolean saying to force-fetch data whenever created
@ -88,7 +87,7 @@ const withSubscription = ({
) )
} }
} }
}) }
} }
export default withSubscription export default withSubscription

View File

@ -1,6 +1,4 @@
import Vue from 'vue' import { createStore } from 'vuex'
import VueRouter from 'vue-router'
import Vuex from 'vuex'
import 'custom-event-polyfill' import 'custom-event-polyfill'
import './lib/event_target_polyfill.js' import './lib/event_target_polyfill.js'
@ -21,34 +19,18 @@ import pollsModule from './modules/polls.js'
import postStatusModule from './modules/postStatus.js' import postStatusModule from './modules/postStatus.js'
import chatsModule from './modules/chats.js' import chatsModule from './modules/chats.js'
import VueI18n from 'vue-i18n' import { createI18n } from 'vue-i18n'
import createPersistedState from './lib/persisted_state.js' import createPersistedState from './lib/persisted_state.js'
import pushNotifications from './lib/push_notifications_plugin.js' import pushNotifications from './lib/push_notifications_plugin.js'
import messages from './i18n/messages.js' import messages from './i18n/messages.js'
import VueClickOutside from 'v-click-outside'
import PortalVue from 'portal-vue'
import VBodyScrollLock from './directives/body_scroll_lock'
import { FontAwesomeIcon, FontAwesomeLayers } from '@fortawesome/vue-fontawesome'
import afterStoreSetup from './boot/after_store.js' import afterStoreSetup from './boot/after_store.js'
const currentLocale = (window.navigator.language || 'en').split('-')[0] const currentLocale = (window.navigator.language || 'en').split('-')[0]
Vue.use(Vuex) const i18n = createI18n({
Vue.use(VueRouter)
Vue.use(VueI18n)
Vue.use(VueClickOutside)
Vue.use(PortalVue)
Vue.use(VBodyScrollLock)
Vue.component('FAIcon', FontAwesomeIcon)
Vue.component('FALayers', FontAwesomeLayers)
const i18n = new VueI18n({
// By default, use the browser locale, we will update it if neccessary // By default, use the browser locale, we will update it if neccessary
locale: 'en', locale: 'en',
fallbackLocale: 'en', fallbackLocale: 'en',
@ -75,7 +57,7 @@ const persistedStateOptions = {
console.error(e) console.error(e)
storageError = true storageError = true
} }
const store = new Vuex.Store({ const store = createStore({
modules: { modules: {
i18n: { i18n: {
getters: { getters: {

View File

@ -1,4 +1,4 @@
import Vue from 'vue' import { reactive } from 'vue'
import { find, omitBy, orderBy, sumBy } from 'lodash' import { find, omitBy, orderBy, sumBy } from 'lodash'
import chatService from '../services/chat_service/chat_service.js' import chatService from '../services/chat_service/chat_service.js'
import { parseChat, parseChatMessage } from '../services/entity_normalizer/entity_normalizer.service.js' import { parseChat, parseChatMessage } from '../services/entity_normalizer/entity_normalizer.service.js'
@ -13,8 +13,8 @@ const emptyChatList = () => ({
const defaultState = { const defaultState = {
chatList: emptyChatList(), chatList: emptyChatList(),
chatListFetcher: null, chatListFetcher: null,
openedChats: {}, openedChats: reactive({}),
openedChatMessageServices: {}, openedChatMessageServices: reactive({}),
fetcher: undefined, fetcher: undefined,
currentChatId: null, currentChatId: null,
lastReadMessageId: null lastReadMessageId: null
@ -137,10 +137,10 @@ const chats = {
}, },
addOpenedChat (state, { _dispatch, chat }) { addOpenedChat (state, { _dispatch, chat }) {
state.currentChatId = chat.id state.currentChatId = chat.id
Vue.set(state.openedChats, chat.id, chat) state.openedChats[chat.id] = chat
if (!state.openedChatMessageServices[chat.id]) { if (!state.openedChatMessageServices[chat.id]) {
Vue.set(state.openedChatMessageServices, chat.id, chatService.empty(chat.id)) state.openedChatMessageServices[chat.id] = chatService.empty(chat.id)
} }
}, },
setCurrentChatId (state, { chatId }) { setCurrentChatId (state, { chatId }) {
@ -160,7 +160,7 @@ const chats = {
} }
} else { } else {
state.chatList.data.push(updatedChat) state.chatList.data.push(updatedChat)
Vue.set(state.chatList.idStore, updatedChat.id, updatedChat) state.chatList.idStore[updatedChat.id] = updatedChat
} }
}) })
}, },
@ -172,7 +172,7 @@ const chats = {
chat.updated_at = updatedChat.updated_at chat.updated_at = updatedChat.updated_at
} }
if (!chat) { state.chatList.data.unshift(updatedChat) } if (!chat) { state.chatList.data.unshift(updatedChat) }
Vue.set(state.chatList.idStore, updatedChat.id, updatedChat) state.chatList.idStore[updatedChat.id] = updatedChat
}, },
deleteChat (state, { _dispatch, id, _rootGetters }) { deleteChat (state, { _dispatch, id, _rootGetters }) {
state.chats.data = state.chats.data.filter(conversation => state.chats.data = state.chats.data.filter(conversation =>
@ -186,8 +186,8 @@ const chats = {
commit('setChatListFetcher', { fetcher: undefined }) commit('setChatListFetcher', { fetcher: undefined })
for (const chatId in state.openedChats) { for (const chatId in state.openedChats) {
chatService.clear(state.openedChatMessageServices[chatId]) chatService.clear(state.openedChatMessageServices[chatId])
Vue.delete(state.openedChats, chatId) delete state.openedChats[chatId]
Vue.delete(state.openedChatMessageServices, chatId) delete state.openedChatMessageServices[chatId]
} }
}, },
setChatsLoading (state, { value }) { setChatsLoading (state, { value }) {
@ -215,8 +215,8 @@ const chats = {
for (const chatId in state.openedChats) { for (const chatId in state.openedChats) {
if (currentChatId !== chatId) { if (currentChatId !== chatId) {
chatService.clear(state.openedChatMessageServices[chatId]) chatService.clear(state.openedChatMessageServices[chatId])
Vue.delete(state.openedChats, chatId) delete state.openedChats[chatId]
Vue.delete(state.openedChatMessageServices, chatId) delete state.openedChatMessageServices[chatId]
} }
} }
}, },

View File

@ -1,4 +1,3 @@
import { set, delete as del } from 'vue'
import { setPreset, applyTheme } from '../services/style_setter/style_setter.js' import { setPreset, applyTheme } from '../services/style_setter/style_setter.js'
import messages from '../i18n/messages' import messages from '../i18n/messages'
@ -98,14 +97,14 @@ const config = {
}, },
mutations: { mutations: {
setOption (state, { name, value }) { setOption (state, { name, value }) {
set(state, name, value) state[name] = value
}, },
setHighlight (state, { user, color, type }) { setHighlight (state, { user, color, type }) {
const data = this.state.config.highlight[user] const data = this.state.config.highlight[user]
if (color || type) { if (color || type) {
set(state.highlight, user, { color: color || data.color, type: type || data.type }) state.highlight[user] = { color: color || data.color, type: type || data.type }
} else { } else {
del(state.highlight, user) delete state.highlight[user]
} }
} }
}, },

View File

@ -1,4 +1,3 @@
import { set } from 'vue'
import { getPreset, applyTheme } from '../services/style_setter/style_setter.js' import { getPreset, applyTheme } from '../services/style_setter/style_setter.js'
import { CURRENT_VERSION } from '../services/theme_data/theme_data.service.js' import { CURRENT_VERSION } from '../services/theme_data/theme_data.service.js'
import apiService from '../services/api/api.service.js' import apiService from '../services/api/api.service.js'
@ -86,7 +85,7 @@ const instance = {
mutations: { mutations: {
setInstanceOption (state, { name, value }) { setInstanceOption (state, { name, value }) {
if (typeof value !== 'undefined') { if (typeof value !== 'undefined') {
set(state, name, value) state[name] = value
} }
}, },
setKnownDomains (state, domains) { setKnownDomains (state, domains) {

View File

@ -1,5 +1,3 @@
import { set, delete as del } from 'vue'
const defaultState = { const defaultState = {
settingsModalState: 'hidden', settingsModalState: 'hidden',
settingsModalLoaded: false, settingsModalLoaded: false,
@ -29,11 +27,10 @@ const interfaceMod = {
if (state.noticeClearTimeout) { if (state.noticeClearTimeout) {
clearTimeout(state.noticeClearTimeout) clearTimeout(state.noticeClearTimeout)
} }
set(state.settings, 'currentSaveStateNotice', { error: false, data: success }) state.settings.currentSaveStateNotice = { error: false, data: success }
set(state.settings, 'noticeClearTimeout', state.settings.noticeClearTimeout = setTimeout(() => delete state.settings.currentSaveStateNotice, 2000)
setTimeout(() => del(state.settings, 'currentSaveStateNotice'), 2000))
} else { } else {
set(state.settings, 'currentSaveStateNotice', { error: true, errorData: error }) state.settings.currentSaveStateNotice = { error: true, errorData: error }
} }
}, },
setNotificationPermission (state, permission) { setNotificationPermission (state, permission) {

View File

@ -1,5 +1,3 @@
import { delete as del } from 'vue'
const oauth = { const oauth = {
state: { state: {
clientId: false, clientId: false,
@ -29,7 +27,7 @@ const oauth = {
state.userToken = false state.userToken = false
// state.token is userToken with older name, coming from persistent state // state.token is userToken with older name, coming from persistent state
// let's clear it as well, since it is being used as a fallback of state.userToken // let's clear it as well, since it is being used as a fallback of state.userToken
del(state, 'token') delete state.token
} }
}, },
getters: { getters: {

View File

@ -1,5 +1,4 @@
import { merge } from 'lodash' import { merge } from 'lodash'
import { set } from 'vue'
const polls = { const polls = {
state: { state: {
@ -13,25 +12,25 @@ const polls = {
// Make expired-state change trigger re-renders properly // Make expired-state change trigger re-renders properly
poll.expired = Date.now() > Date.parse(poll.expires_at) poll.expired = Date.now() > Date.parse(poll.expires_at)
if (existingPoll) { if (existingPoll) {
set(state.pollsObject, poll.id, merge(existingPoll, poll)) state.pollsObject[poll.id] = merge(existingPoll, poll)
} else { } else {
set(state.pollsObject, poll.id, poll) state.pollsObject[poll.id] = poll
} }
}, },
trackPoll (state, pollId) { trackPoll (state, pollId) {
const currentValue = state.trackedPolls[pollId] const currentValue = state.trackedPolls[pollId]
if (currentValue) { if (currentValue) {
set(state.trackedPolls, pollId, currentValue + 1) state.trackedPolls[pollId] = currentValue + 1
} else { } else {
set(state.trackedPolls, pollId, 1) state.trackedPolls[pollId] = 1
} }
}, },
untrackPoll (state, pollId) { untrackPoll (state, pollId) {
const currentValue = state.trackedPolls[pollId] const currentValue = state.trackedPolls[pollId]
if (currentValue) { if (currentValue) {
set(state.trackedPolls, pollId, currentValue - 1) state.trackedPolls[pollId] = currentValue - 1
} else { } else {
set(state.trackedPolls, pollId, 0) state.trackedPolls[pollId] = 0
} }
} }
}, },

View File

@ -12,7 +12,6 @@ import {
isArray, isArray,
omitBy omitBy
} from 'lodash' } from 'lodash'
import { set } from 'vue'
import { import {
isStatusNotification, isStatusNotification,
isValidNotification, isValidNotification,
@ -92,7 +91,7 @@ const mergeOrAdd = (arr, obj, item) => {
// This is a new item, prepare it // This is a new item, prepare it
prepareStatus(item) prepareStatus(item)
arr.push(item) arr.push(item)
set(obj, item.id, item) obj[item.id] = item
return { item, new: true } return { item, new: true }
} }
} }
@ -131,7 +130,7 @@ const addStatusToGlobalStorage = (state, data) => {
if (conversationsObject[conversationId]) { if (conversationsObject[conversationId]) {
conversationsObject[conversationId].push(status) conversationsObject[conversationId].push(status)
} else { } else {
set(conversationsObject, conversationId, [status]) conversationsObject[conversationId] = [status]
} }
} }
return result return result
@ -523,7 +522,7 @@ export const mutations = {
}, },
addEmojiReactionsBy (state, { id, emojiReactions, currentUser }) { addEmojiReactionsBy (state, { id, emojiReactions, currentUser }) {
const status = state.allStatusesObject[id] const status = state.allStatusesObject[id]
set(status, 'emoji_reactions', emojiReactions) status['emoji_reactions'] = emojiReactions
}, },
addOwnReaction (state, { id, emoji, currentUser }) { addOwnReaction (state, { id, emoji, currentUser }) {
const status = state.allStatusesObject[id] const status = state.allStatusesObject[id]
@ -542,9 +541,9 @@ export const mutations = {
// Update count of existing reaction if it exists, otherwise append at the end // Update count of existing reaction if it exists, otherwise append at the end
if (reactionIndex >= 0) { if (reactionIndex >= 0) {
set(status.emoji_reactions, reactionIndex, newReaction) status.emoji_reactions[reactionIndex] = newReaction
} else { } else {
set(status, 'emoji_reactions', [...status.emoji_reactions, newReaction]) status['emoji_reactions'] = [...status.emoji_reactions, newReaction]
} }
}, },
removeOwnReaction (state, { id, emoji, currentUser }) { removeOwnReaction (state, { id, emoji, currentUser }) {
@ -563,9 +562,9 @@ export const mutations = {
} }
if (newReaction.count > 0) { if (newReaction.count > 0) {
set(status.emoji_reactions, reactionIndex, newReaction) status.emoji_reactions[reactionIndex] = newReaction
} else { } else {
set(status, 'emoji_reactions', status.emoji_reactions.filter(r => r.name !== emoji)) status['emoji_reactions'] = status.emoji_reactions.filter(r => r.name !== emoji)
} }
}, },
updateStatusWithPoll (state, { id, poll }) { updateStatusWithPoll (state, { id, poll }) {

View File

@ -1,7 +1,6 @@
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js' import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
import oauthApi from '../services/new_api/oauth.js' import oauthApi from '../services/new_api/oauth.js'
import { compact, map, each, mergeWith, last, concat, uniq, isArray } from 'lodash' import { compact, map, each, mergeWith, last, concat, uniq, isArray } from 'lodash'
import { set } from 'vue'
import { registerPushNotifications, unregisterPushNotifications } from '../services/push/push.js' import { registerPushNotifications, unregisterPushNotifications } from '../services/push/push.js'
// TODO: Unify with mergeOrAdd in statuses.js // TODO: Unify with mergeOrAdd in statuses.js
@ -15,9 +14,9 @@ export const mergeOrAdd = (arr, obj, item) => {
} else { } else {
// This is a new item, prepare it // This is a new item, prepare it
arr.push(item) arr.push(item)
set(obj, item.id, item) obj[item.id] = item
if (item.screen_name && !item.screen_name.includes('@')) { if (item.screen_name && !item.screen_name.includes('@')) {
set(obj, item.screen_name.toLowerCase(), item) obj[item.screen_name.toLowerCase()] = item
} }
return { item, new: true } return { item, new: true }
} }
@ -103,23 +102,23 @@ export const mutations = {
const user = state.usersObject[id] const user = state.usersObject[id]
const tags = user.tags || [] const tags = user.tags || []
const newTags = tags.concat([tag]) const newTags = tags.concat([tag])
set(user, 'tags', newTags) user['tags'] = newTags
}, },
untagUser (state, { user: { id }, tag }) { untagUser (state, { user: { id }, tag }) {
const user = state.usersObject[id] const user = state.usersObject[id]
const tags = user.tags || [] const tags = user.tags || []
const newTags = tags.filter(t => t !== tag) const newTags = tags.filter(t => t !== tag)
set(user, 'tags', newTags) user['tags'] = newTags
}, },
updateRight (state, { user: { id }, right, value }) { updateRight (state, { user: { id }, right, value }) {
const user = state.usersObject[id] const user = state.usersObject[id]
let newRights = user.rights let newRights = user.rights
newRights[right] = value newRights[right] = value
set(user, 'rights', newRights) user['rights'] = newRights
}, },
updateActivationStatus (state, { user: { id }, deactivated }) { updateActivationStatus (state, { user: { id }, deactivated }) {
const user = state.usersObject[id] const user = state.usersObject[id]
set(user, 'deactivated', deactivated) user['deactivated'] = deactivated
}, },
setCurrentUser (state, user) { setCurrentUser (state, user) {
state.lastLoginName = user.screen_name state.lastLoginName = user.screen_name
@ -148,26 +147,26 @@ export const mutations = {
clearFriends (state, userId) { clearFriends (state, userId) {
const user = state.usersObject[userId] const user = state.usersObject[userId]
if (user) { if (user) {
set(user, 'friendIds', []) user['friendIds'] = []
} }
}, },
clearFollowers (state, userId) { clearFollowers (state, userId) {
const user = state.usersObject[userId] const user = state.usersObject[userId]
if (user) { if (user) {
set(user, 'followerIds', []) user['followerIds'] = []
} }
}, },
addNewUsers (state, users) { addNewUsers (state, users) {
each(users, (user) => { each(users, (user) => {
if (user.relationship) { if (user.relationship) {
set(state.relationships, user.relationship.id, user.relationship) state.relationships[user.relationship.id] = user.relationship
} }
mergeOrAdd(state.users, state.usersObject, user) mergeOrAdd(state.users, state.usersObject, user)
}) })
}, },
updateUserRelationship (state, relationships) { updateUserRelationship (state, relationships) {
relationships.forEach((relationship) => { relationships.forEach((relationship) => {
set(state.relationships, relationship.id, relationship) state.relationships[relationship.id] = relationship
}) })
}, },
saveBlockIds (state, blockIds) { saveBlockIds (state, blockIds) {
@ -222,7 +221,7 @@ export const mutations = {
}, },
setColor (state, { user: { id }, highlighted }) { setColor (state, { user: { id }, highlighted }) {
const user = state.usersObject[id] const user = state.usersObject[id]
set(user, 'highlight', highlighted) user['highlight'] = highlighted
}, },
signUpPending (state) { signUpPending (state) {
state.signUpPending = true state.signUpPending = true

View File

@ -1,4 +1,4 @@
import Vue from 'vue' import { reactive } from 'vue'
/* By default async components don't have any way to recover, if component is /* By default async components don't have any way to recover, if component is
* failed, it is failed forever. This helper tries to remedy that by recreating * failed, it is failed forever. This helper tries to remedy that by recreating
@ -13,7 +13,7 @@ function getResettableAsyncComponent (asyncComponent, options) {
...options ...options
}) })
const observe = Vue.observable({ c: asyncComponentFactory() }) const observe = reactive({ c: asyncComponentFactory() })
return { return {
functional: true, functional: true,

View File

@ -3,17 +3,17 @@
import localForage from 'localforage' import localForage from 'localforage'
import { parseNotification } from './services/entity_normalizer/entity_normalizer.service.js' import { parseNotification } from './services/entity_normalizer/entity_normalizer.service.js'
import { prepareNotificationObject } from './services/notification_utils/notification_utils.js' import { prepareNotificationObject } from './services/notification_utils/notification_utils.js'
import Vue from 'vue' import { createApp } from 'vue'
import VueI18n from 'vue-i18n' import { createI18n } from 'vue-i18n'
import messages from './i18n/service_worker_messages.js' import messages from './i18n/service_worker_messages.js'
Vue.use(VueI18n) const i18n = createI18n({
const i18n = new VueI18n({
// By default, use the browser locale, we will update it if neccessary // By default, use the browser locale, we will update it if neccessary
locale: 'en', locale: 'en',
fallbackLocale: 'en', fallbackLocale: 'en',
messages messages
}) })
createApp({}).use(i18n)
function isEnabled () { function isEnabled () {
return localForage.getItem('vuex-lz') return localForage.getItem('vuex-lz')

697
yarn.lock

File diff suppressed because it is too large Load Diff