forked from mirrors/gecko-dev
299 lines
8.2 KiB
JavaScript
299 lines
8.2 KiB
JavaScript
/** @jsx React.DOM */
|
|
|
|
/* 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/. */
|
|
|
|
/*jshint newcap:false*/
|
|
/*global loop:true, React */
|
|
|
|
var loop = loop || {};
|
|
loop.panel = (function(_, mozL10n) {
|
|
"use strict";
|
|
|
|
var sharedViews = loop.shared.views,
|
|
// aliasing translation function as __ for concision
|
|
__ = mozL10n.get;
|
|
|
|
/**
|
|
* Panel router.
|
|
* @type {loop.desktopRouter.DesktopRouter}
|
|
*/
|
|
var router;
|
|
|
|
/**
|
|
* Do not disturb panel subview.
|
|
*/
|
|
var DoNotDisturb = React.createClass({displayName: 'DoNotDisturb',
|
|
getInitialState: function() {
|
|
return {doNotDisturb: navigator.mozLoop.doNotDisturb};
|
|
},
|
|
|
|
handleCheckboxChange: function() {
|
|
// Note: side effect!
|
|
navigator.mozLoop.doNotDisturb = !navigator.mozLoop.doNotDisturb;
|
|
this.setState({doNotDisturb: navigator.mozLoop.doNotDisturb});
|
|
},
|
|
|
|
render: function() {
|
|
// XXX https://github.com/facebook/react/issues/310 for === htmlFor
|
|
return (
|
|
React.DOM.p( {className:"dnd"},
|
|
React.DOM.input( {type:"checkbox", checked:this.state.doNotDisturb,
|
|
id:"dnd-component", onChange:this.handleCheckboxChange} ),
|
|
React.DOM.label( {htmlFor:"dnd-component"}, __("do_not_disturb"))
|
|
)
|
|
);
|
|
}
|
|
});
|
|
|
|
var ToSView = React.createClass({displayName: 'ToSView',
|
|
getInitialState: function() {
|
|
return {seenToS: navigator.mozLoop.getLoopCharPref('seenToS')};
|
|
},
|
|
|
|
render: function() {
|
|
var tosHTML = __("legal_text_and_links", {
|
|
"terms_of_use_url": "https://accounts.firefox.com/legal/terms",
|
|
"privacy_notice_url": "www.mozilla.org/privacy/"
|
|
});
|
|
|
|
if (!this.state.seenToS) {
|
|
navigator.mozLoop.setLoopCharPref('seenToS', 'seen');
|
|
return React.DOM.p( {className:"tos",
|
|
dangerouslySetInnerHTML:{__html: tosHTML}});
|
|
} else {
|
|
return React.DOM.div(null );
|
|
}
|
|
}
|
|
});
|
|
|
|
var PanelLayout = React.createClass({displayName: 'PanelLayout',
|
|
propTypes: {
|
|
summary: React.PropTypes.string.isRequired
|
|
},
|
|
|
|
render: function() {
|
|
return (
|
|
React.DOM.div( {className:"share generate-url"},
|
|
React.DOM.div( {className:"description"},
|
|
React.DOM.p(null, this.props.summary)
|
|
),
|
|
React.DOM.div( {className:"action"},
|
|
this.props.children
|
|
)
|
|
)
|
|
);
|
|
}
|
|
});
|
|
|
|
var CallUrlResult = React.createClass({displayName: 'CallUrlResult',
|
|
propTypes: {
|
|
callUrl: React.PropTypes.string.isRequired,
|
|
retry: React.PropTypes.func.isRequired
|
|
},
|
|
|
|
handleButtonClick: function() {
|
|
this.props.retry();
|
|
},
|
|
|
|
render: function() {
|
|
// XXX setting elem value from a state (in the callUrl input)
|
|
// makes it immutable ie read only but that is fine in our case.
|
|
// readOnly attr will suppress a warning regarding this issue
|
|
// from the react lib.
|
|
return (
|
|
PanelLayout( {summary:__("share_link_url")},
|
|
React.DOM.div( {className:"invite"},
|
|
React.DOM.input( {type:"url", value:this.props.callUrl, readOnly:"true"} ),
|
|
React.DOM.button( {onClick:this.handleButtonClick,
|
|
className:"btn btn-success"}, __("new_url"))
|
|
)
|
|
)
|
|
);
|
|
}
|
|
});
|
|
|
|
var CallUrlForm = React.createClass({displayName: 'CallUrlForm',
|
|
propTypes: {
|
|
client: React.PropTypes.object.isRequired,
|
|
notifier: React.PropTypes.object.isRequired
|
|
},
|
|
|
|
getInitialState: function() {
|
|
return {
|
|
pending: false,
|
|
disabled: true,
|
|
callUrl: false
|
|
};
|
|
},
|
|
|
|
retry: function() {
|
|
this.setState(this.getInitialState());
|
|
},
|
|
|
|
handleTextChange: function(event) {
|
|
this.setState({disabled: !event.currentTarget.value});
|
|
},
|
|
|
|
handleFormSubmit: function(event) {
|
|
event.preventDefault();
|
|
|
|
this.setState({pending: true});
|
|
|
|
this.props.client.requestCallUrl(
|
|
this.refs.caller.getDOMNode().value, this._onCallUrlReceived);
|
|
},
|
|
|
|
_onCallUrlReceived: function(err, callUrlData) {
|
|
var callUrl = false;
|
|
|
|
this.props.notifier.clear();
|
|
|
|
if (err) {
|
|
this.props.notifier.errorL10n("unable_retrieve_url");
|
|
} else {
|
|
callUrl = callUrlData.callUrl || callUrlData.call_url;
|
|
}
|
|
|
|
this.setState({pending: false, callUrl: callUrl});
|
|
},
|
|
|
|
render: function() {
|
|
// If we have a call url, render result
|
|
if (this.state.callUrl) {
|
|
return (
|
|
CallUrlResult( {callUrl:this.state.callUrl, retry:this.retry})
|
|
);
|
|
}
|
|
|
|
// If we don't display the form
|
|
var cx = React.addons.classSet;
|
|
return (
|
|
PanelLayout( {summary:__("get_link_to_share")},
|
|
React.DOM.form( {className:"invite", onSubmit:this.handleFormSubmit},
|
|
|
|
React.DOM.input( {type:"text", name:"caller", ref:"caller", required:"required",
|
|
className:cx({'pending': this.state.pending}),
|
|
onChange:this.handleTextChange,
|
|
placeholder:__("call_identifier_textinput_placeholder")} ),
|
|
|
|
React.DOM.button( {type:"submit", className:"get-url btn btn-success",
|
|
disabled:this.state.disabled},
|
|
__("get_a_call_url")
|
|
)
|
|
),
|
|
ToSView(null )
|
|
)
|
|
);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Panel view.
|
|
*/
|
|
var PanelView = React.createClass({displayName: 'PanelView',
|
|
propTypes: {
|
|
notifier: React.PropTypes.object.isRequired,
|
|
client: React.PropTypes.object.isRequired
|
|
},
|
|
|
|
render: function() {
|
|
return (
|
|
React.DOM.div(null,
|
|
CallUrlForm( {client:this.props.client,
|
|
notifier:this.props.notifier} ),
|
|
DoNotDisturb(null )
|
|
)
|
|
);
|
|
}
|
|
});
|
|
|
|
var PanelRouter = loop.desktopRouter.DesktopRouter.extend({
|
|
/**
|
|
* DOM document object.
|
|
* @type {HTMLDocument}
|
|
*/
|
|
document: undefined,
|
|
|
|
routes: {
|
|
"": "home"
|
|
},
|
|
|
|
initialize: function(options) {
|
|
options = options || {};
|
|
if (!options.document) {
|
|
throw new Error("missing required document");
|
|
}
|
|
this.document = options.document;
|
|
|
|
this._registerVisibilityChangeEvent();
|
|
|
|
this.on("panel:open panel:closed", this.reset, this);
|
|
},
|
|
|
|
/**
|
|
* Register the DOM visibility API event for the whole document, and trigger
|
|
* appropriate events accordingly:
|
|
*
|
|
* - `panel:opened` when the panel is open
|
|
* - `panel:closed` when the panel is closed
|
|
*
|
|
* @link http://www.w3.org/TR/page-visibility/
|
|
*/
|
|
_registerVisibilityChangeEvent: function() {
|
|
this.document.addEventListener("visibilitychange", function(event) {
|
|
this.trigger(event.currentTarget.hidden ? "panel:closed"
|
|
: "panel:open");
|
|
}.bind(this));
|
|
},
|
|
|
|
/**
|
|
* Default entry point.
|
|
*/
|
|
home: function() {
|
|
this.reset();
|
|
},
|
|
|
|
/**
|
|
* Resets this router to its initial state.
|
|
*/
|
|
reset: function() {
|
|
this._notifier.clear();
|
|
var client = new loop.Client({
|
|
baseServerUrl: navigator.mozLoop.serverUrl
|
|
});
|
|
this.loadReactComponent(PanelView( {client:client,
|
|
notifier:this._notifier} ));
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Panel initialisation.
|
|
*/
|
|
function init() {
|
|
// Do the initial L10n setup, we do this before anything
|
|
// else to ensure the L10n environment is setup correctly.
|
|
mozL10n.initialize(navigator.mozLoop);
|
|
|
|
router = new PanelRouter({
|
|
document: document,
|
|
notifier: new sharedViews.NotificationListView({el: "#messages"})
|
|
});
|
|
Backbone.history.start();
|
|
|
|
// Notify the window that we've finished initalization and initial layout
|
|
var evtObject = document.createEvent('Event');
|
|
evtObject.initEvent('loopPanelInitialized', true, false);
|
|
window.dispatchEvent(evtObject);
|
|
}
|
|
|
|
return {
|
|
init: init,
|
|
DoNotDisturb: DoNotDisturb,
|
|
CallUrlForm: CallUrlForm,
|
|
PanelView: PanelView,
|
|
PanelRouter: PanelRouter,
|
|
ToSView: ToSView
|
|
};
|
|
})(_, document.mozL10n);
|