##// END OF EJS Templates
Merge pull request #6800 from takluyver/mdcell-render-event...
Min RK -
r18503:0c4d59eb merge
parent child Browse files
Show More
@@ -1,424 +1,425 b''
1 // Copyright (c) IPython Development Team.
1 // Copyright (c) IPython Development Team.
2 // Distributed under the terms of the Modified BSD License.
2 // Distributed under the terms of the Modified BSD License.
3
3
4 define([
4 define([
5 'base/js/namespace',
5 'base/js/namespace',
6 'base/js/utils',
6 'base/js/utils',
7 'jquery',
7 'jquery',
8 'notebook/js/cell',
8 'notebook/js/cell',
9 'base/js/security',
9 'base/js/security',
10 'notebook/js/mathjaxutils',
10 'notebook/js/mathjaxutils',
11 'notebook/js/celltoolbar',
11 'notebook/js/celltoolbar',
12 'components/marked/lib/marked',
12 'components/marked/lib/marked',
13 'codemirror/lib/codemirror',
13 'codemirror/lib/codemirror',
14 'codemirror/mode/gfm/gfm',
14 'codemirror/mode/gfm/gfm',
15 'notebook/js/codemirror-ipythongfm'
15 'notebook/js/codemirror-ipythongfm'
16 ], function(IPython,utils , $, cell, security, mathjaxutils, celltoolbar, marked, CodeMirror, gfm, ipgfm) {
16 ], function(IPython,utils , $, cell, security, mathjaxutils, celltoolbar, marked, CodeMirror, gfm, ipgfm) {
17 "use strict";
17 "use strict";
18 var Cell = cell.Cell;
18 var Cell = cell.Cell;
19
19
20 var TextCell = function (options) {
20 var TextCell = function (options) {
21 // Constructor
21 // Constructor
22 //
22 //
23 // Construct a new TextCell, codemirror mode is by default 'htmlmixed',
23 // Construct a new TextCell, codemirror mode is by default 'htmlmixed',
24 // and cell type is 'text' cell start as not redered.
24 // and cell type is 'text' cell start as not redered.
25 //
25 //
26 // Parameters:
26 // Parameters:
27 // options: dictionary
27 // options: dictionary
28 // Dictionary of keyword arguments.
28 // Dictionary of keyword arguments.
29 // events: $(Events) instance
29 // events: $(Events) instance
30 // config: dictionary
30 // config: dictionary
31 // keyboard_manager: KeyboardManager instance
31 // keyboard_manager: KeyboardManager instance
32 // notebook: Notebook instance
32 // notebook: Notebook instance
33 options = options || {};
33 options = options || {};
34
34
35 // in all TextCell/Cell subclasses
35 // in all TextCell/Cell subclasses
36 // do not assign most of members here, just pass it down
36 // do not assign most of members here, just pass it down
37 // in the options dict potentially overwriting what you wish.
37 // in the options dict potentially overwriting what you wish.
38 // they will be assigned in the base class.
38 // they will be assigned in the base class.
39 this.notebook = options.notebook;
39 this.notebook = options.notebook;
40 this.events = options.events;
40 this.events = options.events;
41 this.config = options.config;
41 this.config = options.config;
42
42
43 // we cannot put this as a class key as it has handle to "this".
43 // we cannot put this as a class key as it has handle to "this".
44 var cm_overwrite_options = {
44 var cm_overwrite_options = {
45 onKeyEvent: $.proxy(this.handle_keyevent,this)
45 onKeyEvent: $.proxy(this.handle_keyevent,this)
46 };
46 };
47 var config = utils.mergeopt(TextCell, this.config, {cm_config:cm_overwrite_options});
47 var config = utils.mergeopt(TextCell, this.config, {cm_config:cm_overwrite_options});
48 Cell.apply(this, [{
48 Cell.apply(this, [{
49 config: config,
49 config: config,
50 keyboard_manager: options.keyboard_manager,
50 keyboard_manager: options.keyboard_manager,
51 events: this.events}]);
51 events: this.events}]);
52
52
53 this.cell_type = this.cell_type || 'text';
53 this.cell_type = this.cell_type || 'text';
54 mathjaxutils = mathjaxutils;
54 mathjaxutils = mathjaxutils;
55 this.rendered = false;
55 this.rendered = false;
56 };
56 };
57
57
58 TextCell.prototype = Object.create(Cell.prototype);
58 TextCell.prototype = Object.create(Cell.prototype);
59
59
60 TextCell.options_default = {
60 TextCell.options_default = {
61 cm_config : {
61 cm_config : {
62 extraKeys: {"Tab": "indentMore","Shift-Tab" : "indentLess"},
62 extraKeys: {"Tab": "indentMore","Shift-Tab" : "indentLess"},
63 mode: 'htmlmixed',
63 mode: 'htmlmixed',
64 lineWrapping : true,
64 lineWrapping : true,
65 }
65 }
66 };
66 };
67
67
68
68
69 /**
69 /**
70 * Create the DOM element of the TextCell
70 * Create the DOM element of the TextCell
71 * @method create_element
71 * @method create_element
72 * @private
72 * @private
73 */
73 */
74 TextCell.prototype.create_element = function () {
74 TextCell.prototype.create_element = function () {
75 Cell.prototype.create_element.apply(this, arguments);
75 Cell.prototype.create_element.apply(this, arguments);
76
76
77 var cell = $("<div>").addClass('cell text_cell');
77 var cell = $("<div>").addClass('cell text_cell');
78 cell.attr('tabindex','2');
78 cell.attr('tabindex','2');
79
79
80 var prompt = $('<div/>').addClass('prompt input_prompt');
80 var prompt = $('<div/>').addClass('prompt input_prompt');
81 cell.append(prompt);
81 cell.append(prompt);
82 var inner_cell = $('<div/>').addClass('inner_cell');
82 var inner_cell = $('<div/>').addClass('inner_cell');
83 this.celltoolbar = new celltoolbar.CellToolbar({
83 this.celltoolbar = new celltoolbar.CellToolbar({
84 cell: this,
84 cell: this,
85 notebook: this.notebook});
85 notebook: this.notebook});
86 inner_cell.append(this.celltoolbar.element);
86 inner_cell.append(this.celltoolbar.element);
87 var input_area = $('<div/>').addClass('input_area');
87 var input_area = $('<div/>').addClass('input_area');
88 this.code_mirror = new CodeMirror(input_area.get(0), this.cm_config);
88 this.code_mirror = new CodeMirror(input_area.get(0), this.cm_config);
89 // The tabindex=-1 makes this div focusable.
89 // The tabindex=-1 makes this div focusable.
90 var render_area = $('<div/>').addClass('text_cell_render rendered_html')
90 var render_area = $('<div/>').addClass('text_cell_render rendered_html')
91 .attr('tabindex','-1');
91 .attr('tabindex','-1');
92 inner_cell.append(input_area).append(render_area);
92 inner_cell.append(input_area).append(render_area);
93 cell.append(inner_cell);
93 cell.append(inner_cell);
94 this.element = cell;
94 this.element = cell;
95 };
95 };
96
96
97
97
98 // Cell level actions
98 // Cell level actions
99
99
100 TextCell.prototype.select = function () {
100 TextCell.prototype.select = function () {
101 var cont = Cell.prototype.select.apply(this);
101 var cont = Cell.prototype.select.apply(this);
102 if (cont) {
102 if (cont) {
103 if (this.mode === 'edit') {
103 if (this.mode === 'edit') {
104 this.code_mirror.refresh();
104 this.code_mirror.refresh();
105 }
105 }
106 }
106 }
107 return cont;
107 return cont;
108 };
108 };
109
109
110 TextCell.prototype.unrender = function () {
110 TextCell.prototype.unrender = function () {
111 if (this.read_only) return;
111 if (this.read_only) return;
112 var cont = Cell.prototype.unrender.apply(this);
112 var cont = Cell.prototype.unrender.apply(this);
113 if (cont) {
113 if (cont) {
114 var text_cell = this.element;
114 var text_cell = this.element;
115 var output = text_cell.find("div.text_cell_render");
115 var output = text_cell.find("div.text_cell_render");
116 if (this.get_text() === this.placeholder) {
116 if (this.get_text() === this.placeholder) {
117 this.set_text('');
117 this.set_text('');
118 }
118 }
119 this.refresh();
119 this.refresh();
120 }
120 }
121 return cont;
121 return cont;
122 };
122 };
123
123
124 TextCell.prototype.execute = function () {
124 TextCell.prototype.execute = function () {
125 this.render();
125 this.render();
126 };
126 };
127
127
128 /**
128 /**
129 * setter: {{#crossLink "TextCell/set_text"}}{{/crossLink}}
129 * setter: {{#crossLink "TextCell/set_text"}}{{/crossLink}}
130 * @method get_text
130 * @method get_text
131 * @retrun {string} CodeMirror current text value
131 * @retrun {string} CodeMirror current text value
132 */
132 */
133 TextCell.prototype.get_text = function() {
133 TextCell.prototype.get_text = function() {
134 return this.code_mirror.getValue();
134 return this.code_mirror.getValue();
135 };
135 };
136
136
137 /**
137 /**
138 * @param {string} text - Codemiror text value
138 * @param {string} text - Codemiror text value
139 * @see TextCell#get_text
139 * @see TextCell#get_text
140 * @method set_text
140 * @method set_text
141 * */
141 * */
142 TextCell.prototype.set_text = function(text) {
142 TextCell.prototype.set_text = function(text) {
143 this.code_mirror.setValue(text);
143 this.code_mirror.setValue(text);
144 this.unrender();
144 this.unrender();
145 this.code_mirror.refresh();
145 this.code_mirror.refresh();
146 };
146 };
147
147
148 /**
148 /**
149 * setter :{{#crossLink "TextCell/set_rendered"}}{{/crossLink}}
149 * setter :{{#crossLink "TextCell/set_rendered"}}{{/crossLink}}
150 * @method get_rendered
150 * @method get_rendered
151 * */
151 * */
152 TextCell.prototype.get_rendered = function() {
152 TextCell.prototype.get_rendered = function() {
153 return this.element.find('div.text_cell_render').html();
153 return this.element.find('div.text_cell_render').html();
154 };
154 };
155
155
156 /**
156 /**
157 * @method set_rendered
157 * @method set_rendered
158 */
158 */
159 TextCell.prototype.set_rendered = function(text) {
159 TextCell.prototype.set_rendered = function(text) {
160 this.element.find('div.text_cell_render').html(text);
160 this.element.find('div.text_cell_render').html(text);
161 };
161 };
162
162
163
163
164 /**
164 /**
165 * Create Text cell from JSON
165 * Create Text cell from JSON
166 * @param {json} data - JSON serialized text-cell
166 * @param {json} data - JSON serialized text-cell
167 * @method fromJSON
167 * @method fromJSON
168 */
168 */
169 TextCell.prototype.fromJSON = function (data) {
169 TextCell.prototype.fromJSON = function (data) {
170 Cell.prototype.fromJSON.apply(this, arguments);
170 Cell.prototype.fromJSON.apply(this, arguments);
171 if (data.cell_type === this.cell_type) {
171 if (data.cell_type === this.cell_type) {
172 if (data.source !== undefined) {
172 if (data.source !== undefined) {
173 this.set_text(data.source);
173 this.set_text(data.source);
174 // make this value the starting point, so that we can only undo
174 // make this value the starting point, so that we can only undo
175 // to this state, instead of a blank cell
175 // to this state, instead of a blank cell
176 this.code_mirror.clearHistory();
176 this.code_mirror.clearHistory();
177 // TODO: This HTML needs to be treated as potentially dangerous
177 // TODO: This HTML needs to be treated as potentially dangerous
178 // user input and should be handled before set_rendered.
178 // user input and should be handled before set_rendered.
179 this.set_rendered(data.rendered || '');
179 this.set_rendered(data.rendered || '');
180 this.rendered = false;
180 this.rendered = false;
181 this.render();
181 this.render();
182 }
182 }
183 }
183 }
184 };
184 };
185
185
186 /** Generate JSON from cell
186 /** Generate JSON from cell
187 * @return {object} cell data serialised to json
187 * @return {object} cell data serialised to json
188 */
188 */
189 TextCell.prototype.toJSON = function () {
189 TextCell.prototype.toJSON = function () {
190 var data = Cell.prototype.toJSON.apply(this);
190 var data = Cell.prototype.toJSON.apply(this);
191 data.source = this.get_text();
191 data.source = this.get_text();
192 if (data.source == this.placeholder) {
192 if (data.source == this.placeholder) {
193 data.source = "";
193 data.source = "";
194 }
194 }
195 return data;
195 return data;
196 };
196 };
197
197
198
198
199 var MarkdownCell = function (options) {
199 var MarkdownCell = function (options) {
200 // Constructor
200 // Constructor
201 //
201 //
202 // Parameters:
202 // Parameters:
203 // options: dictionary
203 // options: dictionary
204 // Dictionary of keyword arguments.
204 // Dictionary of keyword arguments.
205 // events: $(Events) instance
205 // events: $(Events) instance
206 // config: dictionary
206 // config: dictionary
207 // keyboard_manager: KeyboardManager instance
207 // keyboard_manager: KeyboardManager instance
208 // notebook: Notebook instance
208 // notebook: Notebook instance
209 options = options || {};
209 options = options || {};
210 var config = utils.mergeopt(MarkdownCell, options.config);
210 var config = utils.mergeopt(MarkdownCell, options.config);
211 TextCell.apply(this, [$.extend({}, options, {config: config})]);
211 TextCell.apply(this, [$.extend({}, options, {config: config})]);
212
212
213 this.cell_type = 'markdown';
213 this.cell_type = 'markdown';
214 };
214 };
215
215
216 MarkdownCell.options_default = {
216 MarkdownCell.options_default = {
217 cm_config: {
217 cm_config: {
218 mode: 'ipythongfm'
218 mode: 'ipythongfm'
219 },
219 },
220 placeholder: "Type *Markdown* and LaTeX: $\\alpha^2$"
220 placeholder: "Type *Markdown* and LaTeX: $\\alpha^2$"
221 };
221 };
222
222
223 MarkdownCell.prototype = Object.create(TextCell.prototype);
223 MarkdownCell.prototype = Object.create(TextCell.prototype);
224
224
225 /**
225 /**
226 * @method render
226 * @method render
227 */
227 */
228 MarkdownCell.prototype.render = function () {
228 MarkdownCell.prototype.render = function () {
229 var cont = TextCell.prototype.render.apply(this);
229 var cont = TextCell.prototype.render.apply(this);
230 if (cont) {
230 if (cont) {
231 var text = this.get_text();
231 var text = this.get_text();
232 var math = null;
232 var math = null;
233 if (text === "") { text = this.placeholder; }
233 if (text === "") { text = this.placeholder; }
234 var text_and_math = mathjaxutils.remove_math(text);
234 var text_and_math = mathjaxutils.remove_math(text);
235 text = text_and_math[0];
235 text = text_and_math[0];
236 math = text_and_math[1];
236 math = text_and_math[1];
237 var html = marked.parser(marked.lexer(text));
237 var html = marked.parser(marked.lexer(text));
238 html = mathjaxutils.replace_math(html, math);
238 html = mathjaxutils.replace_math(html, math);
239 html = security.sanitize_html(html);
239 html = security.sanitize_html(html);
240 html = $($.parseHTML(html));
240 html = $($.parseHTML(html));
241 // links in markdown cells should open in new tabs
241 // links in markdown cells should open in new tabs
242 html.find("a[href]").not('[href^="#"]').attr("target", "_blank");
242 html.find("a[href]").not('[href^="#"]').attr("target", "_blank");
243 this.set_rendered(html);
243 this.set_rendered(html);
244 this.typeset();
244 this.typeset();
245 this.events.trigger("rendered.MarkdownCell", {cell: this})
245 }
246 }
246 return cont;
247 return cont;
247 };
248 };
248
249
249
250
250 var RawCell = function (options) {
251 var RawCell = function (options) {
251 // Constructor
252 // Constructor
252 //
253 //
253 // Parameters:
254 // Parameters:
254 // options: dictionary
255 // options: dictionary
255 // Dictionary of keyword arguments.
256 // Dictionary of keyword arguments.
256 // events: $(Events) instance
257 // events: $(Events) instance
257 // config: dictionary
258 // config: dictionary
258 // keyboard_manager: KeyboardManager instance
259 // keyboard_manager: KeyboardManager instance
259 // notebook: Notebook instance
260 // notebook: Notebook instance
260 options = options || {};
261 options = options || {};
261 var config = utils.mergeopt(RawCell, options.config);
262 var config = utils.mergeopt(RawCell, options.config);
262 TextCell.apply(this, [$.extend({}, options, {config: config})]);
263 TextCell.apply(this, [$.extend({}, options, {config: config})]);
263
264
264 this.cell_type = 'raw';
265 this.cell_type = 'raw';
265 };
266 };
266
267
267 RawCell.options_default = {
268 RawCell.options_default = {
268 placeholder : "Write raw LaTeX or other formats here, for use with nbconvert. " +
269 placeholder : "Write raw LaTeX or other formats here, for use with nbconvert. " +
269 "It will not be rendered in the notebook. " +
270 "It will not be rendered in the notebook. " +
270 "When passing through nbconvert, a Raw Cell's content is added to the output unmodified."
271 "When passing through nbconvert, a Raw Cell's content is added to the output unmodified."
271 };
272 };
272
273
273 RawCell.prototype = Object.create(TextCell.prototype);
274 RawCell.prototype = Object.create(TextCell.prototype);
274
275
275 /** @method bind_events **/
276 /** @method bind_events **/
276 RawCell.prototype.bind_events = function () {
277 RawCell.prototype.bind_events = function () {
277 TextCell.prototype.bind_events.apply(this);
278 TextCell.prototype.bind_events.apply(this);
278 var that = this;
279 var that = this;
279 this.element.focusout(function() {
280 this.element.focusout(function() {
280 that.auto_highlight();
281 that.auto_highlight();
281 that.render();
282 that.render();
282 });
283 });
283
284
284 this.code_mirror.on('focus', function() { that.unrender(); });
285 this.code_mirror.on('focus', function() { that.unrender(); });
285 };
286 };
286
287
287 /**
288 /**
288 * Trigger autodetection of highlight scheme for current cell
289 * Trigger autodetection of highlight scheme for current cell
289 * @method auto_highlight
290 * @method auto_highlight
290 */
291 */
291 RawCell.prototype.auto_highlight = function () {
292 RawCell.prototype.auto_highlight = function () {
292 this._auto_highlight(this.config.raw_cell_highlight);
293 this._auto_highlight(this.config.raw_cell_highlight);
293 };
294 };
294
295
295 /** @method render **/
296 /** @method render **/
296 RawCell.prototype.render = function () {
297 RawCell.prototype.render = function () {
297 var cont = TextCell.prototype.render.apply(this);
298 var cont = TextCell.prototype.render.apply(this);
298 if (cont){
299 if (cont){
299 var text = this.get_text();
300 var text = this.get_text();
300 if (text === "") { text = this.placeholder; }
301 if (text === "") { text = this.placeholder; }
301 this.set_text(text);
302 this.set_text(text);
302 this.element.removeClass('rendered');
303 this.element.removeClass('rendered');
303 }
304 }
304 return cont;
305 return cont;
305 };
306 };
306
307
307
308
308 var HeadingCell = function (options) {
309 var HeadingCell = function (options) {
309 // Constructor
310 // Constructor
310 //
311 //
311 // Parameters:
312 // Parameters:
312 // options: dictionary
313 // options: dictionary
313 // Dictionary of keyword arguments.
314 // Dictionary of keyword arguments.
314 // events: $(Events) instance
315 // events: $(Events) instance
315 // config: dictionary
316 // config: dictionary
316 // keyboard_manager: KeyboardManager instance
317 // keyboard_manager: KeyboardManager instance
317 // notebook: Notebook instance
318 // notebook: Notebook instance
318 options = options || {};
319 options = options || {};
319 var config = utils.mergeopt(HeadingCell, options.config);
320 var config = utils.mergeopt(HeadingCell, options.config);
320 TextCell.apply(this, [$.extend({}, options, {config: config})]);
321 TextCell.apply(this, [$.extend({}, options, {config: config})]);
321
322
322 this.level = 1;
323 this.level = 1;
323 this.cell_type = 'heading';
324 this.cell_type = 'heading';
324 };
325 };
325
326
326 HeadingCell.options_default = {
327 HeadingCell.options_default = {
327 cm_config: {
328 cm_config: {
328 theme: 'heading-1'
329 theme: 'heading-1'
329 },
330 },
330 placeholder: "Type Heading Here"
331 placeholder: "Type Heading Here"
331 };
332 };
332
333
333 HeadingCell.prototype = Object.create(TextCell.prototype);
334 HeadingCell.prototype = Object.create(TextCell.prototype);
334
335
335 /** @method fromJSON */
336 /** @method fromJSON */
336 HeadingCell.prototype.fromJSON = function (data) {
337 HeadingCell.prototype.fromJSON = function (data) {
337 if (data.level !== undefined){
338 if (data.level !== undefined){
338 this.level = data.level;
339 this.level = data.level;
339 }
340 }
340 TextCell.prototype.fromJSON.apply(this, arguments);
341 TextCell.prototype.fromJSON.apply(this, arguments);
341 this.code_mirror.setOption("theme", "heading-"+this.level);
342 this.code_mirror.setOption("theme", "heading-"+this.level);
342 };
343 };
343
344
344
345
345 /** @method toJSON */
346 /** @method toJSON */
346 HeadingCell.prototype.toJSON = function () {
347 HeadingCell.prototype.toJSON = function () {
347 var data = TextCell.prototype.toJSON.apply(this);
348 var data = TextCell.prototype.toJSON.apply(this);
348 data.level = this.get_level();
349 data.level = this.get_level();
349 return data;
350 return data;
350 };
351 };
351
352
352 /**
353 /**
353 * Change heading level of cell, and re-render
354 * Change heading level of cell, and re-render
354 * @method set_level
355 * @method set_level
355 */
356 */
356 HeadingCell.prototype.set_level = function (level) {
357 HeadingCell.prototype.set_level = function (level) {
357 this.level = level;
358 this.level = level;
358 this.code_mirror.setOption("theme", "heading-"+level);
359 this.code_mirror.setOption("theme", "heading-"+level);
359
360
360 if (this.rendered) {
361 if (this.rendered) {
361 this.rendered = false;
362 this.rendered = false;
362 this.render();
363 this.render();
363 }
364 }
364 };
365 };
365
366
366 /** The depth of header cell, based on html (h1 to h6)
367 /** The depth of header cell, based on html (h1 to h6)
367 * @method get_level
368 * @method get_level
368 * @return {integer} level - for 1 to 6
369 * @return {integer} level - for 1 to 6
369 */
370 */
370 HeadingCell.prototype.get_level = function () {
371 HeadingCell.prototype.get_level = function () {
371 return this.level;
372 return this.level;
372 };
373 };
373
374
374
375
375 HeadingCell.prototype.get_rendered = function () {
376 HeadingCell.prototype.get_rendered = function () {
376 var r = this.element.find("div.text_cell_render");
377 var r = this.element.find("div.text_cell_render");
377 return r.children().first().html();
378 return r.children().first().html();
378 };
379 };
379
380
380 HeadingCell.prototype.render = function () {
381 HeadingCell.prototype.render = function () {
381 var cont = TextCell.prototype.render.apply(this);
382 var cont = TextCell.prototype.render.apply(this);
382 if (cont) {
383 if (cont) {
383 var text = this.get_text();
384 var text = this.get_text();
384 var math = null;
385 var math = null;
385 // Markdown headings must be a single line
386 // Markdown headings must be a single line
386 text = text.replace(/\n/g, ' ');
387 text = text.replace(/\n/g, ' ');
387 if (text === "") { text = this.placeholder; }
388 if (text === "") { text = this.placeholder; }
388 text = new Array(this.level + 1).join("#") + " " + text;
389 text = new Array(this.level + 1).join("#") + " " + text;
389 var text_and_math = mathjaxutils.remove_math(text);
390 var text_and_math = mathjaxutils.remove_math(text);
390 text = text_and_math[0];
391 text = text_and_math[0];
391 math = text_and_math[1];
392 math = text_and_math[1];
392 var html = marked.parser(marked.lexer(text));
393 var html = marked.parser(marked.lexer(text));
393 html = mathjaxutils.replace_math(html, math);
394 html = mathjaxutils.replace_math(html, math);
394 html = security.sanitize_html(html);
395 html = security.sanitize_html(html);
395 var h = $($.parseHTML(html));
396 var h = $($.parseHTML(html));
396 // add id and linkback anchor
397 // add id and linkback anchor
397 var hash = h.text().trim().replace(/ /g, '-');
398 var hash = h.text().trim().replace(/ /g, '-');
398 h.attr('id', hash);
399 h.attr('id', hash);
399 h.append(
400 h.append(
400 $('<a/>')
401 $('<a/>')
401 .addClass('anchor-link')
402 .addClass('anchor-link')
402 .attr('href', '#' + hash)
403 .attr('href', '#' + hash)
403 .text('¶')
404 .text('¶')
404 );
405 );
405 this.set_rendered(h);
406 this.set_rendered(h);
406 this.typeset();
407 this.typeset();
407 }
408 }
408 return cont;
409 return cont;
409 };
410 };
410
411
411 // Backwards compatability.
412 // Backwards compatability.
412 IPython.TextCell = TextCell;
413 IPython.TextCell = TextCell;
413 IPython.MarkdownCell = MarkdownCell;
414 IPython.MarkdownCell = MarkdownCell;
414 IPython.RawCell = RawCell;
415 IPython.RawCell = RawCell;
415 IPython.HeadingCell = HeadingCell;
416 IPython.HeadingCell = HeadingCell;
416
417
417 var textcell = {
418 var textcell = {
418 'TextCell': TextCell,
419 'TextCell': TextCell,
419 'MarkdownCell': MarkdownCell,
420 'MarkdownCell': MarkdownCell,
420 'RawCell': RawCell,
421 'RawCell': RawCell,
421 'HeadingCell': HeadingCell,
422 'HeadingCell': HeadingCell,
422 };
423 };
423 return textcell;
424 return textcell;
424 });
425 });
General Comments 0
You need to be logged in to leave comments. Login now