New layout/design

Two column layout and style tweaks. Templatized conversation views.
Generalized list view.
This commit is contained in:
lilia 2014-07-22 08:55:26 -10:00
parent 6d5e32bca8
commit def32f42d4
9 changed files with 203 additions and 91 deletions

View file

@ -20,8 +20,9 @@ textsecure.registerOnLoadFunction(function() {
extension.navigator.tabs.create("options.html");
} else {
new Whisper.ConversationListView();
new Whisper.ConversationListView({el: $('#contacts')});
new Whisper.ConversationComposeView({el: $('body')});
Whisper.Threads.fetch({reset: true});
$('.my-number').text(textsecure.storage.getUnencrypted("number_id").split(".")[0]);
textsecure.storage.putUnencrypted("unreadCount", 0);
extension.navigator.setBadgeText("");

View file

@ -0,0 +1,29 @@
var Whisper = Whisper || {};
(function () {
'use strict';
Whisper.ConversationListView = Whisper.ListView.extend({
tagName: 'ul',
id: 'contacts',
itemView: Whisper.ConversationView,
collection: Whisper.Threads,
events: {
'select .conversation': 'select',
'deselect': 'deselect'
},
select: function(e) {
var target = $(e.target).closest('.conversation');
target.siblings().addClass('closed');
target.addClass('selected').trigger('open');
return false;
},
deselect: function() {
this.$el.find('.selected').removeClass('selected').trigger('close');
this.$el.find('.conversation').show();
}
});
})();

View file

@ -1,46 +0,0 @@
var Whisper = Whisper || {};
(function () {
'use strict';
Whisper.ConversationListView = Backbone.View.extend({
tagName: 'ul',
id: 'conversations',
initialize: function() {
this.views = {};
this.threads = Whisper.Threads;
this.listenTo(this.threads, 'change:completed', this.render); // auto update
this.listenTo(this.threads, 'add', this.addThread);
this.listenTo(this.threads, 'reset', this.addAll);
this.listenTo(this.threads, 'all', this.render);
this.listenTo(Whisper.Messages, 'add', this.addMessage);
// Suppresses 'add' events with {reset: true} and prevents the app view
// from being re-rendered for every model. Only renders when the 'reset'
// event is triggered at the end of the fetch.
//this.messages.threads({reset: true});
Whisper.Threads.fetch({reset: true});
Whisper.Messages.fetch();
this.$el.appendTo($('#inbox'));
},
addThread: function(thread) {
this.views[thread.id] = new Whisper.ConversationView({model: thread});
this.$el.prepend(this.views[thread.id].render().el);
},
addAll: function() {
this.$el.html('');
_.each(this.threads.where({'active': true}), this.addThread, this);
},
addMessage: function(message) {
var thread = message.thread();
if (!_.has(this.views, thread.id)) {
this.addThread(thread);
}
thread.trigger('message', message);
}
});
})();

View file

@ -34,10 +34,13 @@ var Whisper = Whisper || {};
className: 'conversation',
events: {
'click': 'toggle',
'click': 'open',
'submit form': 'sendMessage'
},
initialize: function() {
this.template = $('#contact').html();
Mustache.parse(this.template);
this.listenTo(this.model, 'change', this.render); // auto update
this.listenTo(this.model, 'message', this.addMessage); // auto update
this.listenTo(this.model, 'destroy', this.remove); // auto update
@ -50,15 +53,7 @@ var Whisper = Whisper || {};
this.$name = $('<span class="name">');
this.$header = $('<div class="header">').append(this.$image, this.$name);
this.$button = $('<button class="btn">').append($('<span>').text('Send'));
this.$input = $('<input type="text">').attr('autocomplete','off');
this.$form = $("<form class=''>").append(this.$input);
this.$messages = $('<ul class="messages">');
this.$collapsable = $('<div class="collapsable">').hide();
this.$collapsable.append(this.$messages, this.$form);
this.$el.append(this.$destroy, this.$header, this.$collapsable);
this.$el.append(this.$header, this.$collapsable);
},
sendMessage: function(e) {
@ -74,16 +69,15 @@ var Whisper = Whisper || {};
close: function() {
if (!this.$el.hasClass('closed')) {
this.$el.addClass('closed').find('.collapsable').slideUp(600);
this.$el.addClass('closed');
}
},
open: function(e) {
if (this.$el.hasClass('closed')) {
this.$el.removeClass('closed');
this.$el.find('.collapsable').slideDown(600);
}
this.$el.find('input').focus();
this.$el.siblings().addClass('closed');
this.$el.removeClass('closed');
var v = new Whisper.MessageListView({collection: this.model.messages()});
v.render();
},
toggle: function() {
@ -105,9 +99,14 @@ var Whisper = Whisper || {};
},
render: function() {
this.$name.text(this.model.get('name'));
this.$image.css('background-image: ' + this.model.get('image') + ';');
this.$el.html(
Mustache.render(this.template, {
name: this.model.get('name')
})
);
return this;
}
},
});
})();

36
js/views/list_view.js Normal file
View file

@ -0,0 +1,36 @@
var Whisper = Whisper || {};
(function () {
'use strict';
/*
* Generic list view that watches a given collection, wraps its members in
* a given child view and adds the child view elements to its own element.
*/
Whisper.ListView = Backbone.View.extend({
tagName: 'ul',
initialize: function() {
this.listenTo(this.collection, 'change', this.render); // auto update
this.listenTo(this.collection, 'add', this.addOne);
this.listenTo(this.collection, 'reset', this.addAll);
this.listenTo(this.collection, 'all', this.render);
this.collection.fetch({reset: true});
},
addOne: function(model) {
if (this.itemView) {
var view = new this.itemView({model: model});
this.$el.append(view.render().el);
}
},
addAll: function() {
this.$el.html('');
this.collection.each(this.addOne, this);
},
last: function() {
this.collection.at(this.collection.length - 1);
}
});
})();

View file

@ -0,0 +1,15 @@
var Whisper = Whisper || {};
(function () {
'use strict';
Whisper.MessageListView = Whisper.ListView.extend({
tagName: 'ul',
className: 'messages',
itemView: Whisper.MessageView,
render: function() {
$('#main').html('').append(this.el);
}
});
})();