112:f4a4878c99a3
Anton Shestakov <av6@dwimlabs.net>, Thu, 07 Apr 2016 22:56:16 +0800
index: check if roster has the item before removing it Sometimes we get events from contacts that are not in user's roster, trying to remove such contacts used to fail before this patch.

next change 143:2afd675fcaa4
previous change 111:b2e3a00a9691

js/contacts.js

Permissions: -rw-r--r--

Other formats: Feeds:
// Generated by CoffeeScript 1.10.0
(function() {
var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty,
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
Tram.Contact = (function(superClass) {
extend(Contact, superClass);
function Contact() {
return Contact.__super__.constructor.apply(this, arguments);
}
Contact.prototype.idAttribute = 'jid';
Contact.prototype.optimizeSide = 96;
Contact.prototype.optimizeThreshold = 10000;
Contact.prototype.defaults = {
presence: 'unavailable',
show: 'offline'
};
Contact.prototype.initialize = function() {
this.on('add change:avatar', this.optimizeAvatar);
this.on('add change:fullname change:nickname change:bjid', function() {
return this.set('d/handle', this.get('fullname') || this.get('nickname') || this.get('bjid'));
});
return this.on('add change:type change:presence change:callstate', function() {
var actions;
if (this.get('type') === 'self') {
return this.unset('d/actions');
}
if (this.get('presence') === 'subscribe') {
return this.set('d/actions', ['authorize', 'unauthorize']);
}
actions = ['remove'];
if (this.get('presence') !== 'unavailable') {
switch (this.get('callstate')) {
case 'established':
actions.push('hang-up');
break;
case 'outgoing':
actions.push('wait', 'hang-up');
break;
case 'incoming':
actions.push('accept', 'decline');
break;
default:
actions.push('call');
}
}
return this.set('d/actions', actions);
});
};
Contact.prototype.optimizeAvatar = function() {
var avatar, data, img;
avatar = this.get('avatar');
if (!((avatar != null ? avatar.mime : void 0) && (avatar != null ? avatar.data : void 0))) {
return this.unset('avatar/url');
}
data = "data:" + avatar.mime + ";base64," + avatar.data;
if (data.length < this.optimizeThreshold) {
return this.set('avatar/url', data);
}
img = new Image();
img.addEventListener('load', (function(_this) {
return function() {
var canvas, ctx, mime, optimized, ratio;
if (img.width < _this.optimizeSide && img.height < _this.optimizeSide) {
return _this.set('avatar/url', data);
}
ratio = Math.min(_this.optimizeSide / img.width, _this.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 === 'image/jpeg') {
mime = avatar.mime;
}
optimized = canvas.toDataURL(mime);
if (img.src.length < optimized.length) {
return _this.set('avatar/url', data);
} else {
return _this.set('avatar/url', optimized);
}
};
})(this));
return img.src = data;
};
return Contact;
})(Backbone.Model);
Tram.Contacts = (function(superClass) {
extend(Contacts, superClass);
function Contacts() {
return Contacts.__super__.constructor.apply(this, arguments);
}
Contacts.prototype.model = Tram.Contact;
Contacts.prototype.comparator = function(model) {
if (model.get('presence') === 'unavailable') {
return 2;
} else if (model.get('presence') === 'subscribe') {
return 1;
} else if (model.get('type') === 'self') {
return -1;
} else {
return 0;
}
};
Contacts.prototype.initialize = function() {
return this.on('change:presence change:type', this.sort);
};
return Contacts;
})(Backbone.Collection);
Tram.AvatarView = (function(superClass) {
extend(AvatarView, superClass);
function AvatarView() {
this.getColors = bind(this.getColors, this);
return AvatarView.__super__.constructor.apply(this, arguments);
}
AvatarView.prototype.tagName = 'div';
AvatarView.prototype.className = 'vignette';
AvatarView.prototype.template = $('#avatar-template').html();
AvatarView.prototype.colors = Tram.colors.avatar;
AvatarView.prototype.getColors = function(hash) {
var ci;
ci = hash % this.colors.length;
return "color: white; background: " + this.colors[ci] + ";";
};
AvatarView.prototype.render = function() {
this.$el.html(this.template);
this.rivet = rivets.bind(this.el, {
model: this.model,
view: this
});
return this;
};
AvatarView.prototype.remove = function() {
this.rivet.unbind();
return AvatarView.__super__.remove.apply(this, arguments);
};
return AvatarView;
})(Backbone.View);
Tram.ContactView = (function(superClass) {
extend(ContactView, superClass);
function ContactView() {
this.getPipColor = bind(this.getPipColor, this);
return ContactView.__super__.constructor.apply(this, arguments);
}
ContactView.prototype.tagName = 'li';
ContactView.prototype.className = 'contact';
ContactView.prototype.template = $('#contact-template').html();
ContactView.prototype.colors = Tram.colors.show;
ContactView.prototype.events = {
'click [data-chat]': function() {
return this.model.trigger('action/chat');
},
'click [data-authorize]': function() {
return this.model.trigger('action/authorize');
},
'click [data-unauthorize]': function() {
return this.model.trigger('action/unauthorize');
},
'click [data-call]': function(event) {
return this.model.trigger('action/call', event.currentTarget.getAttribute('data-call'));
},
'click [data-accept]': function(event) {
return this.model.trigger('action/accept', event.currentTarget.getAttribute('data-accept'));
},
'click [data-decline]': function() {
return this.model.trigger('action/decline');
},
'click [data-hang-up]': function() {
return this.model.trigger('action/hangup');
},
'click [data-remove]': function() {
return this.model.trigger('action/remove');
}
};
ContactView.prototype.initialize = function() {
this.$el.attr('data-jid', this.model.get('jid'));
this.$el.html(this.template);
this.$avatarColumn = this.$('.avatar-column');
return this.bind();
};
ContactView.prototype.bind = function() {};
ContactView.prototype.getPipColor = function(show) {
return "background: " + (this.colors[show] || this.colors['default']) + ";";
};
ContactView.prototype.render = function() {
var av;
this.rivet = rivets.bind(this.el, {
model: this.model,
view: this
});
av = new Tram.AvatarView({
model: this.model
});
this.$avatarColumn.prepend(av.render().el);
return this;
};
ContactView.prototype.remove = function() {
this.rivet.unbind();
return ContactView.__super__.remove.apply(this, arguments);
};
return ContactView;
})(Backbone.View);
Tram.ContactsApp = (function(superClass) {
extend(ContactsApp, superClass);
function ContactsApp() {
return ContactsApp.__super__.constructor.apply(this, arguments);
}
ContactsApp.prototype.initialize = function() {
this.listenTo(this.collection, 'add', this.onAdd);
this.listenTo(this.collection, 'remove', this.onRemove);
return this.listenTo(this.collection, 'sort', this.onSort);
};
ContactsApp.prototype.onAdd = function(model, collection) {
var el, mi;
mi = collection.indexOf(model);
model.view = new Tram.ContactView({
model: model
});
el = model.view.render().el;
if (mi === 0) {
return this.$el.prepend(el);
} else {
return this.$el.children().eq(mi - 1).after(el);
}
};
ContactsApp.prototype.onRemove = function(model) {
var ref;
return (ref = model.view) != null ? ref.remove() : void 0;
};
ContactsApp.prototype.onSort = function(collection, options) {
if (!options.add) {
return collection.each((function(_this) {
return function(model) {
model.view.$el.detach();
return _this.$el.append(model.view.el);
};
})(this));
}
};
return ContactsApp;
})(Backbone.View);
}).call(this);
//# sourceMappingURL=contacts.js.map