Merge pull request #2248 from gradido/2247-links-in-contribution-messages-clickable

contibution messages, links are recognised
This commit is contained in:
Moriz Wahl 2022-10-25 11:57:02 +02:00 committed by GitHub
commit 3a8ee19bfb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 225 additions and 10 deletions

View File

@ -0,0 +1,38 @@
<template>
<div class="mt-2">
<span v-for="({ type, text }, index) in linkifiedMessage" :key="index">
<b-link v-if="type === 'link'" :to="text">{{ text }}</b-link>
<span v-else>{{ text }}</span>
</span>
</div>
</template>
<script>
const LINK_REGEX_PATTERN =
/(https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*))/i
export default {
name: 'LinkifyMessage',
props: {
message: {
type: String,
required: true,
},
},
computed: {
linkifiedMessage() {
const linkified = []
let string = this.message
let match
while ((match = string.match(LINK_REGEX_PATTERN))) {
if (match.index > 0)
linkified.push({ type: 'text', text: string.substring(0, match.index) })
linkified.push({ type: 'link', text: match[0] })
string = string.substring(match.index + match[0].length)
}
if (string.length > 0) linkified.push({ type: 'text', text: string })
return linkified
},
},
}
</script>

View File

@ -125,4 +125,68 @@ describe('ContributionMessagesListItem', () => {
})
})
})
describe('links in contribtion message', () => {
const propsData = {
message: {
id: 111,
message: 'Lorem ipsum?',
createdAt: '2022-08-29T12:23:27.000Z',
updatedAt: null,
type: 'DIALOG',
userFirstName: 'Peter',
userLastName: 'Lustig',
userId: 107,
__typename: 'ContributionMessage',
},
}
const ModeratorItemWrapper = () => {
return mount(ContributionMessagesListItem, {
localVue,
mocks,
propsData,
})
}
let messageField
describe('message of only one link', () => {
beforeEach(() => {
propsData.message.message = 'https://gradido.net/de/'
wrapper = ModeratorItemWrapper()
messageField = wrapper.find('div.is-not-moderator.text-left > div:nth-child(4)')
})
it('contains the link as text', () => {
expect(messageField.text()).toBe('https://gradido.net/de/')
})
it('contains a link to the given address', () => {
expect(messageField.find('a').attributes('href')).toBe('https://gradido.net/de/')
})
})
describe('message with text and two links', () => {
beforeEach(() => {
propsData.message.message = `Here you find all you need to know about Gradido: https://gradido.net/de/
and here is the link to the repository: https://github.com/gradido/gradido`
wrapper = ModeratorItemWrapper()
messageField = wrapper.find('div.is-not-moderator.text-left > div:nth-child(4)')
})
it('contains the whole text', () => {
expect(messageField.text())
.toBe(`Here you find all you need to know about Gradido: https://gradido.net/de/
and here is the link to the repository: https://github.com/gradido/gradido`)
})
it('contains the two links', () => {
expect(messageField.findAll('a').at(0).attributes('href')).toBe('https://gradido.net/de/')
expect(messageField.findAll('a').at(1).attributes('href')).toBe(
'https://github.com/gradido/gradido',
)
})
})
})
})

View File

@ -1,23 +1,28 @@
<template>
<div class="contribution-messages-list-item">
<div v-if="message.isModerator" class="text-right is-moderator">
<b-avatar square :text="initialLetters" variant="warning"></b-avatar>
<b-avatar square variant="warning"></b-avatar>
<span class="ml-2 mr-2">{{ message.userFirstName }} {{ message.userLastName }}</span>
<span class="ml-2">{{ $d(new Date(message.createdAt), 'short') }}</span>
<small class="ml-4 text-success">{{ $t('moderator') }}</small>
<div class="mt-2">{{ message.message }}</div>
<linkify-message :message="message.message"></linkify-message>
</div>
<div v-else class="text-left is-not-moderator">
<b-avatar :text="initialLetters" variant="info"></b-avatar>
<b-avatar variant="info"></b-avatar>
<span class="ml-2 mr-2">{{ message.userFirstName }} {{ message.userLastName }}</span>
<span class="ml-2">{{ $d(new Date(message.createdAt), 'short') }}</span>
<div class="mt-2">{{ message.message }}</div>
<linkify-message :message="message.message"></linkify-message>
</div>
</div>
</template>
<script>
import LinkifyMessage from '@/components/ContributionMessages/LinkifyMessage.vue'
export default {
name: 'ContributionMessagesListItem',
components: {
LinkifyMessage,
},
props: {
message: {
type: Object,

View File

@ -175,4 +175,68 @@ describe('ContributionMessagesListItem', () => {
})
})
})
describe('links in contribtion message', () => {
const propsData = {
message: {
id: 111,
message: 'Lorem ipsum?',
createdAt: '2022-08-29T12:23:27.000Z',
updatedAt: null,
type: 'DIALOG',
userFirstName: 'Peter',
userLastName: 'Lustig',
userId: 107,
__typename: 'ContributionMessage',
},
}
const ModeratorItemWrapper = () => {
return mount(ContributionMessagesListItem, {
localVue,
mocks,
propsData,
})
}
let messageField
describe('message of only one link', () => {
beforeEach(() => {
propsData.message.message = 'https://gradido.net/de/'
wrapper = ModeratorItemWrapper()
messageField = wrapper.find('div.is-not-moderator.text-right > div:nth-child(4)')
})
it('contains the link as text', () => {
expect(messageField.text()).toBe('https://gradido.net/de/')
})
it('contains a link to the given address', () => {
expect(messageField.find('a').attributes('href')).toBe('https://gradido.net/de/')
})
})
describe('message with text and two links', () => {
beforeEach(() => {
propsData.message.message = `Here you find all you need to know about Gradido: https://gradido.net/de/
and here is the link to the repository: https://github.com/gradido/gradido`
wrapper = ModeratorItemWrapper()
messageField = wrapper.find('div.is-not-moderator.text-right > div:nth-child(4)')
})
it('contains the whole text', () => {
expect(messageField.text())
.toBe(`Here you find all you need to know about Gradido: https://gradido.net/de/
and here is the link to the repository: https://github.com/gradido/gradido`)
})
it('contains the two links', () => {
expect(messageField.findAll('a').at(0).attributes('href')).toBe('https://gradido.net/de/')
expect(messageField.findAll('a').at(1).attributes('href')).toBe(
'https://github.com/gradido/gradido',
)
})
})
})
})

View File

@ -1,24 +1,29 @@
<template>
<div class="contribution-messages-list-item">
<div v-if="isNotModerator" class="is-not-moderator text-right">
<b-avatar :text="initialLetters" variant="info"></b-avatar>
<b-avatar variant="info"></b-avatar>
<span class="ml-2 mr-2">{{ message.userFirstName }} {{ message.userLastName }}</span>
<span class="ml-2">{{ $d(new Date(message.createdAt), 'short') }}</span>
<div class="mt-2">{{ message.message }}</div>
<linkify-message :message="message.message"></linkify-message>
</div>
<div v-else class="is-moderator text-left">
<b-avatar square :text="initialLetters" variant="warning"></b-avatar>
<b-avatar square variant="warning"></b-avatar>
<span class="ml-2 mr-2">{{ message.userFirstName }} {{ message.userLastName }}</span>
<span class="ml-2">{{ $d(new Date(message.createdAt), 'short') }}</span>
<small class="ml-4 text-success">{{ $t('community.moderator') }}</small>
<div class="mt-2">{{ message.message }}</div>
<linkify-message :message="message.message"></linkify-message>
</div>
</div>
</template>
<script>
import LinkifyMessage from '@/components/ContributionMessages/LinkifyMessage.vue'
export default {
name: 'ContributionMessagesListItem',
components: {
LinkifyMessage,
},
props: {
message: {
type: Object,

View File

@ -0,0 +1,37 @@
<template>
<div class="mt-2">
<span v-for="({ type, text }, index) in linkifiedMessage" :key="index">
<b-link v-if="type === 'link'" :to="text">{{ text }}</b-link>
<span v-else>{{ text }}</span>
</span>
</div>
</template>
<script>
const LINK_REGEX_PATTERN = /(https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*))/i
export default {
name: 'LinkifyMessage',
props: {
message: {
type: String,
required: true,
},
},
computed: {
linkifiedMessage() {
const linkified = []
let string = this.message
let match
while ((match = string.match(LINK_REGEX_PATTERN))) {
if (match.index > 0)
linkified.push({ type: 'text', text: string.substring(0, match.index) })
linkified.push({ type: 'link', text: match[0] })
string = string.substring(match.index + match[0].length)
}
if (string.length > 0) linkified.push({ type: 'text', text: string })
return linkified
},
},
}
</script>

View File

@ -88,6 +88,8 @@
</div>
</template>
<script>
const PATTERN_NON_DIGIT = /\D/g
export default {
name: 'ContributionForm',
props: {
@ -104,10 +106,10 @@ export default {
},
methods: {
numberFormat(value) {
return value.replace(/\D/g, '')
return value.replace(PATTERN_NON_DIGIT, '')
},
submit() {
this.form.amount = this.numberFormat(this.form.amount)
this.form.amount = this.form.amount.replace(PATTERN_NON_DIGIT, '')
// spreading is needed for testing
this.$emit(this.form.id ? 'update-contribution' : 'set-contribution', { ...this.form })
this.reset()