textcell.js
298 lines
| 8.7 KiB
| application/javascript
|
JavascriptLexer
Brian E. Granger
|
r4609 | //---------------------------------------------------------------------------- | ||
// Copyright (C) 2008-2011 The IPython Development Team | ||||
// | ||||
// Distributed under the terms of the BSD License. The full license is in | ||||
// the file COPYING, distributed as part of this software. | ||||
//---------------------------------------------------------------------------- | ||||
Brian E. Granger
|
r4349 | |||
//============================================================================ | ||||
Brian Granger
|
r4508 | // TextCell | ||
Brian E. Granger
|
r4349 | //============================================================================ | ||
Brian E. Granger
|
r4352 | var IPython = (function (IPython) { | ||
Brian E. Granger
|
r4349 | |||
Brian Granger
|
r4508 | // TextCell base class | ||
var TextCell = function (notebook) { | ||||
this.code_mirror_mode = this.code_mirror_mode || 'htmlmixed'; | ||||
Brian E. Granger
|
r4352 | IPython.Cell.apply(this, arguments); | ||
this.rendered = false; | ||||
Brian Granger
|
r4508 | this.cell_type = this.cell_type || 'text'; | ||
Brian E. Granger
|
r4352 | }; | ||
Brian Granger
|
r4508 | TextCell.prototype = new IPython.Cell(); | ||
Brian E. Granger
|
r4352 | |||
Brian E. Granger
|
r4499 | |||
Brian Granger
|
r4508 | TextCell.prototype.create_element = function () { | ||
var cell = $("<div>").addClass('cell text_cell border-box-sizing'); | ||||
Brian E. Granger
|
r4629 | cell.attr('tabindex','2'); | ||
Brian Granger
|
r5946 | var input_area = $('<div/>').addClass('text_cell_input border-box-sizing'); | ||
Brian E. Granger
|
r4499 | this.code_mirror = CodeMirror(input_area.get(0), { | ||
indentUnit : 4, | ||||
Brian Granger
|
r4508 | mode: this.code_mirror_mode, | ||
Brian E. Granger
|
r4504 | theme: 'default', | ||
MinRK
|
r5200 | value: this.placeholder, | ||
Brian Granger
|
r5942 | readOnly: this.read_only, | ||
Fernando Perez
|
r5978 | lineWrapping : true, | ||
Brian Granger
|
r5942 | onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this) | ||
Brian E. Granger
|
r4499 | }); | ||
// The tabindex=-1 makes this div focusable. | ||||
Brian Granger
|
r5946 | var render_area = $('<div/>').addClass('text_cell_render border-box-sizing'). | ||
Brian E. Granger
|
r4507 | addClass('rendered_html').attr('tabindex','-1'); | ||
Brian E. Granger
|
r4499 | cell.append(input_area).append(render_area); | ||
Brian E. Granger
|
r4352 | this.element = cell; | ||
}; | ||||
Brian Granger
|
r4508 | TextCell.prototype.bind_events = function () { | ||
Brian E. Granger
|
r4352 | IPython.Cell.prototype.bind_events.apply(this); | ||
var that = this; | ||||
this.element.keydown(function (event) { | ||||
if (event.which === 13) { | ||||
if (that.rendered) { | ||||
that.edit(); | ||||
Brian Granger
|
r5942 | return false; | ||
Brian Granger
|
r5946 | }; | ||
}; | ||||
}); | ||||
this.element.dblclick(function () { | ||||
that.edit(); | ||||
Brian E. Granger
|
r4352 | }); | ||
}; | ||||
Brian E. Granger
|
r4349 | |||
Brian Granger
|
r5942 | TextCell.prototype.handle_codemirror_keyevent = function (editor, event) { | ||
// This method gets called in CodeMirror's onKeyDown/onKeyPress | ||||
// handlers and is used to provide custom key handling. Its return | ||||
// value is used to determine if CodeMirror should ignore the event: | ||||
// true = ignore, false = don't ignore. | ||||
fawce
|
r5990 | |||
Brian Granger
|
r5942 | if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) { | ||
// Always ignore shift-enter in CodeMirror as we handle it. | ||||
return true; | ||||
} | ||||
return false; | ||||
}; | ||||
Brian Granger
|
r4508 | TextCell.prototype.select = function () { | ||
Brian E. Granger
|
r4352 | IPython.Cell.prototype.select.apply(this); | ||
Brian Granger
|
r4508 | var output = this.element.find("div.text_cell_render"); | ||
Brian E. Granger
|
r4352 | output.trigger('focus'); | ||
}; | ||||
Brian E. Granger
|
r4349 | |||
MinRK
|
r5833 | TextCell.prototype.unselect = function() { | ||
// render on selection of another cell | ||||
this.render(); | ||||
IPython.Cell.prototype.unselect.apply(this); | ||||
}; | ||||
Brian Granger
|
r4508 | TextCell.prototype.edit = function () { | ||
MinRK
|
r5200 | if ( this.read_only ) return; | ||
Brian E. Granger
|
r4352 | if (this.rendered === true) { | ||
Brian Granger
|
r4508 | var text_cell = this.element; | ||
var output = text_cell.find("div.text_cell_render"); | ||||
Brian E. Granger
|
r4352 | output.hide(); | ||
Brian Granger
|
r4508 | text_cell.find('div.text_cell_input').show(); | ||
Brian Granger
|
r5946 | this.code_mirror.refresh(); | ||
Brian E. Granger
|
r4499 | this.code_mirror.focus(); | ||
Brian Granger
|
r5971 | // We used to need an additional refresh() after the focus, but | ||
// it appears that this has been fixed in CM. This bug would show | ||||
// up on FF when a newly loaded markdown cell was edited. | ||||
Brian E. Granger
|
r4352 | this.rendered = false; | ||
Brian Granger
|
r5943 | if (this.get_text() === this.placeholder) { | ||
this.set_text(''); | ||||
Brian Granger
|
r5946 | this.refresh(); | ||
Stefan van der Walt
|
r5479 | } | ||
} | ||||
Brian E. Granger
|
r4349 | }; | ||
Brian Granger
|
r4508 | // Subclasses must define render. | ||
TextCell.prototype.render = function () {}; | ||||
Brian E. Granger
|
r4349 | |||
Brian Granger
|
r5943 | TextCell.prototype.get_text = function() { | ||
Brian E. Granger
|
r4499 | return this.code_mirror.getValue(); | ||
Brian E. Granger
|
r4352 | }; | ||
Brian E. Granger
|
r4349 | |||
Brian Granger
|
r5943 | TextCell.prototype.set_text = function(text) { | ||
Brian E. Granger
|
r4499 | this.code_mirror.setValue(text); | ||
this.code_mirror.refresh(); | ||||
Brian E. Granger
|
r4352 | }; | ||
Brian E. Granger
|
r4349 | |||
Brian E. Granger
|
r4513 | TextCell.prototype.get_rendered = function() { | ||
Brian Granger
|
r4508 | return this.element.find('div.text_cell_render').html(); | ||
}; | ||||
TextCell.prototype.set_rendered = function(text) { | ||||
this.element.find('div.text_cell_render').html(text); | ||||
Brian E. Granger
|
r4352 | }; | ||
Brian E. Granger
|
r4349 | |||
Brian Granger
|
r4508 | TextCell.prototype.at_top = function () { | ||
Brian E. Granger
|
r4352 | if (this.rendered) { | ||
return true; | ||||
} else { | ||||
return false; | ||||
} | ||||
}; | ||||
Brian Granger
|
r4508 | TextCell.prototype.at_bottom = function () { | ||
Brian E. Granger
|
r4352 | if (this.rendered) { | ||
return true; | ||||
} else { | ||||
return false; | ||||
} | ||||
}; | ||||
Brian E. Granger
|
r4349 | |||
Brian Granger
|
r4508 | TextCell.prototype.fromJSON = function (data) { | ||
if (data.cell_type === this.cell_type) { | ||||
Brian E. Granger
|
r4499 | if (data.source !== undefined) { | ||
Brian Granger
|
r5943 | this.set_text(data.source); | ||
Brian E. Granger
|
r4513 | this.set_rendered(data.rendered || ''); | ||
this.rendered = false; | ||||
this.render(); | ||||
Stefan van der Walt
|
r5479 | } | ||
} | ||||
Brian E. Granger
|
r4513 | }; | ||
Brian E. Granger
|
r4349 | |||
Brian Granger
|
r4508 | TextCell.prototype.toJSON = function () { | ||
Stefan van der Walt
|
r5479 | var data = {}; | ||
Brian Granger
|
r4508 | data.cell_type = this.cell_type; | ||
Brian Granger
|
r5943 | data.source = this.get_text(); | ||
Brian E. Granger
|
r4484 | return data; | ||
Brian E. Granger
|
r4349 | }; | ||
Brian Granger
|
r4508 | |||
// HTMLCell | ||||
var HTMLCell = function (notebook) { | ||||
Brian Granger
|
r5944 | this.placeholder = "Type <strong>HTML</strong> and LaTeX: $\\alpha^2$"; | ||
Brian Granger
|
r4508 | IPython.TextCell.apply(this, arguments); | ||
this.cell_type = 'html'; | ||||
}; | ||||
HTMLCell.prototype = new TextCell(); | ||||
HTMLCell.prototype.render = function () { | ||||
if (this.rendered === false) { | ||||
Brian Granger
|
r5943 | var text = this.get_text(); | ||
Stefan van der Walt
|
r5479 | if (text === "") { text = this.placeholder; } | ||
Brian Granger
|
r4508 | this.set_rendered(text); | ||
MinRK
|
r5547 | this.typeset(); | ||
Brian Granger
|
r4508 | this.element.find('div.text_cell_input').hide(); | ||
this.element.find("div.text_cell_render").show(); | ||||
this.rendered = true; | ||||
Stefan van der Walt
|
r5479 | } | ||
Brian Granger
|
r4508 | }; | ||
// MarkdownCell | ||||
var MarkdownCell = function (notebook) { | ||||
Brian Granger
|
r5944 | this.placeholder = "Type *Markdown* and LaTeX: $\\alpha^2$"; | ||
Brian Granger
|
r4508 | IPython.TextCell.apply(this, arguments); | ||
this.cell_type = 'markdown'; | ||||
}; | ||||
MarkdownCell.prototype = new TextCell(); | ||||
MarkdownCell.prototype.render = function () { | ||||
if (this.rendered === false) { | ||||
Brian Granger
|
r5943 | var text = this.get_text(); | ||
Stefan van der Walt
|
r5479 | if (text === "") { text = this.placeholder; } | ||
Brian Granger
|
r4508 | var html = IPython.markdown_converter.makeHtml(text); | ||
this.set_rendered(html); | ||||
MinRK
|
r5547 | this.typeset() | ||
Brian Granger
|
r4508 | this.element.find('div.text_cell_input').hide(); | ||
this.element.find("div.text_cell_render").show(); | ||||
Stefan van der Walt
|
r4655 | var code_snippets = this.element.find("pre > code"); | ||
code_snippets.replaceWith(function () { | ||||
var code = $(this).html(); | ||||
/* Substitute br for newlines and for spaces | ||||
before highlighting, since prettify doesn't | ||||
preserve those on all browsers */ | ||||
code = code.replace(/(\r\n|\n|\r)/gm, "<br/>"); | ||||
code = code.replace(/ /gm, ' '); | ||||
code = prettyPrintOne(code); | ||||
return '<code class="prettyprint">' + code + '</code>'; | ||||
}); | ||||
Brian Granger
|
r4508 | this.rendered = true; | ||
Stefan van der Walt
|
r5479 | } | ||
Brian Granger
|
r4508 | }; | ||
// RSTCell | ||||
var RSTCell = function (notebook) { | ||||
Brian Granger
|
r5944 | this.placeholder = "Type *ReStructured Text* and LaTeX: $\\alpha^2$"; | ||
Brian Granger
|
r6017 | this.code_mirror_mode = 'rst'; | ||
Brian Granger
|
r4508 | IPython.TextCell.apply(this, arguments); | ||
this.cell_type = 'rst'; | ||||
}; | ||||
RSTCell.prototype = new TextCell(); | ||||
RSTCell.prototype.render = function () { | ||||
Brian Granger
|
r6017 | this.rendered = true; | ||
this.edit(); | ||||
}; | ||||
RSTCell.prototype.select = function () { | ||||
IPython.Cell.prototype.select.apply(this); | ||||
// In some cases (inserting a new cell) we need a refresh before and | ||||
// after the focus. Not sure why this is the case. | ||||
this.code_mirror.refresh(); | ||||
this.code_mirror.focus(); | ||||
this.code_mirror.refresh(); | ||||
}; | ||||
RSTCell.prototype.at_top = function () { | ||||
var cursor = this.code_mirror.getCursor(); | ||||
if (cursor.line === 0) { | ||||
return true; | ||||
} else { | ||||
return false; | ||||
Stefan van der Walt
|
r5479 | } | ||
Brian Granger
|
r4508 | }; | ||
Brian Granger
|
r6017 | RSTCell.prototype.at_bottom = function () { | ||
var cursor = this.code_mirror.getCursor(); | ||||
if (cursor.line === (this.code_mirror.lineCount()-1)) { | ||||
return true; | ||||
} else { | ||||
return false; | ||||
} | ||||
Brian Granger
|
r4508 | }; | ||
IPython.TextCell = TextCell; | ||||
Brian E. Granger
|
r4499 | IPython.HTMLCell = HTMLCell; | ||
Brian Granger
|
r4508 | IPython.MarkdownCell = MarkdownCell; | ||
IPython.RSTCell = RSTCell; | ||||
Brian E. Granger
|
r4349 | |||
Brian E. Granger
|
r4352 | return IPython; | ||
Brian E. Granger
|
r4349 | |||
Brian E. Granger
|
r4352 | }(IPython)); | ||
Brian E. Granger
|
r4349 | |||