107:cf8588513108
Anton Shestakov <av6@dwimlabs.net>, Thu, 07 Apr 2016 22:08:18 +0800
index: handling incoming "subscribed" and "unsubscribed" presences Currently the client can only comply with the request.

next change 108:9a081cf7fda1
previous change 102:180123942ff9

coffee/contacts.coffee

Permissions: -rw-r--r--

Other formats: Feeds:
class Tram.Contact extends Backbone.Model
idAttribute: 'jid'
optimizeSide: 96
optimizeThreshold: 10000
defaults:
presence: 'unavailable'
show: 'offline'
initialize: ->
@on('add change:avatar', @optimizeAvatar)
@on 'add change:fullname change:nickname change:bjid', ->
@set('d/handle', @get('fullname') or @get('nickname') or @get('bjid'))
@on 'add change:type change:presence change:callstate', ->
if @get('type') is 'self' then return @unset('d/actions')
if @get('presence') is 'subscribe' then return @set('d/actions', ['authorize', 'unauthorize'])
actions = ['remove']
if @get('presence') isnt 'unavailable'
switch @get 'callstate'
when 'established'
actions.push('hang-up')
when 'outgoing'
actions.push('wait', 'hang-up')
when 'incoming'
actions.push('accept', 'decline')
else
actions.push('call')
@set('d/actions', actions)
optimizeAvatar: ->
avatar = @get('avatar')
if not (avatar?.mime and avatar?.data)
return @unset('avatar/url')
data = "data:#{ avatar.mime };base64,#{ avatar.data }"
if data.length < @optimizeThreshold
return @set('avatar/url', data)
img = new Image()
img.addEventListener 'load', =>
if img.width < @optimizeSide and img.height < @optimizeSide
return @set('avatar/url', data)
ratio = Math.min(@optimizeSide / img.width, @optimizeSide / img.height)
canvas = document.createElement('canvas')
canvas.height = Math.round(img.height * ratio)
canvas.width = Math.round(img.width * ratio)
ctx = canvas.getContext('2d')
ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
mime = 'image/png'
if avatar.mime is 'image/jpeg'
mime = avatar.mime
optimized = canvas.toDataURL(mime)
if img.src.length < optimized.length
@set('avatar/url', data)
else
@set('avatar/url', optimized)
img.src = data
class Tram.Contacts extends Backbone.Collection
model: Tram.Contact
comparator: (model) ->
if model.get('presence') is 'unavailable'
return 1
else if model.get('type') is 'self'
return -1
else
return 0
initialize: ->
@on('change:presence change:type', @sort)
class Tram.AvatarView extends Backbone.View
tagName: 'div'
className: 'vignette'
template: $('#avatar-template').html()
colors: Tram.colors.avatar
getColors: (hash) =>
ci = hash % @colors.length
"color: white; background: #{ @colors[ci] };"
render: ->
@$el.html(@template)
@rivet = rivets.bind(@el, model: @model, view: this)
@
remove: ->
@rivet.unbind()
super
class Tram.ContactView extends Backbone.View
tagName: 'li'
className: 'contact'
template: $('#contact-template').html()
colors: Tram.colors.show
events:
'click [data-chat]': -> @model.trigger('chat')
'click [data-authorize]': -> @model.trigger('authorize')
'click [data-unauthorize]': -> @model.trigger('unauthorize')
'click [data-call]': (event) -> @model.trigger('call', event.currentTarget.getAttribute('data-call'))
'click [data-accept]': (event) -> @model.trigger('accept', event.currentTarget.getAttribute('data-accept'))
'click [data-decline]': -> @model.trigger('decline')
'click [data-hang-up]': -> @model.trigger('hangup')
'click [data-remove]': -> @model.trigger('remove')
initialize: ->
@$el.attr('data-jid', @model.get('jid'))
@$el.html(@template)
@$avatarColumn = @$('.avatar-column')
@bind()
bind: ->
getPipColor: (show) =>
"background: #{ @colors[show] || @colors['default'] };"
render: ->
@rivet = rivets.bind(@el, model: @model, view: this)
av = new Tram.AvatarView(model: @model)
@$avatarColumn.prepend(av.render().el)
@
remove: ->
@rivet.unbind()
super
class Tram.ContactsApp extends Backbone.View
initialize: ->
@listenTo(@collection, 'add', @onAdd)
@listenTo(@collection, 'remove', @onRemove)
@listenTo(@collection, 'sort', @onSort)
onAdd: (model, collection) ->
mi = collection.indexOf(model)
model.view = new Tram.ContactView(model: model)
el = model.view.render().el
if mi is 0
@$el.prepend(el)
else
@$el.children().eq(mi - 1).after(el)
onRemove: (model) ->
model.view?.remove()
onSort: (collection, options) ->
if not options.add
collection.each (model) =>
model.view.$el.detach()
@$el.append(model.view.el)