Improve trailing spurious breaks + tests
This commit is contained in:
parent
9a530a72f6
commit
832da062cc
3 changed files with 63 additions and 22 deletions
|
@ -250,7 +250,7 @@ function parseHtmlMessage(html, partCreator, isQuotedMessage) {
|
|||
}
|
||||
|
||||
export function parsePlainTextMessage(body, partCreator, isQuotedMessage) {
|
||||
const lines = body.split(/\r\n|\r|\n/g); // split on any new-line combination not just \n
|
||||
const lines = body.split(/\r\n|\r|\n/g); // split on any new-line combination not just \n, collapses \r\n
|
||||
const parts = lines.reduce((parts, line, i) => {
|
||||
if (isQuotedMessage) {
|
||||
parts.push(partCreator.plain(QUOTE_LINE_PREFIX));
|
||||
|
|
|
@ -100,6 +100,10 @@ export function formatRangeAsCode(range) {
|
|||
replaceRangeAndExpandSelection(range, parts);
|
||||
}
|
||||
|
||||
// parts helper methods
|
||||
const isBlank = part => !part.text || !/\S/.test(part.text);
|
||||
const isNL = part => part.type === "newline";
|
||||
|
||||
export function toggleInlineFormat(range, prefix, suffix = prefix) {
|
||||
const {model, parts} = range;
|
||||
const {partCreator} = model;
|
||||
|
@ -113,14 +117,12 @@ export function toggleInlineFormat(range, prefix, suffix = prefix) {
|
|||
// - 2 newline parts in sequence
|
||||
// - newline part, plain(<empty or just spaces>), newline part
|
||||
|
||||
const isBlank = part => !part.text || !/\S/.test(part.text);
|
||||
const isNL = part => part.type === "newline";
|
||||
|
||||
// bump startIndex onto the first non-blank after the paragraph ending
|
||||
if (isBlank(parts[i - 2]) && isNL(parts[i - 1]) && !isNL(parts[i]) && !isBlank(parts[i])) {
|
||||
startIndex = i;
|
||||
}
|
||||
|
||||
// if at a paragraph break, store the indexes of the paragraph
|
||||
if (isNL(parts[i - 1]) && isNL(parts[i])) {
|
||||
paragraphIndexes.push([startIndex, i - 1]);
|
||||
startIndex = i + 1;
|
||||
|
@ -129,9 +131,11 @@ export function toggleInlineFormat(range, prefix, suffix = prefix) {
|
|||
startIndex = i + 1;
|
||||
}
|
||||
}
|
||||
if (startIndex < parts.length) {
|
||||
// TODO don't use parts.length here to clean up any trailing cruft
|
||||
paragraphIndexes.push([startIndex, parts.length]);
|
||||
|
||||
const lastNonEmptyPart = parts.map(isBlank).lastIndexOf(false);
|
||||
// If we have not yet included the final paragraph then add it now
|
||||
if (startIndex <= lastNonEmptyPart) {
|
||||
paragraphIndexes.push([startIndex, lastNonEmptyPart + 1]);
|
||||
}
|
||||
|
||||
// keep track of how many things we have inserted as an offset:=0
|
||||
|
|
|
@ -18,6 +18,8 @@ import EditorModel from "../../src/editor/model";
|
|||
import {createPartCreator, createRenderer} from "./mock";
|
||||
import {toggleInlineFormat} from "../../src/editor/operations";
|
||||
|
||||
const SERIALIZED_NEWLINE = {"text": "\n", "type": "newline"};
|
||||
|
||||
describe('editor/operations: formatting operations', () => {
|
||||
describe('toggleInlineFormat', () => {
|
||||
it('works for words', () => {
|
||||
|
@ -93,17 +95,54 @@ describe('editor/operations: formatting operations', () => {
|
|||
expect(range.parts.map(p => p.text).join("")).toBe("world,\nhow");
|
||||
expect(model.serializeParts()).toEqual([
|
||||
{"text": "hello world,", "type": "plain"},
|
||||
{"text": "\n", "type": "newline"},
|
||||
SERIALIZED_NEWLINE,
|
||||
{"text": "how are you doing?", "type": "plain"},
|
||||
]);
|
||||
toggleInlineFormat(range, "**");
|
||||
expect(model.serializeParts()).toEqual([
|
||||
{"text": "hello **world,", "type": "plain"},
|
||||
{"text": "\n", "type": "newline"},
|
||||
SERIALIZED_NEWLINE,
|
||||
{"text": "how** are you doing?", "type": "plain"},
|
||||
]);
|
||||
});
|
||||
|
||||
it('works for a paragraph with spurious breaks around it in selected range', () => {
|
||||
const renderer = createRenderer();
|
||||
const pc = createPartCreator();
|
||||
const model = new EditorModel([
|
||||
pc.newline(),
|
||||
pc.newline(),
|
||||
pc.plain("hello world,"),
|
||||
pc.newline(),
|
||||
pc.plain("how are you doing?"),
|
||||
pc.newline(),
|
||||
pc.newline(),
|
||||
], pc, renderer);
|
||||
|
||||
const range = model.startRange(model.positionForOffset(0, false), model.getPositionAtEnd()); // select-all
|
||||
|
||||
expect(range.parts.map(p => p.text).join("")).toBe("\n\nhello world,\nhow are you doing?\n\n");
|
||||
expect(model.serializeParts()).toEqual([
|
||||
SERIALIZED_NEWLINE,
|
||||
SERIALIZED_NEWLINE,
|
||||
{"text": "hello world,", "type": "plain"},
|
||||
SERIALIZED_NEWLINE,
|
||||
{"text": "how are you doing?", "type": "plain"},
|
||||
SERIALIZED_NEWLINE,
|
||||
SERIALIZED_NEWLINE,
|
||||
]);
|
||||
toggleInlineFormat(range, "**");
|
||||
expect(model.serializeParts()).toEqual([
|
||||
SERIALIZED_NEWLINE,
|
||||
SERIALIZED_NEWLINE,
|
||||
{"text": "**hello world,", "type": "plain"},
|
||||
SERIALIZED_NEWLINE,
|
||||
{"text": "how are you doing?**", "type": "plain"},
|
||||
SERIALIZED_NEWLINE,
|
||||
SERIALIZED_NEWLINE,
|
||||
]);
|
||||
});
|
||||
|
||||
it('works for multiple paragraph', () => {
|
||||
const renderer = createRenderer();
|
||||
const pc = createPartCreator();
|
||||
|
@ -116,36 +155,34 @@ describe('editor/operations: formatting operations', () => {
|
|||
pc.plain("new paragraph"),
|
||||
], pc, renderer);
|
||||
|
||||
let range = model.startRange(model.positionForOffset(0, true),
|
||||
model.getPositionAtEnd()); // select-all
|
||||
let range = model.startRange(model.positionForOffset(0, true), model.getPositionAtEnd()); // select-all
|
||||
|
||||
expect(model.serializeParts()).toEqual([
|
||||
{"text": "hello world,", "type": "plain"},
|
||||
{"text": "\n", "type": "newline"},
|
||||
SERIALIZED_NEWLINE,
|
||||
{"text": "how are you doing?", "type": "plain"},
|
||||
{"text": "\n", "type": "newline"},
|
||||
{"text": "\n", "type": "newline"},
|
||||
SERIALIZED_NEWLINE,
|
||||
SERIALIZED_NEWLINE,
|
||||
{"text": "new paragraph", "type": "plain"},
|
||||
]);
|
||||
toggleInlineFormat(range, "__");
|
||||
expect(model.serializeParts()).toEqual([
|
||||
{"text": "__hello world,", "type": "plain"},
|
||||
{"text": "\n", "type": "newline"},
|
||||
SERIALIZED_NEWLINE,
|
||||
{"text": "how are you doing?__", "type": "plain"},
|
||||
{"text": "\n", "type": "newline"},
|
||||
{"text": "\n", "type": "newline"},
|
||||
SERIALIZED_NEWLINE,
|
||||
SERIALIZED_NEWLINE,
|
||||
{"text": "__new paragraph__", "type": "plain"},
|
||||
]);
|
||||
range = model.startRange(model.positionForOffset(0, true),
|
||||
model.getPositionAtEnd()); // select-all
|
||||
range = model.startRange(model.positionForOffset(0, true), model.getPositionAtEnd()); // select-all
|
||||
console.log("RANGE", range.parts);
|
||||
toggleInlineFormat(range, "__");
|
||||
expect(model.serializeParts()).toEqual([
|
||||
{"text": "hello world,", "type": "plain"},
|
||||
{"text": "\n", "type": "newline"},
|
||||
SERIALIZED_NEWLINE,
|
||||
{"text": "how are you doing?", "type": "plain"},
|
||||
{"text": "\n", "type": "newline"},
|
||||
{"text": "\n", "type": "newline"},
|
||||
SERIALIZED_NEWLINE,
|
||||
SERIALIZED_NEWLINE,
|
||||
{"text": "new paragraph", "type": "plain"},
|
||||
]);
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue