@atlaskit/editor-confluence-transformer
Version:
Editor Confluence Transformer
403 lines (392 loc) • 13.3 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.addMarks = addMarks;
exports.calcPixelsFromCSSValue = calcPixelsFromCSSValue;
exports.children = children;
exports.createCodeFragment = createCodeFragment;
exports.encodeMacroParams = void 0;
exports.findTraversalPath = findTraversalPath;
exports.getAcName = getAcName;
exports.getAcTagChildNodes = getAcTagChildNodes;
exports.getAcTagContent = getAcTagContent;
exports.getAcTagNode = getAcTagNode;
exports.getContent = getContent;
exports.getExtensionMacroParams = void 0;
exports.getMacroAttribute = getMacroAttribute;
exports.getMacroParameters = getMacroParameters;
exports.getNodeMarkOfType = getNodeMarkOfType;
exports.getNodeName = getNodeName;
exports.hasClass = hasClass;
exports.mapPanelTypeToPm = exports.mapPanelTypeToCxhtml = void 0;
exports.marksFromStyle = marksFromStyle;
exports.parseMacro = parseMacro;
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _model = require("@atlaskit/editor-prosemirror/model");
var _adfSchema = require("@atlaskit/adf-schema");
var _encodeCxhtml = require("./encode-cxhtml");
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
/**
* Deduce a set of marks from a style declaration.
*/
function marksFromStyle(schema, style) {
var marks = [];
// eslint-disable-next-line no-labels
styles: for (var i = 0; i < style.length; i++) {
var name = style.item(i);
var value = style.getPropertyValue(name);
switch (name) {
case 'text-decoration-color':
case 'text-decoration-style':
// eslint-disable-next-line no-labels
continue styles;
case 'text-decoration-line':
case 'text-decoration':
switch (value) {
case 'line-through':
marks = schema.marks.strike.create().addToSet(marks);
// eslint-disable-next-line no-labels
continue styles;
}
break;
case 'color':
marks = schema.marks.textColor.create({
color: (0, _adfSchema.normalizeHexColor)(value)
}).addToSet(marks);
// eslint-disable-next-line no-labels
continue styles;
case 'background-color':
marks = schema.marks.backgroundColor.create({
color: (0, _adfSchema.normalizeHexColor)(value)
}).addToSet(marks);
// eslint-disable-next-line no-labels
continue styles;
case 'font-family':
if (value === 'monospace') {
marks = schema.marks.code.create().addToSet(marks);
// eslint-disable-next-line no-labels
continue styles;
}
}
throw new Error("Unable to derive a mark for CSS ".concat(name, ": ").concat(value));
}
return marks;
}
/**
* Create a fragment by adding a set of marks to each node.
*/
function addMarks(fragment, marks) {
var result = fragment;
for (var i = 0; i < fragment.childCount; i++) {
var child = result.child(i);
var newChild = child;
var _iterator = _createForOfIteratorHelper(marks),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var mark = _step.value;
newChild = newChild.mark(mark.addToSet(newChild.marks));
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
result = result.replaceChild(i, newChild);
}
return result;
}
function getNodeMarkOfType(node, markType) {
if (!node.marks) {
return null;
}
var foundMarks = node.marks.filter(function (mark) {
return mark.type.name === markType.name;
});
return foundMarks.length ? foundMarks[foundMarks.length - 1] : null;
}
/**
*
* Traverse the DOM node and build an array of the breadth-first-search traversal
* through the tree.
*
* Detection of supported vs unsupported content happens at this stage. Unsupported
* nodes do not have their children traversed. Doing this avoids attempting to
* decode unsupported content descendents into ProseMirror nodes.
*/
function findTraversalPath(roots) {
var inqueue = (0, _toConsumableArray2.default)(roots);
var outqueue = [];
var elem;
// Ignored via go/ees005
// eslint-disable-next-line no-unmodified-loop-condition, no-cond-assign
while (elem = inqueue.shift()) {
outqueue.push(elem);
var _children = void 0;
// Ignored via go/ees005
// eslint-disable-next-line no-cond-assign
if (isNodeSupportedContent(elem) && (_children = childrenOfNode(elem))) {
var childIndex = void 0;
for (childIndex = 0; childIndex < _children.length; childIndex++) {
var child = _children[childIndex];
inqueue.push(child);
}
}
}
return outqueue;
}
function childrenOfNode(node) {
var tag = getNodeName(node);
if (tag === 'AC:STRUCTURED-MACRO') {
return getAcTagChildNodes(node, 'AC:RICH-TEXT-BODY');
}
return node.childNodes;
}
/**
* Return an array containing the child nodes in a fragment.
*
* @param fragment
*/
function children(fragment) {
var nodes = [];
for (var i = 0; i < fragment.childCount; i++) {
nodes.push(fragment.child(i));
}
return nodes;
}
/**
* Quickly determine if a DOM node is supported (i.e. can be represented in the ProseMirror
* schema).
*
* When a node is not supported, its children are not traversed — instead the entire node content
* is stored inside an `unsupportedInline`.
*
* @param node
*/
function isNodeSupportedContent(node) {
if (node.nodeType === Node.TEXT_NODE || node.nodeType === Node.CDATA_SECTION_NODE) {
return true;
}
if (node instanceof HTMLElement || node.nodeType === Node.ELEMENT_NODE) {
var tag = getNodeName(node);
switch (tag) {
case 'DEL':
case 'S':
case 'B':
case 'STRONG':
case 'I':
case 'EM':
case 'CODE':
case 'SUB':
case 'SUP':
case 'U':
case 'BLOCKQUOTE':
case 'SPAN':
case 'H1':
case 'H2':
case 'H3':
case 'H4':
case 'H5':
case 'H6':
case 'BR':
case 'HR':
case 'UL':
case 'OL':
case 'LI':
case 'P':
case 'A':
case 'FAB:MENTION':
case 'FAB:MEDIA-GROUP':
case 'FAB:MEDIA-SINGLE':
case 'FAB:MEDIA':
case 'AC:INLINE-COMMENT-MARKER':
case 'AC:STRUCTURED-MACRO':
return true;
}
}
return false;
}
function getAcName(node) {
return node.getAttribute('ac:name') || '';
}
function getNodeName(node) {
return node.nodeName.toUpperCase();
}
function getAcTagContent(node, tagName) {
for (var i = 0, len = node.childNodes.length; i < len; i++) {
var child = node.childNodes[i];
if (getNodeName(child) === tagName) {
return child.textContent;
}
}
return null;
}
function getAcTagChildNodes(node, tagName) {
var child = getAcTagNode(node, tagName);
if (child) {
// return html collection only if childNodes are found
return child.childNodes.length ? child.childNodes : null;
}
return null;
}
function getAcTagNode(node, tagName) {
for (var i = 0, len = node.childNodes.length; i < len; i++) {
var child = node.childNodes[i];
if (getNodeName(child).toLowerCase() === tagName) {
return child;
}
}
return null;
}
function getMacroAttribute(node, attribute) {
return node.getAttribute('data-macro-' + attribute) || '';
}
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function getMacroParameters(node) {
var params = {};
getMacroAttribute(node, 'parameters').split('|').forEach(function (paramStr) {
var param = paramStr.split('=');
if (param.length) {
params[param[0]] = param[1];
}
});
return params;
}
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/max-params
function createCodeFragment(schema, codeContent, language, title) {
var content = [];
if (!!title) {
var titleNode = schema.nodes.heading.createChecked({
level: 5
}, schema.text(title));
content.push(titleNode);
}
var codeBlockNode = schema.nodes.codeBlock.createChecked({
language: language
}, schema.text(codeContent));
content.push(codeBlockNode);
return _model.Fragment.from(content);
}
function hasClass(node, className) {
if (node && node.className) {
return node.className.indexOf(className) > -1;
}
return false;
}
/**
* Calculates the size of an element in a given dimension, using its CSS property value,
* which may be based to the parent element's dimensions.
*
* @param value Value for a CSS property. Supported units are px and %.
* @param parentPixels The dimension of the container element, in pixels.
*/
function calcPixelsFromCSSValue(value, parentPixels) {
if (value.substr(-2) === 'px') {
return parseInt(value.slice(0, -2), 10);
} else if (value.substr(-1) === '%') {
return Math.round(parseInt(value.slice(0, -1), 10) / 100.0 * parentPixels);
}
return 0;
}
/*
* Constructs a struct string of replacement blocks and marks for a given node
*/
function getContent(node, convertedNodes) {
var fragment = _model.Fragment.fromArray([]);
for (var childIndex = 0; childIndex < node.childNodes.length; childIndex++) {
var child = node.childNodes[childIndex];
var thing = convertedNodes.get(child);
if (thing instanceof _model.Fragment || thing instanceof _model.Node) {
fragment = fragment.append(_model.Fragment.from(thing));
}
}
return fragment;
}
function parseMacro(node) {
var macroName = getAcName(node) || 'Unnamed Macro';
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
var macroId = node.getAttributeNS(_encodeCxhtml.AC_XMLNS, 'macro-id');
var properties = {};
var params = {};
for (var i = 0, len = node.childNodes.length; i < len; i++) {
var child = node.childNodes[i];
var nodeName = getNodeName(child).toLowerCase();
if (child.nodeType === 3) {
continue;
}
var value = child.textContent;
// example: <ac:parameter ac:name=\"colour\">Red</ac:parameter>
if (nodeName === 'ac:parameter') {
var key = getAcName(child);
if (key) {
params[key] = value;
}
} else {
// example: <fab:placeholder-url>, <fab:display-type>, <ac:rich-text-body>
properties[nodeName] = value;
}
}
return {
macroId: macroId,
macroName: macroName,
properties: properties,
params: params
};
}
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-explicit-any
var getExtensionMacroParams = exports.getExtensionMacroParams = function getExtensionMacroParams(params) {
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-explicit-any
var macroParams = {};
Object.keys(params).forEach(function (key) {
/** Safe check for empty keys */
if (key) {
macroParams[key] = {
value: params[key]
};
}
});
return macroParams;
};
var mapPanelTypeToPm = exports.mapPanelTypeToPm = function mapPanelTypeToPm(panelType) {
switch (panelType) {
case 'warning':
return 'error';
case 'note':
return 'warning';
case 'tip':
return 'success';
}
return panelType;
};
var mapPanelTypeToCxhtml = exports.mapPanelTypeToCxhtml = function mapPanelTypeToCxhtml(panelType) {
switch (panelType) {
case 'error':
return 'warning';
case 'warning':
return 'note';
case 'success':
return 'tip';
case 'note':
return 'panel';
}
return panelType;
};
var encodeMacroParams = exports.encodeMacroParams = function encodeMacroParams(doc, params) {
var elem = doc.createDocumentFragment();
Object.keys(params).forEach(function (name) {
var el = doc.createElementNS(_encodeCxhtml.AC_XMLNS, 'ac:parameter');
el.setAttributeNS(_encodeCxhtml.AC_XMLNS, 'ac:name', name);
el.textContent = params[name].value;
elem.appendChild(el);
});
return elem;
};