Skip to content

Commit b9c627e

Browse files
authored
Merge pull request #197 from ycarooliveira/master
(feature) #161 Auto Complete Template Text
2 parents 5031feb + 2bf6ab3 commit b9c627e

File tree

8 files changed

+220
-12
lines changed

8 files changed

+220
-12
lines changed

demo/src/ChatContainer.vue

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
:room-actions="roomActions"
5252
:menu-actions="menuActions"
5353
:room-message="roomMessage"
54+
:templates-text="templatesText"
5455
@fetch-more-rooms="fetchMoreRooms"
5556
@fetch-messages="fetchMessages"
5657
@send-message="sendMessage"
@@ -141,7 +142,21 @@ export default {
141142
{ name: 'removeUser', title: 'Remove User' },
142143
{ name: 'deleteRoom', title: 'Delete Room' }
143144
],
144-
styles: { container: { borderRadius: '4px' } }
145+
styles: { container: { borderRadius: '4px' } },
146+
templatesText: [
147+
{
148+
tag: 'help',
149+
text: 'This is the help'
150+
},
151+
{
152+
tag: 'action',
153+
text: 'this is the action'
154+
},
155+
{
156+
tag: 'action 2',
157+
text: 'this is the second action'
158+
}
159+
]
145160
// ,dbRequestCount: 0
146161
}
147162
},

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
"typescript": "^4.0.5",
6969
"vue": "^2.6.14",
7070
"vue-jest": "^3.0.7",
71-
"vue-template-compiler": "^2.6.11"
71+
"vue-template-compiler": "^2.6.14"
7272
},
7373
"peerDependencies": {
7474
"vue": "^2.6.14"

src/lib/ChatWindow.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
:room-info-enabled="roomInfoEnabled"
5555
:textarea-action-enabled="textareaActionEnabled"
5656
:accepted-files="acceptedFiles"
57+
:templates-text="templatesText"
5758
@toggle-rooms-list="toggleRoomsList"
5859
@room-info="roomInfo"
5960
@fetch-messages="fetchMessages"
@@ -138,7 +139,8 @@ export default {
138139
roomInfoEnabled: { type: Boolean, default: false },
139140
textareaActionEnabled: { type: Boolean, default: false },
140141
roomMessage: { type: String, default: '' },
141-
acceptedFiles: { type: String, default: '*' }
142+
acceptedFiles: { type: String, default: '*' },
143+
templatesText: { type: Array, default: null }
142144
},
143145
144146
emits: [

src/lib/Room/Room.vue

Lines changed: 79 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,14 @@
140140
@select-user-tag="selectUserTag($event)"
141141
/>
142142

143+
<room-Templates-Text
144+
:filtered-templates-text="filteredTemplatesText"
145+
:active-template="activeTemplate"
146+
:active-up-or-down="activeUpOrDown"
147+
@select-template-text="selectTemplateText($event)"
148+
@active-item="activeUpOrDown = 0"
149+
/>
150+
143151
<room-message-reply
144152
:room="room"
145153
:message-reply="messageReply"
@@ -210,8 +218,14 @@
210218
}"
211219
@input="onChangeInput"
212220
@keydown.esc="escapeTextarea"
213-
@keydown.enter.exact.prevent=""
221+
@keydown.enter.exact.prevent="beforeEnter"
214222
@paste="onPasteImage"
223+
@keydown.tab.exact.prevent=""
224+
@keydown.tab="activeTemplate = true"
225+
@keydown.up.exact.prevent=""
226+
@keydown.up="upActiveTemplate"
227+
@keydown.down.exact.prevent=""
228+
@keydown.down="downActiveTemplate"
215229
/>
216230

217231
<div class="vac-icon-textarea">
@@ -264,7 +278,7 @@
264278
type="file"
265279
multiple
266280
:accept="acceptedFiles"
267-
style="display:none"
281+
style="display: none"
268282
@change="onFileChange($event.target.files)"
269283
/>
270284

@@ -298,9 +312,10 @@ import RoomFiles from './RoomFiles/RoomFiles'
298312
import RoomMessageReply from './RoomMessageReply/RoomMessageReply'
299313
import RoomUsersTag from './RoomUsersTag/RoomUsersTag'
300314
import RoomEmojis from './RoomEmojis/RoomEmojis'
315+
import RoomTemplatesText from './RoomTemplatesText/RoomTemplatesText'
301316
import Message from '../Message/Message'
302317
303-
import filteredUsers from '../../utils/filter-items'
318+
import filteredItems from '../../utils/filter-items'
304319
import Recorder from '../../utils/recorder'
305320
306321
const { detectMobile, iOSDevice } = require('../../utils/mobile-detection')
@@ -327,6 +342,7 @@ export default {
327342
RoomMessageReply,
328343
RoomUsersTag,
329344
RoomEmojis,
345+
RoomTemplatesText,
330346
Message
331347
},
332348
@@ -360,7 +376,8 @@ export default {
360376
linkOptions: { type: Object, required: true },
361377
loadingRooms: { type: Boolean, required: true },
362378
roomInfoEnabled: { type: Boolean, required: true },
363-
textareaActionEnabled: { type: Boolean, required: true }
379+
textareaActionEnabled: { type: Boolean, required: true },
380+
templatesText: { type: Array, default: null }
364381
},
365382
366383
emits: [
@@ -398,6 +415,9 @@ export default {
398415
filteredEmojis: [],
399416
filteredUsersTag: [],
400417
selectedUsersTag: [],
418+
filteredTemplatesText: [],
419+
activeTemplate: null,
420+
activeUpOrDown: null,
401421
textareaCursorPosition: null,
402422
cursorRangePosition: null,
403423
emojisDB: new Database(),
@@ -442,6 +462,7 @@ export default {
442462
return (
443463
!!this.filteredEmojis.length ||
444464
!!this.filteredUsersTag.length ||
465+
!!this.filteredTemplatesText.length ||
445466
!!this.files.length ||
446467
!!this.messageReply
447468
)
@@ -515,14 +536,15 @@ export default {
515536
if (isMobile) {
516537
this.message = this.message + '\n'
517538
setTimeout(() => this.onChangeInput())
518-
} else {
539+
} else if (this.filteredTemplatesText.length === 0) {
519540
this.sendMessage()
520541
}
521542
}
522543
523544
setTimeout(() => {
524545
this.updateFooterList('@')
525546
this.updateFooterList(':')
547+
this.updateFooterList('/')
526548
}, 60)
527549
}),
528550
50
@@ -533,6 +555,7 @@ export default {
533555
534556
this.updateFooterList('@')
535557
this.updateFooterList(':')
558+
this.updateFooterList('/')
536559
})
537560
538561
this.$refs.roomTextarea.addEventListener('blur', () => {
@@ -644,6 +667,10 @@ export default {
644667
return
645668
}
646669
670+
if (tagChar === '/' && !this.templatesText) {
671+
return
672+
}
673+
647674
if (
648675
this.textareaCursorPosition === this.$refs.roomTextarea.selectionStart
649676
) {
@@ -677,6 +704,8 @@ export default {
677704
this.updateEmojis(query)
678705
} else if (tagChar === '@') {
679706
this.updateShowUsersTag(query)
707+
} else if (tagChar === '/') {
708+
this.updateShowTemplatesText(query)
680709
}
681710
} else {
682711
this.resetFooterList(tagChar)
@@ -718,7 +747,7 @@ export default {
718747
this.focusTextarea()
719748
},
720749
updateShowUsersTag(query) {
721-
this.filteredUsersTag = filteredUsers(
750+
this.filteredUsersTag = filteredItems(
722751
this.room.users,
723752
'username',
724753
query,
@@ -747,22 +776,65 @@ export default {
747776
748777
this.focusTextarea()
749778
},
779+
updateShowTemplatesText(query) {
780+
this.filteredTemplatesText = filteredItems(
781+
this.templatesText,
782+
'tag',
783+
query,
784+
true
785+
)
786+
},
787+
selectTemplateText(template) {
788+
this.activeTemplate = false
789+
if (!template) return
790+
const { position, endPosition } = this.getCharPosition('/')
791+
792+
const space = this.message.substr(endPosition, endPosition).length
793+
? ''
794+
: ' '
795+
796+
this.message =
797+
this.message.substr(0, position - 1) +
798+
template.text +
799+
space +
800+
this.message.substr(endPosition, this.message.length - 1)
801+
802+
this.cursorRangePosition =
803+
position + template.text.length + space.length + 1
804+
this.focusTextarea()
805+
},
806+
beforeEnter() {
807+
if (this.filteredTemplatesText.length > 0) {
808+
this.activeTemplate = true
809+
}
810+
},
811+
upActiveTemplate() {
812+
this.activeUpOrDown = -1
813+
},
814+
downActiveTemplate() {
815+
this.activeUpOrDown = 1
816+
},
750817
resetFooterList(tagChar = null) {
751818
if (tagChar === ':') {
752819
this.filteredEmojis = []
753820
} else if (tagChar === '@') {
754821
this.filteredUsersTag = []
822+
} else if (tagChar === '/') {
823+
this.filteredTemplatesText = []
755824
} else {
756825
this.filteredEmojis = []
757826
this.filteredUsersTag = []
827+
this.filteredTemplatesText = []
758828
}
759829
760830
this.textareaCursorPosition = null
761831
},
762832
escapeTextarea() {
763833
if (this.filteredEmojis.length) this.filteredEmojis = []
764834
else if (this.filteredUsersTag.length) this.filteredUsersTag = []
765-
else this.resetMessage()
835+
else if (this.filteredTemplatesText.length) {
836+
this.filteredTemplatesText = []
837+
} else this.resetMessage()
766838
},
767839
resetMessage(disableMobileFocus = false, initRoom = false) {
768840
if (!initRoom) {
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
.vac-template-container {
2+
position: absolute;
3+
display: flex;
4+
flex-direction: column;
5+
align-items: center;
6+
width: 100%;
7+
8+
.vac-template-box {
9+
display: flex;
10+
width: 100%;
11+
height: 54px;
12+
overflow: hidden;
13+
cursor: pointer;
14+
background: var(--chat-footer-bg-color-tag);
15+
transition: background-color 0.3s cubic-bezier(0.25, 0.8, 0.5, 1);
16+
}
17+
.vac-template-active {
18+
background: var(--chat-footer-bg-color-tag-active);
19+
transition: background-color 0.3s cubic-bezier(0.25, 0.8, 0.5, 1) !important;
20+
}
21+
.vac-template-info {
22+
display: flex;
23+
overflow: hidden;
24+
padding: 0 20px;
25+
align-items: center;
26+
}
27+
.vac-template-tag {
28+
font-size: 14px;
29+
font-weight: bold;
30+
margin-right: 10px;
31+
}
32+
.vac-template-text {
33+
font-size: 14px;
34+
}
35+
36+
@media only screen and (max-width: 768px) {
37+
.vac-template-box {
38+
height: 50px;
39+
}
40+
41+
.vac-template-info {
42+
padding: 0 12px;
43+
}
44+
}
45+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<template>
2+
<transition name="vac-slide-up">
3+
<div
4+
v-if="filteredTemplatesText.length"
5+
class="vac-template-container vac-app-box-shadow"
6+
:style="{ bottom: `${$parent.$refs.roomFooter.clientHeight}px` }"
7+
>
8+
<div
9+
v-for="(template, index) in filteredTemplatesText"
10+
:key="index"
11+
class="vac-template-box"
12+
:class="{ 'vac-template-active': index === activeItem }"
13+
@mouseover="activeItem = index"
14+
@click="$emit('select-template-text', template)"
15+
>
16+
<div class="vac-template-info">
17+
<div class="vac-template-tag">
18+
/{{ template.tag }}
19+
</div>
20+
<div class="vac-template-text">
21+
{{ template.text }}
22+
</div>
23+
</div>
24+
</div>
25+
</div>
26+
</transition>
27+
</template>
28+
29+
<script>
30+
export default {
31+
name: 'RoomTemplatesText',
32+
props: {
33+
filteredTemplatesText: { type: Array, required: true },
34+
activeTemplate: { type: Boolean, default: null },
35+
activeUpOrDown: { type: Number, default: null }
36+
},
37+
38+
emits: ['select-template-text', 'active-item'],
39+
40+
data() {
41+
return {
42+
activeItem: null
43+
}
44+
},
45+
watch: {
46+
filteredTemplatesText() {
47+
this.activeItem = 0
48+
},
49+
activeTemplate() {
50+
if (this.activeTemplate) {
51+
this.$emit(
52+
'select-template-text',
53+
this.filteredTemplatesText[this.activeItem]
54+
)
55+
}
56+
},
57+
activeUpOrDown() {
58+
if (
59+
this.activeUpOrDown > 0 &&
60+
this.activeItem < this.filteredTemplatesText.length - 1
61+
) {
62+
this.activeItem++
63+
} else if (this.activeUpOrDown < 0 && this.activeItem > 0) {
64+
this.activeItem--
65+
}
66+
this.$emit('active-item')
67+
}
68+
}
69+
}
70+
</script>

src/styles/index.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
@import '../lib/Room/RoomFiles/RoomFiles';
1212
@import '../lib/Room/RoomFile/RoomFile';
1313
@import '../lib/Room/RoomUsersTag/RoomUsersTag';
14+
@import '../lib/Room/RoomTemplatesText/RoomTemplatesText';
1415

1516
@import '../lib/RoomsList/RoomsList';
1617
@import '../lib/RoomsList/RoomContent/RoomContent';

0 commit comments

Comments
 (0)