зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1171940: remove the mode-switching and have only one-mode Edit Context view inside the Hello conversation window. r=Standard8
This commit is contained in:
Родитель
06878cbdf4
Коммит
6bb8d833b9
|
@ -153,18 +153,19 @@ loop.roomViews = (function(mozL10n) {
|
|||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
error: React.PropTypes.object,
|
||||
mozLoop: React.PropTypes.object.isRequired,
|
||||
onAddContextClick: React.PropTypes.func,
|
||||
onEditContextClose: React.PropTypes.func,
|
||||
// This data is supplied by the activeRoomStore.
|
||||
roomData: React.PropTypes.object.isRequired,
|
||||
savingContext: React.PropTypes.bool,
|
||||
show: React.PropTypes.bool.isRequired,
|
||||
showContext: React.PropTypes.bool.isRequired,
|
||||
showEditContext: React.PropTypes.bool.isRequired,
|
||||
socialShareProviders: React.PropTypes.array
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
copiedUrl: false,
|
||||
editMode: false,
|
||||
newRoomName: ""
|
||||
};
|
||||
},
|
||||
|
@ -207,11 +208,15 @@ loop.roomViews = (function(mozL10n) {
|
|||
handleAddContextClick: function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
this.handleEditModeChange(true);
|
||||
if (this.props.onAddContextClick) {
|
||||
this.props.onAddContextClick();
|
||||
}
|
||||
},
|
||||
|
||||
handleEditModeChange: function(newEditMode) {
|
||||
this.setState({ editMode: newEditMode });
|
||||
handleEditContextClose: function() {
|
||||
if (this.props.onEditContextClose) {
|
||||
this.props.onEditContextClose();
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
@ -220,13 +225,16 @@ loop.roomViews = (function(mozL10n) {
|
|||
}
|
||||
|
||||
var canAddContext = this.props.mozLoop.getLoopPref("contextInConversations.enabled") &&
|
||||
!this.props.showContext && !this.state.editMode;
|
||||
// Don't show the link when we're showing the edit form already:
|
||||
!this.props.showEditContext &&
|
||||
// Don't show the link when there's already context data available:
|
||||
!(this.props.roomData.roomContextUrls || this.props.roomData.roomDescription);
|
||||
|
||||
var cx = React.addons.classSet;
|
||||
return (
|
||||
React.createElement("div", {className: "room-invitation-overlay"},
|
||||
React.createElement("div", {className: "room-invitation-content"},
|
||||
React.createElement("p", {className: cx({hide: this.state.editMode})},
|
||||
React.createElement("p", {className: cx({hide: this.props.showEditContext})},
|
||||
mozL10n.get("invite_header_text")
|
||||
),
|
||||
React.createElement("a", {className: cx({hide: !canAddContext, "room-invitation-addcontext": true}),
|
||||
|
@ -237,7 +245,7 @@ loop.roomViews = (function(mozL10n) {
|
|||
React.createElement("div", {className: cx({
|
||||
"btn-group": true,
|
||||
"call-action-group": true,
|
||||
hide: this.state.editMode
|
||||
hide: this.props.showEditContext
|
||||
})},
|
||||
React.createElement("button", {className: "btn btn-info btn-email",
|
||||
onClick: this.handleEmailButtonClick},
|
||||
|
@ -260,62 +268,47 @@ loop.roomViews = (function(mozL10n) {
|
|||
roomUrl: this.props.roomData.roomUrl,
|
||||
show: this.state.showMenu,
|
||||
socialShareProviders: this.props.socialShareProviders}),
|
||||
React.createElement(DesktopRoomContextView, {
|
||||
React.createElement(DesktopRoomEditContextView, {
|
||||
dispatcher: this.props.dispatcher,
|
||||
editMode: this.state.editMode,
|
||||
error: this.props.error,
|
||||
mozLoop: this.props.mozLoop,
|
||||
onEditModeChange: this.handleEditModeChange,
|
||||
onClose: this.handleEditContextClose,
|
||||
roomData: this.props.roomData,
|
||||
savingContext: this.props.savingContext,
|
||||
show: this.props.showContext || this.state.editMode})
|
||||
show: this.props.showEditContext})
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var DesktopRoomContextView = React.createClass({displayName: "DesktopRoomContextView",
|
||||
var DesktopRoomEditContextView = React.createClass({displayName: "DesktopRoomEditContextView",
|
||||
mixins: [React.addons.LinkedStateMixin],
|
||||
|
||||
propTypes: {
|
||||
// Only used for tests.
|
||||
availableContext: React.PropTypes.object,
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
editMode: React.PropTypes.bool,
|
||||
error: React.PropTypes.object,
|
||||
mozLoop: React.PropTypes.object.isRequired,
|
||||
onEditModeChange: React.PropTypes.func,
|
||||
onClose: React.PropTypes.func,
|
||||
// This data is supplied by the activeRoomStore.
|
||||
roomData: React.PropTypes.object.isRequired,
|
||||
savingContext: React.PropTypes.bool.isRequired,
|
||||
show: React.PropTypes.bool.isRequired
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
this._fetchMetadata();
|
||||
},
|
||||
|
||||
componentWillReceiveProps: function(nextProps) {
|
||||
var newState = {};
|
||||
// When the 'show' prop is changed from outside this component, we do need
|
||||
// to update the state.
|
||||
if (("show" in nextProps) && nextProps.show !== this.props.show) {
|
||||
newState.show = nextProps.show;
|
||||
}
|
||||
if (("editMode" in nextProps && nextProps.editMode !== this.props.editMode)) {
|
||||
newState.editMode = nextProps.editMode;
|
||||
// If we're switching to edit mode, fetch the metadata of the current tab.
|
||||
// But _only_ if there's no context currently attached to the room; the
|
||||
// checkbox will be disabled in that case.
|
||||
if (nextProps.editMode) {
|
||||
this.props.mozLoop.getSelectedTabMetadata(function(metadata) {
|
||||
var previewImage = metadata.favicon || "";
|
||||
var description = metadata.title || metadata.description;
|
||||
var metaUrl = metadata.url;
|
||||
this.setState({
|
||||
availableContext: {
|
||||
previewImage: previewImage,
|
||||
description: description,
|
||||
url: metaUrl
|
||||
}
|
||||
});
|
||||
}.bind(this));
|
||||
if (nextProps.show) {
|
||||
this._fetchMetadata();
|
||||
}
|
||||
}
|
||||
// When we receive an update for the `roomData` property, make sure that
|
||||
|
@ -341,28 +334,16 @@ loop.roomViews = (function(mozL10n) {
|
|||
}
|
||||
}
|
||||
|
||||
// Make sure we do not show the edit-mode when we just successfully saved
|
||||
// context.
|
||||
if (this.props.savingContext && nextProps.savingContext !== this.props.savingContext &&
|
||||
!nextProps.error && this.state.editMode) {
|
||||
newState.editMode = false;
|
||||
}
|
||||
|
||||
if (Object.getOwnPropertyNames(newState).length) {
|
||||
this.setState(newState);
|
||||
}
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
return { editMode: false };
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
var url = this._getURL();
|
||||
return {
|
||||
// `availableContext` prop only used in tests.
|
||||
availableContext: this.props.availableContext,
|
||||
editMode: this.props.editMode,
|
||||
show: this.props.show,
|
||||
newRoomName: this.props.roomData.roomName || "",
|
||||
newRoomURL: url && url.location || "",
|
||||
|
@ -371,17 +352,29 @@ loop.roomViews = (function(mozL10n) {
|
|||
};
|
||||
},
|
||||
|
||||
_fetchMetadata: function() {
|
||||
this.props.mozLoop.getSelectedTabMetadata(function(metadata) {
|
||||
var previewImage = metadata.favicon || "";
|
||||
var description = metadata.title || metadata.description;
|
||||
var metaUrl = metadata.url;
|
||||
this.setState({
|
||||
availableContext: {
|
||||
previewImage: previewImage,
|
||||
description: description,
|
||||
url: metaUrl
|
||||
}
|
||||
});
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
handleCloseClick: function(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
if (this.state.editMode) {
|
||||
this.setState({ editMode: false });
|
||||
if (this.props.onEditModeChange) {
|
||||
this.props.onEditModeChange(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.setState({ show: false });
|
||||
if (this.props.onClose) {
|
||||
this.props.onClose();
|
||||
}
|
||||
},
|
||||
|
||||
handleContextClick: function(event) {
|
||||
|
@ -396,15 +389,6 @@ loop.roomViews = (function(mozL10n) {
|
|||
this.props.mozLoop.openURL(url.location);
|
||||
},
|
||||
|
||||
handleEditClick: function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
this.setState({ editMode: true });
|
||||
if (this.props.onEditModeChange) {
|
||||
this.props.onEditModeChange(true);
|
||||
}
|
||||
},
|
||||
|
||||
handleCheckboxChange: function(state) {
|
||||
if (state.checked) {
|
||||
// The checkbox was checked, prefill the fields with the values available
|
||||
|
@ -478,7 +462,7 @@ loop.roomViews = (function(mozL10n) {
|
|||
},
|
||||
|
||||
render: function() {
|
||||
if (!this.state.show && !this.state.editMode) {
|
||||
if (!this.state.show) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -486,93 +470,55 @@ loop.roomViews = (function(mozL10n) {
|
|||
var thumbnail = url && url.thumbnail || "loop/shared/img/icons-16x16.svg#globe";
|
||||
var urlDescription = url && url.description || "";
|
||||
var location = url && url.location || "";
|
||||
var locationData = null;
|
||||
if (location) {
|
||||
locationData = checkboxLabel = sharedUtils.formatURL(location);
|
||||
}
|
||||
if (!checkboxLabel) {
|
||||
try {
|
||||
checkboxLabel = sharedUtils.formatURL((this.state.availableContext ?
|
||||
this.state.availableContext.url : ""));
|
||||
} catch (ex) {}
|
||||
}
|
||||
|
||||
var cx = React.addons.classSet;
|
||||
if (this.state.editMode) {
|
||||
var availableContext = this.state.availableContext;
|
||||
// The checkbox shows as checked when there's already context data
|
||||
// attached to this room.
|
||||
var checked = !!urlDescription;
|
||||
var checkboxLabel = urlDescription || (availableContext && availableContext.url ?
|
||||
availableContext.description : "");
|
||||
|
||||
return (
|
||||
React.createElement("div", {className: "room-context editMode"},
|
||||
React.createElement("p", {className: cx({"error": !!this.props.error,
|
||||
"error-display-area": true})},
|
||||
mozL10n.get("rooms_change_failed_label")
|
||||
),
|
||||
React.createElement("div", {className: "room-context-label"}, mozL10n.get("context_inroom_label")),
|
||||
React.createElement(sharedViews.Checkbox, {
|
||||
additionalClass: cx({ hide: !checkboxLabel }),
|
||||
checked: checked,
|
||||
disabled: checked,
|
||||
label: checkboxLabel,
|
||||
onChange: this.handleCheckboxChange,
|
||||
value: location}),
|
||||
React.createElement("form", {onSubmit: this.handleFormSubmit},
|
||||
React.createElement("input", {className: "room-context-name",
|
||||
onKeyDown: this.handleTextareaKeyDown,
|
||||
placeholder: mozL10n.get("context_edit_name_placeholder"),
|
||||
type: "text",
|
||||
valueLink: this.linkState("newRoomName")}),
|
||||
React.createElement("input", {className: "room-context-url",
|
||||
disabled: availableContext && availableContext.url === this.state.newRoomURL,
|
||||
onKeyDown: this.handleTextareaKeyDown,
|
||||
placeholder: "https://",
|
||||
type: "text",
|
||||
valueLink: this.linkState("newRoomURL")}),
|
||||
React.createElement("textarea", {className: "room-context-comments",
|
||||
onKeyDown: this.handleTextareaKeyDown,
|
||||
placeholder: mozL10n.get("context_edit_comments_placeholder"),
|
||||
rows: "3", type: "text",
|
||||
valueLink: this.linkState("newRoomDescription")})
|
||||
),
|
||||
React.createElement("button", {className: "btn btn-info",
|
||||
disabled: this.props.savingContext,
|
||||
onClick: this.handleFormSubmit},
|
||||
mozL10n.get("context_save_label2")
|
||||
),
|
||||
React.createElement("button", {className: "room-context-btn-close",
|
||||
onClick: this.handleCloseClick,
|
||||
title: mozL10n.get("cancel_button")})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (!locationData) {
|
||||
return null;
|
||||
}
|
||||
var availableContext = this.state.availableContext;
|
||||
// The checkbox shows as checked when there's already context data
|
||||
// attached to this room.
|
||||
var checked = !!urlDescription;
|
||||
var checkboxLabel = urlDescription || (availableContext && availableContext.url ?
|
||||
availableContext.description : "");
|
||||
|
||||
return (
|
||||
React.createElement("div", {className: "room-context"},
|
||||
React.createElement("p", {className: cx({"error": !!this.props.error,
|
||||
"error-display-area": true})},
|
||||
mozL10n.get("rooms_change_failed_label")
|
||||
),
|
||||
React.createElement("div", {className: "room-context-label"}, mozL10n.get("context_inroom_label")),
|
||||
React.createElement("div", {className: "room-context-content",
|
||||
onClick: this.handleContextClick},
|
||||
React.createElement("img", {className: "room-context-thumbnail", src: thumbnail}),
|
||||
React.createElement("div", {className: "room-context-description",
|
||||
title: urlDescription},
|
||||
this._truncate(urlDescription),
|
||||
React.createElement("a", {className: "room-context-url",
|
||||
title: locationData.location}, locationData.hostname)
|
||||
)
|
||||
React.createElement(sharedViews.Checkbox, {
|
||||
additionalClass: cx({ hide: !checkboxLabel }),
|
||||
checked: checked,
|
||||
disabled: checked,
|
||||
label: checkboxLabel,
|
||||
onChange: this.handleCheckboxChange,
|
||||
value: location}),
|
||||
React.createElement("form", {onSubmit: this.handleFormSubmit},
|
||||
React.createElement("input", {className: "room-context-name",
|
||||
onKeyDown: this.handleTextareaKeyDown,
|
||||
placeholder: mozL10n.get("context_edit_name_placeholder"),
|
||||
type: "text",
|
||||
valueLink: this.linkState("newRoomName")}),
|
||||
React.createElement("input", {className: "room-context-url",
|
||||
disabled: availableContext && availableContext.url === this.state.newRoomURL,
|
||||
onKeyDown: this.handleTextareaKeyDown,
|
||||
placeholder: "https://",
|
||||
type: "text",
|
||||
valueLink: this.linkState("newRoomURL")}),
|
||||
React.createElement("textarea", {className: "room-context-comments",
|
||||
onKeyDown: this.handleTextareaKeyDown,
|
||||
placeholder: mozL10n.get("context_edit_comments_placeholder"),
|
||||
rows: "3", type: "text",
|
||||
valueLink: this.linkState("newRoomDescription")})
|
||||
),
|
||||
React.createElement("button", {className: "btn btn-info",
|
||||
disabled: this.props.savingContext,
|
||||
onClick: this.handleFormSubmit},
|
||||
mozL10n.get("context_save_label2")
|
||||
),
|
||||
React.createElement("button", {className: "room-context-btn-close",
|
||||
onClick: this.handleCloseClick,
|
||||
title: mozL10n.get("context_hide_tooltip")}),
|
||||
React.createElement("button", {className: "room-context-btn-edit",
|
||||
onClick: this.handleEditClick,
|
||||
title: mozL10n.get("context_edit_tooltip")})
|
||||
title: mozL10n.get("cancel_button")})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -599,6 +545,13 @@ loop.roomViews = (function(mozL10n) {
|
|||
roomStore: React.PropTypes.instanceOf(loop.store.RoomStore).isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
contextEnabled: this.props.mozLoop.getLoopPref("contextInConversations.enabled"),
|
||||
showEditContext: false
|
||||
};
|
||||
},
|
||||
|
||||
componentWillUpdate: function(nextProps, nextState) {
|
||||
// The SDK needs to know about the configuration and the elements to use
|
||||
// for display. So the best way seems to pass the information here - ideally
|
||||
|
@ -642,13 +595,6 @@ loop.roomViews = (function(mozL10n) {
|
|||
return (this.state.roomState !== ROOM_STATES.HAS_PARTICIPANTS);
|
||||
},
|
||||
|
||||
_shouldRenderContextView: function() {
|
||||
return !!(
|
||||
this.props.mozLoop.getLoopPref("contextInConversations.enabled") &&
|
||||
(this.state.roomContextUrls || this.state.roomDescription)
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Works out if remote video should be rended or not, depending on the
|
||||
* room state and other flags.
|
||||
|
@ -718,6 +664,14 @@ loop.roomViews = (function(mozL10n) {
|
|||
!this.state.mediaConnected;
|
||||
},
|
||||
|
||||
handleAddContextClick: function() {
|
||||
this.setState({ showEditContext: true });
|
||||
},
|
||||
|
||||
handleEditContextClose: function() {
|
||||
this.setState({ showEditContext: false });
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (this.state.roomName) {
|
||||
this.setTitle(this.state.roomName);
|
||||
|
@ -736,7 +690,7 @@ loop.roomViews = (function(mozL10n) {
|
|||
};
|
||||
|
||||
var shouldRenderInvitationOverlay = this._shouldRenderInvitationOverlay();
|
||||
var shouldRenderContextView = this._shouldRenderContextView();
|
||||
var shouldRenderEditContextView = this.state.contextEnabled && this.state.showEditContext;
|
||||
var roomData = this.props.roomStore.getStoreState("activeRoom");
|
||||
|
||||
switch(this.state.roomState) {
|
||||
|
@ -760,18 +714,20 @@ loop.roomViews = (function(mozL10n) {
|
|||
|
||||
return (
|
||||
React.createElement("div", {className: "room-conversation-wrapper"},
|
||||
React.createElement(DesktopRoomInvitationView, {
|
||||
dispatcher: this.props.dispatcher,
|
||||
error: this.state.error,
|
||||
mozLoop: this.props.mozLoop,
|
||||
roomData: roomData,
|
||||
savingContext: this.state.savingContext,
|
||||
show: shouldRenderInvitationOverlay,
|
||||
showContext: shouldRenderContextView,
|
||||
socialShareProviders: this.state.socialShareProviders}),
|
||||
React.createElement("div", {className: "video-layout-wrapper"},
|
||||
React.createElement("div", {className: "conversation room-conversation"},
|
||||
React.createElement("div", {className: "media nested"},
|
||||
React.createElement(DesktopRoomInvitationView, {
|
||||
dispatcher: this.props.dispatcher,
|
||||
error: this.state.error,
|
||||
mozLoop: this.props.mozLoop,
|
||||
onAddContextClick: this.handleAddContextClick,
|
||||
onEditContextClose: this.handleEditContextClose,
|
||||
roomData: roomData,
|
||||
savingContext: this.state.savingContext,
|
||||
show: shouldRenderInvitationOverlay,
|
||||
showEditContext: shouldRenderInvitationOverlay && shouldRenderEditContextView,
|
||||
socialShareProviders: this.state.socialShareProviders}),
|
||||
React.createElement("div", {className: "video_wrapper remote_wrapper"},
|
||||
React.createElement("div", {className: "video_inner remote focus-stream"},
|
||||
React.createElement(sharedViews.MediaView, {displayAvatar: !this.shouldRenderRemoteVideo(),
|
||||
|
@ -798,13 +754,14 @@ loop.roomViews = (function(mozL10n) {
|
|||
video: {enabled: !this.state.videoMuted, visible: true}})
|
||||
)
|
||||
),
|
||||
React.createElement(DesktopRoomContextView, {
|
||||
React.createElement(DesktopRoomEditContextView, {
|
||||
dispatcher: this.props.dispatcher,
|
||||
error: this.state.error,
|
||||
mozLoop: this.props.mozLoop,
|
||||
onClose: this.handleEditContextClose,
|
||||
roomData: roomData,
|
||||
savingContext: this.state.savingContext,
|
||||
show: !shouldRenderInvitationOverlay && shouldRenderContextView}),
|
||||
show: !shouldRenderInvitationOverlay && shouldRenderEditContextView}),
|
||||
React.createElement(sharedViews.chat.TextChatView, {
|
||||
dispatcher: this.props.dispatcher,
|
||||
showAlways: false,
|
||||
|
@ -820,7 +777,7 @@ loop.roomViews = (function(mozL10n) {
|
|||
return {
|
||||
ActiveRoomStoreMixin: ActiveRoomStoreMixin,
|
||||
SocialShareDropdown: SocialShareDropdown,
|
||||
DesktopRoomContextView: DesktopRoomContextView,
|
||||
DesktopRoomEditContextView: DesktopRoomEditContextView,
|
||||
DesktopRoomConversationView: DesktopRoomConversationView,
|
||||
DesktopRoomInvitationView: DesktopRoomInvitationView
|
||||
};
|
||||
|
|
|
@ -153,18 +153,19 @@ loop.roomViews = (function(mozL10n) {
|
|||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
error: React.PropTypes.object,
|
||||
mozLoop: React.PropTypes.object.isRequired,
|
||||
onAddContextClick: React.PropTypes.func,
|
||||
onEditContextClose: React.PropTypes.func,
|
||||
// This data is supplied by the activeRoomStore.
|
||||
roomData: React.PropTypes.object.isRequired,
|
||||
savingContext: React.PropTypes.bool,
|
||||
show: React.PropTypes.bool.isRequired,
|
||||
showContext: React.PropTypes.bool.isRequired,
|
||||
showEditContext: React.PropTypes.bool.isRequired,
|
||||
socialShareProviders: React.PropTypes.array
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
copiedUrl: false,
|
||||
editMode: false,
|
||||
newRoomName: ""
|
||||
};
|
||||
},
|
||||
|
@ -207,11 +208,15 @@ loop.roomViews = (function(mozL10n) {
|
|||
handleAddContextClick: function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
this.handleEditModeChange(true);
|
||||
if (this.props.onAddContextClick) {
|
||||
this.props.onAddContextClick();
|
||||
}
|
||||
},
|
||||
|
||||
handleEditModeChange: function(newEditMode) {
|
||||
this.setState({ editMode: newEditMode });
|
||||
handleEditContextClose: function() {
|
||||
if (this.props.onEditContextClose) {
|
||||
this.props.onEditContextClose();
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
@ -220,13 +225,16 @@ loop.roomViews = (function(mozL10n) {
|
|||
}
|
||||
|
||||
var canAddContext = this.props.mozLoop.getLoopPref("contextInConversations.enabled") &&
|
||||
!this.props.showContext && !this.state.editMode;
|
||||
// Don't show the link when we're showing the edit form already:
|
||||
!this.props.showEditContext &&
|
||||
// Don't show the link when there's already context data available:
|
||||
!(this.props.roomData.roomContextUrls || this.props.roomData.roomDescription);
|
||||
|
||||
var cx = React.addons.classSet;
|
||||
return (
|
||||
<div className="room-invitation-overlay">
|
||||
<div className="room-invitation-content">
|
||||
<p className={cx({hide: this.state.editMode})}>
|
||||
<p className={cx({hide: this.props.showEditContext})}>
|
||||
{mozL10n.get("invite_header_text")}
|
||||
</p>
|
||||
<a className={cx({hide: !canAddContext, "room-invitation-addcontext": true})}
|
||||
|
@ -237,7 +245,7 @@ loop.roomViews = (function(mozL10n) {
|
|||
<div className={cx({
|
||||
"btn-group": true,
|
||||
"call-action-group": true,
|
||||
hide: this.state.editMode
|
||||
hide: this.props.showEditContext
|
||||
})}>
|
||||
<button className="btn btn-info btn-email"
|
||||
onClick={this.handleEmailButtonClick}>
|
||||
|
@ -260,62 +268,47 @@ loop.roomViews = (function(mozL10n) {
|
|||
roomUrl={this.props.roomData.roomUrl}
|
||||
show={this.state.showMenu}
|
||||
socialShareProviders={this.props.socialShareProviders} />
|
||||
<DesktopRoomContextView
|
||||
<DesktopRoomEditContextView
|
||||
dispatcher={this.props.dispatcher}
|
||||
editMode={this.state.editMode}
|
||||
error={this.props.error}
|
||||
mozLoop={this.props.mozLoop}
|
||||
onEditModeChange={this.handleEditModeChange}
|
||||
onClose={this.handleEditContextClose}
|
||||
roomData={this.props.roomData}
|
||||
savingContext={this.props.savingContext}
|
||||
show={this.props.showContext || this.state.editMode} />
|
||||
show={this.props.showEditContext} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var DesktopRoomContextView = React.createClass({
|
||||
var DesktopRoomEditContextView = React.createClass({
|
||||
mixins: [React.addons.LinkedStateMixin],
|
||||
|
||||
propTypes: {
|
||||
// Only used for tests.
|
||||
availableContext: React.PropTypes.object,
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
editMode: React.PropTypes.bool,
|
||||
error: React.PropTypes.object,
|
||||
mozLoop: React.PropTypes.object.isRequired,
|
||||
onEditModeChange: React.PropTypes.func,
|
||||
onClose: React.PropTypes.func,
|
||||
// This data is supplied by the activeRoomStore.
|
||||
roomData: React.PropTypes.object.isRequired,
|
||||
savingContext: React.PropTypes.bool.isRequired,
|
||||
show: React.PropTypes.bool.isRequired
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
this._fetchMetadata();
|
||||
},
|
||||
|
||||
componentWillReceiveProps: function(nextProps) {
|
||||
var newState = {};
|
||||
// When the 'show' prop is changed from outside this component, we do need
|
||||
// to update the state.
|
||||
if (("show" in nextProps) && nextProps.show !== this.props.show) {
|
||||
newState.show = nextProps.show;
|
||||
}
|
||||
if (("editMode" in nextProps && nextProps.editMode !== this.props.editMode)) {
|
||||
newState.editMode = nextProps.editMode;
|
||||
// If we're switching to edit mode, fetch the metadata of the current tab.
|
||||
// But _only_ if there's no context currently attached to the room; the
|
||||
// checkbox will be disabled in that case.
|
||||
if (nextProps.editMode) {
|
||||
this.props.mozLoop.getSelectedTabMetadata(function(metadata) {
|
||||
var previewImage = metadata.favicon || "";
|
||||
var description = metadata.title || metadata.description;
|
||||
var metaUrl = metadata.url;
|
||||
this.setState({
|
||||
availableContext: {
|
||||
previewImage: previewImage,
|
||||
description: description,
|
||||
url: metaUrl
|
||||
}
|
||||
});
|
||||
}.bind(this));
|
||||
if (nextProps.show) {
|
||||
this._fetchMetadata();
|
||||
}
|
||||
}
|
||||
// When we receive an update for the `roomData` property, make sure that
|
||||
|
@ -341,28 +334,16 @@ loop.roomViews = (function(mozL10n) {
|
|||
}
|
||||
}
|
||||
|
||||
// Make sure we do not show the edit-mode when we just successfully saved
|
||||
// context.
|
||||
if (this.props.savingContext && nextProps.savingContext !== this.props.savingContext &&
|
||||
!nextProps.error && this.state.editMode) {
|
||||
newState.editMode = false;
|
||||
}
|
||||
|
||||
if (Object.getOwnPropertyNames(newState).length) {
|
||||
this.setState(newState);
|
||||
}
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
return { editMode: false };
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
var url = this._getURL();
|
||||
return {
|
||||
// `availableContext` prop only used in tests.
|
||||
availableContext: this.props.availableContext,
|
||||
editMode: this.props.editMode,
|
||||
show: this.props.show,
|
||||
newRoomName: this.props.roomData.roomName || "",
|
||||
newRoomURL: url && url.location || "",
|
||||
|
@ -371,17 +352,29 @@ loop.roomViews = (function(mozL10n) {
|
|||
};
|
||||
},
|
||||
|
||||
_fetchMetadata: function() {
|
||||
this.props.mozLoop.getSelectedTabMetadata(function(metadata) {
|
||||
var previewImage = metadata.favicon || "";
|
||||
var description = metadata.title || metadata.description;
|
||||
var metaUrl = metadata.url;
|
||||
this.setState({
|
||||
availableContext: {
|
||||
previewImage: previewImage,
|
||||
description: description,
|
||||
url: metaUrl
|
||||
}
|
||||
});
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
handleCloseClick: function(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
if (this.state.editMode) {
|
||||
this.setState({ editMode: false });
|
||||
if (this.props.onEditModeChange) {
|
||||
this.props.onEditModeChange(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.setState({ show: false });
|
||||
if (this.props.onClose) {
|
||||
this.props.onClose();
|
||||
}
|
||||
},
|
||||
|
||||
handleContextClick: function(event) {
|
||||
|
@ -396,15 +389,6 @@ loop.roomViews = (function(mozL10n) {
|
|||
this.props.mozLoop.openURL(url.location);
|
||||
},
|
||||
|
||||
handleEditClick: function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
this.setState({ editMode: true });
|
||||
if (this.props.onEditModeChange) {
|
||||
this.props.onEditModeChange(true);
|
||||
}
|
||||
},
|
||||
|
||||
handleCheckboxChange: function(state) {
|
||||
if (state.checked) {
|
||||
// The checkbox was checked, prefill the fields with the values available
|
||||
|
@ -478,7 +462,7 @@ loop.roomViews = (function(mozL10n) {
|
|||
},
|
||||
|
||||
render: function() {
|
||||
if (!this.state.show && !this.state.editMode) {
|
||||
if (!this.state.show) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -486,93 +470,55 @@ loop.roomViews = (function(mozL10n) {
|
|||
var thumbnail = url && url.thumbnail || "loop/shared/img/icons-16x16.svg#globe";
|
||||
var urlDescription = url && url.description || "";
|
||||
var location = url && url.location || "";
|
||||
var locationData = null;
|
||||
if (location) {
|
||||
locationData = checkboxLabel = sharedUtils.formatURL(location);
|
||||
}
|
||||
if (!checkboxLabel) {
|
||||
try {
|
||||
checkboxLabel = sharedUtils.formatURL((this.state.availableContext ?
|
||||
this.state.availableContext.url : ""));
|
||||
} catch (ex) {}
|
||||
}
|
||||
|
||||
var cx = React.addons.classSet;
|
||||
if (this.state.editMode) {
|
||||
var availableContext = this.state.availableContext;
|
||||
// The checkbox shows as checked when there's already context data
|
||||
// attached to this room.
|
||||
var checked = !!urlDescription;
|
||||
var checkboxLabel = urlDescription || (availableContext && availableContext.url ?
|
||||
availableContext.description : "");
|
||||
|
||||
return (
|
||||
<div className="room-context editMode">
|
||||
<p className={cx({"error": !!this.props.error,
|
||||
"error-display-area": true})}>
|
||||
{mozL10n.get("rooms_change_failed_label")}
|
||||
</p>
|
||||
<div className="room-context-label">{mozL10n.get("context_inroom_label")}</div>
|
||||
<sharedViews.Checkbox
|
||||
additionalClass={cx({ hide: !checkboxLabel })}
|
||||
checked={checked}
|
||||
disabled={checked}
|
||||
label={checkboxLabel}
|
||||
onChange={this.handleCheckboxChange}
|
||||
value={location} />
|
||||
<form onSubmit={this.handleFormSubmit}>
|
||||
<input className="room-context-name"
|
||||
onKeyDown={this.handleTextareaKeyDown}
|
||||
placeholder={mozL10n.get("context_edit_name_placeholder")}
|
||||
type="text"
|
||||
valueLink={this.linkState("newRoomName")} />
|
||||
<input className="room-context-url"
|
||||
disabled={availableContext && availableContext.url === this.state.newRoomURL}
|
||||
onKeyDown={this.handleTextareaKeyDown}
|
||||
placeholder="https://"
|
||||
type="text"
|
||||
valueLink={this.linkState("newRoomURL")} />
|
||||
<textarea className="room-context-comments"
|
||||
onKeyDown={this.handleTextareaKeyDown}
|
||||
placeholder={mozL10n.get("context_edit_comments_placeholder")}
|
||||
rows="3" type="text"
|
||||
valueLink={this.linkState("newRoomDescription")} />
|
||||
</form>
|
||||
<button className="btn btn-info"
|
||||
disabled={this.props.savingContext}
|
||||
onClick={this.handleFormSubmit}>
|
||||
{mozL10n.get("context_save_label2")}
|
||||
</button>
|
||||
<button className="room-context-btn-close"
|
||||
onClick={this.handleCloseClick}
|
||||
title={mozL10n.get("cancel_button")}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!locationData) {
|
||||
return null;
|
||||
}
|
||||
var availableContext = this.state.availableContext;
|
||||
// The checkbox shows as checked when there's already context data
|
||||
// attached to this room.
|
||||
var checked = !!urlDescription;
|
||||
var checkboxLabel = urlDescription || (availableContext && availableContext.url ?
|
||||
availableContext.description : "");
|
||||
|
||||
return (
|
||||
<div className="room-context">
|
||||
<p className={cx({"error": !!this.props.error,
|
||||
"error-display-area": true})}>
|
||||
{mozL10n.get("rooms_change_failed_label")}
|
||||
</p>
|
||||
<div className="room-context-label">{mozL10n.get("context_inroom_label")}</div>
|
||||
<div className="room-context-content"
|
||||
onClick={this.handleContextClick}>
|
||||
<img className="room-context-thumbnail" src={thumbnail} />
|
||||
<div className="room-context-description"
|
||||
title={urlDescription}>
|
||||
{this._truncate(urlDescription)}
|
||||
<a className="room-context-url"
|
||||
title={locationData.location}>{locationData.hostname}</a>
|
||||
</div>
|
||||
</div>
|
||||
<sharedViews.Checkbox
|
||||
additionalClass={cx({ hide: !checkboxLabel })}
|
||||
checked={checked}
|
||||
disabled={checked}
|
||||
label={checkboxLabel}
|
||||
onChange={this.handleCheckboxChange}
|
||||
value={location} />
|
||||
<form onSubmit={this.handleFormSubmit}>
|
||||
<input className="room-context-name"
|
||||
onKeyDown={this.handleTextareaKeyDown}
|
||||
placeholder={mozL10n.get("context_edit_name_placeholder")}
|
||||
type="text"
|
||||
valueLink={this.linkState("newRoomName")} />
|
||||
<input className="room-context-url"
|
||||
disabled={availableContext && availableContext.url === this.state.newRoomURL}
|
||||
onKeyDown={this.handleTextareaKeyDown}
|
||||
placeholder="https://"
|
||||
type="text"
|
||||
valueLink={this.linkState("newRoomURL")} />
|
||||
<textarea className="room-context-comments"
|
||||
onKeyDown={this.handleTextareaKeyDown}
|
||||
placeholder={mozL10n.get("context_edit_comments_placeholder")}
|
||||
rows="3" type="text"
|
||||
valueLink={this.linkState("newRoomDescription")} />
|
||||
</form>
|
||||
<button className="btn btn-info"
|
||||
disabled={this.props.savingContext}
|
||||
onClick={this.handleFormSubmit}>
|
||||
{mozL10n.get("context_save_label2")}
|
||||
</button>
|
||||
<button className="room-context-btn-close"
|
||||
onClick={this.handleCloseClick}
|
||||
title={mozL10n.get("context_hide_tooltip")}/>
|
||||
<button className="room-context-btn-edit"
|
||||
onClick={this.handleEditClick}
|
||||
title={mozL10n.get("context_edit_tooltip")}/>
|
||||
title={mozL10n.get("cancel_button")}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -599,6 +545,13 @@ loop.roomViews = (function(mozL10n) {
|
|||
roomStore: React.PropTypes.instanceOf(loop.store.RoomStore).isRequired
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
contextEnabled: this.props.mozLoop.getLoopPref("contextInConversations.enabled"),
|
||||
showEditContext: false
|
||||
};
|
||||
},
|
||||
|
||||
componentWillUpdate: function(nextProps, nextState) {
|
||||
// The SDK needs to know about the configuration and the elements to use
|
||||
// for display. So the best way seems to pass the information here - ideally
|
||||
|
@ -642,13 +595,6 @@ loop.roomViews = (function(mozL10n) {
|
|||
return (this.state.roomState !== ROOM_STATES.HAS_PARTICIPANTS);
|
||||
},
|
||||
|
||||
_shouldRenderContextView: function() {
|
||||
return !!(
|
||||
this.props.mozLoop.getLoopPref("contextInConversations.enabled") &&
|
||||
(this.state.roomContextUrls || this.state.roomDescription)
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Works out if remote video should be rended or not, depending on the
|
||||
* room state and other flags.
|
||||
|
@ -718,6 +664,14 @@ loop.roomViews = (function(mozL10n) {
|
|||
!this.state.mediaConnected;
|
||||
},
|
||||
|
||||
handleAddContextClick: function() {
|
||||
this.setState({ showEditContext: true });
|
||||
},
|
||||
|
||||
handleEditContextClose: function() {
|
||||
this.setState({ showEditContext: false });
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (this.state.roomName) {
|
||||
this.setTitle(this.state.roomName);
|
||||
|
@ -736,7 +690,7 @@ loop.roomViews = (function(mozL10n) {
|
|||
};
|
||||
|
||||
var shouldRenderInvitationOverlay = this._shouldRenderInvitationOverlay();
|
||||
var shouldRenderContextView = this._shouldRenderContextView();
|
||||
var shouldRenderEditContextView = this.state.contextEnabled && this.state.showEditContext;
|
||||
var roomData = this.props.roomStore.getStoreState("activeRoom");
|
||||
|
||||
switch(this.state.roomState) {
|
||||
|
@ -760,18 +714,20 @@ loop.roomViews = (function(mozL10n) {
|
|||
|
||||
return (
|
||||
<div className="room-conversation-wrapper">
|
||||
<DesktopRoomInvitationView
|
||||
dispatcher={this.props.dispatcher}
|
||||
error={this.state.error}
|
||||
mozLoop={this.props.mozLoop}
|
||||
roomData={roomData}
|
||||
savingContext={this.state.savingContext}
|
||||
show={shouldRenderInvitationOverlay}
|
||||
showContext={shouldRenderContextView}
|
||||
socialShareProviders={this.state.socialShareProviders} />
|
||||
<div className="video-layout-wrapper">
|
||||
<div className="conversation room-conversation">
|
||||
<div className="media nested">
|
||||
<DesktopRoomInvitationView
|
||||
dispatcher={this.props.dispatcher}
|
||||
error={this.state.error}
|
||||
mozLoop={this.props.mozLoop}
|
||||
onAddContextClick={this.handleAddContextClick}
|
||||
onEditContextClose={this.handleEditContextClose}
|
||||
roomData={roomData}
|
||||
savingContext={this.state.savingContext}
|
||||
show={shouldRenderInvitationOverlay}
|
||||
showEditContext={shouldRenderInvitationOverlay && shouldRenderEditContextView}
|
||||
socialShareProviders={this.state.socialShareProviders} />
|
||||
<div className="video_wrapper remote_wrapper">
|
||||
<div className="video_inner remote focus-stream">
|
||||
<sharedViews.MediaView displayAvatar={!this.shouldRenderRemoteVideo()}
|
||||
|
@ -798,13 +754,14 @@ loop.roomViews = (function(mozL10n) {
|
|||
video={{enabled: !this.state.videoMuted, visible: true}} />
|
||||
</div>
|
||||
</div>
|
||||
<DesktopRoomContextView
|
||||
<DesktopRoomEditContextView
|
||||
dispatcher={this.props.dispatcher}
|
||||
error={this.state.error}
|
||||
mozLoop={this.props.mozLoop}
|
||||
onClose={this.handleEditContextClose}
|
||||
roomData={roomData}
|
||||
savingContext={this.state.savingContext}
|
||||
show={!shouldRenderInvitationOverlay && shouldRenderContextView} />
|
||||
show={!shouldRenderInvitationOverlay && shouldRenderEditContextView} />
|
||||
<sharedViews.chat.TextChatView
|
||||
dispatcher={this.props.dispatcher}
|
||||
showAlways={false}
|
||||
|
@ -820,7 +777,7 @@ loop.roomViews = (function(mozL10n) {
|
|||
return {
|
||||
ActiveRoomStoreMixin: ActiveRoomStoreMixin,
|
||||
SocialShareDropdown: SocialShareDropdown,
|
||||
DesktopRoomContextView: DesktopRoomContextView,
|
||||
DesktopRoomEditContextView: DesktopRoomEditContextView,
|
||||
DesktopRoomConversationView: DesktopRoomConversationView,
|
||||
DesktopRoomInvitationView: DesktopRoomInvitationView
|
||||
};
|
||||
|
|
|
@ -930,7 +930,7 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item {
|
|||
}
|
||||
|
||||
.room-context {
|
||||
background: rgba(0,0,0,.6);
|
||||
background: rgba(0,0,0,.8);
|
||||
border-top: 2px solid #444;
|
||||
border-bottom: 2px solid #444;
|
||||
padding: .5rem;
|
||||
|
@ -939,6 +939,9 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item {
|
|||
left: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
/* Stretch to the maximum available space whilst not covering the conversation
|
||||
toolbar (26px). */
|
||||
height: calc(100% - 26px);
|
||||
font-size: .9em;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
|
@ -950,42 +953,14 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item {
|
|||
z-index: 2;
|
||||
}
|
||||
|
||||
.room-context.editMode {
|
||||
/* Stretch to the maximum available space whilst not covering the conversation
|
||||
toolbar (26px). */
|
||||
height: calc(100% - 26px);
|
||||
}
|
||||
|
||||
.room-invitation-overlay .room-context {
|
||||
position: relative;
|
||||
left: auto;
|
||||
bottom: auto;
|
||||
flex: 0 1 auto;
|
||||
}
|
||||
|
||||
.room-invitation-overlay .room-context.editMode {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.room-context-content {
|
||||
flex: 1 1 auto;
|
||||
text-align: start;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
font-size: .9em;
|
||||
}
|
||||
|
||||
.room-context-thumbnail {
|
||||
/* 16px icon size + 3px border width. */
|
||||
width: 19px;
|
||||
max-height: 19px;
|
||||
border: 3px solid #fff;
|
||||
border-radius: 3px;
|
||||
background-color: #fff;
|
||||
-moz-margin-end: 1ch;
|
||||
flex: 0 1 auto;
|
||||
}
|
||||
|
||||
.room-context > .error-display-area.error {
|
||||
display: block;
|
||||
background-color: rgba(215,67,69,.8);
|
||||
|
@ -1011,7 +986,6 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item {
|
|||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.room-context-description,
|
||||
.room-context > .checkbox-wrapper > label {
|
||||
color: #fff;
|
||||
}
|
||||
|
@ -1020,7 +994,6 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item {
|
|||
color: #707070;
|
||||
}
|
||||
|
||||
.room-context-description,
|
||||
.room-context-comment {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
@ -1079,8 +1052,7 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item {
|
|||
align-self: flex-end;
|
||||
}
|
||||
|
||||
.room-context-btn-close,
|
||||
.room-context-btn-edit {
|
||||
.room-context-btn-close {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
/* 8px offset + 2px border-top */
|
||||
|
@ -1096,31 +1068,16 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item {
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.room-context-btn-edit {
|
||||
right: 20px;
|
||||
background-image: url("../img/icons-10x10.svg#edit-darkergrey");
|
||||
}
|
||||
|
||||
.room-context-btn-edit:hover,
|
||||
.room-context-btn-edit:hover:active {
|
||||
background-image: url("../img/icons-10x10.svg#edit-active");
|
||||
}
|
||||
|
||||
.room-context-btn-close:hover,
|
||||
.room-context-btn-close:hover:active {
|
||||
background-image: url("../img/icons-10x10.svg#close-active");
|
||||
}
|
||||
|
||||
html[dir="rtl"] .room-context-btn-close,
|
||||
html[dir="rtl"] .room-context-btn-edit {
|
||||
html[dir="rtl"] .room-context-btn-close {
|
||||
right: auto;
|
||||
left: 8px;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .room-context-btn-edit {
|
||||
left: 20px;
|
||||
}
|
||||
|
||||
.media-layout {
|
||||
/* 50px is the header, 3em is the footer. */
|
||||
height: calc(100% - 50px - 3em);
|
||||
|
|
Загрузка…
Ссылка в новой задаче