@atlaskit/adf-schema
Version:
Shared package that contains the ADF-schema (json) and ProseMirror node/mark specs
148 lines (143 loc) • 4.68 kB
JavaScript
import { Fragment } from '@atlaskit/editor-prosemirror/model';
import { codeBlock as codeBlockFactory } from '../../next-schema/generated/nodeTypes';
/**
* @name codeBlock_with_no_marks_node
*/
/**
* @name codeBlock_node
*/
var getLanguageFromEditorStyle = function getLanguageFromEditorStyle(dom) {
return dom.getAttribute('data-language') || undefined;
};
// example of BB style:
// <div class="codehilite language-javascript"><pre><span>hello world</span><span>\n</span></pre></div>
var getLanguageFromBitbucketStyle = function getLanguageFromBitbucketStyle(dom) {
if (dom && dom.classList.contains('codehilite')) {
// code block html from Bitbucket always contains an extra new line
return extractLanguageFromClass(dom.className);
}
return;
};
// If there is a child code element, check that for data-language
var getLanguageFromCode = function getLanguageFromCode(dom) {
var firstChild = dom.firstElementChild;
if (firstChild && firstChild.nodeName === 'CODE') {
return firstChild.getAttribute('data-language') || undefined;
}
};
var extractLanguageFromClass = function extractLanguageFromClass(className) {
var languageRegex = /(?:^|\s)language-([^\s]+)/;
var result = languageRegex.exec(className);
if (result && result[1]) {
return result[1];
}
return;
};
var removeLastNewLine = function removeLastNewLine(dom) {
var parent = dom && dom.parentElement;
if (parent && parent.classList.contains('codehilite')) {
dom.textContent = dom.textContent.replace(/\n$/, '');
}
return dom;
};
function parseCodeFromHtml(node) {
var code = '';
node.childNodes.forEach(function (child) {
if (child.nodeType === Node.TEXT_NODE) {
// append text
code += child.nodeValue;
} else if (child.nodeType === Node.ELEMENT_NODE && child instanceof Element) {
var tagName = child.tagName.toLowerCase();
if (tagName === 'div' || tagName === 'p') {
// add a newline before its content, unless it's the first child to avoid leading newlines
if (child.previousElementSibling !== null) {
code += '\n';
}
}
if (tagName === 'br') {
code += '\n';
} else {
code += parseCodeFromHtml(child);
}
}
});
return code;
}
export var codeBlock = codeBlockFactory({
parseDOM: [{
tag: 'pre',
preserveWhitespace: 'full',
getAttrs: function getAttrs(domNode) {
var dom = domNode;
var language = getLanguageFromBitbucketStyle(dom.parentElement) || getLanguageFromEditorStyle(dom.parentElement) || getLanguageFromCode(dom) || dom.getAttribute('data-language');
dom = removeLastNewLine(dom);
return {
language: language
};
}
},
// Handle VSCode, Android Studio paste
// Checking `white-space: pre-wrap` is too aggressive @see ED-2627
{
tag: 'div[style]',
preserveWhitespace: 'full',
getAttrs: function getAttrs(domNode) {
var dom = domNode;
if (dom.style.whiteSpace === 'pre' || dom.style.fontFamily && dom.style.fontFamily.toLowerCase().indexOf('monospace') > -1) {
return {};
}
return false;
},
getContent: function getContent(domNode, schema) {
var code = parseCodeFromHtml(domNode);
return code ? Fragment.from(schema.text(code)) : Fragment.empty;
}
},
// Handle GitHub/Gist paste
{
tag: 'table[style]',
preserveWhitespace: 'full',
getAttrs: function getAttrs(dom) {
if (dom.querySelector('td[class*="blob-code"]')) {
return {};
}
return false;
}
}, {
tag: 'div.code-block',
preserveWhitespace: 'full',
getAttrs: function getAttrs(domNode) {
var dom = domNode;
// TODO: ED-5604 Fix it inside `react-syntax-highlighter`
// Remove line numbers
var lineNumber = dom.querySelectorAll('.react-syntax-highlighter-line-number');
if (lineNumber.length > 0) {
// It's possible to copy without the line numbers too hence this
// `react-syntax-highlighter-line-number` check, so that we don't remove real code
lineNumber.forEach(function (line) {
return line.remove();
});
}
return {};
}
}],
toDOM: function toDOM(node) {
return ['pre', ['code', {
'data-language': node.attrs.language
}, 0]];
}
});
export var toJSON = function toJSON(node) {
return {
attrs: Object.keys(node.attrs).reduce(function (memo, key) {
if (key === 'uniqueId') {
return memo;
}
if (key === 'language' && node.attrs.language === null) {
return memo;
}
memo[key] = node.attrs[key];
return memo;
}, {})
};
};