Simplify panel state management and message passing
This commit is contained in:
parent
9071d98395
commit
94ce4d4b91
12 changed files with 148 additions and 102 deletions
|
@ -223,13 +223,12 @@
|
|||
});
|
||||
};
|
||||
|
||||
extension.on('log', console.log.bind(console));
|
||||
var windowMap = Whisper.windowMap = new Whisper.Bimap('windowId', 'modelId');
|
||||
|
||||
chrome.runtime.onConnect.addListener(function (port) {
|
||||
if (port.name === 'panel_presence') {
|
||||
port.onDisconnect.addListener(function (message) {
|
||||
closeConversation(message.sender.tab.windowId);
|
||||
});
|
||||
// make sure panels are cleaned up on close
|
||||
chrome.windows.onRemoved.addListener(function (windowId) {
|
||||
if (windowMap.windowId[windowId]) {
|
||||
closeConversation(windowId);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
75
js/bimap.js
Normal file
75
js/bimap.js
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*global $, Whisper, Backbone, textsecure, extension*/
|
||||
/* vim: ts=4:sw=4:expandtab:
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
// A bidirectional hash that allows constant-time lookup for
|
||||
// key -> value and value -> key
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
window.Whisper = window.Whisper || {};
|
||||
|
||||
function Bimap (map1, map2) {
|
||||
if (typeof map1 !== 'string' || typeof map2 !== 'string') {
|
||||
throw 'Expected two map name strings as arguments';
|
||||
}
|
||||
|
||||
this.bijection = {};
|
||||
this.bijection[map1] = map2;
|
||||
this.bijection[map2] = map1;
|
||||
|
||||
// makes accessing the maps clearer
|
||||
this[map1] = {};
|
||||
this[map2] = {};
|
||||
|
||||
this[map1 + 'From'] = function (key) { return this[map2][key]; };
|
||||
this[map2 + 'From'] = function (key) { return this[map1][key]; };
|
||||
}
|
||||
|
||||
Bimap.prototype.add = function (obj) {
|
||||
if (typeof obj !== 'object') {
|
||||
throw 'Expected an object as an argument';
|
||||
}
|
||||
|
||||
var keys = Object.keys(obj);
|
||||
var map1 = keys[0];
|
||||
var map2 = keys[1];
|
||||
|
||||
if (this.bijection[map1] !== map2) {
|
||||
throw 'Expected the argument\'s keys to correspond to the Bimap\'s two map names';
|
||||
}
|
||||
|
||||
this[map1][obj[map1]] = obj[map2];
|
||||
this[map2][obj[map2]] = obj[map1];
|
||||
};
|
||||
|
||||
Bimap.prototype.remove = function remove (map, key) {
|
||||
var bijection = this.bijection[map];
|
||||
var correspondingKey = this[map][key];
|
||||
|
||||
// delete from the bijection
|
||||
delete this[bijection][correspondingKey];
|
||||
|
||||
// delete from the specified map
|
||||
delete this[map][key];
|
||||
|
||||
return correspondingKey;
|
||||
};
|
||||
|
||||
// export
|
||||
Whisper.Bimap = Bimap;
|
||||
})();
|
|
@ -26,32 +26,16 @@
|
|||
});
|
||||
};
|
||||
|
||||
var windowId, windowMap = JSON.parse(localStorage.getItem('idPairs'));
|
||||
|
||||
window.addEventListener('storage', function (e) {
|
||||
if (e.key = 'idPairs') {
|
||||
windowMap = JSON.parse(e.newValue);
|
||||
|
||||
if (windowId) {
|
||||
var conversationId = windowMap[windowId];
|
||||
|
||||
if (conversationId) {
|
||||
loadConversation(conversationId);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
var bg = chrome.extension.getBackgroundPage();
|
||||
|
||||
chrome.windows.getCurrent(function (windowInfo) {
|
||||
window.document.title = windowId = windowInfo.id;
|
||||
var windowId = window.document.title = windowInfo.id;
|
||||
|
||||
var conversationId = windowMap[windowId];
|
||||
// close the panel if background.html is refreshed
|
||||
bg.addEventListener('beforeunload', function () {
|
||||
chrome.windows.remove(windowId);
|
||||
});
|
||||
|
||||
if (typeof conversationId !== 'undefined') {
|
||||
loadConversation(conversationId);
|
||||
}
|
||||
loadConversation(bg.Whisper.windowMap.modelIdFrom(windowId));
|
||||
});
|
||||
|
||||
// lets background.js know when a panel disconnects
|
||||
var port = chrome.runtime.connect({name: "panel_presence"});
|
||||
}());
|
||||
|
|
|
@ -15,39 +15,22 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// This script should only be included in background.html
|
||||
// Whisper.windowMap is defined in background.js
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
window.Whisper = window.Whisper || {};
|
||||
|
||||
// TODO: RJS
|
||||
// resetting for now, but super fragile:
|
||||
// 1. if this file is included in conversation.html we're doomed.
|
||||
// 2. if index.html is refreshed, duplicates can be opened
|
||||
// 2.5. ...and refreshing conversation windows will fuck up.
|
||||
if (!localStorage.getItem('activeConversations')) {
|
||||
localStorage.setItem('activeConversations', '{}');
|
||||
}
|
||||
var windowMap = Whisper.windowMap;
|
||||
|
||||
if (!localStorage.getItem('idPairs')) {
|
||||
localStorage.setItem('idPairs', '{}');
|
||||
}
|
||||
|
||||
// TODO: RJS
|
||||
// How do we normally export from modules like this?
|
||||
// Is it necessary to have n copies of each of these scripts..?
|
||||
// (n Whisper objects, etc in existence) Using localStorage for
|
||||
// sync feels like a hack...
|
||||
//
|
||||
window.openConversation = function openConversation (modelId) {
|
||||
var activeConversations = JSON.parse(localStorage.getItem('activeConversations'));
|
||||
var windowId = activeConversations[modelId];
|
||||
|
||||
var windowId = windowMap.windowIdFrom(modelId);
|
||||
|
||||
// prevent multiple copies of the same conversation from being opened
|
||||
if (!windowId) {
|
||||
localStorage.setItem('activeConversations', JSON.stringify(activeConversations));
|
||||
|
||||
// open the window
|
||||
// open the panel
|
||||
chrome.windows.create({
|
||||
url: 'conversation.html',
|
||||
type: 'panel',
|
||||
|
@ -58,40 +41,26 @@
|
|||
var idPairs = JSON.parse(localStorage.getItem('idPairs'));
|
||||
var newWindowId = windowInfo.id;
|
||||
|
||||
// TODO: RJS
|
||||
// should we make a class for bijection?
|
||||
// bit sketchy that we have to keep these two hashes synced...
|
||||
activeConversations[modelId] = newWindowId;
|
||||
idPairs[newWindowId] = modelId;
|
||||
|
||||
localStorage.setItem('activeConversations', JSON.stringify(activeConversations));
|
||||
localStorage.setItem('idPairs', JSON.stringify(idPairs));
|
||||
windowMap.add({
|
||||
windowId: windowInfo.id,
|
||||
modelId: modelId
|
||||
});
|
||||
});
|
||||
} else {
|
||||
try {
|
||||
chrome.windows.update(windowId, { focused: true }, function () {
|
||||
if (chrome.runtime.lastError) {
|
||||
window.closeConversation(windowId);
|
||||
} else {
|
||||
// Tab exists
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
// TODO: RJS
|
||||
// - should check the err type
|
||||
// - should open a new panel here
|
||||
}
|
||||
// focus the panel
|
||||
chrome.windows.update(windowId, { focused: true }, function () {
|
||||
if (chrome.runtime.lastError) {
|
||||
// panel isn't actually open...
|
||||
window.closeConversation(windowId);
|
||||
|
||||
// ...and so we try again.
|
||||
openConversation(modelId);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
window.closeConversation = function closeConversation (windowId) {
|
||||
var activeConversations = JSON.parse(localStorage.getItem('activeConversations'));
|
||||
var idPairs = JSON.parse(localStorage.getItem('idPairs'));
|
||||
|
||||
delete activeConversations[idPairs[windowId]];
|
||||
delete idPairs[windowId];
|
||||
|
||||
localStorage.setItem('activeConversations', JSON.stringify(activeConversations));
|
||||
localStorage.setItem('idPairs', JSON.stringify(idPairs));
|
||||
windowMap.remove('windowId', windowId);
|
||||
};
|
||||
}());
|
||||
})();
|
||||
|
|
|
@ -19,6 +19,8 @@ var Whisper = Whisper || {};
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
var bg = chrome.extension.getBackgroundPage();
|
||||
|
||||
// list of conversations, showing user/group and last message sent
|
||||
Whisper.ConversationListItemView = Backbone.View.extend({
|
||||
tagName: 'div',
|
||||
|
@ -45,7 +47,7 @@ var Whisper = Whisper || {};
|
|||
this.view = new Whisper.ConversationView({ model: this.model });
|
||||
}
|
||||
|
||||
openConversation(modelId);
|
||||
bg.openConversation(modelId);
|
||||
|
||||
this.model.collection.trigger('selected', this.view);
|
||||
},
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
collection: this.model.messageCollection
|
||||
});
|
||||
$('#header').after(this.view.el);
|
||||
//new ...({el: $(#conversation-container)})
|
||||
|
||||
this.model.fetchMessages({reset: true});
|
||||
},
|
||||
|
||||
|
@ -46,7 +46,9 @@
|
|||
'submit .send': 'sendMessage',
|
||||
'close': 'remove',
|
||||
'click .destroy': 'destroyMessages',
|
||||
'click .new-group-update': 'newGroupUpdate'
|
||||
'click .new-group-update': 'newGroupUpdate',
|
||||
'click .settings-btn': 'toggleSettings',
|
||||
'click .go-back': 'toggleSettings'
|
||||
},
|
||||
|
||||
newGroupUpdate: function() {
|
||||
|
@ -83,20 +85,13 @@
|
|||
}
|
||||
},
|
||||
|
||||
/*addAll: function() {
|
||||
this.collection.each(this.addOne);
|
||||
toggleSettings: function (e) {
|
||||
$('body').toggleClass('settings-open');
|
||||
console.log('toggling');
|
||||
debugger;
|
||||
},
|
||||
addOne: function(model) {
|
||||
var view = new Whisper.Message({model: model});
|
||||
view.render();
|
||||
$(this.el).append(view.el);
|
||||
model.bind('remove', view.remove);
|
||||
},*/
|
||||
|
||||
render: function() {
|
||||
//this.$el.empty();
|
||||
//this.addAll();
|
||||
|
||||
this.delegateEvents();
|
||||
this.view.delegateEvents();
|
||||
this.view.scrollToBottom();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue