still convert \n to NewlinePart when pasting/dropping
before we skipped the complete validation (which creates NewlineParts) when pasting or dropping text. We don't want to create PillCandidatePart when inserting text like this, as it would open the auto-complete, but newlines should still be applied. So instead of skipping validation, pass the inputType to the validation code so they can only reject pill candidate characters when not pasting.
This commit is contained in:
parent
e531b29307
commit
80523f5dbe
2 changed files with 27 additions and 38 deletions
|
@ -183,15 +183,14 @@ export default class EditorModel {
|
||||||
if (diff.removed) {
|
if (diff.removed) {
|
||||||
removedOffsetDecrease = this.removeText(position, diff.removed.length);
|
removedOffsetDecrease = this.removeText(position, diff.removed.length);
|
||||||
}
|
}
|
||||||
const canOpenAutoComplete = inputType !== "insertFromPaste" && inputType !== "insertFromDrop";
|
|
||||||
let addedLen = 0;
|
let addedLen = 0;
|
||||||
if (diff.added) {
|
if (diff.added) {
|
||||||
// these shouldn't trigger auto-complete, you just want to append a piece of text
|
addedLen = this._addText(position, diff.added, inputType);
|
||||||
addedLen = this._addText(position, diff.added, {validate: canOpenAutoComplete});
|
|
||||||
}
|
}
|
||||||
this._mergeAdjacentParts();
|
this._mergeAdjacentParts();
|
||||||
const caretOffset = diff.at - removedOffsetDecrease + addedLen;
|
const caretOffset = diff.at - removedOffsetDecrease + addedLen;
|
||||||
let newPosition = this.positionForOffset(caretOffset, true);
|
let newPosition = this.positionForOffset(caretOffset, true);
|
||||||
|
const canOpenAutoComplete = inputType !== "insertFromPaste" && inputType !== "insertFromDrop";
|
||||||
const acPromise = this._setActivePart(newPosition, canOpenAutoComplete);
|
const acPromise = this._setActivePart(newPosition, canOpenAutoComplete);
|
||||||
if (this._transformCallback) {
|
if (this._transformCallback) {
|
||||||
const transformAddedLen = this._transform(newPosition, inputType, diff);
|
const transformAddedLen = this._transform(newPosition, inputType, diff);
|
||||||
|
@ -333,22 +332,20 @@ export default class EditorModel {
|
||||||
* inserts `str` into the model at `pos`.
|
* inserts `str` into the model at `pos`.
|
||||||
* @param {Object} pos
|
* @param {Object} pos
|
||||||
* @param {string} str
|
* @param {string} str
|
||||||
* @param {Object} options
|
* @param {string} inputType the source of the input, see html InputEvent.inputType
|
||||||
* @param {bool} options.validate Whether characters will be validated by the part.
|
* @param {bool} options.validate Whether characters will be validated by the part.
|
||||||
* Validating allows the inserted text to be parsed according to the part rules.
|
* Validating allows the inserted text to be parsed according to the part rules.
|
||||||
* @return {Number} how far from position (in characters) the insertion ended.
|
* @return {Number} how far from position (in characters) the insertion ended.
|
||||||
* This can be more than the length of `str` when crossing non-editable parts, which are skipped.
|
* This can be more than the length of `str` when crossing non-editable parts, which are skipped.
|
||||||
*/
|
*/
|
||||||
_addText(pos, str, {validate=true}) {
|
_addText(pos, str, inputType) {
|
||||||
let {index} = pos;
|
let {index} = pos;
|
||||||
const {offset} = pos;
|
const {offset} = pos;
|
||||||
let addLen = str.length;
|
let addLen = str.length;
|
||||||
const part = this._parts[index];
|
const part = this._parts[index];
|
||||||
if (part) {
|
if (part) {
|
||||||
if (part.canEdit) {
|
if (part.canEdit) {
|
||||||
if (validate && part.validateAndInsert(offset, str)) {
|
if (part.validateAndInsert(offset, str, inputType)) {
|
||||||
str = null;
|
|
||||||
} else if (!validate && part.insert(offset, str)) {
|
|
||||||
str = null;
|
str = null;
|
||||||
} else {
|
} else {
|
||||||
const splitPart = part.split(offset);
|
const splitPart = part.split(offset);
|
||||||
|
@ -367,13 +364,8 @@ export default class EditorModel {
|
||||||
index = 0;
|
index = 0;
|
||||||
}
|
}
|
||||||
while (str) {
|
while (str) {
|
||||||
const newPart = this._partCreator.createPartForInput(str, index);
|
const newPart = this._partCreator.createPartForInput(str, index, inputType);
|
||||||
if (validate) {
|
str = newPart.appendUntilRejected(str, inputType);
|
||||||
str = newPart.appendUntilRejected(str);
|
|
||||||
} else {
|
|
||||||
newPart.insert(0, str);
|
|
||||||
str = null;
|
|
||||||
}
|
|
||||||
this._insertPart(index, newPart);
|
this._insertPart(index, newPart);
|
||||||
index += 1;
|
index += 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ class BasePart {
|
||||||
this._text = text;
|
this._text = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
acceptsInsertion(chr) {
|
acceptsInsertion(chr, offset, inputType) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,10 +56,11 @@ class BasePart {
|
||||||
}
|
}
|
||||||
|
|
||||||
// append str, returns the remaining string if a character was rejected.
|
// append str, returns the remaining string if a character was rejected.
|
||||||
appendUntilRejected(str) {
|
appendUntilRejected(str, inputType) {
|
||||||
|
const offset = this.text.length;
|
||||||
for (let i = 0; i < str.length; ++i) {
|
for (let i = 0; i < str.length; ++i) {
|
||||||
const chr = str.charAt(i);
|
const chr = str.charAt(i);
|
||||||
if (!this.acceptsInsertion(chr, i)) {
|
if (!this.acceptsInsertion(chr, offset + i, inputType)) {
|
||||||
this._text = this._text + str.substr(0, i);
|
this._text = this._text + str.substr(0, i);
|
||||||
return str.substr(i);
|
return str.substr(i);
|
||||||
}
|
}
|
||||||
|
@ -69,10 +70,10 @@ class BasePart {
|
||||||
|
|
||||||
// inserts str at offset if all the characters in str were accepted, otherwise don't do anything
|
// inserts str at offset if all the characters in str were accepted, otherwise don't do anything
|
||||||
// return whether the str was accepted or not.
|
// return whether the str was accepted or not.
|
||||||
validateAndInsert(offset, str) {
|
validateAndInsert(offset, str, inputType) {
|
||||||
for (let i = 0; i < str.length; ++i) {
|
for (let i = 0; i < str.length; ++i) {
|
||||||
const chr = str.charAt(i);
|
const chr = str.charAt(i);
|
||||||
if (!this.acceptsInsertion(chr)) {
|
if (!this.acceptsInsertion(chr, offset + i, inputType)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,16 +83,6 @@ class BasePart {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
insert(offset, str) {
|
|
||||||
if (this.canEdit) {
|
|
||||||
const beforeInsert = this._text.substr(0, offset);
|
|
||||||
const afterInsert = this._text.substr(offset);
|
|
||||||
this._text = beforeInsert + str + afterInsert;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
createAutoComplete() {}
|
createAutoComplete() {}
|
||||||
|
|
||||||
trim(len) {
|
trim(len) {
|
||||||
|
@ -119,8 +110,15 @@ class BasePart {
|
||||||
|
|
||||||
// exported for unit tests, should otherwise only be used through PartCreator
|
// exported for unit tests, should otherwise only be used through PartCreator
|
||||||
export class PlainPart extends BasePart {
|
export class PlainPart extends BasePart {
|
||||||
acceptsInsertion(chr) {
|
acceptsInsertion(chr, offset, inputType) {
|
||||||
return chr !== "@" && chr !== "#" && chr !== ":" && chr !== "\n";
|
if (chr === "\n") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// when not pasting or dropping text, reject characters that should start a pill candidate
|
||||||
|
if (inputType !== "insertFromPaste" && inputType !== "insertFromDrop") {
|
||||||
|
return chr !== "@" && chr !== "#" && chr !== ":";
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
toDOMNode() {
|
toDOMNode() {
|
||||||
|
@ -141,7 +139,6 @@ export class PlainPart extends BasePart {
|
||||||
|
|
||||||
updateDOMNode(node) {
|
updateDOMNode(node) {
|
||||||
if (node.textContent !== this.text) {
|
if (node.textContent !== this.text) {
|
||||||
// console.log("changing plain text from", node.textContent, "to", this.text);
|
|
||||||
node.textContent = this.text;
|
node.textContent = this.text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -211,8 +208,8 @@ class PillPart extends BasePart {
|
||||||
}
|
}
|
||||||
|
|
||||||
class NewlinePart extends BasePart {
|
class NewlinePart extends BasePart {
|
||||||
acceptsInsertion(chr, i) {
|
acceptsInsertion(chr, offset) {
|
||||||
return (this.text.length + i) === 0 && chr === "\n";
|
return offset === 0 && chr === "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
acceptsRemoval(position, chr) {
|
acceptsRemoval(position, chr) {
|
||||||
|
@ -331,11 +328,11 @@ class PillCandidatePart extends PlainPart {
|
||||||
return this._autoCompleteCreator.create(updateCallback);
|
return this._autoCompleteCreator.create(updateCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
acceptsInsertion(chr, i) {
|
acceptsInsertion(chr, offset, inputType) {
|
||||||
if ((this.text.length + i) === 0) {
|
if (offset === 0) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return super.acceptsInsertion(chr, i);
|
return super.acceptsInsertion(chr, offset, inputType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue