2018-05-02 02:05:36 +02:00
|
|
|
{#if realm === 'home'}
|
2018-08-28 15:44:36 +02:00
|
|
|
<h1 class="sr-only">Compose status</h1>
|
2018-05-02 02:05:36 +02:00
|
|
|
{/if}
|
2019-02-14 17:46:43 +01:00
|
|
|
<ComposeFileDrop {realm} >
|
2018-12-15 11:06:12 +01:00
|
|
|
<div class="{computedClassName} {hideAndFadeIn}">
|
2019-04-20 18:12:30 +02:00
|
|
|
<ComposeAuthor {realm} {dialogId} />
|
2018-12-15 11:06:12 +01:00
|
|
|
{#if contentWarningShown}
|
|
|
|
<div class="compose-content-warning-wrapper"
|
|
|
|
transition:slide="{duration: 333}">
|
|
|
|
<ComposeContentWarning {realm} {contentWarning} />
|
|
|
|
</div>
|
|
|
|
{/if}
|
2019-02-14 17:46:43 +01:00
|
|
|
<ComposeInput {realm} {text} {autoFocus} on:postAction="doPostStatus()" />
|
2018-12-15 11:06:12 +01:00
|
|
|
<ComposeLengthGauge {length} {overLimit} />
|
2019-11-23 22:21:21 +01:00
|
|
|
<ComposeAutosuggest {realm} {text} {dialogId} />
|
2019-05-27 09:24:47 +02:00
|
|
|
{#if poll && poll.options && poll.options.length}
|
|
|
|
<div class="compose-poll-wrapper"
|
|
|
|
transition:slide="{duration: 333}">
|
|
|
|
<ComposePoll {realm} {poll} />
|
|
|
|
</div>
|
|
|
|
{/if}
|
|
|
|
<ComposeToolbar {realm} {postPrivacy} {media} {contentWarningShown} {text} {poll} />
|
2018-12-15 11:06:12 +01:00
|
|
|
<ComposeLengthIndicator {length} {overLimit} />
|
2019-02-14 17:46:43 +01:00
|
|
|
<ComposeMedia {realm} {media} />
|
2019-09-15 19:45:46 +02:00
|
|
|
<ComposeMediaSensitive {realm} {media} {sensitive} {contentWarning} {contentWarningShown} />
|
2018-12-15 11:06:12 +01:00
|
|
|
</div>
|
|
|
|
</ComposeFileDrop>
|
2018-12-08 08:23:48 +01:00
|
|
|
<ComposeStickyButton {showSticky}
|
|
|
|
{overLimit}
|
|
|
|
{hideAndFadeIn}
|
|
|
|
on:postAction="doPostStatus()" />
|
2018-05-02 02:05:36 +02:00
|
|
|
{#if !hideBottomBorder}
|
|
|
|
<div class="compose-box-border-bottom {hideAndFadeIn}"></div>
|
|
|
|
{/if}
|
2018-12-15 11:06:12 +01:00
|
|
|
|
2018-02-26 01:26:43 +01:00
|
|
|
<style>
|
2018-02-27 06:54:21 +01:00
|
|
|
.compose-box {
|
2018-02-26 01:26:43 +01:00
|
|
|
border-radius: 4px;
|
2018-03-27 09:02:55 +02:00
|
|
|
padding: 20px 20px 0 20px;
|
2018-02-26 01:26:43 +01:00
|
|
|
display: grid;
|
|
|
|
align-items: flex-start;
|
|
|
|
grid-template-areas:
|
2019-05-06 17:34:03 +02:00
|
|
|
"avatar name handle handle"
|
|
|
|
"avatar cw cw cw"
|
|
|
|
"avatar input input input"
|
|
|
|
"avatar gauge gauge gauge"
|
|
|
|
"avatar autosuggest autosuggest autosuggest"
|
2019-05-27 09:24:47 +02:00
|
|
|
"avatar poll poll poll"
|
2019-05-06 17:34:03 +02:00
|
|
|
"avatar toolbar toolbar length"
|
2019-09-15 19:45:46 +02:00
|
|
|
"avatar media media media"
|
|
|
|
"avatar sensitive sensitive sensitive";
|
2018-02-27 05:55:49 +01:00
|
|
|
grid-template-columns: min-content minmax(0, max-content) 1fr 1fr;
|
2019-05-06 17:34:03 +02:00
|
|
|
position: relative;
|
2018-02-26 01:26:43 +01:00
|
|
|
}
|
|
|
|
|
2018-04-05 08:03:26 +02:00
|
|
|
.compose-box.direct-reply {
|
|
|
|
background-color: var(--status-direct-background);
|
|
|
|
}
|
|
|
|
|
2019-10-08 14:59:50 +02:00
|
|
|
:global(.compose-box-fade-in) {
|
2018-03-30 08:16:53 +02:00
|
|
|
transition: opacity 0.2s linear; /* main page reveal */
|
|
|
|
}
|
|
|
|
|
2018-03-27 09:02:55 +02:00
|
|
|
.compose-box-border-bottom {
|
|
|
|
height: 1px;
|
|
|
|
background: var(--main-border);
|
|
|
|
width: 100%;
|
|
|
|
}
|
|
|
|
|
2018-03-04 01:25:22 +01:00
|
|
|
.compose-content-warning-wrapper {
|
|
|
|
grid-area: cw;
|
|
|
|
}
|
|
|
|
|
2019-05-27 09:24:47 +02:00
|
|
|
.compose-poll-wrapper {
|
|
|
|
grid-area: poll;
|
|
|
|
}
|
|
|
|
|
2018-02-26 01:26:43 +01:00
|
|
|
@media (max-width: 767px) {
|
2018-02-27 06:54:21 +01:00
|
|
|
.compose-box {
|
2018-03-27 09:02:55 +02:00
|
|
|
padding: 10px 10px 0 10px;
|
2019-02-14 17:46:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
.compose-box-realm-dialog {
|
2019-02-14 03:38:34 +01:00
|
|
|
overflow-x: hidden;
|
2018-03-27 09:02:55 +02:00
|
|
|
}
|
2018-02-26 01:26:43 +01:00
|
|
|
}
|
2019-09-21 22:45:48 +02:00
|
|
|
|
|
|
|
@media (max-width: 240px) {
|
|
|
|
.compose-box {
|
|
|
|
padding: 10px 5px 0 5px;
|
|
|
|
}
|
|
|
|
}
|
2018-02-26 01:26:43 +01:00
|
|
|
</style>
|
|
|
|
<script>
|
2018-02-27 06:50:03 +01:00
|
|
|
import ComposeToolbar from './ComposeToolbar.html'
|
|
|
|
import ComposeLengthGauge from './ComposeLengthGauge.html'
|
|
|
|
import ComposeLengthIndicator from './ComposeLengthIndicator.html'
|
2018-02-27 06:54:21 +01:00
|
|
|
import ComposeAuthor from './ComposeAuthor.html'
|
2018-02-27 07:22:56 +01:00
|
|
|
import ComposeInput from './ComposeInput.html'
|
2018-12-02 20:22:18 +01:00
|
|
|
import ComposeStickyButton from './ComposeStickyButton.html'
|
2018-03-02 06:21:49 +01:00
|
|
|
import ComposeMedia from './ComposeMedia.html'
|
2018-03-04 00:44:43 +01:00
|
|
|
import ComposeContentWarning from './ComposeContentWarning.html'
|
2018-12-15 11:06:12 +01:00
|
|
|
import ComposeFileDrop from './ComposeFileDrop.html'
|
2019-05-06 17:34:03 +02:00
|
|
|
import ComposeAutosuggest from './ComposeAutosuggest.html'
|
2019-05-27 09:24:47 +02:00
|
|
|
import ComposePoll from './ComposePoll.html'
|
2019-09-15 19:45:46 +02:00
|
|
|
import ComposeMediaSensitive from './ComposeMediaSensitive.html'
|
2018-03-03 23:51:48 +01:00
|
|
|
import { measureText } from '../../_utils/measureText'
|
2018-08-26 21:14:16 +02:00
|
|
|
import { POST_PRIVACY_OPTIONS } from '../../_static/statuses'
|
2018-03-03 23:51:48 +01:00
|
|
|
import { store } from '../../_store/store'
|
2019-05-27 09:24:57 +02:00
|
|
|
import { slide } from '../../_transitions/slide'
|
2018-04-04 02:50:48 +02:00
|
|
|
import { postStatus, insertHandleForReply, setReplySpoiler, setReplyVisibility } from '../../_actions/compose'
|
2018-03-30 08:16:53 +02:00
|
|
|
import { classname } from '../../_utils/classname'
|
2019-05-27 09:24:47 +02:00
|
|
|
import { POLL_EXPIRY_DEFAULT } from '../../_static/polls'
|
2019-08-20 06:37:11 +02:00
|
|
|
import { scheduleIdleTask } from '../../_utils/scheduleIdleTask'
|
2018-02-26 02:21:17 +01:00
|
|
|
|
2018-02-26 01:26:43 +01:00
|
|
|
export default {
|
2018-04-20 06:38:01 +02:00
|
|
|
oncreate () {
|
2019-08-03 22:49:37 +02:00
|
|
|
const { realm, replySpoiler, replyVisibility } = this.get()
|
2018-12-02 20:22:18 +01:00
|
|
|
if (realm !== 'home' && realm !== 'dialog') {
|
2018-03-09 17:45:12 +01:00
|
|
|
// if this is a reply, populate the handle immediately
|
2018-12-02 20:22:18 +01:00
|
|
|
/* no await */ insertHandleForReply(realm)
|
2018-03-27 09:02:55 +02:00
|
|
|
}
|
2018-03-09 17:45:12 +01:00
|
|
|
|
2018-04-03 18:45:17 +02:00
|
|
|
if (replySpoiler) {
|
|
|
|
// default spoiler is same as the replied-to status
|
|
|
|
setReplySpoiler(realm, replySpoiler)
|
|
|
|
}
|
|
|
|
|
2018-04-04 02:50:48 +02:00
|
|
|
if (replyVisibility) {
|
|
|
|
// make sure the visibility is consistent with the replied-to status
|
|
|
|
setReplyVisibility(realm, replyVisibility)
|
|
|
|
}
|
2018-03-27 09:02:55 +02:00
|
|
|
},
|
2018-02-26 01:26:43 +01:00
|
|
|
components: {
|
2018-02-27 06:54:21 +01:00
|
|
|
ComposeAuthor,
|
2018-02-27 06:50:03 +01:00
|
|
|
ComposeToolbar,
|
|
|
|
ComposeLengthGauge,
|
2018-02-27 07:22:56 +01:00
|
|
|
ComposeLengthIndicator,
|
|
|
|
ComposeInput,
|
2018-12-02 20:22:18 +01:00
|
|
|
ComposeStickyButton,
|
2018-03-04 00:44:43 +01:00
|
|
|
ComposeMedia,
|
2018-12-15 11:06:12 +01:00
|
|
|
ComposeContentWarning,
|
2019-05-06 17:34:03 +02:00
|
|
|
ComposeFileDrop,
|
2019-05-27 09:24:47 +02:00
|
|
|
ComposeAutosuggest,
|
2019-09-15 19:45:46 +02:00
|
|
|
ComposePoll,
|
|
|
|
ComposeMediaSensitive
|
2018-03-03 23:51:48 +01:00
|
|
|
},
|
2018-04-30 07:13:41 +02:00
|
|
|
data: () => ({
|
2019-08-20 04:08:59 +02:00
|
|
|
size: undefined,
|
2018-04-30 07:13:41 +02:00
|
|
|
isReply: false,
|
|
|
|
autoFocus: false,
|
2018-05-01 04:06:08 +02:00
|
|
|
hideBottomBorder: false,
|
2019-04-20 18:12:30 +02:00
|
|
|
hidden: false,
|
2019-09-15 19:45:52 +02:00
|
|
|
dialogId: undefined,
|
|
|
|
aboutToPostStatus: false
|
2018-04-30 07:13:41 +02:00
|
|
|
}),
|
2018-03-03 23:51:48 +01:00
|
|
|
store: () => store,
|
|
|
|
computed: {
|
2018-05-02 02:05:36 +02:00
|
|
|
computedClassName: ({ overLimit, realm, size, postPrivacyKey, isReply }) => (classname(
|
2018-04-20 19:36:05 +02:00
|
|
|
'compose-box',
|
2019-02-14 17:46:43 +01:00
|
|
|
`compose-box-realm-${realm}`,
|
2018-04-20 19:36:05 +02:00
|
|
|
overLimit && 'over-char-limit',
|
|
|
|
isReply && postPrivacyKey === 'direct' && 'direct-reply'
|
|
|
|
)),
|
2018-05-02 02:05:36 +02:00
|
|
|
hideAndFadeIn: ({ hidden }) => (classname(
|
2018-04-20 19:36:05 +02:00
|
|
|
'compose-box-fade-in',
|
|
|
|
hidden && 'hidden'
|
|
|
|
)),
|
2018-12-02 20:22:18 +01:00
|
|
|
showSticky: ({ realm }) => realm === 'home',
|
2018-05-02 02:05:36 +02:00
|
|
|
composeData: ({ $currentComposeData, realm }) => $currentComposeData[realm] || {},
|
|
|
|
text: ({ composeData }) => composeData.text || '',
|
|
|
|
media: ({ composeData }) => composeData.media || [],
|
2019-05-27 09:24:47 +02:00
|
|
|
poll: ({ composeData }) => composeData.poll,
|
2018-12-13 08:45:52 +01:00
|
|
|
inReplyToId: ({ composeData }) => composeData.inReplyToId,
|
2018-05-02 02:05:36 +02:00
|
|
|
postPrivacy: ({ postPrivacyKey }) => POST_PRIVACY_OPTIONS.find(_ => _.key === postPrivacyKey),
|
2019-03-21 04:19:18 +01:00
|
|
|
defaultPostPrivacyKey: ({ $currentVerifyCredentials }) => (
|
|
|
|
($currentVerifyCredentials && $currentVerifyCredentials.source.privacy) || 'public'
|
|
|
|
),
|
2018-05-02 02:05:36 +02:00
|
|
|
postPrivacyKey: ({ composeData, defaultPostPrivacyKey }) => composeData.postPrivacy || defaultPostPrivacyKey,
|
|
|
|
textLength: ({ text }) => measureText(text),
|
|
|
|
contentWarningLength: ({ contentWarning }) => measureText(contentWarning),
|
|
|
|
length: ({ textLength, contentWarningLength, contentWarningShown }) => (
|
2018-04-20 19:36:05 +02:00
|
|
|
textLength + (contentWarningShown ? contentWarningLength : 0)
|
|
|
|
),
|
2018-08-26 21:14:16 +02:00
|
|
|
overLimit: ({ length, $maxStatusChars }) => length > $maxStatusChars,
|
2018-05-02 02:05:36 +02:00
|
|
|
contentWarningShown: ({ composeData }) => composeData.contentWarningShown,
|
2019-09-15 19:45:46 +02:00
|
|
|
contentWarning: ({ composeData }) => composeData.contentWarning || '',
|
|
|
|
sensitive: ({ composeData }) => !!composeData.sensitive
|
2018-03-04 01:25:22 +01:00
|
|
|
},
|
|
|
|
transitions: {
|
|
|
|
slide
|
2018-03-05 01:27:15 +01:00
|
|
|
},
|
|
|
|
methods: {
|
2019-09-15 19:45:52 +02:00
|
|
|
async doPostStatus () {
|
|
|
|
const { aboutToPostStatus } = this.get()
|
|
|
|
const { postingStatus } = this.store.get()
|
|
|
|
if (aboutToPostStatus || postingStatus) { // do nothing if the user rapidly taps the Ctrl-Enter key
|
|
|
|
console.log('ignored post command', { aboutToPostStatus, postingStatus })
|
|
|
|
return
|
|
|
|
}
|
2019-08-20 06:37:11 +02:00
|
|
|
// The reason we add a scheduleIdleTask delay here is because we also use scheduleIdleTask
|
|
|
|
// in ComposeInput.html to debounce the input events. If the user is very fast at typing
|
|
|
|
// at their keyboard and quickly presses Ctrl+Enter or the "Toot" button then there could
|
|
|
|
// be a race condition where not all of their status is posted.
|
2019-09-15 19:45:52 +02:00
|
|
|
this.set({ aboutToPostStatus: true })
|
|
|
|
scheduleIdleTask(() => {
|
|
|
|
this.set({ aboutToPostStatus: false })
|
|
|
|
this.doPostStatusAfterDelay()
|
|
|
|
})
|
2019-08-20 06:37:11 +02:00
|
|
|
},
|
|
|
|
doPostStatusAfterDelay () {
|
2019-08-03 22:49:37 +02:00
|
|
|
const {
|
2018-04-19 18:37:05 +02:00
|
|
|
text,
|
|
|
|
media,
|
|
|
|
postPrivacyKey,
|
|
|
|
contentWarning,
|
|
|
|
realm,
|
|
|
|
overLimit,
|
2018-12-13 08:45:52 +01:00
|
|
|
inReplyToUuid, // typical replies, using Pinafore-specific uuid
|
2019-05-27 09:24:47 +02:00
|
|
|
inReplyToId, // delete-and-redraft replies, using standard id
|
2019-09-15 19:45:46 +02:00
|
|
|
poll,
|
|
|
|
sensitive
|
2018-04-19 18:37:05 +02:00
|
|
|
} = this.get()
|
2019-08-03 22:49:37 +02:00
|
|
|
const mediaIds = media.map(_ => _.data.id)
|
|
|
|
const mediaDescriptions = media.map(_ => _.description)
|
|
|
|
const mediaFocalPoints = media.map(_ => [_.focusX, _.focusY])
|
|
|
|
const inReplyTo = inReplyToId || ((realm === 'home' || realm === 'dialog') ? null : realm)
|
2018-03-08 03:04:20 +01:00
|
|
|
|
2018-08-27 03:54:59 +02:00
|
|
|
if (overLimit || (!text && !media.length)) {
|
2018-04-12 05:01:17 +02:00
|
|
|
return // do nothing if invalid
|
2018-03-27 09:02:55 +02:00
|
|
|
}
|
2018-04-12 05:01:17 +02:00
|
|
|
|
2019-08-03 22:49:37 +02:00
|
|
|
const hasPoll = poll && poll.options && poll.options.length
|
2019-05-27 09:24:47 +02:00
|
|
|
if (hasPoll) {
|
|
|
|
// validate poll
|
|
|
|
if (poll.options.length < 2 || !poll.options.every(Boolean)) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// convert internal poll format to the format Mastodon's REST API uses
|
2019-08-03 22:49:37 +02:00
|
|
|
const pollToPost = hasPoll && {
|
2019-05-27 09:24:47 +02:00
|
|
|
expires_in: (poll.expiry || POLL_EXPIRY_DEFAULT).toString(),
|
|
|
|
multiple: !!poll.multiple,
|
|
|
|
options: poll.options
|
|
|
|
}
|
|
|
|
|
2019-09-15 19:45:52 +02:00
|
|
|
/* no await */ postStatus(realm, text, inReplyTo, mediaIds,
|
2018-04-13 06:18:14 +02:00
|
|
|
sensitive, contentWarning, postPrivacyKey,
|
2019-07-07 09:14:19 +02:00
|
|
|
mediaDescriptions, inReplyToUuid, pollToPost,
|
|
|
|
mediaFocalPoints)
|
2018-03-05 01:27:15 +01:00
|
|
|
}
|
2018-02-26 01:26:43 +01:00
|
|
|
}
|
|
|
|
}
|
2018-02-26 09:24:28 +01:00
|
|
|
</script>
|