import { DOMParser, Node } from "prosemirror-model"; import { Step } from "prosemirror-transform"; import { compose } from "./compose"; import { RefsFragment, RefsNode } from "./composing"; import { schema } from "./schema"; export function parseTextToRefsFragment(text: string): RefsFragment { return compose.fragment( ...splitParagraphs(text) .map(p => p.split(/\n/g)) .map(pLines => { const pContent: RefsNode[] = []; if (pLines.length > 0) { const [firstLine] = pLines.splice(0, 1); // It's not valid to have empty text nodes, so empty lines are // simply left represented as a br node. if (firstLine.length > 0) { pContent.push(compose.text(firstLine)); } // The first line has been pulled out already, so now just iterate // over the rest and prepend each with a br. for (const pLine of pLines) { pContent.push(compose.br()); if (pLine.length > 0) { pContent.push(compose.text(pLine)); } } } return compose.p(...pContent); }) ); } export function parseText(text: string): Node { return compose.doc(parseTextToRefsFragment(text)).node; } export function parseHtml(htmlElement: HTMLElement): Node { const domParser = DOMParser.fromSchema(schema); return domParser.parse(htmlElement); } export function nodeFromJson(json: {}): Node { return schema.nodeFromJSON(json); } export function stepFromJson(step: {}): Step { return Step.fromJSON(schema, step); } /** * Split text into paragraphs, handling both Windows (\r\n) and UNIX (\n) style. */ function splitParagraphs(text: string): string[] { return ( text // Normalise line endings to simplify the remainder of the logic. .replace(/\r\n/g, "\n") .split(/\n\n/g) // Paragraphs are sometimes separated with three new line characters (i.e. // two visible empty lines) rather than just two (one visible line). // // To fix it, we strip any leading new line from paragraphs. .map(line => (line.substr(0, 1) === "\n" ? line.substr(1) : line)) .map(line => (line.substr(line.length - 1, 1) == "\n" ? line.substr(0, line.length - 1) : line)) ); }