mirror of
https://github.com/vector-im/element-web.git
synced 2024-11-16 13:14:58 +08:00
unify setState() and onChange()
also make emoji autocomplete work again also remove the onInputContentChanged prop also slateify the onInputStateChanged prop
This commit is contained in:
parent
a247ea2f77
commit
7405b49b44
@ -35,7 +35,6 @@ export default class MessageComposer extends React.Component {
|
||||
this.onUploadFileSelected = this.onUploadFileSelected.bind(this);
|
||||
this.uploadFiles = this.uploadFiles.bind(this);
|
||||
this.onVoiceCallClick = this.onVoiceCallClick.bind(this);
|
||||
this.onInputContentChanged = this.onInputContentChanged.bind(this);
|
||||
this._onAutocompleteConfirm = this._onAutocompleteConfirm.bind(this);
|
||||
this.onToggleFormattingClicked = this.onToggleFormattingClicked.bind(this);
|
||||
this.onToggleMarkdownClicked = this.onToggleMarkdownClicked.bind(this);
|
||||
@ -44,13 +43,10 @@ export default class MessageComposer extends React.Component {
|
||||
this._onRoomViewStoreUpdate = this._onRoomViewStoreUpdate.bind(this);
|
||||
|
||||
this.state = {
|
||||
autocompleteQuery: '',
|
||||
selection: null,
|
||||
inputState: {
|
||||
style: [],
|
||||
marks: [],
|
||||
blockType: null,
|
||||
isRichtextEnabled: SettingsStore.getValue('MessageComposerInput.isRichTextEnabled'),
|
||||
wordCount: 0,
|
||||
},
|
||||
showFormatting: SettingsStore.getValue('MessageComposer.showFormatting'),
|
||||
isQuoting: Boolean(RoomViewStore.getQuotingEvent()),
|
||||
@ -209,13 +205,6 @@ export default class MessageComposer extends React.Component {
|
||||
// this._startCallApp(true);
|
||||
}
|
||||
|
||||
onInputContentChanged(content: string, selection: {start: number, end: number}) {
|
||||
this.setState({
|
||||
autocompleteQuery: content,
|
||||
selection,
|
||||
});
|
||||
}
|
||||
|
||||
onInputStateChanged(inputState) {
|
||||
this.setState({inputState});
|
||||
}
|
||||
@ -348,7 +337,6 @@ export default class MessageComposer extends React.Component {
|
||||
room={this.props.room}
|
||||
placeholder={placeholderText}
|
||||
onFilesPasted={this.uploadFiles}
|
||||
onContentChanged={this.onInputContentChanged}
|
||||
onInputStateChanged={this.onInputStateChanged} />,
|
||||
formattingButton,
|
||||
stickerpickerButton,
|
||||
@ -365,10 +353,10 @@ export default class MessageComposer extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
const {style, blockType} = this.state.inputState;
|
||||
const {marks, blockType} = this.state.inputState;
|
||||
const formatButtons = ["bold", "italic", "strike", "underline", "code", "quote", "bullet", "numbullet"].map(
|
||||
(name) => {
|
||||
const active = style.includes(name) || blockType === name;
|
||||
const active = marks.includes(name) || blockType === name;
|
||||
const suffix = active ? '-o-n' : '';
|
||||
const onFormatButtonClicked = this.onFormatButtonClicked.bind(this, name);
|
||||
const className = 'mx_MessageComposer_format_button mx_filterFlipColor';
|
||||
|
@ -184,23 +184,6 @@ export default class MessageComposerInput extends React.Component {
|
||||
this.direction = '';
|
||||
}
|
||||
|
||||
/*
|
||||
findPillEntities(contentState: ContentState, contentBlock: ContentBlock, callback) {
|
||||
contentBlock.findEntityRanges(
|
||||
(character) => {
|
||||
const entityKey = character.getEntity();
|
||||
return (
|
||||
entityKey !== null &&
|
||||
(
|
||||
contentState.getEntity(entityKey).getType() === 'LINK' ||
|
||||
contentState.getEntity(entityKey).getType() === ENTITY_TYPES.AT_ROOM_PILL
|
||||
)
|
||||
);
|
||||
}, callback,
|
||||
);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* "Does the right thing" to create an Editor value, based on:
|
||||
* - whether we've got rich text mode enabled
|
||||
@ -226,14 +209,12 @@ export default class MessageComposerInput extends React.Component {
|
||||
}
|
||||
|
||||
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) => {
|
||||
@ -375,6 +356,19 @@ export default class MessageComposerInput extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
if (editorState.document.getFirstText().text !== '') {
|
||||
this.onTypingActivity();
|
||||
} else {
|
||||
this.onFinishedTyping();
|
||||
}
|
||||
|
||||
/*
|
||||
// XXX: what was this ever doing?
|
||||
if (!state.hasOwnProperty('originalEditorState')) {
|
||||
state.originalEditorState = null;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
editorState = RichText.attachImmutableEntitiesToEmoji(editorState);
|
||||
|
||||
@ -405,6 +399,10 @@ export default class MessageComposerInput extends React.Component {
|
||||
// Reset selection
|
||||
editorState = EditorState.forceSelection(editorState, currentSelection);
|
||||
}
|
||||
*/
|
||||
|
||||
const text = editorState.startText.text;
|
||||
const currentStartOffset = editorState.startOffset;
|
||||
|
||||
// Automatic replacement of plaintext emoji to Unicode emoji
|
||||
if (SettingsStore.getValue('MessageComposerInput.autoReplaceEmoji')) {
|
||||
@ -415,23 +413,26 @@ export default class MessageComposerInput extends React.Component {
|
||||
const emojiUc = asciiList[emojiMatch[1]];
|
||||
// hex unicode -> shortname -> actual unicode
|
||||
const unicodeEmoji = shortnameToUnicode(EMOJI_UNICODE_TO_SHORTNAME[emojiUc]);
|
||||
const newContentState = Modifier.replaceText(
|
||||
editorState.getCurrentContent(),
|
||||
currentSelection.merge({
|
||||
anchorOffset: currentStartOffset - emojiMatch[1].length - 1,
|
||||
focusOffset: currentStartOffset,
|
||||
}),
|
||||
unicodeEmoji,
|
||||
);
|
||||
editorState = EditorState.push(
|
||||
editorState,
|
||||
newContentState,
|
||||
'insert-characters',
|
||||
);
|
||||
editorState = EditorState.forceSelection(editorState, newContentState.getSelectionAfter());
|
||||
|
||||
const range = Range.create({
|
||||
anchorKey: editorState.selection.startKey,
|
||||
anchorOffset: currentStartOffset - emojiMatch[1].length - 1,
|
||||
focusKey: editorState.selection.startKey,
|
||||
focusOffset: currentStartOffset,
|
||||
});
|
||||
change = change.insertTextAtRange(range, unicodeEmoji);
|
||||
editorState = change.value;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Record the editor state for this room so that it can be retrieved after
|
||||
// switching to another room and back
|
||||
dis.dispatch({
|
||||
action: 'editor_state',
|
||||
room_id: this.props.room.roomId,
|
||||
editor_state: editorState,
|
||||
});
|
||||
|
||||
/* Since a modification was made, set originalEditorState to null, since newState is now our original */
|
||||
this.setState({
|
||||
editorState,
|
||||
@ -439,68 +440,6 @@ export default class MessageComposerInput extends React.Component {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* We're overriding setState here because it's the most convenient way to monitor changes to the editorState.
|
||||
* Doing it using a separate function that calls setState is a possibility (and was the old approach), but that
|
||||
* approach requires a callback and an extra setState whenever trying to set multiple state properties.
|
||||
*
|
||||
* @param state
|
||||
* @param callback
|
||||
*/
|
||||
setState(state, callback) {
|
||||
/*
|
||||
if (state.editorState != null) {
|
||||
state.editorState = RichText.attachImmutableEntitiesToEmoji(
|
||||
state.editorState);
|
||||
|
||||
// Hide the autocomplete if the cursor location changes but the plaintext
|
||||
// content stays the same. We don't hide if the pt has changed because the
|
||||
// autocomplete will probably have different completions to show.
|
||||
if (
|
||||
!state.editorState.getSelection().equals(
|
||||
this.state.editorState.getSelection(),
|
||||
)
|
||||
&& state.editorState.getCurrentContent().getPlainText() ===
|
||||
this.state.editorState.getCurrentContent().getPlainText()
|
||||
) {
|
||||
this.autocomplete.hide();
|
||||
}
|
||||
|
||||
if (state.editorState.getCurrentContent().hasText()) {
|
||||
this.onTypingActivity();
|
||||
} else {
|
||||
this.onFinishedTyping();
|
||||
}
|
||||
|
||||
// Record the editor state for this room so that it can be retrieved after
|
||||
// switching to another room and back
|
||||
dis.dispatch({
|
||||
action: 'editor_state',
|
||||
room_id: this.props.room.roomId,
|
||||
editor_state: state.editorState.getCurrentContent(),
|
||||
});
|
||||
|
||||
if (!state.hasOwnProperty('originalEditorState')) {
|
||||
state.originalEditorState = null;
|
||||
}
|
||||
}
|
||||
*/
|
||||
super.setState(state, () => {
|
||||
if (callback != null) {
|
||||
callback();
|
||||
}
|
||||
/*
|
||||
const textContent = this.state.editorState.getCurrentContent().getPlainText();
|
||||
const selection = RichText.selectionStateToTextOffsets(
|
||||
this.state.editorState.getSelection(),
|
||||
this.state.editorState.getCurrentContent().getBlocksAsArray());
|
||||
if (this.props.onContentChanged) {
|
||||
this.props.onContentChanged(textContent, selection);
|
||||
}
|
||||
*/
|
||||
});
|
||||
}
|
||||
|
||||
enableRichtext(enabled: boolean) {
|
||||
if (enabled === this.state.isRichtextEnabled) return;
|
||||
|
||||
@ -1133,36 +1072,12 @@ export default class MessageComposerInput extends React.Component {
|
||||
/* returns inline style and block type of current SelectionState so MessageComposer can render formatting
|
||||
buttons. */
|
||||
getSelectionInfo(editorState: Value) {
|
||||
return {};
|
||||
/*
|
||||
const styleName = {
|
||||
BOLD: _td('bold'),
|
||||
ITALIC: _td('italic'),
|
||||
STRIKETHROUGH: _td('strike'),
|
||||
UNDERLINE: _td('underline'),
|
||||
};
|
||||
|
||||
const originalStyle = editorState.getCurrentInlineStyle().toArray();
|
||||
const style = originalStyle
|
||||
.map((style) => styleName[style] || null)
|
||||
.filter((styleName) => !!styleName);
|
||||
|
||||
const blockName = {
|
||||
'code-block': _td('code'),
|
||||
'blockquote': _td('quote'),
|
||||
'unordered-list-item': _td('bullet'),
|
||||
'ordered-list-item': _td('numbullet'),
|
||||
};
|
||||
const originalBlockType = editorState.getCurrentContent()
|
||||
.getBlockForKey(editorState.getSelection().getStartKey())
|
||||
.getType();
|
||||
const blockType = blockName[originalBlockType] || null;
|
||||
|
||||
return {
|
||||
style,
|
||||
blockType,
|
||||
marks: editorState.activeMarks,
|
||||
// XXX: shouldn't we return all the types of blocks in the current selection,
|
||||
// not just the anchor?
|
||||
blockType: editorState.anchorBlock.type,
|
||||
};
|
||||
*/
|
||||
}
|
||||
|
||||
getAutocompleteQuery(editorState: Value) {
|
||||
|
Loading…
Reference in New Issue
Block a user