Merge branch 'better-still-emoji' into shigusegubu

* better-still-emoji:
  fix tests, add performance test (skipped, doesn't assert anything), tweak max mentions count
  made the code responsible for showing unwritten mentions actually work
  remove new options for style and separate line, now groups all chained mentions on a mentionsline regardless of placement. fixes spacing
This commit is contained in:
Henry Jameson 2021-08-12 23:01:29 +03:00
commit f96ffe3699
16 changed files with 132 additions and 646 deletions

View file

@ -41,7 +41,7 @@ const MentionLink = {
},
computed: {
user () {
return this.url && this.$store.getters.findUserByUrl(this.url)
return this.url && this.$store && this.$store.getters.findUserByUrl(this.url)
},
isYou () {
// FIXME why user !== currentUser???
@ -65,9 +65,6 @@ const MentionLink = {
highlightClass () {
if (this.highlight) return highlightClass(this.user)
},
oldStyle () {
return !this.mergedConfig.mentionsNewStyle
},
style () {
if (this.highlight) {
const {
@ -83,8 +80,7 @@ const MentionLink = {
return [
{
'-you': this.isYou,
'-highlighted': this.highlight,
'-oldStyle': this.oldStyle
'-highlighted': this.highlight
},
this.highlightType
]

View file

@ -10,10 +10,6 @@
border-radius: 2px;
}
.original {
margin-right: 0.25em;
}
.full {
position: absolute;
display: inline-block;
@ -41,8 +37,6 @@
}
.new {
margin-right: 0.25em;
&.-you {
& .shortName,
& .full {
@ -61,41 +55,6 @@
margin: 0;
}
&:not(.-oldStyle) {
.short {
padding-left: 0.25em;
padding-right: 0;
padding-top: 0;
padding-bottom: 0;
line-height: 1.5;
font-size: inherit;
.at {
color: var(--faint);
opacity: 0.8;
padding-right: 0.25em;
vertical-align: -20%;
}
}
.you {
padding-right: 0.25em;
}
.userName {
display: inline-block;
color: var(--link);
line-height: inherit;
margin-left: 0;
padding-left: 0.125em;
padding-right: 0.25em;
padding-top: 0;
padding-bottom: 0;
border-top-right-radius: var(--btnRadius);
border-bottom-right-radius: var(--btnRadius);
}
}
&.-striped {
& .userName,
& .full {

View file

@ -18,8 +18,7 @@
:class="classnames"
>
<button
class="short"
:class="[{ '-sublime': !highlight }, oldStyle ? 'button-unstyled' : 'button-default']"
class="short button-unstyled"
@click.prevent="onClick"
>
<!-- eslint-disable vue/no-v-html -->

View file

@ -14,11 +14,8 @@ const MentionsLine = {
MentionLink
},
computed: {
oldStyle () {
return !this.mergedConfig.mentionsNewStyle
},
limit () {
return 6
return 5
},
mentionsComputed () {
return this.mentions.slice(0, this.limit)
@ -29,16 +26,6 @@ const MentionsLine = {
manyMentions () {
return this.extraMentions.length > 0
},
buttonClasses () {
return [
this.oldStyle
? 'button-unstyled'
: 'button-default -sublime',
this.oldStyle
? '-oldStyle'
: '-newStyle'
]
},
...mapGetters(['mergedConfig'])
},
methods: {

View file

@ -1,17 +1,10 @@
.MentionsLine {
.showMoreLess {
white-space: normal;
color: var(--link);
}
&.-newStyle {
line-height: 1.5;
font-size: inherit;
display: inline-block;
padding-top: 0;
padding-bottom: 0;
}
&.-oldStyle {
color: var(--link);
}
.mention-link:not(:last-child) {
margin-right: 0.25em;
}
}

View file

@ -25,15 +25,13 @@
/>
</span><button
v-if="!expanded"
class="showMoreLess"
:class="buttonClasses"
class="button-unstyled showMoreLess"
@click="toggleShowMore"
>
{{ $t('status.plus_more', { number: extraMentions.length }) }}
</button><button
v-if="expanded"
class="showMoreLess"
:class="buttonClasses"
class="button-unstyled showMoreLess"
@click="toggleShowMore"
>
{{ $t('general.show_less') }}

View file

@ -56,25 +56,21 @@ export default Vue.component('RichContent', {
required: false,
type: Boolean,
default: false
},
hideMentions: {
required: false,
type: Boolean,
default: false
}
},
// NEVER EVER TOUCH DATA INSIDE RENDER
render (h) {
// Pre-process HTML
const { newHtml: html, lastMentions } = preProcessPerLine(this.html, this.greentext, this.handleLinks)
const firstMentions = [] // Mentions that appear in the beginning of post body
const { newHtml: html } = preProcessPerLine(this.html, this.greentext, this.handleLinks)
let currentMentions = null // Current chain of mentions, we group all mentions together
// to collapse too many mentions in a row
const lastTags = [] // Tags that appear at the end of post body
const writtenMentions = [] // All mentions that appear in post body
const writtenTags = [] // All tags that appear in post body
// unique index for vue "tag" property
let mentionIndex = 0
let tagsIndex = 0
let firstMentionReplaced = false
const renderImage = (tag) => {
return <StillImage
@ -98,41 +94,32 @@ export default Vue.component('RichContent', {
const renderMention = (attrs, children) => {
const linkData = getLinkData(attrs, children, mentionIndex++)
linkData.notifying = this.attentions.some(a => a.statusnet_profile_url === linkData.url)
if (!linkData.notifying) {
encounteredText = true
}
writtenMentions.push(linkData)
if (!encounteredText) {
firstMentions.push(linkData)
if (!firstMentionReplaced && !this.hideMentions) {
firstMentionReplaced = true
return <MentionsLine mentions={ firstMentions } />
} else {
return ''
}
if (currentMentions === null) {
currentMentions = []
}
currentMentions.push(linkData)
if (currentMentions.length === 1) {
return <MentionsLine mentions={ currentMentions } />
} else {
return <MentionLink
url={attrs.href}
content={flattenDeep(children).join('')}
/>
return ''
}
}
// We stop treating mentions as "first" ones when we encounter
// non-whitespace text
let encounteredText = false
// Processor to use with html_tree_converter
const processItem = (item, index, array, what) => {
// Handle text nodes - just add emoji
if (typeof item === 'string') {
const emptyText = item.trim() === ''
if (item.includes('\n')) {
currentMentions = null
}
if (emptyText) {
return encounteredText ? item : item.trim()
}
if (!encounteredText) {
item = item.trimStart()
encounteredText = true
// don't include spaces when processing mentions - we'll include them
// in MentionsLine
return currentMentions !== null ? item.trim() : item
}
currentMentions = null
if (item.includes(':')) {
item = ['', processTextForEmoji(
item,
@ -156,28 +143,25 @@ export default Vue.component('RichContent', {
const Tag = getTagName(opener)
const attrs = getAttrs(opener)
switch (Tag) {
case 'span': // Replace last mentions class with mentionsline
if (attrs['class'] && attrs['class'].includes('lastMentions')) {
if (firstMentions.length > 1 && lastMentions.length > 1) {
break
} else {
return !this.hideMentions ? <MentionsLine mentions={lastMentions} /> : ''
}
} else {
break
}
case 'br':
currentMentions = null
break
case 'img': // replace images with StillImage
return renderImage(opener)
case 'a': // replace mentions with MentionLink
if (!this.handleLinks) break
if (attrs['class'] && attrs['class'].includes('mention')) {
// Handling mentions here
return renderMention(attrs, children, encounteredText)
return renderMention(attrs, children)
} else {
// Everything else will be handled in reverse pass
encounteredText = true
currentMentions = null
return item // We'll handle it later
}
case 'span':
if (this.handleLinks && attrs['class'] && attrs['class'].includes('h-card')) {
return ['', children.map(processItem), '']
}
}
if (children !== undefined) {
@ -246,8 +230,6 @@ export default Vue.component('RichContent', {
</span>
const event = {
firstMentions,
lastMentions,
lastTags,
writtenMentions,
writtenTags
@ -284,15 +266,12 @@ export const preProcessPerLine = (html, greentext, handleLinks) => {
const lastMentions = []
const greentextHandle = new Set(['p', 'div'])
let nonEmptyIndex = -1
const lines = convertHtmlToLines(html)
const linesNum = lines.filter(c => c.text).length
const newHtml = lines.reverse().map((item, index, array) => {
// Going over each line in reverse to detect last mentions,
// keeping non-text stuff as-is
if (!item.text) return item
const string = item.text
nonEmptyIndex += 1
// Greentext stuff
if (
@ -316,42 +295,19 @@ export const preProcessPerLine = (html, greentext, handleLinks) => {
// Converting that line part into tree
const tree = convertHtmlToTree(string)
// If line has loose text, i.e. text outside a mention or a tag
// we won't touch mentions.
let hasLooseText = false
let mentionsNum = 0
const process = (item) => {
if (Array.isArray(item)) {
const [opener, children, closer] = item
const tag = getTagName(opener)
// If we have a link we probably have mentions
if (tag === 'a') {
if (!handleLinks) return [opener, children, closer]
const attrs = getAttrs(opener)
if (attrs['class'] && attrs['class'].includes('mention')) {
// Got mentions
mentionsNum++
return [opener, children, closer]
} else {
// Not a mention? Means we have loose text or whatever
hasLooseText = true
return [opener, children, closer]
}
} else if (tag === 'span' || tag === 'p') {
if (tag === 'span' || tag === 'p') {
// For span and p we need to go deeper
return [opener, [...children].map(process), closer]
} else {
// Everything else equals to a loose text
hasLooseText = true
return [opener, children, closer]
}
}
if (typeof item === 'string') {
if (item.trim() !== '') {
// only meaningful strings are loose text
hasLooseText = true
}
return item
}
}
@ -359,33 +315,7 @@ export const preProcessPerLine = (html, greentext, handleLinks) => {
// We now processed our tree, now we need to mark line as lastMentions
const result = [...tree].map(process)
if (
handleLinks && // Do we handle links at all?
mentionsNum > 1 && // Does it have more than one mention?
!hasLooseText && // Don't do anything if it has something besides mentions
nonEmptyIndex === 0 && // Only check last (first since list is reversed) line
nonEmptyIndex !== linesNum - 1 // Don't do anything if there's only one line
) {
let mentionIndex = 0
const process = (item) => {
if (Array.isArray(item)) {
const [opener, children] = item
const tag = getTagName(opener)
if (tag === 'a') {
const attrs = getAttrs(opener)
lastMentions.push(getLinkData(attrs, children, mentionIndex++))
} else if (children) {
children.forEach(process)
}
}
}
result.forEach(process)
// we DO need mentions here so that we conditionally remove them if don't
// have first mentions
return ['<span class="lastMentions">', flattenDeep(result).join(''), '</span>'].join('')
} else {
return flattenDeep(result).join('')
}
return flattenDeep(result).join('')
}).reverse().join('')
return { newHtml, lastMentions }

View file

@ -83,16 +83,6 @@
{{ $t('settings.emoji_reactions_on_timeline') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="mentionsOwnLine">
{{ $t('settings.mentions_new_place') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="mentionsNewStyle">
{{ $t('settings.mentions_new_style') }}
</BooleanSetting>
</li>
<h3>{{ $t('settings.attachments') }}</h3>
<li>
<BooleanSetting path="useContainFit">

View file

@ -176,18 +176,18 @@ const Status = {
userId: attn.id
}))
},
alsoMentions () {
if (!this.headTailLinks) return []
const set = new Set(this.headTailLinks.writtenMentions.map(m => m.url))
return this.headTailLinks.writtenMentions.filter(mention => {
return !set.has(mention.url)
})
},
mentionsLine () {
return this.mentionsOwnLine ? this.mentions : this.alsoMentions
},
mentionsOwnLine () {
return this.mergedConfig.mentionsOwnLine
const writtenMentions = this.headTailLinks ? this.headTailLinks.writtenMentions : []
const set = new Set(writtenMentions.map(_ => _.url))
return this.status.attentions.filter(attn => {
return attn.screen_name !== this.replyToName &&
attn.screen_name !== this.status.user.screen_name &&
!set.has(attn.url)
}).map(attn => ({
url: attn.statusnet_profile_url,
content: attn.screen_name,
userId: attn.id
}))
},
hasMentionsLine () {
return this.mentionsLine.length > 0

View file

@ -306,7 +306,6 @@
:no-heading="noHeading"
:highlight="highlight"
:focused="isFocused"
:hide-mentions="mentionsOwnLine && (isReply || true)"
@mediaplay="addMediaPlaying($event)"
@mediapause="removeMediaPlaying($event)"
@parseReady="setHeadTailLinks"

View file

@ -26,8 +26,7 @@ const StatusContent = {
'focused',
'noHeading',
'fullContent',
'singleLine',
'hideMentions'
'singleLine'
],
data () {
return {

View file

@ -48,7 +48,6 @@
:html="status.raw_html"
:emoji="status.emojis"
:handle-links="true"
:hide-mentions="hideMentions"
:greentext="mergedConfig.greentext"
:attentions="status.attentions"
@parseReady="onParseReady"

View file

@ -31,8 +31,7 @@ const StatusContent = {
'focused',
'noHeading',
'fullContent',
'singleLine',
'hideMentions'
'singleLine'
],
computed: {
hideAttachments () {

View file

@ -8,7 +8,6 @@
:status="status"
:compact="compact"
:single-line="singleLine"
:hide-mentions="hideMentions"
@parseReady="$emit('parseReady', $event)"
>
<div v-if="status.poll && status.poll.options">