UNPKG

@atlaskit/adf-schema

Version:

Shared package that contains the ADF-schema (json) and ProseMirror node/mark specs

147 lines (141 loc) 4.29 kB
import { Fragment } from 'prosemirror-model'; /** * @name codeBlock_node */ /** * @name codeBlock_with_no_marks_node */ /** * @name codeBlock_with_marks_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; }; export var codeBlock = { attrs: { language: { default: null }, uniqueId: { default: null } }, content: '(text | unsupportedInline)*', marks: 'unsupportedMark unsupportedNodeAttribute', group: 'block', code: true, defining: true, 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 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; }, // @see ED-5682 getContent: function getContent(domNode, schema) { var dom = domNode; var code = Array.from(dom.children).map(function (child) { return child.textContent; }).filter(function (x) { return x !== undefined; }).join('\n'); 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; }, {}) }; };