cell.js
669 lines
| 20.1 KiB
| application/javascript
|
JavascriptLexer
Jonathan Frederic
|
r17196 | // Copyright (c) IPython Development Team. | ||
// Distributed under the terms of the Modified BSD License. | ||||
Matthias BUSSONNIER
|
r18280 | /** | ||
* | ||||
* | ||||
* @module cell | ||||
* @namespace cell | ||||
* @class Cell | ||||
*/ | ||||
Jonathan Frederic
|
r17196 | define([ | ||
'base/js/namespace', | ||||
Jonathan Frederic
|
r17200 | 'jquery', | ||
Jonathan Frederic
|
r17196 | 'base/js/utils', | ||
Matthias BUSSONNIER
|
r18280 | 'codemirror/lib/codemirror', | ||
'codemirror/addon/edit/matchbrackets', | ||||
'codemirror/addon/edit/closebrackets', | ||||
'codemirror/addon/comment/comment' | ||||
Matthias Bussonnier
|
r18287 | ], function(IPython, $, utils, CodeMirror, cm_match, cm_closeb, cm_comment) { | ||
Matthias BUSSONNIER
|
r17421 | // TODO: remove IPython dependency here | ||
Matthias BUSSONNIER
|
r12103 | "use strict"; | ||
Brian E. Granger
|
r4349 | |||
jon
|
r17210 | var Cell = function (options) { | ||
Matthias BUSSONNIER
|
r18280 | /* Constructor | ||
* | ||||
* The Base `Cell` class from which to inherit. | ||||
* @constructor | ||||
* @param: | ||||
* options: dictionary | ||||
* Dictionary of keyword arguments. | ||||
Matthias Bussonnier
|
r18289 | * events: $(Events) instance | ||
Matthias BUSSONNIER
|
r18280 | * config: dictionary | ||
Matthias Bussonnier
|
r18289 | * keyboard_manager: KeyboardManager instance | ||
Matthias BUSSONNIER
|
r18280 | */ | ||
jon
|
r17210 | options = options || {}; | ||
this.keyboard_manager = options.keyboard_manager; | ||||
this.events = options.events; | ||||
MinRK
|
r17764 | var config = utils.mergeopt(Cell, options.config); | ||
Matthias BUSSONNIER
|
r9537 | // superclass default overwrite our default | ||
MinRK
|
r13668 | |||
jon
|
r17210 | this.placeholder = config.placeholder || ''; | ||
this.read_only = config.cm_config.readOnly; | ||||
Brian E. Granger
|
r4352 | this.selected = false; | ||
Brian E. Granger
|
r14014 | this.rendered = false; | ||
this.mode = 'command'; | ||||
Jonathan Frederic
|
r18854 | |||
// Metadata property | ||||
var that = this; | ||||
this._metadata = {}; | ||||
Object.defineProperty(this, 'metadata', { | ||||
get: function() { return that._metadata; }, | ||||
set: function(value) { | ||||
that._metadata = value; | ||||
Min RK
|
r18999 | if (that.celltoolbar) { | ||
that.celltoolbar.rebuild(); | ||||
} | ||||
Jonathan Frederic
|
r18854 | } | ||
}); | ||||
Matthias BUSSONNIER
|
r8202 | // load this from metadata later ? | ||
Mikhail Korobov
|
r8839 | this.user_highlight = 'auto'; | ||
jon
|
r17210 | this.cm_config = config.cm_config; | ||
Jonathan Frederic
|
r17198 | this.cell_id = utils.uuid(); | ||
jon
|
r17210 | this._options = config; | ||
Matthias BUSSONNIER
|
r13574 | |||
Jonathan Frederic
|
r15495 | // For JS VM engines optimization, attributes should be all set (even | ||
Matthias BUSSONNIER
|
r13574 | // to null) in the constructor, and if possible, if different subclass | ||
// have new attributes with same name, they should be created in the | ||||
// same order. Easiest is to create and set to null in parent class. | ||||
this.element = null; | ||||
MinRK
|
r13676 | this.cell_type = this.cell_type || null; | ||
Matthias BUSSONNIER
|
r13574 | this.code_mirror = null; | ||
Brian E. Granger
|
r4352 | this.create_element(); | ||
Brian E. Granger
|
r4529 | if (this.element !== null) { | ||
Brian E. Granger
|
r4352 | this.element.data("cell", this); | ||
this.bind_events(); | ||||
Brian E. Granger
|
r14049 | this.init_classes(); | ||
Brian E. Granger
|
r4352 | } | ||
}; | ||||
Matthias BUSSONNIER
|
r10165 | Cell.options_default = { | ||
cm_config : { | ||||
Matthias BUSSONNIER
|
r9537 | indentUnit : 4, | ||
Matthias BUSSONNIER
|
r10165 | readOnly: false, | ||
Matthias BUSSONNIER
|
r16596 | theme: "default", | ||
extraKeys: { | ||||
"Cmd-Right":"goLineRight", | ||||
"End":"goLineRight", | ||||
"Cmd-Left":"goLineLeft" | ||||
} | ||||
Matthias BUSSONNIER
|
r10165 | } | ||
Matthias BUSSONNIER
|
r9537 | }; | ||
MinRK
|
r10791 | |||
// FIXME: Workaround CM Bug #332 (Safari segfault on drag) | ||||
// by disabling drag/drop altogether on Safari | ||||
Matthias Bussonnier
|
r17940 | // https://github.com/codemirror/CodeMirror/issues/332 | ||
Jonathan Frederic
|
r17198 | if (utils.browser[0] == "Safari") { | ||
MinRK
|
r10791 | Cell.options_default.cm_config.dragDrop = false; | ||
} | ||||
Matthias BUSSONNIER
|
r9537 | |||
Matthias BUSSONNIER
|
r8713 | /** | ||
* Empty. Subclasses must implement create_element. | ||||
Matthias BUSSONNIER
|
r8714 | * This should contain all the code to create the DOM element in notebook | ||
Matthias BUSSONNIER
|
r8713 | * and will be called by Base Class constructor. | ||
* @method create_element | ||||
*/ | ||||
Matthias BUSSONNIER
|
r9073 | Cell.prototype.create_element = function () { | ||
}; | ||||
Brian E. Granger
|
r4352 | |||
Brian E. Granger
|
r14049 | Cell.prototype.init_classes = function () { | ||
Jonathan Frederic
|
r19176 | /** | ||
* Call after this.element exists to initialize the css classes | ||||
* related to selected, rendered and mode. | ||||
*/ | ||||
Brian E. Granger
|
r14049 | if (this.selected) { | ||
this.element.addClass('selected'); | ||||
} else { | ||||
this.element.addClass('unselected'); | ||||
} | ||||
if (this.rendered) { | ||||
this.element.addClass('rendered'); | ||||
} else { | ||||
this.element.addClass('unrendered'); | ||||
} | ||||
Jonathan Frederic
|
r15493 | }; | ||
Brian E. Granger
|
r14049 | |||
Matthias BUSSONNIER
|
r8713 | /** | ||
Matthias BUSSONNIER
|
r8714 | * Subclasses can implement override bind_events. | ||
* Be carefull to call the parent method when overwriting as it fires event. | ||||
* this will be triggerd after create_element in constructor. | ||||
Matthias BUSSONNIER
|
r8713 | * @method bind_events | ||
*/ | ||||
Brian E. Granger
|
r4352 | Cell.prototype.bind_events = function () { | ||
var that = this; | ||||
Brian Granger
|
r7168 | // We trigger events so that Cell doesn't have to depend on Notebook. | ||
Brian E. Granger
|
r4352 | that.element.click(function (event) { | ||
Brian E. Granger
|
r14033 | if (!that.selected) { | ||
Jonathan Frederic
|
r17196 | that.events.trigger('select.Cell', {'cell':that}); | ||
Jonathan Frederic
|
r15493 | } | ||
Brian E. Granger
|
r4352 | }); | ||
that.element.focusin(function (event) { | ||||
Brian E. Granger
|
r14033 | if (!that.selected) { | ||
Jonathan Frederic
|
r17196 | that.events.trigger('select.Cell', {'cell':that}); | ||
Jonathan Frederic
|
r15493 | } | ||
Brian E. Granger
|
r14016 | }); | ||
MinRK
|
r10785 | if (this.code_mirror) { | ||
this.code_mirror.on("change", function(cm, change) { | ||||
Jonathan Frederic
|
r17196 | that.events.trigger("set_dirty.Notebook", {value: true}); | ||
MinRK
|
r10785 | }); | ||
Brian E. Granger
|
r14092 | } | ||
Brian E. Granger
|
r14015 | if (this.code_mirror) { | ||
this.code_mirror.on('focus', function(cm, change) { | ||||
Jonathan Frederic
|
r17196 | that.events.trigger('edit_mode.Cell', {cell: that}); | ||
Brian E. Granger
|
r14015 | }); | ||
Brian E. Granger
|
r14092 | } | ||
Brian E. Granger
|
r14033 | if (this.code_mirror) { | ||
this.code_mirror.on('blur', function(cm, change) { | ||||
Jonathan Frederic
|
r17196 | that.events.trigger('command_mode.Cell', {cell: that}); | ||
Brian E. Granger
|
r14033 | }); | ||
Brian E. Granger
|
r14092 | } | ||
Matthias BUSSONNIER
|
r18270 | |||
this.element.dblclick(function () { | ||||
if (that.selected === false) { | ||||
this.events.trigger('select.Cell', {'cell':that}); | ||||
} | ||||
var cont = that.unrender(); | ||||
if (cont) { | ||||
that.focus_editor(); | ||||
} | ||||
}); | ||||
Brian E. Granger
|
r4352 | }; | ||
Paul Ivanov
|
r15757 | |||
/** | ||||
* This method gets called in CodeMirror's onKeyDown/onKeyPress | ||||
* handlers and is used to provide custom key handling. | ||||
* | ||||
* To have custom handling, subclasses should override this method, but still call it | ||||
* in order to process the Edit mode keyboard shortcuts. | ||||
* | ||||
* @method handle_codemirror_keyevent | ||||
* @param {CodeMirror} editor - The codemirror instance bound to the cell | ||||
Paul Ivanov
|
r15820 | * @param {event} event - key press event which either should or should not be handled by CodeMirror | ||
Paul Ivanov
|
r15757 | * @return {Boolean} `true` if CodeMirror should ignore the event, `false` Otherwise | ||
*/ | ||||
Cell.prototype.handle_codemirror_keyevent = function (editor, event) { | ||||
Jonathan Frederic
|
r17196 | var shortcuts = this.keyboard_manager.edit_shortcuts; | ||
Paul Ivanov
|
r15757 | |||
Matthias Bussonnier
|
r18282 | var cur = editor.getCursor(); | ||
if((cur.line !== 0 || cur.ch !==0) && event.keyCode === 38){ | ||||
event._ipkmIgnore = true; | ||||
} | ||||
Min RK
|
r18999 | var nLastLine = editor.lastLine(); | ||
if ((event.keyCode === 40) && | ||||
((cur.line !== nLastLine) || | ||||
(cur.ch !== editor.getLineHandle(nLastLine).text.length)) | ||||
) { | ||||
Matthias Bussonnier
|
r18282 | event._ipkmIgnore = true; | ||
} | ||||
Paul Ivanov
|
r15822 | // if this is an edit_shortcuts shortcut, the global keyboard/shortcut | ||
// manager will handle it | ||||
Matthias Bussonnier
|
r18289 | if (shortcuts.handles(event)) { | ||
return true; | ||||
Matthias Bussonnier
|
r18282 | } | ||
Paul Ivanov
|
r15758 | |||
Paul Ivanov
|
r15757 | return false; | ||
}; | ||||
Brian E. Granger
|
r4352 | |||
Matthias BUSSONNIER
|
r8714 | /** | ||
* Triger typsetting of math by mathjax on current cell element | ||||
* @method typeset | ||||
*/ | ||||
Aron Ahmadia
|
r8660 | Cell.prototype.typeset = function () { | ||
Nicholas Bollweg (Nick)
|
r19235 | utils.typeset(this.element); | ||
Aron Ahmadia
|
r8660 | }; | ||
Brian Granger
|
r5959 | |||
Matthias BUSSONNIER
|
r8714 | /** | ||
Brian E. Granger
|
r14013 | * handle cell level logic when a cell is selected | ||
Matthias BUSSONNIER
|
r8714 | * @method select | ||
Brian E. Granger
|
r14014 | * @return is the action being taken | ||
Matthias BUSSONNIER
|
r8714 | */ | ||
Brian Granger
|
r5943 | Cell.prototype.select = function () { | ||
Brian E. Granger
|
r14014 | if (!this.selected) { | ||
this.element.addClass('selected'); | ||||
this.element.removeClass('unselected'); | ||||
this.selected = true; | ||||
return true; | ||||
} else { | ||||
return false; | ||||
Brian E. Granger
|
r14092 | } | ||
Brian Granger
|
r5943 | }; | ||
Matthias BUSSONNIER
|
r8714 | /** | ||
Brian E. Granger
|
r14013 | * handle cell level logic when a cell is unselected | ||
Matthias BUSSONNIER
|
r8714 | * @method unselect | ||
Brian E. Granger
|
r14014 | * @return is the action being taken | ||
Matthias BUSSONNIER
|
r8714 | */ | ||
Brian Granger
|
r5943 | Cell.prototype.unselect = function () { | ||
Brian E. Granger
|
r14014 | if (this.selected) { | ||
this.element.addClass('unselected'); | ||||
this.element.removeClass('selected'); | ||||
this.selected = false; | ||||
return true; | ||||
} else { | ||||
return false; | ||||
Brian E. Granger
|
r14092 | } | ||
Brian Granger
|
r5943 | }; | ||
Matthias BUSSONNIER
|
r8739 | /** | ||
Min RK
|
r18999 | * should be overritten by subclass | ||
* @method execute | ||||
*/ | ||||
Cell.prototype.execute = function () { | ||||
return; | ||||
}; | ||||
/** | ||||
Brian E. Granger
|
r14014 | * handle cell level logic when a cell is rendered | ||
* @method render | ||||
* @return is the action being taken | ||||
Brian E. Granger
|
r14013 | */ | ||
Brian E. Granger
|
r14014 | Cell.prototype.render = function () { | ||
if (!this.rendered) { | ||||
this.element.addClass('rendered'); | ||||
this.element.removeClass('unrendered'); | ||||
this.rendered = true; | ||||
return true; | ||||
} else { | ||||
return false; | ||||
Brian E. Granger
|
r14092 | } | ||
Brian E. Granger
|
r14013 | }; | ||
/** | ||||
Brian E. Granger
|
r14014 | * handle cell level logic when a cell is unrendered | ||
* @method unrender | ||||
* @return is the action being taken | ||||
Brian E. Granger
|
r14013 | */ | ||
Brian E. Granger
|
r14014 | Cell.prototype.unrender = function () { | ||
if (this.rendered) { | ||||
this.element.addClass('unrendered'); | ||||
this.element.removeClass('rendered'); | ||||
this.rendered = false; | ||||
return true; | ||||
} else { | ||||
return false; | ||||
Brian E. Granger
|
r14092 | } | ||
Brian E. Granger
|
r14013 | }; | ||
/** | ||||
Paul Ivanov
|
r15822 | * Delegates keyboard shortcut handling to either IPython keyboard | ||
Paul Ivanov
|
r15755 | * manager when in command mode, or CodeMirror when in edit mode | ||
* | ||||
* @method handle_keyevent | ||||
* @param {CodeMirror} editor - The codemirror instance bound to the cell | ||||
Paul Ivanov
|
r15838 | * @param {event} - key event to be handled | ||
Paul Ivanov
|
r15755 | * @return {Boolean} `true` if CodeMirror should ignore the event, `false` Otherwise | ||
*/ | ||||
Paul Ivanov
|
r15756 | Cell.prototype.handle_keyevent = function (editor, event) { | ||
Paul Ivanov
|
r15755 | if (this.mode === 'command') { | ||
return true; | ||||
} else if (this.mode === 'edit') { | ||||
return this.handle_codemirror_keyevent(editor, event); | ||||
} | ||||
}; | ||||
/** | ||||
Paul Ivanov
|
r15754 | * @method at_top | ||
* @return {Boolean} | ||||
*/ | ||||
Cell.prototype.at_top = function () { | ||||
Paul Ivanov
|
r15819 | var cm = this.code_mirror; | ||
Paul Ivanov
|
r15754 | var cursor = cm.getCursor(); | ||
Paul Ivanov
|
r15835 | if (cursor.line === 0 && cursor.ch === 0) { | ||
Paul Ivanov
|
r15754 | return true; | ||
} | ||||
Paul Ivanov
|
r15836 | return false; | ||
Paul Ivanov
|
r15754 | }; | ||
/** | ||||
* @method at_bottom | ||||
* @return {Boolean} | ||||
* */ | ||||
Cell.prototype.at_bottom = function () { | ||||
Paul Ivanov
|
r15819 | var cm = this.code_mirror; | ||
Paul Ivanov
|
r15754 | var cursor = cm.getCursor(); | ||
Paul Ivanov
|
r15835 | if (cursor.line === (cm.lineCount()-1) && cursor.ch === cm.getLine(cursor.line).length) { | ||
Paul Ivanov
|
r15754 | return true; | ||
} | ||||
Paul Ivanov
|
r15836 | return false; | ||
Paul Ivanov
|
r15754 | }; | ||
Paul Ivanov
|
r15836 | |||
Paul Ivanov
|
r15754 | /** | ||
Brian E. Granger
|
r14014 | * enter the command mode for the cell | ||
* @method command_mode | ||||
* @return is the action being taken | ||||
*/ | ||||
Cell.prototype.command_mode = function () { | ||||
if (this.mode !== 'command') { | ||||
this.mode = 'command'; | ||||
return true; | ||||
} else { | ||||
return false; | ||||
Brian E. Granger
|
r14092 | } | ||
Brian E. Granger
|
r14014 | }; | ||
/** | ||||
* enter the edit mode for the cell | ||||
* @method command_mode | ||||
* @return is the action being taken | ||||
*/ | ||||
Cell.prototype.edit_mode = function () { | ||||
if (this.mode !== 'edit') { | ||||
this.mode = 'edit'; | ||||
return true; | ||||
} else { | ||||
return false; | ||||
Brian E. Granger
|
r14092 | } | ||
Jonathan Frederic
|
r15493 | }; | ||
Jonathan Frederic
|
r15777 | |||
Jonathan Frederic
|
r15495 | /** | ||
Brian E. Granger
|
r14014 | * Focus the cell in the DOM sense | ||
* @method focus_cell | ||||
*/ | ||||
Cell.prototype.focus_cell = function () { | ||||
this.element.focus(); | ||||
Jonathan Frederic
|
r15493 | }; | ||
Brian E. Granger
|
r14014 | |||
/** | ||||
Jonathan Frederic
|
r15497 | * Focus the editor area so a user can type | ||
* | ||||
* NOTE: If codemirror is focused via a mouse click event, you don't want to | ||||
* call this because it will cause a page jump. | ||||
* @method focus_editor | ||||
*/ | ||||
Cell.prototype.focus_editor = function () { | ||||
Jonathan Frederic
|
r15540 | this.refresh(); | ||
Jonathan Frederic
|
r15497 | this.code_mirror.focus(); | ||
}; | ||||
/** | ||||
Matthias BUSSONNIER
|
r8739 | * Refresh codemirror instance | ||
* @method refresh | ||||
*/ | ||||
Brian Granger
|
r5943 | Cell.prototype.refresh = function () { | ||
Min RK
|
r18999 | if (this.code_mirror) { | ||
this.code_mirror.refresh(); | ||||
} | ||||
Brian Granger
|
r5943 | }; | ||
Matthias BUSSONNIER
|
r8739 | /** | ||
* should be overritten by subclass | ||||
Brian E. Granger
|
r14015 | * @method get_text | ||
*/ | ||||
Cell.prototype.get_text = function () { | ||||
Brian Granger
|
r5943 | }; | ||
Matthias BUSSONNIER
|
r8739 | /** | ||
* should be overritten by subclass | ||||
Brian E. Granger
|
r14015 | * @method set_text | ||
* @param {string} text | ||||
*/ | ||||
Cell.prototype.set_text = function (text) { | ||||
Brian Granger
|
r5943 | }; | ||
Matthias BUSSONNIER
|
r8739 | /** | ||
* should be overritten by subclass | ||||
* serialise cell to json. | ||||
* @method toJSON | ||||
**/ | ||||
Brian Granger
|
r5943 | Cell.prototype.toJSON = function () { | ||
MinRK
|
r7523 | var data = {}; | ||
Jessica B. Hamrick
|
r17998 | // deepcopy the metadata so copied cells don't share the same object | ||
data.metadata = JSON.parse(JSON.stringify(this.metadata)); | ||||
MinRK
|
r13676 | data.cell_type = this.cell_type; | ||
MinRK
|
r7523 | return data; | ||
Brian Granger
|
r5943 | }; | ||
Matthias BUSSONNIER
|
r8739 | /** | ||
* should be overritten by subclass | ||||
* @method fromJSON | ||||
**/ | ||||
Brian Granger
|
r5943 | Cell.prototype.fromJSON = function (data) { | ||
MinRK
|
r7523 | if (data.metadata !== undefined) { | ||
Jonathan Frederic
|
r18854 | this.metadata = data.metadata; | ||
MinRK
|
r7523 | } | ||
Brian Granger
|
r5943 | }; | ||
Matthias BUSSONNIER
|
r8739 | /** | ||
Jessica B. Hamrick
|
r17998 | * can the cell be split into two cells (false if not deletable) | ||
Matthias BUSSONNIER
|
r8739 | * @method is_splittable | ||
**/ | ||||
Brian Granger
|
r5946 | Cell.prototype.is_splittable = function () { | ||
Jessica B. Hamrick
|
r17998 | return this.is_deletable(); | ||
Brian Granger
|
r5946 | }; | ||
Matthias BUSSONNIER
|
r8739 | /** | ||
Jessica B. Hamrick
|
r17998 | * can the cell be merged with other cells (false if not deletable) | ||
MinRK
|
r12509 | * @method is_mergeable | ||
**/ | ||||
Cell.prototype.is_mergeable = function () { | ||||
Jessica B. Hamrick
|
r17998 | return this.is_deletable(); | ||
MinRK
|
r12509 | }; | ||
Jessica B. Hamrick
|
r17998 | /** | ||
Jessica B. Hamrick
|
r18000 | * is the cell deletable? only false (undeletable) if | ||
* metadata.deletable is explicitly false -- everything else | ||||
* counts as true | ||||
* | ||||
Jessica B. Hamrick
|
r17998 | * @method is_deletable | ||
**/ | ||||
Cell.prototype.is_deletable = function () { | ||||
Jessica B. Hamrick
|
r18000 | if (this.metadata.deletable === false) { | ||
return false; | ||||
Jessica B. Hamrick
|
r17998 | } | ||
Jessica B. Hamrick
|
r18000 | return true; | ||
Jessica B. Hamrick
|
r17998 | }; | ||
MinRK
|
r12509 | |||
/** | ||||
Matthias BUSSONNIER
|
r8739 | * @return {String} - the text before the cursor | ||
* @method get_pre_cursor | ||||
**/ | ||||
Brian Granger
|
r5946 | Cell.prototype.get_pre_cursor = function () { | ||
var cursor = this.code_mirror.getCursor(); | ||||
Matthias BUSSONNIER
|
r10165 | var text = this.code_mirror.getRange({line:0, ch:0}, cursor); | ||
Brian Granger
|
r5946 | text = text.replace(/^\n+/, '').replace(/\n+$/, ''); | ||
return text; | ||||
Jonathan Frederic
|
r15497 | }; | ||
Brian Granger
|
r5946 | |||
Matthias BUSSONNIER
|
r8739 | /** | ||
* @return {String} - the text after the cursor | ||||
* @method get_post_cursor | ||||
**/ | ||||
Brian Granger
|
r5946 | Cell.prototype.get_post_cursor = function () { | ||
var cursor = this.code_mirror.getCursor(); | ||||
var last_line_num = this.code_mirror.lineCount()-1; | ||||
var last_line_len = this.code_mirror.getLine(last_line_num).length; | ||||
Jonathan Frederic
|
r15497 | var end = {line:last_line_num, ch:last_line_len}; | ||
Brian Granger
|
r5946 | var text = this.code_mirror.getRange(cursor, end); | ||
text = text.replace(/^\n+/, '').replace(/\n+$/, ''); | ||||
return text; | ||||
}; | ||||
Matthias BUSSONNIER
|
r8739 | /** | ||
Matthias BUSSONNIER
|
r9542 | * Show/Hide CodeMirror LineNumber | ||
Matthias BUSSONNIER
|
r9690 | * @method show_line_numbers | ||
Matthias BUSSONNIER
|
r9542 | * | ||
* @param value {Bool} show (true), or hide (false) the line number in CodeMirror | ||||
**/ | ||||
Cell.prototype.show_line_numbers = function (value) { | ||||
this.code_mirror.setOption('lineNumbers', value); | ||||
this.code_mirror.refresh(); | ||||
}; | ||||
/** | ||||
Matthias BUSSONNIER
|
r8739 | * Toggle CodeMirror LineNumber | ||
* @method toggle_line_numbers | ||||
**/ | ||||
Brian Granger
|
r6059 | Cell.prototype.toggle_line_numbers = function () { | ||
Matthias BUSSONNIER
|
r9690 | var val = this.code_mirror.getOption('lineNumbers'); | ||
this.show_line_numbers(!val); | ||||
Brian Granger
|
r6059 | }; | ||
Matthias BUSSONNIER
|
r8739 | /** | ||
Matthias BUSSONNIER
|
r9548 | * Force codemirror highlight mode | ||
Matthias BUSSONNIER
|
r8739 | * @method force_highlight | ||
* @param {object} - CodeMirror mode | ||||
**/ | ||||
Matthias BUSSONNIER
|
r8202 | Cell.prototype.force_highlight = function(mode) { | ||
this.user_highlight = mode; | ||||
this.auto_highlight(); | ||||
}; | ||||
Matthias BUSSONNIER
|
r8739 | /** | ||
* Try to autodetect cell highlight mode, or use selected mode | ||||
* @methods _auto_highlight | ||||
* @private | ||||
* @param {String|object|undefined} - CodeMirror mode | 'auto' | ||||
**/ | ||||
Matthias BUSSONNIER
|
r8202 | Cell.prototype._auto_highlight = function (modes) { | ||
Jonathan Frederic
|
r19176 | /** | ||
*Here we handle manually selected modes | ||||
*/ | ||||
MinRK
|
r18286 | var that = this; | ||
Jonathan Frederic
|
r15497 | var mode; | ||
if( this.user_highlight !== undefined && this.user_highlight != 'auto' ) | ||||
Matthias BUSSONNIER
|
r8202 | { | ||
Jonathan Frederic
|
r15497 | mode = this.user_highlight; | ||
Matthias BUSSONNIER
|
r8202 | CodeMirror.autoLoadMode(this.code_mirror, mode); | ||
this.code_mirror.setOption('mode', mode); | ||||
return; | ||||
} | ||||
Matthias BUSSONNIER
|
r13573 | var current_mode = this.code_mirror.getOption('mode', mode); | ||
Matthias BUSSONNIER
|
r8202 | var first_line = this.code_mirror.getLine(0); | ||
// loop on every pairs | ||||
Jonathan Frederic
|
r15497 | for(mode in modes) { | ||
var regs = modes[mode].reg; | ||||
Matthias BUSSONNIER
|
r8202 | // only one key every time but regexp can't be keys... | ||
Sylvain Corlay
|
r14106 | for(var i=0; i<regs.length; i++) { | ||
Matthias BUSSONNIER
|
r8202 | // here we handle non magic_modes | ||
Jonathan Frederic
|
r15497 | if(first_line.match(regs[i]) !== null) { | ||
Matthias BUSSONNIER
|
r13573 | if(current_mode == mode){ | ||
return; | ||||
} | ||||
Jonathan Frederic
|
r15497 | if (mode.search('magic_') !== 0) { | ||
Nicholas Bollweg (Nick)
|
r19286 | utils.requireCodeMirrorMode(mode, function (spec) { | ||
that.code_mirror.setOption('mode', spec); | ||||
MinRK
|
r18286 | }); | ||
Matthias BUSSONNIER
|
r8202 | return; | ||
} | ||||
Jonathan Frederic
|
r15497 | var open = modes[mode].open || "%%"; | ||
var close = modes[mode].close || "%%end"; | ||||
Matthias Bussonnier
|
r18289 | var magic_mode = mode; | ||
mode = magic_mode.substr(6); | ||||
if(current_mode == magic_mode){ | ||||
Matthias BUSSONNIER
|
r13573 | return; | ||
} | ||||
Nicholas Bollweg (Nick)
|
r19286 | utils.requireCodeMirrorMode(mode, function (spec) { | ||
MinRK
|
r18286 | // create on the fly a mode that switch between | ||
// plain/text and something else, otherwise `%%` is | ||||
// source of some highlight issues. | ||||
Matthias Bussonnier
|
r18289 | CodeMirror.defineMode(magic_mode, function(config) { | ||
MinRK
|
r18286 | return CodeMirror.multiplexingMode( | ||
CodeMirror.getMode(config, 'text/plain'), | ||||
Matthias Bussonnier
|
r18289 | // always set something on close | ||
MinRK
|
r18286 | {open: open, close: close, | ||
Nicholas Bollweg (Nick)
|
r19286 | mode: CodeMirror.getMode(config, spec), | ||
MinRK
|
r18286 | delimStyle: "delimit" | ||
} | ||||
); | ||||
}); | ||||
Matthias Bussonnier
|
r18289 | that.code_mirror.setOption('mode', magic_mode); | ||
Matthias BUSSONNIER
|
r8202 | }); | ||
return; | ||||
} | ||||
} | ||||
} | ||||
Matthias BUSSONNIER
|
r12233 | // fallback on default | ||
Jonathan Frederic
|
r15497 | var default_mode; | ||
Matthias Bussonnier
|
r12237 | try { | ||
default_mode = this._options.cm_config.mode; | ||||
} catch(e) { | ||||
default_mode = 'text/plain'; | ||||
} | ||||
Matthias BUSSONNIER
|
r13573 | if( current_mode === default_mode){ | ||
Jonathan Frederic
|
r15497 | return; | ||
Matthias BUSSONNIER
|
r13573 | } | ||
Matthias BUSSONNIER
|
r8202 | this.code_mirror.setOption('mode', default_mode); | ||
}; | ||||
Brian Granger
|
r6059 | |||
Min RK
|
r18999 | var UnrecognizedCell = function (options) { | ||
/** Constructor for unrecognized cells */ | ||||
Cell.apply(this, arguments); | ||||
this.cell_type = 'unrecognized'; | ||||
this.celltoolbar = null; | ||||
this.data = {}; | ||||
Object.seal(this); | ||||
}; | ||||
UnrecognizedCell.prototype = Object.create(Cell.prototype); | ||||
// cannot merge or split unrecognized cells | ||||
UnrecognizedCell.prototype.is_mergeable = function () { | ||||
return false; | ||||
}; | ||||
UnrecognizedCell.prototype.is_splittable = function () { | ||||
return false; | ||||
}; | ||||
UnrecognizedCell.prototype.toJSON = function () { | ||||
Jonathan Frederic
|
r19176 | /** | ||
* deepcopy the metadata so copied cells don't share the same object | ||||
*/ | ||||
Min RK
|
r18999 | return JSON.parse(JSON.stringify(this.data)); | ||
}; | ||||
UnrecognizedCell.prototype.fromJSON = function (data) { | ||||
this.data = data; | ||||
if (data.metadata !== undefined) { | ||||
this.metadata = data.metadata; | ||||
} else { | ||||
data.metadata = this.metadata; | ||||
} | ||||
Min RK
|
r19107 | this.element.find('.inner_cell').find("a").text("Unrecognized cell type: " + data.cell_type); | ||
Min RK
|
r18999 | }; | ||
UnrecognizedCell.prototype.create_element = function () { | ||||
Cell.prototype.create_element.apply(this, arguments); | ||||
var cell = this.element = $("<div>").addClass('cell unrecognized_cell'); | ||||
cell.attr('tabindex','2'); | ||||
var prompt = $('<div/>').addClass('prompt input_prompt'); | ||||
cell.append(prompt); | ||||
var inner_cell = $('<div/>').addClass('inner_cell'); | ||||
Min RK
|
r19107 | inner_cell.append( | ||
$("<a>") | ||||
.attr("href", "#") | ||||
.text("Unrecognized cell type") | ||||
); | ||||
Min RK
|
r18999 | cell.append(inner_cell); | ||
this.element = cell; | ||||
}; | ||||
Min RK
|
r19107 | |||
UnrecognizedCell.prototype.bind_events = function () { | ||||
Cell.prototype.bind_events.apply(this, arguments); | ||||
var cell = this; | ||||
this.element.find('.inner_cell').find("a").click(function () { | ||||
cell.events.trigger('unrecognized_cell.Cell', {cell: cell}) | ||||
}); | ||||
}; | ||||
Min RK
|
r18999 | |||
Matthias BUSSONNIER
|
r17421 | // Backwards compatibility. | ||
Brian E. Granger
|
r4352 | IPython.Cell = Cell; | ||
Min RK
|
r18999 | return { | ||
Cell: Cell, | ||||
UnrecognizedCell: UnrecognizedCell | ||||
}; | ||||
Jonathan Frederic
|
r17196 | }); | ||