Я играю с веб-сокетами Coldfusion 10 и создал простой чат для тестирования. Я видел несколько чатов, в которых текст «пользователь печатает...», который появляется, когда другой пользователь печатает. Кто-нибудь знает, как это реализовать эффективно?
Coldfusion Websockets Пользователь вводит Функциональность
Ответы (2)
Создайте еще один канал «уведомление» и опубликуйте в нем «Пользователь печатает», когда пользователь делает «keyDown», и «пустая строка», когда «keyUp».
Подпишитесь на этот канал вместе с вашим чатом. целью этого канала на стороне получателя должен быть внутренний HTML-код, который может быть заполнен сообщением «Пользователь печатает».
Псевдокод:
<cfwebsocket name="notificationSocket"
onmessage="notifyHandler"
subscribeto="notificationChannel" >
<cfwebsocket name="ChatSocket"
onmessage="chatHandler"
subscribeto="chatChannel" >
<!-- Conversation displayer -->
<div id="messageBoard"></div>
<!-- your text message input area -->
<textarea onKeyDown="sayTyping()" onKeyUp="sayStopped()" id="chatInput"></textarea>
<div id="notifyArea"></div>
<input name="submit" onClick="publishMessage()"></textarea>
<script>
/*chat Functions*/
var publishMessage = function(){
var msg = document.getElementById('chatInput').value;
mycfwebsocketobject.publish("chatChannel", msg );
};
var chatHandler = function(msgObj){
document.getElementById('messageBoard').innerHTML += ColdFusion.JSON.encode(msgObj);
};
/*notifying Functions*/
var notifyHandler = function(noteObj){
document.getElementById('notifyArea').innerHTML = ColdFusion.JSON.encode(noteObj);
};
var sayTyping = function(){
mycfwebsocketobject.publish("notificationchannel","User is Typing..." );
};
var sayStopped = function(){
mycfwebsocketobject.publish("notificationchannel","" );
};
</script>
Еще одним улучшением будет наличие div уже с текстом «пользователь вводит», и ваш канал транслирует текст как «показать» и «не показать». По сути, это имя класса, данное для отображения и скрытия. Меньше трафика.
Подход 2: Использование одного и того же канала
<cfwebsocket name="ChatSocket"
onmessage="chatHandler"
subscribeto="chatChannel" >
<!-- Conversation displayer -->
<div id="messageBoard"></div>
<!-- your text message input area -->
<textarea onKeyDown="sayTyping()" onKeyUp="sayStopped()" id="chatInput"></textarea>
<div id="notifyArea" class="no">User is typing...</div>
<input name="submit" onClick="publishMessage()"></textarea>
<script>
/*chat Functions*/
var publishMessage = function(){
var msg = document.getElementById('chatInput').value;
mycfwebsocketobject.publish("chatChannel", msg );
};
var chatHandler = function(msgObj){
var msg = ColdFusion.JSON.encode(msgObj);
if (msg == '@userTyping@-yes'){
notifyHandler('yes');
}
else if (msg == '@userTyping@-no'){
notifyHandler('no');
}
else {
document.getElementById('messageBoard').innerHTML += msg;
}
};
/*notifying Functions*/
var notifyHandler = function(action){
document.getElementById('notifyArea').className = action;
/*call the notify handler with off to stop showing the user is typing message
after a certain interval of time. This is to avoid someone believing that
partner is still typing even when the connection is lost*/
if(action == 'on'){
setTimeout(function(){notifyHandler('no')},250);
}
};
var sayTyping = function(){
mycfwebsocketobject.publish("chatChannel","@userTyping@-yes" );
};
var sayStopped = function(){
mycfwebsocketobject.publish("chatChannel","@userTyping@-no" );
};
</script>
<style>
.yes { display:block;}
.no { display:none;}
</style>
Всегда можно обмануть этот код, набрав сообщение «@userTyping@-yes» или «@userTyping@-no». Но, как я уже сказал, это всего лишь POC. Кроме того, для упомянутого вами тайм-аута keyUp все равно позаботится об этом. Но вы также можете вызвать notifyHandler() с помощью setTimeout(), как показано выше.
В комментариях есть вопрос о том, как фильтровать сообщения один на один. Вот пример кода для достижения этого.
Вместо использования атрибута subscribeTo
используйте функцию js для подписки пользователя и передачи некоторых значений заголовка. Затем эти заголовки можно использовать в качестве фильтров в вызове публикации с помощью selector
.
Пример:
<cfwebsocket name="ChatSocket" onOpen="openHandler" onMessage="msgHandler" onError="errHandler">
<script>
function openHandler(){
//Subscribe to the channel, pass in headers for filtering later
ChatSocket.subscribe('chatChannel',{name: '#Session.Auth.FirstName#', UserID: '#Session.Auth.UserID#', AccountID: '#Session.Auth.AccountID#' });
}
function publish(txt, userID){
var msg = {
AccountID: "#Session.Auth.AccountID#",
publisher: '#Session.Auth.UserID#',
id: userID,
message: converthtml(txt)
};
//When including headers, the "selector" is where you will filter who it goes to.
var headers = {
AccountID: "#Session.Auth.AccountID#",
publisher: '#Session.Auth.UserID#',
id: userID,
selector: "UserID eq '"+userID+"' and AccountID eq '#Session.Auth.AccountID#'"
};
ChatSocket.publish('chatChannel',msg, headers);
}
function msgHandler(message){
console.log(message);
}
function errHandler(err){
console.log(err);
}
</script>