diff --git a/background.html b/background.html
index 9f665f44..30017728 100644
--- a/background.html
+++ b/background.html
@@ -24,6 +24,8 @@
+
+
diff --git a/index2.html b/index2.html
index 9571a887..026bfbd8 100644
--- a/index2.html
+++ b/index2.html
@@ -57,6 +57,9 @@
+
+
+
diff --git a/js/background.js b/js/background.js
index b91f8c45..af872969 100644
--- a/js/background.js
+++ b/js/background.js
@@ -225,4 +225,12 @@
extension.on('log', console.log.bind(console));
+ chrome.runtime.onConnect.addListener(function (port) {
+ if (port.name === 'panel_presence') {
+ port.onDisconnect.addListener(function (message) {
+ closeConversation(message.sender.tab.windowId);
+ });
+ }
+ });
+
})();
diff --git a/js/conversation_panel.js b/js/conversation_panel.js
index 56feab88..afbf7ed6 100644
--- a/js/conversation_panel.js
+++ b/js/conversation_panel.js
@@ -26,12 +26,9 @@
});
};
- var windowId, windowMap = {};
-
- extension.trigger('log', 'loaded page');
+ var windowId, windowMap = JSON.parse(localStorage.getItem('idPairs'));
window.addEventListener('storage', function (e) {
- extension.trigger('log', 'got storage event');
if (e.key = 'idPairs') {
windowMap = JSON.parse(e.newValue);
@@ -48,12 +45,13 @@
chrome.windows.getCurrent(function (windowInfo) {
window.document.title = windowId = windowInfo.id;
- extension.trigger('log', 'got page id');
-
var conversationId = windowMap[windowId];
if (typeof conversationId !== 'undefined') {
loadConversation(conversationId);
}
});
+
+ // lets background.js know when a panel disconnects
+ var port = chrome.runtime.connect({name: "panel_presence"});
}());
diff --git a/js/panel_controller.js b/js/panel_controller.js
new file mode 100644
index 00000000..9b29ebe2
--- /dev/null
+++ b/js/panel_controller.js
@@ -0,0 +1,97 @@
+/*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 .
+ */
+
+(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', '{}');
+ }
+
+ 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];
+
+ // prevent multiple copies of the same conversation from being opened
+ if (!windowId) {
+ localStorage.setItem('activeConversations', JSON.stringify(activeConversations));
+
+ // open the window
+ chrome.windows.create({
+ url: 'conversation.html',
+ type: 'panel',
+ focused: true,
+ width: 280,
+ height: 420
+ }, function (windowInfo) {
+ 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));
+ });
+ } 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
+ }
+ }
+ };
+
+ 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));
+ };
+}());
diff --git a/js/views/conversation_list_item_view.js b/js/views/conversation_list_item_view.js
index d527a390..e221d282 100644
--- a/js/views/conversation_list_item_view.js
+++ b/js/views/conversation_list_item_view.js
@@ -45,21 +45,7 @@ var Whisper = Whisper || {};
this.view = new Whisper.ConversationView({ model: this.model });
}
- chrome.windows.create({
- url: 'conversation.html#' + modelId,
- type: 'panel',
- focused: true,
- width: 280,
- height: 420
- }, function (windowInfo) {
- extension.trigger('log', 'maybe up here?');
- extension.trigger('log', localStorage.getItem('idPairs'));
-
- var idPairs = JSON.parse(localStorage.getItem('idPairs') || '{}');
- idPairs[windowInfo.id] = modelId;
- localStorage.setItem('idPairs', JSON.stringify(idPairs));
- extension.trigger('log', 'set idPairs item');
- });
+ openConversation(modelId);
this.model.collection.trigger('selected', this.view);
},
diff --git a/js/views/file_input_view.js b/js/views/file_input_view.js
index 634b17f5..6b9f8709 100644
--- a/js/views/file_input_view.js
+++ b/js/views/file_input_view.js
@@ -17,6 +17,7 @@ var Whisper = Whisper || {};
(function () {
'use strict';
+
Whisper.FileInputView = Backbone.View.extend({
tagName: 'span',
className: 'file-input',