flatten Status.html for perf
This commit is contained in:
parent
73b53c2afd
commit
8581ae0003
|
@ -10,34 +10,134 @@
|
||||||
<StatusHeader :notification :notificationId :status :statusId :timelineType
|
<StatusHeader :notification :notificationId :status :statusId :timelineType
|
||||||
:account :accountId :uuid :isStatusInNotification />
|
:account :accountId :uuid :isStatusInNotification />
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<StatusAuthorName :isStatusInNotification :isStatusInOwnThread :originalAccountId
|
<!-- StatusAuthorName -->
|
||||||
:originalAccount :uuid />
|
<a class="status-author-name {{isStatusInNotification ? 'status-in-notification' : '' }} {{isStatusInOwnThread ? 'status-in-own-thread' : ''}}"
|
||||||
<StatusAuthorHandle :isStatusInNotification :originalAccount />
|
href="/accounts/{{originalAccountId}}"
|
||||||
|
focus-key="{{authorNameKey}}">
|
||||||
|
{{originalAccount.display_name || originalAccount.username}}
|
||||||
|
</a>
|
||||||
|
<!-- StatusAuthorName -->
|
||||||
|
<!-- StatusAuthorHandle -->
|
||||||
|
<span class="status-author-handle {{isStatusInNotification ? 'status-in-notification' : '' }}">
|
||||||
|
{{'@' + originalAccount.acct}}
|
||||||
|
</span>
|
||||||
|
<!-- StatusAuthorHandle -->
|
||||||
{{#if !isStatusInOwnThread}}
|
{{#if !isStatusInOwnThread}}
|
||||||
<StatusRelativeDate :isStatusInNotification :originalStatus :originalStatusId :uuid />
|
<!-- StatusRelativeDate -->
|
||||||
|
<a class="status-relative-date {{isStatusInNotification ? 'status-in-notification' : '' }}"
|
||||||
|
href="/statuses/{{originalStatusId}}"
|
||||||
|
focus-key="{{relativeDateKey}}">
|
||||||
|
<time datetime={{createdAtDate}} title="{{relativeDate}}"
|
||||||
|
aria-label="{{relativeDate}} – click to show thread">
|
||||||
|
{{relativeDate}}
|
||||||
|
</time>
|
||||||
|
</a>
|
||||||
|
<!-- StatusRelativeDate -->
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<StatusSidebar :isStatusInOwnThread :originalAccount />
|
<!-- StatusSidebar -->
|
||||||
|
<Avatar account={{originalAccount}}
|
||||||
|
className="status-sidebar"
|
||||||
|
size="{{isStatusInOwnThread ? 'medium' : 'small'}}" />
|
||||||
|
<!-- StatusSidebar -->
|
||||||
{{#if originalStatus.spoiler_text}}
|
{{#if originalStatus.spoiler_text}}
|
||||||
<StatusSpoiler :isStatusInOwnThread :isStatusInNotification
|
<!-- StatusSpoiler -->
|
||||||
:originalStatus :uuid
|
<div class="status-spoiler {{isStatusInNotification ? 'status-in-notification' : ''}} {{isStatusInOwnThread ? 'status-in-own-thread' : ''}}">
|
||||||
on:recalculateHeight />
|
<p>{{originalStatus.spoiler_text}}</p>
|
||||||
|
</div>
|
||||||
|
<div class="status-spoiler-button {{isStatusInOwnThread ? 'status-in-own-thread' : ''}}">
|
||||||
|
<button type="button" delegate-key="{{spoilerKey}}">
|
||||||
|
{{spoilerShown ? 'Show less' : 'Show more'}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- StatusSpoiler -->
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if !originalStatus.spoiler_text || spoilerShown}}
|
{{#if !originalStatus.spoiler_text || spoilerShown}}
|
||||||
<StatusContent :isStatusInOwnThread :isStatusInNotification
|
<!-- StatusContent -->
|
||||||
:originalStatus :uuid />
|
<div class="status-content {{isStatusInOwnThread ? 'status-in-own-thread' : ''}} {{isStatusInNotification ? 'status-in-notification' : ''}}"
|
||||||
|
ref:contentNode>
|
||||||
|
{{{massagedContent}}}
|
||||||
|
</div>
|
||||||
|
<!-- StatusContent -->
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if originalStatus.media_attachments && originalStatus.media_attachments.length}}
|
{{#if originalStatus.media_attachments && originalStatus.media_attachments.length}}
|
||||||
<StatusMediaAttachments :originalStatus :uuid
|
<!-- StatusMediaAttachments -->
|
||||||
on:recalculateHeight />
|
{{#if sensitive }}
|
||||||
|
<div class="status-sensitive-media-container {{sensitiveShown ? 'status-sensitive-media-shown' : 'status-sensitive-media-hidden'}}">
|
||||||
|
{{#if sensitiveShown}}
|
||||||
|
<button type="button"
|
||||||
|
class="status-sensitive-media-button"
|
||||||
|
aria-label="Hide sensitive media"
|
||||||
|
delegate-key="{{mediaAttachmentsKey}}" >
|
||||||
|
<div class="svg-wrapper">
|
||||||
|
<svg>
|
||||||
|
<use xlink:href="#fa-eye-slash" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
<MediaAttachments :mediaAttachments :sensitive />
|
||||||
|
{{else}}
|
||||||
|
<button type="button"
|
||||||
|
class="status-sensitive-media-button"
|
||||||
|
aria-label="Show sensitive media"
|
||||||
|
delegate-key="{{mediaAttachmentsKey}}" >
|
||||||
|
|
||||||
|
<div class="status-sensitive-media-warning">
|
||||||
|
<span>Sensitive content. Click to show.</span>
|
||||||
|
</div>
|
||||||
|
<div class="svg-wrapper">
|
||||||
|
<svg>
|
||||||
|
<use xlink:href="#fa-eye" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<MediaAttachments :mediaAttachments :sensitive />
|
||||||
|
{{/if}}
|
||||||
|
<!-- StatusMediaAttachments -->
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if isStatusInOwnThread}}
|
{{#if isStatusInOwnThread}}
|
||||||
<StatusDetails :originalStatus :originalStatusId />
|
<StatusDetails :originalStatus :originalStatusId />
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<StatusToolbar :originalStatus :originalStatusId :originalAccountId
|
<!-- StatusToolbar -->
|
||||||
:isStatusInOwnThread :uuid />
|
<div class="status-toolbar {{isStatusInOwnThread ? 'status-in-own-thread' : ''}}">
|
||||||
|
<IconButton
|
||||||
|
label="Reply"
|
||||||
|
href="#fa-reply"
|
||||||
|
disabled="{{disableReply}}"
|
||||||
|
delegateKey="{{replyKey}}"
|
||||||
|
/>
|
||||||
|
<IconButton
|
||||||
|
label="{{reblogLabel}}"
|
||||||
|
pressable="{{!reblogDisabled}}"
|
||||||
|
pressed="{{reblogged}}"
|
||||||
|
disabled="{{reblogDisabled}}"
|
||||||
|
href="{{reblogIcon}}"
|
||||||
|
delegateKey="{{reblogKey}}"
|
||||||
|
/>
|
||||||
|
<IconButton
|
||||||
|
label="Favorite"
|
||||||
|
pressable="true"
|
||||||
|
pressed="{{favorited}}"
|
||||||
|
href="#fa-star"
|
||||||
|
delegateKey="{{favoriteKey}}"
|
||||||
|
/>
|
||||||
|
<IconButton
|
||||||
|
label="Show more options"
|
||||||
|
href="#fa-ellipsis-h"
|
||||||
|
delegateKey="{{optionsKey}}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<!-- StatusToolbar -->
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Status
|
||||||
|
*/
|
||||||
|
|
||||||
.status-article {
|
.status-article {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
max-width: calc(100vw - 40px);
|
max-width: calc(100vw - 40px);
|
||||||
|
@ -85,48 +185,340 @@
|
||||||
width: 580px;
|
width: 580px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* StatusAuthorName
|
||||||
|
*/
|
||||||
|
|
||||||
|
.status-author-name {
|
||||||
|
grid-area: author-name;
|
||||||
|
align-self: center;
|
||||||
|
margin-left: 5px;
|
||||||
|
font-size: 1.1em;
|
||||||
|
min-width: 0;
|
||||||
|
font-weight: 600;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-author-name.status-in-own-thread {
|
||||||
|
font-size: 1.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-author-name, .status-author-name:hover, .status-author-name:visited {
|
||||||
|
color: var(--body-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-author-name.status-in-notification,
|
||||||
|
.status-author-name.status-in-notification:hover,
|
||||||
|
.status-author-name.status-in-notification:visited {
|
||||||
|
color: var(--very-deemphasized-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* StatusAuthorHandle
|
||||||
|
*/
|
||||||
|
|
||||||
|
.status-author-handle {
|
||||||
|
grid-area: author-handle;
|
||||||
|
align-self: center;
|
||||||
|
margin-left: 5px;
|
||||||
|
color: var(--deemphasized-text-color);
|
||||||
|
font-size: 1.1em;
|
||||||
|
min-width: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-author-handle.status-in-notification {
|
||||||
|
color: var(--very-deemphasized-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* StatusRelativeDate
|
||||||
|
*/
|
||||||
|
|
||||||
|
.status-relative-date {
|
||||||
|
grid-area: relative-date;
|
||||||
|
align-self: center;
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-right: 10px;
|
||||||
|
font-size: 1.1em;
|
||||||
|
text-align: right;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.status-relative-date, .status-relative-date:hover, .status-relative-date:visited {
|
||||||
|
color: var(--deemphasized-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-relative-date.status-in-notification,
|
||||||
|
.status-relative-date.status-in-notification:hover,
|
||||||
|
.status-relative-date.status-in-notification:visited {
|
||||||
|
color: var(--very-deemphasized-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* StatusSidebar
|
||||||
|
*/
|
||||||
|
|
||||||
|
:global(.status-sidebar) {
|
||||||
|
grid-area: sidebar;
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
:global(.status-sidebar) {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* StatusSpoiler
|
||||||
|
*/
|
||||||
|
|
||||||
|
.status-spoiler {
|
||||||
|
grid-area: spoiler;
|
||||||
|
word-wrap: break-word;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
font-size: 0.9em;
|
||||||
|
margin: 10px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-spoiler.status-in-own-thread {
|
||||||
|
font-size: 1.3em;
|
||||||
|
margin: 20px 5px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-spoiler.status-in-notification {
|
||||||
|
color: var(--very-deemphasized-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-spoiler-button {
|
||||||
|
grid-area: spoiler-btn;
|
||||||
|
margin: 10px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-spoiler-button.status-in-own-thread {
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-spoiler-button button {
|
||||||
|
padding: 5px 10px;
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* StatusContent
|
||||||
|
*/
|
||||||
|
|
||||||
|
.status-content {
|
||||||
|
margin: 10px 10px 10px 5px;
|
||||||
|
grid-area: content;
|
||||||
|
word-wrap: break-word;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-content.status-in-own-thread {
|
||||||
|
font-size: 1.3em;
|
||||||
|
margin: 20px 10px 20px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.status-content .status-emoji) {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
margin: -3px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.status-content p) {
|
||||||
|
margin: 0 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.status-content p:first-child) {
|
||||||
|
margin: 0 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.status-content p:last-child) {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-content.status-in-notification {
|
||||||
|
color: var(--very-deemphasized-text-color);
|
||||||
|
}
|
||||||
|
:global(.status-content.status-in-notification a, .status-content.status-in-notification a:hover) {
|
||||||
|
color: var(--very-deemphasized-link-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.status-content .invisible) {
|
||||||
|
/* copied from Mastodon */
|
||||||
|
font-size: 0;
|
||||||
|
line-height: 0;
|
||||||
|
display: inline-block;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* StatusMediaAttachments
|
||||||
|
*/
|
||||||
|
|
||||||
|
.status-sensitive-media-container {
|
||||||
|
grid-area: media;
|
||||||
|
margin: 10px 0;
|
||||||
|
position: relative;
|
||||||
|
border-radius: 0;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-sensitive-media-button {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-sensitive-media-button:hover {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-sensitive-media-button:active {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-sensitive-media-shown .status-sensitive-media-button {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
z-index: 90;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-sensitive-media-hidden .status-sensitive-media-button {
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-sensitive-media-container.status-sensitive-media-hidden {
|
||||||
|
width: 100%;
|
||||||
|
margin: 10px auto;
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-sensitive-media-container .status-sensitive-media-warning {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: var(--deemphasized-text-color);
|
||||||
|
z-index: 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-sensitive-media-container .svg-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: flex-start;
|
||||||
|
z-index: 40;
|
||||||
|
pointer-events: none;
|
||||||
|
background: var(--mask-bg);
|
||||||
|
}
|
||||||
|
.status-sensitive-media-hidden .svg-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
.status-sensitive-media-container.status-sensitive-media-shown .svg-wrapper {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
.status-sensitive-media-container svg {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
fill: var(--mask-svg-fill);
|
||||||
|
border-radius: 2px;
|
||||||
|
background: var(--mask-opaque-bg);
|
||||||
|
margin: 1px;
|
||||||
|
padding: 6px 10px;
|
||||||
|
}
|
||||||
|
.status-sensitive-media-container.status-sensitive-media-hidden svg {
|
||||||
|
fill: var(--deemphasized-text-color);
|
||||||
|
background: var(--mask-opaque-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* StatusToolbar
|
||||||
|
*/
|
||||||
|
|
||||||
|
.status-toolbar {
|
||||||
|
grid-area: toolbar;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.status-toolbar.status-in-own-thread {
|
||||||
|
margin-left: 58px;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
import StatusSidebar from './StatusSidebar.html'
|
|
||||||
import StatusHeader from './StatusHeader.html'
|
import StatusHeader from './StatusHeader.html'
|
||||||
import StatusAuthorName from './StatusAuthorName.html'
|
|
||||||
import StatusAuthorHandle from './StatusAuthorHandle.html'
|
|
||||||
import StatusRelativeDate from './StatusRelativeDate.html'
|
|
||||||
import StatusDetails from './StatusDetails.html'
|
import StatusDetails from './StatusDetails.html'
|
||||||
import StatusToolbar from './StatusToolbar.html'
|
import MediaAttachments from './MediaAttachments.html'
|
||||||
import StatusMediaAttachments from './StatusMediaAttachments.html'
|
import Avatar from '../Avatar.html'
|
||||||
import StatusContent from './StatusContent.html'
|
|
||||||
import StatusSpoiler from './StatusSpoiler.html'
|
|
||||||
import { store } from '../../_store/store'
|
import { store } from '../../_store/store'
|
||||||
import { goto } from 'sapper/runtime.js'
|
import { goto } from 'sapper/runtime.js'
|
||||||
import { registerClickDelegate, unregisterClickDelegate } from '../../_utils/delegate'
|
import { registerClickDelegate, unregisterClickDelegate } from '../../_utils/delegate'
|
||||||
import { classname } from '../../_utils/classname'
|
import { classname } from '../../_utils/classname'
|
||||||
|
import { mark, stop } from '../../_utils/marks'
|
||||||
|
import { replaceAll } from '../../_utils/strings'
|
||||||
|
import IconButton from '../IconButton.html'
|
||||||
|
import { setFavorited } from '../../_actions/favorite'
|
||||||
|
import { setReblogged } from '../../_actions/reblog'
|
||||||
|
import { importDialogs } from '../../_utils/asyncModules'
|
||||||
|
import { updateProfileAndRelationship } from '../../_actions/accounts'
|
||||||
|
import timeago from 'timeago.js'
|
||||||
|
const timeagoInstance = timeago()
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
oncreate() {
|
oncreate() {
|
||||||
let delegateKey = this.get('delegateKey')
|
|
||||||
if (!this.get('isStatusInOwnThread')) {
|
if (!this.get('isStatusInOwnThread')) {
|
||||||
// the whole <article> is clickable in this case
|
// the whole <article> is clickable in this case
|
||||||
registerClickDelegate(delegateKey, (e) => this.onClickOrKeydown(e))
|
registerClickDelegate(this.get('delegateKey'), (e) => this.onClickOrKeydown(e))
|
||||||
}
|
}
|
||||||
|
registerClickDelegate(this.get('spoilerKey'), () => this.onClickSpoilerButton())
|
||||||
|
registerClickDelegate(this.get('mediaAttachmentsKey'), () => this.onClickSensitiveMediaButton())
|
||||||
|
registerClickDelegate(this.get('favoriteKey'), () => this.onFavoriteClick())
|
||||||
|
registerClickDelegate(this.get('reblogKey'), () => this.onReblogClick())
|
||||||
|
registerClickDelegate(this.get('replyKey'), () => this.onReplyClick())
|
||||||
|
registerClickDelegate(this.get('optionsKey'), () => this.onOptionsClick())
|
||||||
|
this.hydrateContent()
|
||||||
},
|
},
|
||||||
ondestroy() {
|
ondestroy() {
|
||||||
let delegateKey = this.get('delegateKey')
|
|
||||||
if (!this.get('isStatusInOwnThread')) {
|
if (!this.get('isStatusInOwnThread')) {
|
||||||
unregisterClickDelegate(delegateKey)
|
unregisterClickDelegate(this.get('delegateKey'))
|
||||||
}
|
}
|
||||||
|
unregisterClickDelegate(this.get('spoilerKey'))
|
||||||
|
unregisterClickDelegate(this.get('mediaAttachmentsKey'))
|
||||||
|
unregisterClickDelegate(this.get('favoriteKey'))
|
||||||
|
unregisterClickDelegate(this.get('reblogKey'))
|
||||||
|
unregisterClickDelegate(this.get('replyKey'))
|
||||||
|
unregisterClickDelegate(this.get('optionsKey'))
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
StatusSidebar,
|
|
||||||
StatusHeader,
|
StatusHeader,
|
||||||
StatusAuthorName,
|
|
||||||
StatusAuthorHandle,
|
|
||||||
StatusRelativeDate,
|
|
||||||
StatusDetails,
|
StatusDetails,
|
||||||
StatusToolbar,
|
MediaAttachments,
|
||||||
StatusMediaAttachments,
|
Avatar,
|
||||||
StatusContent,
|
IconButton
|
||||||
StatusSpoiler
|
|
||||||
},
|
},
|
||||||
store: () => store,
|
store: () => store,
|
||||||
helpers: {
|
helpers: {
|
||||||
|
@ -154,6 +546,83 @@
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
goto(`/statuses/${this.get('originalStatusId')}`)
|
goto(`/statuses/${this.get('originalStatusId')}`)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
onClickSpoilerButton() {
|
||||||
|
let uuid = this.get('uuid')
|
||||||
|
let $spoilersShown = this.store.get('spoilersShown')
|
||||||
|
$spoilersShown[uuid] = !$spoilersShown[uuid]
|
||||||
|
this.store.set({'spoilersShown': $spoilersShown})
|
||||||
|
this.fire('recalculateHeight')
|
||||||
|
},
|
||||||
|
hydrateContent() {
|
||||||
|
if (!this.refs.contentNode) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let contentNode = this.refs.contentNode
|
||||||
|
let originalStatus = this.get('originalStatus')
|
||||||
|
let uuid = this.get('uuid')
|
||||||
|
let count = 0
|
||||||
|
mark('hydrateContent')
|
||||||
|
if (originalStatus.tags && originalStatus.tags.length) {
|
||||||
|
let anchorTags = contentNode.querySelectorAll('a[class~=hashtag][href^=http]')
|
||||||
|
for (let tag of originalStatus.tags) {
|
||||||
|
for (let anchorTag of anchorTags) {
|
||||||
|
if (anchorTag.getAttribute('href').endsWith(`/tags/${tag.name}`)) {
|
||||||
|
anchorTag.setAttribute('href', `/tags/${tag.name}`)
|
||||||
|
anchorTag.setAttribute('focus-key', `status-content-link-${uuid}-${++count}`)
|
||||||
|
anchorTag.removeAttribute('target')
|
||||||
|
anchorTag.removeAttribute('rel')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (originalStatus.mentions && originalStatus.mentions.length) {
|
||||||
|
let anchorTags = contentNode.querySelectorAll('a[class~=mention][href^=http]')
|
||||||
|
for (let mention of originalStatus.mentions) {
|
||||||
|
for (let anchorTag of anchorTags) {
|
||||||
|
if (anchorTag.getAttribute('href') === mention.url) {
|
||||||
|
anchorTag.setAttribute('href', `/accounts/${mention.id}`)
|
||||||
|
anchorTag.setAttribute('focus-key', `status-content-link-${uuid}-${++count}`)
|
||||||
|
anchorTag.removeAttribute('target')
|
||||||
|
anchorTag.removeAttribute('rel')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let externalLinks = contentNode.querySelectorAll('a[rel="nofollow noopener"]')
|
||||||
|
for (let link of externalLinks) {
|
||||||
|
link.setAttribute('title', link.getAttribute('href'))
|
||||||
|
}
|
||||||
|
stop('hydrateContent')
|
||||||
|
},
|
||||||
|
onClickSensitiveMediaButton() {
|
||||||
|
let uuid = this.get('uuid')
|
||||||
|
let $sensitivesShown = this.store.get('sensitivesShown') || {}
|
||||||
|
$sensitivesShown[uuid] = !$sensitivesShown[uuid]
|
||||||
|
this.store.set({'sensitivesShown': $sensitivesShown})
|
||||||
|
this.fire('recalculateHeight')
|
||||||
|
},
|
||||||
|
onFavoriteClick() {
|
||||||
|
let originalStatusId = this.get('originalStatusId')
|
||||||
|
let favorited = this.get('favorited')
|
||||||
|
/* no await */ setFavorited(originalStatusId, !favorited)
|
||||||
|
},
|
||||||
|
onReblogClick() {
|
||||||
|
let originalStatusId = this.get('originalStatusId')
|
||||||
|
let reblogged = this.get('reblogged')
|
||||||
|
/* no await */ setReblogged(originalStatusId, !reblogged)
|
||||||
|
},
|
||||||
|
onReplyClick() {
|
||||||
|
let originalStatusId = this.get('originalStatusId')
|
||||||
|
goto(`/statuses/${originalStatusId}/reply`)
|
||||||
|
},
|
||||||
|
async onOptionsClick() {
|
||||||
|
let originalStatusId = this.get('originalStatusId')
|
||||||
|
let originalAccountId = this.get('originalAccountId')
|
||||||
|
let updateRelationshipPromise = updateProfileAndRelationship(originalAccountId)
|
||||||
|
let dialogs = await importDialogs()
|
||||||
|
await updateRelationshipPromise
|
||||||
|
dialogs.showStatusOptionsDialog(originalStatusId)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -187,7 +656,86 @@
|
||||||
return (notification && (notification.type === 'reblog' || notification.type === 'favourite'))
|
return (notification && (notification.type === 'reblog' || notification.type === 'favourite'))
|
||||||
|| status.reblog
|
|| status.reblog
|
||||||
|| timelineType === 'pinned'
|
|| timelineType === 'pinned'
|
||||||
}
|
},
|
||||||
|
authorNameKey: (uuid) => `status-author-name-${uuid}`,
|
||||||
|
createdAtDate: (originalStatus) => originalStatus.created_at,
|
||||||
|
relativeDate: (createdAtDate, isStatusInOwnThread) => {
|
||||||
|
if (isStatusInOwnThread) {
|
||||||
|
return '' // avoid expensive computation when not needed
|
||||||
|
}
|
||||||
|
mark('compute relativeDate')
|
||||||
|
let res = timeagoInstance.format(createdAtDate)
|
||||||
|
stop('compute relativeDate')
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
relativeDateKey: (uuid) => `status-relative-date-${uuid}`,
|
||||||
|
spoilerKey: (uuid) => `spoiler-${uuid}`,
|
||||||
|
massagedContent: (originalStatus, $autoplayGifs) => {
|
||||||
|
let content = originalStatus.content
|
||||||
|
// emojify
|
||||||
|
if (originalStatus.emojis && originalStatus.emojis.length) {
|
||||||
|
for (let emoji of originalStatus.emojis) {
|
||||||
|
let { shortcode, url, static_url } = emoji
|
||||||
|
let urlToUse = $autoplayGifs ? url : static_url
|
||||||
|
let shortcodeWithColons = `:${shortcode}:`
|
||||||
|
content = replaceAll(
|
||||||
|
content,
|
||||||
|
shortcodeWithColons,
|
||||||
|
`<img class="status-emoji" draggable="false" src="${urlToUse}"
|
||||||
|
alt="${shortcodeWithColons}" title="${shortcodeWithColons}" />`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// GNU Social and Pleroma don't add <p> tags
|
||||||
|
if (!content.startsWith('<p>')) {
|
||||||
|
content = `<p>${content}</p>`
|
||||||
|
}
|
||||||
|
return content
|
||||||
|
},
|
||||||
|
mediaAttachments: (originalStatus) => originalStatus.media_attachments,
|
||||||
|
sensitiveShown: ($sensitivesShown, uuid) => !!$sensitivesShown[uuid],
|
||||||
|
sensitive: (originalStatus, $markMediaAsSensitive) => originalStatus.sensitive || $markMediaAsSensitive,
|
||||||
|
mediaAttachmentsKey: (uuid) => `sensitive-${uuid}`,
|
||||||
|
visibility: (originalStatus) => originalStatus.visibility,
|
||||||
|
reblogLabel: (visibility) => {
|
||||||
|
switch (visibility) {
|
||||||
|
case 'private':
|
||||||
|
return 'Cannot be boosted because this is followers-only'
|
||||||
|
case 'direct':
|
||||||
|
return 'Cannot be boosted because this is a direct message'
|
||||||
|
default:
|
||||||
|
return 'Boost'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
reblogIcon: (visibility) => {
|
||||||
|
switch (visibility) {
|
||||||
|
case 'private':
|
||||||
|
return '#fa-lock'
|
||||||
|
case 'direct':
|
||||||
|
return '#fa-envelope'
|
||||||
|
default:
|
||||||
|
return '#fa-retweet'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
reblogDisabled: (visibility) => {
|
||||||
|
return visibility === 'private' || visibility === 'direct'
|
||||||
|
},
|
||||||
|
reblogged: (originalStatusId, $currentStatusModifications, originalStatus) => {
|
||||||
|
if ($currentStatusModifications && originalStatusId in $currentStatusModifications.reblogs) {
|
||||||
|
return $currentStatusModifications.reblogs[originalStatusId]
|
||||||
|
}
|
||||||
|
return originalStatus.reblogged
|
||||||
|
},
|
||||||
|
favorited: (originalStatusId, $currentStatusModifications, originalStatus) => {
|
||||||
|
if ($currentStatusModifications && originalStatusId in $currentStatusModifications.favorites) {
|
||||||
|
return $currentStatusModifications.favorites[originalStatusId]
|
||||||
|
}
|
||||||
|
return originalStatus.favourited
|
||||||
|
},
|
||||||
|
favoriteKey: (uuid) => `fav-${uuid}`,
|
||||||
|
reblogKey: (uuid) => `reblog-${uuid}`,
|
||||||
|
replyKey: (uuid) => `reply-${uuid}`,
|
||||||
|
optionsKey: (uuid) => `options-${uuid}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
|
@ -1,20 +0,0 @@
|
||||||
<span class="status-author-handle {{isStatusInNotification ? 'status-in-notification' : '' }}">
|
|
||||||
{{'@' + originalAccount.acct}}
|
|
||||||
</span>
|
|
||||||
<style>
|
|
||||||
.status-author-handle {
|
|
||||||
grid-area: author-handle;
|
|
||||||
align-self: center;
|
|
||||||
margin-left: 5px;
|
|
||||||
color: var(--deemphasized-text-color);
|
|
||||||
font-size: 1.1em;
|
|
||||||
min-width: 0;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-author-handle.status-in-notification {
|
|
||||||
color: var(--very-deemphasized-text-color);
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,41 +0,0 @@
|
||||||
<a class="status-author-name {{isStatusInNotification ? 'status-in-notification' : '' }} {{isStatusInOwnThread ? 'status-in-own-thread' : ''}}"
|
|
||||||
href="/accounts/{{originalAccountId}}"
|
|
||||||
focus-key="{{focusKey}}"
|
|
||||||
>
|
|
||||||
{{originalAccount.display_name || originalAccount.username}}
|
|
||||||
</a>
|
|
||||||
<style>
|
|
||||||
.status-author-name {
|
|
||||||
grid-area: author-name;
|
|
||||||
align-self: center;
|
|
||||||
margin-left: 5px;
|
|
||||||
font-size: 1.1em;
|
|
||||||
min-width: 0;
|
|
||||||
font-weight: 600;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-author-name.status-in-own-thread {
|
|
||||||
font-size: 1.3em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-author-name, .status-author-name:hover, .status-author-name:visited {
|
|
||||||
color: var(--body-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-author-name.status-in-notification,
|
|
||||||
.status-author-name.status-in-notification:hover,
|
|
||||||
.status-author-name.status-in-notification:visited {
|
|
||||||
color: var(--very-deemphasized-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
computed: {
|
|
||||||
focusKey: (uuid) => `status-author-name-${uuid}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,136 +0,0 @@
|
||||||
<div
|
|
||||||
class="status-content {{isStatusInOwnThread ? 'status-in-own-thread' : ''}} {{isStatusInNotification ? 'status-in-notification' : ''}}"
|
|
||||||
ref:node
|
|
||||||
>
|
|
||||||
{{{massagedContent}}}
|
|
||||||
</div>
|
|
||||||
<style>
|
|
||||||
.status-content {
|
|
||||||
margin: 10px 10px 10px 5px;
|
|
||||||
grid-area: content;
|
|
||||||
word-wrap: break-word;
|
|
||||||
overflow: hidden;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-content.status-in-own-thread {
|
|
||||||
font-size: 1.3em;
|
|
||||||
margin: 20px 10px 20px 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.status-content .status-emoji) {
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
margin: -3px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.status-content p) {
|
|
||||||
margin: 0 0 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.status-content p:first-child) {
|
|
||||||
margin: 0 0 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.status-content p:last-child) {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-content.status-in-notification {
|
|
||||||
color: var(--very-deemphasized-text-color);
|
|
||||||
}
|
|
||||||
:global(.status-content.status-in-notification a, .status-content.status-in-notification a:hover) {
|
|
||||||
color: var(--very-deemphasized-link-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.status-content .invisible) {
|
|
||||||
/* copied from Mastodon */
|
|
||||||
font-size: 0;
|
|
||||||
line-height: 0;
|
|
||||||
display: inline-block;
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
<script>
|
|
||||||
import { replaceAll } from '../../_utils/strings'
|
|
||||||
import { mark, stop } from '../../_utils/marks'
|
|
||||||
import { store } from '../../_store/store'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
oncreate() {
|
|
||||||
this.hydrateContent()
|
|
||||||
},
|
|
||||||
store: () => store,
|
|
||||||
computed: {
|
|
||||||
massagedContent: (originalStatus, $autoplayGifs) => {
|
|
||||||
let content = originalStatus.content
|
|
||||||
// emojify
|
|
||||||
if (originalStatus.emojis && originalStatus.emojis.length) {
|
|
||||||
for (let emoji of originalStatus.emojis) {
|
|
||||||
let { shortcode, url, static_url } = emoji
|
|
||||||
let urlToUse = $autoplayGifs ? url : static_url
|
|
||||||
let shortcodeWithColons = `:${shortcode}:`
|
|
||||||
content = replaceAll(
|
|
||||||
content,
|
|
||||||
shortcodeWithColons,
|
|
||||||
`<img class="status-emoji" draggable="false" src="${urlToUse}"
|
|
||||||
alt="${shortcodeWithColons}" title="${shortcodeWithColons}" />`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// GNU Social and Pleroma don't add <p> tags
|
|
||||||
if (!content.startsWith('<p>')) {
|
|
||||||
content = `<p>${content}</p>`
|
|
||||||
}
|
|
||||||
return content
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
hydrateContent() {
|
|
||||||
if (!this.refs.node) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let node = this.refs.node
|
|
||||||
let originalStatus = this.get('originalStatus')
|
|
||||||
let uuid = this.get('uuid')
|
|
||||||
let count = 0
|
|
||||||
mark('hydrateContent')
|
|
||||||
if (originalStatus.tags && originalStatus.tags.length) {
|
|
||||||
let anchorTags = node.querySelectorAll('a[class~=hashtag][href^=http]')
|
|
||||||
for (let tag of originalStatus.tags) {
|
|
||||||
for (let anchorTag of anchorTags) {
|
|
||||||
if (anchorTag.getAttribute('href').endsWith(`/tags/${tag.name}`)) {
|
|
||||||
anchorTag.setAttribute('href', `/tags/${tag.name}`)
|
|
||||||
anchorTag.setAttribute('focus-key', `status-content-link-${uuid}-${++count}`)
|
|
||||||
anchorTag.removeAttribute('target')
|
|
||||||
anchorTag.removeAttribute('rel')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (originalStatus.mentions && originalStatus.mentions.length) {
|
|
||||||
let anchorTags = node.querySelectorAll('a[class~=mention][href^=http]')
|
|
||||||
for (let mention of originalStatus.mentions) {
|
|
||||||
for (let anchorTag of anchorTags) {
|
|
||||||
if (anchorTag.getAttribute('href') === mention.url) {
|
|
||||||
anchorTag.setAttribute('href', `/accounts/${mention.id}`)
|
|
||||||
anchorTag.setAttribute('focus-key', `status-content-link-${uuid}-${++count}`)
|
|
||||||
anchorTag.removeAttribute('target')
|
|
||||||
anchorTag.removeAttribute('rel')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let externalLinks = node.querySelectorAll('a[rel="nofollow noopener"]')
|
|
||||||
for (let link of externalLinks) {
|
|
||||||
link.setAttribute('title', link.getAttribute('href'))
|
|
||||||
}
|
|
||||||
stop('hydrateContent')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,158 +0,0 @@
|
||||||
{{#if sensitive }}
|
|
||||||
<div class="status-sensitive-media-container {{sensitiveShown ? 'status-sensitive-media-shown' : 'status-sensitive-media-hidden'}}"
|
|
||||||
>
|
|
||||||
{{#if sensitiveShown}}
|
|
||||||
<button type="button"
|
|
||||||
class="status-sensitive-media-button"
|
|
||||||
aria-label="Hide sensitive media"
|
|
||||||
delegate-key="{{delegateKey}}" >
|
|
||||||
<div class="svg-wrapper">
|
|
||||||
<svg>
|
|
||||||
<use xlink:href="#fa-eye-slash" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
<MediaAttachments :mediaAttachments :sensitive />
|
|
||||||
{{else}}
|
|
||||||
<button type="button"
|
|
||||||
class="status-sensitive-media-button"
|
|
||||||
aria-label="Show sensitive media"
|
|
||||||
delegate-key="{{delegateKey}}" >
|
|
||||||
|
|
||||||
<div class="status-sensitive-media-warning">
|
|
||||||
<span>Sensitive content. Click to show.</span>
|
|
||||||
</div>
|
|
||||||
<div class="svg-wrapper">
|
|
||||||
<svg>
|
|
||||||
<use xlink:href="#fa-eye" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
{{else}}
|
|
||||||
<MediaAttachments :mediaAttachments :sensitive />
|
|
||||||
{{/if}}
|
|
||||||
<style>
|
|
||||||
.status-sensitive-media-container {
|
|
||||||
grid-area: media;
|
|
||||||
margin: 10px 0;
|
|
||||||
position: relative;
|
|
||||||
border-radius: 0;
|
|
||||||
border: none;
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-sensitive-media-button {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
border: none;
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-sensitive-media-button:hover {
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-sensitive-media-button:active {
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-sensitive-media-shown .status-sensitive-media-button {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
z-index: 90;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-sensitive-media-hidden .status-sensitive-media-button {
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-sensitive-media-container.status-sensitive-media-hidden {
|
|
||||||
width: 100%;
|
|
||||||
margin: 10px auto;
|
|
||||||
height: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-sensitive-media-container .status-sensitive-media-warning {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
color: var(--deemphasized-text-color);
|
|
||||||
z-index: 60;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-sensitive-media-container .svg-wrapper {
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
justify-content: flex-start;
|
|
||||||
z-index: 40;
|
|
||||||
pointer-events: none;
|
|
||||||
background: var(--mask-bg);
|
|
||||||
}
|
|
||||||
.status-sensitive-media-hidden .svg-wrapper {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
}
|
|
||||||
.status-sensitive-media-container.status-sensitive-media-shown .svg-wrapper {
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
.status-sensitive-media-container svg {
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
fill: var(--mask-svg-fill);
|
|
||||||
border-radius: 2px;
|
|
||||||
background: var(--mask-opaque-bg);
|
|
||||||
margin: 1px;
|
|
||||||
padding: 6px 10px;
|
|
||||||
}
|
|
||||||
.status-sensitive-media-container.status-sensitive-media-hidden svg {
|
|
||||||
fill: var(--deemphasized-text-color);
|
|
||||||
background: var(--mask-opaque-bg);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script>
|
|
||||||
import MediaAttachments from './MediaAttachments.html'
|
|
||||||
import { store } from '../../_store/store'
|
|
||||||
import { registerClickDelegate, unregisterClickDelegate } from '../../_utils/delegate'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
oncreate() {
|
|
||||||
registerClickDelegate(this.get('delegateKey'), () => this.onClickSensitiveMediaButton())
|
|
||||||
},
|
|
||||||
ondestroy() {
|
|
||||||
unregisterClickDelegate(this.get('delegateKey'))
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
MediaAttachments
|
|
||||||
},
|
|
||||||
store: () => store,
|
|
||||||
computed: {
|
|
||||||
mediaAttachments: (originalStatus) => originalStatus.media_attachments,
|
|
||||||
sensitiveShown: ($sensitivesShown, uuid) => !!$sensitivesShown[uuid],
|
|
||||||
sensitive: (originalStatus, $markMediaAsSensitive) => originalStatus.sensitive || $markMediaAsSensitive,
|
|
||||||
delegateKey: (uuid) => `sensitive-${uuid}`,
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
onClickSensitiveMediaButton() {
|
|
||||||
let uuid = this.get('uuid')
|
|
||||||
let $sensitivesShown = this.store.get('sensitivesShown') || {}
|
|
||||||
$sensitivesShown[uuid] = !$sensitivesShown[uuid]
|
|
||||||
this.store.set({'sensitivesShown': $sensitivesShown})
|
|
||||||
this.fire('recalculateHeight')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,48 +0,0 @@
|
||||||
<a class="status-relative-date {{isStatusInNotification ? 'status-in-notification' : '' }}"
|
|
||||||
href="/statuses/{{originalStatusId}}"
|
|
||||||
focus-key="{{focusKey}}"
|
|
||||||
>
|
|
||||||
<time datetime={{createdAtDate}} title="{{relativeDate}}"
|
|
||||||
aria-label="{{relativeDate}} – click to show thread">
|
|
||||||
{{relativeDate}}
|
|
||||||
</time>
|
|
||||||
</a>
|
|
||||||
<style>
|
|
||||||
.status-relative-date {
|
|
||||||
grid-area: relative-date;
|
|
||||||
align-self: center;
|
|
||||||
margin-left: 5px;
|
|
||||||
margin-right: 10px;
|
|
||||||
font-size: 1.1em;
|
|
||||||
text-align: right;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.status-relative-date, .status-relative-date:hover, .status-relative-date:visited {
|
|
||||||
color: var(--deemphasized-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-relative-date.status-in-notification,
|
|
||||||
.status-relative-date.status-in-notification:hover,
|
|
||||||
.status-relative-date.status-in-notification:visited {
|
|
||||||
color: var(--very-deemphasized-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
<script>
|
|
||||||
import { mark, stop } from '../../_utils/marks'
|
|
||||||
import timeago from 'timeago.js'
|
|
||||||
const timeagoInstance = timeago()
|
|
||||||
|
|
||||||
export default {
|
|
||||||
computed: {
|
|
||||||
createdAtDate: (originalStatus) => originalStatus.created_at,
|
|
||||||
relativeDate: (createdAtDate) => {
|
|
||||||
mark('compute relativeDate')
|
|
||||||
let res = timeagoInstance.format(createdAtDate)
|
|
||||||
stop('compute relativeDate')
|
|
||||||
return res
|
|
||||||
},
|
|
||||||
focusKey: (uuid) => `status-relative-date-${uuid}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,23 +0,0 @@
|
||||||
<Avatar account={{originalAccount}}
|
|
||||||
className="status-sidebar"
|
|
||||||
size="{{isStatusInOwnThread ? 'medium' : 'small'}}" />
|
|
||||||
<style>
|
|
||||||
:global(.status-sidebar) {
|
|
||||||
grid-area: sidebar;
|
|
||||||
margin-right: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
|
||||||
:global(.status-sidebar) {
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script>
|
|
||||||
import Avatar from '../Avatar.html'
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
Avatar
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,67 +0,0 @@
|
||||||
<div class="status-spoiler {{isStatusInNotification ? 'status-in-notification' : ''}} {{isStatusInOwnThread ? 'status-in-own-thread' : ''}}">
|
|
||||||
<p>{{originalStatus.spoiler_text}}</p>
|
|
||||||
</div>
|
|
||||||
<div class="status-spoiler-button {{isStatusInOwnThread ? 'status-in-own-thread' : ''}}">
|
|
||||||
<button type="button" delegate-key="{{delegateKey}}">
|
|
||||||
{{spoilerShown ? 'Show less' : 'Show more'}}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<style>
|
|
||||||
.status-spoiler {
|
|
||||||
grid-area: spoiler;
|
|
||||||
word-wrap: break-word;
|
|
||||||
overflow: hidden;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
font-size: 0.9em;
|
|
||||||
margin: 10px 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-spoiler.status-in-own-thread {
|
|
||||||
font-size: 1.3em;
|
|
||||||
margin: 20px 5px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-spoiler.status-in-notification {
|
|
||||||
color: var(--very-deemphasized-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-spoiler-button {
|
|
||||||
grid-area: spoiler-btn;
|
|
||||||
margin: 10px 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-spoiler-button.status-in-own-thread {
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-spoiler-button button {
|
|
||||||
padding: 5px 10px;
|
|
||||||
font-size: 1.1em;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script>
|
|
||||||
import { store } from '../../_store/store'
|
|
||||||
import { registerClickDelegate, unregisterClickDelegate } from '../../_utils/delegate'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
oncreate() {
|
|
||||||
registerClickDelegate(this.get('delegateKey'), () => this.onClickSpoilerButton())
|
|
||||||
},
|
|
||||||
ondestroy() {
|
|
||||||
unregisterClickDelegate(this.get('delegateKey'))
|
|
||||||
},
|
|
||||||
store: () => store,
|
|
||||||
computed: {
|
|
||||||
spoilerShown: ($spoilersShown, uuid) => !!$spoilersShown[uuid],
|
|
||||||
delegateKey: (uuid) => `spoiler-${uuid}`
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
onClickSpoilerButton() {
|
|
||||||
let uuid = this.get('uuid')
|
|
||||||
let $spoilersShown = this.store.get('spoilersShown')
|
|
||||||
$spoilersShown[uuid] = !$spoilersShown[uuid]
|
|
||||||
this.store.set({'spoilersShown': $spoilersShown})
|
|
||||||
this.fire('recalculateHeight')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
Loading…
Reference in New Issue