@atlaskit/editor-wikimarkup-transformer
Version:
Wiki markup transformer for JIRA and Confluence
130 lines (127 loc) • 4.82 kB
JavaScript
import { createParagraphNodeFromInlineNodes, createEmptyParagraphNode } from '../nodes/paragraph';
export function normalizePMNodes(nodes, schema, parentNode) {
return [normalizeMediaGroups, normalizeNestedExpands, normalizeInlineNodes].reduce((currentNodes, normFunc) => normFunc(currentNodes, schema, parentNode), nodes);
}
export function normalizeNestedExpands(nodes, schema, parentNode) {
// When we round-trip through ADF - WikiMarkup - ADF, expands get replaced by strong text.
// That would result in the nested expand being in an invalid situation as it's no longer
// nested in either a table or expand
// This solves the issue for nested expands that sit in the root, which should cover every
// case for Jira software
const output = [];
for (const node of nodes) {
var _node$type;
if ((node === null || node === void 0 ? void 0 : (_node$type = node.type) === null || _node$type === void 0 ? void 0 : _node$type.name) === 'nestedExpand' && parentNode === 'doc') {
output.push(convertNodeToExpand(node, schema));
} else {
output.push(node);
}
}
return output;
}
export function normalizeInlineNodes(nodes, schema, _parentNode) {
const output = [];
let inlineNodeBuffer = [];
for (const node of nodes) {
if (!node.isBlock) {
inlineNodeBuffer.push(node);
continue;
}
if (inlineNodeBuffer.length > 0) {
output.push(...createParagraphNodeFromInlineNodes(inlineNodeBuffer, schema));
}
inlineNodeBuffer = []; // clear buffer
output.push(node);
}
if (inlineNodeBuffer.length > 0) {
output.push(...createParagraphNodeFromInlineNodes(inlineNodeBuffer, schema));
}
if (output.length === 0) {
return [createEmptyParagraphNode(schema)];
}
return output;
}
/**
* Normalize the list of the given nodes for media groups.
* The rule is: if there are consecutive media group nodes (each with a single child media
* node) separated by any space or a single newline, then merge them into one media group
* with multiple child media nodes.
* @param nodes list of nodes to normalize. Must not be null
* @param schema
*/
function normalizeMediaGroups(nodes, schema, _parentNode) {
const output = [];
let mediaGroupBuffer = [];
let separatorBuffer = [];
for (const n of nodes) {
if (n.type.name === 'mediaGroup' && n.childCount === 1) {
mediaGroupBuffer.push(n);
//separator buffer keeps track of the seperator(s) between each mediaGroup nodes,
//so needs resetting every time we encounter a new mediaGroup node
separatorBuffer = [];
continue;
}
if (mediaGroupBuffer.length > 0) {
if (isSignificantSeparatorNode(n, separatorBuffer)) {
output.push(createMergedMediaGroup(mediaGroupBuffer, schema));
output.push(...separatorBuffer);
output.push(n);
mediaGroupBuffer = [];
separatorBuffer = [];
} else {
separatorBuffer.push(n);
}
continue;
}
output.push(n);
}
if (mediaGroupBuffer.length > 0) {
output.push(createMergedMediaGroup(mediaGroupBuffer, schema));
}
// Dump everything else from separator buffer if anything is left
output.push(...separatorBuffer);
return output;
}
/**
* Creates a single mediaGroup whose children are the single media elements from the given mediaGroupNodes.
* @param mediaGroupNodes list of mediaGroups that have a single child each
* @param schema the schema
*/
function createMergedMediaGroup(mediaGroupNodes, schema) {
const {
mediaGroup
} = schema.nodes;
const mediaNodes = mediaGroupNodes.map(v => v.child(0));
return mediaGroup.createChecked({}, mediaNodes);
}
function isSignificantSeparatorNode(n, separatorBuffer) {
return isHardBreak(n, separatorBuffer) || !isEmptyTextNode(n) || isMediaGroupWithMultipleChildren(n);
}
/**
* Existing media groups with more than one child is considered as a significant separator.
*/
function isMediaGroupWithMultipleChildren(n) {
return n.type.name === 'mediaGroup' && n.childCount > 1;
}
/**
* If the current node is a hard break, AND there's already at least
* one hard break in the separator buffer, then we want to return true.
* @param n the current node to examine
* @param separatorBuffer the existing separator buffer.
*/
function isHardBreak(n, separatorBuffer) {
return n.type.name === 'hardBreak' && separatorBuffer.map(v => v.type.name).indexOf('hardBreak') !== -1;
}
function isEmptyTextNode(n) {
return n.textContent !== undefined && n.textContent.trim().length === 0;
}
export function isNextLineEmpty(input) {
// Line with only spaces is considered an empty line
return input.trim().length === 0;
}
function convertNodeToExpand(node, schema) {
const {
expand
} = schema.nodes;
return expand.createChecked(node.attrs, node.content);
}