Bug 1184933 - Part 2. Add the settings menu onto the failure view. r=Mardak

This commit is contained in:
Mark Banner 2015-09-10 12:01:16 +01:00
Родитель 9d3c10d581
Коммит 6ac53b4afe
14 изменённых файлов: 129 добавлений и 11 удалений

Просмотреть файл

@ -87,6 +87,7 @@ loop.conversation = (function(mozL10n) {
return (React.createElement(DirectCallFailureView, { return (React.createElement(DirectCallFailureView, {
contact: {}, contact: {},
dispatcher: this.props.dispatcher, dispatcher: this.props.dispatcher,
mozLoop: this.props.mozLoop,
outgoing: false})); outgoing: false}));
} }
default: { default: {

Просмотреть файл

@ -87,6 +87,7 @@ loop.conversation = (function(mozL10n) {
return (<DirectCallFailureView return (<DirectCallFailureView
contact={{}} contact={{}}
dispatcher={this.props.dispatcher} dispatcher={this.props.dispatcher}
mozLoop={this.props.mozLoop}
outgoing={false} />); outgoing={false} />);
} }
default: { default: {

Просмотреть файл

@ -447,6 +447,7 @@ loop.conversationViews = (function(mozL10n) {
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired, dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
// This is used by the UI showcase. // This is used by the UI showcase.
emailLinkError: React.PropTypes.bool, emailLinkError: React.PropTypes.bool,
mozLoop: React.PropTypes.object.isRequired,
outgoing: React.PropTypes.bool.isRequired outgoing: React.PropTypes.bool.isRequired
}, },
@ -518,6 +519,11 @@ loop.conversationViews = (function(mozL10n) {
hide: !this.props.outgoing hide: !this.props.outgoing
}); });
var settingsMenuItems = [
{ id: "feedback" },
{ id: "help" }
];
var extraMessage; var extraMessage;
if (this.props.outgoing) { if (this.props.outgoing) {
@ -552,7 +558,11 @@ loop.conversationViews = (function(mozL10n) {
onClick: this.emailLink}, onClick: this.emailLink},
mozL10n.get("share_button3") mozL10n.get("share_button3")
) )
) ),
React.createElement(loop.shared.views.SettingsControlButton, {
menuBelow: true,
menuItems: settingsMenuItems,
mozLoop: this.props.mozLoop})
) )
); );
} }
@ -802,6 +812,7 @@ loop.conversationViews = (function(mozL10n) {
case CALL_STATES.TERMINATED: { case CALL_STATES.TERMINATED: {
return (React.createElement(DirectCallFailureView, { return (React.createElement(DirectCallFailureView, {
dispatcher: this.props.dispatcher, dispatcher: this.props.dispatcher,
mozLoop: this.props.mozLoop,
outgoing: this.state.outgoing})); outgoing: this.state.outgoing}));
} }
case CALL_STATES.ONGOING: { case CALL_STATES.ONGOING: {

Просмотреть файл

@ -447,6 +447,7 @@ loop.conversationViews = (function(mozL10n) {
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired, dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
// This is used by the UI showcase. // This is used by the UI showcase.
emailLinkError: React.PropTypes.bool, emailLinkError: React.PropTypes.bool,
mozLoop: React.PropTypes.object.isRequired,
outgoing: React.PropTypes.bool.isRequired outgoing: React.PropTypes.bool.isRequired
}, },
@ -518,6 +519,11 @@ loop.conversationViews = (function(mozL10n) {
hide: !this.props.outgoing hide: !this.props.outgoing
}); });
var settingsMenuItems = [
{ id: "feedback" },
{ id: "help" }
];
var extraMessage; var extraMessage;
if (this.props.outgoing) { if (this.props.outgoing) {
@ -553,6 +559,10 @@ loop.conversationViews = (function(mozL10n) {
{mozL10n.get("share_button3")} {mozL10n.get("share_button3")}
</button> </button>
</div> </div>
<loop.shared.views.SettingsControlButton
menuBelow={true}
menuItems={settingsMenuItems}
mozLoop={this.props.mozLoop} />
</div> </div>
); );
} }
@ -802,6 +812,7 @@ loop.conversationViews = (function(mozL10n) {
case CALL_STATES.TERMINATED: { case CALL_STATES.TERMINATED: {
return (<DirectCallFailureView return (<DirectCallFailureView
dispatcher={this.props.dispatcher} dispatcher={this.props.dispatcher}
mozLoop={this.props.mozLoop}
outgoing={this.state.outgoing} />); outgoing={this.state.outgoing} />);
} }
case CALL_STATES.ONGOING: { case CALL_STATES.ONGOING: {

Просмотреть файл

@ -82,7 +82,8 @@ loop.roomViews = (function(mozL10n) {
propTypes: { propTypes: {
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired, dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
failureReason: React.PropTypes.string failureReason: React.PropTypes.string,
mozLoop: React.PropTypes.object.isRequired
}, },
componentDidMount: function() { componentDidMount: function() {
@ -94,6 +95,10 @@ loop.roomViews = (function(mozL10n) {
}, },
render: function() { render: function() {
var settingsMenuItems = [
{ id: "feedback" },
{ id: "help" }
];
return ( return (
React.createElement("div", {className: "room-failure"}, React.createElement("div", {className: "room-failure"},
React.createElement(loop.conversationViews.FailureInfoView, { React.createElement(loop.conversationViews.FailureInfoView, {
@ -103,7 +108,11 @@ loop.roomViews = (function(mozL10n) {
onClick: this.handleRejoinCall}, onClick: this.handleRejoinCall},
mozL10n.get("rejoin_button") mozL10n.get("rejoin_button")
) )
) ),
React.createElement(loop.shared.views.SettingsControlButton, {
menuBelow: true,
menuItems: settingsMenuItems,
mozLoop: this.props.mozLoop})
) )
); );
} }

Просмотреть файл

@ -82,7 +82,8 @@ loop.roomViews = (function(mozL10n) {
propTypes: { propTypes: {
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired, dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
failureReason: React.PropTypes.string failureReason: React.PropTypes.string,
mozLoop: React.PropTypes.object.isRequired
}, },
componentDidMount: function() { componentDidMount: function() {
@ -94,6 +95,10 @@ loop.roomViews = (function(mozL10n) {
}, },
render: function() { render: function() {
var settingsMenuItems = [
{ id: "feedback" },
{ id: "help" }
];
return ( return (
<div className="room-failure"> <div className="room-failure">
<loop.conversationViews.FailureInfoView <loop.conversationViews.FailureInfoView
@ -104,6 +109,10 @@ loop.roomViews = (function(mozL10n) {
{mozL10n.get("rejoin_button")} {mozL10n.get("rejoin_button")}
</button> </button>
</div> </div>
<loop.shared.views.SettingsControlButton
menuBelow={true}
menuItems={settingsMenuItems}
mozLoop={this.props.mozLoop} />
</div> </div>
); );
} }

Просмотреть файл

@ -208,6 +208,7 @@ html[dir="rtl"] .conversation-toolbar-btn-box.btn-edit-entry {
height: 28px; height: 28px;
background-size: 28px; background-size: 28px;
background-image: url("../img/svg/settings.svg"); background-image: url("../img/svg/settings.svg");
background-color: transparent;
} }
.btn-settings:hover, .btn-settings:hover,
@ -271,6 +272,10 @@ html[dir="rtl"] .conversation-toolbar-btn-box.btn-edit-entry {
/* General Call (incoming or outgoing). */ /* General Call (incoming or outgoing). */
/* XXX call-window currently relates to multiple things like the AcceptCallView,
DirectCallFailureView, PendingConversationView. It doesn't relate to the direct
call media views. We should probably make this more explicit at some stage. */
/* /*
* Height matches the height of the docked window * Height matches the height of the docked window
* but the UI breaks when you pop out * but the UI breaks when you pop out
@ -335,6 +340,19 @@ html[dir="rtl"] .conversation-toolbar-btn-box.btn-edit-entry {
flex: auto; flex: auto;
} }
.direct-call-failure > .settings-control,
.room-failure > .settings-control {
position: absolute;
top: 1rem;
right: .5rem;
}
html[dir="rtl"] .direct-call-failure > .settings-control,
html[dir="rtl"] .room-failure > .settings-control {
left: .5rem;
right: auto;
}
.failure-info { .failure-info {
text-align: center; text-align: center;
/* This flex is designed to set the logo in a standard place, but if the /* This flex is designed to set the logo in a standard place, but if the
@ -450,6 +468,11 @@ html[dir="rtl"] .settings-menu.dropdown-menu {
right: auto; right: auto;
} }
.settings-menu.dropdown-menu.menu-below {
top: 11.5rem;
bottom: auto;
}
/* Expired call url page */ /* Expired call url page */
.expired-url-info { .expired-url-info {

Просмотреть файл

@ -185,6 +185,8 @@ loop.shared.views = (function(_, mozL10n) {
*/ */
var SettingsControlButton = React.createClass({displayName: "SettingsControlButton", var SettingsControlButton = React.createClass({displayName: "SettingsControlButton",
propTypes: { propTypes: {
// Set to true if the menu should be below the button rather than above.
menuBelow: React.PropTypes.bool,
menuItems: React.PropTypes.array, menuItems: React.PropTypes.array,
mozLoop: React.PropTypes.object mozLoop: React.PropTypes.object
}, },
@ -194,6 +196,12 @@ loop.shared.views = (function(_, mozL10n) {
React.addons.PureRenderMixin React.addons.PureRenderMixin
], ],
getDefaultProps: function() {
return {
menuBelow: false
};
},
/** /**
* Show or hide the settings menu * Show or hide the settings menu
*/ */
@ -304,13 +312,14 @@ loop.shared.views = (function(_, mozL10n) {
var settingsDropdownMenuClasses = cx({ var settingsDropdownMenuClasses = cx({
"settings-menu": true, "settings-menu": true,
"dropdown-menu": true, "dropdown-menu": true,
"menu-below": this.props.menuBelow,
"hide": !this.state.showMenu "hide": !this.state.showMenu
}); });
return ( return (
React.createElement("div", null, React.createElement("div", {className: "settings-control"},
React.createElement("button", {className: "btn btn-settings transparent-button", React.createElement("button", {className: "btn btn-settings transparent-button",
onClick: this.toggleDropdownMenu, onClick: this.toggleDropdownMenu,
ref: "menu-button", ref: "anchor",
title: mozL10n.get("settings_menu_button_tooltip")}), title: mozL10n.get("settings_menu_button_tooltip")}),
React.createElement("ul", {className: settingsDropdownMenuClasses, ref: "menu"}, React.createElement("ul", {className: settingsDropdownMenuClasses, ref: "menu"},
menuItemRows menuItemRows

Просмотреть файл

@ -185,6 +185,8 @@ loop.shared.views = (function(_, mozL10n) {
*/ */
var SettingsControlButton = React.createClass({ var SettingsControlButton = React.createClass({
propTypes: { propTypes: {
// Set to true if the menu should be below the button rather than above.
menuBelow: React.PropTypes.bool,
menuItems: React.PropTypes.array, menuItems: React.PropTypes.array,
mozLoop: React.PropTypes.object mozLoop: React.PropTypes.object
}, },
@ -194,6 +196,12 @@ loop.shared.views = (function(_, mozL10n) {
React.addons.PureRenderMixin React.addons.PureRenderMixin
], ],
getDefaultProps: function() {
return {
menuBelow: false
};
},
/** /**
* Show or hide the settings menu * Show or hide the settings menu
*/ */
@ -304,13 +312,14 @@ loop.shared.views = (function(_, mozL10n) {
var settingsDropdownMenuClasses = cx({ var settingsDropdownMenuClasses = cx({
"settings-menu": true, "settings-menu": true,
"dropdown-menu": true, "dropdown-menu": true,
"menu-below": this.props.menuBelow,
"hide": !this.state.showMenu "hide": !this.state.showMenu
}); });
return ( return (
<div> <div className="settings-control">
<button className="btn btn-settings transparent-button" <button className="btn btn-settings transparent-button"
onClick={this.toggleDropdownMenu} onClick={this.toggleDropdownMenu}
ref="menu-button" ref="anchor"
title={mozL10n.get("settings_menu_button_tooltip")} /> title={mozL10n.get("settings_menu_button_tooltip")} />
<ul className={settingsDropdownMenuClasses} ref="menu"> <ul className={settingsDropdownMenuClasses} ref="menu">
{menuItemRows} {menuItemRows}

Просмотреть файл

@ -351,6 +351,7 @@ describe("loop.conversationViews", function () {
function mountTestComponent(options) { function mountTestComponent(options) {
var props = _.extend({ var props = _.extend({
dispatcher: dispatcher, dispatcher: dispatcher,
mozLoop: fakeMozLoop,
outgoing: true outgoing: true
}, options); }, options);
return TestUtils.renderIntoDocument( return TestUtils.renderIntoDocument(

Просмотреть файл

@ -139,7 +139,8 @@ describe("loop.roomViews", function () {
function mountTestComponent(props) { function mountTestComponent(props) {
props = _.extend({ props = _.extend({
dispatcher: dispatcher, dispatcher: dispatcher,
failureReason: FAILURE_DETAILS.UNKNOWN failureReason: FAILURE_DETAILS.UNKNOWN,
mozLoop: fakeMozLoop
}); });
return TestUtils.renderIntoDocument( return TestUtils.renderIntoDocument(
React.createElement(loop.roomViews.RoomFailureView, props)); React.createElement(loop.roomViews.RoomFailureView, props));

Просмотреть файл

@ -325,6 +325,31 @@ describe("loop.shared.views", function() {
expect(comp.state.showMenu).eql(true); expect(comp.state.showMenu).eql(true);
}); });
it("should have a `menu-below` class on the dropdown when the prop is set.", function() {
var settingsMenuItems = [
{ id: "help" }
];
var comp = mountTestComponent({
menuBelow: true,
menuItems: settingsMenuItems
});
var menuItems = comp.getDOMNode().querySelector(".settings-menu");
expect(menuItems.classList.contains("menu-below")).eql(true);
});
it("should not have a `menu-below` class on the dropdown when the prop is not set.", function() {
var settingsMenuItems = [
{ id: "help" }
];
var comp = mountTestComponent({
menuItems: settingsMenuItems
});
var menuItems = comp.getDOMNode().querySelector(".settings-menu");
expect(menuItems.classList.contains("menu-below")).eql(false);
});
it("should show edit Context on menu when the option is enabled", function() { it("should show edit Context on menu when the option is enabled", function() {
var settingsMenuItems = [ var settingsMenuItems = [
{ {

Просмотреть файл

@ -1170,6 +1170,7 @@
React.createElement(DirectCallFailureView, { React.createElement(DirectCallFailureView, {
conversationStore: conversationStores[0], conversationStore: conversationStores[0],
dispatcher: dispatcher, dispatcher: dispatcher,
mozLoop: navigator.mozLoop,
outgoing: false}) outgoing: false})
) )
), ),
@ -1182,6 +1183,7 @@
React.createElement(DirectCallFailureView, { React.createElement(DirectCallFailureView, {
conversationStore: conversationStores[1], conversationStore: conversationStores[1],
dispatcher: dispatcher, dispatcher: dispatcher,
mozLoop: navigator.mozLoop,
outgoing: true}) outgoing: true})
) )
), ),
@ -1195,6 +1197,7 @@
conversationStore: conversationStores[0], conversationStore: conversationStores[0],
dispatcher: dispatcher, dispatcher: dispatcher,
emailLinkError: true, emailLinkError: true,
mozLoop: navigator.mozLoop,
outgoing: true}) outgoing: true})
) )
) )
@ -1360,7 +1363,8 @@
React.createElement("div", {className: "fx-embedded"}, React.createElement("div", {className: "fx-embedded"},
React.createElement(RoomFailureView, { React.createElement(RoomFailureView, {
dispatcher: dispatcher, dispatcher: dispatcher,
failureReason: FAILURE_DETAILS.UNKNOWN}) failureReason: FAILURE_DETAILS.UNKNOWN,
mozLoop: navigator.mozLoop})
) )
) )
), ),

Просмотреть файл

@ -1170,6 +1170,7 @@
<DirectCallFailureView <DirectCallFailureView
conversationStore={conversationStores[0]} conversationStore={conversationStores[0]}
dispatcher={dispatcher} dispatcher={dispatcher}
mozLoop={navigator.mozLoop}
outgoing={false} /> outgoing={false} />
</div> </div>
</FramedExample> </FramedExample>
@ -1182,6 +1183,7 @@
<DirectCallFailureView <DirectCallFailureView
conversationStore={conversationStores[1]} conversationStore={conversationStores[1]}
dispatcher={dispatcher} dispatcher={dispatcher}
mozLoop={navigator.mozLoop}
outgoing={true} /> outgoing={true} />
</div> </div>
</FramedExample> </FramedExample>
@ -1195,6 +1197,7 @@
conversationStore={conversationStores[0]} conversationStore={conversationStores[0]}
dispatcher={dispatcher} dispatcher={dispatcher}
emailLinkError={true} emailLinkError={true}
mozLoop={navigator.mozLoop}
outgoing={true} /> outgoing={true} />
</div> </div>
</FramedExample> </FramedExample>
@ -1360,7 +1363,8 @@
<div className="fx-embedded"> <div className="fx-embedded">
<RoomFailureView <RoomFailureView
dispatcher={dispatcher} dispatcher={dispatcher}
failureReason={FAILURE_DETAILS.UNKNOWN} /> failureReason={FAILURE_DETAILS.UNKNOWN}
mozLoop={navigator.mozLoop} />
</div> </div>
</FramedExample> </FramedExample>
</Section> </Section>