Anton Shestakov <av6@dwimlabs.net>, Wed, 06 Apr 2016 22:21:47 +0800
index: sending chat messages to other contacts
coffee/index.coffee
Permissions: -rw-r--r--
Strophe.addNamespace('LAST', 'jabber:iq:last') Strophe.addNamespace('TIME', 'urn:xmpp:time') Strophe.addNamespace('VCARD_UPDATE', 'vcard-temp:x:update') class window.Tram.ClientState extends Backbone.Model window.contacts ?= new Tram.Contacts() window.contactsApp ?= new Tram.ContactsApp(el: $('[data-app="contacts"]'), collection: contacts) window.calls ?= new Tram.Calls() window.callsApp ?= new Tram.CallsApp(el: $('[data-app="calls"]'), collection: calls) window.clientState ?= new Tram.ClientState() window.faviconApp ?= new Tram.FaviconApp(model: clientState) window.sidebarApp ?= new Tram.SidebarApp(el: $('[data-app="sidebar"]'), model: clientState) contacts.on 'change:show', (model) -> if model.get('type') is 'self' clientState.set('show', model.get('show')) clientState.on 'show', (show, status) -> X.conn.send($pres().c('priority').t('1').up().c('show').t(show).up().c('status').t(status).tree()) clientState.on 'disconnect', -> X.disconnect('Logged out') clientState.on 'change:contact', -> contact = clientState.get('contact') $logs = $('[data-app="logs"]') $logs.children().detach() $logs.append(contact.chat.render().el) $('[data-form="send"]').toggleClass('uk-hidden', not clientState.has('contact')) X.conn.addHandler(onPresence, null, 'presence') X.conn.addHandler(onProfileUpdate, Strophe.NS.VCARD_UPDATE, 'presence') X.conn.addHandler(onChatMessage, null, 'message', 'chat') X.conn.addHandler(onWebRTC, Tram.NS.WEBRTC, 'message', 'chat') X.conn.addHandler(onGetLast, Strophe.NS.LAST, 'iq', 'get') X.conn.addHandler(onGetTime, Strophe.NS.TIME, 'iq', 'get') X.conn.addHandler(onGetVersion, Strophe.NS.VERSION, 'iq', 'get') X.conn.ping.addPingHandler(onPing) X.conn.disco.addIdentity('client', 'web', Tram.info.client) X.conn.disco.addFeature(Strophe.NS.DISCO_INFO) X.conn.disco.addFeature(Strophe.NS.LAST) X.conn.disco.addFeature(Strophe.NS.PING) X.conn.disco.addFeature(Strophe.NS.TIME) X.conn.disco.addFeature(Strophe.NS.VERSION) X.conn.disco.addFeature(Tram.NS.WEBRTC) X.conn.send($pres().c('priority').t('1').up().c('status').t('Online').tree()) if el.childNodes.length is 0 and el.nodeType is Strophe.ElementType.TEXT for node in el.childNodes if node.nodeType is Strophe.ElementType.TEXT iq = $iq(type: 'get', id: X.conn.getUniqueId('version'), to: Tram.config.domain).c('query', xmlns: Strophe.NS.VERSION) name = getText(stanza.getElementsByTagName('name')[0]) version = getText(stanza.getElementsByTagName('version')[0]) os = getText(stanza.getElementsByTagName('os')[0]) 'server/version': version console.error("couldn't get version", stanza?.innerHTML) X.conn.sendIQ(iq.tree(), okcb, failcb, 5000) id = stanza.getAttribute('id') from = stanza.getAttribute('from') iq = $iq(to: from, type: 'result', id: id) .c('query', xmlns: Strophe.NS.VERSION, seconds: '0') id = stanza.getAttribute('id') from = stanza.getAttribute('from') iq = $iq(to: from, type: 'result', id: id) .c('time', xmlns: Strophe.NS.TIME) .c('tzo').t(now.format('Z')).up() .c('utc').t(now.toISOString()) onGetVersion = (stanza) -> id = stanza.getAttribute('id') from = stanza.getAttribute('from') iq = $iq(to: from, type: 'result', id: id) .c('query', xmlns: Strophe.NS.VERSION) .c('name').t(Tram.info.client).up() .c('version').t(Tram.info.version) chats[jid] ?= new Tram.LogApp(collection: new Tram.Messages()) contact = contacts.get(from) self = from is X.conn.jid model.set('type', 'contact') bjid = Strophe.getBareJidFromJid(from) type: if self then 'self' else 'contact' contact.chat = getChat(bjid) clientState.set('contact', contact) contact.on 'authorize', -> X.conn.roster.authorize(contact.get('bjid')) contact.on 'unauthorize', -> X.conn.roster.unauthorize(contact.get('bjid')) X.conn.roster.remove contact.get('bjid'), -> contact.w = new Tram.WebRTCInterface(contact) contact.on 'call', (media) -> contact.set('callstate', 'outgoing') contact.w.init(true, audio: 'a' in media, video: 'v' in media) contact.on 'accept', (media) -> contact.w.init(false, audio: 'a' in media, video: 'v' in media) contact.on 'decline hangup', -> contact.w.sendIntent('terminate') contact.unset('callstate') getContactProfile(contact) getContactProfile = (contact) -> vcard = stanza.getElementsByTagName('vCard')[0] console.warn("no vcard in response", stanza) nickname: getText(vcard.querySelector('NICKNAME')) fullname: getText(vcard.querySelector('FN')) firstname: getText(vcard.querySelector('N > GIVEN')) lastname: getText(vcard.querySelector('N > FAMILY')) mime = getText(vcard.querySelector('PHOTO > TYPE')) data = getText(vcard.querySelector('PHOTO > BINVAL')) contact.set('avatar', mime: mime, data: data) console.warn("couldn't get vcard", stanza) bjid = contact.get('bjid') if bjid is Strophe.getBareJidFromJid(X.conn.jid) X.conn.vcard.get(okcb, bjid, failcb) type = stanza.getAttribute('type') ? 'available' when 'subscribed', 'unsubscribe', 'unsubscribed' console.warn("""not handling <presence type="#{ type }">""", stanza) console.error('got <presence type="error">', stanza) from = stanza.getAttribute('from') contact = getContact(from) show = getText(stanza.getElementsByTagName('show')[0]) status = getText(stanza.getElementsByTagName('status')[0]) priority = getText(stanza.getElementsByTagName('priority')[0]) if type in ['available', 'unavailable'] and contact.get('type') isnt 'self' delay = stanza.getElementsByTagName('delay')[0] stamp = if delay? then new Date(delay.getAttribute('stamp')) else new Date() contact.chat.collection.add id: stanza.getAttribute('id') text: status ? "is now #{ show }" onProfileUpdate = (stanza) -> from = stanza.getAttribute('from') contact = getContact(from) getContactProfile(contact) onChatMessage = (stanza) -> from = stanza.getAttribute('from') type = stanza.getAttribute('type') text = getText(stanza.getElementsByTagName('body')[0]) thread = getText(stanza.getElementsByTagName('thread')[0]) delay = stanza.getElementsByTagName('delay')[0] stamp = if delay? then new Date(delay.getAttribute('stamp')) else new Date() contact = getContact(from) contact.chat.collection.add id: stanza.getAttribute('id') from = stanza.getAttribute('from') contact = getContact(from) intent = stanza.getElementsByTagName('intent')[0] payload = stanza.getElementsByTagName('payload')[0] delay = stanza.getElementsByTagName('delay')[0] stamp = if delay? then new Date(delay.getAttribute('stamp')) else new Date() contact.set('callstate', 'incoming') contact.chat.collection.add id: stanza.getAttribute('id') contact.unset('callstate') contact.w.onPayload(stanza) window.X = new Tram.XMPPInterface() connData.unset('auth-errors') connData.set('auth-errors', ['Invalid username or password.']) $('[data-step="login"]').removeClass('uk-hidden') $('[data-step="main"]').addClass('uk-hidden') X.on 'connected attached', -> $('[data-step="login"]').addClass('uk-hidden') $('[data-step="main"]').removeClass('uk-hidden') $(window).on 'beforeunload unload', -> X.disconnect('Window closed') class ConnectionData extends Backbone.Model validate: (attrs, options) -> @unset('username-errors') @unset('password-errors') if (attrs.username ? '').trim() is '' @set('username-errors', ['This field is required.']) if (attrs.password ? '') is '' @set('password-errors', ['This field is required.']) return @has('username-errors') or @has('password-errors') window.connData = new ConnectionData() X.connect(connData.get('username').trim(), connData.get('password')) $form = $('[data-form="connect"]') window.connRivet = rivets.bind($form.get(0), data: connData, connect: connectfn) $form.find('input').on 'keydown', (e) -> if (not @required or @value isnt '') and e.keyCode is 13 index = $form.find('input').index(@) $next = $form.find('input').eq(index + 1) $form.find('button').trigger('click') if text isnt '' and clientState.has('contact') contact = clientState.get('contact') X.conn.send($msg(to: contact.get('jid'), from: X.conn.jid, type: 'chat').c('body').t(text).tree()) contact.chat.collection.add contact: contacts.findWhere(type: 'self') $('[data-send-button]').on 'click', sendMessage $('#msg').on 'keypress', (e) -> $('[data-add-button]').on 'click', -> jid = $('#new-contact').val().trim() jid = "#{ jid }@#{ Tram.config.domain }" $('#new-contact').val('') X.conn.roster.add jid, null, [], -> X.conn.roster.subscribe(jid, 'I want to chat', null) $('#new-contact').on 'keypress', (e) -> $('[data-add-button]').trigger('click') $('time[datetime]').each -> $this.text(moment($this.attr('datetime')).fromNow())