##// END OF EJS Templates
cleanup whitespace
Matthias Bussonnier -
Show More
@@ -1,588 +1,588
1 // Copyright (c) IPython Development Team.
1 // Copyright (c) IPython Development Team.
2 // Distributed under the terms of the Modified BSD License.
2 // Distributed under the terms of the Modified BSD License.
3
3
4 /**
4 /**
5 *
5 *
6 *
6 *
7 * @module cell
7 * @module cell
8 * @namespace cell
8 * @namespace cell
9 * @class Cell
9 * @class Cell
10 */
10 */
11
11
12
12
13 define([
13 define([
14 'base/js/namespace',
14 'base/js/namespace',
15 'jquery',
15 'jquery',
16 'base/js/utils',
16 'base/js/utils',
17 'codemirror/lib/codemirror',
17 'codemirror/lib/codemirror',
18 'codemirror/addon/edit/matchbrackets',
18 'codemirror/addon/edit/matchbrackets',
19 'codemirror/addon/edit/closebrackets',
19 'codemirror/addon/edit/closebrackets',
20 'codemirror/addon/comment/comment'
20 'codemirror/addon/comment/comment'
21 ], function(IPython, $, utils, CodeMirror, cm_match, cm_closeb, cm_comment) {
21 ], function(IPython, $, utils, CodeMirror, cm_match, cm_closeb, cm_comment) {
22 // TODO: remove IPython dependency here
22 // TODO: remove IPython dependency here
23 "use strict";
23 "use strict";
24
24
25 var Cell = function (options) {
25 var Cell = function (options) {
26 /* Constructor
26 /* Constructor
27 *
27 *
28 * The Base `Cell` class from which to inherit.
28 * The Base `Cell` class from which to inherit.
29 * @constructor
29 * @constructor
30 * @param:
30 * @param:
31 * options: dictionary
31 * options: dictionary
32 * Dictionary of keyword arguments.
32 * Dictionary of keyword arguments.
33 * events: $(Events) instance
33 * events: $(Events) instance
34 * config: dictionary
34 * config: dictionary
35 * keyboard_manager: KeyboardManager instance
35 * keyboard_manager: KeyboardManager instance
36 */
36 */
37 options = options || {};
37 options = options || {};
38 this.keyboard_manager = options.keyboard_manager;
38 this.keyboard_manager = options.keyboard_manager;
39 this.events = options.events;
39 this.events = options.events;
40 var config = utils.mergeopt(Cell, options.config);
40 var config = utils.mergeopt(Cell, options.config);
41 // superclass default overwrite our default
41 // superclass default overwrite our default
42
42
43 this.placeholder = config.placeholder || '';
43 this.placeholder = config.placeholder || '';
44 this.read_only = config.cm_config.readOnly;
44 this.read_only = config.cm_config.readOnly;
45 this.selected = false;
45 this.selected = false;
46 this.rendered = false;
46 this.rendered = false;
47 this.mode = 'command';
47 this.mode = 'command';
48 this.metadata = {};
48 this.metadata = {};
49 // load this from metadata later ?
49 // load this from metadata later ?
50 this.user_highlight = 'auto';
50 this.user_highlight = 'auto';
51 this.cm_config = config.cm_config;
51 this.cm_config = config.cm_config;
52 this.cell_id = utils.uuid();
52 this.cell_id = utils.uuid();
53 this._options = config;
53 this._options = config;
54
54
55 // For JS VM engines optimization, attributes should be all set (even
55 // For JS VM engines optimization, attributes should be all set (even
56 // to null) in the constructor, and if possible, if different subclass
56 // to null) in the constructor, and if possible, if different subclass
57 // have new attributes with same name, they should be created in the
57 // have new attributes with same name, they should be created in the
58 // same order. Easiest is to create and set to null in parent class.
58 // same order. Easiest is to create and set to null in parent class.
59
59
60 this.element = null;
60 this.element = null;
61 this.cell_type = this.cell_type || null;
61 this.cell_type = this.cell_type || null;
62 this.code_mirror = null;
62 this.code_mirror = null;
63
63
64 this.create_element();
64 this.create_element();
65 if (this.element !== null) {
65 if (this.element !== null) {
66 this.element.data("cell", this);
66 this.element.data("cell", this);
67 this.bind_events();
67 this.bind_events();
68 this.init_classes();
68 this.init_classes();
69 }
69 }
70 };
70 };
71
71
72 Cell.options_default = {
72 Cell.options_default = {
73 cm_config : {
73 cm_config : {
74 indentUnit : 4,
74 indentUnit : 4,
75 readOnly: false,
75 readOnly: false,
76 theme: "default",
76 theme: "default",
77 extraKeys: {
77 extraKeys: {
78 "Cmd-Right":"goLineRight",
78 "Cmd-Right":"goLineRight",
79 "End":"goLineRight",
79 "End":"goLineRight",
80 "Cmd-Left":"goLineLeft"
80 "Cmd-Left":"goLineLeft"
81 }
81 }
82 }
82 }
83 };
83 };
84
84
85 // FIXME: Workaround CM Bug #332 (Safari segfault on drag)
85 // FIXME: Workaround CM Bug #332 (Safari segfault on drag)
86 // by disabling drag/drop altogether on Safari
86 // by disabling drag/drop altogether on Safari
87 // https://github.com/codemirror/CodeMirror/issues/332
87 // https://github.com/codemirror/CodeMirror/issues/332
88 if (utils.browser[0] == "Safari") {
88 if (utils.browser[0] == "Safari") {
89 Cell.options_default.cm_config.dragDrop = false;
89 Cell.options_default.cm_config.dragDrop = false;
90 }
90 }
91
91
92 /**
92 /**
93 * Empty. Subclasses must implement create_element.
93 * Empty. Subclasses must implement create_element.
94 * This should contain all the code to create the DOM element in notebook
94 * This should contain all the code to create the DOM element in notebook
95 * and will be called by Base Class constructor.
95 * and will be called by Base Class constructor.
96 * @method create_element
96 * @method create_element
97 */
97 */
98 Cell.prototype.create_element = function () {
98 Cell.prototype.create_element = function () {
99 };
99 };
100
100
101 Cell.prototype.init_classes = function () {
101 Cell.prototype.init_classes = function () {
102 // Call after this.element exists to initialize the css classes
102 // Call after this.element exists to initialize the css classes
103 // related to selected, rendered and mode.
103 // related to selected, rendered and mode.
104 if (this.selected) {
104 if (this.selected) {
105 this.element.addClass('selected');
105 this.element.addClass('selected');
106 } else {
106 } else {
107 this.element.addClass('unselected');
107 this.element.addClass('unselected');
108 }
108 }
109 if (this.rendered) {
109 if (this.rendered) {
110 this.element.addClass('rendered');
110 this.element.addClass('rendered');
111 } else {
111 } else {
112 this.element.addClass('unrendered');
112 this.element.addClass('unrendered');
113 }
113 }
114 if (this.mode === 'edit') {
114 if (this.mode === 'edit') {
115 this.element.addClass('edit_mode');
115 this.element.addClass('edit_mode');
116 } else {
116 } else {
117 this.element.addClass('command_mode');
117 this.element.addClass('command_mode');
118 }
118 }
119 };
119 };
120
120
121 /**
121 /**
122 * Subclasses can implement override bind_events.
122 * Subclasses can implement override bind_events.
123 * Be carefull to call the parent method when overwriting as it fires event.
123 * Be carefull to call the parent method when overwriting as it fires event.
124 * this will be triggerd after create_element in constructor.
124 * this will be triggerd after create_element in constructor.
125 * @method bind_events
125 * @method bind_events
126 */
126 */
127 Cell.prototype.bind_events = function () {
127 Cell.prototype.bind_events = function () {
128 var that = this;
128 var that = this;
129 // We trigger events so that Cell doesn't have to depend on Notebook.
129 // We trigger events so that Cell doesn't have to depend on Notebook.
130 that.element.click(function (event) {
130 that.element.click(function (event) {
131 if (!that.selected) {
131 if (!that.selected) {
132 that.events.trigger('select.Cell', {'cell':that});
132 that.events.trigger('select.Cell', {'cell':that});
133 }
133 }
134 });
134 });
135 that.element.focusin(function (event) {
135 that.element.focusin(function (event) {
136 if (!that.selected) {
136 if (!that.selected) {
137 that.events.trigger('select.Cell', {'cell':that});
137 that.events.trigger('select.Cell', {'cell':that});
138 }
138 }
139 });
139 });
140 if (this.code_mirror) {
140 if (this.code_mirror) {
141 this.code_mirror.on("change", function(cm, change) {
141 this.code_mirror.on("change", function(cm, change) {
142 that.events.trigger("set_dirty.Notebook", {value: true});
142 that.events.trigger("set_dirty.Notebook", {value: true});
143 });
143 });
144 }
144 }
145 if (this.code_mirror) {
145 if (this.code_mirror) {
146 this.code_mirror.on('focus', function(cm, change) {
146 this.code_mirror.on('focus', function(cm, change) {
147 that.events.trigger('edit_mode.Cell', {cell: that});
147 that.events.trigger('edit_mode.Cell', {cell: that});
148 });
148 });
149 }
149 }
150 if (this.code_mirror) {
150 if (this.code_mirror) {
151 this.code_mirror.on('blur', function(cm, change) {
151 this.code_mirror.on('blur', function(cm, change) {
152 that.events.trigger('command_mode.Cell', {cell: that});
152 that.events.trigger('command_mode.Cell', {cell: that});
153 });
153 });
154 }
154 }
155
155
156 this.element.dblclick(function () {
156 this.element.dblclick(function () {
157 if (that.selected === false) {
157 if (that.selected === false) {
158 this.events.trigger('select.Cell', {'cell':that});
158 this.events.trigger('select.Cell', {'cell':that});
159 }
159 }
160 var cont = that.unrender();
160 var cont = that.unrender();
161 if (cont) {
161 if (cont) {
162 that.focus_editor();
162 that.focus_editor();
163 }
163 }
164 });
164 });
165 };
165 };
166
166
167 /**
167 /**
168 * This method gets called in CodeMirror's onKeyDown/onKeyPress
168 * This method gets called in CodeMirror's onKeyDown/onKeyPress
169 * handlers and is used to provide custom key handling.
169 * handlers and is used to provide custom key handling.
170 *
170 *
171 * To have custom handling, subclasses should override this method, but still call it
171 * To have custom handling, subclasses should override this method, but still call it
172 * in order to process the Edit mode keyboard shortcuts.
172 * in order to process the Edit mode keyboard shortcuts.
173 *
173 *
174 * @method handle_codemirror_keyevent
174 * @method handle_codemirror_keyevent
175 * @param {CodeMirror} editor - The codemirror instance bound to the cell
175 * @param {CodeMirror} editor - The codemirror instance bound to the cell
176 * @param {event} event - key press event which either should or should not be handled by CodeMirror
176 * @param {event} event - key press event which either should or should not be handled by CodeMirror
177 * @return {Boolean} `true` if CodeMirror should ignore the event, `false` Otherwise
177 * @return {Boolean} `true` if CodeMirror should ignore the event, `false` Otherwise
178 */
178 */
179 Cell.prototype.handle_codemirror_keyevent = function (editor, event) {
179 Cell.prototype.handle_codemirror_keyevent = function (editor, event) {
180 var shortcuts = this.keyboard_manager.edit_shortcuts;
180 var shortcuts = this.keyboard_manager.edit_shortcuts;
181
181
182 var cur = editor.getCursor();
182 var cur = editor.getCursor();
183 if((cur.line !== 0 || cur.ch !==0) && event.keyCode === 38){
183 if((cur.line !== 0 || cur.ch !==0) && event.keyCode === 38){
184 event._ipkmIgnore = true;
184 event._ipkmIgnore = true;
185 }
185 }
186 var nLastLine = editor.lastLine()
186 var nLastLine = editor.lastLine()
187 if( ( event.keyCode === 40)
187 if( ( event.keyCode === 40)
188 && (( cur.line !== nLastLine)
188 && (( cur.line !== nLastLine)
189 || ( cur.ch !== editor.getLineHandle(nLastLine).text.length))
189 || ( cur.ch !== editor.getLineHandle(nLastLine).text.length))
190 ){
190 ){
191 event._ipkmIgnore = true;
191 event._ipkmIgnore = true;
192 }
192 }
193 // if this is an edit_shortcuts shortcut, the global keyboard/shortcut
193 // if this is an edit_shortcuts shortcut, the global keyboard/shortcut
194 // manager will handle it
194 // manager will handle it
195 if (shortcuts.handles(event)) {
195 if (shortcuts.handles(event)) {
196 return true;
196 return true;
197 }
197 }
198
198
199 return false;
199 return false;
200 };
200 };
201
201
202
202
203 /**
203 /**
204 * Triger typsetting of math by mathjax on current cell element
204 * Triger typsetting of math by mathjax on current cell element
205 * @method typeset
205 * @method typeset
206 */
206 */
207 Cell.prototype.typeset = function () {
207 Cell.prototype.typeset = function () {
208 if (window.MathJax) {
208 if (window.MathJax) {
209 var cell_math = this.element.get(0);
209 var cell_math = this.element.get(0);
210 MathJax.Hub.Queue(["Typeset", MathJax.Hub, cell_math]);
210 MathJax.Hub.Queue(["Typeset", MathJax.Hub, cell_math]);
211 }
211 }
212 };
212 };
213
213
214 /**
214 /**
215 * handle cell level logic when a cell is selected
215 * handle cell level logic when a cell is selected
216 * @method select
216 * @method select
217 * @return is the action being taken
217 * @return is the action being taken
218 */
218 */
219 Cell.prototype.select = function () {
219 Cell.prototype.select = function () {
220 if (!this.selected) {
220 if (!this.selected) {
221 this.element.addClass('selected');
221 this.element.addClass('selected');
222 this.element.removeClass('unselected');
222 this.element.removeClass('unselected');
223 this.selected = true;
223 this.selected = true;
224 return true;
224 return true;
225 } else {
225 } else {
226 return false;
226 return false;
227 }
227 }
228 };
228 };
229
229
230 /**
230 /**
231 * handle cell level logic when a cell is unselected
231 * handle cell level logic when a cell is unselected
232 * @method unselect
232 * @method unselect
233 * @return is the action being taken
233 * @return is the action being taken
234 */
234 */
235 Cell.prototype.unselect = function () {
235 Cell.prototype.unselect = function () {
236 if (this.selected) {
236 if (this.selected) {
237 this.element.addClass('unselected');
237 this.element.addClass('unselected');
238 this.element.removeClass('selected');
238 this.element.removeClass('selected');
239 this.selected = false;
239 this.selected = false;
240 return true;
240 return true;
241 } else {
241 } else {
242 return false;
242 return false;
243 }
243 }
244 };
244 };
245
245
246 /**
246 /**
247 * handle cell level logic when a cell is rendered
247 * handle cell level logic when a cell is rendered
248 * @method render
248 * @method render
249 * @return is the action being taken
249 * @return is the action being taken
250 */
250 */
251 Cell.prototype.render = function () {
251 Cell.prototype.render = function () {
252 if (!this.rendered) {
252 if (!this.rendered) {
253 this.element.addClass('rendered');
253 this.element.addClass('rendered');
254 this.element.removeClass('unrendered');
254 this.element.removeClass('unrendered');
255 this.rendered = true;
255 this.rendered = true;
256 return true;
256 return true;
257 } else {
257 } else {
258 return false;
258 return false;
259 }
259 }
260 };
260 };
261
261
262 /**
262 /**
263 * handle cell level logic when a cell is unrendered
263 * handle cell level logic when a cell is unrendered
264 * @method unrender
264 * @method unrender
265 * @return is the action being taken
265 * @return is the action being taken
266 */
266 */
267 Cell.prototype.unrender = function () {
267 Cell.prototype.unrender = function () {
268 if (this.rendered) {
268 if (this.rendered) {
269 this.element.addClass('unrendered');
269 this.element.addClass('unrendered');
270 this.element.removeClass('rendered');
270 this.element.removeClass('rendered');
271 this.rendered = false;
271 this.rendered = false;
272 return true;
272 return true;
273 } else {
273 } else {
274 return false;
274 return false;
275 }
275 }
276 };
276 };
277
277
278 /**
278 /**
279 * Delegates keyboard shortcut handling to either IPython keyboard
279 * Delegates keyboard shortcut handling to either IPython keyboard
280 * manager when in command mode, or CodeMirror when in edit mode
280 * manager when in command mode, or CodeMirror when in edit mode
281 *
281 *
282 * @method handle_keyevent
282 * @method handle_keyevent
283 * @param {CodeMirror} editor - The codemirror instance bound to the cell
283 * @param {CodeMirror} editor - The codemirror instance bound to the cell
284 * @param {event} - key event to be handled
284 * @param {event} - key event to be handled
285 * @return {Boolean} `true` if CodeMirror should ignore the event, `false` Otherwise
285 * @return {Boolean} `true` if CodeMirror should ignore the event, `false` Otherwise
286 */
286 */
287 Cell.prototype.handle_keyevent = function (editor, event) {
287 Cell.prototype.handle_keyevent = function (editor, event) {
288 if (this.mode === 'command') {
288 if (this.mode === 'command') {
289 return true;
289 return true;
290 } else if (this.mode === 'edit') {
290 } else if (this.mode === 'edit') {
291 return this.handle_codemirror_keyevent(editor, event);
291 return this.handle_codemirror_keyevent(editor, event);
292 }
292 }
293 };
293 };
294
294
295 /**
295 /**
296 * @method at_top
296 * @method at_top
297 * @return {Boolean}
297 * @return {Boolean}
298 */
298 */
299 Cell.prototype.at_top = function () {
299 Cell.prototype.at_top = function () {
300 var cm = this.code_mirror;
300 var cm = this.code_mirror;
301 var cursor = cm.getCursor();
301 var cursor = cm.getCursor();
302 if (cursor.line === 0 && cursor.ch === 0) {
302 if (cursor.line === 0 && cursor.ch === 0) {
303 return true;
303 return true;
304 }
304 }
305 return false;
305 return false;
306 };
306 };
307
307
308 /**
308 /**
309 * @method at_bottom
309 * @method at_bottom
310 * @return {Boolean}
310 * @return {Boolean}
311 * */
311 * */
312 Cell.prototype.at_bottom = function () {
312 Cell.prototype.at_bottom = function () {
313 var cm = this.code_mirror;
313 var cm = this.code_mirror;
314 var cursor = cm.getCursor();
314 var cursor = cm.getCursor();
315 if (cursor.line === (cm.lineCount()-1) && cursor.ch === cm.getLine(cursor.line).length) {
315 if (cursor.line === (cm.lineCount()-1) && cursor.ch === cm.getLine(cursor.line).length) {
316 return true;
316 return true;
317 }
317 }
318 return false;
318 return false;
319 };
319 };
320
320
321 /**
321 /**
322 * enter the command mode for the cell
322 * enter the command mode for the cell
323 * @method command_mode
323 * @method command_mode
324 * @return is the action being taken
324 * @return is the action being taken
325 */
325 */
326 Cell.prototype.command_mode = function () {
326 Cell.prototype.command_mode = function () {
327 if (this.mode !== 'command') {
327 if (this.mode !== 'command') {
328 this.element.addClass('command_mode');
328 this.element.addClass('command_mode');
329 this.element.removeClass('edit_mode');
329 this.element.removeClass('edit_mode');
330 this.mode = 'command';
330 this.mode = 'command';
331 return true;
331 return true;
332 } else {
332 } else {
333 return false;
333 return false;
334 }
334 }
335 };
335 };
336
336
337 /**
337 /**
338 * enter the edit mode for the cell
338 * enter the edit mode for the cell
339 * @method command_mode
339 * @method command_mode
340 * @return is the action being taken
340 * @return is the action being taken
341 */
341 */
342 Cell.prototype.edit_mode = function () {
342 Cell.prototype.edit_mode = function () {
343 if (this.mode !== 'edit') {
343 if (this.mode !== 'edit') {
344 this.element.addClass('edit_mode');
344 this.element.addClass('edit_mode');
345 this.element.removeClass('command_mode');
345 this.element.removeClass('command_mode');
346 this.mode = 'edit';
346 this.mode = 'edit';
347 return true;
347 return true;
348 } else {
348 } else {
349 return false;
349 return false;
350 }
350 }
351 };
351 };
352
352
353 /**
353 /**
354 * Focus the cell in the DOM sense
354 * Focus the cell in the DOM sense
355 * @method focus_cell
355 * @method focus_cell
356 */
356 */
357 Cell.prototype.focus_cell = function () {
357 Cell.prototype.focus_cell = function () {
358 this.element.focus();
358 this.element.focus();
359 };
359 };
360
360
361 /**
361 /**
362 * Focus the editor area so a user can type
362 * Focus the editor area so a user can type
363 *
363 *
364 * NOTE: If codemirror is focused via a mouse click event, you don't want to
364 * NOTE: If codemirror is focused via a mouse click event, you don't want to
365 * call this because it will cause a page jump.
365 * call this because it will cause a page jump.
366 * @method focus_editor
366 * @method focus_editor
367 */
367 */
368 Cell.prototype.focus_editor = function () {
368 Cell.prototype.focus_editor = function () {
369 this.refresh();
369 this.refresh();
370 this.code_mirror.focus();
370 this.code_mirror.focus();
371 };
371 };
372
372
373 /**
373 /**
374 * Refresh codemirror instance
374 * Refresh codemirror instance
375 * @method refresh
375 * @method refresh
376 */
376 */
377 Cell.prototype.refresh = function () {
377 Cell.prototype.refresh = function () {
378 this.code_mirror.refresh();
378 this.code_mirror.refresh();
379 };
379 };
380
380
381 /**
381 /**
382 * should be overritten by subclass
382 * should be overritten by subclass
383 * @method get_text
383 * @method get_text
384 */
384 */
385 Cell.prototype.get_text = function () {
385 Cell.prototype.get_text = function () {
386 };
386 };
387
387
388 /**
388 /**
389 * should be overritten by subclass
389 * should be overritten by subclass
390 * @method set_text
390 * @method set_text
391 * @param {string} text
391 * @param {string} text
392 */
392 */
393 Cell.prototype.set_text = function (text) {
393 Cell.prototype.set_text = function (text) {
394 };
394 };
395
395
396 /**
396 /**
397 * should be overritten by subclass
397 * should be overritten by subclass
398 * serialise cell to json.
398 * serialise cell to json.
399 * @method toJSON
399 * @method toJSON
400 **/
400 **/
401 Cell.prototype.toJSON = function () {
401 Cell.prototype.toJSON = function () {
402 var data = {};
402 var data = {};
403 // deepcopy the metadata so copied cells don't share the same object
403 // deepcopy the metadata so copied cells don't share the same object
404 data.metadata = JSON.parse(JSON.stringify(this.metadata));
404 data.metadata = JSON.parse(JSON.stringify(this.metadata));
405 data.cell_type = this.cell_type;
405 data.cell_type = this.cell_type;
406 return data;
406 return data;
407 };
407 };
408
408
409
409
410 /**
410 /**
411 * should be overritten by subclass
411 * should be overritten by subclass
412 * @method fromJSON
412 * @method fromJSON
413 **/
413 **/
414 Cell.prototype.fromJSON = function (data) {
414 Cell.prototype.fromJSON = function (data) {
415 if (data.metadata !== undefined) {
415 if (data.metadata !== undefined) {
416 this.metadata = data.metadata;
416 this.metadata = data.metadata;
417 }
417 }
418 this.celltoolbar.rebuild();
418 this.celltoolbar.rebuild();
419 };
419 };
420
420
421
421
422 /**
422 /**
423 * can the cell be split into two cells (false if not deletable)
423 * can the cell be split into two cells (false if not deletable)
424 * @method is_splittable
424 * @method is_splittable
425 **/
425 **/
426 Cell.prototype.is_splittable = function () {
426 Cell.prototype.is_splittable = function () {
427 return this.is_deletable();
427 return this.is_deletable();
428 };
428 };
429
429
430
430
431 /**
431 /**
432 * can the cell be merged with other cells (false if not deletable)
432 * can the cell be merged with other cells (false if not deletable)
433 * @method is_mergeable
433 * @method is_mergeable
434 **/
434 **/
435 Cell.prototype.is_mergeable = function () {
435 Cell.prototype.is_mergeable = function () {
436 return this.is_deletable();
436 return this.is_deletable();
437 };
437 };
438
438
439 /**
439 /**
440 * is the cell deletable? only false (undeletable) if
440 * is the cell deletable? only false (undeletable) if
441 * metadata.deletable is explicitly false -- everything else
441 * metadata.deletable is explicitly false -- everything else
442 * counts as true
442 * counts as true
443 *
443 *
444 * @method is_deletable
444 * @method is_deletable
445 **/
445 **/
446 Cell.prototype.is_deletable = function () {
446 Cell.prototype.is_deletable = function () {
447 if (this.metadata.deletable === false) {
447 if (this.metadata.deletable === false) {
448 return false;
448 return false;
449 }
449 }
450 return true;
450 return true;
451 };
451 };
452
452
453 /**
453 /**
454 * @return {String} - the text before the cursor
454 * @return {String} - the text before the cursor
455 * @method get_pre_cursor
455 * @method get_pre_cursor
456 **/
456 **/
457 Cell.prototype.get_pre_cursor = function () {
457 Cell.prototype.get_pre_cursor = function () {
458 var cursor = this.code_mirror.getCursor();
458 var cursor = this.code_mirror.getCursor();
459 var text = this.code_mirror.getRange({line:0, ch:0}, cursor);
459 var text = this.code_mirror.getRange({line:0, ch:0}, cursor);
460 text = text.replace(/^\n+/, '').replace(/\n+$/, '');
460 text = text.replace(/^\n+/, '').replace(/\n+$/, '');
461 return text;
461 return text;
462 };
462 };
463
463
464
464
465 /**
465 /**
466 * @return {String} - the text after the cursor
466 * @return {String} - the text after the cursor
467 * @method get_post_cursor
467 * @method get_post_cursor
468 **/
468 **/
469 Cell.prototype.get_post_cursor = function () {
469 Cell.prototype.get_post_cursor = function () {
470 var cursor = this.code_mirror.getCursor();
470 var cursor = this.code_mirror.getCursor();
471 var last_line_num = this.code_mirror.lineCount()-1;
471 var last_line_num = this.code_mirror.lineCount()-1;
472 var last_line_len = this.code_mirror.getLine(last_line_num).length;
472 var last_line_len = this.code_mirror.getLine(last_line_num).length;
473 var end = {line:last_line_num, ch:last_line_len};
473 var end = {line:last_line_num, ch:last_line_len};
474 var text = this.code_mirror.getRange(cursor, end);
474 var text = this.code_mirror.getRange(cursor, end);
475 text = text.replace(/^\n+/, '').replace(/\n+$/, '');
475 text = text.replace(/^\n+/, '').replace(/\n+$/, '');
476 return text;
476 return text;
477 };
477 };
478
478
479 /**
479 /**
480 * Show/Hide CodeMirror LineNumber
480 * Show/Hide CodeMirror LineNumber
481 * @method show_line_numbers
481 * @method show_line_numbers
482 *
482 *
483 * @param value {Bool} show (true), or hide (false) the line number in CodeMirror
483 * @param value {Bool} show (true), or hide (false) the line number in CodeMirror
484 **/
484 **/
485 Cell.prototype.show_line_numbers = function (value) {
485 Cell.prototype.show_line_numbers = function (value) {
486 this.code_mirror.setOption('lineNumbers', value);
486 this.code_mirror.setOption('lineNumbers', value);
487 this.code_mirror.refresh();
487 this.code_mirror.refresh();
488 };
488 };
489
489
490 /**
490 /**
491 * Toggle CodeMirror LineNumber
491 * Toggle CodeMirror LineNumber
492 * @method toggle_line_numbers
492 * @method toggle_line_numbers
493 **/
493 **/
494 Cell.prototype.toggle_line_numbers = function () {
494 Cell.prototype.toggle_line_numbers = function () {
495 var val = this.code_mirror.getOption('lineNumbers');
495 var val = this.code_mirror.getOption('lineNumbers');
496 this.show_line_numbers(!val);
496 this.show_line_numbers(!val);
497 };
497 };
498
498
499 /**
499 /**
500 * Force codemirror highlight mode
500 * Force codemirror highlight mode
501 * @method force_highlight
501 * @method force_highlight
502 * @param {object} - CodeMirror mode
502 * @param {object} - CodeMirror mode
503 **/
503 **/
504 Cell.prototype.force_highlight = function(mode) {
504 Cell.prototype.force_highlight = function(mode) {
505 this.user_highlight = mode;
505 this.user_highlight = mode;
506 this.auto_highlight();
506 this.auto_highlight();
507 };
507 };
508
508
509 /**
509 /**
510 * Try to autodetect cell highlight mode, or use selected mode
510 * Try to autodetect cell highlight mode, or use selected mode
511 * @methods _auto_highlight
511 * @methods _auto_highlight
512 * @private
512 * @private
513 * @param {String|object|undefined} - CodeMirror mode | 'auto'
513 * @param {String|object|undefined} - CodeMirror mode | 'auto'
514 **/
514 **/
515 Cell.prototype._auto_highlight = function (modes) {
515 Cell.prototype._auto_highlight = function (modes) {
516 //Here we handle manually selected modes
516 //Here we handle manually selected modes
517 var that = this;
517 var that = this;
518 var mode;
518 var mode;
519 if( this.user_highlight !== undefined && this.user_highlight != 'auto' )
519 if( this.user_highlight !== undefined && this.user_highlight != 'auto' )
520 {
520 {
521 mode = this.user_highlight;
521 mode = this.user_highlight;
522 CodeMirror.autoLoadMode(this.code_mirror, mode);
522 CodeMirror.autoLoadMode(this.code_mirror, mode);
523 this.code_mirror.setOption('mode', mode);
523 this.code_mirror.setOption('mode', mode);
524 return;
524 return;
525 }
525 }
526 var current_mode = this.code_mirror.getOption('mode', mode);
526 var current_mode = this.code_mirror.getOption('mode', mode);
527 var first_line = this.code_mirror.getLine(0);
527 var first_line = this.code_mirror.getLine(0);
528 // loop on every pairs
528 // loop on every pairs
529 for(mode in modes) {
529 for(mode in modes) {
530 var regs = modes[mode].reg;
530 var regs = modes[mode].reg;
531 // only one key every time but regexp can't be keys...
531 // only one key every time but regexp can't be keys...
532 for(var i=0; i<regs.length; i++) {
532 for(var i=0; i<regs.length; i++) {
533 // here we handle non magic_modes
533 // here we handle non magic_modes
534 if(first_line.match(regs[i]) !== null) {
534 if(first_line.match(regs[i]) !== null) {
535 if(current_mode == mode){
535 if(current_mode == mode){
536 return;
536 return;
537 }
537 }
538 if (mode.search('magic_') !== 0) {
538 if (mode.search('magic_') !== 0) {
539 utils.requireCodeMirrorMode(mode, function () {
539 utils.requireCodeMirrorMode(mode, function () {
540 that.code_mirror.setOption('mode', mode);
540 that.code_mirror.setOption('mode', mode);
541 });
541 });
542 return;
542 return;
543 }
543 }
544 var open = modes[mode].open || "%%";
544 var open = modes[mode].open || "%%";
545 var close = modes[mode].close || "%%end";
545 var close = modes[mode].close || "%%end";
546 var mmode = mode;
546 var magic_mode = mode;
547 mode = mmode.substr(6);
547 mode = magic_mode.substr(6);
548 if(current_mode == mmode){
548 if(current_mode == magic_mode){
549 return;
549 return;
550 }
550 }
551 utils.requireCodeMirrorMode(mode, function () {
551 utils.requireCodeMirrorMode(mode, function () {
552 // create on the fly a mode that switch between
552 // create on the fly a mode that switch between
553 // plain/text and something else, otherwise `%%` is
553 // plain/text and something else, otherwise `%%` is
554 // source of some highlight issues.
554 // source of some highlight issues.
555 CodeMirror.defineMode(mmode, function(config) {
555 CodeMirror.defineMode(magic_mode, function(config) {
556 return CodeMirror.multiplexingMode(
556 return CodeMirror.multiplexingMode(
557 CodeMirror.getMode(config, 'text/plain'),
557 CodeMirror.getMode(config, 'text/plain'),
558 // always set someting on close
558 // always set something on close
559 {open: open, close: close,
559 {open: open, close: close,
560 mode: CodeMirror.getMode(config, mode),
560 mode: CodeMirror.getMode(config, mode),
561 delimStyle: "delimit"
561 delimStyle: "delimit"
562 }
562 }
563 );
563 );
564 });
564 });
565 that.code_mirror.setOption('mode', mmode);
565 that.code_mirror.setOption('mode', magic_mode);
566 });
566 });
567 return;
567 return;
568 }
568 }
569 }
569 }
570 }
570 }
571 // fallback on default
571 // fallback on default
572 var default_mode;
572 var default_mode;
573 try {
573 try {
574 default_mode = this._options.cm_config.mode;
574 default_mode = this._options.cm_config.mode;
575 } catch(e) {
575 } catch(e) {
576 default_mode = 'text/plain';
576 default_mode = 'text/plain';
577 }
577 }
578 if( current_mode === default_mode){
578 if( current_mode === default_mode){
579 return;
579 return;
580 }
580 }
581 this.code_mirror.setOption('mode', default_mode);
581 this.code_mirror.setOption('mode', default_mode);
582 };
582 };
583
583
584 // Backwards compatibility.
584 // Backwards compatibility.
585 IPython.Cell = Cell;
585 IPython.Cell = Cell;
586
586
587 return {'Cell': Cell};
587 return {'Cell': Cell};
588 });
588 });
@@ -1,39 +1,38
1 // IPython mode is just a slightly altered Python Mode with `?` beeing a extra
1 // IPython mode is just a slightly altered Python Mode with `?` beeing a extra
2 // single operator. Here we define `ipython` mode in the require `python`
2 // single operator. Here we define `ipython` mode in the require `python`
3 // callback to auto-load python mode, which is more likely not the best things
3 // callback to auto-load python mode, which is more likely not the best things
4 // to do, but at least the simple one for now.
4 // to do, but at least the simple one for now.
5
5
6 (function(mod) {
6 (function(mod) {
7 if (typeof exports == "object" && typeof module == "object"){ // CommonJS
7 if (typeof exports == "object" && typeof module == "object"){ // CommonJS
8 mod(require("codemirror/lib/codemirror"),
8 mod(require("codemirror/lib/codemirror"),
9 require("codemirror/mode/python/python")
9 require("codemirror/mode/python/python")
10 );
10 );
11 } else if (typeof define == "function" && define.amd){ // AMD
11 } else if (typeof define == "function" && define.amd){ // AMD
12 define(["codemirror/lib/codemirror",
12 define(["codemirror/lib/codemirror",
13 "codemirror/mode/python/python"], mod);
13 "codemirror/mode/python/python"], mod);
14 } else {// Plain browser env
14 } else {// Plain browser env
15 mod(CodeMirror);
15 mod(CodeMirror);
16 }
16 }
17 })(function(CodeMirror) {
17 })(function(CodeMirror) {
18 "use strict";
18 "use strict";
19
19
20 CodeMirror.defineMode("ipython", function(conf, parserConf) {
20 CodeMirror.defineMode("ipython", function(conf, parserConf) {
21 var pythonConf = {};
21 var pythonConf = {};
22 for (var prop in parserConf) {
22 for (var prop in parserConf) {
23 if (parserConf.hasOwnProperty(prop)) {
23 if (parserConf.hasOwnProperty(prop)) {
24 pythonConf[prop] = parserConf[prop];
24 pythonConf[prop] = parserConf[prop];
25 }
25 }
26 }
26 }
27 pythonConf.name = 'python';
27 pythonConf.name = 'python';
28 pythonConf.singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!\\?]");
28 pythonConf.singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!\\?]");
29 if (pythonConf.version === 3) {
29 if (pythonConf.version === 3) {
30 pythonConf.identifiers = new RegExp("^[_A-Za-z\u00A1-\uFFFF][_A-Za-z0-9\u00A1-\uFFFF]*");
30 pythonConf.identifiers = new RegExp("^[_A-Za-z\u00A1-\uFFFF][_A-Za-z0-9\u00A1-\uFFFF]*");
31 } else if (pythonConf.version === 2) {
31 } else if (pythonConf.version === 2) {
32 pythonConf.identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*");
32 pythonConf.identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*");
33 }
33 }
34 return CodeMirror.getMode(conf, pythonConf);
34 return CodeMirror.getMode(conf, pythonConf);
35 }, 'python');
35 }, 'python');
36
36
37 CodeMirror.defineMIME("text/x-ipython", "ipython");
37 CodeMirror.defineMIME("text/x-ipython", "ipython");
38 })
38 })
39
@@ -1,64 +1,62
1 // IPython GFM (GitHub Flavored Markdown) mode is just a slightly altered GFM
1 // IPython GFM (GitHub Flavored Markdown) mode is just a slightly altered GFM
2 // Mode with support for latex.
2 // Mode with support for latex.
3 //
3 //
4 // Latex support was supported by Codemirror GFM as of
4 // Latex support was supported by Codemirror GFM as of
5 // https://github.com/codemirror/CodeMirror/pull/567
5 // https://github.com/codemirror/CodeMirror/pull/567
6 // But was later removed in
6 // But was later removed in
7 // https://github.com/codemirror/CodeMirror/commit/d9c9f1b1ffe984aee41307f3e927f80d1f23590c
7 // https://github.com/codemirror/CodeMirror/commit/d9c9f1b1ffe984aee41307f3e927f80d1f23590c
8
8
9
9
10 (function(mod) {
10 (function(mod) {
11 if (typeof exports == "object" && typeof module == "object"){ // CommonJS
11 if (typeof exports == "object" && typeof module == "object"){ // CommonJS
12 mod(require("codemirror/lib/codemirror")
12 mod(require("codemirror/lib/codemirror")
13 ,require("codemirror/addon/mode/multiplex")
13 ,require("codemirror/addon/mode/multiplex")
14 ,require("codemirror/mode/gfm/gfm")
14 ,require("codemirror/mode/gfm/gfm")
15 ,require("codemirror/mode/stex/stex")
15 ,require("codemirror/mode/stex/stex")
16 );
16 );
17 } else if (typeof define == "function" && define.amd){ // AMD
17 } else if (typeof define == "function" && define.amd){ // AMD
18 define(["codemirror/lib/codemirror"
18 define(["codemirror/lib/codemirror"
19 ,"codemirror/addon/mode/multiplex"
19 ,"codemirror/addon/mode/multiplex"
20 ,"codemirror/mode/python/python"
20 ,"codemirror/mode/python/python"
21 ,"codemirror/mode/stex/stex"
21 ,"codemirror/mode/stex/stex"
22 ], mod);
22 ], mod);
23 } else {// Plain browser env
23 } else {// Plain browser env
24 mod(CodeMirror);
24 mod(CodeMirror);
25 }
25 }
26 })( function(CodeMirror){
26 })( function(CodeMirror){
27 "use strict";
27 "use strict";
28
28
29 CodeMirror.defineMode("ipythongfm", function(config, parserConfig) {
29 CodeMirror.defineMode("ipythongfm", function(config, parserConfig) {
30
30
31 var gfm_mode = CodeMirror.getMode(config, "gfm");
31 var gfm_mode = CodeMirror.getMode(config, "gfm");
32 var tex_mode = CodeMirror.getMode(config, "stex");
32 var tex_mode = CodeMirror.getMode(config, "stex");
33
33
34 return CodeMirror.multiplexingMode(
34 return CodeMirror.multiplexingMode(
35 gfm_mode,
35 gfm_mode,
36 {
36 {
37 open: "$", close: "$",
37 open: "$", close: "$",
38 mode: tex_mode,
38 mode: tex_mode,
39 delimStyle: "delimit"
39 delimStyle: "delimit"
40 },
40 },
41 {
41 {
42 // not sure this works as $$ is interpreted at (opening $, closing $, as defined just above)
42 // not sure this works as $$ is interpreted at (opening $, closing $, as defined just above)
43 open: "$$", close: "$$",
43 open: "$$", close: "$$",
44 mode: tex_mode,
44 mode: tex_mode,
45 delimStyle: "delimit"
45 delimStyle: "delimit"
46 },
46 },
47 {
47 {
48 open: "\\(", close: "\\)",
48 open: "\\(", close: "\\)",
49 mode: tex_mode,
49 mode: tex_mode,
50 delimStyle: "delimit"
50 delimStyle: "delimit"
51 },
51 },
52 {
52 {
53 open: "\\[", close: "\\]",
53 open: "\\[", close: "\\]",
54 mode: tex_mode,
54 mode: tex_mode,
55 delimStyle: "delimit"
55 delimStyle: "delimit"
56 }
56 }
57 // .. more multiplexed styles can follow here
57 // .. more multiplexed styles can follow here
58 );
58 );
59 }, 'gfm');
59 }, 'gfm');
60
61 CodeMirror.defineMIME("text/x-ipythongfm", "ipythongfm");
62
63
60
61 CodeMirror.defineMIME("text/x-ipythongfm", "ipythongfm");
64 })
62 })
General Comments 0
You need to be logged in to leave comments. Login now