Skip to content

Commit 2ba2960

Browse files
authored
Merge pull request #5488 from toonijn/refactor-markdown
Refactor code duplication of markdown renderers
2 parents d74049d + 238828e commit 2ba2960

File tree

7 files changed

+139
-87
lines changed

7 files changed

+139
-87
lines changed

notebook/static/base/js/markdown.js

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// Copyright (c) Jupyter Development Team.
2+
// Distributed under the terms of the Modified BSD License.
3+
4+
define([
5+
'jquery',
6+
'base/js/utils',
7+
'base/js/mathjaxutils',
8+
'base/js/security',
9+
'components/marked/lib/marked',
10+
'codemirror/lib/codemirror',
11+
], function($, utils, mathjaxutils, security, marked, CodeMirror){
12+
"use strict";
13+
14+
marked.setOptions({
15+
gfm : true,
16+
tables: true,
17+
langPrefix: "cm-s-ipython language-",
18+
highlight: function(code, lang, callback) {
19+
if (!lang) {
20+
// no language, no highlight
21+
if (callback) {
22+
callback(null, code);
23+
return;
24+
} else {
25+
return code;
26+
}
27+
}
28+
utils.requireCodeMirrorMode(lang, function (spec) {
29+
var el = document.createElement("div");
30+
var mode = CodeMirror.getMode({}, spec);
31+
if (!mode) {
32+
console.log("No CodeMirror mode: " + lang);
33+
callback(null, code);
34+
return;
35+
}
36+
try {
37+
CodeMirror.runMode(code, spec, el);
38+
callback(null, el.innerHTML);
39+
} catch (err) {
40+
console.log("Failed to highlight " + lang + " code", err);
41+
callback(err, code);
42+
}
43+
}, function (err) {
44+
console.log("No CodeMirror mode: " + lang);
45+
console.log("Require CodeMirror mode error: " + err);
46+
callback(null, code);
47+
});
48+
}
49+
});
50+
51+
var mathjax_init_done = false;
52+
function ensure_mathjax_init() {
53+
if(!mathjax_init_done) {
54+
mathjax_init_done = true;
55+
mathjaxutils.init();
56+
}
57+
}
58+
59+
function render(markdown, options, callback) {
60+
/**
61+
* Find a readme in the current directory. Look for files with
62+
* a name like 'readme.md' (case insensitive) or similar and
63+
* mimetype 'text/markdown'.
64+
*
65+
* @param markdown: the markdown text to parse
66+
* @param options
67+
* Object with parameters:
68+
* with_math: the markdown can contain mathematics
69+
* clean_tables: prevent default inline styles for table cells
70+
* sanitize: remove dangerous html (like <script>)
71+
* @param callback
72+
* A function with two arguments (err, html)
73+
* err: null or the error if there was one
74+
* html: the rendered html string, or if {sanitize: true} was used
75+
* a sanitized jQuery object
76+
*/
77+
options = $.extend({
78+
// Apply mathjax transformation
79+
with_math: false,
80+
// Prevent marked from returning inline styles for table cells
81+
clean_tables: false,
82+
// Apply sanitation, this will return a jQuery object.
83+
sanitize: false,
84+
}, options);
85+
var renderer = new marked.Renderer();
86+
if(options.clean_tables) {
87+
renderer.tablecell = function (content, flags) {
88+
var type = flags.header ? 'th' : 'td';
89+
var style = flags.align == null ? '': ' style="text-align: ' + flags.align + '"';
90+
var start_tag = '<' + type + style + '>';
91+
var end_tag = '</' + type + '>\n';
92+
return start_tag + content + end_tag;
93+
};
94+
}
95+
var text = markdown;
96+
var math = null;
97+
if(options.with_math) {
98+
ensure_mathjax_init();
99+
var text_and_math = mathjaxutils.remove_math(markdown);
100+
text = text_and_math[0];
101+
math = text_and_math[1];
102+
}
103+
marked(text, { renderer: renderer }, function (err, html) {
104+
if(!err) {
105+
if(options.with_math) {
106+
html = mathjaxutils.replace_math(html, math);
107+
}
108+
if(options.sanitize) {
109+
html = $(security.sanitize_html_and_parse(html));
110+
}
111+
}
112+
callback(err, html);
113+
});
114+
}
115+
116+
return {'render': render};
117+
});

notebook/static/base/js/namespace.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,13 @@ define(function(){
3232
// expose modules
3333

3434
jprop('utils','base/js/utils')
35+
jprop('mathjaxutils','base/js/mathjaxutils');
3536

3637
//Jupyter.load_extensions = Jupyter.utils.load_extensions;
3738
//
3839
jprop('security','base/js/security');
3940
jprop('keyboard','base/js/keyboard');
4041
jprop('dialog','base/js/dialog');
41-
jprop('mathjaxutils','notebook/js/mathjaxutils');
4242

4343

4444
//// exposed constructors

notebook/static/notebook/js/notebook.js

+3-43
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,17 @@ define([
1212
'base/js/utils',
1313
'base/js/i18n',
1414
'base/js/dialog',
15+
'base/js/markdown',
1516
'./cell',
1617
'./textcell',
1718
'./codecell',
1819
'moment',
1920
'services/config',
2021
'services/sessions/session',
2122
'./celltoolbar',
22-
'components/marked/lib/marked',
2323
'codemirror/lib/codemirror',
2424
'codemirror/addon/runmode/runmode',
25-
'./mathjaxutils',
25+
'base/js/mathjaxutils',
2626
'base/js/keyboard',
2727
'./tooltip',
2828
'./celltoolbarpresets/default',
@@ -40,14 +40,14 @@ define([
4040
utils,
4141
i18n,
4242
dialog,
43+
markdown,
4344
cellmod,
4445
textcell,
4546
codecell,
4647
moment,
4748
configmod,
4849
session,
4950
celltoolbar,
50-
marked,
5151
CodeMirror,
5252
runMode,
5353
mathjaxutils,
@@ -116,46 +116,6 @@ define([
116116

117117
mathjaxutils.init();
118118

119-
if (marked) {
120-
marked.setOptions({
121-
gfm : true,
122-
tables: true,
123-
// FIXME: probably want central config for CodeMirror theme when we have js config
124-
langPrefix: "cm-s-ipython language-",
125-
highlight: function(code, lang, callback) {
126-
if (!lang) {
127-
// no language, no highlight
128-
if (callback) {
129-
callback(null, code);
130-
return;
131-
} else {
132-
return code;
133-
}
134-
}
135-
utils.requireCodeMirrorMode(lang, function (spec) {
136-
var el = document.createElement("div");
137-
var mode = CodeMirror.getMode({}, spec);
138-
if (!mode) {
139-
console.log("No CodeMirror mode: " + lang);
140-
callback(null, code);
141-
return;
142-
}
143-
try {
144-
CodeMirror.runMode(code, spec, el);
145-
callback(null, el.innerHTML);
146-
} catch (err) {
147-
console.log("Failed to highlight " + lang + " code", err);
148-
callback(err, code);
149-
}
150-
}, function (err) {
151-
console.log("No CodeMirror mode: " + lang);
152-
console.log("Require CodeMirror mode error: " + err);
153-
callback(null, code);
154-
});
155-
}
156-
});
157-
}
158-
159119
this.element = $(selector);
160120
this.element.scroll();
161121
this.element.data("notebook", this);

notebook/static/notebook/js/outputarea.js

+7-18
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@ define([
77
'base/js/i18n',
88
'base/js/security',
99
'base/js/keyboard',
10+
'base/js/markdown',
1011
'services/config',
11-
'notebook/js/mathjaxutils',
12-
'components/marked/lib/marked',
13-
], function($, utils, i18n, security, keyboard, configmod, mathjaxutils, marked) {
12+
], function($, utils, i18n, security, keyboard, markdown, configmod) {
1413
"use strict";
1514

1615
/**
@@ -728,23 +727,13 @@ define([
728727
};
729728

730729

731-
var append_markdown = function(markdown, md, element) {
730+
var append_markdown = function(text, md, element) {
732731
var type = MIME_MARKDOWN;
733732
var toinsert = this.create_output_subarea(md, "output_markdown rendered_html", type);
734-
var text_and_math = mathjaxutils.remove_math(markdown);
735-
var text = text_and_math[0];
736-
var math = text_and_math[1];
737-
// Prevent marked from returning inline styles for table cells
738-
var renderer = new marked.Renderer();
739-
renderer.tablecell = function (content, flags) {
740-
var type = flags.header ? 'th' : 'td';
741-
var style = flags.align == null ? '': ' style="text-align: ' + flags.align + '"';
742-
var start_tag = '<' + type + style + '>';
743-
var end_tag = '</' + type + '>\n';
744-
return start_tag + content + end_tag;
745-
};
746-
marked(text, { renderer: renderer }, function (err, html) {
747-
html = mathjaxutils.replace_math(html, math);
733+
markdown.render(text, {
734+
with_math: true,
735+
clean_tables: true
736+
}, function (err, html) {
748737
toinsert.append(html);
749738
});
750739
dblclick_to_reset_size(toinsert.find('img'));

notebook/static/notebook/js/textcell.js

+10-24
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,9 @@ define([
66
'base/js/utils',
77
'base/js/i18n',
88
'notebook/js/cell',
9-
'base/js/security',
9+
'base/js/markdown',
1010
'services/config',
11-
'notebook/js/mathjaxutils',
1211
'notebook/js/celltoolbar',
13-
'components/marked/lib/marked',
1412
'codemirror/lib/codemirror',
1513
'codemirror/mode/gfm/gfm',
1614
'notebook/js/codemirror-ipythongfm',
@@ -20,11 +18,9 @@ define([
2018
utils,
2119
i18n,
2220
cell,
23-
security,
21+
markdown,
2422
configmod,
25-
mathjaxutils,
2623
celltoolbar,
27-
marked,
2824
CodeMirror,
2925
gfm,
3026
ipgfm,
@@ -119,7 +115,6 @@ define([
119115
events: this.events}]);
120116

121117
this.cell_type = this.cell_type || 'text';
122-
mathjaxutils = mathjaxutils;
123118
this.rendered = false;
124119
};
125120

@@ -301,8 +296,9 @@ define([
301296
// can reference an image in markdown (using []() or a
302297
// HTML <img>)
303298
var text = this.get_text();
304-
marked(text, function (err, html) {
305-
html = $(security.sanitize_html_and_parse(html));
299+
markdown.render(text, {
300+
sanitize: true,
301+
}, function (err, html) {
306302
html.find('img[src^="attachment:"]').each(function (i, h) {
307303
h = $(h);
308304
var key = h.attr('src').replace(/^attachment:/, '');
@@ -461,21 +457,11 @@ define([
461457
var text = this.get_text();
462458
var math = null;
463459
if (text === "") { text = this.placeholder; }
464-
var text_and_math = mathjaxutils.remove_math(text);
465-
text = text_and_math[0];
466-
math = text_and_math[1];
467-
// Prevent marked from returning inline styles for table cells
468-
var renderer = new marked.Renderer();
469-
renderer.tablecell = function (content, flags) {
470-
var type = flags.header ? 'th' : 'td';
471-
var style = flags.align == null ? '': ' style="text-align: ' + flags.align + '"';
472-
var start_tag = '<' + type + style + '>';
473-
var end_tag = '</' + type + '>\n';
474-
return start_tag + content + end_tag;
475-
};
476-
marked(text, { renderer: renderer }, function (err, html) {
477-
html = mathjaxutils.replace_math(html, math);
478-
html = $(security.sanitize_html_and_parse(html));
460+
markdown.render(text, {
461+
with_math: true,
462+
clean_tables: true,
463+
sanitize: true,
464+
}, function (err, html) {
479465
// add anchors to headings
480466
html.find(":header").addBack(":header").each(function (i, h) {
481467
h = $(h);

notebook/tests/notebook/markdown.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ casper.notebook_test(function () {
1414
function mathjax_render_test(input_string, result, message){
1515
casper.thenEvaluate(function (text){
1616
window._test_result = null;
17-
require(['notebook/js/mathjaxutils'],function(mathjaxutils){
17+
require(['base/js/mathjaxutils'],function(mathjaxutils){
1818
window._test_result = mathjaxutils.remove_math(text);
1919
});
2020
}, {text: input_string});

0 commit comments

Comments
 (0)