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