Merge remote-tracking branch 'origin/develop' into setttingssync
This commit is contained in:
commit
44ae68b025
22 changed files with 180 additions and 76 deletions
87
.forgejo/issue_template/bug.yaml
Normal file
87
.forgejo/issue_template/bug.yaml
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
name: 'Bug report'
|
||||
about: 'Bug report for Pleroma FE'
|
||||
labels:
|
||||
- Bug
|
||||
body:
|
||||
- type: input
|
||||
id: env-browser
|
||||
attributes:
|
||||
label: Browser and OS
|
||||
description: What browser are you using, including version, and what OS are you running?
|
||||
placeholder: Firefox 140, Arch Linux
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: env-instance
|
||||
attributes:
|
||||
label: Instance URL
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: env-backend
|
||||
attributes:
|
||||
label: Backend version information
|
||||
description: Backend version being used. (See Settings->Show advanced->Developer)
|
||||
placeholder: Pleroma BE 2.10
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: env-frontend
|
||||
attributes:
|
||||
label: Frontend version information
|
||||
description: Frontend version being used. (See Settings->Show advanced->Developer)
|
||||
placeholder: Pleroma FE 2.10
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: env-extensions
|
||||
attributes:
|
||||
label: Browser extensions
|
||||
description: List of browser extensions you are using, like uBlock, rikaichamp etc. If none leave empty.
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: env-modifications
|
||||
attributes:
|
||||
label: Known instance/user customizations
|
||||
description: Whether you are using a Pleroma FE fork, any mods mods or instance level styles among others.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: bug-text
|
||||
attributes:
|
||||
label: Bug description
|
||||
description: A short description of the bug. Images can be helpful.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: bug-reproducer
|
||||
attributes:
|
||||
label: Reproduction steps
|
||||
description: Ordered list of reproduction steps needed to make the bug happen. If you don't have reproduction steps, leave this empty.
|
||||
placeholder: |
|
||||
1. Log in with a fresh browser session
|
||||
2. Open timeline X
|
||||
3. Click on button Y
|
||||
4. Z broke
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: bug-seriousness
|
||||
attributes:
|
||||
label: Bug seriousness
|
||||
value: |
|
||||
* How annoying it is:
|
||||
* How often does it happen:
|
||||
* How many people does it affect:
|
||||
* Is there a workaround for it:
|
||||
- type: checkboxes
|
||||
id: duplicate-issues
|
||||
attributes:
|
||||
label: Duplicate issues
|
||||
hide_label: true
|
||||
description: Before submitting this issue, search for same or similar issues on the [Pleroma FE bug tracker](https://git.pleroma.social/pleroma/pleroma-fe/issues).
|
||||
options:
|
||||
- label: I've searched for same or similar issues before submitting this issue.
|
||||
required: true
|
||||
visible: [form]
|
||||
22
.forgejo/issue_template/suggestion.yaml
Normal file
22
.forgejo/issue_template/suggestion.yaml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
name: 'Feature request / Suggestion / Improvement'
|
||||
about: 'Feature requests, suggestions and improvements for Pleroma FE'
|
||||
labels:
|
||||
- Feature Request / Enhancement
|
||||
body:
|
||||
- type: textarea
|
||||
id: issue-text
|
||||
attributes:
|
||||
label: Proposal
|
||||
placeholder: Make groups happen!
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: duplicate-issues
|
||||
attributes:
|
||||
label: Duplicate issues
|
||||
hide_label: true
|
||||
description: Before submitting this issue, search for same or similar requests on the [Pleroma FE bug tracker](https://git.pleroma.social/pleroma/pleroma-fe/issues).
|
||||
options:
|
||||
- label: I've searched for same or similar requests before submitting this issue.
|
||||
required: true
|
||||
visible: [form]
|
||||
12
.forgejo/pull_request_template.md
Normal file
12
.forgejo/pull_request_template.md
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
### Checklist
|
||||
- [ ] Adding a changelog: In the `changelog.d` directory, create a file named `<code>.<type>`.
|
||||
|
||||
<!--
|
||||
`<code>` can be anything, but we recommend using a more or less unique identifier to avoid collisions, such as the branch name.
|
||||
|
||||
`<type>` can be `add`, `change`, `remove`, `fix`, `security` or `skip`. `skip` is only used if there is no user-visible change in the MR (for example, only editing comments in the code). Otherwise, choose a type that corresponds to your change.
|
||||
|
||||
In the file, write the changelog entry. For example, if an MR adds group functionality, we can create a file named `group.add` and write `Add group functionality` in it.
|
||||
|
||||
If one changelog entry is not enough, you may add more. But that might mean you can split it into two MRs. Only use more than one changelog entry if you really need to (for example, when one change in the code fix two different bugs, or when refactoring).
|
||||
-->
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
# For Translators
|
||||
|
||||
To translate Pleroma-FE, use our weblate server: https://translate.pleroma.social/. If you need to add your language it should be added as a json file in [src/i18n/](https://git.pleroma.social/pleroma/pleroma-fe/blob/develop/src/i18n/) folder and added in a list within [src/i18n/languages.js](https://git.pleroma.social/pleroma/pleroma-fe/blob/develop/src/i18n/languages.js).
|
||||
To translate Pleroma-FE, use our weblate server: https://translate.pleroma.social/. If you need to add your language it should be added as a json file in [src/i18n/](https://git.pleroma.social/pleroma/pleroma-fe/src/src/i18n/) folder and added in a list within [src/i18n/languages.js](https://git.pleroma.social/pleroma/pleroma-fe/src/src/i18n/languages.js).
|
||||
|
||||
Pleroma-FE will set your language by your browser locale, but you can change language in settings.
|
||||
|
||||
|
|
@ -32,10 +32,10 @@ yarn unit
|
|||
|
||||
# For Contributors:
|
||||
|
||||
You can create file `/config/local.json` (see [example](https://git.pleroma.social/pleroma/pleroma-fe/blob/develop/config/local.example.json)) to enable some convenience dev options:
|
||||
You can create file `/config/local.json` (see [example](https://git.pleroma.social/pleroma/pleroma-fe/src/config/local.example.json)) to enable some convenience dev options:
|
||||
|
||||
* `target`: makes local dev server redirect to some existing instance's BE instead of local BE, useful for testing things in near-production environment and searching for real-life use-cases.
|
||||
* `staticConfigPreference`: makes FE's `/static/config.json` take preference of BE-served `/api/statusnet/config.json`. Only works in dev mode.
|
||||
* `staticConfigPreference`: makes FE's `/static/config.json` take preference of BE-served `/api/pleroma/frontend_configurations`. Only works in dev mode.
|
||||
|
||||
FE Build process also leaves current commit hash in global variable `___pleromafe_commit_hash` so that you can easily see which pleroma-fe commit instance is running, also helps pinpointing which commit was used when FE was bundled into BE.
|
||||
|
||||
|
|
|
|||
1
changelog.d/attrs-parsing.fix
Normal file
1
changelog.d/attrs-parsing.fix
Normal file
|
|
@ -0,0 +1 @@
|
|||
Fix HTML attribute parsing for escaped quotes
|
||||
|
|
@ -7,9 +7,9 @@
|
|||
|
||||
PleromaFE gets its configuration from several sources, in order of preference (the one above overrides ones below it)
|
||||
|
||||
1. `/api/statusnet/config.json` - this is generated on Backend and contains multiple things including instance name, char limit etc. It also contains FE/Client-specific data, PleromaFE uses `pleromafe` field of it. For more info on changing config on BE, look [here](../backend/configuration/cheatsheet.md#frontend_configurations)
|
||||
2. `/static/config.json` - this is a static FE-provided file, containing only FE specific configuration. This file is completely optional and could be removed but is useful as a fallback if some configuration JSON property isn't present in BE-provided config. It's also a reference point to check what default configuration are and what JSON properties even exist. In local dev mode it could be used to override BE configuration, more about that in HACKING.md. File is located [here](https://git.pleroma.social/pleroma/pleroma-fe/blob/develop/static/config.json).
|
||||
3. Built-in defaults. Those are hard-coded defaults that are used when `/static/config.json` is not available and BE-provided configuration JSON is missing some JSON properties. ( [Code](https://git.pleroma.social/pleroma/pleroma-fe/blob/develop/src/modules/instance.js) )
|
||||
1. `/api/pleroma/frontend_configurations` - this is generated by backend and includes FE/Client-specific data. PleromaFE uses the `pleroma_fe` field of it. For more info on changing config on BE, look [here](../backend/configuration/cheatsheet.md#frontend_configurations)
|
||||
2. `/static/config.json` - this is a static FE-provided file, containing only FE specific configuration. This file is completely optional and could be removed but is useful as a fallback if some configuration JSON property isn't present in BE-provided config. It's also a reference point to check what default configuration are and what JSON properties even exist. In local dev mode it could be used to override BE configuration, more about that in HACKING.md. File is located [here](https://git.pleroma.social/pleroma/pleroma-fe/src/public/static/config.json).
|
||||
3. Built-in defaults. Those are hard-coded defaults that are used when `/static/config.json` is not available and BE-provided configuration JSON is missing some JSON properties. ( [Code](https://git.pleroma.social/pleroma/pleroma-fe/src/src/stores/instance.js) )
|
||||
|
||||
## Instance-defaults
|
||||
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ server {
|
|||
|
||||
In 99% cases PleromaFE uses [MastoAPI](https://docs.joinmastodon.org/api/) with [Pleroma Extensions](../backend/API/differences_in_mastoapi_responses.md) to fetch the data. The rest is either QvitterAPI leftovers or pleroma-exclusive APIs. QvitterAPI doesn't exactly have documentation and uses different JSON structure and sometimes different parameters and workflows, [this](https://twitter-api.readthedocs.io/en/latest/index.html) could be a good reference though. Some pleroma-exclusive API may still be using QvitterAPI JSON structure.
|
||||
|
||||
PleromaFE supports both formats by transforming them into internal format which is basically QvitterAPI one with some additions and renaming. All data is passed trough [Entity Normalizer](https://git.pleroma.social/pleroma/pleroma-fe/-/blob/develop/src/services/entity_normalizer/entity_normalizer.service.js) which can serve as a reference of API and what's actually used, it's also a host for all the hacks and data transformation.
|
||||
PleromaFE supports both formats by transforming them into internal format which is basically QvitterAPI one with some additions and renaming. All data is passed trough [Entity Normalizer](https://git.pleroma.social/pleroma/pleroma-fe/src/src/services/entity_normalizer/entity_normalizer.service.js) which can serve as a reference of API and what's actually used, it's also a host for all the hacks and data transformation.
|
||||
|
||||
For most part, PleromaFE tries to store all the info it can get in global vuex store - every user and post are passed trough updating mechanism where data is either added or merged with existing data, reactively updating the information throughout UI, so if in newest request user's post counter increased, it will be instantly updated in open user profile cards. This is also used to find users, posts and sometimes to build timelines and/or request parameters.
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"name": "pleroma_fe",
|
||||
"version": "2.10.1",
|
||||
"description": "Pleroma frontend, the default frontend of Pleroma social network server",
|
||||
"author": "Pleroma contributors <https://git.pleroma.social/pleroma/pleroma-fe/-/blob/develop/CONTRIBUTORS.md>",
|
||||
"author": "Pleroma contributors <https://git.pleroma.social/pleroma/pleroma-fe/src/CONTRIBUTORS.md>",
|
||||
"private": false,
|
||||
"scripts": {
|
||||
"dev": "node build/update-emoji.js && vite dev",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { mapState } from 'pinia'
|
||||
|
||||
import nsfwImage from '../../assets/nsfw.png'
|
||||
import fileTypeService from '../../services/file_type/file_type.service.js'
|
||||
import Flash from '../flash/flash.vue'
|
||||
import StillImage from '../still-image/still-image.vue'
|
||||
import VideoAttachment from '../video_attachment/video_attachment.vue'
|
||||
|
|
@ -62,9 +61,7 @@ const Attachment = {
|
|||
hideNsfwLocal: useSyncConfigStore().mergedConfig.hideNsfw,
|
||||
preloadImage: useSyncConfigStore().mergedConfig.preloadImage,
|
||||
loading: false,
|
||||
img:
|
||||
fileTypeService.fileType(this.attachment.mimetype) === 'image' &&
|
||||
document.createElement('img'),
|
||||
img: this.attachment.type === 'image' && document.createElement('img'),
|
||||
modalOpen: false,
|
||||
showHidden: false,
|
||||
flashLoaded: false,
|
||||
|
|
@ -85,7 +82,7 @@ const Attachment = {
|
|||
'-editable': this.edit !== undefined,
|
||||
'-compact': this.compact,
|
||||
},
|
||||
'-type-' + this.type,
|
||||
'-type-' + this.attachment.type,
|
||||
this.size && '-size-' + this.size,
|
||||
`-${this.useContainFit ? 'contain' : 'cover'}-fit`,
|
||||
]
|
||||
|
|
@ -98,14 +95,14 @@ const Attachment = {
|
|||
},
|
||||
placeholderName() {
|
||||
if (this.attachment.description === '' || !this.attachment.description) {
|
||||
return this.type.toUpperCase()
|
||||
return this.attachment.type.toUpperCase()
|
||||
}
|
||||
return this.attachment.description
|
||||
},
|
||||
placeholderIconClass() {
|
||||
if (this.type === 'image') return 'image'
|
||||
if (this.type === 'video') return 'video'
|
||||
if (this.type === 'audio') return 'music'
|
||||
if (this.attachment.type === 'image') return 'image'
|
||||
if (this.attachment.type === 'video') return 'video'
|
||||
if (this.attachment.type === 'audio') return 'music'
|
||||
return 'file'
|
||||
},
|
||||
referrerpolicy() {
|
||||
|
|
@ -113,14 +110,11 @@ const Attachment = {
|
|||
? ''
|
||||
: 'no-referrer'
|
||||
},
|
||||
type() {
|
||||
return fileTypeService.fileType(this.attachment.mimetype)
|
||||
},
|
||||
hidden() {
|
||||
return this.nsfw && this.hideNsfwLocal && !this.showHidden
|
||||
},
|
||||
isEmpty() {
|
||||
return this.type === 'html' && !this.attachment.oembed
|
||||
return this.attachment.type === 'html' && !this.attachment.oembed
|
||||
},
|
||||
useModal() {
|
||||
let modalTypes = []
|
||||
|
|
@ -135,7 +129,7 @@ const Attachment = {
|
|||
: ['image']
|
||||
break
|
||||
}
|
||||
return modalTypes.includes(this.type)
|
||||
return modalTypes.includes(this.attachment.type)
|
||||
},
|
||||
videoTag() {
|
||||
return this.useModal ? 'button' : 'span'
|
||||
|
|
@ -160,7 +154,7 @@ const Attachment = {
|
|||
if (this.useModal) {
|
||||
this.$emit('setMedia')
|
||||
useMediaViewerStore().setCurrentMedia(this.attachment)
|
||||
} else if (this.type === 'unknown') {
|
||||
} else if (this.attachment.type === 'unknown') {
|
||||
window.open(this.attachment.url)
|
||||
}
|
||||
},
|
||||
|
|
@ -193,7 +187,7 @@ const Attachment = {
|
|||
if (
|
||||
this.mergedConfig.useOneClickNsfw &&
|
||||
!this.showHidden &&
|
||||
(this.type !== 'video' || this.mergedConfig.playVideosInModal)
|
||||
(this.attachment.type !== 'video' || this.mergedConfig.playVideosInModal)
|
||||
) {
|
||||
this.openModal(event)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
@click="openModal"
|
||||
>
|
||||
<a
|
||||
v-if="type !== 'html'"
|
||||
v-if="attachment.type !== 'html'"
|
||||
class="placeholder"
|
||||
target="_blank"
|
||||
:href="attachment.url"
|
||||
|
|
@ -70,7 +70,7 @@
|
|||
:src="nsfwImage"
|
||||
>
|
||||
<FAIcon
|
||||
v-if="type === 'video'"
|
||||
v-if="attachment.type === 'video'"
|
||||
class="play-icon"
|
||||
icon="play-circle"
|
||||
/>
|
||||
|
|
@ -80,7 +80,7 @@
|
|||
class="attachment-buttons"
|
||||
>
|
||||
<button
|
||||
v-if="type === 'flash' && flashLoaded"
|
||||
v-if="attachment.type === 'flash' && flashLoaded"
|
||||
class="button-default attachment-button -transparent"
|
||||
:title="$t('status.attachment_stop_flash')"
|
||||
@click.prevent="stopFlash"
|
||||
|
|
@ -88,7 +88,7 @@
|
|||
<FAIcon icon="stop" />
|
||||
</button>
|
||||
<button
|
||||
v-if="attachment.description && size !== 'small' && !edit && type !== 'unknown'"
|
||||
v-if="attachment.description && size !== 'small' && !edit && attachment.type !== 'unknown'"
|
||||
class="button-default attachment-button -transparent"
|
||||
:title="$t('status.show_attachment_description')"
|
||||
@click.prevent="toggleDescription"
|
||||
|
|
@ -96,7 +96,7 @@
|
|||
<FAIcon icon="align-right" />
|
||||
</button>
|
||||
<button
|
||||
v-if="!useModal && type !== 'unknown'"
|
||||
v-if="!useModal && attachment.type !== 'unknown'"
|
||||
class="button-default attachment-button -transparent"
|
||||
:title="$t('status.show_attachment_in_modal')"
|
||||
@click.prevent="openModalForce"
|
||||
|
|
@ -138,7 +138,7 @@
|
|||
</div>
|
||||
|
||||
<a
|
||||
v-if="type === 'image' && (!hidden || preloadImage)"
|
||||
v-if="attachment.type === 'image' && (!hidden || preloadImage)"
|
||||
class="image-container"
|
||||
:class="{'-hidden': hidden && preloadImage }"
|
||||
:href="attachment.url"
|
||||
|
|
@ -156,7 +156,7 @@
|
|||
</a>
|
||||
|
||||
<a
|
||||
v-if="type === 'unknown' && !hidden"
|
||||
v-if="attachment.type === 'unknown' && !hidden"
|
||||
class="placeholder-container"
|
||||
:href="attachment.url"
|
||||
target="_blank"
|
||||
|
|
@ -173,7 +173,7 @@
|
|||
|
||||
<component
|
||||
:is="videoTag"
|
||||
v-if="type === 'video' && !hidden"
|
||||
v-if="attachment.type === 'video' && !hidden"
|
||||
class="video-container"
|
||||
:href="attachment.url"
|
||||
@click.stop.prevent="openModal"
|
||||
|
|
@ -193,13 +193,13 @@
|
|||
</component>
|
||||
|
||||
<span
|
||||
v-if="type === 'audio' && !hidden"
|
||||
v-if="attachment.type === 'audio' && !hidden"
|
||||
class="audio-container"
|
||||
:href="attachment.url"
|
||||
@click.stop.prevent="openModal"
|
||||
>
|
||||
<audio
|
||||
v-if="type === 'audio'"
|
||||
v-if="attachment.type === 'audio'"
|
||||
:src="attachment.url"
|
||||
:alt="attachment.description"
|
||||
:title="attachment.description"
|
||||
|
|
@ -210,7 +210,7 @@
|
|||
</span>
|
||||
|
||||
<div
|
||||
v-if="type === 'html' && attachment.oembed"
|
||||
v-if="attachment.type === 'html' && attachment.oembed"
|
||||
class="oembed-container"
|
||||
@click.prevent="linkClicked"
|
||||
>
|
||||
|
|
@ -229,7 +229,7 @@
|
|||
</div>
|
||||
|
||||
<span
|
||||
v-if="type === 'flash' && !hidden"
|
||||
v-if="attachment.type === 'flash' && !hidden"
|
||||
class="flash-container"
|
||||
:href="attachment.url"
|
||||
@click.stop.prevent="openModal"
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@ import StatusBody from '../status_content/status_content.vue'
|
|||
import Timeago from '../timeago/timeago.vue'
|
||||
import UserAvatar from '../user_avatar/user_avatar.vue'
|
||||
|
||||
import fileType from 'src/services/file_type/file_type.service'
|
||||
|
||||
const ChatListItem = {
|
||||
name: 'ChatListItem',
|
||||
props: ['chat'],
|
||||
|
|
@ -28,7 +26,7 @@ const ChatListItem = {
|
|||
}
|
||||
|
||||
const types = this.chat.lastMessage.attachments.map((file) =>
|
||||
fileType.fileType(file.mimetype),
|
||||
file.type,
|
||||
)
|
||||
if (types.includes('video')) {
|
||||
return this.$t('file_type.video')
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import Attachment from '../attachment/attachment.vue'
|
|||
|
||||
import { useMediaViewerStore } from 'src/stores/media_viewer.js'
|
||||
|
||||
const displayTypes = new Set(["image", "video", "flash"])
|
||||
|
||||
const Gallery = {
|
||||
props: [
|
||||
'attachments',
|
||||
|
|
@ -45,20 +47,14 @@ const Gallery = {
|
|||
: attachments
|
||||
.reduce(
|
||||
(acc, attachment, i) => {
|
||||
if (attachment.mimetype.includes('audio')) {
|
||||
if (attachment.type === 'audio') {
|
||||
return [
|
||||
...acc,
|
||||
{ audio: true, items: [attachment] },
|
||||
{ items: [] },
|
||||
]
|
||||
}
|
||||
if (
|
||||
!(
|
||||
attachment.mimetype.includes('image') ||
|
||||
attachment.mimetype.includes('video') ||
|
||||
attachment.mimetype.includes('flash')
|
||||
)
|
||||
) {
|
||||
if (!displayTypes.has(attachment.type)) {
|
||||
return [
|
||||
...acc,
|
||||
{ minimal: true, items: [attachment] },
|
||||
|
|
|
|||
|
|
@ -124,12 +124,12 @@ const ListsNew = {
|
|||
useListsStore()
|
||||
.createList({ title: this.titleDraft })
|
||||
.then((list) => {
|
||||
return useListsStore()
|
||||
useListsStore()
|
||||
.setListAccounts({
|
||||
listId: list.id,
|
||||
accountIds: [...this.addedUserIds],
|
||||
})
|
||||
.then(() => list.id)
|
||||
return list.id
|
||||
})
|
||||
.then((listId) => {
|
||||
this.$router.push({ name: 'lists-timeline', params: { id: listId } })
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import Flash from 'src/components/flash/flash.vue'
|
||||
import fileTypeService from '../../services/file_type/file_type.service.js'
|
||||
import GestureService from '../../services/gesture_service/gesture_service'
|
||||
import Modal from '../modal/modal.vue'
|
||||
import PinchZoom from '../pinch_zoom/pinch_zoom.vue'
|
||||
|
|
@ -59,9 +58,6 @@ const MediaModal = {
|
|||
canNavigate() {
|
||||
return this.media.length > 1
|
||||
},
|
||||
type() {
|
||||
return this.currentMedia ? this.getType(this.currentMedia) : null
|
||||
},
|
||||
swipeDisableClickThreshold() {
|
||||
// If there is only one media, allow more mouse movements to close the modal
|
||||
// because there is less chance that the user wants to switch to another image
|
||||
|
|
@ -69,9 +65,6 @@ const MediaModal = {
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
getType(media) {
|
||||
return fileTypeService.fileType(media.mimetype)
|
||||
},
|
||||
hide() {
|
||||
// HACK: Closing immediately via a touch will cause the click
|
||||
// to be processed on the content below the overlay
|
||||
|
|
@ -96,7 +89,7 @@ const MediaModal = {
|
|||
? this.media.length - 1
|
||||
: this.currentIndex - 1
|
||||
const newMedia = this.media[prevIndex]
|
||||
if (this.getType(newMedia) === 'image') {
|
||||
if (newMedia.type === 'image') {
|
||||
this.loading = true
|
||||
}
|
||||
useMediaViewerStore().setCurrentMedia(newMedia)
|
||||
|
|
@ -109,7 +102,7 @@ const MediaModal = {
|
|||
? 0
|
||||
: this.currentIndex + 1
|
||||
const newMedia = this.media[nextIndex]
|
||||
if (this.getType(newMedia) === 'image') {
|
||||
if (newMedia.type === 'image') {
|
||||
this.loading = true
|
||||
}
|
||||
useMediaViewerStore().setCurrentMedia(newMedia)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
@backdrop-clicked="hideIfNotSwiped"
|
||||
>
|
||||
<SwipeClick
|
||||
v-if="type === 'image'"
|
||||
v-if="currentMedia.type === 'image'"
|
||||
ref="swipeClick"
|
||||
class="modal-image-container"
|
||||
:direction="swipeDirection"
|
||||
|
|
@ -36,13 +36,13 @@
|
|||
</PinchZoom>
|
||||
</SwipeClick>
|
||||
<VideoAttachment
|
||||
v-if="type === 'video'"
|
||||
v-if="currentMedia.type === 'video'"
|
||||
class="modal-image"
|
||||
:attachment="currentMedia"
|
||||
:controls="true"
|
||||
/>
|
||||
<audio
|
||||
v-if="type === 'audio'"
|
||||
v-if="currentMedia.type === 'audio'"
|
||||
class="modal-image"
|
||||
:src="currentMedia.url"
|
||||
:alt="currentMedia.description"
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
controls
|
||||
/>
|
||||
<Flash
|
||||
v-if="type === 'flash'"
|
||||
v-if="currentMedia.type === 'flash'"
|
||||
class="modal-image"
|
||||
:src="currentMedia.url"
|
||||
:alt="currentMedia.description"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import DraftCloser from 'src/components/draft_closer/draft_closer.vue'
|
|||
import Gallery from 'src/components/gallery/gallery.vue'
|
||||
import Popover from 'src/components/popover/popover.vue'
|
||||
import { propsToNative } from '../../services/attributes_helper/attributes_helper.service.js'
|
||||
import fileTypeService from '../../services/file_type/file_type.service.js'
|
||||
import { findOffset } from '../../services/offset_finder/offset_finder.service.js'
|
||||
import genRandomSeed from '../../services/random_seed/random_seed.service.js'
|
||||
import statusPoster from '../../services/status_poster/status_poster.service.js'
|
||||
|
|
@ -650,9 +649,6 @@ const PostStatusForm = {
|
|||
this.$emit('resize')
|
||||
this.uploadingFiles = false
|
||||
},
|
||||
type(fileInfo) {
|
||||
return fileTypeService.fileType(fileInfo.mimetype)
|
||||
},
|
||||
paste(e) {
|
||||
this.autoPreview()
|
||||
this.resize(e)
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ import RichContent from 'src/components/rich_content/rich_content.jsx'
|
|||
|
||||
import { useSyncConfigStore } from 'src/stores/sync_config.js'
|
||||
|
||||
import fileType from 'src/services/file_type/file_type.service'
|
||||
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faFile,
|
||||
|
|
@ -106,7 +104,7 @@ const StatusBody = {
|
|||
},
|
||||
attachmentTypes() {
|
||||
return this.status.attachments.map((file) =>
|
||||
fileType.fileType(file.mimetype),
|
||||
file.type,
|
||||
)
|
||||
},
|
||||
collapsedStatus() {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import ldEscape from 'lodash/escape'
|
||||
import isEqual from 'lodash/isEqual'
|
||||
import merge from 'lodash/merge'
|
||||
import ldUnescape from 'lodash/unescape'
|
||||
|
|
@ -160,6 +161,9 @@ export default {
|
|||
this.$store.dispatch('fetchUserRelationship', this.user.id)
|
||||
},
|
||||
computed: {
|
||||
escapedNewBio() {
|
||||
return ldEscape(this.newBio).replace(/\n/g, '<br>')
|
||||
},
|
||||
somethingToSave() {
|
||||
if (this.newName !== this.user.name_unescaped) return true
|
||||
if (this.newBio !== ldUnescape(this.user.description)) return true
|
||||
|
|
@ -427,7 +431,7 @@ export default {
|
|||
zoomAvatar() {
|
||||
const attachment = {
|
||||
url: this.user.profile_image_url_original,
|
||||
mimetype: 'image',
|
||||
type: 'image',
|
||||
}
|
||||
useMediaViewerStore().setMedia([attachment])
|
||||
useMediaViewerStore().setCurrentMedia(attachment)
|
||||
|
|
|
|||
|
|
@ -358,7 +358,7 @@
|
|||
v-if="!hideBio"
|
||||
class="user-card-bio"
|
||||
:class="{ '-justify-left': mergedConfig.userCardLeftJustify }"
|
||||
:html="editable ? newBio.replace(/\n/g, '<br>') : user.description_html"
|
||||
:html="editable ? escapedNewBio : user.description_html"
|
||||
:emoji="editable ? emoji : user.emoji"
|
||||
:handle-links="true"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { parseLinkHeader } from '@web3-storage/parse-link-header'
|
||||
import escapeHtml from 'escape-html'
|
||||
import fileTypeService from '../file_type/file_type.service.js'
|
||||
import punycode from 'punycode.js'
|
||||
|
||||
import { isStatusNotification } from '../notification_utils/notification_utils.js'
|
||||
|
|
@ -297,6 +298,11 @@ export const parseAttachment = (data) => {
|
|||
// output.meta = ??? missing
|
||||
}
|
||||
|
||||
if (data.type !== 'unknown') {
|
||||
output.type = data.type
|
||||
} else {
|
||||
output.type = fileTypeService.fileType(output.mimetype)
|
||||
}
|
||||
output.url = data.url
|
||||
output.large_thumb_url = data.preview_url
|
||||
output.description = data.description
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ export const getAttrs = (tag, filter) => {
|
|||
.replace(/\/?$/, '')
|
||||
.trim()
|
||||
const attrs = Array.from(
|
||||
innertag.matchAll(/([a-z]+[a-z0-9-]*)(?:=("[^"]+?"|'[^']+?'))?/gi),
|
||||
innertag.matchAll(/([a-z]+[a-z0-9-]*)(?:=((?:"(?:\\.|[^"\\])*")|(?:'(?:\\.|[^'\\])*')))?/gi),
|
||||
)
|
||||
.map(([, key, value]) => [key, value])
|
||||
.map(([k, v]) => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
import { defineStore } from 'pinia'
|
||||
|
||||
import fileTypeService from '../services/file_type/file_type.service.js'
|
||||
|
||||
const supportedTypes = new Set(['image', 'video', 'audio', 'flash'])
|
||||
|
||||
export const useMediaViewerStore = defineStore('mediaViewer', {
|
||||
|
|
@ -13,8 +11,7 @@ export const useMediaViewerStore = defineStore('mediaViewer', {
|
|||
actions: {
|
||||
setMedia(attachments) {
|
||||
const media = attachments.filter((attachment) => {
|
||||
const type = fileTypeService.fileType(attachment.mimetype)
|
||||
return supportedTypes.has(type)
|
||||
return supportedTypes.has(attachment.type)
|
||||
})
|
||||
|
||||
this.media = media
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue