@atlaskit/editor-core
Version:
A package contains Atlassian editor core functionality
376 lines • 17.9 kB
JavaScript
import { Fragment, Node as PMNode, } from '../../prosemirror';
import parseHtml from './parse-html';
import fixDoc from './fix-doc';
import { bfsOrder, convert, ensureBlocks, } from './util';
import { isSchemaWithLists, isSchemaWithMentions, isSchemaWithCodeBlock, isSchemaWithBlockQuotes, isSchemaWithMedia, isSchemaWithTables, } from './schema';
var JIRATransformer = (function () {
function JIRATransformer(schema, customEncoders, mediaContextInfo) {
this.schema = schema;
this.customEncoders = customEncoders || {};
this.mediaContextInfo = mediaContextInfo;
}
JIRATransformer.prototype.encode = function (node) {
this.doc = this.makeDocument();
this.doc.body.appendChild(this.encodeFragment(node.content));
var html = this.doc.body.innerHTML;
// JIRA encodes empty documents as an empty string
if (html === '<p></p>') {
return '';
}
// Normalise to XHTML style self closing tags.
return html
.replace(/<br><\/br>/g, '<br />')
.replace(/<br>/g, '<br />')
.replace(/<hr><\/hr>/g, '<hr />')
.replace(/<hr>/g, '<hr />')
.replace(/&/g, '&');
};
JIRATransformer.prototype.parse = function (html) {
var convertedNodes = new WeakMap();
var dom = fixDoc(parseHtml(html)).querySelector('body');
var nodes = bfsOrder(dom);
// JIRA encodes empty content as a single nbsp
if (nodes.length === 1 && nodes[0].textContent === '\xa0') {
var schemaNodes = this.schema.nodes;
return schemaNodes.doc.create({}, schemaNodes.paragraph.create());
}
// Process through nodes in reverse (so deepest child elements are first).
for (var i = nodes.length - 1; i >= 0; i--) {
var node = nodes[i];
// for tables we take tbody content, because tbody is not in schema so the whole bfs thing wouldn't work
var targetNode = (node.tagName && node.tagName.toUpperCase() === 'TABLE'
? node.firstChild
: node);
var content_1 = this.getContent(targetNode, convertedNodes);
var candidate = convert(content_1, node, this.schema);
if (typeof candidate !== 'undefined') {
convertedNodes.set(node, candidate);
}
}
var content = this.getContent(dom, convertedNodes);
// Dangling inline nodes can't be directly inserted into a document, so
// we attempt to wrap in a paragraph.
var compatibleContent = this.schema.nodes.doc.validContent(content)
? content
: ensureBlocks(content, this.schema);
return this.schema.nodes.doc.createChecked({}, compatibleContent);
};
/*
* Contructs a struct string of replacement blocks and marks for a given node
*/
JIRATransformer.prototype.getContent = function (node, convertedNodes) {
var fragment = Fragment.fromArray([]);
var childIndex;
for (childIndex = 0; childIndex < node.childNodes.length; childIndex++) {
var child = node.childNodes[childIndex];
var thing = convertedNodes.get(child);
if (thing instanceof Fragment || thing instanceof PMNode) {
fragment = fragment.append(Fragment.from(thing));
}
}
return fragment;
};
JIRATransformer.prototype.encodeNode = function (node) {
var _a = this.schema.nodes, blockquote = _a.blockquote, bulletList = _a.bulletList, codeBlock = _a.codeBlock, hardBreak = _a.hardBreak, heading = _a.heading, listItem = _a.listItem, mention = _a.mention, orderedList = _a.orderedList, paragraph = _a.paragraph, rule = _a.rule, mediaGroup = _a.mediaGroup, media = _a.media, table = _a.table;
if (node.isText) {
return this.encodeText(node);
}
else if (node.type === heading) {
return this.encodeHeading(node);
}
else if (node.type === rule) {
return this.encodeHorizontalRule();
}
else if (node.type === paragraph) {
return this.encodeParagraph(node);
}
else if (node.type === hardBreak) {
return this.encodeHardBreak();
}
if (isSchemaWithLists(this.schema)) {
if (node.type === bulletList) {
return this.encodeBulletList(node);
}
else if (node.type === orderedList) {
return this.encodeOrderedList(node);
}
else if (node.type === listItem) {
return this.encodeListItem(node);
}
}
if (isSchemaWithMentions(this.schema) && node.type === mention) {
return this.encodeMention(node, this.customEncoders.mention);
}
if (isSchemaWithCodeBlock(this.schema) && node.type === codeBlock) {
return this.encodeCodeBlock(node);
}
if (isSchemaWithBlockQuotes(this.schema) && node.type === blockquote) {
return this.encodeBlockQuote(node);
}
if (isSchemaWithMedia(this.schema)) {
if (node.type === mediaGroup) {
return this.encodeMediaGroup(node);
}
else if (node.type === media) {
return this.encodeMedia(node);
}
}
if (isSchemaWithTables(this.schema) && node.type === table) {
return this.encodeTable(node);
}
throw new Error("Unexpected node '" + node.type.name + "' for HTML encoding");
};
JIRATransformer.prototype.makeDocument = function () {
var doc = document.implementation.createHTMLDocument('');
doc.body = doc.createElement('body');
doc.documentElement.appendChild(doc.body);
return doc;
};
JIRATransformer.prototype.encodeFragment = function (fragment) {
var _this = this;
var documentFragment = this.doc.createDocumentFragment();
fragment.forEach(function (node) { return documentFragment.appendChild(_this.encodeNode(node)); });
return documentFragment;
};
JIRATransformer.prototype.encodeHeading = function (node) {
function anchorNameEncode(name) {
var noSpaces = name.replace(/ /g, '');
var uriEncoded = encodeURIComponent(noSpaces);
var specialsEncoded = uriEncoded
.replace(/[!'()*]/g, function (c) { return ('%' + c.charCodeAt(0).toString(16)); });
return specialsEncoded;
}
var elem = this.doc.createElement("h" + node.attrs.level);
var anchor = this.doc.createElement('a');
anchor.setAttribute('name', anchorNameEncode(node.textContent));
elem.appendChild(anchor);
elem.appendChild(this.encodeFragment(node.content));
return elem;
};
JIRATransformer.prototype.encodeParagraph = function (node) {
var elem = this.doc.createElement('p');
elem.appendChild(this.encodeFragment(node.content));
return elem;
};
JIRATransformer.prototype.encodeText = function (node) {
if (node.text) {
var root = this.doc.createDocumentFragment();
var elem = root;
var _a = this.schema.marks, code = _a.code, em = _a.em, link = _a.link, mentionQuery = _a.mentionQuery, strike = _a.strike, strong = _a.strong, subsup = _a.subsup, underline = _a.underline, textColor = _a.textColor;
for (var _i = 0, _b = node.marks; _i < _b.length; _i++) {
var mark = _b[_i];
switch (mark.type) {
case strong:
elem = elem.appendChild(this.doc.createElement('b'));
break;
case em:
elem = elem.appendChild(this.doc.createElement('em'));
break;
case code:
elem = elem.appendChild(this.doc.createElement('tt'));
break;
case strike:
elem = elem.appendChild(this.doc.createElement('del'));
break;
case underline:
elem = elem.appendChild(this.doc.createElement('ins'));
break;
case subsup:
elem = elem.appendChild(this.doc.createElement(mark.attrs['type']));
break;
case link:
var linkElem = this.doc.createElement('a');
var href = mark.attrs['href'];
// Handle external links e.g. links which start with http://, https://, ftp://, //
if (href.match(/\w+:\/\//) || href.match(/^\/\//) || href.match('mailto:')) {
linkElem.setAttribute('class', 'external-link');
linkElem.setAttribute('href', href);
linkElem.setAttribute('rel', 'nofollow');
}
else {
linkElem.setAttribute('href', href);
}
if (mark.attrs['title']) {
linkElem.setAttribute('title', mark.attrs['title']);
}
elem = elem.appendChild(linkElem);
break;
case textColor:
var fontElem = this.doc.createElement('font');
fontElem.setAttribute('color', mark.attrs['color']);
elem = elem.appendChild(fontElem);
break;
case mentionQuery:
break;
default:
throw new Error("Unable to encode mark '" + mark.type.name + "'");
}
}
elem.textContent = node.text;
return root;
}
else {
return this.doc.createTextNode('');
}
};
JIRATransformer.prototype.encodeHardBreak = function () {
return this.doc.createElement('br');
};
JIRATransformer.prototype.encodeHorizontalRule = function () {
return this.doc.createElement('hr');
};
JIRATransformer.prototype.encodeBulletList = function (node) {
var elem = this.doc.createElement('ul');
elem.setAttribute('class', 'alternate');
elem.setAttribute('type', 'disc');
elem.appendChild(this.encodeFragment(node.content));
for (var index = 0; index < elem.childElementCount; index++) {
elem.children[index].setAttribute('data-parent', 'ul');
}
return elem;
};
JIRATransformer.prototype.encodeOrderedList = function (node) {
var elem = this.doc.createElement('ol');
elem.appendChild(this.encodeFragment(node.content));
for (var index = 0; index < elem.childElementCount; index++) {
elem.children[index].setAttribute('data-parent', 'ol');
}
return elem;
};
JIRATransformer.prototype.encodeListItem = function (node) {
var _this = this;
var elem = this.doc.createElement('li');
if (node.content.childCount) {
node.content.forEach(function (childNode) {
if (childNode.type === _this.schema.nodes.bulletList || childNode.type === _this.schema.nodes.orderedList) {
var list = _this.encodeNode(childNode);
/**
* Changing type for nested list:
*
* Second level -> circle
* Third and deeper -> square
*/
if (list instanceof HTMLElement && list.tagName === 'UL') {
list.setAttribute('type', 'circle');
[].forEach.call(list.querySelectorAll('ul'), function (ul) {
ul.setAttribute('type', 'square');
});
}
elem.appendChild(list);
}
else {
// Strip the paragraph node from the list item.
elem.appendChild(_this.encodeFragment(childNode.content));
}
});
}
return elem;
};
JIRATransformer.prototype.encodeMention = function (node, encoder) {
var elem = this.doc.createElement('a');
elem.setAttribute('class', 'user-hover');
elem.setAttribute('href', encoder ? encoder(node.attrs.id) : node.attrs.id);
elem.setAttribute('rel', node.attrs.id);
elem.innerText = node.attrs.text;
return elem;
};
JIRATransformer.prototype.encodeCodeBlock = function (node) {
var elem = this.doc.createElement('div');
elem.setAttribute('class', 'code panel');
var content = this.doc.createElement('div');
content.setAttribute('class', 'codeContent panelContent');
var pre = this.doc.createElement('pre');
// java is default language for JIRA
pre.setAttribute('class', "code-" + (node.attrs.language || 'plain').toLocaleLowerCase());
pre.appendChild(this.encodeFragment(node.content));
content.appendChild(pre);
elem.appendChild(content);
return elem;
};
JIRATransformer.prototype.encodeBlockQuote = function (node) {
var elem = this.doc.createElement('blockquote');
elem.appendChild(this.encodeFragment(node.content));
return elem;
};
JIRATransformer.prototype.encodeMediaGroup = function (node) {
var elem = this.doc.createElement('p');
elem.setAttribute('class', 'mediaGroup');
elem.appendChild(this.encodeFragment(node.content));
return elem;
};
JIRATransformer.prototype.addDataToNode = function (domNode, mediaNode, defaultDisplayType) {
if (defaultDisplayType === void 0) { defaultDisplayType = 'thumbnail'; }
var _a = mediaNode.attrs, id = _a.id, type = _a.type, collection = _a.collection, __fileName = _a.__fileName, __displayType = _a.__displayType;
// Order of dataset matters in IE Edge, please keep the current order
domNode.dataset.attachmentType = __displayType || defaultDisplayType;
if (__fileName) {
domNode.dataset.attachmentName = __fileName;
}
domNode.dataset.mediaServicesType = type;
domNode.dataset.mediaServicesId = id;
if (collection) {
domNode.dataset.mediaServicesCollection = collection;
}
};
JIRATransformer.prototype.buildURLWithContextInfo = function (fileId, contextInfo) {
var clientId = contextInfo.clientId, serviceHost = contextInfo.serviceHost, token = contextInfo.token, collection = contextInfo.collection;
return serviceHost + "/file/" + fileId + "/image?token=" + token + "&client=" + clientId + "&collection=" + collection + "&width=200&height=200&mode=fit";
};
JIRATransformer.prototype.isImageMimeType = function (mimeType) {
return mimeType && mimeType.indexOf('image/') > -1;
};
JIRATransformer.prototype.encodeMedia = function (node) {
// span.image-wrap > a > jira-attachment-thumbnail > img[data-media-*] > content
// span.no-br > a[data-media] > content
var elem = this.doc.createElement('span');
var a = this.doc.createElement('a');
if (node.attrs.__displayType === 'file' ||
!(node.attrs.__displayType || this.isImageMimeType(node.attrs.__fileMimeType))) {
elem.setAttribute('class', 'nobr');
this.addDataToNode(a, node, 'file');
a.textContent = node.attrs.__fileName || '';
}
else {
elem.setAttribute('class', 'image-wrap');
var img = this.doc.createElement('img');
img.setAttribute('alt', node.attrs.__fileName);
// Newly uploaded items have collection
if (node.attrs.collection && this.mediaContextInfo && this.mediaContextInfo.uploadContext) {
img.setAttribute('src', this.buildURLWithContextInfo(node.attrs.id, this.mediaContextInfo.uploadContext));
}
else if (this.mediaContextInfo && this.mediaContextInfo.viewContext) {
img.setAttribute('src', this.buildURLWithContextInfo(node.attrs.id, this.mediaContextInfo.viewContext));
}
this.addDataToNode(img, node);
var jiraThumb = this.doc.createElement('jira-attachment-thumbnail');
jiraThumb.appendChild(img);
a.appendChild(jiraThumb);
}
elem.appendChild(a);
return elem;
};
JIRATransformer.prototype.encodeTable = function (node) {
var _this = this;
var elem = this.doc.createElement('table');
var tbody = this.doc.createElement('tbody');
node.descendants(function (rowNode) {
var rowElement = _this.doc.createElement('tr');
rowNode.descendants(function (colNode) {
var cellType = colNode.type === _this.schema.nodes.tableCell ? 'd' : 'h';
var cellElement = _this.doc.createElement("t" + cellType);
cellElement.setAttribute('class', "confluenceT" + cellType);
cellElement.appendChild(_this.encodeFragment(colNode.content));
rowElement.appendChild(cellElement);
return false;
});
tbody.appendChild(rowElement);
return false;
});
elem.appendChild(tbody);
elem.setAttribute('class', 'confluenceTable');
return elem;
};
return JIRATransformer;
}());
export default JIRATransformer;
//# sourceMappingURL=index.js.map