зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1131581: move screensharing options into a dropdown anchored to the screenshare toolbar button. r=Standard8
This commit is contained in:
Родитель
4bb94f35b0
Коммит
ad14612ec0
|
@ -17,6 +17,8 @@
|
|||
|
||||
/* desktop version */
|
||||
.fx-embedded .conversation-toolbar {
|
||||
/* required to have dropdowns float atop the .room-invitation-overlay: */
|
||||
z-index: 1020;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
@ -40,13 +42,13 @@
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
.conversation-toolbar li {
|
||||
.conversation-toolbar > li {
|
||||
float: left;
|
||||
font-size: 0; /* prevents vertical bottom padding added to buttons in google
|
||||
chrome */
|
||||
}
|
||||
|
||||
.standalone .conversation-toolbar li {
|
||||
.standalone .conversation-toolbar > li {
|
||||
/* XXX Might make sense to use relative units here.
|
||||
*/
|
||||
margin-right: 16px;
|
||||
|
@ -165,7 +167,8 @@
|
|||
background-color: transparent;
|
||||
opacity: 1;
|
||||
}
|
||||
.conversation-toolbar .transparent-button:hover {
|
||||
.conversation-toolbar .transparent-button:hover,
|
||||
.conversation-toolbar .transparent-button.menu-showing {
|
||||
background-color: rgba(255,255,255,.35);
|
||||
opacity: 1;
|
||||
}
|
||||
|
@ -208,9 +211,15 @@
|
|||
|
||||
/* Screen share button */
|
||||
.btn-screen-share {
|
||||
/* XXX Replace this with the real button: bug 1126286 */
|
||||
position: relative;
|
||||
background-image: url(../img/icons-16x16.svg#screen-white);
|
||||
background-size: 16px 16px;
|
||||
width: 42px;
|
||||
}
|
||||
|
||||
/* Make room for the chevron. */
|
||||
.conversation-toolbar .btn-screen-share:not(.active) {
|
||||
background-position: 5px center;
|
||||
}
|
||||
|
||||
.btn-screen-share.active {
|
||||
|
@ -220,7 +229,21 @@
|
|||
}
|
||||
|
||||
.btn-screen-share.disabled {
|
||||
/* XXX Add css here for disabled state: bug 1126286 */
|
||||
background-image: url(../img/icons-16x16.svg#screen-disabled);
|
||||
}
|
||||
|
||||
.btn-screen-share .chevron {
|
||||
background-image: url(../img/icons-10x10.svg#dropdown-white);
|
||||
background-size: 10px 10px;
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
top: 8px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
.btn-screen-share.disabled .chevron {
|
||||
background-image: url(../img/icons-10x10.svg#dropdown-disabled);
|
||||
}
|
||||
|
||||
.fx-embedded .remote_wrapper {
|
||||
|
@ -364,9 +387,10 @@
|
|||
background-color: #111;
|
||||
}
|
||||
|
||||
.conversation-window-dropdown li {
|
||||
.conversation-window-dropdown > li {
|
||||
padding: 2px;
|
||||
font-size: .9em;
|
||||
font-size: .7rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Expired call url page */
|
||||
|
|
|
@ -26,7 +26,11 @@ use[id$="-active"] {
|
|||
}
|
||||
|
||||
use[id$="-white"] {
|
||||
fill: rgba(255, 255, 255, 0.8);
|
||||
fill: rgba(255,255,255,0.8);
|
||||
}
|
||||
|
||||
use[id$="-disabled"] {
|
||||
fill: rgba(255,255,255,0.4);
|
||||
}
|
||||
</style>
|
||||
<defs style="display:none">
|
||||
|
|
До Ширина: | Высота: | Размер: 2.0 KiB После Ширина: | Высота: | Размер: 2.0 KiB |
|
@ -32,6 +32,10 @@ use[id$="-red"] {
|
|||
use[id$="-white"] {
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
use[id$="-disabled"] {
|
||||
fill: rgba(255,255,255,.6);
|
||||
}
|
||||
</style>
|
||||
<defs style="display:none">
|
||||
<path id="audio-shape" fill-rule="evenodd" clip-rule="evenodd" d="M11.429,6.857v2.286c0,1.894-1.535,3.429-3.429,3.429
|
||||
|
@ -181,5 +185,6 @@ use[id$="-white"] {
|
|||
<use id="video-active" xlink:href="#video-shape"/>
|
||||
<use id="tour" xlink:href="#tour-shape"/>
|
||||
<use id="screen-white" xlink:href="#screen-shape"/>
|
||||
<use id="screen-disabled" xlink:href="#screen-shape"/>
|
||||
<use id="screenmute-white" xlink:href="#screenmute-shape"/>
|
||||
</svg>
|
||||
|
|
До Ширина: | Высота: | Размер: 12 KiB После Ширина: | Высота: | Размер: 12 KiB |
|
@ -101,6 +101,31 @@ loop.shared.mixins = (function() {
|
|||
componentDidMount: function() {
|
||||
this.documentBody.addEventListener("click", this._onBodyClick);
|
||||
this.documentBody.addEventListener("blur", this.hideDropdownMenu);
|
||||
|
||||
var menu = this.refs.menu;
|
||||
if (!menu) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Correct the position of the menu if necessary.
|
||||
var menuNode = menu.getDOMNode();
|
||||
var menuNodeRect = menuNode.getBoundingClientRect();
|
||||
var bodyRect = {
|
||||
height: this.documentBody.offsetHeight,
|
||||
width: this.documentBody.offsetWidth
|
||||
};
|
||||
|
||||
// First we check the vertical overflow.
|
||||
var y = menuNodeRect.top + menuNodeRect.height;
|
||||
if (y >= bodyRect.height) {
|
||||
menuNode.style.marginTop = bodyRect.height - y + "px";
|
||||
}
|
||||
|
||||
// Then we check the horizontal overflow.
|
||||
var x = menuNodeRect.left + menuNodeRect.width;
|
||||
if (x >= bodyRect.width) {
|
||||
menuNode.style.marginLeft = bodyRect.width - x + "px";
|
||||
}
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
|
|
|
@ -85,6 +85,8 @@ loop.shared.views = (function(_, l10n) {
|
|||
* loop.shared.utils.SCREEN_SHARE_STATES
|
||||
*/
|
||||
var ScreenShareControlButton = React.createClass({displayName: "ScreenShareControlButton",
|
||||
mixins: [sharedMixins.DropdownMenuMixin],
|
||||
|
||||
propTypes: {
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
visible: React.PropTypes.bool.isRequired,
|
||||
|
@ -96,11 +98,14 @@ loop.shared.views = (function(_, l10n) {
|
|||
this.props.dispatcher.dispatch(
|
||||
new sharedActions.EndScreenShare({}));
|
||||
} else {
|
||||
this.props.dispatcher.dispatch(
|
||||
new sharedActions.StartScreenShare({}));
|
||||
this.toggleDropdownMenu();
|
||||
}
|
||||
},
|
||||
|
||||
_handleShareWindows: function() {
|
||||
this.props.dispatcher.dispatch(new sharedActions.StartScreenShare({}));
|
||||
},
|
||||
|
||||
_getTitle: function() {
|
||||
var prefix = this.props.state === SCREEN_SHARE_STATES.ACTIVE ?
|
||||
"active" : "inactive";
|
||||
|
@ -113,18 +118,36 @@ loop.shared.views = (function(_, l10n) {
|
|||
return null;
|
||||
}
|
||||
|
||||
var screenShareClasses = React.addons.classSet({
|
||||
var cx = React.addons.classSet;
|
||||
|
||||
var isActive = this.props.state === SCREEN_SHARE_STATES.ACTIVE;
|
||||
var screenShareClasses = cx({
|
||||
"btn": true,
|
||||
"btn-screen-share": true,
|
||||
"transparent-button": true,
|
||||
"active": this.props.state === SCREEN_SHARE_STATES.ACTIVE,
|
||||
"menu-showing": this.state.showMenu,
|
||||
"active": isActive,
|
||||
"disabled": this.props.state === SCREEN_SHARE_STATES.PENDING
|
||||
});
|
||||
var dropdownMenuClasses = cx({
|
||||
"native-dropdown-menu": true,
|
||||
"conversation-window-dropdown": true,
|
||||
"visually-hidden": !this.state.showMenu
|
||||
});
|
||||
|
||||
return (
|
||||
React.createElement("button", {className: screenShareClasses,
|
||||
onClick: this.handleClick,
|
||||
title: this._getTitle()})
|
||||
React.createElement("div", null,
|
||||
React.createElement("button", {className: screenShareClasses,
|
||||
onClick: this.handleClick,
|
||||
title: this._getTitle()},
|
||||
isActive ? null : React.createElement("span", {className: "chevron"})
|
||||
),
|
||||
React.createElement("ul", {ref: "menu", className: dropdownMenuClasses},
|
||||
React.createElement("li", {onClick: this._handleShareWindows},
|
||||
l10n.get("share_windows_button_title")
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -85,6 +85,8 @@ loop.shared.views = (function(_, l10n) {
|
|||
* loop.shared.utils.SCREEN_SHARE_STATES
|
||||
*/
|
||||
var ScreenShareControlButton = React.createClass({
|
||||
mixins: [sharedMixins.DropdownMenuMixin],
|
||||
|
||||
propTypes: {
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
visible: React.PropTypes.bool.isRequired,
|
||||
|
@ -96,11 +98,14 @@ loop.shared.views = (function(_, l10n) {
|
|||
this.props.dispatcher.dispatch(
|
||||
new sharedActions.EndScreenShare({}));
|
||||
} else {
|
||||
this.props.dispatcher.dispatch(
|
||||
new sharedActions.StartScreenShare({}));
|
||||
this.toggleDropdownMenu();
|
||||
}
|
||||
},
|
||||
|
||||
_handleShareWindows: function() {
|
||||
this.props.dispatcher.dispatch(new sharedActions.StartScreenShare({}));
|
||||
},
|
||||
|
||||
_getTitle: function() {
|
||||
var prefix = this.props.state === SCREEN_SHARE_STATES.ACTIVE ?
|
||||
"active" : "inactive";
|
||||
|
@ -113,18 +118,36 @@ loop.shared.views = (function(_, l10n) {
|
|||
return null;
|
||||
}
|
||||
|
||||
var screenShareClasses = React.addons.classSet({
|
||||
var cx = React.addons.classSet;
|
||||
|
||||
var isActive = this.props.state === SCREEN_SHARE_STATES.ACTIVE;
|
||||
var screenShareClasses = cx({
|
||||
"btn": true,
|
||||
"btn-screen-share": true,
|
||||
"transparent-button": true,
|
||||
"active": this.props.state === SCREEN_SHARE_STATES.ACTIVE,
|
||||
"menu-showing": this.state.showMenu,
|
||||
"active": isActive,
|
||||
"disabled": this.props.state === SCREEN_SHARE_STATES.PENDING
|
||||
});
|
||||
var dropdownMenuClasses = cx({
|
||||
"native-dropdown-menu": true,
|
||||
"conversation-window-dropdown": true,
|
||||
"visually-hidden": !this.state.showMenu
|
||||
});
|
||||
|
||||
return (
|
||||
<button className={screenShareClasses}
|
||||
onClick={this.handleClick}
|
||||
title={this._getTitle()}></button>
|
||||
<div>
|
||||
<button className={screenShareClasses}
|
||||
onClick={this.handleClick}
|
||||
title={this._getTitle()}>
|
||||
{isActive ? null : <span className="chevron"/>}
|
||||
</button>
|
||||
<ul ref="menu" className={dropdownMenuClasses}>
|
||||
<li onClick={this._handleShareWindows}>
|
||||
{l10n.get("share_windows_button_title")}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -118,8 +118,9 @@ describe("loop.shared.views", function() {
|
|||
state: SCREEN_SHARE_STATES.PENDING
|
||||
}));
|
||||
|
||||
expect(comp.getDOMNode().classList.contains("active")).eql(false);
|
||||
expect(comp.getDOMNode().classList.contains("disabled")).eql(true);
|
||||
var node = comp.getDOMNode().querySelector(".btn-screen-share");
|
||||
expect(node.classList.contains("active")).eql(false);
|
||||
expect(node.classList.contains("disabled")).eql(true);
|
||||
});
|
||||
|
||||
it("should render an active share button", function() {
|
||||
|
@ -130,11 +131,12 @@ describe("loop.shared.views", function() {
|
|||
state: SCREEN_SHARE_STATES.ACTIVE
|
||||
}));
|
||||
|
||||
expect(comp.getDOMNode().classList.contains("active")).eql(true);
|
||||
expect(comp.getDOMNode().classList.contains("disabled")).eql(false);
|
||||
var node = comp.getDOMNode().querySelector(".btn-screen-share");
|
||||
expect(node.classList.contains("active")).eql(true);
|
||||
expect(node.classList.contains("disabled")).eql(false);
|
||||
});
|
||||
|
||||
it("should dispatch a StartScreenShare action on click when the state is not active",
|
||||
it("should show the screenshare dropdown on click when the state is not active",
|
||||
function() {
|
||||
var comp = TestUtils.renderIntoDocument(
|
||||
React.createElement(sharedViews.ScreenShareControlButton, {
|
||||
|
@ -143,7 +145,24 @@ describe("loop.shared.views", function() {
|
|||
state: SCREEN_SHARE_STATES.INACTIVE
|
||||
}));
|
||||
|
||||
TestUtils.Simulate.click(comp.getDOMNode());
|
||||
expect(comp.state.showMenu).eql(false);
|
||||
|
||||
TestUtils.Simulate.click(comp.getDOMNode().querySelector(".btn-screen-share"));
|
||||
|
||||
expect(comp.state.showMenu).eql(true);
|
||||
});
|
||||
|
||||
it("should dispatch a StartScreenShare action on option click in screenshare dropdown",
|
||||
function() {
|
||||
var comp = TestUtils.renderIntoDocument(
|
||||
React.createElement(sharedViews.ScreenShareControlButton, {
|
||||
dispatcher: dispatcher,
|
||||
visible: true,
|
||||
state: SCREEN_SHARE_STATES.INACTIVE
|
||||
}));
|
||||
|
||||
TestUtils.Simulate.click(comp.getDOMNode().querySelector(
|
||||
".conversation-window-dropdown > li"));
|
||||
|
||||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
|
@ -159,7 +178,7 @@ describe("loop.shared.views", function() {
|
|||
state: SCREEN_SHARE_STATES.ACTIVE
|
||||
}));
|
||||
|
||||
TestUtils.Simulate.click(comp.getDOMNode());
|
||||
TestUtils.Simulate.click(comp.getDOMNode().querySelector(".btn-screen-share"));
|
||||
|
||||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
sinon.assert.calledWithExactly(dispatcher.dispatch,
|
||||
|
|
|
@ -185,6 +185,7 @@ mute_local_video_button_title=Mute your video
|
|||
unmute_local_video_button_title=Unmute your video
|
||||
active_screenshare_button_title=Stop sharing
|
||||
inactive_screenshare_button_title=Share your screen
|
||||
share_windows_button_title=Share other Windows
|
||||
|
||||
## LOCALIZATION NOTE (call_with_contact_title): The title displayed
|
||||
## when calling a contact. Don't translate the part between {{..}} because
|
||||
|
|
Загрузка…
Ссылка в новой задаче