mirror of https://github.com/vector-im/riot-web
				
				
				
			support auto complete for /commands
							parent
							
								
									88cc1c428d
								
							
						
					
					
						commit
						c5cd8b943a
					
				|  | @ -20,7 +20,7 @@ import dis from '../../../dispatcher'; | |||
| import EditorModel from '../../../editor/model'; | ||||
| import {getCaretOffsetAndText} from '../../../editor/dom'; | ||||
| 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 BasicMessageComposer from "./BasicMessageComposer"; | ||||
| import ReplyPreview from "./ReplyPreview"; | ||||
|  | @ -164,7 +164,7 @@ export default class SendMessageComposer extends React.Component { | |||
|     _isSlashCommand() { | ||||
|         const parts = this.model.parts; | ||||
|         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); | ||||
|         return isPlain && parts.length > 0 && parts[0].text.startsWith("/"); | ||||
|     } | ||||
|  | @ -227,15 +227,11 @@ export default class SendMessageComposer extends React.Component { | |||
|     } | ||||
| 
 | ||||
|     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); | ||||
|     } | ||||
| 
 | ||||
|     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.dispatcherRef = dis.register(this.onAction); | ||||
|         this.sendHistoryManager = new ComposerHistoryManager(this.props.room.roomId, 'mx_slate_composer_history_'); | ||||
|  |  | |||
|  | @ -303,7 +303,7 @@ export default class EditorModel { | |||
|             index = 0; | ||||
|         } | ||||
|         while (str) { | ||||
|             const newPart = this._partCreator.createPartForInput(str); | ||||
|             const newPart = this._partCreator.createPartForInput(str, index); | ||||
|             if (validate) { | ||||
|                 str = newPart.appendUntilRejected(str); | ||||
|             } 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": | ||||
|                 return html + "\n"; | ||||
|             case "plain": | ||||
|             case "command": | ||||
|             case "pill-candidate": | ||||
|             case "at-room-pill": | ||||
|                 return html + part.text; | ||||
|  | @ -47,6 +48,7 @@ export function textSerialize(model) { | |||
|             case "newline": | ||||
|                 return text + "\n"; | ||||
|             case "plain": | ||||
|             case "command": | ||||
|             case "pill-candidate": | ||||
|             case "at-room-pill": | ||||
|                 return text + part.text; | ||||
|  | @ -59,7 +61,11 @@ export function textSerialize(model) { | |||
| 
 | ||||
| export function containsEmote(model) { | ||||
|     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) { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Bruno Windels
						Bruno Windels