diff --git a/src/editor/deserialize.ts b/src/editor/deserialize.ts index 1f84c08239..b95634ca42 100644 --- a/src/editor/deserialize.ts +++ b/src/editor/deserialize.ts @@ -129,7 +129,9 @@ function parseElement(n: HTMLElement, partCreator: PartCreator, lastNode: HTMLEl case "U": return partCreator.plain(`${n.textContent}`); case "LI": { - const indent = " ".repeat(state.listDepth - 1); + const BASE_INDENT = 4; + const depth = state.listDepth - 1; + const indent = " ".repeat(BASE_INDENT * depth); if (n.parentElement.nodeName === "OL") { // The markdown parser doesn't do nested indexed lists at all, but this supports it anyway. const index = state.listIndex[state.listIndex.length - 1]; diff --git a/test/editor/deserialize-test.js b/test/editor/deserialize-test.js index 998e1d0190..2de6375b82 100644 --- a/test/editor/deserialize-test.js +++ b/test/editor/deserialize-test.js @@ -18,6 +18,8 @@ import '../skinned-sdk'; // Must be first for skinning to work import { parseEvent } from "../../src/editor/deserialize"; import { createPartCreator } from "./mock"; +const FOUR_SPACES = " ".repeat(4); + function htmlMessage(formattedBody, msgtype = "m.text") { return { getContent() { @@ -235,6 +237,26 @@ describe('editor/deserialize', function() { expect(parts[3]).toStrictEqual({ type: "newline", text: "\n" }); expect(parts[4]).toStrictEqual({ type: "plain", text: "3. Finish" }); }); + it('nested unordered lists', () => { + const html = ""; + const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); + expect(parts.length).toBe(5); + expect(parts[0]).toStrictEqual({ type: "plain", text: "- Oak" }); + expect(parts[1]).toStrictEqual({ type: "newline", text: "\n" }); + expect(parts[2]).toStrictEqual({ type: "plain", text: `${FOUR_SPACES}- Spruce` }); + expect(parts[3]).toStrictEqual({ type: "newline", text: "\n" }); + expect(parts[4]).toStrictEqual({ type: "plain", text: `${FOUR_SPACES.repeat(2)}- Birch` }); + }); + it('nested ordered lists', () => { + const html = "
  1. Oak
    1. Spruce
      1. Birch
"; + const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); + expect(parts.length).toBe(5); + expect(parts[0]).toStrictEqual({ type: "plain", text: "1. Oak" }); + expect(parts[1]).toStrictEqual({ type: "newline", text: "\n" }); + expect(parts[2]).toStrictEqual({ type: "plain", text: `${FOUR_SPACES}1. Spruce` }); + expect(parts[3]).toStrictEqual({ type: "newline", text: "\n" }); + expect(parts[4]).toStrictEqual({ type: "plain", text: `${FOUR_SPACES.repeat(2)}1. Birch` }); + }); it('mx-reply is stripped', function() { const html = "foobar"; const parts = normalize(parseEvent(htmlMessage(html), createPartCreator()));