unify buttons on the node type names, and make them work
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
@ -215,7 +215,7 @@ export default class MessageComposer extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onFormatButtonClicked(name: "bold" | "italic" | "strike" | "code" | "underline" | "quote" | "bullet" | "numbullet", event) {
|
onFormatButtonClicked(name, event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.messageComposerInput.onFormatButtonClicked(name, event);
|
this.messageComposerInput.onFormatButtonClicked(name, event);
|
||||||
}
|
}
|
||||||
@ -303,14 +303,14 @@ export default class MessageComposer extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
const formattingButton = (
|
const formattingButton = this.state.inputState.isRichTextEnabled ? (
|
||||||
<img className="mx_MessageComposer_formatting"
|
<img className="mx_MessageComposer_formatting"
|
||||||
title={_t("Show Text Formatting Toolbar")}
|
title={_t("Show Text Formatting Toolbar")}
|
||||||
src="img/button-text-formatting.svg"
|
src="img/button-text-formatting.svg"
|
||||||
onClick={this.onToggleFormattingClicked}
|
onClick={this.onToggleFormattingClicked}
|
||||||
style={{visibility: this.state.showFormatting ? 'hidden' : 'visible'}}
|
style={{visibility: this.state.showFormatting ? 'hidden' : 'visible'}}
|
||||||
key="controls_formatting" />
|
key="controls_formatting" />
|
||||||
);
|
) : null;
|
||||||
|
|
||||||
let placeholderText;
|
let placeholderText;
|
||||||
if (this.state.isQuoting) {
|
if (this.state.isQuoting) {
|
||||||
@ -353,31 +353,27 @@ export default class MessageComposer extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const {marks, blockType} = this.state.inputState;
|
let formatBar;
|
||||||
const formatButtons = ["bold", "italic", "strike", "underline", "code", "quote", "bullet", "numbullet"].map(
|
if (this.state.showFormatting) {
|
||||||
(name) => {
|
const {marks, blockType} = this.state.inputState;
|
||||||
const active = marks.includes(name) || blockType === name;
|
const formatButtons = ["bold", "italic", "deleted", "underlined", "code", "block-quote", "bulleted-list", "numbered-list"].map(
|
||||||
const suffix = active ? '-o-n' : '';
|
(name) => {
|
||||||
const onFormatButtonClicked = this.onFormatButtonClicked.bind(this, name);
|
const active = marks.some(mark => mark.type === name) || blockType === name;
|
||||||
const className = 'mx_MessageComposer_format_button mx_filterFlipColor';
|
const suffix = active ? '-on' : '';
|
||||||
return <img className={className}
|
const onFormatButtonClicked = this.onFormatButtonClicked.bind(this, name);
|
||||||
title={_t(name)}
|
const className = 'mx_MessageComposer_format_button mx_filterFlipColor';
|
||||||
onMouseDown={onFormatButtonClicked}
|
return <img className={className}
|
||||||
key={name}
|
title={_t(name)}
|
||||||
src={`img/button-text-${name}${suffix}.svg`}
|
onMouseDown={onFormatButtonClicked}
|
||||||
height="17" />;
|
key={name}
|
||||||
},
|
src={`img/button-text-${name}${suffix}.svg`}
|
||||||
);
|
height="17" />;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
formatBar =
|
||||||
<div className="mx_MessageComposer">
|
|
||||||
<div className="mx_MessageComposer_wrapper">
|
|
||||||
<div className="mx_MessageComposer_row">
|
|
||||||
{ controls }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="mx_MessageComposer_formatbar_wrapper">
|
<div className="mx_MessageComposer_formatbar_wrapper">
|
||||||
<div className="mx_MessageComposer_formatbar" style={this.state.showFormatting ? {} : {display: 'none'}}>
|
<div className="mx_MessageComposer_formatbar">
|
||||||
{ formatButtons }
|
{ formatButtons }
|
||||||
<div style={{flex: 1}}></div>
|
<div style={{flex: 1}}></div>
|
||||||
<img title={this.state.inputState.isRichTextEnabled ? _t("Turn Markdown on") : _t("Turn Markdown off")}
|
<img title={this.state.inputState.isRichTextEnabled ? _t("Turn Markdown on") : _t("Turn Markdown off")}
|
||||||
@ -390,6 +386,16 @@ export default class MessageComposer extends React.Component {
|
|||||||
src="img/icon-text-cancel.svg" />
|
src="img/icon-text-cancel.svg" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mx_MessageComposer">
|
||||||
|
<div className="mx_MessageComposer_wrapper">
|
||||||
|
<div className="mx_MessageComposer_row">
|
||||||
|
{ controls }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{ formatBar }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -132,9 +132,6 @@ export default class MessageComposerInput extends React.Component {
|
|||||||
// js-sdk Room object
|
// js-sdk Room object
|
||||||
room: PropTypes.object.isRequired,
|
room: PropTypes.object.isRequired,
|
||||||
|
|
||||||
// called with current plaintext content (as a string) whenever it changes
|
|
||||||
onContentChanged: PropTypes.func,
|
|
||||||
|
|
||||||
onFilesPasted: PropTypes.func,
|
onFilesPasted: PropTypes.func,
|
||||||
|
|
||||||
onInputStateChanged: PropTypes.func,
|
onInputStateChanged: PropTypes.func,
|
||||||
@ -319,15 +316,6 @@ export default class MessageComposerInput extends React.Component {
|
|||||||
dis.unregister(this.dispatcherRef);
|
dis.unregister(this.dispatcherRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUpdate(nextProps, nextState) {
|
|
||||||
// this is dirty, but moving all this state to MessageComposer is dirtier
|
|
||||||
if (this.props.onInputStateChanged && nextState !== this.state) {
|
|
||||||
const state = this.getSelectionInfo(nextState.editorState);
|
|
||||||
state.isRichTextEnabled = nextState.isRichTextEnabled;
|
|
||||||
this.props.onInputStateChanged(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onAction = (payload) => {
|
onAction = (payload) => {
|
||||||
const editor = this.refs.editor;
|
const editor = this.refs.editor;
|
||||||
let editorState = this.state.editorState;
|
let editorState = this.state.editorState;
|
||||||
@ -567,6 +555,27 @@ export default class MessageComposerInput extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.props.onInputStateChanged) {
|
||||||
|
let blockType = editorState.blocks.first().type;
|
||||||
|
console.log("onInputStateChanged; current block type is " + blockType + " and marks are " + editorState.activeMarks);
|
||||||
|
|
||||||
|
if (blockType === 'list-item') {
|
||||||
|
const parent = editorState.document.getParent(editorState.blocks.first().key);
|
||||||
|
if (parent.type === 'numbered-list') {
|
||||||
|
blockType = 'numbered-list';
|
||||||
|
}
|
||||||
|
else if (parent.type === 'bulleted-list') {
|
||||||
|
blockType = 'bulleted-list';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const inputState = {
|
||||||
|
marks: editorState.activeMarks,
|
||||||
|
isRichTextEnabled: this.state.isRichTextEnabled,
|
||||||
|
blockType
|
||||||
|
};
|
||||||
|
this.props.onInputStateChanged(inputState);
|
||||||
|
}
|
||||||
|
|
||||||
// Record the editor state for this room so that it can be retrieved after
|
// Record the editor state for this room so that it can be retrieved after
|
||||||
// switching to another room and back
|
// switching to another room and back
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
@ -1239,17 +1248,6 @@ export default class MessageComposerInput extends React.Component {
|
|||||||
await this.setDisplayedCompletion(null); // restore originalEditorState
|
await this.setDisplayedCompletion(null); // restore originalEditorState
|
||||||
};
|
};
|
||||||
|
|
||||||
/* returns inline style and block type of current SelectionState so MessageComposer can render formatting
|
|
||||||
buttons. */
|
|
||||||
getSelectionInfo(editorState: Value) {
|
|
||||||
return {
|
|
||||||
marks: editorState.activeMarks,
|
|
||||||
// XXX: shouldn't we return all the types of blocks in the current selection,
|
|
||||||
// not just the anchor?
|
|
||||||
blockType: editorState.anchorBlock ? editorState.anchorBlock.type : null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If passed null, restores the original editor content from state.originalEditorState.
|
/* If passed null, restores the original editor content from state.originalEditorState.
|
||||||
* If passed a non-null displayedCompletion, modifies state.originalEditorState to compute new state.editorState.
|
* If passed a non-null displayedCompletion, modifies state.originalEditorState to compute new state.editorState.
|
||||||
*/
|
*/
|
||||||
@ -1406,18 +1404,22 @@ export default class MessageComposerInput extends React.Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onFormatButtonClicked = (name: "bold" | "italic" | "strike" | "code" | "underline" | "quote" | "bullet" | "numbullet", e) => {
|
onFormatButtonClicked = (name, e) => {
|
||||||
e.preventDefault(); // don't steal focus from the editor!
|
if (e) {
|
||||||
|
e.preventDefault(); // don't steal focus from the editor!
|
||||||
|
}
|
||||||
|
|
||||||
const command = {
|
// XXX: horrible evil hack to ensure the editor is focused so the act
|
||||||
// code: 'code-block', // let's have the button do inline code for now
|
// of focusing it doesn't then cancel the format button being pressed
|
||||||
quote: 'block-quote',
|
if (document.activeElement && document.activeElement.className !== 'mx_MessageComposer_editor') {
|
||||||
bullet: 'bulleted-list',
|
this.refs.editor.focus();
|
||||||
numbullet: 'numbered-list',
|
setTimeout(()=>{
|
||||||
underline: 'underlined',
|
this.handleKeyCommand(name);
|
||||||
strike: 'deleted',
|
}, 500); // can't find any callback to hook this to. onFocus and onChange and willComponentUpdate fire too early.
|
||||||
}[name] || name;
|
return;
|
||||||
this.handleKeyCommand(command);
|
}
|
||||||
|
|
||||||
|
this.handleKeyCommand(name);
|
||||||
};
|
};
|
||||||
|
|
||||||
getAutocompleteQuery(editorState: Value) {
|
getAutocompleteQuery(editorState: Value) {
|
||||||
|