Merge pull request #2883 from YaoiFangirl420/cleanup_message_composer
Cleanup message composer render() methodpull/21833/head
commit
9917bed942
|
@ -42,14 +42,159 @@ const formatButtonList = [
|
||||||
_td("numbered-list"),
|
_td("numbered-list"),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
function ComposerAvatar(props) {
|
||||||
|
const MemberStatusMessageAvatar = sdk.getComponent('avatars.MemberStatusMessageAvatar');
|
||||||
|
return <div className="mx_MessageComposer_avatar">
|
||||||
|
<MemberStatusMessageAvatar member={props.me} width={24} height={24} />
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
ComposerAvatar.propTypes = {
|
||||||
|
me: PropTypes.object.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
function CallButton(props) {
|
||||||
|
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||||
|
const onVoiceCallClick = (ev) => {
|
||||||
|
dis.dispatch({
|
||||||
|
action: 'place_call',
|
||||||
|
type: "voice",
|
||||||
|
room_id: props.roomId,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return <AccessibleButton className="mx_MessageComposer_button mx_MessageComposer_voicecall"
|
||||||
|
onClick={onVoiceCallClick}
|
||||||
|
title={_t('Voice call')}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
|
||||||
|
CallButton.propTypes = {
|
||||||
|
roomId: PropTypes.string.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
function VideoCallButton(props) {
|
||||||
|
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||||
|
const onCallClick = (ev) => {
|
||||||
|
dis.dispatch({
|
||||||
|
action: 'place_call',
|
||||||
|
type: ev.shiftKey ? "screensharing" : "video",
|
||||||
|
room_id: props.roomId,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return <AccessibleButton className="mx_MessageComposer_button mx_MessageComposer_videocall"
|
||||||
|
onClick={onCallClick}
|
||||||
|
title={_t('Video call')}
|
||||||
|
/>;
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoCallButton.propTypes = {
|
||||||
|
roomId: PropTypes.string.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
function HangupButton(props) {
|
||||||
|
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||||
|
const onHangupClick = () => {
|
||||||
|
const call = CallHandler.getCallForRoom(props.roomId);
|
||||||
|
if (!call) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dis.dispatch({
|
||||||
|
action: 'hangup',
|
||||||
|
// hangup the call for this room, which may not be the room in props
|
||||||
|
// (e.g. conferences which will hangup the 1:1 room instead)
|
||||||
|
room_id: call.roomId,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
return <AccessibleButton className="mx_MessageComposer_button mx_MessageComposer_hangup"
|
||||||
|
onClick={onHangupClick}
|
||||||
|
title={_t('Hangup')}
|
||||||
|
/>;
|
||||||
|
}
|
||||||
|
|
||||||
|
HangupButton.propTypes = {
|
||||||
|
roomId: PropTypes.string.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
function FormattingButton(props) {
|
||||||
|
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||||
|
return <AccessibleButton
|
||||||
|
element="img"
|
||||||
|
className="mx_MessageComposer_formatting"
|
||||||
|
alt={_t("Show Text Formatting Toolbar")}
|
||||||
|
title={_t("Show Text Formatting Toolbar")}
|
||||||
|
src={require("../../../../res/img/button-text-formatting.svg")}
|
||||||
|
style={{visibility: props.showFormatting ? 'hidden' : 'visible'}}
|
||||||
|
onClick={props.onClickHandler}
|
||||||
|
/>;
|
||||||
|
}
|
||||||
|
|
||||||
|
FormattingButton.propTypes = {
|
||||||
|
showFormatting: PropTypes.bool.isRequired,
|
||||||
|
onClickHandler: PropTypes.func.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
class UploadButton extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
roomId: PropTypes.string.isRequired,
|
||||||
|
}
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
this.onUploadClick = this.onUploadClick.bind(this);
|
||||||
|
this.onUploadFileInputChange = this.onUploadFileInputChange.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
onUploadClick(ev) {
|
||||||
|
if (MatrixClientPeg.get().isGuest()) {
|
||||||
|
dis.dispatch({action: 'require_registration'});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.refs.uploadInput.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
onUploadFileInputChange(ev) {
|
||||||
|
if (ev.target.files.length === 0) return;
|
||||||
|
|
||||||
|
// take a copy so we can safely reset the value of the form control
|
||||||
|
// (Note it is a FileList: we can't use slice or sesnible iteration).
|
||||||
|
const tfiles = [];
|
||||||
|
for (let i = 0; i < ev.target.files.length; ++i) {
|
||||||
|
tfiles.push(ev.target.files[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentMessages.sharedInstance().sendContentListToRoom(
|
||||||
|
tfiles, this.props.roomId, MatrixClientPeg.get(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// This is the onChange handler for a file form control, but we're
|
||||||
|
// not keeping any state, so reset the value of the form control
|
||||||
|
// to empty.
|
||||||
|
// NB. we need to set 'value': the 'files' property is immutable.
|
||||||
|
ev.target.value = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const uploadInputStyle = {display: 'none'};
|
||||||
|
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||||
|
return (
|
||||||
|
<AccessibleButton className="mx_MessageComposer_button mx_MessageComposer_upload"
|
||||||
|
onClick={this.onUploadClick}
|
||||||
|
title={_t('Upload file')}
|
||||||
|
>
|
||||||
|
<input ref="uploadInput" type="file"
|
||||||
|
style={uploadInputStyle}
|
||||||
|
multiple
|
||||||
|
onChange={this.onUploadFileInputChange}
|
||||||
|
/>
|
||||||
|
</AccessibleButton>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default class MessageComposer extends React.Component {
|
export default class MessageComposer extends React.Component {
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
this.onCallClick = this.onCallClick.bind(this);
|
|
||||||
this.onHangupClick = this.onHangupClick.bind(this);
|
|
||||||
this.onUploadClick = this.onUploadClick.bind(this);
|
|
||||||
this._onUploadFileInputChange = this._onUploadFileInputChange.bind(this);
|
|
||||||
this.onVoiceCallClick = this.onVoiceCallClick.bind(this);
|
|
||||||
this._onAutocompleteConfirm = this._onAutocompleteConfirm.bind(this);
|
this._onAutocompleteConfirm = this._onAutocompleteConfirm.bind(this);
|
||||||
this.onToggleFormattingClicked = this.onToggleFormattingClicked.bind(this);
|
this.onToggleFormattingClicked = this.onToggleFormattingClicked.bind(this);
|
||||||
this.onToggleMarkdownClicked = this.onToggleMarkdownClicked.bind(this);
|
this.onToggleMarkdownClicked = this.onToggleMarkdownClicked.bind(this);
|
||||||
|
@ -58,6 +203,8 @@ export default class MessageComposer extends React.Component {
|
||||||
this._onRoomStateEvents = this._onRoomStateEvents.bind(this);
|
this._onRoomStateEvents = this._onRoomStateEvents.bind(this);
|
||||||
this._onRoomViewStoreUpdate = this._onRoomViewStoreUpdate.bind(this);
|
this._onRoomViewStoreUpdate = this._onRoomViewStoreUpdate.bind(this);
|
||||||
this._onTombstoneClick = this._onTombstoneClick.bind(this);
|
this._onTombstoneClick = this._onTombstoneClick.bind(this);
|
||||||
|
this.renderPlaceholderText = this.renderPlaceholderText.bind(this);
|
||||||
|
this.renderFormatBar = this.renderFormatBar.bind(this);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
inputState: {
|
inputState: {
|
||||||
|
@ -136,65 +283,6 @@ export default class MessageComposer extends React.Component {
|
||||||
this.setState({ isQuoting });
|
this.setState({ isQuoting });
|
||||||
}
|
}
|
||||||
|
|
||||||
onUploadClick(ev) {
|
|
||||||
if (MatrixClientPeg.get().isGuest()) {
|
|
||||||
dis.dispatch({action: 'require_registration'});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.refs.uploadInput.click();
|
|
||||||
}
|
|
||||||
|
|
||||||
_onUploadFileInputChange(ev) {
|
|
||||||
if (ev.target.files.length === 0) return;
|
|
||||||
|
|
||||||
// take a copy so we can safely reset the value of the form control
|
|
||||||
// (Note it is a FileList: we can't use slice or sesnible iteration).
|
|
||||||
const tfiles = [];
|
|
||||||
for (let i = 0; i < ev.target.files.length; ++i) {
|
|
||||||
tfiles.push(ev.target.files[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
ContentMessages.sharedInstance().sendContentListToRoom(
|
|
||||||
tfiles, this.props.room.roomId, MatrixClientPeg.get(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// This is the onChange handler for a file form control, but we're
|
|
||||||
// not keeping any state, so reset the value of the form control
|
|
||||||
// to empty.
|
|
||||||
// NB. we need to set 'value': the 'files' property is immutable.
|
|
||||||
ev.target.value = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
onHangupClick() {
|
|
||||||
const call = CallHandler.getCallForRoom(this.props.room.roomId);
|
|
||||||
//var call = CallHandler.getAnyActiveCall();
|
|
||||||
if (!call) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
dis.dispatch({
|
|
||||||
action: 'hangup',
|
|
||||||
// hangup the call for this room, which may not be the room in props
|
|
||||||
// (e.g. conferences which will hangup the 1:1 room instead)
|
|
||||||
room_id: call.roomId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onCallClick(ev) {
|
|
||||||
dis.dispatch({
|
|
||||||
action: 'place_call',
|
|
||||||
type: ev.shiftKey ? "screensharing" : "video",
|
|
||||||
room_id: this.props.room.roomId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onVoiceCallClick(ev) {
|
|
||||||
dis.dispatch({
|
|
||||||
action: 'place_call',
|
|
||||||
type: "voice",
|
|
||||||
room_id: this.props.room.roomId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onInputStateChanged(inputState) {
|
onInputStateChanged(inputState) {
|
||||||
// Merge the new input state with old to support partial updates
|
// Merge the new input state with old to support partial updates
|
||||||
|
@ -245,119 +333,94 @@ export default class MessageComposer extends React.Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
renderPlaceholderText() {
|
||||||
const uploadInputStyle = {display: 'none'};
|
const roomIsEncrypted = MatrixClientPeg.get().isRoomEncrypted(this.props.room.roomId);
|
||||||
const MemberStatusMessageAvatar = sdk.getComponent('avatars.MemberStatusMessageAvatar');
|
if (this.state.isQuoting) {
|
||||||
const MessageComposerInput = sdk.getComponent("rooms.MessageComposerInput");
|
if (roomIsEncrypted) {
|
||||||
|
return _t('Send an encrypted reply…');
|
||||||
const controls = [];
|
} else {
|
||||||
|
return _t('Send a reply (unencrypted)…');
|
||||||
if (this.state.me) {
|
}
|
||||||
controls.push(
|
|
||||||
<div key="controls_avatar" className="mx_MessageComposer_avatar">
|
|
||||||
<MemberStatusMessageAvatar member={this.state.me} width={24} height={24} />
|
|
||||||
</div>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.props.e2eStatus) {
|
|
||||||
controls.push(<E2EIcon
|
|
||||||
status={this.props.e2eStatus}
|
|
||||||
key="e2eIcon"
|
|
||||||
className="mx_MessageComposer_e2eIcon" />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let callButton;
|
|
||||||
let videoCallButton;
|
|
||||||
let hangupButton;
|
|
||||||
|
|
||||||
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
|
||||||
// Call buttons
|
|
||||||
if (this.props.callState && this.props.callState !== 'ended') {
|
|
||||||
hangupButton =
|
|
||||||
<AccessibleButton className="mx_MessageComposer_button mx_MessageComposer_hangup"
|
|
||||||
key="controls_hangup"
|
|
||||||
onClick={this.onHangupClick}
|
|
||||||
title={_t('Hangup')}
|
|
||||||
>
|
|
||||||
</AccessibleButton>;
|
|
||||||
} else {
|
} else {
|
||||||
callButton =
|
if (roomIsEncrypted) {
|
||||||
<AccessibleButton className="mx_MessageComposer_button mx_MessageComposer_voicecall"
|
return _t('Send an encrypted message…');
|
||||||
key="controls_call"
|
} else {
|
||||||
onClick={this.onVoiceCallClick}
|
return _t('Send a message (unencrypted)…');
|
||||||
title={_t('Voice call')}
|
}
|
||||||
>
|
|
||||||
</AccessibleButton>;
|
|
||||||
videoCallButton =
|
|
||||||
<AccessibleButton className="mx_MessageComposer_button mx_MessageComposer_videocall"
|
|
||||||
key="controls_videocall"
|
|
||||||
onClick={this.onCallClick}
|
|
||||||
title={_t('Video call')}
|
|
||||||
>
|
|
||||||
</AccessibleButton>;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderFormatBar() {
|
||||||
|
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||||
|
const {marks, blockType} = this.state.inputState;
|
||||||
|
const formatButtons = formatButtonList.map((name) => {
|
||||||
|
// special-case to match the md serializer and the special-case in MessageComposerInput.js
|
||||||
|
const markName = name === 'inline-code' ? 'code' : name;
|
||||||
|
const active = marks.some(mark => mark.type === markName) || blockType === name;
|
||||||
|
const suffix = active ? '-on' : '';
|
||||||
|
const onFormatButtonClicked = this.onFormatButtonClicked.bind(this, name);
|
||||||
|
const className = 'mx_MessageComposer_format_button mx_filterFlipColor';
|
||||||
|
return (
|
||||||
|
<img className={className}
|
||||||
|
title={_t(name)}
|
||||||
|
onMouseDown={onFormatButtonClicked}
|
||||||
|
key={name}
|
||||||
|
src={require(`../../../../res/img/button-text-${name}${suffix}.svg`)}
|
||||||
|
height="17"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mx_MessageComposer_formatbar_wrapper">
|
||||||
|
<div className="mx_MessageComposer_formatbar">
|
||||||
|
{ formatButtons }
|
||||||
|
<div style={{ flex: 1 }}></div>
|
||||||
|
<AccessibleButton
|
||||||
|
className="mx_MessageComposer_formatbar_markdown mx_MessageComposer_markdownDisabled"
|
||||||
|
onClick={this.onToggleMarkdownClicked}
|
||||||
|
title={_t("Markdown is disabled")}
|
||||||
|
/>
|
||||||
|
<AccessibleButton element="img" title={_t("Hide Text Formatting Toolbar")}
|
||||||
|
onClick={this.onToggleFormattingClicked}
|
||||||
|
className="mx_MessageComposer_formatbar_cancel mx_filterFlipColor"
|
||||||
|
src={require("../../../../res/img/icon-text-cancel.svg")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const controls = [
|
||||||
|
this.state.me ? <ComposerAvatar key="controls_avatar" me={this.state.me} /> : null,
|
||||||
|
this.props.e2eStatus ? <E2EIcon key="e2eIcon" status={this.props.e2eStatus} className="mx_MessageComposer_e2eIcon" /> : null,
|
||||||
|
];
|
||||||
|
|
||||||
if (!this.state.tombstone && this.state.canSendMessages) {
|
if (!this.state.tombstone && this.state.canSendMessages) {
|
||||||
// This also currently includes the call buttons. Really we should
|
// This also currently includes the call buttons. Really we should
|
||||||
// check separately for whether we can call, but this is slightly
|
// check separately for whether we can call, but this is slightly
|
||||||
// complex because of conference calls.
|
// complex because of conference calls.
|
||||||
const uploadButton = (
|
|
||||||
<AccessibleButton className="mx_MessageComposer_button mx_MessageComposer_upload"
|
|
||||||
key="controls_upload"
|
|
||||||
onClick={this.onUploadClick}
|
|
||||||
title={_t('Upload file')}
|
|
||||||
>
|
|
||||||
<input ref="uploadInput" type="file"
|
|
||||||
style={uploadInputStyle}
|
|
||||||
multiple
|
|
||||||
onChange={this._onUploadFileInputChange} />
|
|
||||||
</AccessibleButton>
|
|
||||||
);
|
|
||||||
|
|
||||||
const formattingButton = this.state.inputState.isRichTextEnabled ? (
|
const MessageComposerInput = sdk.getComponent("rooms.MessageComposerInput");
|
||||||
<AccessibleButton element="img" className="mx_MessageComposer_formatting"
|
const showFormattingButton = this.state.inputState.isRichTextEnabled;
|
||||||
alt={_t("Show Text Formatting Toolbar")}
|
const callInProgress = this.props.callState && this.props.callState !== 'ended';
|
||||||
title={_t("Show Text Formatting Toolbar")}
|
|
||||||
src={require("../../../../res/img/button-text-formatting.svg")}
|
|
||||||
onClick={this.onToggleFormattingClicked}
|
|
||||||
style={{visibility: this.state.showFormatting ? 'hidden' : 'visible'}}
|
|
||||||
key="controls_formatting" />
|
|
||||||
) : null;
|
|
||||||
|
|
||||||
const roomIsEncrypted = MatrixClientPeg.get().isRoomEncrypted(this.props.room.roomId);
|
|
||||||
let placeholderText;
|
|
||||||
if (this.state.isQuoting) {
|
|
||||||
if (roomIsEncrypted) {
|
|
||||||
placeholderText = _t('Send an encrypted reply…');
|
|
||||||
} else {
|
|
||||||
placeholderText = _t('Send a reply (unencrypted)…');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (roomIsEncrypted) {
|
|
||||||
placeholderText = _t('Send an encrypted message…');
|
|
||||||
} else {
|
|
||||||
placeholderText = _t('Send a message (unencrypted)…');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const stickerpickerButton = <Stickerpicker key='stickerpicker_controls_button' room={this.props.room} />;
|
|
||||||
|
|
||||||
controls.push(
|
controls.push(
|
||||||
<MessageComposerInput
|
<MessageComposerInput
|
||||||
ref={(c) => this.messageComposerInput = c}
|
ref={(c) => this.messageComposerInput = c}
|
||||||
key="controls_input"
|
key="controls_input"
|
||||||
room={this.props.room}
|
room={this.props.room}
|
||||||
placeholder={placeholderText}
|
placeholder={this.renderPlaceholderText()}
|
||||||
onInputStateChanged={this.onInputStateChanged}
|
onInputStateChanged={this.onInputStateChanged}
|
||||||
permalinkCreator={this.props.permalinkCreator} />,
|
permalinkCreator={this.props.permalinkCreator} />,
|
||||||
formattingButton,
|
showFormattingButton ? <FormattingButton key="controls_formatting"
|
||||||
stickerpickerButton,
|
showFormatting={this.state.showFormatting} onClickHandler={this.onToggleFormattingClicked} /> : null,
|
||||||
uploadButton,
|
<Stickerpicker key='stickerpicker_controls_button' room={this.props.room} />,
|
||||||
hangupButton,
|
<UploadButton key="controls_upload" roomId={this.props.room.roomId} />,
|
||||||
callButton,
|
callInProgress ? <HangupButton key="controls_hangup" roomId={this.props.room.roomId} /> : null,
|
||||||
videoCallButton,
|
callInProgress ? null : <CallButton key="controls_call" roomId={this.props.room.roomId} />,
|
||||||
|
callInProgress ? null : <VideoCallButton key="controls_videocall" roomId={this.props.room.roomId} />,
|
||||||
);
|
);
|
||||||
} else if (this.state.tombstone) {
|
} else if (this.state.tombstone) {
|
||||||
const replacementRoomId = this.state.tombstone.getContent()['replacement_room'];
|
const replacementRoomId = this.state.tombstone.getContent()['replacement_room'];
|
||||||
|
@ -388,42 +451,7 @@ export default class MessageComposer extends React.Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let formatBar;
|
const showFormatBar = this.state.showFormatting && this.state.inputState.isRichTextEnabled;
|
||||||
if (this.state.showFormatting && this.state.inputState.isRichTextEnabled) {
|
|
||||||
const {marks, blockType} = this.state.inputState;
|
|
||||||
const formatButtons = formatButtonList.map((name) => {
|
|
||||||
// special-case to match the md serializer and the special-case in MessageComposerInput.js
|
|
||||||
const markName = name === 'inline-code' ? 'code' : name;
|
|
||||||
const active = marks.some(mark => mark.type === markName) || blockType === name;
|
|
||||||
const suffix = active ? '-on' : '';
|
|
||||||
const onFormatButtonClicked = this.onFormatButtonClicked.bind(this, name);
|
|
||||||
const className = 'mx_MessageComposer_format_button mx_filterFlipColor';
|
|
||||||
return <img className={className}
|
|
||||||
title={_t(name)}
|
|
||||||
onMouseDown={onFormatButtonClicked}
|
|
||||||
key={name}
|
|
||||||
src={require(`../../../../res/img/button-text-${name}${suffix}.svg`)}
|
|
||||||
height="17" />;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
formatBar =
|
|
||||||
<div className="mx_MessageComposer_formatbar_wrapper">
|
|
||||||
<div className="mx_MessageComposer_formatbar">
|
|
||||||
{ formatButtons }
|
|
||||||
<div style={{ flex: 1 }}></div>
|
|
||||||
<AccessibleButton className="mx_MessageComposer_formatbar_markdown mx_MessageComposer_markdownDisabled"
|
|
||||||
onClick={this.onToggleMarkdownClicked}
|
|
||||||
title={_t("Markdown is disabled")}
|
|
||||||
/>
|
|
||||||
<AccessibleButton element="img" title={_t("Hide Text Formatting Toolbar")}
|
|
||||||
onClick={this.onToggleFormattingClicked}
|
|
||||||
className="mx_MessageComposer_formatbar_cancel mx_filterFlipColor"
|
|
||||||
src={require("../../../../res/img/icon-text-cancel.svg")}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const wrapperClasses = classNames({
|
const wrapperClasses = classNames({
|
||||||
mx_MessageComposer_wrapper: true,
|
mx_MessageComposer_wrapper: true,
|
||||||
|
@ -436,7 +464,7 @@ export default class MessageComposer extends React.Component {
|
||||||
{ controls }
|
{ controls }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{ formatBar }
|
{ showFormatBar ? this.renderFormatBar() : null }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue