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