diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 1d9c011c2d25..406bb2be1dfb 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1700,9 +1700,9 @@ pref("loop.debug.websocket", false); pref("loop.debug.sdk", false); pref("loop.debug.twoWayMediaTelemetry", false); #ifdef DEBUG -pref("loop.CSP", "default-src 'self' about: file: chrome: http://localhost:*; img-src 'self' data: https://www.gravatar.com/ about: file: chrome:; font-src 'none'; connect-src wss://*.tokbox.com https://*.opentok.com https://*.tokbox.com wss://*.mozilla.com https://*.mozilla.org wss://*.mozaws.net http://localhost:* ws://localhost:*; media-src blob:"); +pref("loop.CSP", "default-src 'self' about: file: chrome: http://localhost:*; img-src *; font-src 'none'; connect-src wss://*.tokbox.com https://*.opentok.com https://*.tokbox.com wss://*.mozilla.com https://*.mozilla.org wss://*.mozaws.net http://localhost:* ws://localhost:*; media-src blob:"); #else -pref("loop.CSP", "default-src 'self' about: file: chrome:; img-src 'self' data: https://www.gravatar.com/ about: file: chrome:; font-src 'none'; connect-src wss://*.tokbox.com https://*.opentok.com https://*.tokbox.com wss://*.mozilla.com https://*.mozilla.org wss://*.mozaws.net; media-src blob:"); +pref("loop.CSP", "default-src 'self' about: file: chrome:; img-src *; font-src 'none'; connect-src wss://*.tokbox.com https://*.opentok.com https://*.tokbox.com wss://*.mozilla.com https://*.mozilla.org wss://*.mozaws.net; media-src blob:"); #endif pref("loop.oauth.google.redirect_uri", "urn:ietf:wg:oauth:2.0:oob:auto"); pref("loop.oauth.google.scope", "https://www.google.com/m8/feeds"); diff --git a/browser/components/loop/MozLoopAPI.jsm b/browser/components/loop/MozLoopAPI.jsm index 67d538ae45b6..68a8f03b39be 100644 --- a/browser/components/loop/MozLoopAPI.jsm +++ b/browser/components/loop/MozLoopAPI.jsm @@ -21,6 +21,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "LoopStorage", "resource:///modules/loop/LoopStorage.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "hookWindowCloseForPanelClose", "resource://gre/modules/MozSocialAPI.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "PageMetadata", + "resource://gre/modules/PageMetadata.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PluralForm", "resource://gre/modules/PluralForm.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "UITour", @@ -844,6 +846,24 @@ function injectLoopAPI(targetWindow) { } }, + /** + * Gets the metadata related to the currently selected tab in + * the most recent window. + * + * @param {Function} A callback that is passed the metadata. + */ + getSelectedTabMetadata: { + value: function(callback) { + let win = Services.wm.getMostRecentWindow("navigator:browser"); + win.messageManager.addMessageListener("PageMetadata:PageDataResult", function onPageDataResult(msg) { + win.messageManager.removeMessageListener("PageMetadata:PageDataResult", onPageDataResult); + let pageData = msg.json; + callback(cloneValueInto(pageData, targetWindow)); + }); + win.gBrowser.selectedBrowser.messageManager.sendAsyncMessage("PageMetadata:GetPageData"); + } + }, + /** * Associates a session-id and a call-id with a window for debugging. * diff --git a/browser/components/loop/content/css/panel.css b/browser/components/loop/content/css/panel.css index 7c8c0dd35a58..c42c72a6adb7 100644 --- a/browser/components/loop/content/css/panel.css +++ b/browser/components/loop/content/css/panel.css @@ -170,25 +170,71 @@ body { /* Rooms */ .rooms { min-height: 100px; + padding: 0 1rem; } .rooms > h1 { font-weight: bold; color: #999; - padding: .5rem 1rem; -} - -.rooms > p { padding: .5rem 0; - margin: 0; } -.rooms > p > .btn { +.rooms > div > .context { + margin: .5rem 0 0; + background-color: #DEEFF7; + border-radius: 3px 3px 0 0; + padding: .5rem; +} + +.rooms > div > .context > .context-enabled { + margin-bottom: .5rem; + display: block; +} + +.rooms > div > .context > .context-enabled > input { + -moz-margin-start: 0; +} + +.rooms > div > .context > .context-preview { + float: right; + width: 100px; + max-height: 200px; + -moz-margin-start: 10px; + margin-bottom: 10px; +} + +body[dir=rtl] .rooms > div > .context > .context-preview { + float: left; +} + +.rooms > div > .context > .context-preview[src=""] { + display: none; +} + +.rooms > div > .context > .context-description { + display: block; + color: #707070; +} + +.rooms > div > .context > .context-url { + display: block; + color: #59A1D7; + clear: both; +} + +.rooms > div > .btn { display: block; font-size: 1rem; - margin: 0 auto; + margin: 0 auto .5rem; + width: 100%; padding: .5rem 1rem; + border-radius: 0 0 3px 3px; +} + +/* Remove when bug 1142671 is backed out. */ +.rooms > div > :not(.context) + .btn { border-radius: 3px; + margin-top: 0.5rem; } .room-list { @@ -197,6 +243,8 @@ body { overflow: auto; border-top: 1px solid #ccc; border-bottom: 1px solid #ccc; + margin-left: -1rem; + margin-right: -1rem; } .room-list:empty { diff --git a/browser/components/loop/content/js/panel.js b/browser/components/loop/content/js/panel.js index 6005a20b7d35..22711093142a 100644 --- a/browser/components/loop/content/js/panel.js +++ b/browser/components/loop/content/js/panel.js @@ -594,6 +594,7 @@ loop.panel = (function(_, mozL10n) { mixins: [Backbone.Events, sharedMixins.WindowCloseMixin], propTypes: { + mozLoop: React.PropTypes.object.isRequired, store: React.PropTypes.instanceOf(loop.store.RoomStore).isRequired, dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired, userDisplayName: React.PropTypes.string.isRequired // for room creation @@ -666,7 +667,8 @@ loop.panel = (function(_, mozL10n) { ); }, this) ), - React.createElement("p", null, + React.createElement("div", null, + React.createElement(ContextInfo, {mozLoop: this.props.mozLoop}), React.createElement("button", {className: "btn btn-info new-room-button", onClick: this.handleCreateButtonClick, disabled: this._hasPendingOperation()}, @@ -678,6 +680,60 @@ loop.panel = (function(_, mozL10n) { } }); + /** + * Context info that is offered to be part of a Room. + */ + var ContextInfo = React.createClass({displayName: "ContextInfo", + propTypes: { + mozLoop: React.PropTypes.object.isRequired, + }, + + mixins: [sharedMixins.DocumentVisibilityMixin], + + getInitialState: function() { + return { + previewImage: "", + description: "", + url: "" + }; + }, + + onDocumentVisible: function() { + this.props.mozLoop.getSelectedTabMetadata(function callback(metadata) { + var previewImage = metadata.previews.length ? metadata.previews[0] : ""; + var description = metadata.description || metadata.title; + var url = metadata.url; + this.setState({previewImage: previewImage, + description: description, + url: url}); + }.bind(this)); + }, + + onDocumentHidden: function() { + this.setState({previewImage: "", + description: "", + url: ""}); + }, + + render: function() { + if (!this.props.mozLoop.getLoopPref("contextInConverations.enabled") || + !this.state.url) { + return null; + } + return ( + React.createElement("div", {className: "context"}, + React.createElement("label", {className: "context-enabled"}, + React.createElement("input", {type: "checkbox"}), + mozL10n.get("context_offer_label") + ), + React.createElement("img", {className: "context-preview", src: this.state.previewImage}), + React.createElement("span", {className: "context-description"}, this.state.description), + React.createElement("span", {className: "context-url"}, this.state.url) + ) + ); + } + }); + /** * Panel view. */ @@ -819,7 +875,8 @@ loop.panel = (function(_, mozL10n) { React.createElement(Tab, {name: "rooms"}, React.createElement(RoomList, {dispatcher: this.props.dispatcher, store: this.props.roomStore, - userDisplayName: this._getUserDisplayName()}), + userDisplayName: this._getUserDisplayName(), + mozLoop: this.props.mozLoop}), React.createElement(ToSView, null) ), React.createElement(Tab, {name: "contacts"}, @@ -890,6 +947,7 @@ loop.panel = (function(_, mozL10n) { init: init, AuthLink: AuthLink, AvailabilityDropdown: AvailabilityDropdown, + ContextInfo: ContextInfo, GettingStartedView: GettingStartedView, PanelView: PanelView, RoomEntry: RoomEntry, diff --git a/browser/components/loop/content/js/panel.jsx b/browser/components/loop/content/js/panel.jsx index 171544bae78e..ca0c600177a4 100644 --- a/browser/components/loop/content/js/panel.jsx +++ b/browser/components/loop/content/js/panel.jsx @@ -594,6 +594,7 @@ loop.panel = (function(_, mozL10n) { mixins: [Backbone.Events, sharedMixins.WindowCloseMixin], propTypes: { + mozLoop: React.PropTypes.object.isRequired, store: React.PropTypes.instanceOf(loop.store.RoomStore).isRequired, dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired, userDisplayName: React.PropTypes.string.isRequired // for room creation @@ -666,13 +667,68 @@ loop.panel = (function(_, mozL10n) { />; }, this) } -
+