Parcourir la source

Move replacement logic into editorCore, update sub-components

sbkwgh il y a 8 ans
Parent
commit
c702e92b6b

+ 7 - 1
src/components/InputEditor.vue

@@ -16,12 +16,13 @@
 					:error='error'
 
 					@input='emitInput'
+					@mentions='emitMentions'
 					@focus='setFocusInput(true)'
 					@blur='setFocusInput(false)'
 				></input-editor-core>
 			</template>
 			<template slot='Preview'>
-				<input-editor-preview :value='value'></input-editor-preview>
+				<input-editor-preview :value='value' :mentions='mentions'></input-editor-preview>
 			</template>
 		</tab-view>
 		
@@ -49,6 +50,7 @@
 		data () {
 			return {
 				showTab: 0,
+				mentions: [],
 				focusInput: false
 			}
 		},
@@ -62,6 +64,10 @@
 				this.emitInput('')
 				this.$emit('close')
 			},
+			emitMentions (mentions) {
+				this.mentions = mentions
+				this.$emit('mentions', mentions)
+			},
 			emitInput (val) {
 				this.$emit('input', val)
 			},

+ 43 - 0
src/components/InputEditorCore.vue

@@ -80,6 +80,8 @@
 	import TabView from './TabView'
 	import ErrorTooltip from './ErrorTooltip'
 
+	let usernames = {}
+
 	export default {
 		name: 'InputEditorCore',
 		props: ['value', 'error'],
@@ -111,7 +113,48 @@
 					this.imageModalVisible = state
 				}
 			},
+			checkUsernames (matches) {
+				let doneCount = 0
+				let mentions = []
+
+				let done = res => {
+					doneCount++
+
+					if(res) mentions.push(res)
+
+					if(doneCount === matches.length) {
+						this.$emit('mentions', mentions)
+					}
+				}
+
+				matches.forEach(match => {
+					this.checkUsername(match, done)
+				})
+
+			},
+			checkUsername (match, cb) {
+				let username = match.trim().slice(1)
+				let checkedUsername = usernames[username]
+
+				if(checkedUsername !== undefined) {
+					cb(checkedUsername)
+				} else if(checkedUsername === undefined) {				
+					this.axios
+						.get('/api/v1/user/' + username)
+						.then(_ => {
+							usernames[username] = username
+							cb(username)
+						})
+						.catch(_ => {
+							usernames[username] = null
+							cb(null)
+						})
+				}
+			},
 			setEditor (value) {
+				let matches = value.match(/(^|\s)@[^\s]+/g) || []
+				this.checkUsernames(matches)
+
 				this.$emit('input', value)
 			},
 			getSelectionData () {

+ 7 - 42
src/components/InputEditorPreview.vue

@@ -22,52 +22,17 @@
 
 	export default {
 		name: 'InputEditorPreview',
-		props: ['value'],
-		data () {
-			return {
-				value_: this.value
-			}
-		},
-		methods: {
-			replaceUsername (match) {
-				let username = match.slice(1)
-				let link = usernames[username]
-				let regexp = new RegExp('(^|\\s)' + match + '($|\\s)')
-
-				if(link) {
-					this.$nextTick(() => {
-						this.value_ = this.value_.replace(regexp, '$1' + link + '$2')
-					})
-				} else if(link === undefined) {				
-					this.axios
-						.get('/api/v1/user/' + username)
-						.then(_ => {
-							let newLink = `[${match}](/user/${username})`
-
-							this.$nextTick(() => {
-								this.value_ = this.value_.replace(regexp, '$1' + newLink + '$2')
-							})
-							usernames[username] = newLink
-						})
-						.catch(_ => {
-							usernames[username] = null
-						})
-				}
-			}
-		},
+		props: ['value', 'mentions'],
 		computed: {
 			HTML () {
-				return Marked(this.value_);
-			}
-		},
-		watch: {
-			value (val) {
-				let matches = val.match(/@[^\s]+/g) || []
-				matches.forEach(match => {
-					this.replaceUsername(match)
+				let replacedMd = this.value
+
+				;(this.mentions || []).forEach(mention => {
+					let regexp = new RegExp('(^|\\s)@' + mention + '($|\\s)')
+					replacedMd = replacedMd.replace(regexp, `$1[@${mention}](/user/${mention})$2`)
 				})
 
-				this.value_ = val
+				return Marked(replacedMd);
 			}
 		}
 	}

+ 6 - 0
src/components/routes/Thread.vue

@@ -16,8 +16,11 @@
 		</header>
 		<input-editor
 			v-model='editor'
+
 			:show='editorState'
 			:replyUsername='replyUsername'
+			
+			v-on:mentions='setMentions'
 			v-on:close='hideEditor'
 			v-on:submit='addPost'
 		>
@@ -102,6 +105,9 @@
 				this.$store.commit('setThreadEditorState', false);
 				this.clearReply()
 			},
+			setMentions (mentions) {
+				this.$store.commit('setMentions', mentions)
+			},
 			clearReply () {
 				this.$store.commit({
 					type: 'setReply',

+ 6 - 1
src/components/routes/ThreadNew.vue

@@ -21,6 +21,7 @@
 				<input-editor-core
 					v-model='editor'
 					:error='errors.content'
+					@mentions='setMentions'
 					@focus='setFocusInput(true)'
 					@blur='setFocusInput(false)'
 				></input-editor-core>
@@ -29,7 +30,7 @@
 				<div class='editor__format_bar editor__format_bar--preview'>
 					preview
 				</div>
-				<input-editor-preview :value='editor'></input-editor-preview>
+				<input-editor-preview :value='editor' :mentions='mentions'></input-editor-preview>
 			</div>
 		</div>
 		<loading-button class='button--green submit' :loading='loading' @click='postThread'>Post thread</loading-button>
@@ -58,6 +59,7 @@
 			return {
 				selectedCategory: this.$store.state.category.selectedCategory,
 				editor: '',
+				mentions: [],
 				name: '',
 				loading: false,
 				focusInput: false,
@@ -112,6 +114,9 @@
 			},
 			setFocusInput (val) {
 				this.focusInput = val
+			},
+			setMentions (mentions) {
+				this.mentions = mentions
 			}
 		},
 		watch: {

+ 4 - 0
src/store/modules/thread.js

@@ -12,6 +12,7 @@ const state = {
 		show: false,
 		value: ''
 	},
+	mentions: [],
 	loadingPosts: false,
 	nextURL: '',
 	previousURL: '',
@@ -195,6 +196,9 @@ const mutations = {
 	},
 	incrementNextPostsCount (state) {
 		state.nextPostsCount++
+	},
+	setMentions (state, mentions) {
+		state.mentions = mentions
 	}
 }