mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 22:57:21 +01:00
Begin adding server-side autocomplete to web client
This commit is contained in:
16
package-lock.json
generated
16
package-lock.json
generated
@@ -1701,7 +1701,7 @@
|
||||
"dependencies": {
|
||||
"sax": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "http://registry.npmjs.org/sax/-/sax-1.2.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz",
|
||||
"integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o="
|
||||
},
|
||||
"uuid": {
|
||||
@@ -17240,7 +17240,7 @@
|
||||
},
|
||||
"chalk": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
|
||||
"requires": {
|
||||
"ansi-styles": "^2.2.1",
|
||||
@@ -21931,7 +21931,7 @@
|
||||
"dependencies": {
|
||||
"css-select": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "http://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
|
||||
"integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
|
||||
"requires": {
|
||||
"boolbase": "~1.0.0",
|
||||
@@ -24684,6 +24684,11 @@
|
||||
"punycode": "^1.4.1"
|
||||
}
|
||||
},
|
||||
"tributejs": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/tributejs/-/tributejs-3.4.0.tgz",
|
||||
"integrity": "sha512-BWB2YvfKpa6hZgcP9hKN5/tH3P/Guspn4r+ePgwNpftnQwMb6GVWTUgBpkMtVXkR5dwLLcP/iW87i9C1mp21zQ=="
|
||||
},
|
||||
"trim-leading-lines": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/trim-leading-lines/-/trim-leading-lines-0.1.1.tgz",
|
||||
@@ -26042,6 +26047,11 @@
|
||||
"resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.6.0.tgz",
|
||||
"integrity": "sha512-x3LV3wdmmERhVCYy3quqA57NJW7F3i6faas++pJQWtknWT+n7k30F4TVdHvCLn48peTJFRvCpxs3UuFPqgeELg=="
|
||||
},
|
||||
"vue-tribute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/vue-tribute/-/vue-tribute-1.0.1.tgz",
|
||||
"integrity": "sha1-ThJfdoEjxUBd4izjQ4NqmaCVRz0="
|
||||
},
|
||||
"vuedraggable": {
|
||||
"version": "2.16.0",
|
||||
"resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-2.16.0.tgz",
|
||||
|
||||
@@ -90,6 +90,7 @@
|
||||
"svg-url-loader": "^2.3.2",
|
||||
"svgo": "^1.0.5",
|
||||
"svgo-loader": "^2.1.0",
|
||||
"tributejs": "^3.4.0",
|
||||
"universal-analytics": "^0.4.16",
|
||||
"update": "^0.7.4",
|
||||
"upgrade": "^1.1.0",
|
||||
@@ -104,6 +105,7 @@
|
||||
"vue-router": "^3.0.0",
|
||||
"vue-style-loader": "^4.1.0",
|
||||
"vue-template-compiler": "^2.5.16",
|
||||
"vue-tribute": "^1.0.1",
|
||||
"vuedraggable": "^2.15.0",
|
||||
"vuejs-datepicker": "git://github.com/habitrpg/vuejs-datepicker.git#5d237615463a84a23dd6f3f77c6ab577d68593ec",
|
||||
"webpack": "^3.12.0",
|
||||
|
||||
@@ -16,7 +16,7 @@ div
|
||||
span.mr-1(v-if="msg.username") @{{ msg.username }}
|
||||
span.mr-1(v-if="msg.username") •
|
||||
span(v-b-tooltip="", :title="msg.timestamp | date") {{ msg.timestamp | timeAgo }}
|
||||
.text(v-html='atHighlight(parseMarkdown(msg.text))')
|
||||
.text(v-html='atHighlight(parseMarkdown(msg.text))', ref='markdownContainer')
|
||||
hr
|
||||
.d-flex(v-if='msg.id')
|
||||
.action.d-flex.align-items-center(v-if='!inbox', @click='copyAsTodo(msg)')
|
||||
@@ -244,6 +244,16 @@ export default {
|
||||
return achievementsLib.getContribText(message.contributor, message.backer) || '';
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
const links = this.$refs.markdownContainer.getElementsByTagName('a');
|
||||
for (var i = 0; i < links.length; i++) {
|
||||
const link = links[i];
|
||||
links[i].onclick = (event) => {
|
||||
event.preventDefault();
|
||||
this.$router.push({ path: link.getAttribute('href')});
|
||||
};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async like () {
|
||||
let message = cloneDeep(this.msg);
|
||||
@@ -299,7 +309,8 @@ export default {
|
||||
});
|
||||
},
|
||||
parseMarkdown (text) {
|
||||
return habiticaMarkdown.render(text);
|
||||
const mdText = habiticaMarkdown.render(text);
|
||||
return mdText;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
h3(v-once) {{ label }}
|
||||
|
||||
.row
|
||||
vue-tribute(:options="autocompleteOptions")
|
||||
textarea(:placeholder='placeholder',
|
||||
v-model='newMessage',
|
||||
ref='user-entry',
|
||||
@@ -14,13 +15,6 @@
|
||||
maxlength='3000'
|
||||
)
|
||||
span {{ currentLength }} / 3000
|
||||
autocomplete(
|
||||
:text='newMessage',
|
||||
v-on:select="selectedAutocomplete",
|
||||
:textbox='textbox',
|
||||
:coords='coords',
|
||||
:caretPosition = 'caretPosition',
|
||||
:chat='group.chat')
|
||||
|
||||
.row.chat-actions
|
||||
.col-6.chat-receive-actions
|
||||
@@ -42,17 +36,29 @@
|
||||
|
||||
<script>
|
||||
import debounce from 'lodash/debounce';
|
||||
import VueTribute from 'vue-tribute';
|
||||
import axios from 'axios';
|
||||
|
||||
import autocomplete from '../chat/autoComplete';
|
||||
import communityGuidelines from './communityGuidelines';
|
||||
import chatMessage from '../chat/chatMessages';
|
||||
import styleHelper from 'client/mixins/styleHelper';
|
||||
import tier1 from 'assets/svg/tier-1.svg';
|
||||
import tier2 from 'assets/svg/tier-2.svg';
|
||||
import tier3 from 'assets/svg/tier-3.svg';
|
||||
import tier4 from 'assets/svg/tier-4.svg';
|
||||
import tier5 from 'assets/svg/tier-5.svg';
|
||||
import tier6 from 'assets/svg/tier-6.svg';
|
||||
import tier7 from 'assets/svg/tier-7.svg';
|
||||
import tier8 from 'assets/svg/tier-mod.svg';
|
||||
import tier9 from 'assets/svg/tier-staff.svg';
|
||||
import tierNPC from 'assets/svg/tier-npc.svg';
|
||||
|
||||
export default {
|
||||
props: ['label', 'group', 'placeholder'],
|
||||
components: {
|
||||
autocomplete,
|
||||
communityGuidelines,
|
||||
chatMessage,
|
||||
VueTribute,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
@@ -67,6 +73,34 @@
|
||||
LEFT: 0,
|
||||
},
|
||||
textbox: this.$refs,
|
||||
icons: Object.freeze({
|
||||
tier1,
|
||||
tier2,
|
||||
tier3,
|
||||
tier4,
|
||||
tier5,
|
||||
tier6,
|
||||
tier7,
|
||||
tier8,
|
||||
tier9,
|
||||
tierNPC,
|
||||
}),
|
||||
autocompleteOptions: {
|
||||
async values (text, cb) {
|
||||
let suggestions = await axios.get(`/api/v4/members/find/${text}`);
|
||||
cb(suggestions.data.data);
|
||||
},
|
||||
selectTemplate (item) {
|
||||
return `@${item.original.auth.local.username}`;
|
||||
},
|
||||
lookup (item) {
|
||||
return item.auth.local.username;
|
||||
},
|
||||
menuItemTemplate (item) {
|
||||
let userTierClass = styleHelper.methods.userLevelStyle(item.original);
|
||||
return `<h3 class='profile-name ${userTierClass}'> ${item.original.profile.name}</h3> @${item.string}`;
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -140,16 +174,19 @@
|
||||
}, 500);
|
||||
},
|
||||
|
||||
selectedAutocomplete (newText) {
|
||||
this.newMessage = newText;
|
||||
},
|
||||
|
||||
fetchRecentMessages () {
|
||||
this.$emit('fetchRecentMessages');
|
||||
},
|
||||
reverseChat () {
|
||||
this.group.chat.reverse();
|
||||
},
|
||||
tierIcon (user) {
|
||||
const isNPC = Boolean(user.backer && user.backer.npc);
|
||||
if (isNPC) {
|
||||
return this.icons.tierNPC;
|
||||
}
|
||||
return this.icons[`tier${user.contributor.level}`];
|
||||
},
|
||||
},
|
||||
beforeRouteUpdate (to, from, next) {
|
||||
// Reset chat
|
||||
@@ -230,4 +267,77 @@
|
||||
}
|
||||
}
|
||||
|
||||
.v-tribute {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
@import '~client/assets/scss/tiers.scss';
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.tribute-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: auto;
|
||||
max-height: 400px;
|
||||
max-width: 600px;
|
||||
overflow: auto;
|
||||
display: block;
|
||||
z-index: 999999;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 4px rgba(#000, 0.13);
|
||||
}
|
||||
.tribute-container ul {
|
||||
margin: 0;
|
||||
margin-top: 2px;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
border: 1px solid rgba(#000, 0.13);
|
||||
background-clip: padding-box;
|
||||
overflow: hidden;
|
||||
-moz-transition: none;
|
||||
-webkit-transition: none;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.tribute-container li {
|
||||
color: $gray-200;
|
||||
padding: 12px 24px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
-moz-transition: none;
|
||||
-webkit-transition: none;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.tribute-container li.highlight,
|
||||
.tribute-container li:hover {
|
||||
background-color: rgba(213, 200, 255, 0.32);
|
||||
color: $purple-300;
|
||||
}
|
||||
|
||||
.tribute-container li span {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tribute-container li.no-match {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.profile-name {
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
margin-bottom: 0rem;
|
||||
}
|
||||
|
||||
|
||||
.tier-svg-icon {
|
||||
width: 10px;
|
||||
display: inline-block;
|
||||
margin-left: .5em;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -15,7 +15,7 @@ export async function highlightMentions (text) {
|
||||
.exec();
|
||||
members.forEach((member) => {
|
||||
const username = member.auth.local.username;
|
||||
text = text.replace(new RegExp(`@${username}\\b`, 'g'), `[@${username}](https://habitica.com/members/${member._id})`);
|
||||
text = text.replace(new RegExp(`@${username}\\b`, 'g'), `[@${username}](/members/${member._id})`);
|
||||
});
|
||||
}
|
||||
return text;
|
||||
|
||||
Reference in New Issue
Block a user