Skip to content

Commit 6d19be8

Browse files
authored
Merge pull request #2452 from uProxy/background-ui
Add a component to live in the real background
2 parents f0e13e9 + cadf902 commit 6d19be8

File tree

18 files changed

+418
-56
lines changed

18 files changed

+418
-56
lines changed

src/cca/app/scripts/context.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import user_interface = require('../../../generic_ui/scripts/ui');
66
import CoreConnector = require('../../../generic_ui/scripts/core_connector');
77
import CordovaCoreConnector = require('./cordova_core_connector');
88

9-
var ui_context :UiGlobals;
109
export var browserConnector = new CordovaCoreConnector({
1110
name: 'uproxy-ui-to-core-connector'
1211
});
@@ -15,8 +14,8 @@ export var ui :user_interface.UserInterface;
1514
export var model :ui_model.Model;
1615

1716
chrome.runtime.getBackgroundPage((bgPage) => {
18-
ui_context = (<any>bgPage).ui_context;
19-
ui = new user_interface.UserInterface(core, ui_context.browserApi);
17+
var ui_context = (<any>bgPage).ui_context;
18+
ui = new user_interface.UserInterface(core, ui_context.browserApi, ui_context.backgroundUi);
2019
model = ui.model;
2120
console.log('Got references from background page; importing vulcanized');
2221

src/chrome/extension/scripts/background.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,25 @@
99
// Assumes that core_stub.ts has been loaded.
1010
// UserInterface is defined in 'generic_ui/scripts/ui.ts'.
1111

12+
import background_ui = require('../../../generic_ui/scripts/background_ui');
13+
import chrome_panel_connector = require('./chrome_panel_connector');
1214
import ChromeBrowserApi = require('./chrome_browser_api');
1315
import ChromeCoreConnector = require('./chrome_core_connector');
1416
import ChromeTabAuth = require('./chrome_tab_auth');
15-
16-
import UiApi = require('../../../interfaces/ui');
17-
import user_interface = require('../../../generic_ui/scripts/ui');
18-
import CoreConnector = require('../../../generic_ui/scripts/core_connector');
19-
import uproxy_core_api = require('../../../interfaces/uproxy_core_api');
2017
import Constants = require('../../../generic_ui/scripts/constants');
18+
import CoreConnector = require('../../../generic_ui/scripts/core_connector');
19+
import user_interface = require('../../../generic_ui/scripts/ui');
20+
2121
import compareVersion = require('compare-version');
22+
import uproxy_core_api = require('../../../interfaces/uproxy_core_api');
2223

2324
/// <reference path='../../../freedom/typings/social.d.ts' />
2425
/// <reference path='../../../third_party/typings/chrome/chrome.d.ts'/>
2526

2627
// --------------------- Communicating with the App ----------------------------
2728
export var browserConnector :ChromeCoreConnector; // way for ui to speak to a uProxy.CoreApi
2829
export var core :CoreConnector; // way for ui to speak to a uProxy.CoreApi
30+
export var backgroundUi: background_ui.BackgroundUi;
2931
export var browserApi :ChromeBrowserApi;
3032
// Chrome Window ID of the window used to launch uProxy,
3133
// i.e. the window where the extension icon was clicked
@@ -146,7 +148,20 @@ core = new CoreConnector(browserConnector);
146148
var oAuth = new ChromeTabAuth();
147149
browserConnector.onUpdate(uproxy_core_api.Update.GET_CREDENTIALS,
148150
oAuth.login.bind(oAuth));
149-
var ui = new user_interface.UserInterface(core, browserApi);
151+
152+
backgroundUi = new background_ui.BackgroundUi(
153+
new chrome_panel_connector.ChromePanelConnector(),
154+
core);
155+
156+
/*
157+
* TODO: this is a separate user_interface object from the one we refer to
158+
* elsewhere in the code. It will register listeners for all events and
159+
* commands, however, these listeners will immediately be unbound after the
160+
* panel is opened for the first time. Its version of any data should not be
161+
* relied upon as canonical and no updates made to data here should be expected
162+
* to persist within the general UI.
163+
*/
164+
var ui = new user_interface.UserInterface(core, browserApi, backgroundUi);
150165

151166
// used for de-duplicating urls caught by the listeners
152167
var lastUrl = '';
@@ -206,4 +221,3 @@ chrome.webRequest.onBeforeRequest.addListener(
206221
{ urls: ['https://www.uproxy.org/request/*', 'https://www.uproxy.org/offer/*'] },
207222
['blocking']
208223
);
209-

src/chrome/extension/scripts/chrome_core_connector.spec.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/// <reference path='../../../../../third_party/typings/browser.d.ts'/>
22

3+
import background_ui = require('../../../generic_ui/scripts/background_ui');
34
import ChromeCoreConnector = require('./chrome_core_connector');
45
import ChromeBrowserApi = require('./chrome_browser_api');
56
import CoreConnector = require('../../../generic_ui/scripts/core_connector');
@@ -31,6 +32,7 @@ var mockAppPort = () => {
3132

3233
var chromeBrowserApi :ChromeBrowserApi;
3334
var chromeCoreConnector = new ChromeCoreConnector();
35+
var backgroundUi :background_ui.BackgroundUi;
3436
var core = new CoreConnector(chromeCoreConnector);
3537

3638
// The ordering of the specs matter, as they provide a connect / disconnect
@@ -42,12 +44,15 @@ describe('core-connector', () => {
4244
'on',
4345
'handlePopupLaunch']);
4446

45-
47+
backgroundUi = jasmine.createSpyObj('BackgroundUi', [
48+
'registerAsFakeBackground',
49+
'fireSignal'
50+
]);
4651

4752
var connectPromise :Promise<void>;
4853

4954
beforeEach(() => {
50-
ui = new UI.UserInterface(core, chromeBrowserApi);
55+
ui = new UI.UserInterface(core, chromeBrowserApi, backgroundUi);
5156
spyOn(console, 'log');
5257
spyOn(console, 'warn');
5358
});
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/// <reference path='../../../../../third_party/typings/browser.d.ts'/>
2+
3+
import panel_connector = require('../../../interfaces/panel_connector');
4+
5+
export class ChromePanelConnector implements panel_connector.BrowserPanelConnector {
6+
public startListening(
7+
connectHandler: panel_connector.PanelConnectHandler,
8+
messageHandler: panel_connector.MessageHandler,
9+
disconnectHandler: panel_connector.PanelDisconnectHandler) {
10+
chrome.runtime.onConnect.addListener((port: chrome.runtime.Port) => {
11+
let panel = new ChromePanel(port, messageHandler, disconnectHandler);
12+
connectHandler(panel);
13+
});
14+
}
15+
}
16+
17+
interface MessageFormat {
18+
name: string;
19+
data: Object;
20+
}
21+
22+
class ChromePanel implements panel_connector.Panel {
23+
private _port: chrome.runtime.Port;
24+
25+
constructor(
26+
port: chrome.runtime.Port,
27+
messageHandler: panel_connector.MessageHandler,
28+
disconnectHandler: panel_connector.PanelDisconnectHandler) {
29+
this._port = port;
30+
31+
this._port.onMessage.addListener((message: MessageFormat) => {
32+
messageHandler(message.name, message.data);
33+
});
34+
35+
this._port.onDisconnect.addListener(() => {
36+
disconnectHandler(this);
37+
});
38+
}
39+
40+
public sendMessage(name: string, data?: Object) {
41+
var message: MessageFormat = { name: name, data: data };
42+
43+
this._port.postMessage(message);
44+
}
45+
}

src/chrome/extension/scripts/context.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,15 @@ import CoreConnector = require('../../../generic_ui/scripts/core_connector');
88
import ChromeCoreConnector = require('./chrome_core_connector');
99
import browser_connector = require('../../../interfaces/browser_connector');
1010

11-
var ui_context :UiGlobals = (<any>chrome.extension.getBackgroundPage()).ui_context;
12-
export var core :CoreConnector = ui_context.core;
13-
export var browserConnector :browser_connector.CoreBrowserConnector = ui_context.browserConnector;
11+
var background_context: any = (<any>chrome.extension.getBackgroundPage()).ui_context;
12+
export var core :CoreConnector = background_context.core;
13+
export var browserConnector :browser_connector.CoreBrowserConnector = background_context.browserConnector;
14+
15+
export var ui :user_interface.UserInterface =
16+
new user_interface.UserInterface(core,
17+
background_context.browserApi,
18+
background_context.backgroundUi);
1419

15-
export var ui :user_interface.UserInterface = new user_interface.UserInterface(core, ui_context.browserApi);
1620
export var model :ui_model.Model = ui.model;
1721

1822
ui.browser = 'chrome';

src/firefox/data/scripts/background.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,28 @@
1-
import ui_model = require('../../../generic_ui/scripts/model');
2-
import user_interface = require('../../../generic_ui/scripts/ui');
1+
import background_ui = require('../../../generic_ui/scripts/background_ui');
32
import CoreConnector = require('../../../generic_ui/scripts/core_connector');
4-
import FirefoxCoreConnector = require('./firefox_connector');
53
import FirefoxBrowserApi = require('./firefox_browser_api');
4+
import FirefoxCoreConnector = require('./firefox_connector');
5+
import firefox_panel_connector = require('./firefox_panel_connector');
6+
import ui_model = require('../../../generic_ui/scripts/model');
7+
import panel_connector = require('../../../interfaces/panel_connector');
68
import port = require('./port');
9+
import user_interface = require('../../../generic_ui/scripts/ui');
710

811
export var ui :user_interface.UserInterface;
912
export var core :CoreConnector;
1013
export var browserConnector :FirefoxCoreConnector;
1114
export var model :ui_model.Model;
15+
export var panelConnector: panel_connector.BrowserPanelConnector;
1216
var firefoxBrowserApi :FirefoxBrowserApi;
1317

1418
function initUI() {
1519
browserConnector = new FirefoxCoreConnector();
1620
core = new CoreConnector(browserConnector);
1721
firefoxBrowserApi = new FirefoxBrowserApi();
22+
panelConnector = new firefox_panel_connector.FirefoxPanelConnector();
23+
var backgroundUi = new background_ui.BackgroundUi(panelConnector, core);
1824

19-
return new user_interface.UserInterface(core, firefoxBrowserApi);
25+
return new user_interface.UserInterface(core, firefoxBrowserApi, backgroundUi);
2026
}
2127

2228
if (undefined === ui) {
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/**
2+
* In Firefox, we have a very strict singleton way of handling the panel where
3+
* we can guarantee that only one panel will ever be created and its state will
4+
* never be altered. Given that all scripts are running in the same
5+
* environment, we have an insanely simple way of representing that here
6+
*/
7+
import panel_connector = require('../../../interfaces/panel_connector');
8+
9+
export class FirefoxPanelConnector implements panel_connector.BrowserPanelConnector {
10+
private connectHandler: panel_connector.PanelConnectHandler;
11+
private messageHandler: panel_connector.MessageHandler;
12+
private disconnectHandler: panel_connector.PanelDisconnectHandler;
13+
private currentPanel: panel_connector.Panel = null;
14+
15+
public startListening(
16+
connectHandler: panel_connector.PanelConnectHandler,
17+
messageHandler: panel_connector.MessageHandler,
18+
disconnectHandler: panel_connector.PanelDisconnectHandler) {
19+
this.connectHandler = connectHandler;
20+
this.messageHandler = messageHandler;
21+
this.disconnectHandler = disconnectHandler;
22+
}
23+
24+
public panelConnect(fn: panel_connector.MessageHandler) {
25+
if (this.currentPanel) {
26+
this.disconnectHandler(this.currentPanel);
27+
}
28+
29+
this.currentPanel = new DummyPanel(fn);
30+
this.connectHandler(this.currentPanel);
31+
}
32+
33+
public sendMessageFromPanel(name: string, data: Object): void {
34+
this.messageHandler(name, data);
35+
}
36+
}
37+
38+
class DummyPanel implements panel_connector.Panel {
39+
private sendMessageHandler: panel_connector.MessageHandler;
40+
41+
constructor(sendMessageHandler: panel_connector.MessageHandler) {
42+
this.sendMessageHandler = sendMessageHandler;
43+
}
44+
45+
public sendMessage(name: string, data: Object) {
46+
return this.sendMessageHandler(name, data);
47+
}
48+
}

src/generic_ui/polymer/context.d.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ interface UiGlobals {
1818
browserApi :any;
1919

2020
// Corresponds to interfaces/browser_connector.ts Interface: CoreBrowserConnector
21-
browserConnector :any
21+
browserConnector :any;
22+
23+
// Firefox only, hack for background UI
24+
panelConnector: any;
2225
}
2326

2427
// Defined in: firefox and chrome specific background pages.

src/generic_ui/polymer/root.html

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,25 @@
99
<link rel="import" href="../../bower/paper-tabs/paper-tabs.html">
1010
<link rel="import" href="../../bower/core-tooltip/core-tooltip.html">
1111
<link rel="import" href="../../bower/core-overlay/core-overlay.html">
12-
<link rel='import' href='invite-user.html'>
13-
<link rel="import" href="i18n-filter.html">
14-
<link rel="import" href='splash.html'>
15-
<link rel="import" href='faq.html'>
16-
<link rel="import" href='roster.html'>
17-
<link rel="import" href='settings.html'>
18-
<link rel="import" href='logs.html'>
19-
<link rel='import' href='copypaste.html'>
20-
<link rel='import' href='bubble.html'>
21-
<link rel='import' href='feedback.html'>
2212
<link rel='import' href='advanced-settings.html'>
23-
<link rel='import' href='reconnect.html'>
24-
<link rel='import' href='troubleshoot.html'>
25-
<link rel='import' href='dialog.html'>
2613
<link rel='import' href='browser-elements.html'>
14+
<link rel='import' href='bubble.html'>
15+
<link rel='import' href='button.html'>
16+
<link rel='import' href='copypaste.html'>
17+
<link rel='import' href='dialog.html'>
18+
<link rel="import" href='faq.html'>
19+
<link rel='import' href='feedback.html'>
20+
<link rel="import" href="i18n-filter.html">
2721
<link rel='import' href='icons.html'>
22+
<link rel='import' href='invite-user.html'>
23+
<link rel="import" href='logs.html'>
2824
<link rel='import' href='proxy-error.html'>
29-
<link rel='import' href='button.html'>
25+
<link rel='import' href='reconnect.html'>
26+
<link rel="import" href='roster.html'>
27+
<link rel="import" href='settings.html'>
28+
<link rel="import" href='splash.html'>
29+
<link rel='import' href='state.html'>
30+
<link rel='import' href='troubleshoot.html'>
3031

3132
<polymer-element name='uproxy-root' attributes='model' on-open-dialog='{{ openDialog }}'>
3233

@@ -276,6 +277,7 @@
276277
margin: 4px auto 0;
277278
}
278279
</style>
280+
<uproxy-state id="state"></uproxy-state>
279281

280282
<core-signals on-core-signal-close-settings="{{ closeSettings }}"></core-signals>
281283

src/generic_ui/polymer/root.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import user_interface = require('../scripts/ui');
88
import user_module = require('../scripts/user');
99

1010
var ui = ui_context.ui;
11-
var core = ui_context.core;
1211
var model = ui_context.model;
1312
var RTL_LANGUAGES :string[] = ['ar', 'fa', 'ur', 'he'];
1413

@@ -44,7 +43,7 @@ Polymer({
4443
// uproxy-bubble, now the only welcome content is on the splash screen
4544
// and the empty roster text.
4645
model.globalSettings.hasSeenWelcome = true;
47-
core.updateGlobalSettings(model.globalSettings);
46+
this.$.state.updateGlobalSettings(model.globalSettings);
4847
}
4948
},
5049
statsIconClicked: function() {
@@ -63,7 +62,7 @@ Polymer({
6362
},
6463
closedSharing: function() {
6564
model.globalSettings.hasSeenSharingEnabledScreen = true;
66-
core.updateGlobalSettings(model.globalSettings);
65+
this.$.state.updateGlobalSettings(model.globalSettings);
6766
},
6867
dismissCopyPasteError: function() {
6968
ui.copyPasteError = ui_types.CopyPasteError.NONE;
@@ -147,7 +146,7 @@ Polymer({
147146
ready: function() {
148147
// Expose global ui object and UI module in this context.
149148
this.ui = ui;
150-
this.core = core;
149+
this.core = ui_context.core;
151150
this.ui_constants = ui_types;
152151
this.user_interface = user_interface;
153152
this.model = model;
@@ -167,7 +166,7 @@ Polymer({
167166
} else {
168167
// setting the value is taken care of in the polymer binding, we just need
169168
// to sync the value to core
170-
core.updateGlobalSettings(model.globalSettings);
169+
this.$.state.updateGlobalSettings(model.globalSettings);
171170
}
172171
},
173172
signalToFireChanged: function() {
@@ -245,7 +244,7 @@ Polymer({
245244
}
246245
},
247246
restart: function() {
248-
core.restart();
247+
this.$.state.restart();
249248
},
250249
fireOpenInviteUserPanel: function() {
251250
this.fire('core-signal', { name: 'open-invite-user-dialog' });

0 commit comments

Comments
 (0)