##// END OF EJS Templates
don't set target on internal markdown links...
MinRK -
Show More
@@ -1,556 +1,556 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2008-2012 The IPython Development Team
2 // Copyright (C) 2008-2012 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // TextCell
9 // TextCell
10 //============================================================================
10 //============================================================================
11
11
12
12
13
13
14 /**
14 /**
15 A module that allow to create different type of Text Cell
15 A module that allow to create different type of Text Cell
16 @module IPython
16 @module IPython
17 @namespace IPython
17 @namespace IPython
18 */
18 */
19 var IPython = (function (IPython) {
19 var IPython = (function (IPython) {
20 "use strict";
20 "use strict";
21
21
22 // TextCell base class
22 // TextCell base class
23 var key = IPython.utils.keycodes;
23 var key = IPython.utils.keycodes;
24
24
25 /**
25 /**
26 * Construct a new TextCell, codemirror mode is by default 'htmlmixed', and cell type is 'text'
26 * Construct a new TextCell, codemirror mode is by default 'htmlmixed', and cell type is 'text'
27 * cell start as not redered.
27 * cell start as not redered.
28 *
28 *
29 * @class TextCell
29 * @class TextCell
30 * @constructor TextCell
30 * @constructor TextCell
31 * @extend IPython.Cell
31 * @extend IPython.Cell
32 * @param {object|undefined} [options]
32 * @param {object|undefined} [options]
33 * @param [options.cm_config] {object} config to pass to CodeMirror, will extend/overwrite default config
33 * @param [options.cm_config] {object} config to pass to CodeMirror, will extend/overwrite default config
34 * @param [options.placeholder] {string} default string to use when souce in empty for rendering (only use in some TextCell subclass)
34 * @param [options.placeholder] {string} default string to use when souce in empty for rendering (only use in some TextCell subclass)
35 */
35 */
36 var TextCell = function (options) {
36 var TextCell = function (options) {
37 // in all TextCell/Cell subclasses
37 // in all TextCell/Cell subclasses
38 // do not assign most of members here, just pass it down
38 // do not assign most of members here, just pass it down
39 // in the options dict potentially overwriting what you wish.
39 // in the options dict potentially overwriting what you wish.
40 // they will be assigned in the base class.
40 // they will be assigned in the base class.
41
41
42 // we cannot put this as a class key as it has handle to "this".
42 // we cannot put this as a class key as it has handle to "this".
43 var cm_overwrite_options = {
43 var cm_overwrite_options = {
44 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
44 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
45 };
45 };
46
46
47 options = this.mergeopt(TextCell,options,{cm_config:cm_overwrite_options});
47 options = this.mergeopt(TextCell,options,{cm_config:cm_overwrite_options});
48
48
49 IPython.Cell.apply(this, [options]);
49 IPython.Cell.apply(this, [options]);
50
50
51
51
52 this.rendered = false;
52 this.rendered = false;
53 this.cell_type = this.cell_type || 'text';
53 this.cell_type = this.cell_type || 'text';
54 };
54 };
55
55
56 TextCell.prototype = new IPython.Cell();
56 TextCell.prototype = new IPython.Cell();
57
57
58 TextCell.options_default = {
58 TextCell.options_default = {
59 cm_config : {
59 cm_config : {
60 extraKeys: {"Tab": "indentMore","Shift-Tab" : "indentLess"},
60 extraKeys: {"Tab": "indentMore","Shift-Tab" : "indentLess"},
61 mode: 'htmlmixed',
61 mode: 'htmlmixed',
62 lineWrapping : true,
62 lineWrapping : true,
63 }
63 }
64 };
64 };
65
65
66
66
67
67
68 /**
68 /**
69 * Create the DOM element of the TextCell
69 * Create the DOM element of the TextCell
70 * @method create_element
70 * @method create_element
71 * @private
71 * @private
72 */
72 */
73 TextCell.prototype.create_element = function () {
73 TextCell.prototype.create_element = function () {
74 IPython.Cell.prototype.create_element.apply(this, arguments);
74 IPython.Cell.prototype.create_element.apply(this, arguments);
75 var cell = $("<div>").addClass('cell text_cell border-box-sizing');
75 var cell = $("<div>").addClass('cell text_cell border-box-sizing');
76 cell.attr('tabindex','2');
76 cell.attr('tabindex','2');
77
77
78 this.celltoolbar = new IPython.CellToolbar(this);
78 this.celltoolbar = new IPython.CellToolbar(this);
79 cell.append(this.celltoolbar.element);
79 cell.append(this.celltoolbar.element);
80
80
81 var input_area = $('<div/>').addClass('text_cell_input border-box-sizing');
81 var input_area = $('<div/>').addClass('text_cell_input border-box-sizing');
82 this.code_mirror = CodeMirror(input_area.get(0), this.cm_config);
82 this.code_mirror = CodeMirror(input_area.get(0), this.cm_config);
83
83
84 // The tabindex=-1 makes this div focusable.
84 // The tabindex=-1 makes this div focusable.
85 var render_area = $('<div/>').addClass('text_cell_render border-box-sizing').
85 var render_area = $('<div/>').addClass('text_cell_render border-box-sizing').
86 addClass('rendered_html').attr('tabindex','-1');
86 addClass('rendered_html').attr('tabindex','-1');
87 cell.append(input_area).append(render_area);
87 cell.append(input_area).append(render_area);
88 this.element = cell;
88 this.element = cell;
89 };
89 };
90
90
91
91
92 /**
92 /**
93 * Bind the DOM evet to cell actions
93 * Bind the DOM evet to cell actions
94 * Need to be called after TextCell.create_element
94 * Need to be called after TextCell.create_element
95 * @private
95 * @private
96 * @method bind_event
96 * @method bind_event
97 */
97 */
98 TextCell.prototype.bind_events = function () {
98 TextCell.prototype.bind_events = function () {
99 IPython.Cell.prototype.bind_events.apply(this);
99 IPython.Cell.prototype.bind_events.apply(this);
100 var that = this;
100 var that = this;
101 this.element.keydown(function (event) {
101 this.element.keydown(function (event) {
102 if (event.which === 13 && !event.shiftKey) {
102 if (event.which === 13 && !event.shiftKey) {
103 if (that.rendered) {
103 if (that.rendered) {
104 that.edit();
104 that.edit();
105 return false;
105 return false;
106 };
106 };
107 };
107 };
108 });
108 });
109 this.element.dblclick(function () {
109 this.element.dblclick(function () {
110 that.edit();
110 that.edit();
111 });
111 });
112 };
112 };
113
113
114 /**
114 /**
115 * This method gets called in CodeMirror's onKeyDown/onKeyPress
115 * This method gets called in CodeMirror's onKeyDown/onKeyPress
116 * handlers and is used to provide custom key handling.
116 * handlers and is used to provide custom key handling.
117 *
117 *
118 * Subclass should override this method to have custom handeling
118 * Subclass should override this method to have custom handeling
119 *
119 *
120 * @method handle_codemirror_keyevent
120 * @method handle_codemirror_keyevent
121 * @param {CodeMirror} editor - The codemirror instance bound to the cell
121 * @param {CodeMirror} editor - The codemirror instance bound to the cell
122 * @param {event} event -
122 * @param {event} event -
123 * @return {Boolean} `true` if CodeMirror should ignore the event, `false` Otherwise
123 * @return {Boolean} `true` if CodeMirror should ignore the event, `false` Otherwise
124 */
124 */
125 TextCell.prototype.handle_codemirror_keyevent = function (editor, event) {
125 TextCell.prototype.handle_codemirror_keyevent = function (editor, event) {
126
126
127 if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) {
127 if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) {
128 // Always ignore shift-enter in CodeMirror as we handle it.
128 // Always ignore shift-enter in CodeMirror as we handle it.
129 return true;
129 return true;
130 }
130 }
131 return false;
131 return false;
132 };
132 };
133
133
134 /**
134 /**
135 * Select the current cell and trigger 'focus'
135 * Select the current cell and trigger 'focus'
136 * @method select
136 * @method select
137 */
137 */
138 TextCell.prototype.select = function () {
138 TextCell.prototype.select = function () {
139 IPython.Cell.prototype.select.apply(this);
139 IPython.Cell.prototype.select.apply(this);
140 var output = this.element.find("div.text_cell_render");
140 var output = this.element.find("div.text_cell_render");
141 output.trigger('focus');
141 output.trigger('focus');
142 };
142 };
143
143
144 /**
144 /**
145 * unselect the current cell and `render` it
145 * unselect the current cell and `render` it
146 * @method unselect
146 * @method unselect
147 */
147 */
148 TextCell.prototype.unselect = function() {
148 TextCell.prototype.unselect = function() {
149 // render on selection of another cell
149 // render on selection of another cell
150 this.render();
150 this.render();
151 IPython.Cell.prototype.unselect.apply(this);
151 IPython.Cell.prototype.unselect.apply(this);
152 };
152 };
153
153
154 /**
154 /**
155 *
155 *
156 * put the current cell in edition mode
156 * put the current cell in edition mode
157 * @method edit
157 * @method edit
158 */
158 */
159 TextCell.prototype.edit = function () {
159 TextCell.prototype.edit = function () {
160 if (this.rendered === true) {
160 if (this.rendered === true) {
161 var text_cell = this.element;
161 var text_cell = this.element;
162 var output = text_cell.find("div.text_cell_render");
162 var output = text_cell.find("div.text_cell_render");
163 output.hide();
163 output.hide();
164 text_cell.find('div.text_cell_input').show();
164 text_cell.find('div.text_cell_input').show();
165 this.code_mirror.refresh();
165 this.code_mirror.refresh();
166 this.code_mirror.focus();
166 this.code_mirror.focus();
167 // We used to need an additional refresh() after the focus, but
167 // We used to need an additional refresh() after the focus, but
168 // it appears that this has been fixed in CM. This bug would show
168 // it appears that this has been fixed in CM. This bug would show
169 // up on FF when a newly loaded markdown cell was edited.
169 // up on FF when a newly loaded markdown cell was edited.
170 this.rendered = false;
170 this.rendered = false;
171 if (this.get_text() === this.placeholder) {
171 if (this.get_text() === this.placeholder) {
172 this.set_text('');
172 this.set_text('');
173 this.refresh();
173 this.refresh();
174 }
174 }
175 }
175 }
176 };
176 };
177
177
178
178
179 /**
179 /**
180 * Empty, Subclasses must define render.
180 * Empty, Subclasses must define render.
181 * @method render
181 * @method render
182 */
182 */
183 TextCell.prototype.render = function () {};
183 TextCell.prototype.render = function () {};
184
184
185
185
186 /**
186 /**
187 * setter: {{#crossLink "TextCell/set_text"}}{{/crossLink}}
187 * setter: {{#crossLink "TextCell/set_text"}}{{/crossLink}}
188 * @method get_text
188 * @method get_text
189 * @retrun {string} CodeMirror current text value
189 * @retrun {string} CodeMirror current text value
190 */
190 */
191 TextCell.prototype.get_text = function() {
191 TextCell.prototype.get_text = function() {
192 return this.code_mirror.getValue();
192 return this.code_mirror.getValue();
193 };
193 };
194
194
195 /**
195 /**
196 * @param {string} text - Codemiror text value
196 * @param {string} text - Codemiror text value
197 * @see TextCell#get_text
197 * @see TextCell#get_text
198 * @method set_text
198 * @method set_text
199 * */
199 * */
200 TextCell.prototype.set_text = function(text) {
200 TextCell.prototype.set_text = function(text) {
201 this.code_mirror.setValue(text);
201 this.code_mirror.setValue(text);
202 this.code_mirror.refresh();
202 this.code_mirror.refresh();
203 };
203 };
204
204
205 /**
205 /**
206 * setter :{{#crossLink "TextCell/set_rendered"}}{{/crossLink}}
206 * setter :{{#crossLink "TextCell/set_rendered"}}{{/crossLink}}
207 * @method get_rendered
207 * @method get_rendered
208 * @return {html} html of rendered element
208 * @return {html} html of rendered element
209 * */
209 * */
210 TextCell.prototype.get_rendered = function() {
210 TextCell.prototype.get_rendered = function() {
211 return this.element.find('div.text_cell_render').html();
211 return this.element.find('div.text_cell_render').html();
212 };
212 };
213
213
214 /**
214 /**
215 * @method set_rendered
215 * @method set_rendered
216 */
216 */
217 TextCell.prototype.set_rendered = function(text) {
217 TextCell.prototype.set_rendered = function(text) {
218 this.element.find('div.text_cell_render').html(text);
218 this.element.find('div.text_cell_render').html(text);
219 };
219 };
220
220
221 /**
221 /**
222 * not deprecated, but implementation wrong
222 * not deprecated, but implementation wrong
223 * @method at_top
223 * @method at_top
224 * @deprecated
224 * @deprecated
225 * @return {Boolean} true is cell rendered, false otherwise
225 * @return {Boolean} true is cell rendered, false otherwise
226 * I doubt this is what it is supposed to do
226 * I doubt this is what it is supposed to do
227 * this implementation is completly false
227 * this implementation is completly false
228 */
228 */
229 TextCell.prototype.at_top = function () {
229 TextCell.prototype.at_top = function () {
230 if (this.rendered) {
230 if (this.rendered) {
231 return true;
231 return true;
232 } else {
232 } else {
233 return false;
233 return false;
234 }
234 }
235 };
235 };
236
236
237
237
238 /**
238 /**
239 * not deprecated, but implementation wrong
239 * not deprecated, but implementation wrong
240 * @method at_bottom
240 * @method at_bottom
241 * @deprecated
241 * @deprecated
242 * @return {Boolean} true is cell rendered, false otherwise
242 * @return {Boolean} true is cell rendered, false otherwise
243 * I doubt this is what it is supposed to do
243 * I doubt this is what it is supposed to do
244 * this implementation is completly false
244 * this implementation is completly false
245 * */
245 * */
246 TextCell.prototype.at_bottom = function () {
246 TextCell.prototype.at_bottom = function () {
247 if (this.rendered) {
247 if (this.rendered) {
248 return true;
248 return true;
249 } else {
249 } else {
250 return false;
250 return false;
251 }
251 }
252 };
252 };
253
253
254 /**
254 /**
255 * Create Text cell from JSON
255 * Create Text cell from JSON
256 * @param {json} data - JSON serialized text-cell
256 * @param {json} data - JSON serialized text-cell
257 * @method fromJSON
257 * @method fromJSON
258 */
258 */
259 TextCell.prototype.fromJSON = function (data) {
259 TextCell.prototype.fromJSON = function (data) {
260 IPython.Cell.prototype.fromJSON.apply(this, arguments);
260 IPython.Cell.prototype.fromJSON.apply(this, arguments);
261 if (data.cell_type === this.cell_type) {
261 if (data.cell_type === this.cell_type) {
262 if (data.source !== undefined) {
262 if (data.source !== undefined) {
263 this.set_text(data.source);
263 this.set_text(data.source);
264 // make this value the starting point, so that we can only undo
264 // make this value the starting point, so that we can only undo
265 // to this state, instead of a blank cell
265 // to this state, instead of a blank cell
266 this.code_mirror.clearHistory();
266 this.code_mirror.clearHistory();
267 this.set_rendered(data.rendered || '');
267 this.set_rendered(data.rendered || '');
268 this.rendered = false;
268 this.rendered = false;
269 this.render();
269 this.render();
270 }
270 }
271 }
271 }
272 };
272 };
273
273
274 /** Generate JSON from cell
274 /** Generate JSON from cell
275 * @return {object} cell data serialised to json
275 * @return {object} cell data serialised to json
276 */
276 */
277 TextCell.prototype.toJSON = function () {
277 TextCell.prototype.toJSON = function () {
278 var data = IPython.Cell.prototype.toJSON.apply(this);
278 var data = IPython.Cell.prototype.toJSON.apply(this);
279 data.cell_type = this.cell_type;
279 data.cell_type = this.cell_type;
280 data.source = this.get_text();
280 data.source = this.get_text();
281 return data;
281 return data;
282 };
282 };
283
283
284
284
285 /**
285 /**
286 * @class MarkdownCell
286 * @class MarkdownCell
287 * @constructor MarkdownCell
287 * @constructor MarkdownCell
288 * @extends IPython.HTMLCell
288 * @extends IPython.HTMLCell
289 */
289 */
290 var MarkdownCell = function (options) {
290 var MarkdownCell = function (options) {
291 var options = options || {};
291 var options = options || {};
292
292
293 options = this.mergeopt(MarkdownCell,options);
293 options = this.mergeopt(MarkdownCell,options);
294 TextCell.apply(this, [options]);
294 TextCell.apply(this, [options]);
295
295
296 this.cell_type = 'markdown';
296 this.cell_type = 'markdown';
297 };
297 };
298
298
299 MarkdownCell.options_default = {
299 MarkdownCell.options_default = {
300 cm_config: {
300 cm_config: {
301 mode: 'gfm'
301 mode: 'gfm'
302 },
302 },
303 placeholder: "Type *Markdown* and LaTeX: $\\alpha^2$"
303 placeholder: "Type *Markdown* and LaTeX: $\\alpha^2$"
304 }
304 }
305
305
306
306
307
307
308
308
309 MarkdownCell.prototype = new TextCell();
309 MarkdownCell.prototype = new TextCell();
310
310
311 /**
311 /**
312 * @method render
312 * @method render
313 */
313 */
314 MarkdownCell.prototype.render = function () {
314 MarkdownCell.prototype.render = function () {
315 if (this.rendered === false) {
315 if (this.rendered === false) {
316 var text = this.get_text();
316 var text = this.get_text();
317 if (text === "") { text = this.placeholder; }
317 if (text === "") { text = this.placeholder; }
318 var text_math = IPython.mathjaxutils.remove_math(text);
318 var text_math = IPython.mathjaxutils.remove_math(text);
319 var text = text_math[0];
319 var text = text_math[0];
320 var math = text_math[1];
320 var math = text_math[1];
321 var html = marked.parser(marked.lexer(text));
321 var html = marked.parser(marked.lexer(text));
322 html = $(IPython.mathjaxutils.replace_math(html, math));
322 html = $(IPython.mathjaxutils.replace_math(html, math));
323 // links in markdown cells should open in new tabs
323 // links in markdown cells should open in new tabs
324 html.find("a[href]").attr("target", "_blank");
324 html.find("a[href]").not('[href^="#"]').attr("target", "_blank");
325 try {
325 try {
326 this.set_rendered(html);
326 this.set_rendered(html);
327 } catch (e) {
327 } catch (e) {
328 console.log("Error running Javascript in Markdown:");
328 console.log("Error running Javascript in Markdown:");
329 console.log(e);
329 console.log(e);
330 this.set_rendered($("<div/>").addClass("js-error").html(
330 this.set_rendered($("<div/>").addClass("js-error").html(
331 "Error rendering Markdown!<br/>" + e.toString())
331 "Error rendering Markdown!<br/>" + e.toString())
332 );
332 );
333 }
333 }
334 this.element.find('div.text_cell_input').hide();
334 this.element.find('div.text_cell_input').hide();
335 this.element.find("div.text_cell_render").show();
335 this.element.find("div.text_cell_render").show();
336 this.typeset()
336 this.typeset()
337 this.rendered = true;
337 this.rendered = true;
338 }
338 }
339 };
339 };
340
340
341
341
342 // RawCell
342 // RawCell
343
343
344 /**
344 /**
345 * @class RawCell
345 * @class RawCell
346 * @constructor RawCell
346 * @constructor RawCell
347 * @extends IPython.TextCell
347 * @extends IPython.TextCell
348 */
348 */
349 var RawCell = function (options) {
349 var RawCell = function (options) {
350
350
351 options = this.mergeopt(RawCell,options)
351 options = this.mergeopt(RawCell,options)
352 TextCell.apply(this, [options]);
352 TextCell.apply(this, [options]);
353
353
354 this.cell_type = 'raw';
354 this.cell_type = 'raw';
355
355
356 var that = this
356 var that = this
357 this.element.focusout(
357 this.element.focusout(
358 function() { that.auto_highlight(); }
358 function() { that.auto_highlight(); }
359 );
359 );
360 };
360 };
361
361
362 RawCell.options_default = {
362 RawCell.options_default = {
363 placeholder : "Type plain text and LaTeX: $\\alpha^2$"
363 placeholder : "Type plain text and LaTeX: $\\alpha^2$"
364 };
364 };
365
365
366
366
367
367
368 RawCell.prototype = new TextCell();
368 RawCell.prototype = new TextCell();
369
369
370 /**
370 /**
371 * Trigger autodetection of highlight scheme for current cell
371 * Trigger autodetection of highlight scheme for current cell
372 * @method auto_highlight
372 * @method auto_highlight
373 */
373 */
374 RawCell.prototype.auto_highlight = function () {
374 RawCell.prototype.auto_highlight = function () {
375 this._auto_highlight(IPython.config.raw_cell_highlight);
375 this._auto_highlight(IPython.config.raw_cell_highlight);
376 };
376 };
377
377
378 /** @method render **/
378 /** @method render **/
379 RawCell.prototype.render = function () {
379 RawCell.prototype.render = function () {
380 this.rendered = true;
380 this.rendered = true;
381 this.edit();
381 this.edit();
382 };
382 };
383
383
384
384
385 /** @method handle_codemirror_keyevent **/
385 /** @method handle_codemirror_keyevent **/
386 RawCell.prototype.handle_codemirror_keyevent = function (editor, event) {
386 RawCell.prototype.handle_codemirror_keyevent = function (editor, event) {
387
387
388 var that = this;
388 var that = this;
389 if (event.which === key.UPARROW && event.type === 'keydown') {
389 if (event.which === key.UPARROW && event.type === 'keydown') {
390 // If we are not at the top, let CM handle the up arrow and
390 // If we are not at the top, let CM handle the up arrow and
391 // prevent the global keydown handler from handling it.
391 // prevent the global keydown handler from handling it.
392 if (!that.at_top()) {
392 if (!that.at_top()) {
393 event.stop();
393 event.stop();
394 return false;
394 return false;
395 } else {
395 } else {
396 return true;
396 return true;
397 };
397 };
398 } else if (event.which === key.DOWNARROW && event.type === 'keydown') {
398 } else if (event.which === key.DOWNARROW && event.type === 'keydown') {
399 // If we are not at the bottom, let CM handle the down arrow and
399 // If we are not at the bottom, let CM handle the down arrow and
400 // prevent the global keydown handler from handling it.
400 // prevent the global keydown handler from handling it.
401 if (!that.at_bottom()) {
401 if (!that.at_bottom()) {
402 event.stop();
402 event.stop();
403 return false;
403 return false;
404 } else {
404 } else {
405 return true;
405 return true;
406 };
406 };
407 };
407 };
408 return false;
408 return false;
409 };
409 };
410
410
411 /** @method select **/
411 /** @method select **/
412 RawCell.prototype.select = function () {
412 RawCell.prototype.select = function () {
413 IPython.Cell.prototype.select.apply(this);
413 IPython.Cell.prototype.select.apply(this);
414 this.code_mirror.refresh();
414 this.code_mirror.refresh();
415 this.code_mirror.focus();
415 this.code_mirror.focus();
416 };
416 };
417
417
418 /** @method at_top **/
418 /** @method at_top **/
419 RawCell.prototype.at_top = function () {
419 RawCell.prototype.at_top = function () {
420 var cursor = this.code_mirror.getCursor();
420 var cursor = this.code_mirror.getCursor();
421 if (cursor.line === 0 && cursor.ch === 0) {
421 if (cursor.line === 0 && cursor.ch === 0) {
422 return true;
422 return true;
423 } else {
423 } else {
424 return false;
424 return false;
425 }
425 }
426 };
426 };
427
427
428
428
429 /** @method at_bottom **/
429 /** @method at_bottom **/
430 RawCell.prototype.at_bottom = function () {
430 RawCell.prototype.at_bottom = function () {
431 var cursor = this.code_mirror.getCursor();
431 var cursor = this.code_mirror.getCursor();
432 if (cursor.line === (this.code_mirror.lineCount()-1) && cursor.ch === this.code_mirror.getLine(cursor.line).length) {
432 if (cursor.line === (this.code_mirror.lineCount()-1) && cursor.ch === this.code_mirror.getLine(cursor.line).length) {
433 return true;
433 return true;
434 } else {
434 } else {
435 return false;
435 return false;
436 }
436 }
437 };
437 };
438
438
439
439
440 /**
440 /**
441 * @class HeadingCell
441 * @class HeadingCell
442 * @extends IPython.TextCell
442 * @extends IPython.TextCell
443 */
443 */
444
444
445 /**
445 /**
446 * @constructor HeadingCell
446 * @constructor HeadingCell
447 * @extends IPython.TextCell
447 * @extends IPython.TextCell
448 */
448 */
449 var HeadingCell = function (options) {
449 var HeadingCell = function (options) {
450
450
451 options = this.mergeopt(HeadingCell,options)
451 options = this.mergeopt(HeadingCell,options)
452 TextCell.apply(this, [options]);
452 TextCell.apply(this, [options]);
453
453
454 /**
454 /**
455 * heading level of the cell, use getter and setter to access
455 * heading level of the cell, use getter and setter to access
456 * @property level
456 * @property level
457 */
457 */
458 this.level = 1;
458 this.level = 1;
459 this.cell_type = 'heading';
459 this.cell_type = 'heading';
460 };
460 };
461
461
462 HeadingCell.options_default = {
462 HeadingCell.options_default = {
463 placeholder: "Type Heading Here"
463 placeholder: "Type Heading Here"
464 };
464 };
465
465
466 HeadingCell.prototype = new TextCell();
466 HeadingCell.prototype = new TextCell();
467
467
468 /** @method fromJSON */
468 /** @method fromJSON */
469 HeadingCell.prototype.fromJSON = function (data) {
469 HeadingCell.prototype.fromJSON = function (data) {
470 if (data.level != undefined){
470 if (data.level != undefined){
471 this.level = data.level;
471 this.level = data.level;
472 }
472 }
473 TextCell.prototype.fromJSON.apply(this, arguments);
473 TextCell.prototype.fromJSON.apply(this, arguments);
474 };
474 };
475
475
476
476
477 /** @method toJSON */
477 /** @method toJSON */
478 HeadingCell.prototype.toJSON = function () {
478 HeadingCell.prototype.toJSON = function () {
479 var data = TextCell.prototype.toJSON.apply(this);
479 var data = TextCell.prototype.toJSON.apply(this);
480 data.level = this.get_level();
480 data.level = this.get_level();
481 return data;
481 return data;
482 };
482 };
483
483
484
484
485 /**
485 /**
486 * Change heading level of cell, and re-render
486 * Change heading level of cell, and re-render
487 * @method set_level
487 * @method set_level
488 */
488 */
489 HeadingCell.prototype.set_level = function (level) {
489 HeadingCell.prototype.set_level = function (level) {
490 this.level = level;
490 this.level = level;
491 if (this.rendered) {
491 if (this.rendered) {
492 this.rendered = false;
492 this.rendered = false;
493 this.render();
493 this.render();
494 };
494 };
495 };
495 };
496
496
497 /** The depth of header cell, based on html (h1 to h6)
497 /** The depth of header cell, based on html (h1 to h6)
498 * @method get_level
498 * @method get_level
499 * @return {integer} level - for 1 to 6
499 * @return {integer} level - for 1 to 6
500 */
500 */
501 HeadingCell.prototype.get_level = function () {
501 HeadingCell.prototype.get_level = function () {
502 return this.level;
502 return this.level;
503 };
503 };
504
504
505
505
506 HeadingCell.prototype.set_rendered = function (html) {
506 HeadingCell.prototype.set_rendered = function (html) {
507 this.element.find("div.text_cell_render").html(html);
507 this.element.find("div.text_cell_render").html(html);
508 };
508 };
509
509
510
510
511 HeadingCell.prototype.get_rendered = function () {
511 HeadingCell.prototype.get_rendered = function () {
512 var r = this.element.find("div.text_cell_render");
512 var r = this.element.find("div.text_cell_render");
513 return r.children().first().html();
513 return r.children().first().html();
514 };
514 };
515
515
516
516
517 HeadingCell.prototype.render = function () {
517 HeadingCell.prototype.render = function () {
518 if (this.rendered === false) {
518 if (this.rendered === false) {
519 var text = this.get_text();
519 var text = this.get_text();
520 // Markdown headings must be a single line
520 // Markdown headings must be a single line
521 text = text.replace(/\n/g, ' ');
521 text = text.replace(/\n/g, ' ');
522 if (text === "") { text = this.placeholder; }
522 if (text === "") { text = this.placeholder; }
523 text = Array(this.level + 1).join("#") + " " + text;
523 text = Array(this.level + 1).join("#") + " " + text;
524 var text_and_math = IPython.mathjaxutils.remove_math(text);
524 var text_and_math = IPython.mathjaxutils.remove_math(text);
525 var text = text_and_math[0];
525 var text = text_and_math[0];
526 var math = text_and_math[1];
526 var math = text_and_math[1];
527 var html = marked.parser(marked.lexer(text));
527 var html = marked.parser(marked.lexer(text));
528 var h = $(IPython.mathjaxutils.replace_math(html, math));
528 var h = $(IPython.mathjaxutils.replace_math(html, math));
529 // add id and linkback anchor
529 // add id and linkback anchor
530 var hash = h.text().replace(/ /g, '-');
530 var hash = h.text().replace(/ /g, '-');
531 h.attr('id', hash);
531 h.attr('id', hash);
532 h.append(
532 h.append(
533 $('<a/>')
533 $('<a/>')
534 .addClass('anchor-link')
534 .addClass('anchor-link')
535 .attr('href', '#' + hash)
535 .attr('href', '#' + hash)
536 .text('¶')
536 .text('¶')
537 );
537 );
538
538
539 this.set_rendered(h);
539 this.set_rendered(h);
540 this.typeset();
540 this.typeset();
541 this.element.find('div.text_cell_input').hide();
541 this.element.find('div.text_cell_input').hide();
542 this.element.find("div.text_cell_render").show();
542 this.element.find("div.text_cell_render").show();
543 this.rendered = true;
543 this.rendered = true;
544 };
544 };
545 };
545 };
546
546
547 IPython.TextCell = TextCell;
547 IPython.TextCell = TextCell;
548 IPython.MarkdownCell = MarkdownCell;
548 IPython.MarkdownCell = MarkdownCell;
549 IPython.RawCell = RawCell;
549 IPython.RawCell = RawCell;
550 IPython.HeadingCell = HeadingCell;
550 IPython.HeadingCell = HeadingCell;
551
551
552
552
553 return IPython;
553 return IPython;
554
554
555 }(IPython));
555 }(IPython));
556
556
General Comments 0
You need to be logged in to leave comments. Login now