MOBILE-3142 chat: Change chat look and feel
parent
efcb7af1a9
commit
4c151051eb
|
@ -4,8 +4,7 @@ $item-message-note-text: $gray-dark !default;
|
|||
$item-message-note-font-size: 75% !default;
|
||||
$item-message-mine-bg: $gray-light !default;
|
||||
|
||||
ion-app.app-root page-addon-messages-discussion.ion-page {
|
||||
|
||||
@mixin message-page {
|
||||
ion-content {
|
||||
background-color: $gray-lighter !important;
|
||||
@include darkmode() {
|
||||
|
@ -194,6 +193,12 @@ ion-app.app-root page-addon-messages-discussion.ion-page {
|
|||
.addon-message-not-mine.activated .tail {
|
||||
border-bottom-color: darken($item-message-bg, 10%);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ion-app.app-root page-addon-messages-discussion.ion-page {
|
||||
|
||||
@include message-page();
|
||||
|
||||
.toolbar-title {
|
||||
padding: 0;
|
||||
|
@ -224,4 +229,4 @@ ion-app.app-root page-addon-messages-discussion.ion-page {
|
|||
ion-app.app-root.ios page-addon-messages-discussion ion-footer .toolbar:last-child {
|
||||
padding-bottom: 4px;
|
||||
min-height: 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,10 +9,12 @@
|
|||
"errorwhilegettingchatusers": "Error while getting chat users.",
|
||||
"errorwhileretrievingmessages": "Error while retrieving messages from the server.",
|
||||
"errorwhilesendingmessage": "Error while sending the message.",
|
||||
"messagebeepseveryone": "{{$a}} beeps everyone!",
|
||||
"messagebeepsyou": "{{$a}} has just beeped you!",
|
||||
"messageenter": "{{$a}} has just entered this chat",
|
||||
"messageexit": "{{$a}} has left this chat",
|
||||
"messages": "Messages",
|
||||
"messageyoubeep": "You beeped {{$a}}",
|
||||
"modulenameplural": "Chats",
|
||||
"mustbeonlinetosendmessages": "You must be online to send messages.",
|
||||
"nomessages": "No messages yet",
|
||||
|
|
|
@ -8,55 +8,63 @@
|
|||
</ion-buttons>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content class="has-footer">
|
||||
<ion-content class="has-footer">
|
||||
<core-loading [hideUntil]="loaded">
|
||||
<div aria-live="polite">
|
||||
<div *ngFor="let message of messages; index as index; last as last">
|
||||
<ion-list class="addon-messages-discussion-container safe-area-page" aria-live="polite">
|
||||
<ng-container *ngFor="let message of messages; index as index; last as last">
|
||||
|
||||
<div text-center *ngIf="showDate(messages[index], messages[index - 1])" class="addon-mod-chat-notice">
|
||||
<ion-badge text-wrap color="light">
|
||||
<span>{{ message.timestamp * 1000 | coreFormatDate:"strftimedayshort" }}</span>
|
||||
<h6 text-center *ngIf="message.showDate" class="addon-messages-date">
|
||||
{{ message.timestamp * 1000 | coreFormatDate:"strftimedayshort" }}
|
||||
</h6>
|
||||
|
||||
<div text-center *ngIf="message.special" class="addon-mod-chat-notice">
|
||||
<ion-badge text-wrap color="success" *ngIf="message.system && message.message == 'enter'">
|
||||
<span><core-icon name="fa-sign-in"></core-icon> {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} {{ 'addon.mod_chat.messageenter' | translate:{$a: message.userfullname} }}</span>
|
||||
</ion-badge>
|
||||
|
||||
<ion-badge text-wrap color="danger" *ngIf="message.system && message.message == 'exit'">
|
||||
<span><core-icon name="fa-sign-out"></core-icon> {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} {{ 'addon.mod_chat.messageexit' | translate:{$a: message.userfullname} }}</span>
|
||||
</ion-badge>
|
||||
|
||||
<ion-badge text-wrap color="primary" *ngIf="message.beep == 'all'">
|
||||
<span><ion-icon name="notifications"></ion-icon> {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }}
|
||||
{{ 'addon.mod_chat.messagebeepseveryone' | translate:{$a: message.userfullname} }} </span>
|
||||
</ion-badge>
|
||||
|
||||
<ion-badge text-wrap color="primary" *ngIf="message.userid != currentUserId && message.beep == currentUserId">
|
||||
<span><ion-icon name="notifications"></ion-icon> {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }}
|
||||
{{ 'addon.mod_chat.messagebeepsyou' | translate:{$a: message.userfullname} }} </span>
|
||||
</ion-badge>
|
||||
|
||||
<ion-badge text-wrap color="light" *ngIf="message.userid == currentUserId && message.beep && message.beep != 'all'">
|
||||
<span><ion-icon name="notifications"></ion-icon> {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }}
|
||||
{{ 'addon.mod_chat.messageyoubeep' | translate:{$a: message.beepwho} }} </span>
|
||||
</ion-badge>
|
||||
</div>
|
||||
|
||||
<div text-center *ngIf="message.system && message.message == 'enter'" class="addon-mod-chat-notice">
|
||||
<ion-badge text-wrap color="light">
|
||||
<span>{{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} {{ 'addon.mod_chat.messageenter' | translate:{$a: message.userfullname} }}</span>
|
||||
</ion-badge>
|
||||
</div>
|
||||
|
||||
<div text-center *ngIf="message.system && message.message == 'exit'" class="addon-mod-chat-notice">
|
||||
<ion-badge text-wrap color="light">
|
||||
<span>{{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} {{ 'addon.mod_chat.messageexit' | translate:{$a: message.userfullname} }}</span>
|
||||
</ion-badge>
|
||||
</div>
|
||||
|
||||
<div text-center *ngIf="message.message == currentUserBeep" class="addon-mod-chat-notice">
|
||||
<ion-badge text-wrap color="light">
|
||||
<span>{{ 'addon.mod_chat.messagebeepsyou' | translate:{$a: message.userfullname} }}</span>
|
||||
</ion-badge>
|
||||
</div>
|
||||
|
||||
<ion-item text-wrap *ngIf="!message.system && message.message.substr(0, 4) != 'beep'" class="addon-mod-chat-message">
|
||||
<ion-avatar core-user-avatar [user]="message" item-start></ion-avatar>
|
||||
<h2>
|
||||
<p float-end>{{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }}</p>
|
||||
<core-format-text [text]="message.userfullname"></core-format-text>
|
||||
<ion-item text-wrap *ngIf="!message.special" class="addon-message" [class.addon-message-mine]="message.userid == currentUserId" [class.addon-message-not-mine]="message.userid != currentUserId" [class.addon-message-no-user]="!message.showUserData" [@coreSlideInOut]="message.userid == currentUserId ? '' : 'fromLeft'">
|
||||
<!-- User data. -->
|
||||
<h2 class="addon-message-user">
|
||||
<ion-avatar item-start core-user-avatar [user]="message" [linkProfile]="false" *ngIf="message.showUserData"></ion-avatar>
|
||||
<div *ngIf="message.showUserData">{{ message.userfullname }}</div>
|
||||
<ion-note>{{ message.timestamp * 1000 | coreFormatDate: "strftimetime" }}</ion-note>
|
||||
</h2>
|
||||
<core-format-text [text]="message.message" (afterRender)="last && scrollToBottom()"></core-format-text>
|
||||
</ion-item>
|
||||
</div>
|
||||
|
||||
<div text-center margin *ngIf="!messages || messages.length <= 0">
|
||||
<p>{{ 'addon.mod_chat.nomessages' | translate}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="addon-message-text">
|
||||
<core-format-text [text]="message.message" (afterRender)="last && scrollToBottom()"></core-format-text>
|
||||
</p>
|
||||
<div class="tail" *ngIf="message.showTail"></div>
|
||||
</ion-item>
|
||||
</ng-container>
|
||||
|
||||
</ion-list>
|
||||
<core-empty-box *ngIf="!messages || messages.length <= 0" icon="chatbubbles" [message]="'addon.mod_chat.nomessages' | translate"></core-empty-box>
|
||||
</core-loading>
|
||||
</ion-content>
|
||||
<ion-footer color="light" class="footer-adjustable">
|
||||
<ion-toolbar color="light" position="bottom">
|
||||
<p text-center *ngIf="!isOnline">{{ 'addon.mod_chat.mustbeonlinetosendmessages' | translate }}</p>
|
||||
<core-send-message-form *ngIf="isOnline && polling && loaded" [message]="newMessage" (onSubmit)="sendMessage($event)" [showKeyboard]="showKeyboard" [placeholder]="'addon.messages.newmessage' | translate" (onResize)="resizeContent()"></core-send-message-form>
|
||||
<core-send-message-form [sendDisabled]="sending" *ngIf="isOnline && polling && loaded" [message]="newMessage" (onSubmit)="sendMessage($event)" [showKeyboard]="showKeyboard" [placeholder]="'addon.messages.newmessage' | translate" (onResize)="resizeContent()"></core-send-message-form>
|
||||
<button *ngIf="isOnline && !polling && loaded" (click)="reconnect()" ion-button block color="light">{{ 'core.login.reconnect' | translate }}</button>
|
||||
</ion-toolbar>
|
||||
</ion-footer>
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
ion-app.app-root page-addon-mod-chat-chat {
|
||||
@include message-page();
|
||||
|
||||
.addon-mod-chat-notice {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.addon-mod-chat-message {
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
|||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||
import { AddonModChatProvider, AddonModChatMessageWithUserData } from '../../providers/chat';
|
||||
import { Network } from '@ionic-native/network';
|
||||
import { coreSlideInOut } from '@classes/animations';
|
||||
import { CoreSendMessageFormComponent } from '@components/send-message-form/send-message-form';
|
||||
import * as moment from 'moment';
|
||||
|
||||
/**
|
||||
|
@ -31,9 +33,11 @@ import * as moment from 'moment';
|
|||
@Component({
|
||||
selector: 'page-addon-mod-chat-chat',
|
||||
templateUrl: 'chat.html',
|
||||
animations: [coreSlideInOut]
|
||||
})
|
||||
export class AddonModChatChatPage {
|
||||
@ViewChild(Content) content: Content;
|
||||
@ViewChild(CoreSendMessageFormComponent) sendMessageForm: CoreSendMessageFormComponent;
|
||||
|
||||
loaded = false;
|
||||
title: string;
|
||||
|
@ -41,7 +45,8 @@ export class AddonModChatChatPage {
|
|||
newMessage: string;
|
||||
polling: any;
|
||||
isOnline: boolean;
|
||||
currentUserBeep: string;
|
||||
currentUserId: number;
|
||||
sending: boolean;
|
||||
|
||||
protected logger;
|
||||
protected courseId: number;
|
||||
|
@ -53,6 +58,7 @@ export class AddonModChatChatPage {
|
|||
protected keyboardObserver: any;
|
||||
protected viewDestroyed = false;
|
||||
protected pollingRunning = false;
|
||||
protected users = [];
|
||||
|
||||
constructor(navParams: NavParams, logger: CoreLoggerProvider, network: Network, zone: NgZone, private navCtrl: NavController,
|
||||
private chatProvider: AddonModChatProvider, private appProvider: CoreAppProvider, sitesProvider: CoreSitesProvider,
|
||||
|
@ -63,7 +69,7 @@ export class AddonModChatChatPage {
|
|||
this.courseId = navParams.get('courseId');
|
||||
this.title = navParams.get('title');
|
||||
this.logger = logger.getInstance('AddonModChoiceChoicePage');
|
||||
this.currentUserBeep = 'beep ' + sitesProvider.getCurrentSiteUserId();
|
||||
this.currentUserId = sitesProvider.getCurrentSiteUserId();
|
||||
this.isOnline = this.appProvider.isOnline();
|
||||
this.onlineObserver = network.onchange().subscribe(() => {
|
||||
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
||||
|
@ -127,11 +133,14 @@ export class AddonModChatChatPage {
|
|||
|
||||
modal.onDidDismiss((data) => {
|
||||
if (data && data.talkTo) {
|
||||
this.newMessage = `To ${data.talkTo}: `;
|
||||
this.newMessage = `To ${data.talkTo}: ` + this.sendMessageForm.message;
|
||||
}
|
||||
if (data && data.beepTo) {
|
||||
this.sendMessage('', data.beepTo);
|
||||
}
|
||||
if (data && data.users) {
|
||||
this.users = data.users;
|
||||
}
|
||||
});
|
||||
|
||||
modal.present({
|
||||
|
@ -139,6 +148,38 @@ export class AddonModChatChatPage {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user fullname for a beep.
|
||||
*
|
||||
* @param id User Id before parsing.
|
||||
* @return User fullname.
|
||||
*/
|
||||
protected getUserFullname(id: string): Promise<string> {
|
||||
if (isNaN(parseInt(id, 10))) {
|
||||
return Promise.resolve(id);
|
||||
}
|
||||
|
||||
const user = this.users.find((user) => user.id == id);
|
||||
|
||||
if (user) {
|
||||
return Promise.resolve(user.fullname);
|
||||
}
|
||||
|
||||
return this.chatProvider.getChatUsers(this.sessionId).then((data) => {
|
||||
this.users = data.users;
|
||||
const user = this.users.find((user) => user.id == id);
|
||||
|
||||
if (user) {
|
||||
return user.fullname;
|
||||
}
|
||||
|
||||
return id;
|
||||
}).catch((error) => {
|
||||
// Ignore errors.
|
||||
return id;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to login the user.
|
||||
*
|
||||
|
@ -160,8 +201,33 @@ export class AddonModChatChatPage {
|
|||
this.lastTime = messagesInfo.chatnewlasttime || 0;
|
||||
|
||||
return this.chatProvider.getMessagesUserData(messagesInfo.messages, this.courseId).then((messages) => {
|
||||
this.messages = this.messages.concat(<AddonModChatMessageWithUserData[]> messages);
|
||||
if (messages.length) {
|
||||
const previousLength = this.messages.length;
|
||||
this.messages = this.messages.concat(<AddonModChatMessageWithUserData[]> messages);
|
||||
|
||||
// Calculate which messages need to display the date or user data.
|
||||
for (let index = previousLength ; index < this.messages.length; index++) {
|
||||
const message = this.messages[index];
|
||||
const prevMessage = index > 0 ? this.messages[index - 1] : null;
|
||||
|
||||
message.showDate = this.showDate(message, prevMessage);
|
||||
message.beep = message.message.substr(0, 5) == 'beep ' && message.message.substr(5).trim();
|
||||
|
||||
if (message.beep && message.beep != this.currentUserId) {
|
||||
this.getUserFullname(message.beep).then((fullname) => {
|
||||
message.beepwho = fullname;
|
||||
});
|
||||
}
|
||||
|
||||
message.special = message.system || !!message.beep;
|
||||
|
||||
message.showUserData = this.showUserData(message, prevMessage);
|
||||
prevMessage ?
|
||||
prevMessage.showTail = this.showTail(prevMessage, message) : null;
|
||||
}
|
||||
|
||||
this.messages[this.messages.length - 1].showTail = true;
|
||||
|
||||
// New messages or beeps, scroll to bottom.
|
||||
setTimeout(() => this.scrollToBottom());
|
||||
}
|
||||
|
@ -196,6 +262,30 @@ export class AddonModChatChatPage {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the user info should be displayed for the current message.
|
||||
* User data is only displayed if the previous message was from another user.
|
||||
*
|
||||
* @param message Current message where to show the user info.
|
||||
* @param prevMessage Previous message.
|
||||
* @return Whether user data should be shown.
|
||||
*/
|
||||
showUserData(message: any, prevMessage?: any): boolean {
|
||||
return message.userid != this.currentUserId &&
|
||||
(!prevMessage || prevMessage.userid != message.userid || message.showDate || prevMessage.special);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a css tail should be shown.
|
||||
*
|
||||
* @param message Current message where to show the user info.
|
||||
* @param nextMessage Next message.
|
||||
* @return Whether user data should be shown.
|
||||
*/
|
||||
showTail(message: any, nextMessage?: any): boolean {
|
||||
return !nextMessage || nextMessage.userid != message.userid || nextMessage.showDate || nextMessage.special;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to be called every certain time to fetch chat messages.
|
||||
*
|
||||
|
@ -259,9 +349,8 @@ export class AddonModChatChatPage {
|
|||
// Silent error.
|
||||
return;
|
||||
}
|
||||
text = this.textUtils.replaceNewLines(text, '<br>');
|
||||
|
||||
const modal = this.domUtils.showModalLoading('core.sending', true);
|
||||
this.sending = true;
|
||||
this.chatProvider.sendMessage(this.sessionId, text, beep).then(() => {
|
||||
// Update messages to show the sent message.
|
||||
this.fetchMessagesInterval().catch(() => {
|
||||
|
@ -272,9 +361,12 @@ export class AddonModChatChatPage {
|
|||
messages without the keyboard being closed. */
|
||||
this.appProvider.closeKeyboard();
|
||||
|
||||
this.newMessage = text;
|
||||
|
||||
this.domUtils.showErrorModalDefault(error, 'addon.mod_chat.errorwhilesendingmessage', true);
|
||||
}).finally(() => {
|
||||
modal.dismiss();
|
||||
this.sending = false;
|
||||
this.sendMessageForm.focus();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ export class AddonModChatUsersPage {
|
|||
* Close the chat users modal.
|
||||
*/
|
||||
closeModal(): void {
|
||||
this.viewCtrl.dismiss();
|
||||
this.viewCtrl.dismiss({users: this.users});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -77,8 +77,8 @@ export class AddonModChatUsersPage {
|
|||
*
|
||||
* @param user User object.
|
||||
*/
|
||||
talkTo(user: AddonModChatUser): void {
|
||||
this.viewCtrl.dismiss({talkTo: user.fullname});
|
||||
talkTo(user: AddonModChatUser): void {
|
||||
this.viewCtrl.dismiss({talkTo: user.fullname, users: this.users});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -87,7 +87,7 @@ export class AddonModChatUsersPage {
|
|||
* @param user User object.
|
||||
*/
|
||||
beepTo(user: AddonModChatUser): void {
|
||||
this.viewCtrl.dismiss({beepTo: user.id});
|
||||
this.viewCtrl.dismiss({beepTo: user.id, users: this.users});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -432,10 +432,12 @@
|
|||
"addon.mod_chat.errorwhilegettingchatusers": "Error while getting chat users.",
|
||||
"addon.mod_chat.errorwhileretrievingmessages": "Error while retrieving messages from the server.",
|
||||
"addon.mod_chat.errorwhilesendingmessage": "Error while sending the message.",
|
||||
"addon.mod_chat.messagebeepseveryone": "{{$a}} beeps everyone!",
|
||||
"addon.mod_chat.messagebeepsyou": "{{$a}} has just beeped you!",
|
||||
"addon.mod_chat.messageenter": "{{$a}} has just entered this chat",
|
||||
"addon.mod_chat.messageexit": "{{$a}} has left this chat",
|
||||
"addon.mod_chat.messages": "Messages",
|
||||
"addon.mod_chat.messageyoubeep": "You beeped {{$a}}",
|
||||
"addon.mod_chat.modulenameplural": "Chats",
|
||||
"addon.mod_chat.mustbeonlinetosendmessages": "You must be online to send messages.",
|
||||
"addon.mod_chat.nomessages": "No messages yet",
|
||||
|
|
|
@ -60,7 +60,8 @@ ion-app.app-root core-ion-tabs {
|
|||
}
|
||||
}
|
||||
|
||||
.scroll-content, .fixed-content {
|
||||
ion-content:not(.has-footer) > .scroll-content,
|
||||
ion-content:not(.has-footer) > .fixed-content {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<form>
|
||||
<textarea class="core-send-message-input" [core-auto-focus]="showKeyboard" [placeholder]="placeholder" rows="1" core-auto-rows [(ngModel)]="message" name="message" (onResize)="textareaResized()" (keydown.enter)="enterClicked($event)" (keydown.control.enter)="enterClicked($event, 'control')" (keydown.meta.enter)="enterClicked($event, 'meta')" aria-multiline="true"></textarea>
|
||||
<ion-buttons end>
|
||||
<button ion-button icon-only clear="true" type="submit" [disabled]="!message" [attr.aria-label]="'core.send' | translate" [core-suppress-events] (onClick)="submitForm($event)">
|
||||
<button ion-button icon-only clear="true" type="submit" [disabled]="!message || sendDisabled" [attr.aria-label]="'core.send' | translate" [core-suppress-events] (onClick)="submitForm($event)">
|
||||
<ion-icon name="send" color="dark"></ion-icon>
|
||||
</button>
|
||||
</ion-buttons>
|
||||
|
|
|
@ -19,6 +19,7 @@ import { CoreEventsProvider } from '@providers/events';
|
|||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreConstants } from '@core/constants';
|
||||
|
||||
/**
|
||||
|
@ -39,13 +40,15 @@ export class CoreSendMessageFormComponent implements OnInit {
|
|||
@Input() message: string; // Input text.
|
||||
@Input() placeholder = ''; // Placeholder for the input area.
|
||||
@Input() showKeyboard = false; // If keyboard is shown or not.
|
||||
@Input() sendDisabled = false; // If send is disabled.
|
||||
@Output() onSubmit: EventEmitter<string>; // Send data when submitting the message form.
|
||||
@Output() onResize: EventEmitter<void>; // Emit when resizing the textarea.
|
||||
|
||||
protected sendOnEnter: boolean;
|
||||
|
||||
constructor(private utils: CoreUtilsProvider, private textUtils: CoreTextUtilsProvider, configProvider: CoreConfigProvider,
|
||||
eventsProvider: CoreEventsProvider, sitesProvider: CoreSitesProvider, private appProvider: CoreAppProvider) {
|
||||
eventsProvider: CoreEventsProvider, sitesProvider: CoreSitesProvider, private appProvider: CoreAppProvider,
|
||||
private domUtils: CoreDomUtilsProvider) {
|
||||
|
||||
this.onSubmit = new EventEmitter();
|
||||
this.onResize = new EventEmitter();
|
||||
|
@ -99,6 +102,10 @@ export class CoreSendMessageFormComponent implements OnInit {
|
|||
* @param other The name of the other key that was clicked, undefined if no other key.
|
||||
*/
|
||||
enterClicked(e: Event, other: string): void {
|
||||
if (this.sendDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.sendOnEnter && !other) {
|
||||
// Enter clicked, send the message.
|
||||
this.submitForm(e);
|
||||
|
|
Loading…
Reference in New Issue