UNPKG

@atlaskit/editor-core

Version:

A package contains Atlassian editor core functionality

268 lines • 10.7 kB
import * as tslib_1 from "tslib"; import { Fragment, Slice } from '../'; import matches from './matches'; import sampleSchema from './schema'; /** * ProseMirror doesn't support empty text nodes, which can be quite * inconvenient when you want to capture a position ref without introducing * text. * * Take a couple of examples: * * p('{<>}') * p('Hello ', '{<>}', 'world!') * * After the ref syntax is stripped you're left with: * * p('') * p('Hello ', '', 'world!') * * This violates the rule of text nodes being non-empty. This class solves the * problem by providing an alternative data structure that *only* stores refs, * and can be used in scenarios where an empty text would be forbidden. * * This is done under the hood when using `text()` factory, and instead of * always returning a text node, it'll instead return one of two things: * * - a text node -- when given a non-empty string * - a refs tracker -- when given a string that *only* contains refs. */ var RefsTracker = (function () { function RefsTracker() { } return RefsTracker; }()); export { RefsTracker }; /** * Create a text node. * * Special markers called "refs" can be put in the text. Refs provide a way to * declaratively describe a position within some text, and then access the * position in the resulting node. */ export function text(value, schema) { var stripped = ''; var textIndex = 0; var refs = {}; // Helpers var isEven = function (n) { return n % 2 === 0; }; for (var _i = 0, _a = matches(value, /([\\]+)?{(\w+|<|>|<>)}/g); _i < _a.length; _i++) { var match = _a[_i]; var refToken = match[0], skipChars = match[1], refName = match[2]; var index = match.index; var skipLen = skipChars && skipChars.length; if (skipLen) { if (isEven(skipLen)) { index += (skipLen / 2); } else { stripped += value.slice(textIndex, index + ((skipLen - 1) / 2)); stripped += value.slice(index + skipLen, index + refToken.length); textIndex = index + refToken.length; continue; } } stripped += value.slice(textIndex, index); refs[refName] = stripped.length; textIndex = match.index + refToken.length; } stripped += value.slice(textIndex); var node = stripped === '' ? new RefsTracker() : schema.text(stripped); node.refs = refs; return node; } /** * Offset ref position values by some amount. */ export function offsetRefs(refs, offset) { var result = {}; for (var name_1 in refs) { result[name_1] = refs[name_1] + offset; } return result; } /** * Given a collection of nodes, sequence them in an array and return the result * along with the updated refs. */ export function sequence() { var content = []; for (var _i = 0; _i < arguments.length; _i++) { content[_i] = arguments[_i]; } var position = 0; var refs = {}; var nodes = []; // It's bizarre that this is necessary. An if/else in the for...of should have // sufficient but it did not work at the time of writing. var isRefsTracker = function (n) { return n instanceof RefsTracker; }; var isRefsNode = function (n) { return !isRefsTracker(n); }; for (var _a = 0, content_1 = content; _a < content_1.length; _a++) { var node = content_1[_a]; if (isRefsTracker(node)) { refs = tslib_1.__assign({}, refs, offsetRefs(node.refs, position)); } if (isRefsNode(node)) { var thickness = node.isText ? 0 : 1; refs = tslib_1.__assign({}, refs, offsetRefs(node.refs, position + thickness)); position += node.nodeSize; nodes.push(node); } } return { nodes: nodes, refs: refs }; } /** * Given a jagged array, flatten it down to a single level. */ export function flatten(deep) { var flat = []; for (var _i = 0, deep_1 = deep; _i < deep_1.length; _i++) { var item = deep_1[_i]; if (Array.isArray(item)) { flat.splice.apply(flat, [flat.length, 0].concat(item)); } else { flat.push(item); } } return flat; } /** * Coerce builder content into ref nodes. */ export function coerce(content, schema) { var refsContent = content .map(function (item) { return typeof item === 'string' ? text(item, schema) : item; }); return sequence.apply(void 0, flatten(refsContent)); } /** * Create a factory for nodes. */ export function nodeFactory(type, attrs) { if (attrs === void 0) { attrs = {}; } return function () { var content = []; for (var _i = 0; _i < arguments.length; _i++) { content[_i] = arguments[_i]; } var _a = coerce(content, type.schema), nodes = _a.nodes, refs = _a.refs; var node = type.create(attrs, nodes); node.refs = refs; return node; }; } /** * Create a factory for marks. */ export function markFactory(type, attrs) { if (attrs === void 0) { attrs = {}; } var mark = type.create(attrs); return function () { var content = []; for (var _i = 0; _i < arguments.length; _i++) { content[_i] = arguments[_i]; } var nodes = coerce(content, type.schema).nodes; return nodes .map(function (node) { if (mark.type.isInSet(node.marks)) { return node; } else { var refNode = node.mark(mark.addToSet(node.marks)); refNode.refs = node.refs; return refNode; } }); }; } export var createCell = function (colspan, rowspan) { return td({ colspan: colspan, rowspan: rowspan })(p('x')); }; export var createHeaderCell = function (colspan, rowspan) { return th({ colspan: colspan, rowspan: rowspan })(p('x')); }; export var doc = nodeFactory(sampleSchema.nodes.doc, {}); export var p = nodeFactory(sampleSchema.nodes.paragraph, {}); export var blockquote = nodeFactory(sampleSchema.nodes.blockquote, {}); export var h1 = nodeFactory(sampleSchema.nodes.heading, { level: 1 }); export var h2 = nodeFactory(sampleSchema.nodes.heading, { level: 2 }); export var h3 = nodeFactory(sampleSchema.nodes.heading, { level: 3 }); export var h4 = nodeFactory(sampleSchema.nodes.heading, { level: 4 }); export var h5 = nodeFactory(sampleSchema.nodes.heading, { level: 5 }); export var h6 = nodeFactory(sampleSchema.nodes.heading, { level: 6 }); export var li = nodeFactory(sampleSchema.nodes.listItem, {}); export var ul = nodeFactory(sampleSchema.nodes.bulletList, {}); export var ol = nodeFactory(sampleSchema.nodes.orderedList, {}); export var br = sampleSchema.nodes.hardBreak.createChecked(); export var panel = nodeFactory(sampleSchema.nodes.panel, {}); export var panelNote = nodeFactory(sampleSchema.nodes.panel, { panelType: 'note' }); export var plain = nodeFactory(sampleSchema.nodes.plain, {}); export var hardBreak = nodeFactory(sampleSchema.nodes.hardBreak, {}); // tslint:disable-next-line:variable-name export var code_block = function (attrs) { if (attrs === void 0) { attrs = {}; } return nodeFactory(sampleSchema.nodes.codeBlock, attrs); }; export var img = function (attrs) { return sampleSchema.nodes.image.createChecked(attrs); }; export var emoji = function (attrs) { var emojiNodeAttrs = { shortName: attrs.shortName, id: attrs.id, text: attrs.fallback || attrs.shortName, }; return sampleSchema.nodes.emoji.createChecked(emojiNodeAttrs); }; export var mention = function (attrs) { return sampleSchema.nodes.mention.createChecked(attrs); }; export var hr = sampleSchema.nodes.rule.createChecked(); export var em = markFactory(sampleSchema.marks.em, {}); export var subsup = function (attrs) { return markFactory(sampleSchema.marks.subsup, attrs); }; export var underline = markFactory(sampleSchema.marks.underline, {}); export var strong = markFactory(sampleSchema.marks.strong, {}); export var code = markFactory(sampleSchema.marks.code, {}); export var strike = markFactory(sampleSchema.marks.strike, {}); export var mentionQuery = function (attrs) { if (attrs === void 0) { attrs = { active: true }; } return markFactory(sampleSchema.marks.mentionQuery, attrs ? attrs : {}); }; export var a = function (attrs) { return markFactory(sampleSchema.marks.link, attrs); }; export var fragment = function () { var content = []; for (var _i = 0; _i < arguments.length; _i++) { content[_i] = arguments[_i]; } return flatten(content); }; export var slice = function () { var content = []; for (var _i = 0; _i < arguments.length; _i++) { content[_i] = arguments[_i]; } return new Slice(Fragment.from(coerce(content, sampleSchema).nodes), 0, 0); }; export var emojiQuery = markFactory(sampleSchema.marks.emojiQuery, {}); export var singleImage = function (attrs) { if (attrs === void 0) { attrs = {}; } return nodeFactory(sampleSchema.nodes.singleImage, attrs); }; export var mediaGroup = nodeFactory(sampleSchema.nodes.mediaGroup); export var media = function (attrs) { return sampleSchema.nodes.media.create(attrs); }; export var textColor = function (attrs) { return markFactory(sampleSchema.marks.textColor, attrs); }; export var table = nodeFactory(sampleSchema.nodes.table, {}); export var tr = nodeFactory(sampleSchema.nodes.tableRow, {}); export var td = function (attrs) { return nodeFactory(sampleSchema.nodes.tableCell, attrs); }; export var th = function (attrs) { return nodeFactory(sampleSchema.nodes.tableHeader, attrs); }; export var tdEmpty = td({})(p('')); export var thEmpty = th({})(p('')); export var tdCursor = td({})(p('{<>}')); export var thCursor = th({})(p('{<>}')); export var td11 = createCell(1, 1); export var th11 = createHeaderCell(1, 1); export var decisionList = nodeFactory(sampleSchema.nodes.decisionList, {}); export var decisionItem = nodeFactory(sampleSchema.nodes.decisionItem, {}); export var taskList = nodeFactory(sampleSchema.nodes.taskList, {}); export var taskItem = nodeFactory(sampleSchema.nodes.taskItem, {}); export var confluenceUnsupportedBlock = function (cxhtml) { return nodeFactory(sampleSchema.nodes.confluenceUnsupportedBlock, { cxhtml: cxhtml })(); }; export var confluenceUnsupportedInline = function (cxhtml) { return nodeFactory(sampleSchema.nodes.confluenceUnsupportedInline, { cxhtml: cxhtml })(); }; export var confluenceJiraIssue = function (attrs) { return sampleSchema.nodes.confluenceJiraIssue.create(attrs); }; //# sourceMappingURL=schema-builder.js.map