mirror of
https://github.com/sudoxnym/habitica.git
synced 2026-05-24 06:35:37 +00:00
* Various Chat Fixes * Allow adding `@mention` anywhere (previously was fixed at the end of the text) * Add re-focus after mouseclick on `@mention` choice * Remove`@mention` space barrier (since server ingests mentions without spaces in between) Co-authored-by: Bart Enkelaar <benkelaar@gmail.com> * Boundry Search + Select shutoff Co-authored-by: Bart Enkelaar <benkelaar@gmail.com>
This commit is contained in:
parent
920a093b0e
commit
92beff46b6
2 changed files with 51 additions and 38 deletions
|
|
@ -90,12 +90,12 @@ export default {
|
|||
props: ['selections', 'text', 'caretPosition', 'coords', 'chat', 'textbox'],
|
||||
data () {
|
||||
return {
|
||||
atRegex: /(?!\b)@[\w-]*$/,
|
||||
atRegex: /(?!\b)@([\w-]*)$/,
|
||||
currentSearch: '',
|
||||
searchActive: false,
|
||||
searchEscaped: false,
|
||||
currentSearchPosition: 0,
|
||||
tmpSelections: [],
|
||||
searchResults: [],
|
||||
icons: Object.freeze({
|
||||
tier1,
|
||||
tier2,
|
||||
|
|
@ -114,7 +114,7 @@ export default {
|
|||
computed: {
|
||||
autocompleteStyle () {
|
||||
function heightToUse (textBox, topCoords) {
|
||||
const textBoxHeight = textBox['user-entry'].clientHeight;
|
||||
const textBoxHeight = textBox.clientHeight;
|
||||
return topCoords < textBoxHeight ? topCoords + 30 : textBoxHeight + 10;
|
||||
}
|
||||
return {
|
||||
|
|
@ -128,38 +128,25 @@ export default {
|
|||
backgroundColor: 'white',
|
||||
};
|
||||
},
|
||||
searchResults () {
|
||||
if (!this.searchActive) return [];
|
||||
if (!this.atRegex.exec(this.text)) return [];
|
||||
this.currentSearch = this.atRegex.exec(this.text)[0]; // eslint-disable-line vue/no-side-effects-in-computed-properties, max-len, prefer-destructuring
|
||||
this.currentSearch = this.currentSearch.substring(1, this.currentSearch.length); // eslint-disable-line vue/no-side-effects-in-computed-properties, max-len
|
||||
|
||||
const lowerCaseSearch = this.currentSearch.toLowerCase();
|
||||
return this.tmpSelections
|
||||
.filter(option => { // eslint-disable-line arrow-body-style
|
||||
return option.displayName.toLowerCase().indexOf(lowerCaseSearch) !== -1
|
||||
|| (option.username
|
||||
&& option.username.toLowerCase().indexOf(lowerCaseSearch) !== -1);
|
||||
})
|
||||
.slice(0, 4);
|
||||
},
|
||||
|
||||
},
|
||||
watch: {
|
||||
text (newText) {
|
||||
if (!newText[newText.length - 1] || newText[newText.length - 1] === ' ') {
|
||||
text (newText, prevText) {
|
||||
const delCharsBool = prevText.length > newText.length;
|
||||
const caretPosition = this.textbox.selectionEnd;
|
||||
const lastFocusChar = delCharsBool ? prevText[caretPosition] : newText[caretPosition - 1];
|
||||
if (
|
||||
newText.length === 0 // Delete all
|
||||
|| /\s/.test(lastFocusChar) // End Search
|
||||
|| (lastFocusChar === '@' && delCharsBool) // Cancel Search
|
||||
) {
|
||||
this.searchActive = false;
|
||||
this.searchEscaped = false;
|
||||
return;
|
||||
this.searchResults = [];
|
||||
} else {
|
||||
if (lastFocusChar === '@') this.searchActive = true;
|
||||
if (this.searchActive) {
|
||||
this.searchResults = this.solveSearchResults(newText.substring(0, caretPosition));
|
||||
}
|
||||
}
|
||||
if (newText[newText.length - 1] === '@') {
|
||||
this.searchEscaped = false;
|
||||
}
|
||||
if (this.searchEscaped) return;
|
||||
|
||||
if (!this.atRegex.test(newText)) return;
|
||||
|
||||
this.searchActive = true;
|
||||
},
|
||||
chat () {
|
||||
this.resetDefaults();
|
||||
|
|
@ -170,11 +157,23 @@ export default {
|
|||
this.grabUserNames();
|
||||
},
|
||||
methods: {
|
||||
solveSearchResults (textFocus) {
|
||||
if (!this.searchActive) return [];
|
||||
const regexRes = this.atRegex.exec(textFocus);
|
||||
if (!regexRes) return [];
|
||||
this.currentSearch = regexRes[1]; // eslint-disable-line vue/no-side-effects-in-computed-properties, max-len, prefer-destructuring
|
||||
|
||||
const lowerCaseSearch = this.currentSearch.toLowerCase();
|
||||
|
||||
return this.tmpSelections
|
||||
.filter(option => option.displayName.toLowerCase().includes(lowerCaseSearch)
|
||||
|| (option.username && option.username.toLowerCase().includes(lowerCaseSearch)))
|
||||
.slice(0, 4);
|
||||
},
|
||||
resetDefaults () {
|
||||
// Mounted is not called when switching between group pages because they have the
|
||||
// the same parent component. So, reset the data
|
||||
this.searchActive = false;
|
||||
this.searchEscaped = false;
|
||||
this.tmpSelections = [];
|
||||
this.resetSelection();
|
||||
},
|
||||
|
|
@ -218,11 +217,18 @@ export default {
|
|||
return isContributor ? this.icons[`tier${message.contributor.level}`] : null;
|
||||
},
|
||||
select (result) {
|
||||
let newText = this.text;
|
||||
const { text } = this;
|
||||
const targetName = `${result.username || result.displayName} `;
|
||||
newText = newText.replace(new RegExp(`${this.currentSearch}$`), targetName);
|
||||
this.$emit('select', newText);
|
||||
const oldCaret = this.caretPosition;
|
||||
let newText = text.substring(0, this.caretPosition)
|
||||
.replace(new RegExp(`${this.currentSearch}$`), targetName);
|
||||
const newCaret = newText.length;
|
||||
newText += text.substring(oldCaret, text.length);
|
||||
this.$emit('select', newText, newCaret);
|
||||
this.resetSelection();
|
||||
|
||||
// Made selection, shut off searching
|
||||
this.searchActive = false;
|
||||
},
|
||||
setHover (result) {
|
||||
this.resetSelection();
|
||||
|
|
@ -263,7 +269,6 @@ export default {
|
|||
},
|
||||
cancel () {
|
||||
this.searchActive = false;
|
||||
this.searchEscaped = true;
|
||||
this.resetSelection();
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ export default {
|
|||
TOP: 0,
|
||||
LEFT: 0,
|
||||
},
|
||||
textbox: this.$refs,
|
||||
textbox: null,
|
||||
MAX_MESSAGE_LENGTH: MAX_MESSAGE_LENGTH.toString(),
|
||||
};
|
||||
},
|
||||
|
|
@ -130,6 +130,9 @@ export default {
|
|||
return this.user.flags.communityGuidelinesAccepted;
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.textbox = this.$refs['user-entry'];
|
||||
},
|
||||
methods: {
|
||||
// https://medium.com/@_jh3y/how-to-where-s-the-caret-getting-the-xy-position-of-the-caret-a24ba372990a
|
||||
getCoord (e, text) {
|
||||
|
|
@ -249,8 +252,13 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
selectedAutocomplete (newText) {
|
||||
selectedAutocomplete (newText, newCaret) {
|
||||
this.newMessage = newText;
|
||||
// Wait for v-modal to update
|
||||
this.$nextTick(() => {
|
||||
this.textbox.setSelectionRange(newCaret, newCaret);
|
||||
this.textbox.focus();
|
||||
});
|
||||
},
|
||||
|
||||
fetchRecentMessages () {
|
||||
|
|
|
|||
Loading…
Reference in a new issue