unify buttons on the node type names, and make them work

This commit is contained in:
Matthew Hodgson 2018-05-20 22:39:40 +01:00
parent d799b7e424
commit f981d7b729
15 changed files with 68 additions and 60 deletions

View File

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -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>
); );
} }

View File

@ -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) {