##// END OF EJS Templates
JS Configurablity Take 2...
Matthias BUSSONNIER -
Show More
@@ -1,334 +1,345 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2008-2011 The IPython Development Team
2 // Copyright (C) 2008-2011 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 // Cell
9 // Cell
10 //============================================================================
10 //============================================================================
11 /**
11 /**
12 * An extendable module that provide base functionnality to create cell for notebook.
12 * An extendable module that provide base functionnality to create cell for notebook.
13 * @module IPython
13 * @module IPython
14 * @namespace IPython
14 * @namespace IPython
15 * @submodule Cell
15 * @submodule Cell
16 */
16 */
17
17
18 var IPython = (function (IPython) {
18 var IPython = (function (IPython) {
19
19
20 var utils = IPython.utils;
20 var utils = IPython.utils;
21
21
22 /**
22 /**
23 * The Base `Cell` class from which to inherit
23 * The Base `Cell` class from which to inherit
24 * @class Cell
24 * @class Cell
25 **/
25 **/
26
26
27 /*
27 /*
28 * @constructor
28 * @constructor
29 *
29 *
30 * @param {object|undefined} [options]
30 * @param {object|undefined} [options]
31 * @param [options.cm_config] {object} config to pass to CodeMirror, will extend default parameters
31 * @param [options.cm_config] {object} config to pass to CodeMirror, will extend default parameters
32 */
32 */
33 var Cell = function (options) {
33 var Cell = function (options) {
34
34
35 options = options || {};
35 options = this.mergeopt(Cell, options)
36 // superclass default overwrite our default
36 // superclass default overwrite our default
37 this.cm_config = $.extend({},Cell.cm_default,options.cm_config);
38
37
39 this.placeholder = this.placeholder || '';
38 this.placeholder = options.placeholder || '';
40 this.read_only = false;
39 this.read_only = options.cm_config.readOnly;
41 this.selected = false;
40 this.selected = false;
42 this.element = null;
41 this.element = null;
43 this.metadata = {};
42 this.metadata = {};
44 // load this from metadata later ?
43 // load this from metadata later ?
45 this.user_highlight = 'auto';
44 this.user_highlight = 'auto';
45 this.cm_config = options.cm_config;
46 this.create_element();
46 this.create_element();
47 if (this.element !== null) {
47 if (this.element !== null) {
48 this.element.data("cell", this);
48 this.element.data("cell", this);
49 this.bind_events();
49 this.bind_events();
50 }
50 }
51 this.cell_id = utils.uuid();
51 this.cell_id = utils.uuid();
52 this._options = options;
52 };
53 };
53
54
54 Cell.cm_default = {
55 Cell.options_default = {
56 cm_config : {
55 indentUnit : 4,
57 indentUnit : 4,
56 readOnly: this.read_only,
58 readOnly: false,
59 theme: "default"
60 }
57 };
61 };
58
62
63 Cell.prototype.mergeopt = function(_class, options, overwrite){
64 overwrite = overwrite ||Β {};
65 return $.extend(true, {}, _class.options_default, options, overwrite)
66
67 }
68
69
59
70
60 /**
71 /**
61 * Empty. Subclasses must implement create_element.
72 * Empty. Subclasses must implement create_element.
62 * This should contain all the code to create the DOM element in notebook
73 * This should contain all the code to create the DOM element in notebook
63 * and will be called by Base Class constructor.
74 * and will be called by Base Class constructor.
64 * @method create_element
75 * @method create_element
65 */
76 */
66 Cell.prototype.create_element = function () {
77 Cell.prototype.create_element = function () {
67 };
78 };
68
79
69
80
70 /**
81 /**
71 * Subclasses can implement override bind_events.
82 * Subclasses can implement override bind_events.
72 * Be carefull to call the parent method when overwriting as it fires event.
83 * Be carefull to call the parent method when overwriting as it fires event.
73 * this will be triggerd after create_element in constructor.
84 * this will be triggerd after create_element in constructor.
74 * @method bind_events
85 * @method bind_events
75 */
86 */
76 Cell.prototype.bind_events = function () {
87 Cell.prototype.bind_events = function () {
77 var that = this;
88 var that = this;
78 // We trigger events so that Cell doesn't have to depend on Notebook.
89 // We trigger events so that Cell doesn't have to depend on Notebook.
79 that.element.click(function (event) {
90 that.element.click(function (event) {
80 if (that.selected === false) {
91 if (that.selected === false) {
81 $([IPython.events]).trigger('select.Cell', {'cell':that});
92 $([IPython.events]).trigger('select.Cell', {'cell':that});
82 }
93 }
83 });
94 });
84 that.element.focusin(function (event) {
95 that.element.focusin(function (event) {
85 if (that.selected === false) {
96 if (that.selected === false) {
86 $([IPython.events]).trigger('select.Cell', {'cell':that});
97 $([IPython.events]).trigger('select.Cell', {'cell':that});
87 }
98 }
88 });
99 });
89 };
100 };
90
101
91 /**
102 /**
92 * Triger typsetting of math by mathjax on current cell element
103 * Triger typsetting of math by mathjax on current cell element
93 * @method typeset
104 * @method typeset
94 */
105 */
95 Cell.prototype.typeset = function () {
106 Cell.prototype.typeset = function () {
96 if (window.MathJax){
107 if (window.MathJax){
97 var cell_math = this.element.get(0);
108 var cell_math = this.element.get(0);
98 MathJax.Hub.Queue(["Typeset",MathJax.Hub,cell_math]);
109 MathJax.Hub.Queue(["Typeset", MathJax.Hub, cell_math]);
99 }
110 }
100 };
111 };
101
112
102 /**
113 /**
103 * should be triggerd when cell is selected
114 * should be triggerd when cell is selected
104 * @method select
115 * @method select
105 */
116 */
106 Cell.prototype.select = function () {
117 Cell.prototype.select = function () {
107 this.element.addClass('selected');
118 this.element.addClass('selected');
108 this.selected = true;
119 this.selected = true;
109 };
120 };
110
121
111
122
112 /**
123 /**
113 * should be triggerd when cell is unselected
124 * should be triggerd when cell is unselected
114 * @method unselect
125 * @method unselect
115 */
126 */
116 Cell.prototype.unselect = function () {
127 Cell.prototype.unselect = function () {
117 this.element.removeClass('selected');
128 this.element.removeClass('selected');
118 this.selected = false;
129 this.selected = false;
119 };
130 };
120
131
121 /**
132 /**
122 * should be overritten by subclass
133 * should be overritten by subclass
123 * @method get_text
134 * @method get_text
124 */
135 */
125 Cell.prototype.get_text = function () {
136 Cell.prototype.get_text = function () {
126 };
137 };
127
138
128 /**
139 /**
129 * should be overritten by subclass
140 * should be overritten by subclass
130 * @method set_text
141 * @method set_text
131 * @param {string} text
142 * @param {string} text
132 */
143 */
133 Cell.prototype.set_text = function (text) {
144 Cell.prototype.set_text = function (text) {
134 };
145 };
135
146
136 /**
147 /**
137 * Refresh codemirror instance
148 * Refresh codemirror instance
138 * @method refresh
149 * @method refresh
139 */
150 */
140 Cell.prototype.refresh = function () {
151 Cell.prototype.refresh = function () {
141 this.code_mirror.refresh();
152 this.code_mirror.refresh();
142 };
153 };
143
154
144
155
145 /**
156 /**
146 * should be overritten by subclass
157 * should be overritten by subclass
147 * @method edit
158 * @method edit
148 **/
159 **/
149 Cell.prototype.edit = function () {
160 Cell.prototype.edit = function () {
150 };
161 };
151
162
152
163
153 /**
164 /**
154 * should be overritten by subclass
165 * should be overritten by subclass
155 * @method render
166 * @method render
156 **/
167 **/
157 Cell.prototype.render = function () {
168 Cell.prototype.render = function () {
158 };
169 };
159
170
160 /**
171 /**
161 * should be overritten by subclass
172 * should be overritten by subclass
162 * serialise cell to json.
173 * serialise cell to json.
163 * @method toJSON
174 * @method toJSON
164 **/
175 **/
165 Cell.prototype.toJSON = function () {
176 Cell.prototype.toJSON = function () {
166 var data = {};
177 var data = {};
167 data.metadata = this.metadata;
178 data.metadata = this.metadata;
168 return data;
179 return data;
169 };
180 };
170
181
171
182
172 /**
183 /**
173 * should be overritten by subclass
184 * should be overritten by subclass
174 * @method fromJSON
185 * @method fromJSON
175 **/
186 **/
176 Cell.prototype.fromJSON = function (data) {
187 Cell.prototype.fromJSON = function (data) {
177 if (data.metadata !== undefined) {
188 if (data.metadata !== undefined) {
178 this.metadata = data.metadata;
189 this.metadata = data.metadata;
179 }
190 }
180 this.celltoolbar.rebuild();
191 this.celltoolbar.rebuild();
181 };
192 };
182
193
183
194
184 /**
195 /**
185 * can the cell be splitted in 2 cells.
196 * can the cell be splitted in 2 cells.
186 * @method is_splittable
197 * @method is_splittable
187 **/
198 **/
188 Cell.prototype.is_splittable = function () {
199 Cell.prototype.is_splittable = function () {
189 return true;
200 return true;
190 };
201 };
191
202
192
203
193 /**
204 /**
194 * @return {String} - the text before the cursor
205 * @return {String} - the text before the cursor
195 * @method get_pre_cursor
206 * @method get_pre_cursor
196 **/
207 **/
197 Cell.prototype.get_pre_cursor = function () {
208 Cell.prototype.get_pre_cursor = function () {
198 var cursor = this.code_mirror.getCursor();
209 var cursor = this.code_mirror.getCursor();
199 var text = this.code_mirror.getRange({line:0,ch:0}, cursor);
210 var text = this.code_mirror.getRange({line:0, ch:0}, cursor);
200 text = text.replace(/^\n+/, '').replace(/\n+$/, '');
211 text = text.replace(/^\n+/, '').replace(/\n+$/, '');
201 return text;
212 return text;
202 }
213 }
203
214
204
215
205 /**
216 /**
206 * @return {String} - the text after the cursor
217 * @return {String} - the text after the cursor
207 * @method get_post_cursor
218 * @method get_post_cursor
208 **/
219 **/
209 Cell.prototype.get_post_cursor = function () {
220 Cell.prototype.get_post_cursor = function () {
210 var cursor = this.code_mirror.getCursor();
221 var cursor = this.code_mirror.getCursor();
211 var last_line_num = this.code_mirror.lineCount()-1;
222 var last_line_num = this.code_mirror.lineCount()-1;
212 var last_line_len = this.code_mirror.getLine(last_line_num).length;
223 var last_line_len = this.code_mirror.getLine(last_line_num).length;
213 var end = {line:last_line_num, ch:last_line_len}
224 var end = {line:last_line_num, ch:last_line_len}
214 var text = this.code_mirror.getRange(cursor, end);
225 var text = this.code_mirror.getRange(cursor, end);
215 text = text.replace(/^\n+/, '').replace(/\n+$/, '');
226 text = text.replace(/^\n+/, '').replace(/\n+$/, '');
216 return text;
227 return text;
217 };
228 };
218
229
219
230
220 /** Grow the cell by hand. This is used upon reloading from JSON, when the
231 /** Grow the cell by hand. This is used upon reloading from JSON, when the
221 * autogrow handler is not called.
232 * autogrow handler is not called.
222 *
233 *
223 * could be made static
234 * could be made static
224 *
235 *
225 * @param {Dom element} - element
236 * @param {Dom element} - element
226 * @method grow
237 * @method grow
227 **/
238 **/
228 Cell.prototype.grow = function(element) {
239 Cell.prototype.grow = function(element) {
229 var dom = element.get(0);
240 var dom = element.get(0);
230 var lines_count = 0;
241 var lines_count = 0;
231 // modified split rule from
242 // modified split rule from
232 // http://stackoverflow.com/questions/2035910/how-to-get-the-number-of-lines-in-a-textarea/2036424#2036424
243 // http://stackoverflow.com/questions/2035910/how-to-get-the-number-of-lines-in-a-textarea/2036424#2036424
233 var lines = dom.value.split(/\r|\r\n|\n/);
244 var lines = dom.value.split(/\r|\r\n|\n/);
234 lines_count = lines.length;
245 lines_count = lines.length;
235 if (lines_count >= 1) {
246 if (lines_count >= 1) {
236 dom.rows = lines_count;
247 dom.rows = lines_count;
237 } else {
248 } else {
238 dom.rows = 1;
249 dom.rows = 1;
239 }
250 }
240 };
251 };
241
252
242 /**
253 /**
243 * Show/Hide CodeMirror LineNumber
254 * Show/Hide CodeMirror LineNumber
244 * @method show_line_numbers
255 * @method show_line_numbers
245 *
256 *
246 * @param value {Bool} show (true), or hide (false) the line number in CodeMirror
257 * @param value {Bool} show (true), or hide (false) the line number in CodeMirror
247 **/
258 **/
248 Cell.prototype.show_line_numbers = function (value) {
259 Cell.prototype.show_line_numbers = function (value) {
249 this.code_mirror.setOption('lineNumbers', value);
260 this.code_mirror.setOption('lineNumbers', value);
250 this.code_mirror.refresh();
261 this.code_mirror.refresh();
251 };
262 };
252
263
253 /**
264 /**
254 * Toggle CodeMirror LineNumber
265 * Toggle CodeMirror LineNumber
255 * @method toggle_line_numbers
266 * @method toggle_line_numbers
256 **/
267 **/
257 Cell.prototype.toggle_line_numbers = function () {
268 Cell.prototype.toggle_line_numbers = function () {
258 var val = this.code_mirror.getOption('lineNumbers');
269 var val = this.code_mirror.getOption('lineNumbers');
259 this.show_line_numbers(!val);
270 this.show_line_numbers(!val);
260 };
271 };
261
272
262 /**
273 /**
263 * Force codemirror highlight mode
274 * Force codemirror highlight mode
264 * @method force_highlight
275 * @method force_highlight
265 * @param {object} - CodeMirror mode
276 * @param {object} - CodeMirror mode
266 **/
277 **/
267 Cell.prototype.force_highlight = function(mode) {
278 Cell.prototype.force_highlight = function(mode) {
268 this.user_highlight = mode;
279 this.user_highlight = mode;
269 this.auto_highlight();
280 this.auto_highlight();
270 };
281 };
271
282
272 /**
283 /**
273 * Try to autodetect cell highlight mode, or use selected mode
284 * Try to autodetect cell highlight mode, or use selected mode
274 * @methods _auto_highlight
285 * @methods _auto_highlight
275 * @private
286 * @private
276 * @param {String|object|undefined} - CodeMirror mode | 'auto'
287 * @param {String|object|undefined} - CodeMirror mode | 'auto'
277 **/
288 **/
278 Cell.prototype._auto_highlight = function (modes) {
289 Cell.prototype._auto_highlight = function (modes) {
279 //Here we handle manually selected modes
290 //Here we handle manually selected modes
280 if( this.user_highlight != undefined && this.user_highlight != 'auto' )
291 if( this.user_highlight != undefined && this.user_highlight != 'auto' )
281 {
292 {
282 var mode = this.user_highlight;
293 var mode = this.user_highlight;
283 CodeMirror.autoLoadMode(this.code_mirror, mode);
294 CodeMirror.autoLoadMode(this.code_mirror, mode);
284 this.code_mirror.setOption('mode', mode);
295 this.code_mirror.setOption('mode', mode);
285 return;
296 return;
286 }
297 }
287 var first_line = this.code_mirror.getLine(0);
298 var first_line = this.code_mirror.getLine(0);
288 // loop on every pairs
299 // loop on every pairs
289 for( var mode in modes) {
300 for( var mode in modes) {
290 var regs = modes[mode]['reg'];
301 var regs = modes[mode]['reg'];
291 // only one key every time but regexp can't be keys...
302 // only one key every time but regexp can't be keys...
292 for(var reg in regs ) {
303 for(var reg in regs ) {
293 // here we handle non magic_modes
304 // here we handle non magic_modes
294 if(first_line.match(regs[reg]) != null) {
305 if(first_line.match(regs[reg]) != null) {
295 if (mode.search('magic_') != 0) {
306 if (mode.search('magic_') != 0) {
296 this.code_mirror.setOption('mode',mode);
307 this.code_mirror.setOption('mode', mode);
297 CodeMirror.autoLoadMode(this.code_mirror, mode);
308 CodeMirror.autoLoadMode(this.code_mirror, mode);
298 return;
309 return;
299 }
310 }
300 var open = modes[mode]['open']|| "%%";
311 var open = modes[mode]['open']|| "%%";
301 var close = modes[mode]['close']|| "%%end";
312 var close = modes[mode]['close']|| "%%end";
302 var mmode = mode;
313 var mmode = mode;
303 mode = mmode.substr(6);
314 mode = mmode.substr(6);
304 CodeMirror.autoLoadMode(this.code_mirror, mode);
315 CodeMirror.autoLoadMode(this.code_mirror, mode);
305 // create on the fly a mode that swhitch between
316 // create on the fly a mode that swhitch between
306 // plain/text and smth else otherwise `%%` is
317 // plain/text and smth else otherwise `%%` is
307 // source of some highlight issues.
318 // source of some highlight issues.
308 // we use patchedGetMode to circumvent a bug in CM
319 // we use patchedGetMode to circumvent a bug in CM
309 CodeMirror.defineMode(mmode , function(config) {
320 CodeMirror.defineMode(mmode , function(config) {
310 return CodeMirror.multiplexingMode(
321 return CodeMirror.multiplexingMode(
311 CodeMirror.patchedGetMode(config, 'text/plain'),
322 CodeMirror.patchedGetMode(config, 'text/plain'),
312 // always set someting on close
323 // always set someting on close
313 {open: open, close: close,
324 {open: open, close: close,
314 mode: CodeMirror.patchedGetMode(config, mode),
325 mode: CodeMirror.patchedGetMode(config, mode),
315 delimStyle: "delimit"
326 delimStyle: "delimit"
316 }
327 }
317 );
328 );
318 });
329 });
319 this.code_mirror.setOption('mode', mmode);
330 this.code_mirror.setOption('mode', mmode);
320 return;
331 return;
321 }
332 }
322 }
333 }
323 }
334 }
324 // fallback on default (python)
335 // fallback on default (python)
325 var default_mode = this.default_mode || 'text/plain';
336 var default_mode = this.default_mode || 'text/plain';
326 this.code_mirror.setOption('mode', default_mode);
337 this.code_mirror.setOption('mode', default_mode);
327 };
338 };
328
339
329 IPython.Cell = Cell;
340 IPython.Cell = Cell;
330
341
331 return IPython;
342 return IPython;
332
343
333 }(IPython));
344 }(IPython));
334
345
@@ -1,428 +1,425 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2008-2011 The IPython Development Team
2 // Copyright (C) 2008-2011 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 // CodeCell
9 // CodeCell
10 //============================================================================
10 //============================================================================
11 /**
11 /**
12 * An extendable module that provide base functionnality to create cell for notebook.
12 * An extendable module that provide base functionnality to create cell for notebook.
13 * @module IPython
13 * @module IPython
14 * @namespace IPython
14 * @namespace IPython
15 * @submodule CodeCell
15 * @submodule CodeCell
16 */
16 */
17
17
18
18
19 /* local util for codemirror */
19 /* local util for codemirror */
20 var posEq = function(a, b) {return a.line == b.line && a.ch == b.ch;}
20 var posEq = function(a, b) {return a.line == b.line && a.ch == b.ch;}
21
21
22 /**
22 /**
23 *
23 *
24 * function to delete until previous non blanking space character
24 * function to delete until previous non blanking space character
25 * or first multiple of 4 tabstop.
25 * or first multiple of 4 tabstop.
26 * @private
26 * @private
27 */
27 */
28 CodeMirror.commands.delSpaceToPrevTabStop = function(cm){
28 CodeMirror.commands.delSpaceToPrevTabStop = function(cm){
29 var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to);
29 var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to);
30 if (!posEq(from, to)) {cm.replaceRange("", from, to); return}
30 if (!posEq(from, to)) {cm.replaceRange("", from, to); return}
31 var cur = cm.getCursor(), line = cm.getLine(cur.line);
31 var cur = cm.getCursor(), line = cm.getLine(cur.line);
32 var tabsize = cm.getOption('tabSize');
32 var tabsize = cm.getOption('tabSize');
33 var chToPrevTabStop = cur.ch-(Math.ceil(cur.ch/tabsize)-1)*tabsize;
33 var chToPrevTabStop = cur.ch-(Math.ceil(cur.ch/tabsize)-1)*tabsize;
34 var from = {ch:cur.ch-chToPrevTabStop,line:cur.line}
34 var from = {ch:cur.ch-chToPrevTabStop,line:cur.line}
35 var select = cm.getRange(from,cur)
35 var select = cm.getRange(from,cur)
36 if( select.match(/^\ +$/) != null){
36 if( select.match(/^\ +$/) != null){
37 cm.replaceRange("",from,cur)
37 cm.replaceRange("",from,cur)
38 } else {
38 } else {
39 cm.deleteH(-1,"char")
39 cm.deleteH(-1,"char")
40 }
40 }
41 };
41 };
42
42
43
43
44 var IPython = (function (IPython) {
44 var IPython = (function (IPython) {
45 "use strict";
45 "use strict";
46
46
47 var utils = IPython.utils;
47 var utils = IPython.utils;
48 var key = IPython.utils.keycodes;
48 var key = IPython.utils.keycodes;
49 CodeMirror.modeURL = "/static/codemirror/mode/%N/%N.js";
49 CodeMirror.modeURL = "/static/codemirror/mode/%N/%N.js";
50
50
51 /**
51 /**
52 * A Cell conceived to write code.
52 * A Cell conceived to write code.
53 *
53 *
54 * The kernel doesn't have to be set at creation time, in that case
54 * The kernel doesn't have to be set at creation time, in that case
55 * it will be null and set_kernel has to be called later.
55 * it will be null and set_kernel has to be called later.
56 * @class CodeCell
56 * @class CodeCell
57 * @extends IPython.Cell
57 * @extends IPython.Cell
58 *
58 *
59 * @constructor
59 * @constructor
60 * @param {Object|null} kernel
60 * @param {Object|null} kernel
61 * @param {object|undefined} [options]
61 * @param {object|undefined} [options]
62 * @param [options.cm_config] {object} config to pass to CodeMirror
62 * @param [options.cm_config] {object} config to pass to CodeMirror
63 */
63 */
64 var CodeCell = function (kernel, options) {
64 var CodeCell = function (kernel, options) {
65 var options = options || {}
66 this.kernel = kernel || null;
65 this.kernel = kernel || null;
67 this.code_mirror = null;
66 this.code_mirror = null;
68 this.input_prompt_number = null;
67 this.input_prompt_number = null;
69 this.collapsed = false;
68 this.collapsed = false;
70 this.default_mode = 'python';
69 this.default_mode = 'python';
71
70
72
71
73 var cm_overwrite_options = {
72 var cm_overwrite_options = {
74 extraKeys: {"Tab": "indentMore","Shift-Tab" : "indentLess",'Backspace':"delSpaceToPrevTabStop"},
75 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
73 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
76 };
74 };
77
75
78 var arg_cm_options = options.cm_options || {};
76 options = this.mergeopt(CodeCell, options, {cm_config:cm_overwrite_options});
79 var cm_config = $.extend({},CodeCell.cm_default, arg_cm_options, cm_overwrite_options);
80
81 var options = {};
82 options.cm_config = cm_config;
83
77
84 IPython.Cell.apply(this,[options]);
78 IPython.Cell.apply(this,[options]);
85
79
86 var that = this;
80 var that = this;
87 this.element.focusout(
81 this.element.focusout(
88 function() { that.auto_highlight(); }
82 function() { that.auto_highlight(); }
89 );
83 );
90 };
84 };
91
85
92 CodeCell.cm_default = {
86 CodeCell.options_default = {
87 cm_config : {
88 extraKeys: {"Tab": "indentMore","Shift-Tab" : "indentLess",'Backspace':"delSpaceToPrevTabStop"},
93 mode: 'python',
89 mode: 'python',
94 theme: 'ipython',
90 theme: 'ipython',
95 matchBrackets: true
91 matchBrackets: true
92 }
96 };
93 };
97
94
98
95
99 CodeCell.prototype = new IPython.Cell();
96 CodeCell.prototype = new IPython.Cell();
100
97
101 /**
98 /**
102 * @method auto_highlight
99 * @method auto_highlight
103 */
100 */
104 CodeCell.prototype.auto_highlight = function () {
101 CodeCell.prototype.auto_highlight = function () {
105 this._auto_highlight(IPython.config.cell_magic_highlight)
102 this._auto_highlight(IPython.config.cell_magic_highlight)
106 };
103 };
107
104
108 /** @method create_element */
105 /** @method create_element */
109 CodeCell.prototype.create_element = function () {
106 CodeCell.prototype.create_element = function () {
110 IPython.Cell.prototype.create_element.apply(this, arguments);
107 IPython.Cell.prototype.create_element.apply(this, arguments);
111
108
112 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox');
109 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox');
113 cell.attr('tabindex','2');
110 cell.attr('tabindex','2');
114
111
115 this.celltoolbar = new IPython.CellToolbar(this);
112 this.celltoolbar = new IPython.CellToolbar(this);
116
113
117 var input = $('<div></div>').addClass('input hbox');
114 var input = $('<div></div>').addClass('input hbox');
118 var vbox = $('<div/>').addClass('vbox box-flex1')
115 var vbox = $('<div/>').addClass('vbox box-flex1')
119 input.append($('<div/>').addClass('prompt input_prompt'));
116 input.append($('<div/>').addClass('prompt input_prompt'));
120 vbox.append(this.celltoolbar.element);
117 vbox.append(this.celltoolbar.element);
121 var input_area = $('<div/>').addClass('input_area');
118 var input_area = $('<div/>').addClass('input_area');
122 this.code_mirror = CodeMirror(input_area.get(0), this.cm_config);
119 this.code_mirror = CodeMirror(input_area.get(0), this.cm_config);
123 $(this.code_mirror.getInputField()).attr("spellcheck", "false");
120 $(this.code_mirror.getInputField()).attr("spellcheck", "false");
124 vbox.append(input_area);
121 vbox.append(input_area);
125 input.append(vbox);
122 input.append(vbox);
126 var output = $('<div></div>');
123 var output = $('<div></div>');
127 cell.append(input).append(output);
124 cell.append(input).append(output);
128 this.element = cell;
125 this.element = cell;
129 this.output_area = new IPython.OutputArea(output, true);
126 this.output_area = new IPython.OutputArea(output, true);
130
127
131 // construct a completer only if class exist
128 // construct a completer only if class exist
132 // otherwise no print view
129 // otherwise no print view
133 if (IPython.Completer !== undefined)
130 if (IPython.Completer !== undefined)
134 {
131 {
135 this.completer = new IPython.Completer(this);
132 this.completer = new IPython.Completer(this);
136 }
133 }
137 };
134 };
138
135
139 /**
136 /**
140 * This method gets called in CodeMirror's onKeyDown/onKeyPress
137 * This method gets called in CodeMirror's onKeyDown/onKeyPress
141 * handlers and is used to provide custom key handling. Its return
138 * handlers and is used to provide custom key handling. Its return
142 * value is used to determine if CodeMirror should ignore the event:
139 * value is used to determine if CodeMirror should ignore the event:
143 * true = ignore, false = don't ignore.
140 * true = ignore, false = don't ignore.
144 * @method handle_codemirror_keyevent
141 * @method handle_codemirror_keyevent
145 */
142 */
146 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
143 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
147
144
148 if (this.read_only){
145 if (this.read_only){
149 return false;
146 return false;
150 }
147 }
151
148
152 var that = this;
149 var that = this;
153 // whatever key is pressed, first, cancel the tooltip request before
150 // whatever key is pressed, first, cancel the tooltip request before
154 // they are sent, and remove tooltip if any, except for tab again
151 // they are sent, and remove tooltip if any, except for tab again
155 if (event.type === 'keydown' && event.which != key.TAB ) {
152 if (event.type === 'keydown' && event.which != key.TAB ) {
156 IPython.tooltip.remove_and_cancel_tooltip();
153 IPython.tooltip.remove_and_cancel_tooltip();
157 };
154 };
158
155
159 var cur = editor.getCursor();
156 var cur = editor.getCursor();
160 if (event.keyCode === key.ENTER){
157 if (event.keyCode === key.ENTER){
161 this.auto_highlight();
158 this.auto_highlight();
162 }
159 }
163
160
164 if (event.keyCode === key.ENTER && (event.shiftKey || event.ctrlKey)) {
161 if (event.keyCode === key.ENTER && (event.shiftKey || event.ctrlKey)) {
165 // Always ignore shift-enter in CodeMirror as we handle it.
162 // Always ignore shift-enter in CodeMirror as we handle it.
166 return true;
163 return true;
167 } else if (event.which === 40 && event.type === 'keypress' && IPython.tooltip.time_before_tooltip >= 0) {
164 } else if (event.which === 40 && event.type === 'keypress' && IPython.tooltip.time_before_tooltip >= 0) {
168 // triger on keypress (!) otherwise inconsistent event.which depending on plateform
165 // triger on keypress (!) otherwise inconsistent event.which depending on plateform
169 // browser and keyboard layout !
166 // browser and keyboard layout !
170 // Pressing '(' , request tooltip, don't forget to reappend it
167 // Pressing '(' , request tooltip, don't forget to reappend it
171 IPython.tooltip.pending(that);
168 IPython.tooltip.pending(that);
172 } else if (event.which === key.UPARROW && event.type === 'keydown') {
169 } else if (event.which === key.UPARROW && event.type === 'keydown') {
173 // If we are not at the top, let CM handle the up arrow and
170 // If we are not at the top, let CM handle the up arrow and
174 // prevent the global keydown handler from handling it.
171 // prevent the global keydown handler from handling it.
175 if (!that.at_top()) {
172 if (!that.at_top()) {
176 event.stop();
173 event.stop();
177 return false;
174 return false;
178 } else {
175 } else {
179 return true;
176 return true;
180 };
177 };
181 } else if (event.which === key.ESC) {
178 } else if (event.which === key.ESC) {
182 IPython.tooltip.remove_and_cancel_tooltip(true);
179 IPython.tooltip.remove_and_cancel_tooltip(true);
183 return true;
180 return true;
184 } else if (event.which === key.DOWNARROW && event.type === 'keydown') {
181 } else if (event.which === key.DOWNARROW && event.type === 'keydown') {
185 // If we are not at the bottom, let CM handle the down arrow and
182 // If we are not at the bottom, let CM handle the down arrow and
186 // prevent the global keydown handler from handling it.
183 // prevent the global keydown handler from handling it.
187 if (!that.at_bottom()) {
184 if (!that.at_bottom()) {
188 event.stop();
185 event.stop();
189 return false;
186 return false;
190 } else {
187 } else {
191 return true;
188 return true;
192 };
189 };
193 } else if (event.keyCode === key.TAB && event.type == 'keydown' && event.shiftKey) {
190 } else if (event.keyCode === key.TAB && event.type == 'keydown' && event.shiftKey) {
194 if (editor.somethingSelected()){
191 if (editor.somethingSelected()){
195 var anchor = editor.getCursor("anchor");
192 var anchor = editor.getCursor("anchor");
196 var head = editor.getCursor("head");
193 var head = editor.getCursor("head");
197 if( anchor.line != head.line){
194 if( anchor.line != head.line){
198 return false;
195 return false;
199 }
196 }
200 }
197 }
201 IPython.tooltip.request(that);
198 IPython.tooltip.request(that);
202 event.stop();
199 event.stop();
203 return true;
200 return true;
204 } else if (event.keyCode === key.TAB && event.type == 'keydown') {
201 } else if (event.keyCode === key.TAB && event.type == 'keydown') {
205 // Tab completion.
202 // Tab completion.
206 //Do not trim here because of tooltip
203 //Do not trim here because of tooltip
207 if (editor.somethingSelected()){return false}
204 if (editor.somethingSelected()){return false}
208 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
205 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
209 if (pre_cursor.trim() === "") {
206 if (pre_cursor.trim() === "") {
210 // Don't autocomplete if the part of the line before the cursor
207 // Don't autocomplete if the part of the line before the cursor
211 // is empty. In this case, let CodeMirror handle indentation.
208 // is empty. In this case, let CodeMirror handle indentation.
212 return false;
209 return false;
213 } else if ((pre_cursor.substr(-1) === "("|| pre_cursor.substr(-1) === " ") && IPython.config.tooltip_on_tab ) {
210 } else if ((pre_cursor.substr(-1) === "("|| pre_cursor.substr(-1) === " ") && IPython.config.tooltip_on_tab ) {
214 IPython.tooltip.request(that);
211 IPython.tooltip.request(that);
215 // Prevent the event from bubbling up.
212 // Prevent the event from bubbling up.
216 event.stop();
213 event.stop();
217 // Prevent CodeMirror from handling the tab.
214 // Prevent CodeMirror from handling the tab.
218 return true;
215 return true;
219 } else {
216 } else {
220 event.stop();
217 event.stop();
221 this.completer.startCompletion();
218 this.completer.startCompletion();
222 return true;
219 return true;
223 };
220 };
224 } else {
221 } else {
225 // keypress/keyup also trigger on TAB press, and we don't want to
222 // keypress/keyup also trigger on TAB press, and we don't want to
226 // use those to disable tab completion.
223 // use those to disable tab completion.
227 return false;
224 return false;
228 };
225 };
229 return false;
226 return false;
230 };
227 };
231
228
232
229
233 // Kernel related calls.
230 // Kernel related calls.
234
231
235 CodeCell.prototype.set_kernel = function (kernel) {
232 CodeCell.prototype.set_kernel = function (kernel) {
236 this.kernel = kernel;
233 this.kernel = kernel;
237 }
234 }
238
235
239 /**
236 /**
240 * Execute current code cell to the kernel
237 * Execute current code cell to the kernel
241 * @method execute
238 * @method execute
242 */
239 */
243 CodeCell.prototype.execute = function () {
240 CodeCell.prototype.execute = function () {
244 this.output_area.clear_output(true, true, true);
241 this.output_area.clear_output(true, true, true);
245 this.set_input_prompt('*');
242 this.set_input_prompt('*');
246 this.element.addClass("running");
243 this.element.addClass("running");
247 var callbacks = {
244 var callbacks = {
248 'execute_reply': $.proxy(this._handle_execute_reply, this),
245 'execute_reply': $.proxy(this._handle_execute_reply, this),
249 'output': $.proxy(this.output_area.handle_output, this.output_area),
246 'output': $.proxy(this.output_area.handle_output, this.output_area),
250 'clear_output': $.proxy(this.output_area.handle_clear_output, this.output_area),
247 'clear_output': $.proxy(this.output_area.handle_clear_output, this.output_area),
251 'set_next_input': $.proxy(this._handle_set_next_input, this)
248 'set_next_input': $.proxy(this._handle_set_next_input, this)
252 };
249 };
253 var msg_id = this.kernel.execute(this.get_text(), callbacks, {silent: false});
250 var msg_id = this.kernel.execute(this.get_text(), callbacks, {silent: false});
254 };
251 };
255
252
256 /**
253 /**
257 * @method _handle_execute_reply
254 * @method _handle_execute_reply
258 * @private
255 * @private
259 */
256 */
260 CodeCell.prototype._handle_execute_reply = function (content) {
257 CodeCell.prototype._handle_execute_reply = function (content) {
261 this.set_input_prompt(content.execution_count);
258 this.set_input_prompt(content.execution_count);
262 this.element.removeClass("running");
259 this.element.removeClass("running");
263 $([IPython.events]).trigger('set_dirty.Notebook', {'value': true});
260 $([IPython.events]).trigger('set_dirty.Notebook', {'value': true});
264 }
261 }
265
262
266 CodeCell.prototype._handle_set_next_input = function (text) {
263 CodeCell.prototype._handle_set_next_input = function (text) {
267 var data = {'cell': this, 'text': text}
264 var data = {'cell': this, 'text': text}
268 $([IPython.events]).trigger('set_next_input.Notebook', data);
265 $([IPython.events]).trigger('set_next_input.Notebook', data);
269 }
266 }
270
267
271 // Basic cell manipulation.
268 // Basic cell manipulation.
272
269
273 CodeCell.prototype.select = function () {
270 CodeCell.prototype.select = function () {
274 IPython.Cell.prototype.select.apply(this);
271 IPython.Cell.prototype.select.apply(this);
275 this.code_mirror.refresh();
272 this.code_mirror.refresh();
276 this.code_mirror.focus();
273 this.code_mirror.focus();
277 this.auto_highlight();
274 this.auto_highlight();
278 // We used to need an additional refresh() after the focus, but
275 // We used to need an additional refresh() after the focus, but
279 // it appears that this has been fixed in CM. This bug would show
276 // it appears that this has been fixed in CM. This bug would show
280 // up on FF when a newly loaded markdown cell was edited.
277 // up on FF when a newly loaded markdown cell was edited.
281 };
278 };
282
279
283
280
284 CodeCell.prototype.select_all = function () {
281 CodeCell.prototype.select_all = function () {
285 var start = {line: 0, ch: 0};
282 var start = {line: 0, ch: 0};
286 var nlines = this.code_mirror.lineCount();
283 var nlines = this.code_mirror.lineCount();
287 var last_line = this.code_mirror.getLine(nlines-1);
284 var last_line = this.code_mirror.getLine(nlines-1);
288 var end = {line: nlines-1, ch: last_line.length};
285 var end = {line: nlines-1, ch: last_line.length};
289 this.code_mirror.setSelection(start, end);
286 this.code_mirror.setSelection(start, end);
290 };
287 };
291
288
292
289
293 CodeCell.prototype.collapse = function () {
290 CodeCell.prototype.collapse = function () {
294 this.collapsed = true;
291 this.collapsed = true;
295 this.output_area.collapse();
292 this.output_area.collapse();
296 };
293 };
297
294
298
295
299 CodeCell.prototype.expand = function () {
296 CodeCell.prototype.expand = function () {
300 this.collapsed = false;
297 this.collapsed = false;
301 this.output_area.expand();
298 this.output_area.expand();
302 };
299 };
303
300
304
301
305 CodeCell.prototype.toggle_output = function () {
302 CodeCell.prototype.toggle_output = function () {
306 this.collapsed = Boolean(1 - this.collapsed);
303 this.collapsed = Boolean(1 - this.collapsed);
307 this.output_area.toggle_output();
304 this.output_area.toggle_output();
308 };
305 };
309
306
310
307
311 CodeCell.prototype.toggle_output_scroll = function () {
308 CodeCell.prototype.toggle_output_scroll = function () {
312 this.output_area.toggle_scroll();
309 this.output_area.toggle_scroll();
313 };
310 };
314
311
315
312
316 CodeCell.input_prompt_classical = function (prompt_value, lines_number) {
313 CodeCell.input_prompt_classical = function (prompt_value, lines_number) {
317 var ns = prompt_value || "&nbsp;";
314 var ns = prompt_value || "&nbsp;";
318 return 'In&nbsp;[' + ns + ']:'
315 return 'In&nbsp;[' + ns + ']:'
319 };
316 };
320
317
321 CodeCell.input_prompt_continuation = function (prompt_value, lines_number) {
318 CodeCell.input_prompt_continuation = function (prompt_value, lines_number) {
322 var html = [CodeCell.input_prompt_classical(prompt_value, lines_number)];
319 var html = [CodeCell.input_prompt_classical(prompt_value, lines_number)];
323 for(var i=1; i < lines_number; i++){html.push(['...:'])};
320 for(var i=1; i < lines_number; i++){html.push(['...:'])};
324 return html.join('</br>')
321 return html.join('</br>')
325 };
322 };
326
323
327 CodeCell.input_prompt_function = CodeCell.input_prompt_classical;
324 CodeCell.input_prompt_function = CodeCell.input_prompt_classical;
328
325
329
326
330 CodeCell.prototype.set_input_prompt = function (number) {
327 CodeCell.prototype.set_input_prompt = function (number) {
331 var nline = 1
328 var nline = 1
332 if( this.code_mirror != undefined) {
329 if( this.code_mirror != undefined) {
333 nline = this.code_mirror.lineCount();
330 nline = this.code_mirror.lineCount();
334 }
331 }
335 this.input_prompt_number = number;
332 this.input_prompt_number = number;
336 var prompt_html = CodeCell.input_prompt_function(this.input_prompt_number, nline);
333 var prompt_html = CodeCell.input_prompt_function(this.input_prompt_number, nline);
337 this.element.find('div.input_prompt').html(prompt_html);
334 this.element.find('div.input_prompt').html(prompt_html);
338 };
335 };
339
336
340
337
341 CodeCell.prototype.clear_input = function () {
338 CodeCell.prototype.clear_input = function () {
342 this.code_mirror.setValue('');
339 this.code_mirror.setValue('');
343 };
340 };
344
341
345
342
346 CodeCell.prototype.get_text = function () {
343 CodeCell.prototype.get_text = function () {
347 return this.code_mirror.getValue();
344 return this.code_mirror.getValue();
348 };
345 };
349
346
350
347
351 CodeCell.prototype.set_text = function (code) {
348 CodeCell.prototype.set_text = function (code) {
352 return this.code_mirror.setValue(code);
349 return this.code_mirror.setValue(code);
353 };
350 };
354
351
355
352
356 CodeCell.prototype.at_top = function () {
353 CodeCell.prototype.at_top = function () {
357 var cursor = this.code_mirror.getCursor();
354 var cursor = this.code_mirror.getCursor();
358 if (cursor.line === 0 && cursor.ch === 0) {
355 if (cursor.line === 0 && cursor.ch === 0) {
359 return true;
356 return true;
360 } else {
357 } else {
361 return false;
358 return false;
362 }
359 }
363 };
360 };
364
361
365
362
366 CodeCell.prototype.at_bottom = function () {
363 CodeCell.prototype.at_bottom = function () {
367 var cursor = this.code_mirror.getCursor();
364 var cursor = this.code_mirror.getCursor();
368 if (cursor.line === (this.code_mirror.lineCount()-1) && cursor.ch === this.code_mirror.getLine(cursor.line).length) {
365 if (cursor.line === (this.code_mirror.lineCount()-1) && cursor.ch === this.code_mirror.getLine(cursor.line).length) {
369 return true;
366 return true;
370 } else {
367 } else {
371 return false;
368 return false;
372 }
369 }
373 };
370 };
374
371
375
372
376 CodeCell.prototype.clear_output = function (stdout, stderr, other) {
373 CodeCell.prototype.clear_output = function (stdout, stderr, other) {
377 this.output_area.clear_output(stdout, stderr, other);
374 this.output_area.clear_output(stdout, stderr, other);
378 };
375 };
379
376
380
377
381 // JSON serialization
378 // JSON serialization
382
379
383 CodeCell.prototype.fromJSON = function (data) {
380 CodeCell.prototype.fromJSON = function (data) {
384 IPython.Cell.prototype.fromJSON.apply(this, arguments);
381 IPython.Cell.prototype.fromJSON.apply(this, arguments);
385 if (data.cell_type === 'code') {
382 if (data.cell_type === 'code') {
386 if (data.input !== undefined) {
383 if (data.input !== undefined) {
387 this.set_text(data.input);
384 this.set_text(data.input);
388 // make this value the starting point, so that we can only undo
385 // make this value the starting point, so that we can only undo
389 // to this state, instead of a blank cell
386 // to this state, instead of a blank cell
390 this.code_mirror.clearHistory();
387 this.code_mirror.clearHistory();
391 this.auto_highlight();
388 this.auto_highlight();
392 }
389 }
393 if (data.prompt_number !== undefined) {
390 if (data.prompt_number !== undefined) {
394 this.set_input_prompt(data.prompt_number);
391 this.set_input_prompt(data.prompt_number);
395 } else {
392 } else {
396 this.set_input_prompt();
393 this.set_input_prompt();
397 };
394 };
398 this.output_area.fromJSON(data.outputs);
395 this.output_area.fromJSON(data.outputs);
399 if (data.collapsed !== undefined) {
396 if (data.collapsed !== undefined) {
400 if (data.collapsed) {
397 if (data.collapsed) {
401 this.collapse();
398 this.collapse();
402 } else {
399 } else {
403 this.expand();
400 this.expand();
404 };
401 };
405 };
402 };
406 };
403 };
407 };
404 };
408
405
409
406
410 CodeCell.prototype.toJSON = function () {
407 CodeCell.prototype.toJSON = function () {
411 var data = IPython.Cell.prototype.toJSON.apply(this);
408 var data = IPython.Cell.prototype.toJSON.apply(this);
412 data.input = this.get_text();
409 data.input = this.get_text();
413 data.cell_type = 'code';
410 data.cell_type = 'code';
414 if (this.input_prompt_number) {
411 if (this.input_prompt_number) {
415 data.prompt_number = this.input_prompt_number;
412 data.prompt_number = this.input_prompt_number;
416 };
413 };
417 var outputs = this.output_area.toJSON();
414 var outputs = this.output_area.toJSON();
418 data.outputs = outputs;
415 data.outputs = outputs;
419 data.language = 'python';
416 data.language = 'python';
420 data.collapsed = this.collapsed;
417 data.collapsed = this.collapsed;
421 return data;
418 return data;
422 };
419 };
423
420
424
421
425 IPython.CodeCell = CodeCell;
422 IPython.CodeCell = CodeCell;
426
423
427 return IPython;
424 return IPython;
428 }(IPython));
425 }(IPython));
@@ -1,561 +1,598 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
13
12 /**
14 /**
13 A module that allow to create different type of Text Cell
15 A module that allow to create different type of Text Cell
14 @module IPython
16 @module IPython
15 @namespace IPython
17 @namespace IPython
16 */
18 */
17 var IPython = (function (IPython) {
19 var IPython = (function (IPython) {
18
20
19 // TextCell base class
21 // TextCell base class
20 var key = IPython.utils.keycodes;
22 var key = IPython.utils.keycodes;
21
23
22 /**
24 /**
23 * Construct a new TextCell, codemirror mode is by default 'htmlmixed', and cell type is 'text'
25 * Construct a new TextCell, codemirror mode is by default 'htmlmixed', and cell type is 'text'
24 * cell start as not redered.
26 * cell start as not redered.
25 *
27 *
26 * @class TextCell
28 * @class TextCell
27 * @constructor TextCell
29 * @constructor TextCell
28 * @extend Ipython.Cell
30 * @extend Ipython.Cell
29 * @param {object|undefined} [options]
31 * @param {object|undefined} [options]
30 * @param [options.cm_config] {object} config to pass to CodeMirror, will extend/overwrite default config
32 * @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)
31 */
34 */
32 var TextCell = function (options) {
35 var TextCell = function (options) {
33 this.code_mirror_mode = this.code_mirror_mode || 'htmlmixed';
36 // in all TextCell/Cell subclasses
34 var options = options || {};
37 // do not assign most of members here, just pass it down
38 // in the options dict potentially overwriting what you wish.
39 // they will be assigned in the base class.
35
40
41 // we cannot put this as a class key as it has handle to "this".
36 var cm_overwrite_options = {
42 var cm_overwrite_options = {
37 extraKeys: {"Tab": "indentMore","Shift-Tab" : "indentLess"},
38 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
43 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
39 };
44 };
40
45
41 var arg_cm_options = options.cm_options || {};
46 options = this.mergeopt(TextCell,options,{cm_config:cm_overwrite_options});
42 var cm_config = $.extend({},TextCell.cm_default, arg_cm_options, cm_overwrite_options);
43
47
44 var options = {};
48 IPython.Cell.apply(this, [options]);
45 options.cm_config = cm_config;
46
49
47
50
48 IPython.Cell.apply(this, [options]);
49 this.rendered = false;
51 this.rendered = false;
50 this.cell_type = this.cell_type || 'text';
52 this.cell_type = this.cell_type || 'text';
51 };
53 };
52
54
53 TextCell.cm_default = {
55 TextCell.prototype = new IPython.Cell();
54 mode: this.code_mirror_mode,
56
55 theme: 'default',
57 TextCell.options_default = {
56 value: this.placeholder,
58 cm_config : {
59 extraKeys: {"Tab": "indentMore","Shift-Tab" : "indentLess"},
60 mode: 'htmlmixed',
57 lineWrapping : true,
61 lineWrapping : true,
58 }
62 }
63 };
59
64
60
65
61 TextCell.prototype = new IPython.Cell();
62
66
63 /**
67 /**
64 * Create the DOM element of the TextCell
68 * Create the DOM element of the TextCell
65 * @method create_element
69 * @method create_element
66 * @private
70 * @private
67 */
71 */
68 TextCell.prototype.create_element = function () {
72 TextCell.prototype.create_element = function () {
69 IPython.Cell.prototype.create_element.apply(this, arguments);
73 IPython.Cell.prototype.create_element.apply(this, arguments);
70 var cell = $("<div>").addClass('cell text_cell border-box-sizing vbox');
74 var cell = $("<div>").addClass('cell text_cell border-box-sizing vbox');
71 cell.attr('tabindex','2');
75 cell.attr('tabindex','2');
72
76
73 this.celltoolbar = new IPython.CellToolbar(this);
77 this.celltoolbar = new IPython.CellToolbar(this);
74 cell.append(this.celltoolbar.element);
78 cell.append(this.celltoolbar.element);
75
79
76 var input_area = $('<div/>').addClass('text_cell_input border-box-sizing');
80 var input_area = $('<div/>').addClass('text_cell_input border-box-sizing');
77 this.code_mirror = CodeMirror(input_area.get(0), this.cm_config);
81 this.code_mirror = CodeMirror(input_area.get(0), this.cm_config);
82
78 // The tabindex=-1 makes this div focusable.
83 // The tabindex=-1 makes this div focusable.
79 var render_area = $('<div/>').addClass('text_cell_render border-box-sizing').
84 var render_area = $('<div/>').addClass('text_cell_render border-box-sizing').
80 addClass('rendered_html').attr('tabindex','-1');
85 addClass('rendered_html').attr('tabindex','-1');
81 cell.append(input_area).append(render_area);
86 cell.append(input_area).append(render_area);
82 this.element = cell;
87 this.element = cell;
83 };
88 };
84
89
85
90
86 /**
91 /**
87 * Bind the DOM evet to cell actions
92 * Bind the DOM evet to cell actions
88 * Need to be called after TextCell.create_element
93 * Need to be called after TextCell.create_element
89 * @private
94 * @private
90 * @method bind_event
95 * @method bind_event
91 */
96 */
92 TextCell.prototype.bind_events = function () {
97 TextCell.prototype.bind_events = function () {
93 IPython.Cell.prototype.bind_events.apply(this);
98 IPython.Cell.prototype.bind_events.apply(this);
94 var that = this;
99 var that = this;
95 this.element.keydown(function (event) {
100 this.element.keydown(function (event) {
96 if (event.which === 13 && !event.shiftKey) {
101 if (event.which === 13 && !event.shiftKey) {
97 if (that.rendered) {
102 if (that.rendered) {
98 that.edit();
103 that.edit();
99 return false;
104 return false;
100 };
105 };
101 };
106 };
102 });
107 });
103 this.element.dblclick(function () {
108 this.element.dblclick(function () {
104 that.edit();
109 that.edit();
105 });
110 });
106 };
111 };
107
112
108 /**
113 /**
109 * This method gets called in CodeMirror's onKeyDown/onKeyPress
114 * This method gets called in CodeMirror's onKeyDown/onKeyPress
110 * handlers and is used to provide custom key handling.
115 * handlers and is used to provide custom key handling.
111 *
116 *
112 * Subclass should override this method to have custom handeling
117 * Subclass should override this method to have custom handeling
113 *
118 *
114 * @method handle_codemirror_keyevent
119 * @method handle_codemirror_keyevent
115 * @param {CodeMirror} editor - The codemirror instance bound to the cell
120 * @param {CodeMirror} editor - The codemirror instance bound to the cell
116 * @param {event} event -
121 * @param {event} event -
117 * @return {Boolean} `true` if CodeMirror should ignore the event, `false` Otherwise
122 * @return {Boolean} `true` if CodeMirror should ignore the event, `false` Otherwise
118 */
123 */
119 TextCell.prototype.handle_codemirror_keyevent = function (editor, event) {
124 TextCell.prototype.handle_codemirror_keyevent = function (editor, event) {
120
125
121 if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) {
126 if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) {
122 // Always ignore shift-enter in CodeMirror as we handle it.
127 // Always ignore shift-enter in CodeMirror as we handle it.
123 return true;
128 return true;
124 }
129 }
125 return false;
130 return false;
126 };
131 };
127
132
128 /**
133 /**
129 * Select the current cell and trigger 'focus'
134 * Select the current cell and trigger 'focus'
130 * @method select
135 * @method select
131 */
136 */
132 TextCell.prototype.select = function () {
137 TextCell.prototype.select = function () {
133 IPython.Cell.prototype.select.apply(this);
138 IPython.Cell.prototype.select.apply(this);
134 var output = this.element.find("div.text_cell_render");
139 var output = this.element.find("div.text_cell_render");
135 output.trigger('focus');
140 output.trigger('focus');
136 };
141 };
137
142
138 /**
143 /**
139 * unselect the current cell and `render` it
144 * unselect the current cell and `render` it
140 * @method unselect
145 * @method unselect
141 */
146 */
142 TextCell.prototype.unselect = function() {
147 TextCell.prototype.unselect = function() {
143 // render on selection of another cell
148 // render on selection of another cell
144 this.render();
149 this.render();
145 IPython.Cell.prototype.unselect.apply(this);
150 IPython.Cell.prototype.unselect.apply(this);
146 };
151 };
147
152
148 /**
153 /**
149 *
154 *
150 * put the current cell in edition mode
155 * put the current cell in edition mode
151 * @method edit
156 * @method edit
152 */
157 */
153 TextCell.prototype.edit = function () {
158 TextCell.prototype.edit = function () {
154 if ( this.read_only ) return;
159 if ( this.read_only ) return;
155 if (this.rendered === true) {
160 if (this.rendered === true) {
156 var text_cell = this.element;
161 var text_cell = this.element;
157 var output = text_cell.find("div.text_cell_render");
162 var output = text_cell.find("div.text_cell_render");
158 output.hide();
163 output.hide();
159 text_cell.find('div.text_cell_input').show();
164 text_cell.find('div.text_cell_input').show();
160 this.code_mirror.refresh();
165 this.code_mirror.refresh();
161 this.code_mirror.focus();
166 this.code_mirror.focus();
162 // We used to need an additional refresh() after the focus, but
167 // We used to need an additional refresh() after the focus, but
163 // 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
164 // up on FF when a newly loaded markdown cell was edited.
169 // up on FF when a newly loaded markdown cell was edited.
165 this.rendered = false;
170 this.rendered = false;
166 if (this.get_text() === this.placeholder) {
171 if (this.get_text() === this.placeholder) {
167 this.set_text('');
172 this.set_text('');
168 this.refresh();
173 this.refresh();
169 }
174 }
170 }
175 }
171 };
176 };
172
177
173
178
174 /**
179 /**
175 * Empty, Subclasses must define render.
180 * Empty, Subclasses must define render.
176 * @method render
181 * @method render
177 */
182 */
178 TextCell.prototype.render = function () {};
183 TextCell.prototype.render = function () {};
179
184
180
185
181 /**
186 /**
182 * setter: {{#crossLink "TextCell/set_text"}}{{/crossLink}}
187 * setter: {{#crossLink "TextCell/set_text"}}{{/crossLink}}
183 * @method get_text
188 * @method get_text
184 * @retrun {string} CodeMirror current text value
189 * @retrun {string} CodeMirror current text value
185 */
190 */
186 TextCell.prototype.get_text = function() {
191 TextCell.prototype.get_text = function() {
187 return this.code_mirror.getValue();
192 return this.code_mirror.getValue();
188 };
193 };
189
194
190 /**
195 /**
191 * @param {string} text - Codemiror text value
196 * @param {string} text - Codemiror text value
192 * @see TextCell#get_text
197 * @see TextCell#get_text
193 * @method set_text
198 * @method set_text
194 * */
199 * */
195 TextCell.prototype.set_text = function(text) {
200 TextCell.prototype.set_text = function(text) {
196 this.code_mirror.setValue(text);
201 this.code_mirror.setValue(text);
197 this.code_mirror.refresh();
202 this.code_mirror.refresh();
198 };
203 };
199
204
200 /**
205 /**
201 * setter :{{#crossLink "TextCell/set_rendered"}}{{/crossLink}}
206 * setter :{{#crossLink "TextCell/set_rendered"}}{{/crossLink}}
202 * @method get_rendered
207 * @method get_rendered
203 * @return {html} html of rendered element
208 * @return {html} html of rendered element
204 * */
209 * */
205 TextCell.prototype.get_rendered = function() {
210 TextCell.prototype.get_rendered = function() {
206 return this.element.find('div.text_cell_render').html();
211 return this.element.find('div.text_cell_render').html();
207 };
212 };
208
213
209 /**
214 /**
210 * @method set_rendered
215 * @method set_rendered
211 */
216 */
212 TextCell.prototype.set_rendered = function(text) {
217 TextCell.prototype.set_rendered = function(text) {
213 this.element.find('div.text_cell_render').html(text);
218 this.element.find('div.text_cell_render').html(text);
214 };
219 };
215
220
216 /**
221 /**
217 * not deprecated, but implementation wrong
222 * not deprecated, but implementation wrong
218 * @method at_top
223 * @method at_top
219 * @deprecated
224 * @deprecated
220 * @return {Boolean} true is cell rendered, false otherwise
225 * @return {Boolean} true is cell rendered, false otherwise
221 * I doubt this is what it is supposed to do
226 * I doubt this is what it is supposed to do
222 * this implementation is completly false
227 * this implementation is completly false
223 */
228 */
224 TextCell.prototype.at_top = function () {
229 TextCell.prototype.at_top = function () {
225 if (this.rendered) {
230 if (this.rendered) {
226 return true;
231 return true;
227 } else {
232 } else {
228 return false;
233 return false;
229 }
234 }
230 };
235 };
231
236
232
237
233 /**
238 /**
234 * not deprecated, but implementation wrong
239 * not deprecated, but implementation wrong
235 * @method at_bottom
240 * @method at_bottom
236 * @deprecated
241 * @deprecated
237 * @return {Boolean} true is cell rendered, false otherwise
242 * @return {Boolean} true is cell rendered, false otherwise
238 * I doubt this is what it is supposed to do
243 * I doubt this is what it is supposed to do
239 * this implementation is completly false
244 * this implementation is completly false
240 * */
245 * */
241 TextCell.prototype.at_bottom = function () {
246 TextCell.prototype.at_bottom = function () {
242 if (this.rendered) {
247 if (this.rendered) {
243 return true;
248 return true;
244 } else {
249 } else {
245 return false;
250 return false;
246 }
251 }
247 };
252 };
248
253
249 /**
254 /**
250 * Create Text cell from JSON
255 * Create Text cell from JSON
251 * @param {json} data - JSON serialized text-cell
256 * @param {json} data - JSON serialized text-cell
252 * @method fromJSON
257 * @method fromJSON
253 */
258 */
254 TextCell.prototype.fromJSON = function (data) {
259 TextCell.prototype.fromJSON = function (data) {
255 IPython.Cell.prototype.fromJSON.apply(this, arguments);
260 IPython.Cell.prototype.fromJSON.apply(this, arguments);
256 if (data.cell_type === this.cell_type) {
261 if (data.cell_type === this.cell_type) {
257 if (data.source !== undefined) {
262 if (data.source !== undefined) {
258 this.set_text(data.source);
263 this.set_text(data.source);
259 // 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
260 // to this state, instead of a blank cell
265 // to this state, instead of a blank cell
261 this.code_mirror.clearHistory();
266 this.code_mirror.clearHistory();
262 this.set_rendered(data.rendered || '');
267 this.set_rendered(data.rendered || '');
263 this.rendered = false;
268 this.rendered = false;
264 this.render();
269 this.render();
265 }
270 }
266 }
271 }
267 };
272 };
268
273
269 /** Generate JSON from cell
274 /** Generate JSON from cell
270 * @return {object} cell data serialised to json
275 * @return {object} cell data serialised to json
271 */
276 */
272 TextCell.prototype.toJSON = function () {
277 TextCell.prototype.toJSON = function () {
273 var data = IPython.Cell.prototype.toJSON.apply(this);
278 var data = IPython.Cell.prototype.toJSON.apply(this);
274 data.cell_type = this.cell_type;
279 data.cell_type = this.cell_type;
275 data.source = this.get_text();
280 data.source = this.get_text();
276 return data;
281 return data;
277 };
282 };
278
283
279
284
280 /**
285 /**
281 * @constructor HtmlCell
286 * @constructor HtmlCell
282 * @class HtmlCell
287 * @class HtmlCell
283 * @extends Ipython.TextCell
288 * @extends Ipython.TextCell
284 */
289 */
285 var HTMLCell = function () {
290 var HTMLCell = function (options) {
286 this.placeholder = "Type <strong>HTML</strong> and LaTeX: $\\alpha^2$";
291
287 IPython.TextCell.apply(this, arguments);
292 options = this.mergeopt(HTMLCell,options);
293 TextCell.apply(this, [options]);
294
288 this.cell_type = 'html';
295 this.cell_type = 'html';
289 };
296 };
290
297
298 HTMLCell.options_default = {
299 cm_config : {
300 mode: 'htmlmixed',
301 },
302 placeholder: "Type <strong>HTML</strong> and LaTeX: $\\alpha^2$"
303 };
304
291
305
292 HTMLCell.prototype = new TextCell();
306 HTMLCell.prototype = new TextCell();
293
307
294 /**
308 /**
295 * @method render
309 * @method render
296 */
310 */
297 HTMLCell.prototype.render = function () {
311 HTMLCell.prototype.render = function () {
298 if (this.rendered === false) {
312 if (this.rendered === false) {
299 var text = this.get_text();
313 var text = this.get_text();
300 if (text === "") { text = this.placeholder; }
314 if (text === "") { text = this.placeholder; }
301 this.set_rendered(text);
315 this.set_rendered(text);
302 this.typeset();
316 this.typeset();
303 this.element.find('div.text_cell_input').hide();
317 this.element.find('div.text_cell_input').hide();
304 this.element.find("div.text_cell_render").show();
318 this.element.find("div.text_cell_render").show();
305 this.rendered = true;
319 this.rendered = true;
306 }
320 }
307 };
321 };
308
322
309
323
310 /**
324 /**
311 * @class MarkdownCell
325 * @class MarkdownCell
312 * @constructor MarkdownCell
326 * @constructor MarkdownCell
313 * @extends Ipython.HtmlCell
327 * @extends Ipython.HtmlCell
314 */
328 */
315 var MarkdownCell = function () {
329 var MarkdownCell = function (options) {
316 this.placeholder = "Type *Markdown* and LaTeX: $\\alpha^2$";
330 var options = options || {};
317 IPython.TextCell.apply(this, arguments);
331
332 options = this.mergeopt(MarkdownCell,options);
333 TextCell.apply(this, [options]);
334
318 this.cell_type = 'markdown';
335 this.cell_type = 'markdown';
319 };
336 };
320
337
338 MarkdownCell.options_default = {
339 cm_config: {
340 mode: 'markdown'
341 },
342 placeholder: "Type *Markdown* and LaTeX: $\\alpha^2$"
343 }
344
345
346
321
347
322 MarkdownCell.prototype = new TextCell();
348 MarkdownCell.prototype = new TextCell();
323
349
324 /**
350 /**
325 * @method render
351 * @method render
326 */
352 */
327 MarkdownCell.prototype.render = function () {
353 MarkdownCell.prototype.render = function () {
328 if (this.rendered === false) {
354 if (this.rendered === false) {
329 var text = this.get_text();
355 var text = this.get_text();
330 if (text === "") { text = this.placeholder; }
356 if (text === "") { text = this.placeholder; }
331 text = IPython.mathjaxutils.remove_math(text)
357 text = IPython.mathjaxutils.remove_math(text)
332 var html = IPython.markdown_converter.makeHtml(text);
358 var html = IPython.markdown_converter.makeHtml(text);
333 html = IPython.mathjaxutils.replace_math(html)
359 html = IPython.mathjaxutils.replace_math(html)
334 try {
360 try {
335 this.set_rendered(html);
361 this.set_rendered(html);
336 } catch (e) {
362 } catch (e) {
337 console.log("Error running Javascript in Markdown:");
363 console.log("Error running Javascript in Markdown:");
338 console.log(e);
364 console.log(e);
339 this.set_rendered($("<div/>").addClass("js-error").html(
365 this.set_rendered($("<div/>").addClass("js-error").html(
340 "Error rendering Markdown!<br/>" + e.toString())
366 "Error rendering Markdown!<br/>" + e.toString())
341 );
367 );
342 }
368 }
343 this.element.find('div.text_cell_input').hide();
369 this.element.find('div.text_cell_input').hide();
344 this.element.find("div.text_cell_render").show();
370 this.element.find("div.text_cell_render").show();
345 var code_snippets = this.element.find("pre > code");
371 var code_snippets = this.element.find("pre > code");
346 code_snippets.replaceWith(function () {
372 code_snippets.replaceWith(function () {
347 var code = $(this).html();
373 var code = $(this).html();
348 /* Substitute br for newlines and &nbsp; for spaces
374 /* Substitute br for newlines and &nbsp; for spaces
349 before highlighting, since prettify doesn't
375 before highlighting, since prettify doesn't
350 preserve those on all browsers */
376 preserve those on all browsers */
351 code = code.replace(/(\r\n|\n|\r)/gm, "<br/>");
377 code = code.replace(/(\r\n|\n|\r)/gm, "<br/>");
352 code = code.replace(/ /gm, '&nbsp;');
378 code = code.replace(/ /gm, '&nbsp;');
353 code = prettyPrintOne(code);
379 code = prettyPrintOne(code);
354
380
355 return '<code class="prettyprint">' + code + '</code>';
381 return '<code class="prettyprint">' + code + '</code>';
356 });
382 });
357 this.typeset()
383 this.typeset()
358 this.rendered = true;
384 this.rendered = true;
359 }
385 }
360 };
386 };
361
387
362
388
363 // RawCell
389 // RawCell
364
390
365 /**
391 /**
366 * @class RawCell
392 * @class RawCell
367 * @constructor RawCell
393 * @constructor RawCell
368 * @extends Ipython.TextCell
394 * @extends Ipython.TextCell
369 */
395 */
370 var RawCell = function () {
396 var RawCell = function (options) {
371 this.placeholder = "Type plain text and LaTeX: $\\alpha^2$";
397
372 this.code_mirror_mode = 'rst';
398 options = this.mergeopt(RawCell,options)
373 IPython.TextCell.apply(this, arguments);
399 TextCell.apply(this, [options]);
400
374 this.cell_type = 'raw';
401 this.cell_type = 'raw';
375 var that = this
376
402
403 var that = this
377 this.element.focusout(
404 this.element.focusout(
378 function() { that.auto_highlight(); }
405 function() { that.auto_highlight(); }
379 );
406 );
380 };
407 };
381
408
409 RawCell.options_default = {
410 placeholder : "Type plain text and LaTeX: $\\alpha^2$"
411 };
412
413
382
414
383 RawCell.prototype = new TextCell();
415 RawCell.prototype = new TextCell();
384
416
385 /**
417 /**
386 * Trigger autodetection of highlight scheme for current cell
418 * Trigger autodetection of highlight scheme for current cell
387 * @method auto_highlight
419 * @method auto_highlight
388 */
420 */
389 RawCell.prototype.auto_highlight = function () {
421 RawCell.prototype.auto_highlight = function () {
390 this._auto_highlight(IPython.config.raw_cell_highlight);
422 this._auto_highlight(IPython.config.raw_cell_highlight);
391 };
423 };
392
424
393 /** @method render **/
425 /** @method render **/
394 RawCell.prototype.render = function () {
426 RawCell.prototype.render = function () {
395 this.rendered = true;
427 this.rendered = true;
396 this.edit();
428 this.edit();
397 };
429 };
398
430
399
431
400 /** @method handle_codemirror_keyevent **/
432 /** @method handle_codemirror_keyevent **/
401 RawCell.prototype.handle_codemirror_keyevent = function (editor, event) {
433 RawCell.prototype.handle_codemirror_keyevent = function (editor, event) {
402
434
403 var that = this;
435 var that = this;
404 if (event.which === key.UPARROW && event.type === 'keydown') {
436 if (event.which === key.UPARROW && event.type === 'keydown') {
405 // If we are not at the top, let CM handle the up arrow and
437 // If we are not at the top, let CM handle the up arrow and
406 // prevent the global keydown handler from handling it.
438 // prevent the global keydown handler from handling it.
407 if (!that.at_top()) {
439 if (!that.at_top()) {
408 event.stop();
440 event.stop();
409 return false;
441 return false;
410 } else {
442 } else {
411 return true;
443 return true;
412 };
444 };
413 } else if (event.which === key.DOWNARROW && event.type === 'keydown') {
445 } else if (event.which === key.DOWNARROW && event.type === 'keydown') {
414 // If we are not at the bottom, let CM handle the down arrow and
446 // If we are not at the bottom, let CM handle the down arrow and
415 // prevent the global keydown handler from handling it.
447 // prevent the global keydown handler from handling it.
416 if (!that.at_bottom()) {
448 if (!that.at_bottom()) {
417 event.stop();
449 event.stop();
418 return false;
450 return false;
419 } else {
451 } else {
420 return true;
452 return true;
421 };
453 };
422 };
454 };
423 return false;
455 return false;
424 };
456 };
425
457
426 /** @method select **/
458 /** @method select **/
427 RawCell.prototype.select = function () {
459 RawCell.prototype.select = function () {
428 IPython.Cell.prototype.select.apply(this);
460 IPython.Cell.prototype.select.apply(this);
429 this.code_mirror.refresh();
461 this.code_mirror.refresh();
430 this.code_mirror.focus();
462 this.code_mirror.focus();
431 };
463 };
432
464
433 /** @method at_top **/
465 /** @method at_top **/
434 RawCell.prototype.at_top = function () {
466 RawCell.prototype.at_top = function () {
435 var cursor = this.code_mirror.getCursor();
467 var cursor = this.code_mirror.getCursor();
436 if (cursor.line === 0 && cursor.ch === 0) {
468 if (cursor.line === 0 && cursor.ch === 0) {
437 return true;
469 return true;
438 } else {
470 } else {
439 return false;
471 return false;
440 }
472 }
441 };
473 };
442
474
443
475
444 /** @method at_bottom **/
476 /** @method at_bottom **/
445 RawCell.prototype.at_bottom = function () {
477 RawCell.prototype.at_bottom = function () {
446 var cursor = this.code_mirror.getCursor();
478 var cursor = this.code_mirror.getCursor();
447 if (cursor.line === (this.code_mirror.lineCount()-1) && cursor.ch === this.code_mirror.getLine(cursor.line).length) {
479 if (cursor.line === (this.code_mirror.lineCount()-1) && cursor.ch === this.code_mirror.getLine(cursor.line).length) {
448 return true;
480 return true;
449 } else {
481 } else {
450 return false;
482 return false;
451 }
483 }
452 };
484 };
453
485
454
486
455 /**
487 /**
456 * @class HeadingCell
488 * @class HeadingCell
457 * @extends Ipython.TextCell
489 * @extends Ipython.TextCell
458 */
490 */
459
491
460 /**
492 /**
461 * @constructor HeadingCell
493 * @constructor HeadingCell
462 * @extends Ipython.TextCell
494 * @extends Ipython.TextCell
463 */
495 */
464 var HeadingCell = function () {
496 var HeadingCell = function (options) {
465 this.placeholder = "Type Heading Here";
497
466 IPython.TextCell.apply(this, arguments);
498 options = this.mergeopt(HeadingCell,options)
499 TextCell.apply(this, [options]);
500
467 /**
501 /**
468 * heading level of the cell, use getter and setter to access
502 * heading level of the cell, use getter and setter to access
469 * @property level
503 * @property level
470 */
504 */
471 this.level = 1;
505 this.level = 1;
472 this.cell_type = 'heading';
506 this.cell_type = 'heading';
473 };
507 };
474
508
509 HeadingCell.options_default = {
510 placeholder: "Type Heading Here"
511 };
475
512
476 HeadingCell.prototype = new TextCell();
513 HeadingCell.prototype = new TextCell();
477
514
478 /** @method fromJSON */
515 /** @method fromJSON */
479 HeadingCell.prototype.fromJSON = function (data) {
516 HeadingCell.prototype.fromJSON = function (data) {
480 if (data.level != undefined){
517 if (data.level != undefined){
481 this.level = data.level;
518 this.level = data.level;
482 }
519 }
483 IPython.TextCell.prototype.fromJSON.apply(this, arguments);
520 TextCell.prototype.fromJSON.apply(this, arguments);
484 };
521 };
485
522
486
523
487 /** @method toJSON */
524 /** @method toJSON */
488 HeadingCell.prototype.toJSON = function () {
525 HeadingCell.prototype.toJSON = function () {
489 var data = IPython.TextCell.prototype.toJSON.apply(this);
526 var data = TextCell.prototype.toJSON.apply(this);
490 data.level = this.get_level();
527 data.level = this.get_level();
491 return data;
528 return data;
492 };
529 };
493
530
494
531
495 /**
532 /**
496 * Change heading level of cell, and re-render
533 * Change heading level of cell, and re-render
497 * @method set_level
534 * @method set_level
498 */
535 */
499 HeadingCell.prototype.set_level = function (level) {
536 HeadingCell.prototype.set_level = function (level) {
500 this.level = level;
537 this.level = level;
501 if (this.rendered) {
538 if (this.rendered) {
502 this.rendered = false;
539 this.rendered = false;
503 this.render();
540 this.render();
504 };
541 };
505 };
542 };
506
543
507 /** The depth of header cell, based on html (h1 to h6)
544 /** The depth of header cell, based on html (h1 to h6)
508 * @method get_level
545 * @method get_level
509 * @return {integer} level - for 1 to 6
546 * @return {integer} level - for 1 to 6
510 */
547 */
511 HeadingCell.prototype.get_level = function () {
548 HeadingCell.prototype.get_level = function () {
512 return this.level;
549 return this.level;
513 };
550 };
514
551
515
552
516 HeadingCell.prototype.set_rendered = function (text) {
553 HeadingCell.prototype.set_rendered = function (text) {
517 var r = this.element.find("div.text_cell_render");
554 var r = this.element.find("div.text_cell_render");
518 r.empty();
555 r.empty();
519 var link = text.replace(/ /g, '_');
556 var link = text.replace(/ /g, '_');
520 r.append(
557 r.append(
521 $('<h'+this.level+'/>')
558 $('<h'+this.level+'/>')
522 .append(
559 .append(
523 $('<a/>')
560 $('<a/>')
524 .addClass('heading-anchor')
561 .addClass('heading-anchor')
525 .attr('href', '#' + link)
562 .attr('href', '#' + link)
526 .attr('id', link)
563 .attr('id', link)
527 .html(text)
564 .html(text)
528 )
565 )
529 );
566 );
530 };
567 };
531
568
532
569
533 HeadingCell.prototype.get_rendered = function () {
570 HeadingCell.prototype.get_rendered = function () {
534 var r = this.element.find("div.text_cell_render");
571 var r = this.element.find("div.text_cell_render");
535 return r.children().first().html();
572 return r.children().first().html();
536 };
573 };
537
574
538
575
539 HeadingCell.prototype.render = function () {
576 HeadingCell.prototype.render = function () {
540 if (this.rendered === false) {
577 if (this.rendered === false) {
541 var text = this.get_text();
578 var text = this.get_text();
542 if (text === "") { text = this.placeholder; }
579 if (text === "") { text = this.placeholder; }
543 this.set_rendered(text);
580 this.set_rendered(text);
544 this.typeset();
581 this.typeset();
545 this.element.find('div.text_cell_input').hide();
582 this.element.find('div.text_cell_input').hide();
546 this.element.find("div.text_cell_render").show();
583 this.element.find("div.text_cell_render").show();
547 this.rendered = true;
584 this.rendered = true;
548 };
585 };
549 };
586 };
550
587
551 IPython.TextCell = TextCell;
588 IPython.TextCell = TextCell;
552 IPython.HTMLCell = HTMLCell;
589 IPython.HTMLCell = HTMLCell;
553 IPython.MarkdownCell = MarkdownCell;
590 IPython.MarkdownCell = MarkdownCell;
554 IPython.RawCell = RawCell;
591 IPython.RawCell = RawCell;
555 IPython.HeadingCell = HeadingCell;
592 IPython.HeadingCell = HeadingCell;
556
593
557
594
558 return IPython;
595 return IPython;
559
596
560 }(IPython));
597 }(IPython));
561
598
General Comments 0
You need to be logged in to leave comments. Login now