@atlaskit/editor-core
Version:
A package contains Atlassian editor core functionality
268 lines • 10.7 kB
JavaScript
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