mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-13 07:46:06 +00:00
Avoid Hashtags in Comments in the Editor
Co-Authored-By: mattwr18 <mattwr18@gmail.com>
This commit is contained in:
parent
e6e9b1b7d7
commit
1255a46b7a
@ -26,7 +26,10 @@ describe('ContributionForm.vue', () => {
|
|||||||
const postTitle = 'this is a title for a post'
|
const postTitle = 'this is a title for a post'
|
||||||
const postContent = 'this is a post'
|
const postContent = 'this is a post'
|
||||||
const imageUpload = {
|
const imageUpload = {
|
||||||
file: { filename: 'avataar.svg', previewElement: '' },
|
file: {
|
||||||
|
filename: 'avataar.svg',
|
||||||
|
previewElement: '',
|
||||||
|
},
|
||||||
url: 'someUrlToImage',
|
url: 'someUrlToImage',
|
||||||
}
|
}
|
||||||
const image = '/uploads/1562010976466-avataaars'
|
const image = '/uploads/1562010976466-avataaars'
|
||||||
@ -217,7 +220,12 @@ describe('ContributionForm.vue', () => {
|
|||||||
content: 'auf Deutsch geschrieben',
|
content: 'auf Deutsch geschrieben',
|
||||||
language: 'de',
|
language: 'de',
|
||||||
image,
|
image,
|
||||||
categories: [{ id: 'cat12', name: 'Democracy & Politics' }],
|
categories: [
|
||||||
|
{
|
||||||
|
id: 'cat12',
|
||||||
|
name: 'Democracy & Politics',
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
wrapper = Wrapper()
|
wrapper = Wrapper()
|
||||||
|
|||||||
@ -224,6 +224,170 @@ export default {
|
|||||||
doc: { type: Object, default: () => {} },
|
doc: { type: Object, default: () => {} },
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
let mentionExtension
|
||||||
|
if (!this.users) {
|
||||||
|
mentionExtension = []
|
||||||
|
} else {
|
||||||
|
mentionExtension = [
|
||||||
|
new Mention({
|
||||||
|
// a list of all suggested items
|
||||||
|
items: () => {
|
||||||
|
return this.users
|
||||||
|
},
|
||||||
|
// is called when a suggestion starts
|
||||||
|
onEnter: ({ items, query, range, command, virtualNode }) => {
|
||||||
|
this.suggestionType = this.mentionSuggestionType
|
||||||
|
|
||||||
|
this.query = query
|
||||||
|
this.filteredItems = items
|
||||||
|
this.suggestionRange = range
|
||||||
|
this.renderPopup(virtualNode)
|
||||||
|
// we save the command for inserting a selected mention
|
||||||
|
// this allows us to call it inside of our custom popup
|
||||||
|
// via keyboard navigation and on click
|
||||||
|
this.insertMentionOrHashtag = command
|
||||||
|
},
|
||||||
|
// is called when a suggestion has changed
|
||||||
|
onChange: ({ items, query, range, virtualNode }) => {
|
||||||
|
this.query = query
|
||||||
|
this.filteredItems = items
|
||||||
|
this.suggestionRange = range
|
||||||
|
this.navigatedItemIndex = 0
|
||||||
|
this.renderPopup(virtualNode)
|
||||||
|
},
|
||||||
|
// is called when a suggestion is cancelled
|
||||||
|
onExit: () => {
|
||||||
|
this.suggestionType = this.nullSuggestionType
|
||||||
|
|
||||||
|
// reset all saved values
|
||||||
|
this.query = null
|
||||||
|
this.filteredItems = []
|
||||||
|
this.suggestionRange = null
|
||||||
|
this.navigatedItemIndex = 0
|
||||||
|
this.destroyPopup()
|
||||||
|
},
|
||||||
|
// is called on every keyDown event while a suggestion is active
|
||||||
|
onKeyDown: ({ event }) => {
|
||||||
|
// pressing up arrow
|
||||||
|
if (event.keyCode === 38) {
|
||||||
|
this.upHandler()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// pressing down arrow
|
||||||
|
if (event.keyCode === 40) {
|
||||||
|
this.downHandler()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// pressing enter
|
||||||
|
if (event.keyCode === 13) {
|
||||||
|
this.enterHandler()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
// is called when a suggestion has changed
|
||||||
|
// this function is optional because there is basic filtering built-in
|
||||||
|
// you can overwrite it if you prefer your own filtering
|
||||||
|
// in this example we use fuse.js with support for fuzzy search
|
||||||
|
onFilter: (items, query) => {
|
||||||
|
if (!query) {
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
const fuse = new Fuse(items, {
|
||||||
|
threshold: 0.2,
|
||||||
|
keys: ['slug'],
|
||||||
|
})
|
||||||
|
return fuse.search(query)
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
let hashtagExtension
|
||||||
|
if (!this.hashtags) {
|
||||||
|
hashtagExtension = []
|
||||||
|
} else {
|
||||||
|
hashtagExtension = [
|
||||||
|
new Hashtag({
|
||||||
|
// a list of all suggested items
|
||||||
|
items: () => {
|
||||||
|
return this.hashtags
|
||||||
|
},
|
||||||
|
// is called when a suggestion starts
|
||||||
|
onEnter: ({ items, query, range, command, virtualNode }) => {
|
||||||
|
this.suggestionType = this.hashtagSuggestionType
|
||||||
|
|
||||||
|
this.query = this.sanitizedQuery(query)
|
||||||
|
this.filteredItems = items
|
||||||
|
this.suggestionRange = range
|
||||||
|
this.renderPopup(virtualNode)
|
||||||
|
// we save the command for inserting a selected mention
|
||||||
|
// this allows us to call it inside of our custom popup
|
||||||
|
// via keyboard navigation and on click
|
||||||
|
this.insertMentionOrHashtag = command
|
||||||
|
},
|
||||||
|
// is called when a suggestion has changed
|
||||||
|
onChange: ({ items, query, range, virtualNode }) => {
|
||||||
|
this.query = this.sanitizedQuery(query)
|
||||||
|
this.filteredItems = items
|
||||||
|
this.suggestionRange = range
|
||||||
|
this.navigatedItemIndex = 0
|
||||||
|
this.renderPopup(virtualNode)
|
||||||
|
},
|
||||||
|
// is called when a suggestion is cancelled
|
||||||
|
onExit: () => {
|
||||||
|
this.suggestionType = this.nullSuggestionType
|
||||||
|
|
||||||
|
// reset all saved values
|
||||||
|
this.query = null
|
||||||
|
this.filteredItems = []
|
||||||
|
this.suggestionRange = null
|
||||||
|
this.navigatedItemIndex = 0
|
||||||
|
this.destroyPopup()
|
||||||
|
},
|
||||||
|
// is called on every keyDown event while a suggestion is active
|
||||||
|
onKeyDown: ({ event }) => {
|
||||||
|
// pressing up arrow
|
||||||
|
if (event.keyCode === 38) {
|
||||||
|
this.upHandler()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// pressing down arrow
|
||||||
|
if (event.keyCode === 40) {
|
||||||
|
this.downHandler()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// pressing enter
|
||||||
|
if (event.keyCode === 13) {
|
||||||
|
this.enterHandler()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// pressing space
|
||||||
|
if (event.keyCode === 32) {
|
||||||
|
this.spaceHandler()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
// is called when a suggestion has changed
|
||||||
|
// this function is optional because there is basic filtering built-in
|
||||||
|
// you can overwrite it if you prefer your own filtering
|
||||||
|
// in this example we use fuse.js with support for fuzzy search
|
||||||
|
onFilter: (items, query) => {
|
||||||
|
query = this.sanitizedQuery(query)
|
||||||
|
if (!query) {
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
return items.filter(item =>
|
||||||
|
JSON.stringify(item)
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(query.toLowerCase()),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
lastValueHash: null,
|
lastValueHash: null,
|
||||||
editor: new Editor({
|
editor: new Editor({
|
||||||
@ -249,154 +413,8 @@ export default {
|
|||||||
emptyNodeText: this.placeholder || this.$t('editor.placeholder'),
|
emptyNodeText: this.placeholder || this.$t('editor.placeholder'),
|
||||||
}),
|
}),
|
||||||
new History(),
|
new History(),
|
||||||
new Mention({
|
...mentionExtension,
|
||||||
// a list of all suggested items
|
...hashtagExtension,
|
||||||
items: () => {
|
|
||||||
return this.users
|
|
||||||
},
|
|
||||||
// is called when a suggestion starts
|
|
||||||
onEnter: ({ items, query, range, command, virtualNode }) => {
|
|
||||||
this.suggestionType = this.mentionSuggestionType
|
|
||||||
|
|
||||||
this.query = query
|
|
||||||
this.filteredItems = items
|
|
||||||
this.suggestionRange = range
|
|
||||||
this.renderPopup(virtualNode)
|
|
||||||
// we save the command for inserting a selected mention
|
|
||||||
// this allows us to call it inside of our custom popup
|
|
||||||
// via keyboard navigation and on click
|
|
||||||
this.insertMentionOrHashtag = command
|
|
||||||
},
|
|
||||||
// is called when a suggestion has changed
|
|
||||||
onChange: ({ items, query, range, virtualNode }) => {
|
|
||||||
this.query = query
|
|
||||||
this.filteredItems = items
|
|
||||||
this.suggestionRange = range
|
|
||||||
this.navigatedItemIndex = 0
|
|
||||||
this.renderPopup(virtualNode)
|
|
||||||
},
|
|
||||||
// is called when a suggestion is cancelled
|
|
||||||
onExit: () => {
|
|
||||||
this.suggestionType = this.nullSuggestionType
|
|
||||||
|
|
||||||
// reset all saved values
|
|
||||||
this.query = null
|
|
||||||
this.filteredItems = []
|
|
||||||
this.suggestionRange = null
|
|
||||||
this.navigatedItemIndex = 0
|
|
||||||
this.destroyPopup()
|
|
||||||
},
|
|
||||||
// is called on every keyDown event while a suggestion is active
|
|
||||||
onKeyDown: ({ event }) => {
|
|
||||||
// pressing up arrow
|
|
||||||
if (event.keyCode === 38) {
|
|
||||||
this.upHandler()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// pressing down arrow
|
|
||||||
if (event.keyCode === 40) {
|
|
||||||
this.downHandler()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// pressing enter
|
|
||||||
if (event.keyCode === 13) {
|
|
||||||
this.enterHandler()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
// is called when a suggestion has changed
|
|
||||||
// this function is optional because there is basic filtering built-in
|
|
||||||
// you can overwrite it if you prefer your own filtering
|
|
||||||
// in this example we use fuse.js with support for fuzzy search
|
|
||||||
onFilter: (items, query) => {
|
|
||||||
if (!query) {
|
|
||||||
return items
|
|
||||||
}
|
|
||||||
const fuse = new Fuse(items, {
|
|
||||||
threshold: 0.2,
|
|
||||||
keys: ['slug'],
|
|
||||||
})
|
|
||||||
return fuse.search(query)
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
new Hashtag({
|
|
||||||
// a list of all suggested items
|
|
||||||
items: () => {
|
|
||||||
return this.hashtags
|
|
||||||
},
|
|
||||||
// is called when a suggestion starts
|
|
||||||
onEnter: ({ items, query, range, command, virtualNode }) => {
|
|
||||||
this.suggestionType = this.hashtagSuggestionType
|
|
||||||
|
|
||||||
this.query = this.sanitizedQuery(query)
|
|
||||||
this.filteredItems = items
|
|
||||||
this.suggestionRange = range
|
|
||||||
this.renderPopup(virtualNode)
|
|
||||||
// we save the command for inserting a selected mention
|
|
||||||
// this allows us to call it inside of our custom popup
|
|
||||||
// via keyboard navigation and on click
|
|
||||||
this.insertMentionOrHashtag = command
|
|
||||||
},
|
|
||||||
// is called when a suggestion has changed
|
|
||||||
onChange: ({ items, query, range, virtualNode }) => {
|
|
||||||
this.query = this.sanitizedQuery(query)
|
|
||||||
this.filteredItems = items
|
|
||||||
this.suggestionRange = range
|
|
||||||
this.navigatedItemIndex = 0
|
|
||||||
this.renderPopup(virtualNode)
|
|
||||||
},
|
|
||||||
// is called when a suggestion is cancelled
|
|
||||||
onExit: () => {
|
|
||||||
this.suggestionType = this.nullSuggestionType
|
|
||||||
|
|
||||||
// reset all saved values
|
|
||||||
this.query = null
|
|
||||||
this.filteredItems = []
|
|
||||||
this.suggestionRange = null
|
|
||||||
this.navigatedItemIndex = 0
|
|
||||||
this.destroyPopup()
|
|
||||||
},
|
|
||||||
// is called on every keyDown event while a suggestion is active
|
|
||||||
onKeyDown: ({ event }) => {
|
|
||||||
// pressing up arrow
|
|
||||||
if (event.keyCode === 38) {
|
|
||||||
this.upHandler()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// pressing down arrow
|
|
||||||
if (event.keyCode === 40) {
|
|
||||||
this.downHandler()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// pressing enter
|
|
||||||
if (event.keyCode === 13) {
|
|
||||||
this.enterHandler()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// pressing space
|
|
||||||
if (event.keyCode === 32) {
|
|
||||||
this.spaceHandler()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
// is called when a suggestion has changed
|
|
||||||
// this function is optional because there is basic filtering built-in
|
|
||||||
// you can overwrite it if you prefer your own filtering
|
|
||||||
// in this example we use fuse.js with support for fuzzy search
|
|
||||||
onFilter: (items, query) => {
|
|
||||||
query = this.sanitizedQuery(query)
|
|
||||||
if (!query) {
|
|
||||||
return items
|
|
||||||
}
|
|
||||||
return items.filter(item =>
|
|
||||||
JSON.stringify(item)
|
|
||||||
.toLowerCase()
|
|
||||||
.includes(query.toLowerCase()),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
],
|
||||||
onUpdate: e => {
|
onUpdate: e => {
|
||||||
clearTimeout(throttleInputEvent)
|
clearTimeout(throttleInputEvent)
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { mount, createLocalVue } from '@vue/test-utils'
|
import { mount, createLocalVue } from '@vue/test-utils'
|
||||||
import CommentForm from './index.vue'
|
import CommentForm from './CommentForm.vue'
|
||||||
import Styleguide from '@human-connection/styleguide'
|
import Styleguide from '@human-connection/styleguide'
|
||||||
import Vuex from 'vuex'
|
import Vuex from 'vuex'
|
||||||
|
|
||||||
@ -21,9 +21,15 @@ describe('CommentForm.vue', () => {
|
|||||||
mutate: jest
|
mutate: jest
|
||||||
.fn()
|
.fn()
|
||||||
.mockResolvedValueOnce({
|
.mockResolvedValueOnce({
|
||||||
data: { CreateComment: { contentExcerpt: 'this is a comment' } },
|
data: {
|
||||||
|
CreateComment: {
|
||||||
|
contentExcerpt: 'this is a comment',
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
.mockRejectedValue({ message: 'Ouch!' }),
|
.mockRejectedValue({
|
||||||
|
message: 'Ouch!',
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
$toast: {
|
$toast: {
|
||||||
error: jest.fn(),
|
error: jest.fn(),
|
||||||
@ -31,7 +37,9 @@ describe('CommentForm.vue', () => {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
propsData = {
|
propsData = {
|
||||||
post: { id: 1 },
|
post: {
|
||||||
|
id: 1,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -45,7 +53,12 @@ describe('CommentForm.vue', () => {
|
|||||||
getters,
|
getters,
|
||||||
})
|
})
|
||||||
const Wrapper = () => {
|
const Wrapper = () => {
|
||||||
return mount(CommentForm, { mocks, localVue, propsData, store })
|
return mount(CommentForm, {
|
||||||
|
mocks,
|
||||||
|
localVue,
|
||||||
|
propsData,
|
||||||
|
store,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@ -2,7 +2,13 @@
|
|||||||
<ds-form v-model="form" @submit="handleSubmit">
|
<ds-form v-model="form" @submit="handleSubmit">
|
||||||
<template slot-scope="{ errors }">
|
<template slot-scope="{ errors }">
|
||||||
<ds-card>
|
<ds-card>
|
||||||
<hc-editor ref="editor" :users="users" :value="form.content" @input="updateEditorContent" />
|
<hc-editor
|
||||||
|
ref="editor"
|
||||||
|
:users="users"
|
||||||
|
:hashtags="null"
|
||||||
|
:value="form.content"
|
||||||
|
@input="updateEditorContent"
|
||||||
|
/>
|
||||||
<ds-space />
|
<ds-space />
|
||||||
<ds-flex :gutter="{ base: 'small', md: 'small', sm: 'x-large', xs: 'x-large' }">
|
<ds-flex :gutter="{ base: 'small', md: 'small', sm: 'x-large', xs: 'x-large' }">
|
||||||
<ds-flex-item :width="{ base: '0%', md: '50%', sm: '0%', xs: '0%' }" />
|
<ds-flex-item :width="{ base: '0%', md: '50%', sm: '0%', xs: '0%' }" />
|
||||||
@ -49,8 +49,8 @@
|
|||||||
"email-exists": "Es gibt schon ein Benutzerkonto mit dieser E-Mail Adresse!",
|
"email-exists": "Es gibt schon ein Benutzerkonto mit dieser E-Mail Adresse!",
|
||||||
"invalid-invitation-token": "Es sieht so aus, als ob der Einladungscode schon eingelöst wurde. Jeder Code kann nur einmalig benutzt werden."
|
"invalid-invitation-token": "Es sieht so aus, als ob der Einladungscode schon eingelöst wurde. Jeder Code kann nur einmalig benutzt werden."
|
||||||
},
|
},
|
||||||
"submit": "Konto erstellen",
|
"submit": "Konto erstellen",
|
||||||
"success": "Eine Mail mit einem Bestätigungslink für die Registrierung wurde an <b>{email}</b> geschickt"
|
"success": "Eine Mail mit einem Bestätigungslink für die Registrierung wurde an <b>{email}</b> geschickt"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"create-user-account": {
|
"create-user-account": {
|
||||||
@ -229,7 +229,7 @@
|
|||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"submit": "Kommentiere",
|
"submit": "Kommentiere",
|
||||||
"submitted": "Kommentar Gesendet"
|
"submitted": "Kommentar gesendet"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
|
|||||||
@ -67,7 +67,7 @@ import HcTag from '~/components/Tag'
|
|||||||
import ContentMenu from '~/components/ContentMenu'
|
import ContentMenu from '~/components/ContentMenu'
|
||||||
import HcUser from '~/components/User'
|
import HcUser from '~/components/User'
|
||||||
import HcShoutButton from '~/components/ShoutButton.vue'
|
import HcShoutButton from '~/components/ShoutButton.vue'
|
||||||
import HcCommentForm from '~/components/comments/CommentForm'
|
import HcCommentForm from '~/components/comments/CommentForm/CommentForm'
|
||||||
import HcCommentList from '~/components/comments/CommentList'
|
import HcCommentList from '~/components/comments/CommentList'
|
||||||
import { postMenuModalsData, deletePostMutation } from '~/components/utils/PostHelpers'
|
import { postMenuModalsData, deletePostMutation } from '~/components/utils/PostHelpers'
|
||||||
import PostQuery from '~/graphql/PostQuery.js'
|
import PostQuery from '~/graphql/PostQuery.js'
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user