@atlaskit/editor-core
Version:
A package contains Atlassian editor core functionality
105 lines (97 loc) • 3.5 kB
text/typescript
import { NodeSpec, browser } from '../../prosemirror';
import { Definition as Text } from './text';
import { NoMark } from './doc';
/**
* @name codeBlock_node
*/
export interface Definition {
type: 'codeBlock';
content?: Array<Text & NoMark>;
attrs?: {
language?: 'abap' | 'actionscript' | 'ada' | 'arduino' | 'autoit' | 'c' | 'c++' | 'clojure'
| 'coffeescript' | 'csharp' | 'css' | 'cuda' | 'd' | 'dart' | 'delphi' | 'elixir'
| 'erlang' | 'fortran' | 'foxpro' | 'go' | 'groovy' | 'haskell' | 'haxe' | 'html'
| 'java' | 'javascript' | 'julia' | 'kotlin' | 'latex' | 'livescript' | 'lua'
| 'mathematica' | 'matlab' | 'objective-c' | 'objective-j' | 'objectpascal'
| 'ocaml' | 'octave' | 'perl' | 'php' | 'powershell' | 'prolog' | 'puppet'
| 'python' | 'qml' | 'r' | 'racket' | 'restructuredtext' | 'ruby' | 'rust'
| 'sass' | 'scala' | 'scheme' | 'shell' | 'smalltalk' | 'sql' | 'standardml'
| 'swift' | 'tcl' | 'tex' | 'typescript' | 'vala' | 'vbnet' | 'verilog'
| 'vhdl' | 'xml' | 'xquery';
};
}
const getLanguageFromEditorStyle = (dom: HTMLElement): string | undefined => {
return dom.dataset['language'];
};
// example of BB style:
// <div class="codehilite language-javascript"><pre><span>hello world</span><span>\n</span></pre></div>
const getLanguageFromBitbucketStyle = (dom: HTMLElement): string | undefined => {
if (dom && dom.classList.contains('codehilite')) {
// code block html from Bitbucket always contains an extra new line
return extractLanguageFromClass(dom.className);
}
};
const extractLanguageFromClass = (className: string): string | undefined => {
const languageRegex = /(?:^|\s)language-([^\s]+)/;
const result = languageRegex.exec(className);
if (result && result[1]) {
return result[1];
}
};
const removeLastNewLine = (dom: HTMLElement): HTMLElement => {
const parent = dom && dom.parentElement;
if (parent && parent.classList.contains('codehilite')) {
dom.textContent = dom.textContent!.replace(/\n$/, '');
}
return dom;
};
export const codeBlock: NodeSpec = {
attrs: { language: { default: null }, uniqueId: { default: null } },
content: 'text*',
group: 'block',
code: true,
defining: true,
parseDOM: [{
tag: 'pre',
preserveWhitespace: 'full',
getAttrs: (dom: HTMLElement) => {
const language = (
getLanguageFromBitbucketStyle(dom.parentElement!) ||
getLanguageFromEditorStyle(dom.parentElement!) ||
dom.getAttribute('data-language')!
);
dom = removeLastNewLine(dom);
return { language };
}
},
// Handle VSCode paste, it wraps copied content with
// <div style="...white-space: pre;...">
{
tag: 'div[style]',
preserveWhitespace: 'full',
getAttrs: (dom: HTMLElement) => {
if (
dom.style.whiteSpace === 'pre' || dom.style.whiteSpace === 'pre-wrap' ||
(dom.style.fontFamily && dom.style.fontFamily.toLowerCase().indexOf('monospace') > -1)
) {
return {};
}
return false;
}
},
// Handle GitHub/Gist paste
{
tag: 'table[style]',
preserveWhitespace: 'full',
getAttrs: (dom: HTMLElement) => {
if (dom.querySelector('td[class*="blob-code"]')) {
return {};
}
return false;
}
}],
toDOM(node): [string, any, number] {
const className = browser.ie && browser.ie_version <= 11 ? 'ie11' : '';
return ['pre', { 'data-language': node.attrs.language, 'class': className }, 0];
}
};