##// END OF EJS Templates
Catch errors after our then()s, instead of in parallel with them (this missing exceptions)...
Catch errors after our then()s, instead of in parallel with them (this missing exceptions) When an error is thrown in a then() success handler, it doesn't call the same then()'s error handler. I also made all of the utils.reject handlers verbose to aid in debugging.

File last commit:

r18864:006d1360
r19080:cbc9dc59
Show More
textcell.js
346 lines | 11.1 KiB | application/javascript | JavascriptLexer
// Copyright (c) IPython Development Team.
// Distributed under the terms of the Modified BSD License.
define([
'base/js/namespace',
'base/js/utils',
'jquery',
'notebook/js/cell',
'base/js/security',
'notebook/js/mathjaxutils',
'notebook/js/celltoolbar',
'components/marked/lib/marked',
'codemirror/lib/codemirror',
'codemirror/mode/gfm/gfm',
'notebook/js/codemirror-ipythongfm'
], function(IPython,utils , $, cell, security, mathjaxutils, celltoolbar, marked, CodeMirror, gfm, ipgfm) {
"use strict";
var Cell = cell.Cell;
var TextCell = function (options) {
// Constructor
//
// Construct a new TextCell, codemirror mode is by default 'htmlmixed',
// and cell type is 'text' cell start as not redered.
//
// Parameters:
// options: dictionary
// Dictionary of keyword arguments.
// events: $(Events) instance
// config: dictionary
// keyboard_manager: KeyboardManager instance
// notebook: Notebook instance
options = options || {};
// in all TextCell/Cell subclasses
// do not assign most of members here, just pass it down
// in the options dict potentially overwriting what you wish.
// they will be assigned in the base class.
this.notebook = options.notebook;
this.events = options.events;
this.config = options.config;
// we cannot put this as a class key as it has handle to "this".
var cm_overwrite_options = {
onKeyEvent: $.proxy(this.handle_keyevent,this)
};
var config = utils.mergeopt(TextCell, this.config, {cm_config:cm_overwrite_options});
Cell.apply(this, [{
config: config,
keyboard_manager: options.keyboard_manager,
events: this.events}]);
this.cell_type = this.cell_type || 'text';
mathjaxutils = mathjaxutils;
this.rendered = false;
};
TextCell.prototype = Object.create(Cell.prototype);
TextCell.options_default = {
cm_config : {
extraKeys: {"Tab": "indentMore","Shift-Tab" : "indentLess"},
mode: 'htmlmixed',
lineWrapping : true,
}
};
/**
* Create the DOM element of the TextCell
* @method create_element
* @private
*/
TextCell.prototype.create_element = function () {
Cell.prototype.create_element.apply(this, arguments);
var cell = $("<div>").addClass('cell text_cell');
cell.attr('tabindex','2');
var prompt = $('<div/>').addClass('prompt input_prompt');
cell.append(prompt);
var inner_cell = $('<div/>').addClass('inner_cell');
this.celltoolbar = new celltoolbar.CellToolbar({
cell: this,
notebook: this.notebook});
inner_cell.append(this.celltoolbar.element);
var input_area = $('<div/>').addClass('input_area');
this.code_mirror = new CodeMirror(input_area.get(0), this.cm_config);
// The tabindex=-1 makes this div focusable.
var render_area = $('<div/>').addClass('text_cell_render rendered_html')
.attr('tabindex','-1');
inner_cell.append(input_area).append(render_area);
cell.append(inner_cell);
this.element = cell;
};
// Cell level actions
TextCell.prototype.select = function () {
var cont = Cell.prototype.select.apply(this);
if (cont) {
if (this.mode === 'edit') {
this.code_mirror.refresh();
}
}
return cont;
};
TextCell.prototype.unrender = function () {
if (this.read_only) return;
var cont = Cell.prototype.unrender.apply(this);
if (cont) {
var text_cell = this.element;
var output = text_cell.find("div.text_cell_render");
if (this.get_text() === this.placeholder) {
this.set_text('');
}
this.refresh();
}
return cont;
};
TextCell.prototype.execute = function () {
this.render();
};
/**
* setter: {{#crossLink "TextCell/set_text"}}{{/crossLink}}
* @method get_text
* @retrun {string} CodeMirror current text value
*/
TextCell.prototype.get_text = function() {
return this.code_mirror.getValue();
};
/**
* @param {string} text - Codemiror text value
* @see TextCell#get_text
* @method set_text
* */
TextCell.prototype.set_text = function(text) {
this.code_mirror.setValue(text);
this.unrender();
this.code_mirror.refresh();
};
/**
* setter :{{#crossLink "TextCell/set_rendered"}}{{/crossLink}}
* @method get_rendered
* */
TextCell.prototype.get_rendered = function() {
return this.element.find('div.text_cell_render').html();
};
/**
* @method set_rendered
*/
TextCell.prototype.set_rendered = function(text) {
this.element.find('div.text_cell_render').html(text);
};
/**
* Create Text cell from JSON
* @param {json} data - JSON serialized text-cell
* @method fromJSON
*/
TextCell.prototype.fromJSON = function (data) {
Cell.prototype.fromJSON.apply(this, arguments);
if (data.cell_type === this.cell_type) {
if (data.source !== undefined) {
this.set_text(data.source);
// make this value the starting point, so that we can only undo
// to this state, instead of a blank cell
this.code_mirror.clearHistory();
// TODO: This HTML needs to be treated as potentially dangerous
// user input and should be handled before set_rendered.
this.set_rendered(data.rendered || '');
this.rendered = false;
this.render();
}
}
};
/** Generate JSON from cell
* @return {object} cell data serialised to json
*/
TextCell.prototype.toJSON = function () {
var data = Cell.prototype.toJSON.apply(this);
data.source = this.get_text();
if (data.source == this.placeholder) {
data.source = "";
}
return data;
};
var MarkdownCell = function (options) {
// Constructor
//
// Parameters:
// options: dictionary
// Dictionary of keyword arguments.
// events: $(Events) instance
// config: dictionary
// keyboard_manager: KeyboardManager instance
// notebook: Notebook instance
options = options || {};
var config = utils.mergeopt(MarkdownCell, options.config);
TextCell.apply(this, [$.extend({}, options, {config: config})]);
this.cell_type = 'markdown';
};
MarkdownCell.options_default = {
cm_config: {
mode: 'ipythongfm'
},
placeholder: "Type *Markdown* and LaTeX: $\\alpha^2$"
};
MarkdownCell.prototype = Object.create(TextCell.prototype);
MarkdownCell.prototype.set_heading_level = function (level) {
// make a markdown cell a heading
level = level || 1;
var source = this.get_text();
source = source.replace(/^(#*)\s?/,
new Array(level + 1).join('#') + ' ');
this.set_text(source);
this.refresh();
if (this.rendered) {
this.render();
}
};
/**
* @method render
*/
MarkdownCell.prototype.render = function () {
var cont = TextCell.prototype.render.apply(this);
if (cont) {
var that = this;
var text = this.get_text();
var math = null;
if (text === "") { text = this.placeholder; }
var text_and_math = mathjaxutils.remove_math(text);
text = text_and_math[0];
math = text_and_math[1];
marked(text, function (err, html) {
html = mathjaxutils.replace_math(html, math);
html = security.sanitize_html(html);
html = $($.parseHTML(html));
// add anchors to headings
html.find(":header").addBack(":header").each(function (i, h) {
h = $(h);
var hash = h.text().replace(/ /g, '-');
h.attr('id', hash);
h.append(
$('<a/>')
.addClass('anchor-link')
.attr('href', '#' + hash)
.text('ΒΆ')
);
});
// links in markdown cells should open in new tabs
html.find("a[href]").not('[href^="#"]').attr("target", "_blank");
that.set_rendered(html);
that.typeset();
that.events.trigger("rendered.MarkdownCell", {cell: that});
});
}
return cont;
};
var RawCell = function (options) {
// Constructor
//
// Parameters:
// options: dictionary
// Dictionary of keyword arguments.
// events: $(Events) instance
// config: dictionary
// keyboard_manager: KeyboardManager instance
// notebook: Notebook instance
options = options || {};
var config = utils.mergeopt(RawCell, options.config);
TextCell.apply(this, [$.extend({}, options, {config: config})]);
this.cell_type = 'raw';
};
RawCell.options_default = {
placeholder : "Write raw LaTeX or other formats here, for use with nbconvert. " +
"It will not be rendered in the notebook. " +
"When passing through nbconvert, a Raw Cell's content is added to the output unmodified."
};
RawCell.prototype = Object.create(TextCell.prototype);
/** @method bind_events **/
RawCell.prototype.bind_events = function () {
TextCell.prototype.bind_events.apply(this);
var that = this;
this.element.focusout(function() {
that.auto_highlight();
that.render();
});
this.code_mirror.on('focus', function() { that.unrender(); });
};
/**
* Trigger autodetection of highlight scheme for current cell
* @method auto_highlight
*/
RawCell.prototype.auto_highlight = function () {
this._auto_highlight(this.config.raw_cell_highlight);
};
/** @method render **/
RawCell.prototype.render = function () {
var cont = TextCell.prototype.render.apply(this);
if (cont){
var text = this.get_text();
if (text === "") { text = this.placeholder; }
this.set_text(text);
this.element.removeClass('rendered');
}
return cont;
};
// Backwards compatability.
IPython.TextCell = TextCell;
IPython.MarkdownCell = MarkdownCell;
IPython.RawCell = RawCell;
var textcell = {
TextCell: TextCell,
MarkdownCell: MarkdownCell,
RawCell: RawCell,
};
return textcell;
});