Restore two column layout
Establishes basic functionality for viewing conversations in two column mode, including message area and message list resizing, and maintaining scroll position. Various subviews need to be retooled but are more or less still functional, i.e., new message, message detail, key verification, etc...
This commit is contained in:
parent
00dfcbb462
commit
d6a4e6e496
|
@ -16,12 +16,29 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<script type='text/x-tmpl-mustache' id='two-column'>
|
||||
<div class='title-bar' id='header'>
|
||||
<div class='menu'>
|
||||
<button class='hamburger'></button>
|
||||
<ul class='menu-list'>
|
||||
<li><a class='new-group'>Create Group</a></li>
|
||||
<li><a class='settings'>Settings</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<span class='conversation-title'>Signal</span>
|
||||
<div class='socket-status'></div>
|
||||
</div>
|
||||
<div class='gutter'>
|
||||
<div class='conversations scrollable'></div>
|
||||
<span class='fab'></span>
|
||||
</div>
|
||||
<div class='conversation-stack'></div>
|
||||
</script>
|
||||
<script type='text/x-tmpl-mustache' id='conversation'>
|
||||
<div class='title-bar' id='header'>
|
||||
<div class='menu'>
|
||||
<div class='conversation-header'>
|
||||
<div class='conversation-menu menu'>
|
||||
<button class='hamburger'></button>
|
||||
<ul class='menu-list'>
|
||||
<li><a class='openInbox'>Open Inbox</a></li>
|
||||
{{#group}}
|
||||
<li><a class='view-members'>Members</a></li>
|
||||
<li><a class='new-group-update'>Update group</a></li>
|
||||
|
|
|
@ -117,45 +117,7 @@
|
|||
conversation.fetchContacts();
|
||||
});
|
||||
conversation.fetchMessages();
|
||||
|
||||
var windowId = windowMap.windowIdFrom(modelId);
|
||||
|
||||
// prevent multiple copies of the same conversation from being opened
|
||||
if (!windowId) {
|
||||
// open the panel
|
||||
extension.windows.open({
|
||||
id: modelId,
|
||||
url: 'conversation.html',
|
||||
type: 'panel',
|
||||
frame: 'none',
|
||||
focused: true,
|
||||
width: 300,
|
||||
height: 440,
|
||||
minWidth: 230,
|
||||
minHeight: 73
|
||||
}, function (windowInfo) {
|
||||
windowId = windowInfo.id;
|
||||
windowMap.add({ windowId: windowId, modelId: modelId });
|
||||
|
||||
windowInfo.onClosed.addListener(function () {
|
||||
onWindowClosed(windowId);
|
||||
});
|
||||
|
||||
// close the panel if background.html is refreshed
|
||||
extension.windows.beforeUnload(function() {
|
||||
// TODO: reattach after reload instead of closing.
|
||||
extension.windows.remove(windowId);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// focus the panel
|
||||
extension.windows.focus(windowId, function (error) {
|
||||
if (error) {
|
||||
closeConversation(windowId); // panel isn't actually open...
|
||||
openConversation(modelId); // ...and so we try again.
|
||||
}
|
||||
});
|
||||
}
|
||||
return conversation;
|
||||
};
|
||||
|
||||
/* Inbox window controller */
|
||||
|
@ -170,7 +132,7 @@
|
|||
type: 'panel',
|
||||
frame: 'none',
|
||||
focused: true,
|
||||
width: 260,
|
||||
width: 580,
|
||||
height: 440,
|
||||
minWidth: 230,
|
||||
minHeight: 150
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
className: function() {
|
||||
return [ 'conversation', this.model.get('type') ].join(' ');
|
||||
},
|
||||
id: function() {
|
||||
return 'conversation-' + this.model.cid;
|
||||
},
|
||||
template: $('#conversation').html(),
|
||||
render_attributes: function() {
|
||||
return {
|
||||
|
@ -36,10 +39,6 @@
|
|||
this.render();
|
||||
|
||||
this.appWindow = options.appWindow;
|
||||
new Whisper.WindowControlsView({
|
||||
appWindow: this.appWindow
|
||||
}).$el.insertAfter(this.$('.menu'));
|
||||
|
||||
this.fileInput = new Whisper.FileInputView({
|
||||
el: this.$('.attachments'),
|
||||
window: this.appWindow.contentWindow
|
||||
|
@ -85,7 +84,8 @@
|
|||
'click .hamburger': 'toggleMenu',
|
||||
'click .openInbox' : 'openInbox',
|
||||
'click' : 'onClick',
|
||||
'select .entry': 'messageDetail'
|
||||
'select .entry': 'messageDetail',
|
||||
'force-resize': 'forceUpdateMessageFieldSize'
|
||||
},
|
||||
|
||||
viewMembers: function() {
|
||||
|
@ -235,12 +235,15 @@
|
|||
|
||||
$bottomBar.outerHeight(this.$messageField.outerHeight() + 1);
|
||||
var $bottomBarNewHeight = $bottomBar.outerHeight();
|
||||
$discussionContainer.outerHeight(this.$el.outerHeight() - $bottomBarNewHeight - this.$('#header').outerHeight());
|
||||
$discussionContainer.outerHeight(this.$el.outerHeight() - $bottomBarNewHeight - this.$('.conversation-header').outerHeight());
|
||||
|
||||
this.view.scrollToBottomIfNeeded();
|
||||
},
|
||||
|
||||
forceUpdateMessageFieldSize: function (event) {
|
||||
if (this.$el.css('display') === 'none') {
|
||||
return;
|
||||
}
|
||||
this.view.scrollToBottomIfNeeded();
|
||||
window.autosize.update(this.$messageField);
|
||||
this.updateMessageFieldSize(event);
|
||||
|
|
|
@ -56,11 +56,32 @@
|
|||
}
|
||||
});
|
||||
|
||||
Whisper.ConversationStack = Whisper.View.extend({
|
||||
className: 'conversation-stack',
|
||||
open: function(conversation) {
|
||||
var $el = this.$('#conversation-' + conversation.cid);
|
||||
if ($el === null || $el.length === 0) {
|
||||
var view = new Whisper.ConversationView({
|
||||
model: conversation,
|
||||
appWindow: this.model.appWindow
|
||||
});
|
||||
$el = view.$el;
|
||||
}
|
||||
$el.prependTo(this.el);
|
||||
$el.find('.message-list').trigger('reset-scroll');
|
||||
$el.trigger('force-resize');
|
||||
}
|
||||
});
|
||||
|
||||
Whisper.InboxView = Whisper.View.extend({
|
||||
template: $('#inbox').html(),
|
||||
template: $('#two-column').html(),
|
||||
className: 'inbox',
|
||||
initialize: function (options) {
|
||||
this.render();
|
||||
this.conversation_stack = new Whisper.ConversationStack({
|
||||
el: this.$('.conversation-stack'),
|
||||
model: { appWindow: options.appWindow }
|
||||
});
|
||||
|
||||
this.newConversationView = new Whisper.NewConversationView({
|
||||
appWindow: options.appWindow
|
||||
|
@ -91,7 +112,8 @@
|
|||
'select .contact': 'openConversation',
|
||||
},
|
||||
openConversation: function(e, data) {
|
||||
bg.openConversation(data.modelId);
|
||||
var conversation = bg.openConversation(data.modelId);
|
||||
this.conversation_stack.open(conversation);
|
||||
this.hideCompose();
|
||||
},
|
||||
showCompose: function() {
|
||||
|
|
|
@ -17,10 +17,6 @@
|
|||
'use strict';
|
||||
window.Whisper = window.Whisper || {};
|
||||
|
||||
var scrollPosition,
|
||||
scrollHeight,
|
||||
shouldStickToBottom;
|
||||
|
||||
Whisper.MessageListView = Whisper.ListView.extend({
|
||||
tagName: 'ul',
|
||||
className: 'message-list',
|
||||
|
@ -28,16 +24,24 @@
|
|||
events: {
|
||||
'add': 'scrollToBottom',
|
||||
'update *': 'scrollToBottom',
|
||||
'scroll': 'measureScrollPosition'
|
||||
'scroll': 'measureScrollPosition',
|
||||
'reset-scroll': 'resetScrollPosition'
|
||||
},
|
||||
measureScrollPosition: function() {
|
||||
scrollPosition = this.$el.scrollTop() + this.$el.outerHeight();
|
||||
scrollHeight = this.el.scrollHeight;
|
||||
shouldStickToBottom = scrollPosition === scrollHeight;
|
||||
this.scrollPosition = this.$el.scrollTop() + this.$el.outerHeight();
|
||||
this.scrollHeight = this.el.scrollHeight;
|
||||
this.shouldStickToBottom = this.scrollPosition === this.scrollHeight;
|
||||
},
|
||||
resetScrollPosition: function() {
|
||||
var scrollPosition = this.scrollPosition;
|
||||
if (this.scrollHeight !== this.el.scrollHeight) {
|
||||
scrollPosition = this.el.scrollHeight * this.scrollPosition / this.scrollHeight;
|
||||
}
|
||||
this.$el.scrollTop(scrollPosition - this.$el.outerHeight());
|
||||
},
|
||||
scrollToBottomIfNeeded: function() {
|
||||
if (shouldStickToBottom) {
|
||||
this.$el.scrollTop(scrollHeight);
|
||||
if (this.shouldStickToBottom) {
|
||||
this.$el.scrollTop(this.scrollHeight);
|
||||
}
|
||||
},
|
||||
scrollToBottom: function() {
|
||||
|
|
|
@ -341,10 +341,7 @@
|
|||
.bottom-bar {
|
||||
$button-width: 36px;
|
||||
|
||||
position: fixed;
|
||||
bottom: 1px; // offset 1 for window frame.
|
||||
height: 36px;
|
||||
width: calc(100% - 2px);
|
||||
border-top: 1px solid $grey_l;
|
||||
background: white;
|
||||
|
||||
|
|
|
@ -91,7 +91,8 @@ button.back {
|
|||
padding-right: 8px;
|
||||
|
||||
.hamburger {
|
||||
width: 36px;
|
||||
width: $header-height;
|
||||
height: $header-height;
|
||||
background: url('/images/menu.png') no-repeat center;
|
||||
}
|
||||
.menu-list {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
padding: $header-height 0 0;
|
||||
}
|
||||
|
||||
.conversation-stack,
|
||||
.new-conversation, .inbox, .gutter {
|
||||
height: 100%;
|
||||
}
|
||||
|
@ -14,6 +15,11 @@
|
|||
// TODO: spinner
|
||||
}
|
||||
|
||||
.gutter {
|
||||
float: left;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.socket-status {
|
||||
float: left;
|
||||
padding: 6px;
|
||||
|
@ -40,6 +46,31 @@
|
|||
}
|
||||
}
|
||||
|
||||
.conversation-stack {
|
||||
padding-left: 300px;
|
||||
padding-top: $header-height;
|
||||
.conversation {
|
||||
display: none;
|
||||
}
|
||||
.conversation:first-child {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.conversation-header {
|
||||
background: $grey_l;
|
||||
}
|
||||
.menu.conversation-menu {
|
||||
float: right;
|
||||
padding-left: 8px;
|
||||
padding-right: 0;
|
||||
|
||||
.menu-list {
|
||||
right: 0;
|
||||
left: initial;
|
||||
}
|
||||
}
|
||||
|
||||
.contact {
|
||||
.number, .checkbox {
|
||||
display: none;
|
||||
|
@ -56,7 +87,7 @@ input.search {
|
|||
.fab {
|
||||
z-index: 1;
|
||||
position: fixed;
|
||||
right: 25px;;
|
||||
left: 215px;;
|
||||
bottom: 22px;
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
|
@ -99,7 +130,7 @@ input.search {
|
|||
color: $grey_d;
|
||||
background: #eee;
|
||||
|
||||
.new-group-update-form {
|
||||
.gutter .new-group-update-form {
|
||||
display: none;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
@ -110,7 +141,7 @@ input.search {
|
|||
font-weight: 300;
|
||||
}
|
||||
|
||||
.timestamp {
|
||||
.gutter .timestamp {
|
||||
position: absolute;
|
||||
top: 14px;
|
||||
right: 12px;
|
||||
|
|
|
@ -90,6 +90,7 @@ button.back {
|
|||
padding-right: 8px; }
|
||||
.menu .hamburger {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
background: url("/images/menu.png") no-repeat center; }
|
||||
.menu .menu-list {
|
||||
display: none;
|
||||
|
@ -330,6 +331,7 @@ img.emoji {
|
|||
.gutter {
|
||||
padding: 36px 0 0; }
|
||||
|
||||
.conversation-stack,
|
||||
.new-conversation, .inbox, .gutter {
|
||||
height: 100%; }
|
||||
|
||||
|
@ -337,6 +339,10 @@ img.emoji {
|
|||
height: 100%;
|
||||
overflow: auto; }
|
||||
|
||||
.gutter {
|
||||
float: left;
|
||||
max-width: 300px; }
|
||||
|
||||
.socket-status {
|
||||
float: left;
|
||||
padding: 6px;
|
||||
|
@ -355,6 +361,25 @@ img.emoji {
|
|||
.socket-status .closed {
|
||||
background: url("/images/error_red.png") no-repeat left center; }
|
||||
|
||||
.conversation-stack {
|
||||
padding-left: 300px;
|
||||
padding-top: 36px; }
|
||||
.conversation-stack .conversation {
|
||||
display: none; }
|
||||
.conversation-stack .conversation:first-child {
|
||||
display: block; }
|
||||
|
||||
.conversation-header {
|
||||
background: #f3f3f3; }
|
||||
|
||||
.menu.conversation-menu {
|
||||
float: right;
|
||||
padding-left: 8px;
|
||||
padding-right: 0; }
|
||||
.menu.conversation-menu .menu-list {
|
||||
right: 0;
|
||||
left: initial; }
|
||||
|
||||
.contact .number, .contact .checkbox {
|
||||
display: none; }
|
||||
|
||||
|
@ -367,7 +392,7 @@ input.search {
|
|||
.fab {
|
||||
z-index: 1;
|
||||
position: fixed;
|
||||
right: 25px;
|
||||
left: 215px;
|
||||
bottom: 22px;
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
|
@ -401,14 +426,14 @@ input.search {
|
|||
.index {
|
||||
color: #454545;
|
||||
background: #eee; }
|
||||
.index .new-group-update-form {
|
||||
.index .gutter .new-group-update-form {
|
||||
display: none;
|
||||
padding: 0.5em; }
|
||||
.index .last-message {
|
||||
margin: 6px 0;
|
||||
font-size: small;
|
||||
font-weight: 300; }
|
||||
.index .timestamp {
|
||||
.index .gutter .timestamp {
|
||||
position: absolute;
|
||||
top: 14px;
|
||||
right: 12px;
|
||||
|
@ -679,10 +704,7 @@ input.search {
|
|||
cursor: pointer; }
|
||||
|
||||
.bottom-bar {
|
||||
position: fixed;
|
||||
bottom: 1px;
|
||||
height: 36px;
|
||||
width: calc(100% - 2px);
|
||||
border-top: 1px solid #f3f3f3;
|
||||
background: white; }
|
||||
.bottom-bar button, .bottom-bar input, .bottom-bar textarea {
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue