API Version: Development
/* API is ready, loop through the list of contacts */
IPCortex.PBX.contacts.forEach(
function(contact) {
/* Listen for updates in case the user changes state */
contact.addListener('update', function() {
processContact(contact);
});
processContact(contact);
}
);
/*
* Enable chat subsystem. This call provides a shortcut for providing a new-room callback.
* Enabling chat automatically makes the current user 'online'
*/
console.log(TAG, 'Chat enable');
IPCortex.PBX.enableChat(processRoom);
processContact()
which manages the contact's presence in the DOM based on their availability.IPCortex.PBX.enableChat()
is called with a callback parameter of processRoom
. This both enables the chat subsystem and sets a new-room listener event to call processRoom
. An alternate mechanism for detecting new chat rooms is used in the Video Client sample.processContact()
:function processContact(contact) {
/* Return early if this is "myself" */
if ( contact.cID == IPCortex.PBX.Auth.id ) {
return;
}
/* Return early if contact exists */
var element = document.getElementById(contact.cID);
if ( element ) {
/* Remove offline contacts */
if ( ! contact.canChat && element.parentNode )
element.parentNode.removeChild(element);
return;
}
/* Create online contact */
if ( contact.canChat ) {
var element = document.createElement('div');
document.getElementById('contacts').appendChild(element);
element.innerHTML = contact.name;
element.className = 'contact';
element.id = contact.cID;
var offer = document.createElement('i');
element.appendChild(offer);
offer.className = 'material-icons contact-offer';
offer.innerHTML = 'chat_bubble';
offer.addEventListener('click', function() {
contact.chat();
});
}
}
contact.canChat
) then the contact should be removed from the webpage.contact.chat()
- Because of Javascript closure and scope rules (read this if you need to brush up), each 'click' event will reference the correct contact object, and therefore call the correct chat()
method with no further processing.processRoom()
is called whenever a new room is created, and we can break it down into smaller chunks as follows:function processRoom(newRoom) {
/*
* 1 - Add a listener for all future room updates, such as new messages.
* 2 - Handle the creation of the new room in the DOM
* 3 - Save some useful information about the room
* 4 - Enable room specific 'click' events for the room buttons.
*/
}
addListener
being used on the new room to register for 'update' events. In this case, the events we handle are the 'death' of the room, in which case it is removed from the DOM; the setting or changing of the room name, which is injected into the DOM; and the arrival of messages which are placed into the <textarea>
.thisRoom
variable, making the use of the global room
object un-necessary. The technique of storing the data externally is used, because a larger scale application would quickly become unwieldy if all such functions were declared inline as below.newRoom.addListener('update', function(room) {
/* If a room is dead, delete from DOM */
if ( rooms[room.roomID] && room.state == 'dead' ) {
rooms[room.roomID].elem.parentNode.removeChild(rooms[room.roomID].elem);
delete rooms[room.roomID];
return;
}
/* If room name has changed, update on display */
if ( rooms[room.roomID].label !== room.label ) {
rooms[room.roomID].label = room.label;
rooms[room.roomID].title.innerHTML = room.label + ' (' + newRoom.roomID + ')';
}
/* Add new messages into textarea */
room.messages.forEach(function (message) {
rooms[room.roomID].text.value += '\n' + message.cN + ' :\n ' + message.msg;
rooms[room.roomID].text.scrollTop = rooms[room.roomID].text.scrollHeight;
});
});
<div>
is cloned and then updated to have a unique ID./* For each new room we need to store the provided Class object
* and create display elements
*/
var elem = document.getElementById('clone').cloneNode(true);
elem.style.display = 'block';
elem.id = newRoom.roomID;
document.body.appendChild(elem);
/* Store important room info needed as events occur */
var thisRoom = rooms[newRoom.roomID] = {
room: newRoom,
elem: elem,
title: elem.getElementsByTagName('div')[0],
text: elem.getElementsByTagName('textarea')[0]
};
thisRoom
declared in part 3 above will remain in scope for the life of the room, allowing it to be referenced within the 'click' events for the 'close' and 'send' buttons.room.leave()
which will subsequently cause a 'dead' update event to arrive and clean up the room. Similarly the sent message is not put into the textarea, but instead it is sent with room.post()
, and will arrive through the update event to be handled accordingly./* Quick way to get hold of input box and submit buttons */
var inputs = elem.getElementsByTagName('input');
inputs[0].addEventListener('click', function() {
console.log(TAG, 'Close room', thisRoom.room.roomID);
thisRoom.room.leave();
});
inputs[2].addEventListener('click', function() {
console.log(TAG, 'Send message on room', thisRoom.room.roomID);
/* No text entered, nothing to send */
if ( ! inputs[1].value )
return;
/* Send the message and clear the input */
thisRoom.room.post(inputs[1].value);
inputs[1].value = '';
});