mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1097703 - Enable install/open FxOS Loop client from standalone UI for ROOM. r=mbanner
This commit is contained in:
parent
3b5b8cdf05
commit
94e8297c83
@ -37,6 +37,8 @@
|
||||
<script type="text/javascript" src="loop/shared/js/store.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/roomStore.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/conversationStore.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/roomStates.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/fxOSActiveRoomStore.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/activeRoomStore.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/feedbackStore.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/feedbackViews.js"></script>
|
||||
|
@ -29,6 +29,8 @@
|
||||
<script type="text/javascript" src="loop/shared/js/dispatcher.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/store.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/roomStore.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/roomStates.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/fxOSActiveRoomStore.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/js/activeRoomStore.js"></script>
|
||||
<script type="text/javascript" src="loop/js/client.js"></script>
|
||||
<script type="text/javascript;version=1.8" src="loop/js/contacts.js"></script>
|
||||
|
@ -21,31 +21,7 @@ loop.store.ActiveRoomStore = (function() {
|
||||
ROOM_FULL: 202
|
||||
};
|
||||
|
||||
var ROOM_STATES = loop.store.ROOM_STATES = {
|
||||
// The initial state of the room
|
||||
INIT: "room-init",
|
||||
// The store is gathering the room data
|
||||
GATHER: "room-gather",
|
||||
// The store has got the room data
|
||||
READY: "room-ready",
|
||||
// Obtaining media from the user
|
||||
MEDIA_WAIT: "room-media-wait",
|
||||
// The room is known to be joined on the loop-server
|
||||
JOINED: "room-joined",
|
||||
// The room is connected to the sdk server.
|
||||
SESSION_CONNECTED: "room-session-connected",
|
||||
// There are participants in the room.
|
||||
HAS_PARTICIPANTS: "room-has-participants",
|
||||
// There was an issue with the room
|
||||
FAILED: "room-failed",
|
||||
// The room is full
|
||||
FULL: "room-full",
|
||||
// The room conversation has ended
|
||||
ENDED: "room-ended",
|
||||
// The window is closing
|
||||
CLOSING: "room-closing"
|
||||
};
|
||||
|
||||
var ROOM_STATES = loop.store.ROOM_STATES;
|
||||
/**
|
||||
* Active room store.
|
||||
*
|
||||
|
164
browser/components/loop/content/shared/js/fxOSActiveRoomStore.js
Normal file
164
browser/components/loop/content/shared/js/fxOSActiveRoomStore.js
Normal file
@ -0,0 +1,164 @@
|
||||
/* 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/. */
|
||||
|
||||
/* global loop:true */
|
||||
|
||||
var loop = loop || {};
|
||||
loop.store = loop.store || {};
|
||||
|
||||
loop.store.FxOSActiveRoomStore = (function() {
|
||||
"use strict";
|
||||
var sharedActions = loop.shared.actions;
|
||||
var ROOM_STATES = loop.store.ROOM_STATES;
|
||||
|
||||
var FxOSActiveRoomStore = loop.store.createStore({
|
||||
actions: [
|
||||
"fetchServerData"
|
||||
],
|
||||
|
||||
initialize: function(options) {
|
||||
if (!options.mozLoop) {
|
||||
throw new Error("Missing option mozLoop");
|
||||
}
|
||||
this._mozLoop = options.mozLoop;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns initial state data for this active room.
|
||||
*/
|
||||
getInitialStoreState: function() {
|
||||
return {
|
||||
roomState: ROOM_STATES.INIT,
|
||||
audioMuted: false,
|
||||
videoMuted: false,
|
||||
failureReason: undefined
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Registers the actions with the dispatcher that this store is interested
|
||||
* in after the initial setup has been performed.
|
||||
*/
|
||||
_registerPostSetupActions: function() {
|
||||
this.dispatcher.register(this, [
|
||||
"joinRoom"
|
||||
]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Execute fetchServerData event action from the dispatcher. Although
|
||||
* this is to fetch the server data - for rooms on the standalone client,
|
||||
* we don't actually need to get any data. Therefore we just save the
|
||||
* data that is given to us for when the user chooses to join the room.
|
||||
*
|
||||
* @param {sharedActions.FetchServerData} actionData
|
||||
*/
|
||||
fetchServerData: function(actionData) {
|
||||
if (actionData.windowType !== "room") {
|
||||
// Nothing for us to do here, leave it to other stores.
|
||||
return;
|
||||
}
|
||||
|
||||
this._registerPostSetupActions();
|
||||
|
||||
this.setStoreState({
|
||||
roomToken: actionData.token,
|
||||
roomState: ROOM_STATES.READY
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the action to join to a room.
|
||||
*/
|
||||
joinRoom: function() {
|
||||
// Reset the failure reason if necessary.
|
||||
if (this.getStoreState().failureReason) {
|
||||
this.setStoreState({failureReason: undefined});
|
||||
}
|
||||
|
||||
this._setupOutgoingRoom(true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets up an outgoing room. It will try launching the activity to let the
|
||||
* FirefoxOS loop app handle the call. If the activity fails:
|
||||
* - if installApp is true, then it'll try to install the FirefoxOS loop
|
||||
* app.
|
||||
* - if installApp is false, then it'll just log and error and fail.
|
||||
*
|
||||
* @param {boolean} installApp
|
||||
*/
|
||||
_setupOutgoingRoom: function(installApp) {
|
||||
var request = new MozActivity({
|
||||
name: "room-call",
|
||||
data: {
|
||||
type: "loop/rToken",
|
||||
token: this.getStoreState("roomToken")
|
||||
}
|
||||
});
|
||||
|
||||
request.onsuccess = function() {};
|
||||
|
||||
request.onerror = (function(event) {
|
||||
if (!installApp) {
|
||||
// This really should not happen ever.
|
||||
console.error(
|
||||
"Unexpected activity launch error after the app has been installed");
|
||||
return;
|
||||
}
|
||||
if (event.target.error.name !== "NO_PROVIDER") {
|
||||
console.error ("Unexpected " + event.target.error.name);
|
||||
return;
|
||||
}
|
||||
// We need to install the FxOS app.
|
||||
this.setStoreState({
|
||||
marketplaceSrc: loop.config.marketplaceUrl,
|
||||
onMarketplaceMessage: this._onMarketplaceMessage.bind(this)
|
||||
});
|
||||
}).bind(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* This method will handle events generated on the marketplace frame. It
|
||||
* will launch the FirefoxOS loop app installation, and receive the result
|
||||
* of the installation.
|
||||
*
|
||||
* @param {DOMEvent} event
|
||||
*/
|
||||
_onMarketplaceMessage: function(event) {
|
||||
var message = event.data;
|
||||
switch (message.name) {
|
||||
case "loaded":
|
||||
var marketplace = window.document.getElementById("marketplace");
|
||||
// Once we have it loaded, we request the installation of the FxOS
|
||||
// Loop client app. We will be receiving the result of this action
|
||||
// via postMessage from the child iframe.
|
||||
marketplace.contentWindow.postMessage({
|
||||
"name": "install-package",
|
||||
"data": {
|
||||
"product": {
|
||||
"name": loop.config.fxosApp.name,
|
||||
"manifest_url": loop.config.fxosApp.manifestUrl,
|
||||
"is_packaged": true
|
||||
}
|
||||
}
|
||||
}, "*");
|
||||
break;
|
||||
case "install-package":
|
||||
window.removeEventListener("message", this.onMarketplaceMessage);
|
||||
if (message.error) {
|
||||
console.error(message.error.error);
|
||||
return;
|
||||
}
|
||||
// We installed the FxOS app, so we can continue with the call
|
||||
// process.
|
||||
this._setupOutgoingRoom(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return FxOSActiveRoomStore;
|
||||
})();
|
33
browser/components/loop/content/shared/js/roomStates.js
Normal file
33
browser/components/loop/content/shared/js/roomStates.js
Normal file
@ -0,0 +1,33 @@
|
||||
/* 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/. */
|
||||
|
||||
/* global loop:true */
|
||||
|
||||
var loop = loop || {};
|
||||
loop.store = loop.store || {};
|
||||
|
||||
loop.store.ROOM_STATES = {
|
||||
// The initial state of the room
|
||||
INIT: "room-init",
|
||||
// The store is gathering the room data
|
||||
GATHER: "room-gather",
|
||||
// The store has got the room data
|
||||
READY: "room-ready",
|
||||
// Obtaining media from the user
|
||||
MEDIA_WAIT: "room-media-wait",
|
||||
// The room is known to be joined on the loop-server
|
||||
JOINED: "room-joined",
|
||||
// The room is connected to the sdk server.
|
||||
SESSION_CONNECTED: "room-session-connected",
|
||||
// There are participants in the room.
|
||||
HAS_PARTICIPANTS: "room-has-participants",
|
||||
// There was an issue with the room
|
||||
FAILED: "room-failed",
|
||||
// The room is full
|
||||
FULL: "room-full",
|
||||
// The room conversation has ended
|
||||
ENDED: "room-ended",
|
||||
// The window is closing
|
||||
CLOSING: "room-closing"
|
||||
};
|
@ -66,22 +66,24 @@ browser.jar:
|
||||
content/browser/loop/shared/img/telefonica@2x.png (content/shared/img/telefonica@2x.png)
|
||||
|
||||
# Shared scripts
|
||||
content/browser/loop/shared/js/actions.js (content/shared/js/actions.js)
|
||||
content/browser/loop/shared/js/conversationStore.js (content/shared/js/conversationStore.js)
|
||||
content/browser/loop/shared/js/store.js (content/shared/js/store.js)
|
||||
content/browser/loop/shared/js/roomStore.js (content/shared/js/roomStore.js)
|
||||
content/browser/loop/shared/js/activeRoomStore.js (content/shared/js/activeRoomStore.js)
|
||||
content/browser/loop/shared/js/feedbackStore.js (content/shared/js/feedbackStore.js)
|
||||
content/browser/loop/shared/js/dispatcher.js (content/shared/js/dispatcher.js)
|
||||
content/browser/loop/shared/js/feedbackApiClient.js (content/shared/js/feedbackApiClient.js)
|
||||
content/browser/loop/shared/js/models.js (content/shared/js/models.js)
|
||||
content/browser/loop/shared/js/mixins.js (content/shared/js/mixins.js)
|
||||
content/browser/loop/shared/js/otSdkDriver.js (content/shared/js/otSdkDriver.js)
|
||||
content/browser/loop/shared/js/views.js (content/shared/js/views.js)
|
||||
content/browser/loop/shared/js/feedbackViews.js (content/shared/js/feedbackViews.js)
|
||||
content/browser/loop/shared/js/utils.js (content/shared/js/utils.js)
|
||||
content/browser/loop/shared/js/validate.js (content/shared/js/validate.js)
|
||||
content/browser/loop/shared/js/websocket.js (content/shared/js/websocket.js)
|
||||
content/browser/loop/shared/js/actions.js (content/shared/js/actions.js)
|
||||
content/browser/loop/shared/js/conversationStore.js (content/shared/js/conversationStore.js)
|
||||
content/browser/loop/shared/js/store.js (content/shared/js/store.js)
|
||||
content/browser/loop/shared/js/roomStore.js (content/shared/js/roomStore.js)
|
||||
content/browser/loop/shared/js/roomStates.js (content/shared/js/roomStates.js)
|
||||
content/browser/loop/shared/js/fxOSActiveRoomStore.js (content/shared/js/fxOSActiveRoomStore.js)
|
||||
content/browser/loop/shared/js/activeRoomStore.js (content/shared/js/activeRoomStore.js)
|
||||
content/browser/loop/shared/js/feedbackStore.js (content/shared/js/feedbackStore.js)
|
||||
content/browser/loop/shared/js/dispatcher.js (content/shared/js/dispatcher.js)
|
||||
content/browser/loop/shared/js/feedbackApiClient.js (content/shared/js/feedbackApiClient.js)
|
||||
content/browser/loop/shared/js/models.js (content/shared/js/models.js)
|
||||
content/browser/loop/shared/js/mixins.js (content/shared/js/mixins.js)
|
||||
content/browser/loop/shared/js/otSdkDriver.js (content/shared/js/otSdkDriver.js)
|
||||
content/browser/loop/shared/js/views.js (content/shared/js/views.js)
|
||||
content/browser/loop/shared/js/feedbackViews.js (content/shared/js/feedbackViews.js)
|
||||
content/browser/loop/shared/js/utils.js (content/shared/js/utils.js)
|
||||
content/browser/loop/shared/js/validate.js (content/shared/js/validate.js)
|
||||
content/browser/loop/shared/js/websocket.js (content/shared/js/websocket.js)
|
||||
|
||||
# Shared libs
|
||||
#ifdef DEBUG
|
||||
|
@ -83,6 +83,7 @@ config:
|
||||
@echo "loop.config.learnMoreUrl = '`echo $(LOOP_PRODUCT_HOMEPAGE_URL)`';" >> content/config.js
|
||||
@echo "loop.config.fxosApp = loop.config.fxosApp || {};" >> content/config.js
|
||||
@echo "loop.config.fxosApp.name = 'Loop';" >> content/config.js
|
||||
@echo "loop.config.fxosApp.rooms = true;" >> content/config.js
|
||||
@echo "loop.config.fxosApp.manifestUrl = 'http://fake-market.herokuapp.com/apps/packagedApp/manifest.webapp';" >> content/config.js
|
||||
@echo "loop.config.roomsSupportUrl = 'https://support.mozilla.org/kb/group-conversations-firefox-hello-webrtc';" >> content/config.js
|
||||
@echo "loop.config.guestSupportUrl = 'https://support.mozilla.org/kb/respond-firefox-hello-invitation-guest-mode';" >> content/config.js
|
||||
|
@ -98,12 +98,15 @@
|
||||
<script type="text/javascript" src="shared/js/websocket.js"></script>
|
||||
<script type="text/javascript" src="shared/js/otSdkDriver.js"></script>
|
||||
<script type="text/javascript" src="shared/js/store.js"></script>
|
||||
<script type="text/javascript" src="shared/js/roomStates.js"></script>
|
||||
<script type="text/javascript" src="shared/js/fxOSActiveRoomStore.js"></script>
|
||||
<script type="text/javascript" src="shared/js/activeRoomStore.js"></script>
|
||||
<script type="text/javascript" src="shared/js/feedbackStore.js"></script>
|
||||
<script type="text/javascript" src="shared/js/feedbackViews.js"></script>
|
||||
<script type="text/javascript" src="js/standaloneAppStore.js"></script>
|
||||
<script type="text/javascript" src="js/standaloneClient.js"></script>
|
||||
<script type="text/javascript" src="js/standaloneMozLoop.js"></script>
|
||||
<script type="text/javascript" src="js/fxOSMarketplace.js"></script>
|
||||
<script type="text/javascript" src="js/standaloneRoomViews.js"></script>
|
||||
<script type="text/javascript" src="js/webapp.js"></script>
|
||||
|
||||
|
@ -0,0 +1,37 @@
|
||||
/** @jsx React.DOM */
|
||||
|
||||
var loop = loop || {};
|
||||
loop.fxOSMarketplaceViews = (function() {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* The Firefox Marketplace exposes a web page that contains a postMesssage
|
||||
* based API that wraps a small set of functionality from the WebApps API
|
||||
* that allow us to request the installation of apps given their manifest
|
||||
* URL. We will be embedding the content of this web page within an hidden
|
||||
* iframe in case that we need to request the installation of the FxOS Loop
|
||||
* client.
|
||||
*/
|
||||
var FxOSHiddenMarketplaceView = React.createClass({displayName: 'FxOSHiddenMarketplaceView',
|
||||
render: function() {
|
||||
return React.DOM.iframe({id: "marketplace", src: this.props.marketplaceSrc, hidden: true});
|
||||
},
|
||||
|
||||
componentDidUpdate: function() {
|
||||
// This happens only once when we change the 'src' property of the iframe.
|
||||
if (this.props.onMarketplaceMessage) {
|
||||
// The reason for listening on the global window instead of on the
|
||||
// iframe content window is because the Marketplace is doing a
|
||||
// window.top.postMessage.
|
||||
// XXX Bug 1097703: This should be changed to an action when the old
|
||||
// style URLs go away.
|
||||
window.addEventListener("message", this.props.onMarketplaceMessage);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
FxOSHiddenMarketplaceView: FxOSHiddenMarketplaceView
|
||||
};
|
||||
|
||||
})();
|
@ -0,0 +1,37 @@
|
||||
/** @jsx React.DOM */
|
||||
|
||||
var loop = loop || {};
|
||||
loop.fxOSMarketplaceViews = (function() {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* The Firefox Marketplace exposes a web page that contains a postMesssage
|
||||
* based API that wraps a small set of functionality from the WebApps API
|
||||
* that allow us to request the installation of apps given their manifest
|
||||
* URL. We will be embedding the content of this web page within an hidden
|
||||
* iframe in case that we need to request the installation of the FxOS Loop
|
||||
* client.
|
||||
*/
|
||||
var FxOSHiddenMarketplaceView = React.createClass({
|
||||
render: function() {
|
||||
return <iframe id="marketplace" src={this.props.marketplaceSrc} hidden/>;
|
||||
},
|
||||
|
||||
componentDidUpdate: function() {
|
||||
// This happens only once when we change the 'src' property of the iframe.
|
||||
if (this.props.onMarketplaceMessage) {
|
||||
// The reason for listening on the global window instead of on the
|
||||
// iframe content window is because the Marketplace is doing a
|
||||
// window.top.postMessage.
|
||||
// XXX Bug 1097703: This should be changed to an action when the old
|
||||
// style URLs go away.
|
||||
window.addEventListener("message", this.props.onMarketplaceMessage);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
FxOSHiddenMarketplaceView: FxOSHiddenMarketplaceView
|
||||
};
|
||||
|
||||
})();
|
@ -20,8 +20,10 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
var StandaloneRoomInfoArea = React.createClass({displayName: 'StandaloneRoomInfoArea',
|
||||
propTypes: {
|
||||
helper: React.PropTypes.instanceOf(loop.shared.utils.Helper).isRequired,
|
||||
activeRoomStore:
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore).isRequired,
|
||||
activeRoomStore: React.PropTypes.oneOfType([
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore),
|
||||
React.PropTypes.instanceOf(loop.store.FxOSActiveRoomStore)
|
||||
]).isRequired,
|
||||
feedbackStore:
|
||||
React.PropTypes.instanceOf(loop.store.FeedbackStore).isRequired
|
||||
},
|
||||
@ -189,8 +191,10 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
],
|
||||
|
||||
propTypes: {
|
||||
activeRoomStore:
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore).isRequired,
|
||||
activeRoomStore: React.PropTypes.oneOfType([
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore),
|
||||
React.PropTypes.instanceOf(loop.store.FxOSActiveRoomStore)
|
||||
]).isRequired,
|
||||
feedbackStore:
|
||||
React.PropTypes.instanceOf(loop.store.FeedbackStore).isRequired,
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
@ -379,6 +383,9 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
enableHangup: this._roomIsActive()})
|
||||
)
|
||||
),
|
||||
loop.fxOSMarketplaceViews.FxOSHiddenMarketplaceView({
|
||||
marketplaceSrc: this.state.marketplaceSrc,
|
||||
onMarketplaceMessage: this.state.onMarketplaceMessage}),
|
||||
StandaloneRoomFooter(null)
|
||||
)
|
||||
);
|
||||
|
@ -20,8 +20,10 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
var StandaloneRoomInfoArea = React.createClass({
|
||||
propTypes: {
|
||||
helper: React.PropTypes.instanceOf(loop.shared.utils.Helper).isRequired,
|
||||
activeRoomStore:
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore).isRequired,
|
||||
activeRoomStore: React.PropTypes.oneOfType([
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore),
|
||||
React.PropTypes.instanceOf(loop.store.FxOSActiveRoomStore)
|
||||
]).isRequired,
|
||||
feedbackStore:
|
||||
React.PropTypes.instanceOf(loop.store.FeedbackStore).isRequired
|
||||
},
|
||||
@ -189,8 +191,10 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
],
|
||||
|
||||
propTypes: {
|
||||
activeRoomStore:
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore).isRequired,
|
||||
activeRoomStore: React.PropTypes.oneOfType([
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore),
|
||||
React.PropTypes.instanceOf(loop.store.FxOSActiveRoomStore)
|
||||
]).isRequired,
|
||||
feedbackStore:
|
||||
React.PropTypes.instanceOf(loop.store.FeedbackStore).isRequired,
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
@ -379,6 +383,9 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
enableHangup={this._roomIsActive()} />
|
||||
</div>
|
||||
</div>
|
||||
<loop.fxOSMarketplaceViews.FxOSHiddenMarketplaceView
|
||||
marketplaceSrc={this.state.marketplaceSrc}
|
||||
onMarketplaceMessage={this.state.onMarketplaceMessage} />
|
||||
<StandaloneRoomFooter />
|
||||
</div>
|
||||
);
|
||||
|
@ -127,30 +127,6 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* The Firefox Marketplace exposes a web page that contains a postMesssage
|
||||
* based API that wraps a small set of functionality from the WebApps API
|
||||
* that allow us to request the installation of apps given their manifest
|
||||
* URL. We will be embedding the content of this web page within an hidden
|
||||
* iframe in case that we need to request the installation of the FxOS Loop
|
||||
* client.
|
||||
*/
|
||||
var FxOSHiddenMarketplace = React.createClass({displayName: 'FxOSHiddenMarketplace',
|
||||
render: function() {
|
||||
return React.DOM.iframe({id: "marketplace", src: this.props.marketplaceSrc, hidden: true});
|
||||
},
|
||||
|
||||
componentDidUpdate: function() {
|
||||
// This happens only once when we change the 'src' property of the iframe.
|
||||
if (this.props.onMarketplaceMessage) {
|
||||
// The reason for listening on the global window instead of on the
|
||||
// iframe content window is because the Marketplace is doing a
|
||||
// window.top.postMessage.
|
||||
window.addEventListener("message", this.props.onMarketplaceMessage);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var FxOSConversationModel = Backbone.Model.extend({
|
||||
setupOutgoingCall: function(selectedCallType) {
|
||||
if (selectedCallType) {
|
||||
@ -568,7 +544,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
dangerouslySetInnerHTML: {__html: tosHTML}})
|
||||
),
|
||||
|
||||
FxOSHiddenMarketplace({
|
||||
loop.fxOSMarketplaceViews.FxOSHiddenMarketplaceView({
|
||||
marketplaceSrc: this.state.marketplaceSrc,
|
||||
onMarketplaceMessage: this.state.onMarketplaceMessage}),
|
||||
|
||||
@ -962,8 +938,10 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
// XXX New types for flux style
|
||||
standaloneAppStore: React.PropTypes.instanceOf(
|
||||
loop.store.StandaloneAppStore).isRequired,
|
||||
activeRoomStore: React.PropTypes.instanceOf(
|
||||
loop.store.ActiveRoomStore).isRequired,
|
||||
activeRoomStore: React.PropTypes.oneOfType([
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore),
|
||||
React.PropTypes.instanceOf(loop.store.FxOSActiveRoomStore)
|
||||
]).isRequired,
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
feedbackStore: React.PropTypes.instanceOf(loop.store.FeedbackStore)
|
||||
},
|
||||
@ -1039,14 +1017,6 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
|
||||
// Older non-flux based items.
|
||||
var notifications = new sharedModels.NotificationCollection();
|
||||
var conversation
|
||||
if (helper.isFirefoxOS(navigator.userAgent)) {
|
||||
conversation = new FxOSConversationModel();
|
||||
} else {
|
||||
conversation = new sharedModels.ConversationModel({}, {
|
||||
sdk: OT
|
||||
});
|
||||
}
|
||||
|
||||
var feedbackApiClient = new loop.FeedbackAPIClient(
|
||||
loop.config.feedbackApiUrl, {
|
||||
@ -1064,6 +1034,29 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
dispatcher: dispatcher,
|
||||
sdk: OT
|
||||
});
|
||||
var conversation;
|
||||
var activeRoomStore;
|
||||
if (helper.isFirefoxOS(navigator.userAgent)) {
|
||||
if (loop.config.fxosApp) {
|
||||
conversation = new FxOSConversationModel();
|
||||
if (loop.config.fxosApp.rooms) {
|
||||
activeRoomStore = new loop.store.FxOSActiveRoomStore(dispatcher, {
|
||||
mozLoop: standaloneMozLoop
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
conversation = conversation ||
|
||||
new sharedModels.ConversationModel({}, {
|
||||
sdk: OT
|
||||
});
|
||||
activeRoomStore = activeRoomStore ||
|
||||
new loop.store.ActiveRoomStore(dispatcher, {
|
||||
mozLoop: standaloneMozLoop,
|
||||
sdkDriver: sdkDriver
|
||||
});
|
||||
|
||||
var feedbackClient = new loop.FeedbackAPIClient(
|
||||
loop.config.feedbackApiUrl, {
|
||||
product: loop.config.feedbackProductName,
|
||||
@ -1078,10 +1071,6 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
helper: helper,
|
||||
sdk: OT
|
||||
});
|
||||
var activeRoomStore = new loop.store.ActiveRoomStore(dispatcher, {
|
||||
mozLoop: standaloneMozLoop,
|
||||
sdkDriver: sdkDriver
|
||||
});
|
||||
var feedbackStore = new loop.store.FeedbackStore(dispatcher, {
|
||||
feedbackClient: feedbackClient
|
||||
});
|
||||
|
@ -127,30 +127,6 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* The Firefox Marketplace exposes a web page that contains a postMesssage
|
||||
* based API that wraps a small set of functionality from the WebApps API
|
||||
* that allow us to request the installation of apps given their manifest
|
||||
* URL. We will be embedding the content of this web page within an hidden
|
||||
* iframe in case that we need to request the installation of the FxOS Loop
|
||||
* client.
|
||||
*/
|
||||
var FxOSHiddenMarketplace = React.createClass({
|
||||
render: function() {
|
||||
return <iframe id="marketplace" src={this.props.marketplaceSrc} hidden/>;
|
||||
},
|
||||
|
||||
componentDidUpdate: function() {
|
||||
// This happens only once when we change the 'src' property of the iframe.
|
||||
if (this.props.onMarketplaceMessage) {
|
||||
// The reason for listening on the global window instead of on the
|
||||
// iframe content window is because the Marketplace is doing a
|
||||
// window.top.postMessage.
|
||||
window.addEventListener("message", this.props.onMarketplaceMessage);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var FxOSConversationModel = Backbone.Model.extend({
|
||||
setupOutgoingCall: function(selectedCallType) {
|
||||
if (selectedCallType) {
|
||||
@ -568,7 +544,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
dangerouslySetInnerHTML={{__html: tosHTML}}></p>
|
||||
</div>
|
||||
|
||||
<FxOSHiddenMarketplace
|
||||
<loop.fxOSMarketplaceViews.FxOSHiddenMarketplaceView
|
||||
marketplaceSrc={this.state.marketplaceSrc}
|
||||
onMarketplaceMessage= {this.state.onMarketplaceMessage} />
|
||||
|
||||
@ -962,8 +938,10 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
// XXX New types for flux style
|
||||
standaloneAppStore: React.PropTypes.instanceOf(
|
||||
loop.store.StandaloneAppStore).isRequired,
|
||||
activeRoomStore: React.PropTypes.instanceOf(
|
||||
loop.store.ActiveRoomStore).isRequired,
|
||||
activeRoomStore: React.PropTypes.oneOfType([
|
||||
React.PropTypes.instanceOf(loop.store.ActiveRoomStore),
|
||||
React.PropTypes.instanceOf(loop.store.FxOSActiveRoomStore)
|
||||
]).isRequired,
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
feedbackStore: React.PropTypes.instanceOf(loop.store.FeedbackStore)
|
||||
},
|
||||
@ -1039,14 +1017,6 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
|
||||
// Older non-flux based items.
|
||||
var notifications = new sharedModels.NotificationCollection();
|
||||
var conversation
|
||||
if (helper.isFirefoxOS(navigator.userAgent)) {
|
||||
conversation = new FxOSConversationModel();
|
||||
} else {
|
||||
conversation = new sharedModels.ConversationModel({}, {
|
||||
sdk: OT
|
||||
});
|
||||
}
|
||||
|
||||
var feedbackApiClient = new loop.FeedbackAPIClient(
|
||||
loop.config.feedbackApiUrl, {
|
||||
@ -1064,6 +1034,29 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
dispatcher: dispatcher,
|
||||
sdk: OT
|
||||
});
|
||||
var conversation;
|
||||
var activeRoomStore;
|
||||
if (helper.isFirefoxOS(navigator.userAgent)) {
|
||||
if (loop.config.fxosApp) {
|
||||
conversation = new FxOSConversationModel();
|
||||
if (loop.config.fxosApp.rooms) {
|
||||
activeRoomStore = new loop.store.FxOSActiveRoomStore(dispatcher, {
|
||||
mozLoop: standaloneMozLoop
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
conversation = conversation ||
|
||||
new sharedModels.ConversationModel({}, {
|
||||
sdk: OT
|
||||
});
|
||||
activeRoomStore = activeRoomStore ||
|
||||
new loop.store.ActiveRoomStore(dispatcher, {
|
||||
mozLoop: standaloneMozLoop,
|
||||
sdkDriver: sdkDriver
|
||||
});
|
||||
|
||||
var feedbackClient = new loop.FeedbackAPIClient(
|
||||
loop.config.feedbackApiUrl, {
|
||||
product: loop.config.feedbackProductName,
|
||||
@ -1078,10 +1071,6 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
||||
helper: helper,
|
||||
sdk: OT
|
||||
});
|
||||
var activeRoomStore = new loop.store.ActiveRoomStore(dispatcher, {
|
||||
mozLoop: standaloneMozLoop,
|
||||
sdkDriver: sdkDriver
|
||||
});
|
||||
var feedbackStore = new loop.store.FeedbackStore(dispatcher, {
|
||||
feedbackClient: feedbackClient
|
||||
});
|
||||
|
@ -30,6 +30,7 @@ function getConfigFile(req, res) {
|
||||
"loop.config.legalWebsiteUrl = 'https://www.mozilla.org/about/legal/terms/firefox-hello/';",
|
||||
"loop.config.fxosApp = loop.config.fxosApp || {};",
|
||||
"loop.config.fxosApp.name = 'Loop';",
|
||||
"loop.config.fxosApp.rooms = true;",
|
||||
"loop.config.fxosApp.manifestUrl = 'http://fake-market.herokuapp.com/apps/packagedApp/manifest.webapp';",
|
||||
"loop.config.roomsSupportUrl = 'https://support.mozilla.org/kb/group-conversations-firefox-hello-webrtc';",
|
||||
"loop.config.guestSupportUrl = 'https://support.mozilla.org/kb/respond-firefox-hello-invitation-guest-mode';",
|
||||
|
@ -52,6 +52,8 @@
|
||||
<script src="../../content/shared/js/store.js"></script>
|
||||
<script src="../../content/shared/js/conversationStore.js"></script>
|
||||
<script src="../../content/shared/js/roomStore.js"></script>
|
||||
<script src="../../content/shared/js/roomStates.js"></script>
|
||||
<script src="../../content/shared/js/fxOSActiveRoomStore.js"></script>
|
||||
<script src="../../content/shared/js/activeRoomStore.js"></script>
|
||||
<script src="../../content/shared/js/feedbackStore.js"></script>
|
||||
<script src="../../content/shared/js/feedbackViews.js"></script>
|
||||
|
212
browser/components/loop/test/shared/fxOSActiveRoomStore_test.js
Normal file
212
browser/components/loop/test/shared/fxOSActiveRoomStore_test.js
Normal file
@ -0,0 +1,212 @@
|
||||
/* global chai, loop */
|
||||
|
||||
var expect = chai.expect;
|
||||
var sharedActions = loop.shared.actions;
|
||||
|
||||
describe("loop.store.FxOSActiveRoomStore", function () {
|
||||
"use strict";
|
||||
|
||||
var ROOM_STATES = loop.store.ROOM_STATES;
|
||||
|
||||
var sandbox;
|
||||
var dispatcher;
|
||||
var fakeMozLoop;
|
||||
var store;
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox = sinon.sandbox.create();
|
||||
sandbox.useFakeTimers();
|
||||
|
||||
dispatcher = new loop.Dispatcher();
|
||||
sandbox.stub(dispatcher, "dispatch");
|
||||
|
||||
fakeMozLoop = {
|
||||
setLoopPref: sandbox.stub(),
|
||||
rooms: {
|
||||
join: sinon.stub()
|
||||
}
|
||||
};
|
||||
|
||||
store = new loop.store.FxOSActiveRoomStore(dispatcher, {
|
||||
mozLoop: fakeMozLoop
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe("#FxOSActiveRoomStore - constructor", function() {
|
||||
it("should throw an error if mozLoop is missing", function() {
|
||||
expect(function() {
|
||||
new loop.store.FxOSActiveRoomStore(dispatcher);
|
||||
}).to.Throw(/mozLoop/);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#FxOSActiveRoomStore - fetchServerData", function() {
|
||||
it("should save the token", function() {
|
||||
store.fetchServerData(new sharedActions.FetchServerData({
|
||||
windowType: "room",
|
||||
token: "fakeToken"
|
||||
}));
|
||||
|
||||
expect(store.getStoreState().roomToken).eql("fakeToken");
|
||||
});
|
||||
|
||||
it("should set the state to `READY`", function() {
|
||||
store.fetchServerData(new sharedActions.FetchServerData({
|
||||
windowType: "room",
|
||||
token: "fakeToken"
|
||||
}));
|
||||
|
||||
expect(store.getStoreState().roomState).eql(ROOM_STATES.READY);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#FxOSActiveRoomStore - setupOutgoingRoom", function() {
|
||||
var realMozActivity;
|
||||
var _activityDetail;
|
||||
var _onerror;
|
||||
|
||||
function fireError(errorName) {
|
||||
_onerror({
|
||||
target: {
|
||||
error: {
|
||||
name: errorName
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
before(function() {
|
||||
realMozActivity = window.MozActivity;
|
||||
|
||||
window.MozActivity = function(activityDetail) {
|
||||
_activityDetail = activityDetail;
|
||||
return {
|
||||
set onerror(cbk) {
|
||||
_onerror = cbk;
|
||||
}
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
after(function() {
|
||||
window.MozActivity = realMozActivity;
|
||||
});
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox.stub(console, "error");
|
||||
_activityDetail = undefined;
|
||||
_onerror = undefined;
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it("should reset failureReason", function() {
|
||||
store.setStoreState({failureReason: "Test"});
|
||||
|
||||
store.joinRoom();
|
||||
|
||||
expect(store.getStoreState().failureReason).eql(undefined);
|
||||
});
|
||||
|
||||
it("should create an activity", function() {
|
||||
store.setStoreState({
|
||||
roomToken: "fakeToken",
|
||||
token: "fakeToken"
|
||||
});
|
||||
|
||||
expect(_activityDetail).to.not.exist;
|
||||
store.joinRoom();
|
||||
expect(_activityDetail).to.exist;
|
||||
expect(_activityDetail).eql({
|
||||
name: "room-call",
|
||||
data: {
|
||||
type: "loop/rToken",
|
||||
token: "fakeToken"
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("should change the store state when the activity fail with a " +
|
||||
"NO_PROVIDER error", function() {
|
||||
|
||||
loop.config = {
|
||||
marketplaceUrl: "http://market/"
|
||||
};
|
||||
store._setupOutgoingRoom(true);
|
||||
fireError("NO_PROVIDER");
|
||||
expect(store.getStoreState().marketplaceSrc).eql(
|
||||
loop.config.marketplaceUrl
|
||||
);
|
||||
});
|
||||
|
||||
it("should log an error when the activity fail with a error different " +
|
||||
"from NO_PROVIDER", function() {
|
||||
loop.config = {
|
||||
marketplaceUrl: "http://market/"
|
||||
};
|
||||
store._setupOutgoingRoom(true);
|
||||
fireError("whatever");
|
||||
sinon.assert.calledOnce(console.error);
|
||||
sinon.assert.calledWith(console.error, "Unexpected whatever");
|
||||
});
|
||||
|
||||
it("should log an error and exist if an activity error is received when " +
|
||||
"the parameter is false ", function() {
|
||||
loop.config = {
|
||||
marketplaceUrl: "http://market/"
|
||||
};
|
||||
store._setupOutgoingRoom(false);
|
||||
fireError("whatever");
|
||||
sinon.assert.calledOnce(console.error);
|
||||
sinon.assert.calledWith(console.error,
|
||||
"Unexpected activity launch error after the app has been installed");
|
||||
});
|
||||
});
|
||||
|
||||
describe("#FxOSActiveRoomStore - _onMarketplaceMessage", function() {
|
||||
var setupOutgoingRoom;
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox.stub(console, "error");
|
||||
setupOutgoingRoom = sandbox.stub(store, "_setupOutgoingRoom");
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
setupOutgoingRoom.restore();
|
||||
});
|
||||
|
||||
it("We should call trigger a FxOS outgoing call if we get " +
|
||||
"install-package message without error", function() {
|
||||
|
||||
sinon.assert.notCalled(setupOutgoingRoom);
|
||||
store._onMarketplaceMessage({
|
||||
data: {
|
||||
name: "install-package"
|
||||
}
|
||||
});
|
||||
sinon.assert.calledOnce(setupOutgoingRoom);
|
||||
});
|
||||
|
||||
it("We should log an error if we get install-package message with an " +
|
||||
"error", function() {
|
||||
|
||||
sinon.assert.notCalled(setupOutgoingRoom);
|
||||
store._onMarketplaceMessage({
|
||||
data: {
|
||||
name: "install-package",
|
||||
error: { error: "whatever error" }
|
||||
}
|
||||
});
|
||||
sinon.assert.notCalled(setupOutgoingRoom);
|
||||
sinon.assert.calledOnce(console.error);
|
||||
sinon.assert.calledWith(console.error, "whatever error");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -50,6 +50,8 @@
|
||||
<script src="../../content/shared/js/dispatcher.js"></script>
|
||||
<script src="../../content/shared/js/otSdkDriver.js"></script>
|
||||
<script src="../../content/shared/js/store.js"></script>
|
||||
<script src="../../content/shared/js/roomStates.js"></script>
|
||||
<script src="../../content/shared/js/fxOSActiveRoomStore.js"></script>
|
||||
<script src="../../content/shared/js/activeRoomStore.js"></script>
|
||||
<script src="../../content/shared/js/roomStore.js"></script>
|
||||
<script src="../../content/shared/js/conversationStore.js"></script>
|
||||
@ -67,6 +69,7 @@
|
||||
<script src="validate_test.js"></script>
|
||||
<script src="dispatcher_test.js"></script>
|
||||
<script src="activeRoomStore_test.js"></script>
|
||||
<script src="fxOSActiveRoomStore_test.js"></script>
|
||||
<script src="conversationStore_test.js"></script>
|
||||
<script src="feedbackStore_test.js"></script>
|
||||
<script src="otSdkDriver_test.js"></script>
|
||||
|
@ -48,6 +48,8 @@
|
||||
<script src="../../content/shared/js/validate.js"></script>
|
||||
<script src="../../content/shared/js/dispatcher.js"></script>
|
||||
<script src="../../content/shared/js/store.js"></script>
|
||||
<script src="../../content/shared/js/roomStates.js"></script>
|
||||
<script src="../../content/shared/js/fxOSActiveRoomStore.js"></script>
|
||||
<script src="../../content/shared/js/activeRoomStore.js"></script>
|
||||
<script src="../../content/shared/js/feedbackStore.js"></script>
|
||||
<script src="../../content/shared/js/feedbackViews.js"></script>
|
||||
@ -56,6 +58,7 @@
|
||||
<script src="../../standalone/content/js/standaloneAppStore.js"></script>
|
||||
<script src="../../standalone/content/js/standaloneClient.js"></script>
|
||||
<script src="../../standalone/content/js/standaloneMozLoop.js"></script>
|
||||
<script src="../../standalone/content/js/fxOSMarketplace.js"></script>
|
||||
<script src="../../standalone/content/js/standaloneRoomViews.js"></script>
|
||||
<script src="../../standalone/content/js/webapp.js"></script>
|
||||
<!-- Test scripts -->
|
||||
|
@ -332,6 +332,26 @@ describe("loop.standaloneRoomViews", function() {
|
||||
.not.eql(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Marketplace hidden iframe", function() {
|
||||
|
||||
it("should set src when the store state change",
|
||||
function(done) {
|
||||
|
||||
var marketplace = view.getDOMNode().querySelector("#marketplace");
|
||||
expect(marketplace.src).to.be.equal("");
|
||||
|
||||
activeRoomStore.setStoreState({
|
||||
marketplaceSrc: "http://market/",
|
||||
onMarketplaceMessage: function () {}
|
||||
});
|
||||
|
||||
view.forceUpdate(function() {
|
||||
expect(marketplace.src).to.be.equal("http://market/");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -44,12 +44,15 @@
|
||||
<script src="../content/shared/js/store.js"></script>
|
||||
<script src="../content/shared/js/roomStore.js"></script>
|
||||
<script src="../content/shared/js/conversationStore.js"></script>
|
||||
<script src="../content/shared/js/roomStates.js"></script>
|
||||
<script src="../content/shared/js/fxOSActiveRoomStore.js"></script>
|
||||
<script src="../content/shared/js/activeRoomStore.js"></script>
|
||||
<script src="../content/shared/js/feedbackStore.js"></script>
|
||||
<script src="../content/shared/js/feedbackViews.js"></script>
|
||||
<script src="../content/js/roomViews.js"></script>
|
||||
<script src="../content/js/conversationViews.js"></script>
|
||||
<script src="../content/js/client.js"></script>
|
||||
<script src="../content/js/fxOSMarketplace.js"></script>
|
||||
<script src="../content/js/webapp.js"></script>
|
||||
<script src="../content/js/standaloneRoomViews.js"></script>
|
||||
<script type="text/javascript;version=1.8" src="../content/js/contacts.js"></script>
|
||||
|
Loading…
Reference in New Issue
Block a user