зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1156205: show a scrollbar in the social share dropdown list inside the Loop conversation window when the number of items exceeds the maximum height. r=Standard8
This commit is contained in:
Родитель
f44b959fb7
Коммит
e7926bf434
|
@ -161,6 +161,9 @@ loop.conversation = (function(mozL10n) {
|
|||
mozLoop: navigator.mozLoop}
|
||||
), document.querySelector('#main'));
|
||||
|
||||
document.body.setAttribute("dir", mozL10n.getDirection());
|
||||
document.body.setAttribute("platform", loop.shared.utils.getPlatform());
|
||||
|
||||
dispatcher.dispatch(new sharedActions.GetWindowData({
|
||||
windowId: windowId
|
||||
}));
|
||||
|
|
|
@ -161,6 +161,9 @@ loop.conversation = (function(mozL10n) {
|
|||
mozLoop={navigator.mozLoop}
|
||||
/>, document.querySelector('#main'));
|
||||
|
||||
document.body.setAttribute("dir", mozL10n.getDirection());
|
||||
document.body.setAttribute("platform", loop.shared.utils.getPlatform());
|
||||
|
||||
dispatcher.dispatch(new sharedActions.GetWindowData({
|
||||
windowId: windowId
|
||||
}));
|
||||
|
|
|
@ -140,7 +140,7 @@ loop.conversationViews = (function(mozL10n) {
|
|||
var EMAIL_OR_PHONE_RE = /^(:?\S+@\S+|\+\d+)$/;
|
||||
|
||||
var AcceptCallView = React.createClass({displayName: "AcceptCallView",
|
||||
mixins: [sharedMixins.DropdownMenuMixin],
|
||||
mixins: [sharedMixins.DropdownMenuMixin()],
|
||||
|
||||
propTypes: {
|
||||
callType: React.PropTypes.string.isRequired,
|
||||
|
|
|
@ -140,7 +140,7 @@ loop.conversationViews = (function(mozL10n) {
|
|||
var EMAIL_OR_PHONE_RE = /^(:?\S+@\S+|\+\d+)$/;
|
||||
|
||||
var AcceptCallView = React.createClass({
|
||||
mixins: [sharedMixins.DropdownMenuMixin],
|
||||
mixins: [sharedMixins.DropdownMenuMixin()],
|
||||
|
||||
propTypes: {
|
||||
callType: React.PropTypes.string.isRequired,
|
||||
|
|
|
@ -117,7 +117,7 @@ loop.panel = (function(_, mozL10n) {
|
|||
* Availability drop down menu subview.
|
||||
*/
|
||||
var AvailabilityDropdown = React.createClass({displayName: "AvailabilityDropdown",
|
||||
mixins: [sharedMixins.DropdownMenuMixin],
|
||||
mixins: [sharedMixins.DropdownMenuMixin()],
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
|
@ -322,7 +322,7 @@ loop.panel = (function(_, mozL10n) {
|
|||
mozLoop: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
mixins: [sharedMixins.DropdownMenuMixin, sharedMixins.WindowCloseMixin],
|
||||
mixins: [sharedMixins.DropdownMenuMixin(), sharedMixins.WindowCloseMixin],
|
||||
|
||||
handleClickSettingsEntry: function() {
|
||||
// XXX to be implemented at the same time as unhiding the entry
|
||||
|
@ -941,6 +941,7 @@ loop.panel = (function(_, mozL10n) {
|
|||
), document.querySelector("#main"));
|
||||
|
||||
document.body.setAttribute("dir", mozL10n.getDirection());
|
||||
document.body.setAttribute("platform", loop.shared.utils.getPlatform());
|
||||
|
||||
// Notify the window that we've finished initalization and initial layout
|
||||
var evtObject = document.createEvent('Event');
|
||||
|
|
|
@ -117,7 +117,7 @@ loop.panel = (function(_, mozL10n) {
|
|||
* Availability drop down menu subview.
|
||||
*/
|
||||
var AvailabilityDropdown = React.createClass({
|
||||
mixins: [sharedMixins.DropdownMenuMixin],
|
||||
mixins: [sharedMixins.DropdownMenuMixin()],
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
|
@ -322,7 +322,7 @@ loop.panel = (function(_, mozL10n) {
|
|||
mozLoop: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
mixins: [sharedMixins.DropdownMenuMixin, sharedMixins.WindowCloseMixin],
|
||||
mixins: [sharedMixins.DropdownMenuMixin(), sharedMixins.WindowCloseMixin],
|
||||
|
||||
handleClickSettingsEntry: function() {
|
||||
// XXX to be implemented at the same time as unhiding the entry
|
||||
|
@ -941,6 +941,7 @@ loop.panel = (function(_, mozL10n) {
|
|||
/>, document.querySelector("#main"));
|
||||
|
||||
document.body.setAttribute("dir", mozL10n.getDirection());
|
||||
document.body.setAttribute("platform", loop.shared.utils.getPlatform());
|
||||
|
||||
// Notify the window that we've finished initalization and initial layout
|
||||
var evtObject = document.createEvent('Event');
|
||||
|
|
|
@ -113,6 +113,7 @@ loop.roomViews = (function(mozL10n) {
|
|||
var shareDropdown = cx({
|
||||
"share-service-dropdown": true,
|
||||
"dropdown-menu": true,
|
||||
"visually-hidden": true,
|
||||
"share-button-unavailable": !this.props.socialShareButtonAvailable,
|
||||
"hide": !this.props.show
|
||||
});
|
||||
|
@ -170,7 +171,7 @@ loop.roomViews = (function(mozL10n) {
|
|||
* Desktop room invitation view (overlay).
|
||||
*/
|
||||
var DesktopRoomInvitationView = React.createClass({displayName: "DesktopRoomInvitationView",
|
||||
mixins: [sharedMixins.DropdownMenuMixin],
|
||||
mixins: [sharedMixins.DropdownMenuMixin(".room-invitation-overlay")],
|
||||
|
||||
propTypes: {
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
|
@ -185,7 +186,8 @@ loop.roomViews = (function(mozL10n) {
|
|||
getInitialState: function() {
|
||||
return {
|
||||
copiedUrl: false,
|
||||
editMode: false
|
||||
editMode: false,
|
||||
newRoomName: ""
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -239,31 +241,31 @@ loop.roomViews = (function(mozL10n) {
|
|||
React.createElement("a", {className: cx({hide: !canAddContext, "room-invitation-addcontext": true}),
|
||||
onClick: this.handleAddContextClick},
|
||||
mozL10n.get("context_add_some_label")
|
||||
),
|
||||
React.createElement("div", {className: "btn-group call-action-group"},
|
||||
React.createElement("button", {className: "btn btn-info btn-email",
|
||||
onClick: this.handleEmailButtonClick},
|
||||
mozL10n.get("email_link_button")
|
||||
),
|
||||
React.createElement("button", {className: "btn btn-info btn-copy",
|
||||
onClick: this.handleCopyButtonClick},
|
||||
this.state.copiedUrl ? mozL10n.get("copied_url_button") :
|
||||
mozL10n.get("copy_url_button2")
|
||||
),
|
||||
React.createElement("button", {className: "btn btn-info btn-share",
|
||||
ref: "anchor",
|
||||
onClick: this.handleShareButtonClick},
|
||||
mozL10n.get("share_button3")
|
||||
)
|
||||
),
|
||||
React.createElement(SocialShareDropdown, {
|
||||
dispatcher: this.props.dispatcher,
|
||||
roomUrl: this.props.roomData.roomUrl,
|
||||
show: this.state.showMenu,
|
||||
socialShareButtonAvailable: this.props.socialShareButtonAvailable,
|
||||
socialShareProviders: this.props.socialShareProviders,
|
||||
ref: "menu"})
|
||||
)
|
||||
),
|
||||
React.createElement("div", {className: "btn-group call-action-group"},
|
||||
React.createElement("button", {className: "btn btn-info btn-email",
|
||||
onClick: this.handleEmailButtonClick},
|
||||
mozL10n.get("email_link_button")
|
||||
),
|
||||
React.createElement("button", {className: "btn btn-info btn-copy",
|
||||
onClick: this.handleCopyButtonClick},
|
||||
this.state.copiedUrl ? mozL10n.get("copied_url_button") :
|
||||
mozL10n.get("copy_url_button2")
|
||||
),
|
||||
React.createElement("button", {className: "btn btn-info btn-share",
|
||||
ref: "anchor",
|
||||
onClick: this.handleShareButtonClick},
|
||||
mozL10n.get("share_button3")
|
||||
)
|
||||
),
|
||||
React.createElement(SocialShareDropdown, {
|
||||
dispatcher: this.props.dispatcher,
|
||||
roomUrl: this.props.roomData.roomUrl,
|
||||
show: this.state.showMenu,
|
||||
socialShareButtonAvailable: this.props.socialShareButtonAvailable,
|
||||
socialShareProviders: this.props.socialShareProviders,
|
||||
ref: "menu"}),
|
||||
React.createElement(DesktopRoomContextView, {
|
||||
dispatcher: this.props.dispatcher,
|
||||
editMode: this.state.editMode,
|
||||
|
|
|
@ -113,6 +113,7 @@ loop.roomViews = (function(mozL10n) {
|
|||
var shareDropdown = cx({
|
||||
"share-service-dropdown": true,
|
||||
"dropdown-menu": true,
|
||||
"visually-hidden": true,
|
||||
"share-button-unavailable": !this.props.socialShareButtonAvailable,
|
||||
"hide": !this.props.show
|
||||
});
|
||||
|
@ -170,7 +171,7 @@ loop.roomViews = (function(mozL10n) {
|
|||
* Desktop room invitation view (overlay).
|
||||
*/
|
||||
var DesktopRoomInvitationView = React.createClass({
|
||||
mixins: [sharedMixins.DropdownMenuMixin],
|
||||
mixins: [sharedMixins.DropdownMenuMixin(".room-invitation-overlay")],
|
||||
|
||||
propTypes: {
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
|
@ -185,7 +186,8 @@ loop.roomViews = (function(mozL10n) {
|
|||
getInitialState: function() {
|
||||
return {
|
||||
copiedUrl: false,
|
||||
editMode: false
|
||||
editMode: false,
|
||||
newRoomName: ""
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -240,30 +242,30 @@ loop.roomViews = (function(mozL10n) {
|
|||
onClick={this.handleAddContextClick}>
|
||||
{mozL10n.get("context_add_some_label")}
|
||||
</a>
|
||||
<div className="btn-group call-action-group">
|
||||
<button className="btn btn-info btn-email"
|
||||
onClick={this.handleEmailButtonClick}>
|
||||
{mozL10n.get("email_link_button")}
|
||||
</button>
|
||||
<button className="btn btn-info btn-copy"
|
||||
onClick={this.handleCopyButtonClick}>
|
||||
{this.state.copiedUrl ? mozL10n.get("copied_url_button") :
|
||||
mozL10n.get("copy_url_button2")}
|
||||
</button>
|
||||
<button className="btn btn-info btn-share"
|
||||
ref="anchor"
|
||||
onClick={this.handleShareButtonClick}>
|
||||
{mozL10n.get("share_button3")}
|
||||
</button>
|
||||
</div>
|
||||
<SocialShareDropdown
|
||||
dispatcher={this.props.dispatcher}
|
||||
roomUrl={this.props.roomData.roomUrl}
|
||||
show={this.state.showMenu}
|
||||
socialShareButtonAvailable={this.props.socialShareButtonAvailable}
|
||||
socialShareProviders={this.props.socialShareProviders}
|
||||
ref="menu" />
|
||||
</div>
|
||||
<div className="btn-group call-action-group">
|
||||
<button className="btn btn-info btn-email"
|
||||
onClick={this.handleEmailButtonClick}>
|
||||
{mozL10n.get("email_link_button")}
|
||||
</button>
|
||||
<button className="btn btn-info btn-copy"
|
||||
onClick={this.handleCopyButtonClick}>
|
||||
{this.state.copiedUrl ? mozL10n.get("copied_url_button") :
|
||||
mozL10n.get("copy_url_button2")}
|
||||
</button>
|
||||
<button className="btn btn-info btn-share"
|
||||
ref="anchor"
|
||||
onClick={this.handleShareButtonClick}>
|
||||
{mozL10n.get("share_button3")}
|
||||
</button>
|
||||
</div>
|
||||
<SocialShareDropdown
|
||||
dispatcher={this.props.dispatcher}
|
||||
roomUrl={this.props.roomData.roomUrl}
|
||||
show={this.state.showMenu}
|
||||
socialShareButtonAvailable={this.props.socialShareButtonAvailable}
|
||||
socialShareProviders={this.props.socialShareProviders}
|
||||
ref="menu" />
|
||||
<DesktopRoomContextView
|
||||
dispatcher={this.props.dispatcher}
|
||||
editMode={this.state.editMode}
|
||||
|
|
|
@ -426,9 +426,9 @@ p {
|
|||
border-radius: 2px;
|
||||
}
|
||||
|
||||
body[dir=rtl] .dropdown-menu-item {
|
||||
body[dir=rtl] .dropdown-menu {
|
||||
left: auto;
|
||||
right: 10px;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.dropdown-menu-item {
|
||||
|
|
|
@ -866,7 +866,6 @@ html, .fx-embedded, #main,
|
|||
}
|
||||
|
||||
.room-invitation-content {
|
||||
order: 1;
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
|
@ -882,7 +881,7 @@ html, .fx-embedded, #main,
|
|||
}
|
||||
|
||||
.room-invitation-overlay .btn-group {
|
||||
padding: 0;
|
||||
padding: 0 0 1em 0;
|
||||
}
|
||||
|
||||
.room-invitation-addcontext {
|
||||
|
@ -913,6 +912,14 @@ body[dir="rtl"] .room-invitation-addcontext {
|
|||
text-align: start;
|
||||
bottom: auto;
|
||||
top: 0;
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* When the dropdown is showing a vertical scrollbar, compensate for its width. */
|
||||
body[platform="other"] .share-service-dropdown.overflow > .dropdown-menu-item,
|
||||
body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item {
|
||||
-moz-padding-end: 20px;
|
||||
}
|
||||
|
||||
.share-service-dropdown.share-button-unavailable {
|
||||
|
@ -988,7 +995,6 @@ body[dir=rtl] .share-service-dropdown .share-panel-header {
|
|||
position: relative;
|
||||
left: auto;
|
||||
bottom: auto;
|
||||
order: 2;
|
||||
flex: 0 1 auto;
|
||||
}
|
||||
|
||||
|
|
|
@ -83,110 +83,165 @@ loop.shared.mixins = (function() {
|
|||
|
||||
/**
|
||||
* Dropdown menu mixin.
|
||||
*
|
||||
* @param {Sring} [boundingBoxSelector] Selector that points to an element that
|
||||
* defines the constraints this dropdown
|
||||
* is shown within. If not provided,
|
||||
* `document.body` is assumed to be the
|
||||
* constraining element.
|
||||
* @type {Object}
|
||||
*/
|
||||
var DropdownMenuMixin = {
|
||||
get documentBody() {
|
||||
return rootObject.document.body;
|
||||
},
|
||||
var DropdownMenuMixin = function(boundingBoxSelector) {
|
||||
return {
|
||||
get documentBody() {
|
||||
return rootObject.document.body;
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {showMenu: false};
|
||||
},
|
||||
getInitialState: function() {
|
||||
return {
|
||||
showMenu: false
|
||||
};
|
||||
},
|
||||
|
||||
_onBodyClick: function(event) {
|
||||
var menuButton = this.refs["menu-button"] && this.refs["menu-button"].getDOMNode();
|
||||
if (this.refs.anchor) {
|
||||
menuButton = this.refs.anchor.getDOMNode();
|
||||
_onBodyClick: function(event) {
|
||||
var menuButton = this.refs["menu-button"] && this.refs["menu-button"].getDOMNode();
|
||||
if (this.refs.anchor) {
|
||||
menuButton = this.refs.anchor.getDOMNode();
|
||||
}
|
||||
// If a menu button/ anchor is defined and clicked on, it will be in charge
|
||||
// of hiding or showing the popup.
|
||||
if (event.target !== menuButton) {
|
||||
this.setState({ showMenu: false });
|
||||
}
|
||||
},
|
||||
|
||||
_correctMenuPosition: function() {
|
||||
var menu = this.refs.menu && this.refs.menu.getDOMNode();
|
||||
if (!menu) {
|
||||
return;
|
||||
}
|
||||
if (menu.style.maxWidth)
|
||||
menu.style.maxWidth = "none";
|
||||
if (menu.style.maxHeight)
|
||||
menu.style.maxHeight = "none";
|
||||
|
||||
// Correct the position of the menu only if necessary.
|
||||
var x, y, boundingBox, boundingRect;
|
||||
// Amount of pixels that the dropdown needs to stay away from the edges of
|
||||
// the page body.
|
||||
var boundOffset = 4;
|
||||
var menuNodeRect = menu.getBoundingClientRect();
|
||||
// If the menu dimensions are constrained to a bounding element, instead of
|
||||
// the document body, find that element.
|
||||
if (boundingBoxSelector) {
|
||||
boundingBox = this.documentBody.querySelector(boundingBoxSelector);
|
||||
if (boundingBox) {
|
||||
boundingRect = boundingBox.getBoundingClientRect();
|
||||
}
|
||||
}
|
||||
if (!boundingRect) {
|
||||
boundingRect = {
|
||||
height: this.documentBody.offsetHeight,
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: this.documentBody.offsetWidth
|
||||
};
|
||||
}
|
||||
// Make sure the menu position will be a certain fixed amount of pixels away
|
||||
// from the border of the bounding box.
|
||||
boundingRect.width -= boundOffset;
|
||||
boundingRect.height -= boundOffset;
|
||||
|
||||
var x = menuNodeRect.left;
|
||||
var y = menuNodeRect.top;
|
||||
|
||||
// If there's an anchor present, position it relative to it first.
|
||||
var anchor = this.refs.anchor && this.refs.anchor.getDOMNode();
|
||||
if (anchor) {
|
||||
// XXXmikedeboer: at the moment we only support positioning centered above
|
||||
// anchor node. Please add more modes as necessary.
|
||||
var anchorNodeRect = anchor.getBoundingClientRect();
|
||||
// Because we're _correcting_ the position of the dropdown, we assume that
|
||||
// the node is positioned absolute at 0,0 coordinates (top left).
|
||||
x = Math.floor(anchorNodeRect.left - (menuNodeRect.width / 2) + (anchorNodeRect.width / 2));
|
||||
y = Math.floor(anchorNodeRect.top - menuNodeRect.height - anchorNodeRect.height);
|
||||
}
|
||||
|
||||
var overflowX = false;
|
||||
var overflowY = false;
|
||||
// Check the horizontal overflow.
|
||||
if (x + menuNodeRect.width > boundingRect.width) {
|
||||
// Anchor positioning is already relative, so don't subtract it again.
|
||||
x = Math.floor(boundingRect.width - ((anchor ? 0 : x) + menuNodeRect.width));
|
||||
overflowX = true;
|
||||
}
|
||||
// Check the vertical overflow.
|
||||
if (y + menuNodeRect.height > boundingRect.height) {
|
||||
// Anchor positioning is already relative, so don't subtract it again.
|
||||
y = Math.floor(boundingRect.height - ((anchor ? 0 : y) + menuNodeRect.height));
|
||||
overflowY = true;
|
||||
}
|
||||
|
||||
if (anchor || overflowX) {
|
||||
// Set the maximum dimensions that the menu DOMNode may grow to. The
|
||||
// content overflow style should be defined in CSS.
|
||||
// Since we don't care much about horizontal overflow currently, this
|
||||
// doesn't really do much for now.
|
||||
if (menuNodeRect.width > boundingRect.width) {
|
||||
menu.classList.add("overflow");
|
||||
menu.style.maxWidth = boundingRect.width + "px";
|
||||
}
|
||||
menu.style.marginLeft = x + "px";
|
||||
} else if (!menu.style.marginLeft) {
|
||||
menu.style.marginLeft = "auto";
|
||||
}
|
||||
|
||||
if (anchor || overflowY) {
|
||||
if (menuNodeRect.height > (boundingRect.height + y)) {
|
||||
menu.classList.add("overflow");
|
||||
// Set the maximum dimensions that the menu DOMNode may grow to. The
|
||||
// content overflow style should be defined in CSS.
|
||||
menu.style.maxHeight = (boundingRect.height + y) + "px";
|
||||
// Since we just adjusted the max-height of the menu - thus its actual
|
||||
// height as well - we need to adjust its vertical offset with the same
|
||||
// amount.
|
||||
y += menuNodeRect.height - (boundingRect.height + y);
|
||||
}
|
||||
menu.style.marginTop = y + "px";
|
||||
} else if (!menu.style.marginLeft) {
|
||||
menu.style.marginTop = "auto";
|
||||
}
|
||||
|
||||
menu.style.visibility = "visible";
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.documentBody.addEventListener("click", this._onBodyClick);
|
||||
rootObject.addEventListener("blur", this.hideDropdownMenu);
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
this.documentBody.removeEventListener("click", this._onBodyClick);
|
||||
rootObject.removeEventListener("blur", this.hideDropdownMenu);
|
||||
},
|
||||
|
||||
showDropdownMenu: function() {
|
||||
this.setState({showMenu: true}, this._correctMenuPosition);
|
||||
},
|
||||
|
||||
hideDropdownMenu: function() {
|
||||
this.setState({showMenu: false}, function() {
|
||||
var menu = this.refs.menu && this.refs.menu.getDOMNode();
|
||||
if (menu) {
|
||||
menu.style.visibility = "hidden";
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
toggleDropdownMenu: function() {
|
||||
this[this.state.showMenu ? "hideDropdownMenu" : "showDropdownMenu"]();
|
||||
}
|
||||
// If a menu button/ anchor is defined and clicked on, it will be in charge
|
||||
// of hiding or showing the popup.
|
||||
if (event.target !== menuButton) {
|
||||
this.setState({ showMenu: false });
|
||||
}
|
||||
},
|
||||
|
||||
_correctMenuPosition: function() {
|
||||
var menu = this.refs.menu && this.refs.menu.getDOMNode();
|
||||
if (!menu) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Correct the position of the menu only if necessary.
|
||||
var x, y;
|
||||
var menuNodeRect = menu.getBoundingClientRect();
|
||||
var x = menuNodeRect.left;
|
||||
var y = menuNodeRect.top;
|
||||
// Amount of pixels that the dropdown needs to stay away from the edges of
|
||||
// the page body.
|
||||
var bodyMargin = 10;
|
||||
var bodyRect = {
|
||||
height: this.documentBody.offsetHeight - bodyMargin,
|
||||
width: this.documentBody.offsetWidth - bodyMargin
|
||||
};
|
||||
|
||||
// If there's an anchor present, position it relative to it first.
|
||||
var anchor = this.refs.anchor && this.refs.anchor.getDOMNode();
|
||||
if (anchor) {
|
||||
// XXXmikedeboer: at the moment we only support positioning centered above
|
||||
// anchor node. Please add more modes as necessary.
|
||||
var anchorNodeRect = anchor.getBoundingClientRect();
|
||||
// Because we're _correcting_ the position of the dropdown, we assume that
|
||||
// the node is positioned absolute at 0,0 coordinates (top left).
|
||||
x = anchorNodeRect.left - (menuNodeRect.width / 2) + (anchorNodeRect.width / 2);
|
||||
y = anchorNodeRect.top - menuNodeRect.height - anchorNodeRect.height;
|
||||
}
|
||||
|
||||
var overflowX = false;
|
||||
var overflowY = false;
|
||||
// Check the horizontal overflow.
|
||||
if (x + menuNodeRect.width > bodyRect.width) {
|
||||
// Anchor positioning is already relative, so don't subtract it again.
|
||||
x = bodyRect.width - ((anchor ? 0 : x) + menuNodeRect.width);
|
||||
overflowX = true;
|
||||
}
|
||||
// Check the vertical overflow.
|
||||
if (y + menuNodeRect.height > bodyRect.height) {
|
||||
// Anchor positioning is already relative, so don't subtract it again.
|
||||
y = bodyRect.height - ((anchor ? 0 : y) + menuNodeRect.height);
|
||||
overflowY = true;
|
||||
}
|
||||
|
||||
if (anchor || overflowX) {
|
||||
menu.style.marginLeft = x + "px";
|
||||
} else if (!menu.style.marginLeft) {
|
||||
menu.style.marginLeft = "auto";
|
||||
}
|
||||
|
||||
if (anchor || overflowY) {
|
||||
menu.style.marginTop = y + "px";
|
||||
} else if (!menu.style.marginLeft) {
|
||||
menu.style.marginTop = "auto";
|
||||
}
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.documentBody.addEventListener("click", this._onBodyClick);
|
||||
rootObject.addEventListener("blur", this.hideDropdownMenu);
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
this.documentBody.removeEventListener("click", this._onBodyClick);
|
||||
rootObject.removeEventListener("blur", this.hideDropdownMenu);
|
||||
},
|
||||
|
||||
showDropdownMenu: function() {
|
||||
this.setState({showMenu: true});
|
||||
rootObject.setTimeout(this._correctMenuPosition, 0);
|
||||
},
|
||||
|
||||
hideDropdownMenu: function() {
|
||||
this.setState({showMenu: false});
|
||||
},
|
||||
|
||||
toggleDropdownMenu: function() {
|
||||
this[this.state.showMenu ? "hideDropdownMenu" : "showDropdownMenu"]();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -260,6 +260,25 @@ var inChrome = typeof Components != "undefined" && "utils" in Components;
|
|||
return { major: Infinity, minor: 0 };
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to get the current short platform string, based on the return value
|
||||
* of `getOS`.
|
||||
* Possible return values are 'mac', 'win' or 'other'.
|
||||
*
|
||||
* @param {String} [os] Optional string for the OS, used in tests only.
|
||||
* @return {String} 'mac', 'win' or 'other'.
|
||||
*/
|
||||
var getPlatform = function(os) {
|
||||
os = getOS(os);
|
||||
var platform = "other";
|
||||
if (os.indexOf("mac") > -1) {
|
||||
platform = "mac";
|
||||
} else if (os.indexOf("win") > -1) {
|
||||
platform = "win";
|
||||
}
|
||||
return platform;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to allow getting some of the location data in a way that's compatible
|
||||
* with stubbing for unit tests.
|
||||
|
@ -632,6 +651,7 @@ var inChrome = typeof Components != "undefined" && "utils" in Components;
|
|||
getBoolPreference: getBoolPreference,
|
||||
getOS: getOS,
|
||||
getOSVersion: getOSVersion,
|
||||
getPlatform: getPlatform,
|
||||
isChrome: isChrome,
|
||||
isFirefox: isFirefox,
|
||||
isFirefoxOS: isFirefoxOS,
|
||||
|
|
|
@ -83,7 +83,7 @@ loop.shared.views = (function(_, l10n) {
|
|||
* loop.shared.utils.SCREEN_SHARE_STATES
|
||||
*/
|
||||
var ScreenShareControlButton = React.createClass({displayName: "ScreenShareControlButton",
|
||||
mixins: [sharedMixins.DropdownMenuMixin],
|
||||
mixins: [sharedMixins.DropdownMenuMixin()],
|
||||
|
||||
propTypes: {
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
|
@ -151,7 +151,8 @@ loop.shared.views = (function(_, l10n) {
|
|||
var dropdownMenuClasses = cx({
|
||||
"native-dropdown-menu": true,
|
||||
"conversation-window-dropdown": true,
|
||||
"visually-hidden": !this.state.showMenu
|
||||
"hide": !this.state.showMenu,
|
||||
"visually-hidden": true
|
||||
});
|
||||
var windowSharingClasses = cx({
|
||||
"disabled": this.state.windowSharingDisabled
|
||||
|
|
|
@ -83,7 +83,7 @@ loop.shared.views = (function(_, l10n) {
|
|||
* loop.shared.utils.SCREEN_SHARE_STATES
|
||||
*/
|
||||
var ScreenShareControlButton = React.createClass({
|
||||
mixins: [sharedMixins.DropdownMenuMixin],
|
||||
mixins: [sharedMixins.DropdownMenuMixin()],
|
||||
|
||||
propTypes: {
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
|
@ -151,7 +151,8 @@ loop.shared.views = (function(_, l10n) {
|
|||
var dropdownMenuClasses = cx({
|
||||
"native-dropdown-menu": true,
|
||||
"conversation-window-dropdown": true,
|
||||
"visually-hidden": !this.state.showMenu
|
||||
"hide": !this.state.showMenu,
|
||||
"visually-hidden": true
|
||||
});
|
||||
var windowSharingClasses = cx({
|
||||
"disabled": this.state.windowSharingDisabled
|
||||
|
|
|
@ -386,7 +386,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
});
|
||||
|
||||
var InitiateCallButton = React.createClass({displayName: "InitiateCallButton",
|
||||
mixins: [sharedMixins.DropdownMenuMixin],
|
||||
mixins: [sharedMixins.DropdownMenuMixin()],
|
||||
|
||||
propTypes: {
|
||||
caption: React.PropTypes.string.isRequired,
|
||||
|
|
|
@ -386,7 +386,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
|
|||
});
|
||||
|
||||
var InitiateCallButton = React.createClass({
|
||||
mixins: [sharedMixins.DropdownMenuMixin],
|
||||
mixins: [sharedMixins.DropdownMenuMixin()],
|
||||
|
||||
propTypes: {
|
||||
caption: React.PropTypes.string.isRequired,
|
||||
|
|
|
@ -319,6 +319,43 @@ describe("loop.shared.utils", function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe("#getPlatform", function() {
|
||||
it("should recognize the OSX userAgent string", function() {
|
||||
var UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:37.0) Gecko/20100101 Firefox/37.0";
|
||||
var result = sharedUtils.getPlatform(UA);
|
||||
|
||||
expect(result).eql("mac");
|
||||
});
|
||||
|
||||
it("should recognize the Windows userAgent string", function() {
|
||||
var UA = "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:10.0) Gecko/20100101 Firefox/10.0";
|
||||
var result = sharedUtils.getPlatform(UA);
|
||||
|
||||
expect(result).eql("win");
|
||||
});
|
||||
|
||||
it("should recognize the Linux userAgent string", function() {
|
||||
var UA = "Mozilla/5.0 (X11; Linux i686 on x86_64; rv:10.0) Gecko/20100101 Firefox/10.0";
|
||||
var result = sharedUtils.getPlatform(UA);
|
||||
|
||||
expect(result).eql("other");
|
||||
});
|
||||
|
||||
it("should recognize the OSX oscpu string", function() {
|
||||
var oscpu = "Intel Mac OS X 10.10";
|
||||
var result = sharedUtils.getPlatform(oscpu);
|
||||
|
||||
expect(result).eql("mac");
|
||||
});
|
||||
|
||||
it("should recognize the Windows oscpu string", function() {
|
||||
var oscpu = "Windows NT 5.3; Win64; x64";
|
||||
var result = sharedUtils.getPlatform(oscpu);
|
||||
|
||||
expect(result).eql("win");
|
||||
});
|
||||
});
|
||||
|
||||
describe("#objectDiff", function() {
|
||||
var a, b, diff;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче