From 2ff2ff0e75fbd0c0d75683bc95054e0df4261107 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 29 Aug 2019 17:43:18 +0200 Subject: [PATCH 1/3] support autocomplete replacing text with multiple parts and append ": " to user pills --- src/editor/autocomplete.js | 19 ++++++++----------- src/editor/model.js | 19 +++++++++++-------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/editor/autocomplete.js b/src/editor/autocomplete.js index 79a69c07a6..67015b72e1 100644 --- a/src/editor/autocomplete.js +++ b/src/editor/autocomplete.js @@ -27,8 +27,7 @@ export default class AutocompleteWrapperModel { onEscape(e) { this._getAutocompleterComponent().onEscape(e); this._updateCallback({ - replacePart: this._partCreator.plain(this._queryPart.text), - caretOffset: this._queryOffset, + replaceParts: [this._partCreator.plain(this._queryPart.text)], close: true, }); } @@ -70,26 +69,24 @@ export default class AutocompleteWrapperModel { // cache the typed value and caret here // so we can restore it in onComponentSelectionChange when the value is undefined (meaning it should be the typed text) this._queryPart = part; - this._queryOffset = offset; return this._updateQuery(part.text); } onComponentSelectionChange(completion) { if (!completion) { this._updateCallback({ - replacePart: this._queryPart, - caretOffset: this._queryOffset, + replaceParts: [this._queryPart], }); } else { this._updateCallback({ - replacePart: this._partForCompletion(completion), + replaceParts: this._partForCompletion(completion), }); } } onComponentConfirm(completion) { this._updateCallback({ - replacePart: this._partForCompletion(completion), + replaceParts: this._partForCompletion(completion), close: true, }); } @@ -101,16 +98,16 @@ export default class AutocompleteWrapperModel { switch (firstChr) { case "@": { if (completionId === "@room") { - return this._partCreator.atRoomPill(completionId); + return [this._partCreator.atRoomPill(completionId)]; } else { - return this._partCreator.userPill(text, completionId); + return [this._partCreator.userPill(text, completionId), this._partCreator.plain(": ")]; } } case "#": - return this._partCreator.roomPill(completionId); + return [this._partCreator.roomPill(completionId)]; // used for emoji and command completion replacement default: - return this._partCreator.plain(text); + return [this._partCreator.plain(text)]; } } } diff --git a/src/editor/model.js b/src/editor/model.js index 59371cc3e6..4b8405adef 100644 --- a/src/editor/model.js +++ b/src/editor/model.js @@ -47,6 +47,7 @@ export default class EditorModel { this._activePartIdx = null; this._autoComplete = null; this._autoCompletePartIdx = null; + this._autoCompletePartCount = 0; this._transformCallback = null; this.setUpdateCallback(updateCallback); } @@ -219,6 +220,7 @@ export default class EditorModel { // make sure that react picks up the difference between both acs this._autoComplete = ac; this._autoCompletePartIdx = index; + this._autoCompletePartCount = 1; } } } @@ -230,23 +232,24 @@ export default class EditorModel { this._activePartIdx = null; this._autoComplete = null; this._autoCompletePartIdx = null; + this._autoCompletePartCount = 0; } return Promise.resolve(); } - _onAutoComplete = ({replacePart, caretOffset, close}) => { + _onAutoComplete = ({replaceParts, close}) => { let pos; - if (replacePart) { - this._replacePart(this._autoCompletePartIdx, replacePart); - const index = this._autoCompletePartIdx; - if (caretOffset === undefined) { - caretOffset = replacePart.text.length; - } - pos = new DocumentPosition(index, caretOffset); + if (replaceParts) { + this._parts.splice(this._autoCompletePartIdx, this._autoCompletePartCount, ...replaceParts); + this._autoCompletePartCount = replaceParts.length; + const lastPart = replaceParts[replaceParts.length - 1]; + const lastPartIndex = this._autoCompletePartIdx + replaceParts.length - 1; + pos = new DocumentPosition(lastPartIndex, lastPart.text.length); } if (close) { this._autoComplete = null; this._autoCompletePartIdx = null; + this._autoCompletePartCount = 0; } // rerender even if editor contents didn't change // to make sure the MessageEditor checks From c9572250befce53e2578ba8e21db809c112bfc26 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 29 Aug 2019 17:47:14 +0200 Subject: [PATCH 2/3] only append colon to user-pill when at start of composer by passing position to autocomplete, so completion can depend on where the pill-candidate appears. --- src/editor/autocomplete.js | 7 +++++-- src/editor/model.js | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/editor/autocomplete.js b/src/editor/autocomplete.js index 67015b72e1..d3b8f713b9 100644 --- a/src/editor/autocomplete.js +++ b/src/editor/autocomplete.js @@ -65,10 +65,11 @@ export default class AutocompleteWrapperModel { this._getAutocompleterComponent().moveSelection(+1); } - onPartUpdate(part, offset) { + onPartUpdate(part, pos) { // cache the typed value and caret here // so we can restore it in onComponentSelectionChange when the value is undefined (meaning it should be the typed text) this._queryPart = part; + this._partIndex = pos.index; return this._updateQuery(part.text); } @@ -100,7 +101,9 @@ export default class AutocompleteWrapperModel { if (completionId === "@room") { return [this._partCreator.atRoomPill(completionId)]; } else { - return [this._partCreator.userPill(text, completionId), this._partCreator.plain(": ")]; + const pill = this._partCreator.userPill(text, completionId); + const postfix = this._partCreator.plain(this._partIndex === 0 ? ": " : " "); + return [pill, postfix]; } } case "#": diff --git a/src/editor/model.js b/src/editor/model.js index 4b8405adef..734d96393f 100644 --- a/src/editor/model.js +++ b/src/editor/model.js @@ -226,7 +226,7 @@ export default class EditorModel { } // not _autoComplete, only there if active part is autocomplete part if (this.autoComplete) { - return this.autoComplete.onPartUpdate(part, pos.offset); + return this.autoComplete.onPartUpdate(part, pos); } } else { this._activePartIdx = null; From be79cdddb09eb434f91b54ab60b58f0e975c0ed8 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 29 Aug 2019 18:00:38 +0200 Subject: [PATCH 3/3] apply autocomplete changes to mock to fix editor unit tests --- test/editor/mock.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/editor/mock.js b/test/editor/mock.js index 7e0fd6b273..bb1a51d14b 100644 --- a/test/editor/mock.js +++ b/test/editor/mock.js @@ -40,12 +40,12 @@ class MockAutoComplete { } else { pill = this._partCreator.roomPill(match.resourceId); } - this._updateCallback({replacePart: pill, close}); + this._updateCallback({replaceParts: [pill], close}); } } // called by EditorModel when typing into pill-candidate part - onPartUpdate(part, offset) { + onPartUpdate(part, pos) { this._part = part; } }