Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Merge pull request #2069 from matrix-org/t3chguy/slate_cont2
Browse files Browse the repository at this point in the history
Moar Slate Fixes
  • Loading branch information
ara4n committed Jul 17, 2018
2 parents 48fbf14 + 720a728 commit 02c3bc9
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 24 deletions.
2 changes: 1 addition & 1 deletion src/autocomplete/UserProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export default class UserProvider extends AutocompleteProvider {
// relies on the length of the entity === length of the text in the decoration.
completion: user.rawDisplayName.replace(' (IRC)', ''),
completionId: user.userId,
suffix: (selection.beginning && selection.start === 0) ? ': ' : ' ',
suffix: (selection.beginning && range.start === 0) ? ': ' : ' ',
href: makeUserPermalink(user.userId),
component: (
<PillCompletion
Expand Down
4 changes: 3 additions & 1 deletion src/components/views/rooms/MessageComposer.js
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,9 @@ export default class MessageComposer extends React.Component {
if (this.state.showFormatting && this.state.inputState.isRichTextEnabled) {
const {marks, blockType} = this.state.inputState;
const formatButtons = formatButtonList.map((name) => {
const active = marks.some(mark => mark.type === name) || blockType === 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';
Expand Down
68 changes: 47 additions & 21 deletions src/components/views/rooms/MessageComposerInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,8 @@ export default class MessageComposerInput extends React.Component {
const quote = Block.create('block-quote');
if (this.state.isRichTextEnabled) {
let change = editorState.change();
if (editorState.anchorText.text === '' && editorState.anchorBlock.nodes.size === 1) {
const anchorText = editorState.anchorText;
if ((!anchorText || anchorText.text === '') && editorState.anchorBlock.nodes.size === 1) {
// replace the current block rather than split the block
change = change.replaceNodeByKey(editorState.anchorBlock.key, quote);
}
Expand Down Expand Up @@ -969,19 +970,21 @@ export default class MessageComposerInput extends React.Component {
onPaste = (event: Event, change: Change, editor: Editor): Change => {
const transfer = getEventTransfer(event);

if (transfer.type === "files") {
return this.props.onFilesPasted(transfer.files);
}
else if (transfer.type === "html") {
// FIXME: https://github.com/ianstormtaylor/slate/issues/1497 means
// that we will silently discard nested blocks (e.g. nested lists) :(
const fragment = this.html.deserialize(transfer.html);
if (this.state.isRichTextEnabled) {
return change.insertFragment(fragment.document);
}
else {
return change.insertText(this.md.serialize(fragment));
switch (transfer.type) {
case 'files':
return this.props.onFilesPasted(transfer.files);
case 'html': {
// FIXME: https://github.com/ianstormtaylor/slate/issues/1497 means
// that we will silently discard nested blocks (e.g. nested lists) :(
const fragment = this.html.deserialize(transfer.html);
if (this.state.isRichTextEnabled) {
return change.insertFragment(fragment.document);
} else {
return change.insertText(this.md.serialize(fragment));
}
}
case 'text':
return change.insertText(transfer.text);
}
};

Expand All @@ -990,15 +993,30 @@ export default class MessageComposerInput extends React.Component {
return change.insertText('\n');
}

if (this.state.editorState.blocks.some(
block => ['code', 'block-quote', 'list-item'].includes(block.type)
)) {
// allow the user to terminate blocks by hitting return rather than sending a msg
const editorState = this.state.editorState;

const lastBlock = editorState.blocks.last();
if (['code', 'block-quote', 'list-item'].includes(lastBlock.type)) {
const text = lastBlock.text;
if (text === '') {
// allow the user to cancel empty block by hitting return, useful in conjunction with below `inBlock`
return change
.setBlocks(DEFAULT_NODE)
.unwrapBlock('bulleted-list')
.unwrapBlock('numbered-list');
}

// TODO strip trailing lines from blockquotes/list entries
// the below code seemingly works but doesn't account for edge cases like return with caret not at end
/* const trailingNewlines = text.match(/\n*$/);
if (trailingNewlines && trailingNewlines[0]) {
remove trailing newlines at the end of this block before making a new one
return change.deleteBackward(trailingNewlines[0].length);
}*/

return;
}

const editorState = this.state.editorState;

let contentText;
let contentHTML;

Expand Down Expand Up @@ -1515,6 +1533,14 @@ export default class MessageComposerInput extends React.Component {
mx_MessageComposer_input_error: this.state.someCompletions === false,
});

const isEmpty = this.state.editorState.document.isEmpty;

let {placeholder} = this.props;
// XXX: workaround for placeholder being shown when there is a formatting block e.g blockquote but no text
if (isEmpty && this.state.editorState.startBlock.type !== DEFAULT_NODE) {
placeholder = undefined;
}

return (
<div className="mx_MessageComposer_input_wrapper" onClick={this.focusComposer}>
<div className="mx_MessageComposer_autocomplete_wrapper">
Expand All @@ -1536,7 +1562,7 @@ export default class MessageComposerInput extends React.Component {
<Editor ref="editor"
dir="auto"
className="mx_MessageComposer_editor"
placeholder={this.props.placeholder}
placeholder={placeholder}
value={this.state.editorState}
onChange={this.onChange}
onKeyDown={this.onKeyDown}
Expand All @@ -1546,7 +1572,7 @@ export default class MessageComposerInput extends React.Component {
renderNode={this.renderNode}
renderMark={this.renderMark}
// disable spell check for the placeholder because browsers don't like "unencrypted"
spellCheck={!this.state.editorState.document.isEmpty}
spellCheck={!isEmpty}
/>
</div>
</div>
Expand Down
8 changes: 7 additions & 1 deletion src/stores/MessageComposerStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,13 @@ class MessageComposerStore {

setEditorState(roomId: string, editorState: Value, richText: boolean) {
localStorage.setItem(this._getKey(roomId), JSON.stringify({
editor_state: editorState,
editor_state: editorState.toJSON({
preserveSelection: true,
// XXX: re-hydrating history is not currently supported by fromJSON
// preserveHistory: true,
// XXX: this seems like a workaround for selection.isSet being based on anchorKey instead of anchorPath
preserveKeys: true,
}),
rich_text: richText,
}));
}
Expand Down

0 comments on commit 02c3bc9

Please sign in to comment.