diff options
Diffstat (limited to 'src/components/status')
| -rw-r--r-- | src/components/status/status.js | 42 | ||||
| -rw-r--r-- | src/components/status/status.vue | 79 |
2 files changed, 58 insertions, 63 deletions
diff --git a/src/components/status/status.js b/src/components/status/status.js index c718fe9f..0273a5be 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -4,14 +4,14 @@ import RetweetButton from '../retweet_button/retweet_button.vue' import DeleteButton from '../delete_button/delete_button.vue' import PostStatusForm from '../post_status_form/post_status_form.vue' import UserCardContent from '../user_card_content/user_card_content.vue' -import StillImage from '../still-image/still-image.vue' +import UserAvatar from '../user_avatar/user_avatar.vue' import Gallery from '../gallery/gallery.vue' import LinkPreview from '../link-preview/link-preview.vue' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import fileType from 'src/services/file_type/file_type.service' import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js' -import { mentionMatchesUrl } from 'src/services/mention_matcher/mention_matcher.js' -import { filter, find } from 'lodash' +import { mentionMatchesUrl, extractTagFromUrl } from 'src/services/matcher/matcher.service.js' +import { filter, find, unescape } from 'lodash' const Status = { name: 'Status', @@ -36,6 +36,7 @@ const Status = { preview: null, showPreview: false, showingTall: this.inConversation && this.focused, + showingLongSubject: false, expandingSubject: typeof this.$store.state.config.collapseMessageWithSubject === 'undefined' ? !this.$store.state.instance.collapseMessageWithSubject : !this.$store.state.config.collapseMessageWithSubject, @@ -89,6 +90,7 @@ const Status = { retweet () { return !!this.statusoid.retweeted_status }, retweeter () { return this.statusoid.user.name || this.statusoid.user.screen_name }, retweeterHtml () { return this.statusoid.user.name_html }, + retweeterProfileLink () { return this.generateUserProfileLink(this.statusoid.user.id, this.statusoid.user.screen_name) }, status () { if (this.retweet) { return this.statusoid.retweeted_status @@ -108,6 +110,14 @@ const Status = { return hits }, muted () { return !this.unmuted && (this.status.user.muted || this.muteWordHits.length > 0) }, + hideFilteredStatuses () { + return typeof this.$store.state.config.hideFilteredStatuses === 'undefined' + ? this.$store.state.instance.hideFilteredStatuses + : this.$store.state.config.hideFilteredStatuses + }, + hideStatus () { + return (this.hideReply || this.deleted) || (this.muted && this.hideFilteredStatuses) + }, isFocused () { // retweet or root of an expanded conversation if (this.focused) { @@ -129,6 +139,9 @@ const Status = { const lengthScore = this.status.statusnet_html.split(/<p|<br/).length + this.status.text.length / 80 return lengthScore > 20 }, + longSubject () { + return this.status.summary.length > 900 + }, isReply () { return !!(this.status.in_reply_to_status_id && this.status.in_reply_to_user_id) }, @@ -196,14 +209,15 @@ const Status = { }, replySubject () { if (!this.status.summary) return '' + const decodedSummary = unescape(this.status.summary) const behavior = typeof this.$store.state.config.subjectLineBehavior === 'undefined' ? this.$store.state.instance.subjectLineBehavior : this.$store.state.config.subjectLineBehavior - const startsWithRe = this.status.summary.match(/^re[: ]/i) + const startsWithRe = decodedSummary.match(/^re[: ]/i) if (behavior !== 'noop' && startsWithRe || behavior === 'masto') { - return this.status.summary + return decodedSummary } else if (behavior === 'email') { - return 're: '.concat(this.status.summary) + return 're: '.concat(decodedSummary) } else if (behavior === 'noop') { return '' } @@ -244,7 +258,7 @@ const Status = { DeleteButton, PostStatusForm, UserCardContent, - StillImage, + UserAvatar, Gallery, LinkPreview }, @@ -268,7 +282,7 @@ const Status = { } if (target.tagName === 'A') { if (target.className.match(/mention/)) { - const href = target.getAttribute('href') + const href = target.href const attn = this.status.attentions.find(attn => mentionMatchesUrl(attn, href)) if (attn) { event.stopPropagation() @@ -278,6 +292,15 @@ const Status = { return } } + if (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') } }, @@ -334,6 +357,9 @@ const Status = { 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) diff --git a/src/components/status/status.vue b/src/components/status/status.vue index 3e3e82bf..aae365d1 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -1,5 +1,5 @@ <template> - <div class="status-el" v-if="!hideReply && !deleted" :class="[{ 'status-el_focused': isFocused }, { 'status-conversation': inlineExpanded }]"> + <div class="status-el" v-if="!hideStatus" :class="[{ 'status-el_focused': isFocused }, { 'status-conversation': inlineExpanded }]"> <template v-if="muted && !noReplyLinks"> <div class="media status container muted"> <small> @@ -13,10 +13,12 @@ </template> <template v-else> <div v-if="retweet && !noHeading" :class="[repeaterClass, { highlighted: repeaterStyle }]" :style="[repeaterStyle]" class="media container retweet-info"> - <StillImage v-if="retweet" class='avatar' :class='{ "better-shadow": betterShadow }' :src="statusoid.user.profile_image_url_original"/> + <UserAvatar v-if="retweet" :betterShadow="betterShadow" :src="statusoid.user.profile_image_url_original"/> <div class="media-body faint"> - <a v-if="retweeterHtml" :href="statusoid.user.statusnet_profile_url" class="user-name" :title="'@'+statusoid.user.screen_name" v-html="retweeterHtml"></a> - <a v-else :href="statusoid.user.statusnet_profile_url" class="user-name" :title="'@'+statusoid.user.screen_name">{{retweeter}}</a> + <span class="user-name"> + <router-link v-if="retweeterHtml" :to="retweeterProfileLink" v-html="retweeterHtml"/> + <router-link v-else :to="retweeterProfileLink">{{retweeter}}</router-link> + </span> <i class='fa icon-retweet retweeted' :title="$t('tool_tip.repeat')"></i> {{$t('timeline.repeated')}} </div> @@ -25,7 +27,7 @@ <div :class="[userClass, { highlighted: userStyle, 'is-retweet': retweet }]" :style="[ userStyle ]" class="media status"> <div v-if="!noHeading" class="media-left"> <router-link :to="userProfileLink" @click.stop.prevent.capture.native="toggleUserExpanded"> - <StillImage class='avatar' :class="{'avatar-compact': compact, 'better-shadow': betterShadow}" :src="status.user.profile_image_url_original"/> + <UserAvatar :compact="compact" :betterShadow="betterShadow" :src="status.user.profile_image_url_original"/> </router-link> </div> <div class="status-body"> @@ -54,7 +56,7 @@ </div> <h4 class="replies" v-if="inConversation && !noReplyLinks"> <small v-if="replies.length">Replies:</small> - <small class="reply-link" v-for="reply in replies"> + <small class="reply-link" v-bind:key="reply.id" v-for="reply in replies"> <a href="#" @click.prevent="gotoOriginal(reply.id)" @mouseenter="replyEnter(reply.id, $event)" @mouseout="replyLeave()">{{reply.name}} </a> </small> </h4> @@ -85,7 +87,12 @@ </div> </div> - <div :class="{'tall-status': hideTallStatus}" class="status-content-wrapper"> + <div class="status-content-wrapper" :class="{ 'tall-status': !showingLongSubject }" v-if="longSubject"> + <a class="tall-status-hider" :class="{ 'tall-status-hider_focused': isFocused }" v-if="!showingLongSubject" href="#" @click.prevent="showingLongSubject=true">Show more</a> + <div @click.prevent="linkClicked" class="status-content media-body" v-html="status.statusnet_html"></div> + <a v-if="showingLongSubject" href="#" class="status-unhider" @click.prevent="showingLongSubject=false">Show less</a> + </div> + <div :class="{'tall-status': hideTallStatus}" class="status-content-wrapper" v-else> <a class="tall-status-hider" :class="{ 'tall-status-hider_focused': isFocused }" v-if="hideTallStatus" href="#" @click.prevent="toggleShowMore">Show more</a> <div @click.prevent="linkClicked" class="status-content media-body" v-html="status.statusnet_html" v-if="!hideSubjectStatus"></div> <div @click.prevent="linkClicked" class="status-content media-body" v-html="status.summary_html" v-else></div> @@ -93,7 +100,7 @@ <a v-if="showingMore" href="#" class="status-unhider" @click.prevent="toggleShowMore">Show less</a> </div> - <div v-if="status.attachments && !hideSubjectStatus" class="attachments media-body"> + <div v-if="status.attachments && (!hideSubjectStatus || showingLongSubject)" class="attachments media-body"> <attachment class="non-gallery" v-for="attachment in nonGalleryAttachments" @@ -413,7 +420,7 @@ padding: 0.4em 0.6em 0 0.6em; margin: 0; - .avatar { + .avatar.still-image { border-radius: $fallback--avatarAltRadius; border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius); margin-left: 28px; @@ -431,6 +438,8 @@ .user-name { font-weight: bold; + overflow: hidden; + text-overflow: ellipsis; img { width: 14px; @@ -497,46 +506,6 @@ color: var(--cBlue, $fallback--cBlue); } -.status .avatar-compact { - width: 32px; - height: 32px; - box-shadow: var(--avatarStatusShadow); - border-radius: $fallback--avatarAltRadius; - border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius); - - &.better-shadow { - box-shadow: var(--avatarStatusShadowInset); - filter: var(--avatarStatusShadowFilter) - } -} - -.avatar.still-image { - width: 48px; - height: 48px; - box-shadow: var(--avatarStatusShadow); - border-radius: $fallback--avatarRadius; - border-radius: var(--avatarRadius, $fallback--avatarRadius); - overflow: hidden; - position: relative; - - &.better-shadow { - box-shadow: var(--avatarStatusShadowInset); - filter: var(--avatarStatusShadowFilter) - } - - img { - width: 100%; - height: 100%; - } - - &.animated::before { - display: none; - } - - &.retweeted { - } -} - .status:hover .animated.avatar { canvas { display: none; @@ -594,7 +563,7 @@ a.unmute { @media all and (max-width: 800px) { .status-el { .retweet-info { - .avatar { + .avatar.still-image { margin-left: 20px; } } @@ -603,14 +572,14 @@ a.unmute { max-width: 100%; } - .status .avatar { + .status .avatar.still-image { width: 40px; height: 40px; - } - .status .avatar-compact { - width: 32px; - height: 32px; + &.avatar-compact { + width: 32px; + height: 32px; + } } } |
