Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Commit

Permalink
Merge branches 't/ckeditor5/5988' and 't/ckeditor5/6007' into github-rte
Browse files Browse the repository at this point in the history
# Conflicts:
#	package.json
  • Loading branch information
fredck committed May 2, 2020
3 parents 15bacf5 + 61b514a + c155acc commit 4df9c75
Show file tree
Hide file tree
Showing 26 changed files with 538 additions and 2,568 deletions.
5 changes: 4 additions & 1 deletion .gitignore
@@ -1 +1,4 @@
node_modules/
/node_modules/
/build/
/package-lock.json
/yarn.lock
6 changes: 5 additions & 1 deletion package.json
Expand Up @@ -10,7 +10,11 @@
"ckeditor5-plugin"
],
"dependencies": {
"@ckeditor/ckeditor5-engine": "^19.0.0"
"@ckeditor/ckeditor5-core": "^19.0.0",
"@ckeditor/ckeditor5-engine": "^19.0.0",
"marked": "^0.7.0",
"turndown": "^6.0.0",
"turndown-plugin-gfm": "^1.0.2"
},
"devDependencies": {
"eslint": "^5.5.0",
Expand Down
31 changes: 17 additions & 14 deletions src/gfmdataprocessor.js
Expand Up @@ -7,11 +7,10 @@
* @module markdown-gfm/gfmdataprocessor
*/

import marked from './lib/marked/marked';
import toMarkdown from './lib/to-markdown/to-markdown';
import HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';
import GFMRenderer from './lib/marked/renderer';
import converters from './lib/to-markdown/converters';

import markdown2html from './markdown2html/markdown2html';
import html2markdown, { turndownService } from './html2markdown/html2markdown';

/**
* This data processor implementation uses GitHub Flavored Markdown as input/output data.
Expand All @@ -36,21 +35,26 @@ export default class GFMDataProcessor {
this._htmlDP = new HtmlDataProcessor( document );
}

/**
* Keeps the specified element in the output as HTML. This is useful if the editor contains
* features that produce HTML that are not part of the markdon standards.
*
* By default, all HTML tags are removed.
*
* @param element {String} The element name to be kept.
*/
keepHtml( element ) {
turndownService.keep( [ element ] );
}

/**
* Converts the provided Markdown string to view tree.
*
* @param {String} data A Markdown string.
* @returns {module:engine/view/documentfragment~DocumentFragment} The converted view element.
*/
toView( data ) {
const html = marked.parse( data, {
gfm: true,
breaks: true,
tables: true,
xhtml: true,
renderer: new GFMRenderer()
} );

const html = markdown2html( data );
return this._htmlDP.toView( html );
}

Expand All @@ -63,7 +67,6 @@ export default class GFMDataProcessor {
*/
toData( viewFragment ) {
const html = this._htmlDP.toData( viewFragment );

return toMarkdown( html, { gfm: true, converters } );
return html2markdown( html );
}
}
82 changes: 82 additions & 0 deletions src/html2markdown/html2markdown.js
@@ -0,0 +1,82 @@
/**
* @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md.
*/

import TurndownService from 'turndown';
import { gfm } from 'turndown-plugin-gfm';

// Overrides the escape() method, enlarging it.
{
const originalEscape = TurndownService.prototype.escape;
TurndownService.prototype.escape = function( string ) {
// Urls should not be escaped. Our strategy is using a regex to find them and escape everything
// which is out of the matches parts.

// eslint-disable-next-line max-len
const regex = /\b(?:https?:\/\/|www\.)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()[\]{};:'".,<>?«»“”‘’])/g;

let escaped = '';
let lastIndex = 0;
let m;
do {
m = regex.exec( string );

// The substring should to to the matched index or, if nothing found, the end of the string.
const index = m ? m.index : string.length;

// Append the substring between the last match and the current one (if anything).
if ( index > lastIndex ) {
escaped += escape( string.substring( lastIndex, index ) );
}

// Append the match itself now, if anything.
m && ( escaped += m[ 0 ] );

lastIndex = regex.lastIndex;
}
while ( m );

return escaped;

function escape( string ) {
string = originalEscape( string );

// Escape "<".
string = string.replace( /</g, '\\<' );

return string;
}
};
}

const turndownService = new TurndownService( {
codeBlockStyle: 'fenced',
hr: '---',
headingStyle: 'atx'
} );

turndownService.use( [
gfm,
todoList
] );

export default function html2markdown( html ) {
return turndownService.turndown( html );
}

export { turndownService };

// This is a copy of the original taskListItems rule from turdown-plugin-gfm, with minor changes.
function todoList( turndownService ) {
turndownService.addRule( 'taskListItems', {
filter( node ) {
return node.type === 'checkbox' &&
// Changes here as CKEditor outputs a deeper structure.
( node.parentNode.nodeName === 'LI' || node.parentNode.parentNode.nodeName === 'LI' );
},
replacement( content, node ) {
return ( node.checked ? '[x]' : '[ ]' ) + ' ';
}
} );
}

0 comments on commit 4df9c75

Please sign in to comment.