+ {{ $t('settings.style.preview.content') }} +
+ +
+ {{ $t('settings.style.preview.mono') }}
+
+
+ {{ $t('settings.style.preview.link') }}
+
+ diff --git a/.babelrc b/.babelrc index bc2b0e31..3c732dd1 100644 --- a/.babelrc +++ b/.babelrc @@ -1,5 +1,5 @@ { - "presets": ["es2015", "stage-2", "env"], - "plugins": ["transform-runtime", "lodash", "transform-vue-jsx"], + "presets": ["@babel/preset-env"], + "plugins": ["@babel/plugin-transform-runtime", "lodash", "@vue/babel-plugin-transform-vue-jsx"], "comments": false } diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9d42288e..7f6d3c92 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -24,7 +24,7 @@ test: - apt install firefox-esr -y --no-install-recommends - firefox --version - yarn - - npm run unit + - yarn unit build: stage: build diff --git a/CHANGELOG b/CHANGELOG deleted file mode 100644 index ca2ebcfa..00000000 --- a/CHANGELOG +++ /dev/null @@ -1,35 +0,0 @@ -## 2017-02-20 - -- Overall CSS styling fixes -- Current theme is displayed in theme selector -- Theme selector is moved to the settings page -- Oembed attachments will now display correctly -- Styling changes to the user info cards -- Notification count in title -- Better Notification handling (persistance, mark as read) -- Post statuses with ctrl+enter -- Links in statuses open in a new tab -- Optimized mobile view -- Fix crash on persistance failure -- Compress persisted state -- Sync mutes with backend (SEE NOTE BELOW) - -Pleroma will now try to get the current mutes from the backend. Sadly, a bug in -Qvitter will not allow getting the mutes from the endpoint, because it will -ignore HTTP Basic authentication. Mutes will still persist in Pleroma through -localstorage, but the mutes from Qvitter won't be picked up if the call fails. - -The patch for Qvitter: - ---- a/actions/apiqvittermutes.php -+++ b/actions/apiqvittermutes.php -@@ -74,7 +74,7 @@ class ApiQvitterMutesAction extends ApiPrivateAuthAction - { - parent::handle(); - -- $this->target = Profile::current(); -+ $this->target = $this->scoped; - - if(!$this->target instanceof Profile) { - $this->clientError(_('You have to be logged in to view your mutes.'), 403); - diff --git a/CHANGELOG.md b/CHANGELOG.md index 2719edcf..ad03c760 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,14 +2,94 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - ## [Unreleased] +### Changed +- Removed the use of with_move parameters when fetching notifications + +### Fixed +- Weird bug related to post being sent seemingly after pasting with keyboard (hopefully) +- Multiple issues with muted statuses/notifications + +## [Unreleased patch] +### Add +- Added private notifications option for push notifications +- 'Copy link' button for statuses (in the ellipsis menu) +- Autocomplete domains from list of known instances + +### Changed +- Registration page no longer requires email if the server is configured not to require it +- Change heart to thumbs up in reaction picker +- Close the media modal on navigation events +- Add colons to the emoji alt text, to make them copyable +- Add better visual indication for drag-and-drop for files + +### Fixed +- Status ellipsis menu closes properly when selecting certain options +- Cropped images look correct in Chrome +- Newlines in the muted words settings work again +- Clicking on non-latin hashtags won't open a new window +- Uploading and drag-dropping multiple files works correctly now. + +## [2.0.3] - 2020-05-02 +### Fixed +- Show more/less works correctly with auto-collapsed subjects and long posts +- RTL characters won't look messed up in notifications + +### Changed +- Emoji autocomplete will match any part of the word and not just start, for example :drool will now helpfully suggest :blobcatdrool: and :blobcatdroolreach: + +### Add +- Follow request notification support + +## [2.0.2] - 2020-04-08 +### Fixed +- Favorite/Repeat avatars not showing up on private instances/non-public posts +- Autocorrect getting triggered in the captcha field +- Overflow on long domains in follow/move notifications + +### Changed +- Polish translation updated + +## [2.0.0] - 2020-02-28 +### Added +- Tons of color slots including ones for hover/pressed/toggled buttons +- Experimental `--variable[,mod]` syntax support for color slots in themes. the `mod` makes color brighter/darker depending on background color (makes darker color brighter/darker depending on background color) +- Paper theme by Shpuld +- Icons in nav panel +- Private mode support +- Support for 'Move' type notifications +- Pleroma AMOLED dark theme +- User level domain mutes, under User Settings -> Mutes +- Emoji reactions for statuses +- MRF keyword policy disclosure +### Changed +- Updated Pleroma default themes +- theme engine update to 3 (themes v2.1 introduction) +- massive internal changes in theme engine - slowly away from "generate things separately with spaghetti code" towards "feed all data into single 'generateTheme' function and declare slot inheritance and all in a separate file" +- Breezy theme updates to make it closer to actual Breeze in some aspects +- when using `--variable` in shadows it no longer uses the actual CSS3 variable, instead it generates color from other slots +- theme doesn't get saved to local storage when opening FE anonymously +- Captcha now resets on failed registrations +- Notifications column now cleans itself up to optimize performance when tab is left open for a long time +- 403 messaging +### Fixed +- Fixed loader-spinner not disappearing when a status preview fails to load +- anon viewers won't get theme data saved to local storage, so admin changing default theme will have an effect for users coming back to instance. +- Single notifications left unread when hitting read on another device/tab +- Registration fixed +- Deactivation of remote accounts from frontend +- Fixed NSFW unhiding not working with videos when using one-click unhiding/displaying +- Improved performance of anything that uses popovers (most notably statuses) + +## [1.1.7 and earlier] - 2019-12-14 ### Added - Ability to hide/show repeats from user - User profile button clutter organized into a menu - Emoji picker - Started changelog anew - Ability to change user's email +- About page +- Added remote user redirect ### Changed - changed the way fading effects for user profile/long statuses works, now uses css-mask instead of gradient background hacks which weren't exactly compatible with semi-transparent themes ### Fixed diff --git a/README.md b/README.md index 889f0837..b66383ad 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# pleroma_fe +# Pleroma-FE -> A single column frontend for both Pleroma and GS servers. +> A single column frontend designed for Pleroma. ![screenshot](https://i.imgur.com/DJVqSJ0.png) @@ -11,7 +11,6 @@ To translate Pleroma-FE, add your language to [src/i18n/messages.js](https://git # FOR ADMINS You don't need to build Pleroma-FE yourself. Those using the Pleroma backend will be able to use it out of the box. -For the GNU social backend, check out https://git.pleroma.social/pleroma/pleroma-fe/wikis/dual-boot-with-qvitter to see how to run Pleroma-FE and Qvitter at the same time. ## Build Setup diff --git a/build/webpack.base.conf.js b/build/webpack.base.conf.js index f8968966..dfef37a6 100644 --- a/build/webpack.base.conf.js +++ b/build/webpack.base.conf.js @@ -3,6 +3,7 @@ var config = require('../config') var utils = require('./utils') var projectRoot = path.resolve(__dirname, '../') var ServiceWorkerWebpackPlugin = require('serviceworker-webpack-plugin') +var FontelloPlugin = require("fontello-webpack-plugin") var env = process.env.NODE_ENV // check env & config/index.js to decide weither to enable CSS Sourcemaps for the @@ -11,6 +12,8 @@ var cssSourceMapDev = (env === 'development' && config.dev.cssSourceMap) var cssSourceMapProd = (env === 'production' && config.build.productionSourceMap) var useCssSourceMap = cssSourceMapDev || cssSourceMapProd +var now = Date.now() + module.exports = { entry: { app: './src/main.js' @@ -32,6 +35,7 @@ module.exports = { ], alias: { 'vue$': 'vue/dist/vue.runtime.common', + 'static': path.resolve(__dirname, '../static'), 'src': path.resolve(__dirname, '../src'), 'assets': path.resolve(__dirname, '../src/assets'), 'components': path.resolve(__dirname, '../src/components') @@ -90,6 +94,14 @@ module.exports = { new ServiceWorkerWebpackPlugin({ entry: path.join(__dirname, '..', 'src/sw.js'), filename: 'sw-pleroma.js' + }), + new FontelloPlugin({ + config: require('../static/fontello.json'), + name: 'fontello', + output: { + css: 'static/[name].' + now + '.css', // [hash] is not supported. Use the current timestamp instead for versioning. + font: 'static/font/[name].' + now + '.[ext]' + } }) ] } diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index 35363537..14b0428f 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -19,32 +19,69 @@ There's currently no mechanism for user-settings synchronization across several ## Options -### `theme` -Default theme used for new users. De-facto instance-default, user can change theme. +### `alwaysShowSubjectInput` +`true` - will always show subject line input, `false` - only show when it's not empty (i.e. replying). To hide subject line input completely, set it to `false` and `subjectLineBehavior` to `"noop"` ### `background` Default image background. Be aware of using too big images as they may take longer to load. Currently image is fitted with `background-size: cover` which means "scaled and cropped", currently left-aligned. De-facto instance default, user can choose their own background, if they remove their own background, instance default will be used instead. +### `collapseMessageWithSubject` +Collapse post content when post has a subject line (content warning). Instance-default. + +### `disableChat` +hides the chat (TODO: even if it's enabled on backend) + +### `greentext` +Changes lines prefixed with the `>` character to have a green text color + +### `hideFilteredStatuses` +Removes filtered statuses from timelines. + +### `hideMutedPosts` +Removes muted statuses from timelines. + +### `hidePostStats` +Hide repeats/favorites counters for posts. + +### `hideSitename` +Hide instance name in header. + +### `hideUserStats` +Hide followers/friends counters for users. + +### `loginMethod` +`"password"` - show simple password field +`"token"` - show button to log in with external method (will redirect to login form, more details in BE documentation) + ### `logo`, `logoMask`, `logoMargin` Instance `logo`, could be any image, including svg. By default it assumes logo used will be monochrome-with-alpha one, this is done to be compatible with both light and dark themes, so that white logo designed with dark theme in mind won't be invisible over light theme, this is done via [CSS3 Masking](https://www.html5rocks.com/en/tutorials/masking/adobe/). Basically - it will take alpha channel of the image and fill non-transparent areas of it with solid color. If you really want colorful logo - it can be done by setting `logoMask` to `false`. `logoMargin` allows you to adjust vertical margins between logo boundary and navbar borders. The idea is that to have logo's image without any extra margins and instead adjust them to your need in layout. +### `minimalScopesMode` +Limit scope selection to *Direct*, *User default* and *Scope of post replying to*. This also makes it impossible to reply to a DM with a non-DM post from PleromaFE. + +### `nsfwCensorImage` +Use custom image for NSFW'd images + +### `postContentType` +Default post formatting option (markdown/bbcode/plaintext/etc...) + ### `redirectRootNoLogin`, `redirectRootLogin` These two settings should point to where FE should redirect visitor when they login/open up website root -### `chatDisabled` -hides the chat (TODO: even if it's enabled on backend) +### `scopeCopy` +Copy post scope (visibility) when replying to a post. Instance-default. + +### `sidebarRight` +Change alignment of sidebar and panels to the right. Defaults to `false`. + +### `showFeaturesPanel` +Show panel showcasing instance features/settings to logged-out visitors ### `showInstanceSpecificPanel` This allows you to include arbitrary HTML content in a panel below navigation menu. PleromaFE looks for an html page `instance/panel.html`, by default it's not provided in FE, but BE bundles some [default one](https://git.pleroma.social/pleroma/pleroma/blob/develop/priv/static/instance/panel.html). De-facto instance-defaults, since user can hide instance-specific panel. -### `collapseMessageWithSubject` -Collapse post content when post has a subject line (content warning). Instance-default. - -### `scopeCopy` -Copy post scope (visibility) when replying to a post. Instance-default. - ### `subjectLineBehavior` How to handle subject line (CW) when replying to a post. * `"email"` - like EMail - prepend `re: ` to subject line if it doesn't already start with it. @@ -52,36 +89,22 @@ How to handle subject line (CW) when replying to a post. * `"noop"` - do not copy Instance-default. -### `postContentType` -Default post formatting option (markdown/bbcode/plaintext/etc...) - -### `alwaysShowSubjectInput` -`true` - will always show subject line input, `false` - only show when it's not empty (i.e. replying). To hide subject line input completely, set it to `false` and `subjectLineBehavior` to `"noop"` - -### `hidePostStats` and `hideUserStats` -Hide counters for posts and users respectively, i.e. hiding repeats/favorites counts for posts, hiding followers/friends counts for users. This is just cosmetic and aimed to ease pressure and bias imposed by stat numbers of people and/or posts. (as an example: so that people care less about how many followers someone has since they can't see that info) - -### `loginMethod` -`"password"` - show simple password field -`"token"` - show button to log in with external method (will redirect to login form, more details in BE documentation) +### `theme` +Default theme used for new users. De-facto instance-default, user can change theme. ### `webPushNotifications` Enables [PushAPI](https://developer.mozilla.org/en-US/docs/Web/API/Push_API) - based notifications for users. Instance-default. -### `noAttachmentLinks` -**TODO Currently doesn't seem to be doing anything code-wise**, but implication is to disable adding links for attachments, which looks nicer but breaks compatibility with old GNU/Social servers. -### `nsfwCensorImage` -Use custom image for NSFW'd images - -### `showFeaturesPanel` -Show panel showcasing instance features/settings to logged-out visitors ## Indirect configuration Some features are configured depending on how backend is configured. In general the approach is "if backend allows it there's no need to hide it, if backend doesn't allow it there's no need to show it. ### Chat -**TODO somewhat broken, see: chatDisabled** chat can be disabled by disabling it in backend +**TODO somewhat broken, see: disableChat** chat can be disabled by disabling it in backend + +### Private Mode +If the `private` instance setting is enabled in the backend, features that are not accessible without authentication, such as the timelines and search will be disabled for unauthenticated users. ### Rich text formatting in post formatting Rich text formatting options are displayed depending on how many formatting options are enabled on backend, if you don't want your users to use rich text at all you can only allow "text/plain" one, frontend then will only display post text format as a label instead of dropdown (just so that users know for example if you only allow Markdown, only BBCode or only Plain text) @@ -89,10 +112,3 @@ Rich text formatting options are displayed depending on how many formatting opti ### Who to follow This is a panel intended for users to find people to follow based on randomness or on post contents. Being potentially privacy unfriendly feature it needs to be enabled and configured in backend to be enabled. -### Safe DM message display - -Setting this will change the warning text that is displayed for direct messages. - -ATTENTION: If you actually want the behavior to change. You will need to set the appropriate option at the backend. See the backend documentation for information about that. - -DO NOT activate this without checking the backend configuration first! diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md index 076bfb1c..f417f33d 100644 --- a/docs/USER_GUIDE.md +++ b/docs/USER_GUIDE.md @@ -33,7 +33,7 @@ will become Note that you can only use emoji defined on your instance, you cannot "copy" someone else's emoji, and will have to ask your administrator to copy emoji from other instance to yours. Lastly, there's two convenience options for emoji: an emoji picker (smiley face to the right of "submit" button) and autocomplete suggestions - when you start typing :shortcode: it will automatically try to suggest you emoj and complete the shortcode for you if you select one. **Note** that if emoji doesn't show up in suggestions nor in emoji picker it means there's no such emoji on your instance, if shortcode doesn't match any defined emoji it will appear as text. * **Attachments** are fairly simple - you can attach any file to a post as long as the file is within maximum size limits. If you're uploading explicit material you can mark all of your attachments as sensitive (or add `#nsfw` tag) - it will hide the images and videos behind a warning so that it won't be displayed instantly. -* **Subject line** also known as **CW** (Content Warning) could be used as a header to the post and/or to warn others about contents of the post having something that might upset somebody or something among those lines. Several applications allow to hide post content leaving only subject line visible. As a side-effect using subject line will also mark your images as sensitive (see above). +* **Subject line** also known as **CW** (Content Warning) could be used as a header to the post and/or to warn others about contents of the post having something that might upset somebody or something among those lines. Several applications allow to hide post content leaving only subject line visible. Using a subject line will not mark your images as sensitive, you will have to do that explicitly (see above). * **Visiblity scope** controls who will be able to see your posts. There are four scopes available: 1. `Public`: This is the default, and some fediverse software like GNU Social only supports this. This means that your post is accessible by anyone and will be shown in the public timelines. diff --git a/index.html b/index.html index fd4e795e..1ff944d9 100644 --- a/index.html +++ b/index.html @@ -6,8 +6,6 @@
{{ $t("about.mrf.mrf_policies_desc") }}
+ +{{ $t("about.mrf.simple.accept_desc") }}
+ +{{ $t("about.mrf.simple.reject_desc") }}
+ +{{ $t("about.mrf.simple.quarantine_desc") }}
+ +{{ $t("about.mrf.simple.ftl_removal_desc") }}
+ +{{ $t("about.mrf.simple.media_nsfw_desc") }}
+ +{{ $t("about.mrf.simple.media_removal_desc") }}
+ +{{ $t('settings.filtering_explanation') }}
- -{{ $t('settings.version.backend_version') }}
-{{ $t('settings.version.frontend_version') }}
-{{ $t('settings.import_followers_from_a_csv_file') }}
+{{ $t('settings.import_blocks_from_a_csv_file') }}
+{{ $t('settings.filtering_explanation') }}
+ +
+
{{ $t('settings.notification_mutes') }}
+{{ $t('settings.notification_blocks') }}
+{{ $t('settings.name') }}
+{{ $t('settings.bio') }}
+
+
+
+
+
+
+
+
+
+
+ {{ $t('settings.avatar_size_instruction') }} +
+{{ $t('settings.current_avatar') }}
+ +{{ $t('settings.set_new_avatar') }}
+{{ $t('settings.current_profile_banner') }}
+ +{{ $t('settings.set_new_profile_banner') }}
+ +{{ $t('settings.set_new_profile_background') }}
+ +{{ $t('settings.new_email') }}
+ +{{ $t('settings.current_password') }}
+ ++ {{ $t('settings.changed_email') }} +
+ +{{ $t('settings.change_email_error') }}
+{{ changeEmailError }}
+ +{{ $t('settings.current_password') }}
+ +{{ $t('settings.new_password') }}
+ +{{ $t('settings.confirm_new_password') }}
+ ++ {{ $t('settings.changed_password') }} +
++ {{ $t('settings.change_password_error') }} +
++ {{ changePasswordError }} +
+{{ $t('settings.app_name') }} | +{{ $t('settings.valid_until') }} | ++ |
---|---|---|
{{ oauthToken.appName }} | +{{ oauthToken.validUntil }} | +
+ |
+
+ {{ $t('settings.delete_account_description') }} +
+{{ $t('settings.delete_account_instructions') }}
+{{ $t('login.password') }}
+ ++ {{ $t('settings.delete_account_error') }} +
++ {{ deleteAccountError }} +
+
+ {{ $t('settings.style.preview.mono') }}
+
+
+ {{ $t('settings.style.preview.link') }}
+
+ {{ $t('settings.theme_help') }}
-{{ $t('settings.theme_help_v2_1') }}
{{ $t('settings.theme_help_v2_2') }}
{{ $t('settings.version.backend_version') }}
+{{ $t('settings.version.frontend_version') }}
+ for paragraphs, GS uses
between them)
- // as well as approximate line count by counting characters and approximating ~80
- // per line.
- //
- // Using max-height + overflow: auto for status components resulted in false positives
- // very often with japanese characters, and it was very annoying.
- tallStatus () {
- const lengthScore = this.status.statusnet_html.split(/
20
- },
- longSubject () {
- return this.status.summary.length > 900
- },
isReply () {
return !!(this.status.in_reply_to_status_id && this.status.in_reply_to_user_id)
},
@@ -163,7 +171,7 @@ const Status = {
if (this.inConversation || !this.isReply) {
return false
}
- if (this.status.user.id === this.$store.state.users.currentUser.id) {
+ if (this.status.user.id === this.currentUser.id) {
return false
}
if (this.status.type === 'retweet') {
@@ -174,43 +182,19 @@ const Status = {
if (this.status.user.id === this.status.attentions[i].id) {
continue
}
- const taggedUser = this.$store.getters.findUser(this.status.attentions[i].id)
- if (checkFollowing && taggedUser && taggedUser.following) {
+ // There's zero guarantee of this working. If we happen to have that user and their
+ // relationship in store then it will work, but there's kinda little chance of having
+ // them for people you're not following.
+ const relationship = this.$store.state.users.relationships[this.status.attentions[i].id]
+ if (checkFollowing && relationship && relationship.following) {
return false
}
- if (this.status.attentions[i].id === this.$store.state.users.currentUser.id) {
+ if (this.status.attentions[i].id === this.currentUser.id) {
return false
}
}
return this.status.attentions.length > 0
},
- hideSubjectStatus () {
- if (this.tallStatus && !this.localCollapseSubjectDefault) {
- return false
- }
- return !this.expandingSubject && this.status.summary
- },
- hideTallStatus () {
- if (this.status.summary && this.localCollapseSubjectDefault) {
- return false
- }
- if (this.showingTall) {
- return false
- }
- return this.tallStatus
- },
- showingMore () {
- return (this.tallStatus && this.showingTall) || (this.status.summary && this.expandingSubject)
- },
- nsfwClickthrough () {
- if (!this.status.nsfw) {
- return false
- }
- if (this.status.summary && this.localCollapseSubjectDefault) {
- return false
- }
- return true
- },
replySubject () {
if (!this.status.summary) return ''
const decodedSummary = unescape(this.status.summary)
@@ -224,43 +208,6 @@ const Status = {
return ''
}
},
- attachmentSize () {
- if ((this.mergedConfig.hideAttachments && !this.inConversation) ||
- (this.mergedConfig.hideAttachmentsInConv && this.inConversation) ||
- (this.status.attachments.length > this.maxThumbnails)) {
- return 'hide'
- } else if (this.compact) {
- return 'small'
- }
- return 'normal'
- },
- galleryTypes () {
- if (this.attachmentSize === 'hide') {
- return []
- }
- return this.mergedConfig.playVideosInModal
- ? ['image', 'video']
- : ['image']
- },
- galleryAttachments () {
- return this.status.attachments.filter(
- file => fileType.fileMatchesSomeType(this.galleryTypes, file)
- )
- },
- nonGalleryAttachments () {
- return this.status.attachments.filter(
- file => !fileType.fileMatchesSomeType(this.galleryTypes, file)
- )
- },
- maxThumbnails () {
- return this.mergedConfig.maxThumbnails
- },
- contentHtml () {
- if (!this.status.summary_html) {
- return this.status.statusnet_html
- }
- return this.status.summary_html + '
' + this.status.statusnet_html
- },
combinedFavsAndRepeatsUsers () {
// Use the status from the global status repository since favs and repeats are saved in it
const combinedUsers = [].concat(
@@ -269,31 +216,31 @@ const Status = {
)
return uniqBy(combinedUsers, 'id')
},
- ownStatus () {
- return this.status.user.id === this.$store.state.users.currentUser.id
- },
tags () {
return this.status.tags.filter(tagObj => tagObj.hasOwnProperty('name')).map(tagObj => tagObj.name).join(' ')
},
hidePostStats () {
return this.mergedConfig.hidePostStats
},
- ...mapGetters(['mergedConfig'])
+ ...mapGetters(['mergedConfig']),
+ ...mapState({
+ betterShadow: state => state.interface.browserSupport.cssFilter,
+ currentUser: state => state.users.currentUser
+ })
},
components: {
- Attachment,
FavoriteButton,
+ ReactButton,
RetweetButton,
ExtraButtons,
PostStatusForm,
- Poll,
UserCard,
UserAvatar,
- Gallery,
- LinkPreview,
AvatarList,
Timeago,
- StatusPopover
+ StatusPopover,
+ EmojiReactions,
+ StatusContent
},
methods: {
visibilityIcon (visibility) {
@@ -314,32 +261,6 @@ const Status = {
clearError () {
this.error = undefined
},
- linkClicked (event) {
- const target = event.target.closest('.status-content a')
- if (target) {
- if (target.className.match(/mention/)) {
- const href = target.href
- const attn = this.status.attentions.find(attn => mentionMatchesUrl(attn, href))
- if (attn) {
- event.stopPropagation()
- event.preventDefault()
- const link = this.generateUserProfileLink(attn.id, attn.screen_name)
- this.$router.push(link)
- return
- }
- }
- if (target.rel.match(/(?:^|\s)tag(?:$|\s)/) || target.className.match(/hashtag/)) {
- // Extract tag name from link url
- const tag = extractTagFromUrl(target.href)
- if (tag) {
- const link = this.generateTagLink(tag)
- this.$router.push(link)
- return
- }
- }
- window.open(target.href, '_blank')
- }
- },
toggleReplying () {
this.replying = !this.replying
},
@@ -357,26 +278,8 @@ const Status = {
toggleUserExpanded () {
this.userExpanded = !this.userExpanded
},
- toggleShowMore () {
- if (this.showingTall) {
- this.showingTall = false
- } else if (this.expandingSubject && this.status.summary) {
- this.expandingSubject = false
- } else if (this.hideTallStatus) {
- this.showingTall = true
- } else if (this.hideSubjectStatus && this.status.summary) {
- this.expandingSubject = true
- }
- },
generateUserProfileLink (id, name) {
return generateProfileLink(id, name, this.$store.state.instance.restrictedNicknames)
- },
- generateTagLink (tag) {
- return `/tag/${tag}`
- },
- setMedia () {
- const attachments = this.attachmentSize === 'hide' ? this.status.attachments : this.galleryAttachments
- return () => this.$store.dispatch('setMedia', attachments)
}
},
watch: {
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 65778b2e..336f912a 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -17,12 +17,33 @@
for paragraphs, GS uses
between them)
+ // as well as approximate line count by counting characters and approximating ~80
+ // per line.
+ //
+ // Using max-height + overflow: auto for status components resulted in false positives
+ // very often with japanese characters, and it was very annoying.
+ tallStatus () {
+ const lengthScore = this.status.statusnet_html.split(/
20
+ },
+ longSubject () {
+ return this.status.summary.length > 900
+ },
+ // When a status has a subject and is also tall, we should only have one show more/less button. If the default is to collapse statuses with subjects, we just treat it like a status with a subject; otherwise, we just treat it like a tall status.
+ mightHideBecauseSubject () {
+ return this.status.summary && (!this.tallStatus || this.localCollapseSubjectDefault)
+ },
+ mightHideBecauseTall () {
+ return this.tallStatus && (!this.status.summary || !this.localCollapseSubjectDefault)
+ },
+ hideSubjectStatus () {
+ return this.mightHideBecauseSubject && !this.expandingSubject
+ },
+ hideTallStatus () {
+ return this.mightHideBecauseTall && !this.showingTall
+ },
+ showingMore () {
+ return (this.mightHideBecauseTall && this.showingTall) || (this.mightHideBecauseSubject && this.expandingSubject)
+ },
+ nsfwClickthrough () {
+ if (!this.status.nsfw) {
+ return false
+ }
+ if (this.status.summary && this.localCollapseSubjectDefault) {
+ return false
+ }
+ return true
+ },
+ attachmentSize () {
+ if ((this.mergedConfig.hideAttachments && !this.inConversation) ||
+ (this.mergedConfig.hideAttachmentsInConv && this.inConversation) ||
+ (this.status.attachments.length > this.maxThumbnails)) {
+ return 'hide'
+ } else if (this.compact) {
+ return 'small'
+ }
+ return 'normal'
+ },
+ galleryTypes () {
+ if (this.attachmentSize === 'hide') {
+ return []
+ }
+ return this.mergedConfig.playVideosInModal
+ ? ['image', 'video']
+ : ['image']
+ },
+ galleryAttachments () {
+ return this.status.attachments.filter(
+ file => fileType.fileMatchesSomeType(this.galleryTypes, file)
+ )
+ },
+ nonGalleryAttachments () {
+ return this.status.attachments.filter(
+ file => !fileType.fileMatchesSomeType(this.galleryTypes, file)
+ )
+ },
+ hasImageAttachments () {
+ return this.status.attachments.some(
+ file => fileType.fileType(file.mimetype) === 'image'
+ )
+ },
+ hasVideoAttachments () {
+ return this.status.attachments.some(
+ file => fileType.fileType(file.mimetype) === 'video'
+ )
+ },
+ maxThumbnails () {
+ return this.mergedConfig.maxThumbnails
+ },
+ postBodyHtml () {
+ const html = this.status.statusnet_html
+
+ if (this.mergedConfig.greentext) {
+ try {
+ if (html.includes('>')) {
+ // This checks if post has '>' at the beginning, excluding mentions so that @mention >impying works
+ return processHtml(html, (string) => {
+ if (string.includes('>') &&
+ string
+ .replace(/<[^>]+?>/gi, '') // remove all tags
+ .replace(/@\w+/gi, '') // remove mentions (even failed ones)
+ .trim()
+ .startsWith('>')) {
+ return `${string}`
+ } else {
+ return string
+ }
+ })
+ } else {
+ return html
+ }
+ } catch (e) {
+ console.err('Failed to process status html', e)
+ return html
+ }
+ } else {
+ return html
+ }
+ },
+ contentHtml () {
+ if (!this.status.summary_html) {
+ return this.postBodyHtml
+ }
+ return this.status.summary_html + '
' + this.postBodyHtml
+ },
+ ...mapGetters(['mergedConfig']),
+ ...mapState({
+ betterShadow: state => state.interface.browserSupport.cssFilter,
+ currentUser: state => state.users.currentUser
+ })
+ },
+ components: {
+ Attachment,
+ Poll,
+ Gallery,
+ LinkPreview
+ },
+ methods: {
+ linkClicked (event) {
+ const target = event.target.closest('.status-content a')
+ if (target) {
+ if (target.className.match(/mention/)) {
+ const href = target.href
+ const attn = this.status.attentions.find(attn => mentionMatchesUrl(attn, href))
+ if (attn) {
+ event.stopPropagation()
+ event.preventDefault()
+ const link = this.generateUserProfileLink(attn.id, attn.screen_name)
+ this.$router.push(link)
+ return
+ }
+ }
+ if (target.rel.match(/(?:^|\s)tag(?:$|\s)/) || target.className.match(/hashtag/)) {
+ // Extract tag name from dataset or link url
+ const tag = target.dataset.tag || extractTagFromUrl(target.href)
+ if (tag) {
+ const link = this.generateTagLink(tag)
+ this.$router.push(link)
+ return
+ }
+ }
+ window.open(target.href, '_blank')
+ }
+ },
+ toggleShowMore () {
+ if (this.mightHideBecauseTall) {
+ this.showingTall = !this.showingTall
+ } else if (this.mightHideBecauseSubject) {
+ this.expandingSubject = !this.expandingSubject
+ }
+ },
+ generateUserProfileLink (id, name) {
+ return generateProfileLink(id, name, this.$store.state.instance.restrictedNicknames)
+ },
+ generateTagLink (tag) {
+ return `/tag/${tag}`
+ },
+ setMedia () {
+ const attachments = this.attachmentSize === 'hide' ? this.status.attachments : this.galleryAttachments
+ return () => this.$store.dispatch('setMedia', attachments)
+ }
+ }
+}
+
+export default StatusContent
diff --git a/src/components/status_content/status_content.vue b/src/components/status_content/status_content.vue
new file mode 100644
index 00000000..8c2e8749
--- /dev/null
+++ b/src/components/status_content/status_content.vue
@@ -0,0 +1,240 @@
+
+
+
{{ $t('settings.name') }}
-{{ $t('settings.bio') }}
-
-
-
-
-
-
-
-
-
- {{ $t('settings.avatar_size_instruction') }} -
-{{ $t('settings.current_avatar') }}
- -{{ $t('settings.set_new_avatar') }}
-{{ $t('settings.current_profile_banner') }}
- -{{ $t('settings.set_new_profile_banner') }}
- -{{ $t('settings.set_new_profile_background') }}
- -{{ $t('settings.new_email') }}
- -{{ $t('settings.current_password') }}
- -- {{ $t('settings.changed_email') }} -
- -{{ $t('settings.change_email_error') }}
-{{ changeEmailError }}
- -{{ $t('settings.current_password') }}
- -{{ $t('settings.new_password') }}
- -{{ $t('settings.confirm_new_password') }}
- -- {{ $t('settings.changed_password') }} -
-- {{ $t('settings.change_password_error') }} -
-- {{ changePasswordError }} -
-{{ $t('settings.app_name') }} | -{{ $t('settings.valid_until') }} | -- |
---|---|---|
{{ oauthToken.appName }} | -{{ oauthToken.validUntil }} | -
- |
-
- {{ $t('settings.delete_account_description') }} -
-{{ $t('settings.delete_account_instructions') }}
-{{ $t('login.password') }}
- -- {{ $t('settings.delete_account_error') }} -
-- {{ deleteAccountError }} -
-{{ $t('settings.notification_mutes') }}
-{{ $t('settings.notification_blocks') }}
-{{ $t('settings.import_followers_from_a_csv_file') }}
-{{ $t('settings.import_blocks_from_a_csv_file') }}
-This is the default placeholder ToS. You should change it to fit the needs of your instance.
+This is the default placeholder ToS. You should copy it over to your static folder and edit it to fit the needs of your instance.
To do so, place a file at "/instance/static/terms-of-service.html"
in your
Pleroma install containing the real ToS for your instance.
See the Pleroma documentation for more information.
3 4
5 \n 6 7
8
' + expect(processHtml(inputOutput, processorKeep)).to.eql(inputOutput) + }) + + it('fed with sorta valid HTML but tags aren\'t closed', () => { + const inputOutput = 'just leaving a
p \nwithin
p!
and a3 4
5 \n 6 7
8
_
_\n__
_
' + const output = '
_' + expect(processHtml(input, processorReplace)).to.eql(output) + }) + + it('fed with sorta valid HTML but tags aren\'t closed', () => { + const input = 'just leaving a
p \nwithin
p!
and a_\n_
_
_