Skip to content
Snippets Groups Projects
Commit 5249b1d2 authored by lain's avatar lain
Browse files

Add basic mention completion.

parent df2a39c0
Branches
No related tags found
No related merge requests found
import statusPoster from '../../services/status_poster/status_poster.service.js'
import MediaUpload from '../media_upload/media_upload.vue'
import fileTypeService from '../../services/file_type/file_type.service.js'
import Tribute from '../../../node_modules/tributejs/src/Tribute.js'
require('../../../node_modules/tributejs/scss/tribute.scss')
import Completion from '../../services/completion/completion.js'
import { merge, reject, map, uniqBy } from 'lodash'
import { take, filter, reject, map, uniqBy } from 'lodash'
const buildMentionsString = ({user, attentions}, currentUser) => {
let allAttentions = [...attentions]
......@@ -21,51 +20,6 @@ const buildMentionsString = ({user, attentions}, currentUser) => {
return mentions.join(' ') + ' '
}
const defaultCollection = {
// symbol that starts the lookup
trigger: '@',
// element to target for @mentions
iframe: null,
// class added in the flyout menu for active item
selectClass: 'highlight',
// function called on select that returns the content to insert
selectTemplate: function (item) {
return '@' + item.original.screen_name
},
// template for displaying item in menu
menuItemTemplate: function (item) {
return `<img src="${item.original.profile_image_url}"></img> <div class='name'>${item.string}</div>`
},
// template for when no match is found (optional),
// If no template is provided, menu is hidden.
noMatchTemplate: null,
// specify an alternative parent container for the menu
menuContainer: document.body,
// column to search against in the object (accepts function or string)
lookup: ({name, screen_name}) => `${name} (@${screen_name})`, // eslint-disable-line camelcase
// column that contains the content to insert by default
fillAttr: 'screen_name',
// REQUIRED: array of objects to match
values: [],
// specify whether a space is required before the trigger character
requireLeadingSpace: true,
// specify whether a space is allowed in the middle of mentions
allowSpaces: false
}
const tribute = new Tribute({ collection: [] })
const PostStatusForm = {
props: [
'replyTo',
......@@ -89,30 +43,37 @@ const PostStatusForm = {
newStatus: {
status: statusText,
files: []
}
},
caret: 0
}
},
computed: {
candidates () {
if (this.textAtCaret.charAt(0) === '@') {
const matchedUsers = filter(this.users, (user) => (user.name + user.screen_name).match(this.textAtCaret.slice(1)))
return map(take(matchedUsers, 5), ({screen_name, name}) => screen_name)
} else {
return ['nothing']
}
},
textAtCaret () {
return (this.wordAtCaret || {}).word || ''
},
wordAtCaret () {
const word = Completion.wordAtPosition(this.newStatus.status, this.caret - 1) || {}
return word
},
users () {
return this.$store.state.users.users
},
completions () {
let users = this.users
users = merge({values: users}, defaultCollection)
return [users]
}
},
watch: {
completions () {
tribute.collection = this.completions
}
},
mounted () {
const textarea = this.$el.querySelector('textarea')
tribute.collection = this.completions
tribute.attach(textarea)
},
methods: {
replace (replacement) {
this.newStatus.status = Completion.replaceWord(this.newStatus.status, this.wordAtCaret, replacement)
},
setCaret ({target: {selectionStart}}) {
this.caret = selectionStart
},
postStatus (newStatus) {
statusPoster.postStatus({
status: newStatus.status,
......
......@@ -2,7 +2,7 @@
<div class="post-status-form">
<form @submit.prevent="postStatus(newStatus)">
<div class="form-group" >
<textarea v-model="newStatus.status" placeholder="Just landed in L.A." rows="3" class="form-control" @keyup.meta.enter="postStatus(newStatus)" @keyup.ctrl.enter="postStatus(newStatus)" @drop="fileDrop" @dragover.prevent="fileDrag"></textarea>
<textarea @click="setCaret" @keyup="setCaret" v-model="newStatus.status" placeholder="Just landed in L.A." rows="3" class="form-control" @keyup.meta.enter="postStatus(newStatus)" @keyup.ctrl.enter="postStatus(newStatus)" @drop="fileDrop" @dragover.prevent="fileDrag"></textarea>
</div>
<div class="attachments">
<div class="attachment" v-for="file in newStatus.files">
......@@ -13,6 +13,13 @@
<a v-if="type(file) === 'unknown'" :href="file.image">{{file.url}}</a>
</div>
</div>
<div>
<h1>Word</h1>
<h2>{{textAtCaret}}</h2>
<h1>Candidates</h1>
<h3 v-for="candidate in candidates" @click="replace('@' + candidate)">{{candidate}}</h3>
</div>
<div class='form-bottom'>
<media-upload @uploading="disableSubmit" @uploaded="addMediaFile" @upload-failed="enableSubmit" :drop-files="dropFiles"></media-upload>
<button :disabled="submitDisabled" type="submit" class="btn btn-default base05 base01-background">Submit</button>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment