39:28ad6d3e2618
Anton Shestakov <av6@dwimlabs.net>, Wed, 23 Mar 2016 16:55:52 +0800
index: maintain only one contact with type 'self' This isn't done in an event handler of contacts collection because doing it in 'add' handler would trigger 'sort' event after the model has been added, but before its 'add' event has propagated, and that's dumb.

next change 41:260f3df482df
previous change 37:16b1f46f4cbf

coffee/index.coffee

Permissions: -rw-r--r--

Other formats: Feeds:
Strophe.addNamespace('VCARD_UPDATE', 'vcard-temp:x:update')
window.contacts ?= new Tram.Contacts()
window.contactsApp ?= new Tram.ContactsApp(el: $('[data-app="contacts"]'), collection: contacts)
window.messages ?= new Tram.Messages()
window.logApp ?= new Tram.LogApp(el: $('[data-app="log"]'), collection: messages)
onConnected = ->
X.conn.addHandler(onPresence, null, 'presence')
X.conn.addHandler(onProfileUpdate, Strophe.NS.VCARD_UPDATE, 'presence')
X.conn.addHandler(onGetVersion, Strophe.NS.VERSION, 'iq', 'get')
X.conn.send($pres().c('priority').t('1').up().c('status').t('Online').tree())
getVersion()
getText = (el) ->
if not el
return null
str = ''
if el.childNodes.length is 0 and el.nodeType is Strophe.ElementType.TEXT
str += el.nodeValue
for node in el.childNodes
if node.nodeType is Strophe.ElementType.TEXT
str += node.nodeValue
return str
getVersion = ->
iq = $iq(type: 'get', id: X.conn.getUniqueId('version'), to: Tram.config.domain).c('query', xmlns: Strophe.NS.VERSION)
okcb = (stanza) ->
name = getText stanza.getElementsByTagName('name')[0]
version = getText stanza.getElementsByTagName('version')[0]
os = getText stanza.getElementsByTagName('os')[0]
delay = stanza.getElementsByTagName('delay')[0]
stamp = if delay then new Date(delay.getAttribute('stamp')) else new Date()
messages.add
id: stanza.getAttribute('id')
type: stanza.getAttribute('type')
from: stanza.getAttribute('from')
stamp: stamp
cls: 'info'
name: name
version: version
os: os
text: "connected to #{ name } #{ version } on #{ os }"
failcb = (stanza) ->
console.error("couldn't get version", stanza?.innerHTML)
X.conn.sendIQ(iq.tree(), okcb, failcb, 5000)
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)
X.conn.send(iq.tree())
return true
getContact = (from) ->
contact = contacts.get(from)
if contact?
return contact
self = from is X.conn.jid
if self
contacts.each (model) ->
model.set('type', 'contact')
contact = contacts.add
jid: from
bjid: Strophe.getBareJidFromJid(from)
type: if self then 'self' else 'contact'
getContactProfile(contact)
return contact
getContactProfile = (contact) ->
okcb = (stanza) ->
vcard = stanza.getElementsByTagName('vCard')[0]
if !vcard
console.warn("no vcard in response", stanza)
return
contact.set
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'))
if mime and data
contact.set('avatar', mime: mime, data: data)
else
contact.unset('avatar')
failcb = (stanza) ->
console.warn("couldn't get vcard", stanza)
bjid = contact.get('bjid')
if bjid is Strophe.getBareJidFromJid(X.conn.jid)
bjid = null
X.conn.vcard.get(okcb, bjid, failcb)
onPresence = (stanza) ->
from = stanza.getAttribute('from')
type = stanza.getAttribute('type') ? 'online'
if type is 'subscribe'
console.warn('not handling <presence type="subscribe">', stanza)
return true
if type is 'subscribed'
console.warn('not handling <presence type="subscribed">', stanza)
return true
if type is 'error'
console.error('got <presence type="error">', stanza)
return true
delay = stanza.getElementsByTagName('delay')[0]
stamp = if delay then new Date(delay.getAttribute('stamp')) else new Date()
priority = stanza.getElementsByTagName('priority')[0]
priority = if priority then getText(priority) else '0'
show = stanza.getElementsByTagName('show')[0]
show = if show then getText(show) else undefined
s = stanza.getElementsByTagName('status')[0]
s = if s then getText(s) else undefined
contact = getContact(from)
contact.set
presence: type
show: show
status: s
messages.add
id: stanza.getAttribute('id')
type: 'presence'
cls: 'presence'
from: from
stamp: stamp
contact: contact
show: show
priority: priority
text: 'is now ' + (show ? type)
return true
onProfileUpdate = (stanza) ->
from = stanza.getAttribute('from')
contact = getContact(from)
getContactProfile(contact)
return true
window.X = new Tram.XMPPInterface()
X.on 'connecting', ->
$('[data-msg^="a/"]').addClass('uk-hidden')
X.on 'authfail', ->
$('[data-msg="a/fail"]').removeClass('uk-hidden')
X.on 'disconnected', ->
$('[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')
onConnected()
$('button[data-disconnect]').on 'click', ->
X.disconnect('Logged out')
$(window).on 'beforeunload unload', ->
X.disconnect('Window closed')
$form = $('[data-form="connect"]')
$form.find('input').on 'keydown', (e) ->
if (not @required or @value isnt '') and e.keyCode is 13
e.preventDefault()
index = $form.find('input').index(@)
$next = $form.find('input').eq(index + 1)
if $next.length isnt 0
$next.focus()
else
$form.find('button').trigger('click')
$form.find('button').on 'click', (e) ->
e.preventDefault()
ok = true
Tram.validation.unsetError($('#username, #password'))
ok &= Tram.validation.validateRequired($('#username'), true)
ok &= Tram.validation.validateRequired($('#password'))
if ok
X.connect($('#username').val().trim(), $('#password').val())
window.setInterval ->
$('time[datetime]').each ->
$this = $(this)
$this.text(moment($this.attr('datetime')).fromNow())
, 15 * 1000