support auto complete for /commands
This commit is contained in:
parent
88cc1c428d
commit
c5cd8b943a
4 changed files with 41 additions and 9 deletions
|
@ -20,7 +20,7 @@ import dis from '../../../dispatcher';
|
||||||
import EditorModel from '../../../editor/model';
|
import EditorModel from '../../../editor/model';
|
||||||
import {getCaretOffsetAndText} from '../../../editor/dom';
|
import {getCaretOffsetAndText} from '../../../editor/dom';
|
||||||
import {htmlSerializeIfNeeded, textSerialize, containsEmote, stripEmoteCommand} from '../../../editor/serialize';
|
import {htmlSerializeIfNeeded, textSerialize, containsEmote, stripEmoteCommand} from '../../../editor/serialize';
|
||||||
import {PartCreator} from '../../../editor/parts';
|
import {CommandPartCreator} from '../../../editor/parts';
|
||||||
import {MatrixClient} from 'matrix-js-sdk';
|
import {MatrixClient} from 'matrix-js-sdk';
|
||||||
import BasicMessageComposer from "./BasicMessageComposer";
|
import BasicMessageComposer from "./BasicMessageComposer";
|
||||||
import ReplyPreview from "./ReplyPreview";
|
import ReplyPreview from "./ReplyPreview";
|
||||||
|
@ -164,7 +164,7 @@ export default class SendMessageComposer extends React.Component {
|
||||||
_isSlashCommand() {
|
_isSlashCommand() {
|
||||||
const parts = this.model.parts;
|
const parts = this.model.parts;
|
||||||
const isPlain = parts.reduce((isPlain, part) => {
|
const isPlain = parts.reduce((isPlain, part) => {
|
||||||
return isPlain && (part.type === "plain" || part.type === "newline");
|
return isPlain && (part.type === "command" || part.type === "plain" || part.type === "newline");
|
||||||
}, true);
|
}, true);
|
||||||
return isPlain && parts.length > 0 && parts[0].text.startsWith("/");
|
return isPlain && parts.length > 0 && parts[0].text.startsWith("/");
|
||||||
}
|
}
|
||||||
|
@ -227,15 +227,11 @@ export default class SendMessageComposer extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
const sel = document.getSelection();
|
|
||||||
const {caret} = getCaretOffsetAndText(this._editorRef, sel);
|
|
||||||
const parts = this.model.serializeParts();
|
|
||||||
this.props.editState.setEditorState(caret, parts);
|
|
||||||
dis.unregister(this.dispatcherRef);
|
dis.unregister(this.dispatcherRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
const partCreator = new PartCreator(this.props.room, this.context.matrixClient);
|
const partCreator = new CommandPartCreator(this.props.room, this.context.matrixClient);
|
||||||
this.model = new EditorModel([], partCreator);
|
this.model = new EditorModel([], partCreator);
|
||||||
this.dispatcherRef = dis.register(this.onAction);
|
this.dispatcherRef = dis.register(this.onAction);
|
||||||
this.sendHistoryManager = new ComposerHistoryManager(this.props.room.roomId, 'mx_slate_composer_history_');
|
this.sendHistoryManager = new ComposerHistoryManager(this.props.room.roomId, 'mx_slate_composer_history_');
|
||||||
|
|
|
@ -303,7 +303,7 @@ export default class EditorModel {
|
||||||
index = 0;
|
index = 0;
|
||||||
}
|
}
|
||||||
while (str) {
|
while (str) {
|
||||||
const newPart = this._partCreator.createPartForInput(str);
|
const newPart = this._partCreator.createPartForInput(str, index);
|
||||||
if (validate) {
|
if (validate) {
|
||||||
str = newPart.appendUntilRejected(str);
|
str = newPart.appendUntilRejected(str);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -441,3 +441,33 @@ export class PartCreator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// part creator that support auto complete for /commands,
|
||||||
|
// used in SendMessageComposer
|
||||||
|
export class CommandPartCreator extends PartCreator {
|
||||||
|
createPartForInput(text, partIndex) {
|
||||||
|
// at beginning and starts with /? create
|
||||||
|
if (partIndex === 0 && text[0] === "/") {
|
||||||
|
return new CommandPart("", this._autoCompleteCreator);
|
||||||
|
} else {
|
||||||
|
return super.createPartForInput(text, partIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializePart(part) {
|
||||||
|
if (part.type === "command") {
|
||||||
|
return new CommandPart(part.text, this._autoCompleteCreator);
|
||||||
|
} else {
|
||||||
|
return super.deserializePart(part);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CommandPart extends PillCandidatePart {
|
||||||
|
acceptsInsertion(chr, i) {
|
||||||
|
return PlainPart.prototype.acceptsInsertion.call(this, chr, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
get type() {
|
||||||
|
return "command";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ export function mdSerialize(model) {
|
||||||
case "newline":
|
case "newline":
|
||||||
return html + "\n";
|
return html + "\n";
|
||||||
case "plain":
|
case "plain":
|
||||||
|
case "command":
|
||||||
case "pill-candidate":
|
case "pill-candidate":
|
||||||
case "at-room-pill":
|
case "at-room-pill":
|
||||||
return html + part.text;
|
return html + part.text;
|
||||||
|
@ -47,6 +48,7 @@ export function textSerialize(model) {
|
||||||
case "newline":
|
case "newline":
|
||||||
return text + "\n";
|
return text + "\n";
|
||||||
case "plain":
|
case "plain":
|
||||||
|
case "command":
|
||||||
case "pill-candidate":
|
case "pill-candidate":
|
||||||
case "at-room-pill":
|
case "at-room-pill":
|
||||||
return text + part.text;
|
return text + part.text;
|
||||||
|
@ -59,7 +61,11 @@ export function textSerialize(model) {
|
||||||
|
|
||||||
export function containsEmote(model) {
|
export function containsEmote(model) {
|
||||||
const firstPart = model.parts[0];
|
const firstPart = model.parts[0];
|
||||||
return firstPart && firstPart.type === "plain" && firstPart.text.startsWith("/me ");
|
// part type will be "plain" while editing,
|
||||||
|
// and "command" while composing a message.
|
||||||
|
return firstPart &&
|
||||||
|
(firstPart.type === "plain" || firstPart.type === "command") &&
|
||||||
|
firstPart.text.startsWith("/me ");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function stripEmoteCommand(model) {
|
export function stripEmoteCommand(model) {
|
||||||
|
|
Loading…
Reference in a new issue