diff --git a/web/static/js/api.js b/web/static/js/api.js index 7baa4ad..7869859 100644 --- a/web/static/js/api.js +++ b/web/static/js/api.js @@ -1,218 +1,222 @@ import {Socket, LongPoll, Presence} from "phoenix" import UserListWidget from "./widgets/userlist" import UserStatusWidget from "./widgets/userstatus" import ChatInputWidget from "./widgets/chatinput" import ChatRoomWidget from "./widgets/chatroom" class KolabChat { /** * Configuration parameters: * - token: User session token * - context: KolabChat instance identifier * - roomId: Chat room Id to join in * - userListElement: Id of HTML element where to put userslist widget * - userStatusElement: Id of HTML element where to put users status widget * - chatInputElement: Id of HTML element which is a text chat input * - chatRoomElement: Id of HTML element where to put text conversation */ constructor(config) { this.config = config || {} if (!this.config.context) this.config.context = location.hostname; } /** * Initialize WebSocket communication */ init(config) { if (config) this.config = KolabChat.extend(this.config, config) this.initWidgets() // TODO: for integration with external systems we'll use configurable full wss:// url this.socket = new Socket("/socket", { params: {token: this.config.token, context: this.config.context}, logger: ((kind, msg, data) => { console.log(`${kind}: ${msg}`, data) }), }) this.socket.onOpen(e => { // when connected start using 'system' channel // for users' presence this.initPresence() if (this.config.roomId) { this.initRoom(this.config.roomId) } }) this.socket.connect() } /** * Initializes configured UI widgets */ initWidgets() { let config if (this.config.userListElement && $('#' + this.config.userListElement).length) { config = { username: this.username, openChat: (e, user) => { this.openChat(e, user) } } this.userListWidget = new UserListWidget(this.config.userListElement, config) } if (this.config.userStatusElement && $('#' + this.config.userStatusElement).length) { config = { username: this.username, statusChange: status => { this.setStatus(status) } } this.userStatusWidget = new UserStatusWidget(this.config.userStatusElement, config) } if (this.config.chatRoomElement && $('#' + this.config.chatRoomElement).length) { this.chatRoomWidget = new ChatRoomWidget(this.config.chatRoomElement) } if (this.config.chatInputElement && $('#' + this.config.chatInputElement).length) { config = { submit: (e, msg) => { this.sendTxtMessage(e, msg) } } this.chatInputWidget = new ChatInputWidget(this.config.chatInputElement, config) } } /** * Initialize user presence * Create users list and status widgets */ initPresence() { this.system = this.socket.channel("system", {context: this.config.context}) this.system.on("info", info => { this.username = info.user + + if (this.userListWidget) { + this.userListWidget.setUsername(this.username) + } }) this.system.on("presence_state", state => { this.presences = Presence.syncState({}, state) this.renderPresences(this.presences) }) this.system.on("presence_diff", diff => { // ignore initial presence_diff result, handle presence_state first if (this.presences !== undefined) { this.presences = Presence.syncDiff(this.presences, diff) this.renderPresences(this.presences) } }) this.system.join() } /** * Initialize chat channel */ initRoom(roomId) { this.chat = this.socket.channel("room:" + roomId) this.chat.on("new:message", message => { this.chatRoomWidget.append(message.user, message.body) }) this.chat.join() } /** * Send text message to the chat room */ sendTxtMessage(event, message) { this.chat.push("new:message", { user: this.username, // TODO: this is not really needed body: message }) } /** * Handler for presence responses */ renderPresences(presences) { let userPresence if (this.userStatusWidget && (userPresence = presences[this.username])) { userPresence = this.listBy(this.username, userPresence, this.config.context) this.userStatusWidget.render(userPresence) } if (this.userListWidget) { presences = Presence.list(presences, this.listBy) this.userListWidget.render(presences) } } listBy(user, {metas: metas}, context) { let statusWeights = { offline: 0, busy: 10, away: 20, online: 30 } // Find "best" availability status for the user // If set, narrow the result to the current session context let mostAvailableStatus = metas.reduce((best, meta) => { if (context && context != meta.context) return best return statusWeights[best] > statusWeights[meta.status] ? best : meta.status }, "offline") return { user: user, status: mostAvailableStatus } } /** * User status change */ setStatus(status) { this.system.push('set-status', {status: status}); } /** * Open chat window (and create a new chat room) */ openChat(event, user) { // TODO: Use 'system' channel to create a chat room first let roomId = "lobby" let windowName = 'KolabChat' + new Date().getTime() let url = "/chat/" + encodeURIComponent(roomId) + "/?token=" + encodeURIComponent(this.config.token) var extwin = window.open(url, windowName); } static extend(obj, src) { Object.keys(src).forEach(function(key) { obj[key] = src[key] }) return obj } } export default KolabChat diff --git a/web/static/js/widgets/userlist.js b/web/static/js/widgets/userlist.js index a55f6f5..4b2b08a 100644 --- a/web/static/js/widgets/userlist.js +++ b/web/static/js/widgets/userlist.js @@ -1,62 +1,70 @@ class UserListWidget { /** * Configuration: * - username: Current user name * - openChat: callback for "Open chat" button */ constructor(id, config) { this.config = config || {} this.id = id } + setUsername(username) + { + this.config.username = username + } + + /** * Render users list */ render(presences) { let list = $('#' + this.id) let config = this.config let html = presences.map(presence => { + if (presence.user != config.username) { let buttons = this.buttons(presence) - return ` -
  • - ${presence.user} - ${buttons} -
  • ` + return ` +
  • + ${presence.user} + ${buttons} +
  • ` + } }) .join("") list.html(html) $('button', list).on('click', function(e) { let action = $(this).data('action') if (action && config[action]) { config[action](e, $(this).parents('li').data('user')) } }) } /** * Render users list record buttons */ buttons(presence) { let buttons = '' if (this.config.openChat) { // && presence.user != this.config.username) { let btn_name = ' Open chat' buttons += `` } if (buttons) { buttons = '
    ' + buttons + '
    ' } return buttons } } export default UserListWidget