diff --git a/CHANGELOG.md b/CHANGELOG.md index 6244951a73..99f601a504 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - New option to optimize timeline rendering to make the site more responsive (enabled by default) ## [Unreleased patch] - ### Fixed - Fixed chats list not updating its order when new messages come in - Fixed chat messages sometimes getting lost when you receive a message at the same time @@ -16,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Added - Import/export a muted users +- Proper handling of deletes when using websocket streaming ## [2.1.1] - 2020-09-08 ### Changed diff --git a/build/webpack.base.conf.js b/build/webpack.base.conf.js index dfef37a636..ef40333ce4 100644 --- a/build/webpack.base.conf.js +++ b/build/webpack.base.conf.js @@ -97,6 +97,7 @@ module.exports = { }), new FontelloPlugin({ config: require('../static/fontello.json'), + host: 'https://fontello.com', name: 'fontello', output: { css: 'static/[name].' + now + '.css', // [hash] is not supported. Use the current timestamp instead for versioning. diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js index 5c09f6ca7b..3ad80df33e 100644 --- a/src/components/emoji_picker/emoji_picker.js +++ b/src/components/emoji_picker/emoji_picker.js @@ -8,10 +8,20 @@ const LOAD_EMOJI_BY = 60 const LOAD_EMOJI_MARGIN = 64 const filterByKeyword = (list, keyword = '') => { + if (keyword === '') return list + const keywordLowercase = keyword.toLowerCase() - return list.filter(emoji => - emoji.displayText.toLowerCase().includes(keywordLowercase) - ) + let orderedEmojiList = [] + for (const emoji of list) { + const indexOfKeyword = emoji.displayText.toLowerCase().indexOf(keywordLowercase) + if (indexOfKeyword > -1) { + if (!Array.isArray(orderedEmojiList[indexOfKeyword])) { + orderedEmojiList[indexOfKeyword] = [] + } + orderedEmojiList[indexOfKeyword].push(emoji) + } + } + return orderedEmojiList.flat() } const EmojiPicker = { diff --git a/src/components/react_button/react_button.js b/src/components/react_button/react_button.js index 11627e9cbb..dd71e5465a 100644 --- a/src/components/react_button/react_button.js +++ b/src/components/react_button/react_button.js @@ -28,9 +28,17 @@ const ReactButton = { emojis () { if (this.filterWord !== '') { const filterWordLowercase = this.filterWord.toLowerCase() - return this.$store.state.instance.emoji.filter(emoji => - emoji.displayText.toLowerCase().includes(filterWordLowercase) - ) + let orderedEmojiList = [] + for (const emoji of this.$store.state.instance.emoji) { + const indexOfFilterWord = emoji.displayText.toLowerCase().indexOf(filterWordLowercase) + if (indexOfFilterWord > -1) { + if (!Array.isArray(orderedEmojiList[indexOfFilterWord])) { + orderedEmojiList[indexOfFilterWord] = [] + } + orderedEmojiList[indexOfFilterWord].push(emoji) + } + } + return orderedEmojiList.flat() } return this.$store.state.instance.emoji || [] }, diff --git a/src/components/reply_button/reply_button.js b/src/components/reply_button/reply_button.js new file mode 100644 index 0000000000..2295765040 --- /dev/null +++ b/src/components/reply_button/reply_button.js @@ -0,0 +1,12 @@ + +const ReplyButton = { + name: 'ReplyButton', + props: ['status', 'replying'], + computed: { + loggedIn () { + return !!this.$store.state.users.currentUser + } + } +} + +export default ReplyButton diff --git a/src/components/reply_button/reply_button.vue b/src/components/reply_button/reply_button.vue new file mode 100644 index 0000000000..b2904b5c4a --- /dev/null +++ b/src/components/reply_button/reply_button.vue @@ -0,0 +1,21 @@ + + + diff --git a/src/components/status/status.js b/src/components/status/status.js index cd6e2f729f..e48b2eb885 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -1,3 +1,4 @@ +import ReplyButton from '../reply_button/reply_button.vue' import FavoriteButton from '../favorite_button/favorite_button.vue' import ReactButton from '../react_button/react_button.vue' import RetweetButton from '../retweet_button/retweet_button.vue' @@ -19,6 +20,7 @@ import { unescape, uniqBy } from 'lodash' const Status = { name: 'Status', components: { + ReplyButton, FavoriteButton, ReactButton, RetweetButton, @@ -158,7 +160,7 @@ const Status = { return this.mergedConfig.hideFilteredStatuses }, hideStatus () { - return this.deleted || (this.muted && this.hideFilteredStatuses) || this.virtualHidden + return (this.muted && this.hideFilteredStatuses) || this.virtualHidden }, isFocused () { // retweet or root of an expanded conversation diff --git a/src/components/status/status.scss b/src/components/status/status.scss index c92d870bbb..66a91c1ee4 100644 --- a/src/components/status/status.scss +++ b/src/components/status/status.scss @@ -30,6 +30,18 @@ $status-margin: 0.75em; border-left-style: solid; } + .gravestone { + padding: $status-margin; + color: $fallback--faint; + color: var(--faint, $fallback--faint); + display: flex; + + .deleted-text { + margin: 0.5em 0; + align-items: center; + } + } + .status-container { display: flex; padding: $status-margin; diff --git a/src/components/status/status.vue b/src/components/status/status.vue index aa67e433f3..ffae32fccd 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -95,6 +95,7 @@
-
- - - {{ status.replies_count }} -
+
+
+
+ +
+
+
+ {{ $t('status.status_deleted') }} +
+ +
+
+
@@ -42,5 +48,10 @@ border-radius: $fallback--avatarAltRadius; border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius); } + + &.-placeholder { + background-color: $fallback--fg; + background-color: var(--fg, $fallback--fg); + } } diff --git a/src/i18n/en.json b/src/i18n/en.json index 01f895038f..d3d575624e 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -665,7 +665,8 @@ "show_full_subject": "Show full subject", "hide_full_subject": "Hide full subject", "show_content": "Show content", - "hide_content": "Hide content" + "hide_content": "Hide content", + "status_deleted": "This post was deleted" }, "user_card": { "approve": "Approve", diff --git a/src/i18n/fi.json b/src/i18n/fi.json index 3832dcaa88..2524f2788a 100644 --- a/src/i18n/fi.json +++ b/src/i18n/fi.json @@ -578,7 +578,8 @@ "show_full_subject": "Näytä koko otsikko", "hide_full_subject": "Piilota koko otsikko", "show_content": "Näytä sisältö", - "hide_content": "Piilota sisältö" + "hide_content": "Piilota sisältö", + "status_deleted": "Poistettu viesti" }, "user_card": { "approve": "Hyväksy", diff --git a/src/i18n/it.json b/src/i18n/it.json index 4d09600411..ce50863091 100644 --- a/src/i18n/it.json +++ b/src/i18n/it.json @@ -702,7 +702,8 @@ "reply_to": "Rispondi a", "delete_confirm": "Vuoi veramente eliminare questo messaggio?", "unbookmark": "Rimuovi segnalibro", - "bookmark": "Aggiungi segnalibro" + "bookmark": "Aggiungi segnalibro", + "status_deleted": "Questo messagio è stato cancellato" }, "time": { "years_short": "{0}a", diff --git a/src/i18n/ru.json b/src/i18n/ru.json index 3444a26d48..8f421b50de 100644 --- a/src/i18n/ru.json +++ b/src/i18n/ru.json @@ -473,5 +473,10 @@ "tool_tip": { "accept_follow_request": "Принять запрос на чтение", "reject_follow_request": "Отклонить запрос на чтение" + }, + "image_cropper": { + "save_without_cropping": "Сохранить не обрезая", + "save": "Сохранить", + "crop_picture": "Обрезать картинку" } } diff --git a/src/modules/api.js b/src/modules/api.js index 73511442d7..0a354c3f3a 100644 --- a/src/modules/api.js +++ b/src/modules/api.js @@ -72,6 +72,8 @@ const api = { showImmediately: timelineData.visibleStatuses.length === 0, timeline: 'friends' }) + } else if (message.event === 'delete') { + dispatch('deleteStatusById', message.id) } else if (message.event === 'pleroma:chat_update') { dispatch('addChatMessages', { chatId: message.chatUpdate.id, diff --git a/src/modules/statuses.js b/src/modules/statuses.js index 155cc4b91e..e673141d48 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -611,6 +611,10 @@ const statuses = { commit('setDeleted', { status }) apiService.deleteStatus({ id: status.id, credentials: rootState.users.currentUser.credentials }) }, + deleteStatusById ({ rootState, commit }, id) { + const status = rootState.statuses.allStatusesObject[id] + commit('setDeleted', { status }) + }, markStatusesAsDeleted ({ commit }, condition) { commit('setManyDeleted', condition) },