diff --git a/add-on/chrome/bootstrap.js b/add-on/chrome/bootstrap.js
index 048d1f22..2956bec5 100644
--- a/add-on/chrome/bootstrap.js
+++ b/add-on/chrome/bootstrap.js
@@ -27,6 +27,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
"resource:///modules/CustomizableUI.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "AboutLoop",
+ "chrome://loop/content/modules/AboutLoop.jsm");
// See LOG_LEVELS in Console.jsm. Common examples: "All", "Info", "Warn", & "Error".
const PREF_LOG_LEVEL = "loop.debug.loglevel";
@@ -347,6 +349,41 @@ var WindowListener = {
this.maybeAddCopyPanel();
this.updateToolbarState();
+
+ this.addSidebar();
+ },
+
+ /* XXX akita make this into it's own object. */
+ addSidebar: function() {
+ let ownerDocument = gBrowser.ownerDocument;
+ var browser = ownerDocument.getElementById("browser");
+
+ let sidebarBrowser = document.createElementNS(kNSXUL, "browser");
+ sidebarBrowser.setAttribute("id", "loop-side-browser");
+ sidebarBrowser.setAttribute("disable-history", "true");
+ sidebarBrowser.setAttribute("disable-global-history", "true");
+
+ // XXX akita something like these seem likely to be required once we
+ // electrolyze this along with a URI_MUST_LOAD_IN_CHILD in
+ // AboutLoop.jsm
+ // sidebarBrowser.setAttribute("message-manager-group", "social");
+ // sidebarBrowser.setAttribute("message", "true");
+ // sidebarBrowser.setAttribute("remote", "true");
+
+ sidebarBrowser.setAttribute("type", "content");
+
+ this.sidebar = sidebarBrowser;
+ this.sidebar.width = 250;
+
+ browser.appendChild(sidebarBrowser);
+ },
+
+ loadSidebar: function(token) {
+ log.info("loadSidebar called:", token, this.sidebar);
+ let url = "about:loopconversation#" + token;
+ Services.perms.add(Services.io.newURI(url, null, null), "camera",
+ Services.perms.ALLOW_ACTION, Services.perms.EXPIRE_SESSION);
+ this.sidebar.setAttribute("src", url);
},
/**
@@ -1360,6 +1397,11 @@ function startup(data) {
return;
}
+ // register about: handlers
+ AboutLoop.conversation.register(); // eslint-disable-line no-undef
+ AboutLoop.panel.register(); // eslint-disable-line no-undef
+ AboutLoop.toc.register(); // eslint-disable-line no-undef
+
createLoopButton();
// Attach to hidden window (for OS X).
@@ -1431,6 +1473,11 @@ function shutdown(data, reason) {
// Stop waiting for browser windows to open.
wm.removeListener(WindowListener);
+ // unregister about: handlers
+ AboutLoop.conversation.unregister(); // eslint-disable-line no-undef
+ AboutLoop.panel.unregister(); // eslint-disable-line no-undef
+ AboutLoop.toc.unregister(); // eslint-disable-line no-undef
+
// If the app is shutting down, don't worry about cleaning up, just let
// it fade away...
if (reason == APP_SHUTDOWN) {
diff --git a/add-on/chrome/modules/AboutLoop.jsm b/add-on/chrome/modules/AboutLoop.jsm
new file mode 100644
index 00000000..5671be16
--- /dev/null
+++ b/add-on/chrome/modules/AboutLoop.jsm
@@ -0,0 +1,114 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+/* Basic code borrowed and adapted from PocketAbout stuff in mozilla-central
+ */
+
+const { interfaces: Ci, results: Cr, manager: Cm, utils: Cu } = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+// See LOG_LEVELS in Console.jsm. Common examples: "All", "Info", "Warn", & "Error".
+const PREF_LOG_LEVEL = "loop.debug.loglevel";
+
+XPCOMUtils.defineLazyGetter(this, "log", () => {
+ let ConsoleAPI = Cu.import("resource://gre/modules/Console.jsm", {}).ConsoleAPI;
+ let consoleOptions = {
+ maxLogLevelPref: PREF_LOG_LEVEL,
+ prefix: "Loop"
+ };
+ return new ConsoleAPI(consoleOptions);
+});
+
+
+function AboutPage(chromeURL, aboutHost, classID, description, uriFlags) {
+this.chromeURL = chromeURL;
+ this.aboutHost = aboutHost;
+ this.classID = Components.ID(classID);
+ this.description = description;
+ this.uriFlags = uriFlags;
+}
+
+AboutPage.prototype = {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),
+ getURIFlags: function(aURI) { // eslint-disable-line no-unused-vars
+ return this.uriFlags;
+ },
+
+ newChannel: function(aURI, aLoadInfo) {
+ let newURI = Services.io.newURI(this.chromeURL, null, null);
+ let channel = Services.io.newChannelFromURIWithLoadInfo(newURI,
+ aLoadInfo);
+ channel.originalURI = aURI;
+
+ if (this.uriFlags & Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT) {
+ let principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(aURI);
+ channel.owner = principal;
+ }
+ return channel;
+ },
+
+ createInstance: function(outer, iid) {
+ if (outer != null) {
+ throw Cr.NS_ERROR_NO_AGGREGATION;
+ }
+ return this.QueryInterface(iid);
+ },
+
+ register: function() {
+ Cm.QueryInterface(Ci.nsIComponentRegistrar).registerFactory(
+ this.classID, this.description,
+ "@mozilla.org/network/protocol/about;1?what=" + this.aboutHost, this);
+ },
+
+ unregister: function() {
+ Cm.QueryInterface(Ci.nsIComponentRegistrar).unregisterFactory(
+ this.classID, this);
+ }
+};
+
+/* exported AboutLoop */
+var AboutLoop = {};
+
+// Note that about:loopconversation and about:looppanel are used in some
+// checks in mozilla-central (eg getUserMedia-related), so if we want to
+// make changes to the URL names themselves, we'll need to change them
+// there too...
+XPCOMUtils.defineLazyGetter(AboutLoop, "conversation", () => {
+ return new AboutPage("chrome://loop/content/panels/sidebar.html",
+ "loopconversation",
+ "E79DB45D-2D6D-48BE-B179-6A16C95E97BA",
+ "About Loop Conversation",
+ Ci.nsIAboutModule.ALLOW_SCRIPT |
+ Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT |
+ Ci.nsIAboutModule.MAKE_UNLINKABLE |
+ Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT |
+ Ci.nsIAboutModule.URI_MUST_LOAD_IN_CHILD);
+});
+
+XPCOMUtils.defineLazyGetter(AboutLoop, "panel", () => {
+ return new AboutPage("chrome://loop/content/panels/panel.html",
+ "looppanel",
+ "A5DE152B-DE58-42BC-A68C-33E00B17EC2C",
+ "About Loop Panel",
+ Ci.nsIAboutModule.ALLOW_SCRIPT |
+ Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT |
+ Ci.nsIAboutModule.MAKE_UNLINKABLE |
+ Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT);
+});
+
+XPCOMUtils.defineLazyGetter(AboutLoop, "toc", () => {
+ return new AboutPage("chrome://loop/content/panels/toc.html",
+ "looptoc",
+ "A1220CE0-E5D1-45B6-BEBA-3706166A2AA4",
+ "About Loop ToC",
+ Ci.nsIAboutModule.ALLOW_SCRIPT |
+ Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT |
+ Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT |
+ Ci.nsIAboutModule.MAKE_UNLINKABLE); // XXX akita-sidebar load in child?
+});
+
+this.EXPORTED_SYMBOLS = ["AboutLoop"];
diff --git a/add-on/chrome/modules/MozLoopAPI.jsm b/add-on/chrome/modules/MozLoopAPI.jsm
index 92b975dc..89bbef80 100644
--- a/add-on/chrome/modules/MozLoopAPI.jsm
+++ b/add-on/chrome/modules/MozLoopAPI.jsm
@@ -211,6 +211,13 @@ const kMessageHandlers = {
reply();
},
+ LoadSidebar: function(message, reply) {
+ let win = Services.wm.getMostRecentWindow("navigator:browser");
+ let [roomToken] = message.data;
+ win.LoopUI.loadSidebar(roomToken);
+ reply();
+ },
+
/**
* Creates a layout for the remote cursor on the browser chrome,
* and positions it on the received coordinates.
@@ -1171,6 +1178,7 @@ const LoopAPIInternal = {
gPageListeners = [new RemotePages("about:looppanel"),
new RemotePages("about:loopconversation"),
+ new RemotePages("about:looptoc"),
// Slideshow added here to expose the loop api to make L10n work.
// XXX Can remove once slideshow is made remote.
new RemotePages("chrome://loop/content/panels/slideshow.html")];
diff --git a/add-on/panels/js/conversation.jsx b/add-on/panels/js/conversation.jsx
deleted file mode 100644
index 57be7912..00000000
--- a/add-on/panels/js/conversation.jsx
+++ /dev/null
@@ -1,252 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var loop = loop || {};
-loop.conversation = (function(mozL10n) {
- "use strict";
-
- var sharedMixins = loop.shared.mixins;
- var sharedActions = loop.shared.actions;
- var FAILURE_DETAILS = loop.shared.utils.FAILURE_DETAILS;
-
- var DesktopRoomConversationView = loop.roomViews.DesktopRoomConversationView;
- var FeedbackView = loop.feedbackViews.FeedbackView;
- var RoomFailureView = loop.roomViews.RoomFailureView;
-
- /**
- * Master controller view for handling if incoming or outgoing calls are
- * in progress, and hence, which view to display.
- */
- var AppControllerView = React.createClass({
- mixins: [
- Backbone.Events,
- loop.store.StoreMixin("conversationAppStore"),
- sharedMixins.DocumentTitleMixin,
- sharedMixins.WindowCloseMixin
- ],
-
- propTypes: {
- cursorStore: React.PropTypes.instanceOf(loop.store.RemoteCursorStore).isRequired,
- dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
- roomStore: React.PropTypes.instanceOf(loop.store.RoomStore)
- },
-
- componentWillMount: function() {
- this.listenTo(this.props.cursorStore, "change:remoteCursorPosition",
- this._onRemoteCursorPositionChange);
- this.listenTo(this.props.cursorStore, "change:remoteCursorClick",
- this._onRemoteCursorClick);
- },
-
- _onRemoteCursorPositionChange: function() {
- loop.request("AddRemoteCursorOverlay",
- this.props.cursorStore.getStoreState("remoteCursorPosition"));
- },
-
- _onRemoteCursorClick: function() {
- let click = this.props.cursorStore.getStoreState("remoteCursorClick");
- // if the click is 'false', assume it is a storeState reset,
- // so don't do anything
- if (!click) {
- return;
- }
-
- this.props.cursorStore.setStoreState({
- remoteCursorClick: false
- });
-
- loop.request("ClickRemoteCursor", click);
- },
-
- getInitialState: function() {
- return this.getStoreState();
- },
-
- _renderFeedbackForm: function() {
- this.setTitle(mozL10n.get("conversation_has_ended"));
-
- return (
{"If you see this, please file a bug"}
+