mirror of
https://github.com/jupyter/notebook.git
synced 2025-02-11 12:30:51 +08:00
Merge pull request #6991 from minrk/unhandled-types
Handle unrecognized output and cell types
This commit is contained in:
commit
eb14a13843
@ -53,7 +53,9 @@ define([
|
||||
get: function() { return that._metadata; },
|
||||
set: function(value) {
|
||||
that._metadata = value;
|
||||
that.celltoolbar.rebuild();
|
||||
if (that.celltoolbar) {
|
||||
that.celltoolbar.rebuild();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -194,11 +196,11 @@ define([
|
||||
if((cur.line !== 0 || cur.ch !==0) && event.keyCode === 38){
|
||||
event._ipkmIgnore = true;
|
||||
}
|
||||
var nLastLine = editor.lastLine()
|
||||
if( ( event.keyCode === 40)
|
||||
&& (( cur.line !== nLastLine)
|
||||
|| ( cur.ch !== editor.getLineHandle(nLastLine).text.length))
|
||||
){
|
||||
var nLastLine = editor.lastLine();
|
||||
if ((event.keyCode === 40) &&
|
||||
((cur.line !== nLastLine) ||
|
||||
(cur.ch !== editor.getLineHandle(nLastLine).text.length))
|
||||
) {
|
||||
event._ipkmIgnore = true;
|
||||
}
|
||||
// if this is an edit_shortcuts shortcut, the global keyboard/shortcut
|
||||
@ -254,6 +256,14 @@ define([
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* should be overritten by subclass
|
||||
* @method execute
|
||||
*/
|
||||
Cell.prototype.execute = function () {
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* handle cell level logic when a cell is rendered
|
||||
* @method render
|
||||
@ -386,7 +396,9 @@ define([
|
||||
* @method refresh
|
||||
*/
|
||||
Cell.prototype.refresh = function () {
|
||||
this.code_mirror.refresh();
|
||||
if (this.code_mirror) {
|
||||
this.code_mirror.refresh();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -590,8 +602,74 @@ define([
|
||||
this.code_mirror.setOption('mode', default_mode);
|
||||
};
|
||||
|
||||
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 () {
|
||||
// deepcopy the metadata so copied cells don't share the same object
|
||||
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;
|
||||
}
|
||||
this.element.find('.inner_cell').find("a").text("Unrecognized cell type: " + data.cell_type);
|
||||
};
|
||||
|
||||
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');
|
||||
inner_cell.append(
|
||||
$("<a>")
|
||||
.attr("href", "#")
|
||||
.text("Unrecognized cell type")
|
||||
);
|
||||
cell.append(inner_cell);
|
||||
this.element = cell;
|
||||
};
|
||||
|
||||
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})
|
||||
});
|
||||
};
|
||||
|
||||
// Backwards compatibility.
|
||||
IPython.Cell = Cell;
|
||||
|
||||
return {'Cell': Cell};
|
||||
return {
|
||||
Cell: Cell,
|
||||
UnrecognizedCell: UnrecognizedCell
|
||||
};
|
||||
});
|
||||
|
@ -6,6 +6,7 @@ define([
|
||||
'jquery',
|
||||
'base/js/utils',
|
||||
'base/js/dialog',
|
||||
'notebook/js/cell',
|
||||
'notebook/js/textcell',
|
||||
'notebook/js/codecell',
|
||||
'services/sessions/session',
|
||||
@ -22,13 +23,14 @@ define([
|
||||
'notebook/js/scrollmanager'
|
||||
], function (
|
||||
IPython,
|
||||
$,
|
||||
utils,
|
||||
dialog,
|
||||
textcell,
|
||||
codecell,
|
||||
$,
|
||||
utils,
|
||||
dialog,
|
||||
cellmod,
|
||||
textcell,
|
||||
codecell,
|
||||
session,
|
||||
celltoolbar,
|
||||
celltoolbar,
|
||||
marked,
|
||||
CodeMirror,
|
||||
runMode,
|
||||
@ -147,7 +149,7 @@ define([
|
||||
this.minimum_autosave_interval = 120000;
|
||||
this.notebook_name_blacklist_re = /[\/\\:]/;
|
||||
this.nbformat = 4; // Increment this when changing the nbformat
|
||||
this.nbformat_minor = 0; // Increment this when changing the nbformat
|
||||
this.nbformat_minor = this.current_nbformat_minor = 0; // Increment this when changing the nbformat
|
||||
this.codemirror_mode = 'ipython';
|
||||
this.create_elements();
|
||||
this.bind_events();
|
||||
@ -211,6 +213,14 @@ define([
|
||||
that.dirty = true;
|
||||
});
|
||||
|
||||
this.events.on('unrecognized_cell.Cell', function () {
|
||||
that.warn_nbformat_minor();
|
||||
});
|
||||
|
||||
this.events.on('unrecognized_output.OutputArea', function () {
|
||||
that.warn_nbformat_minor();
|
||||
});
|
||||
|
||||
this.events.on('set_dirty.Notebook', function (event, data) {
|
||||
that.dirty = data.value;
|
||||
});
|
||||
@ -304,6 +314,28 @@ define([
|
||||
return null;
|
||||
};
|
||||
};
|
||||
|
||||
Notebook.prototype.warn_nbformat_minor = function (event) {
|
||||
// trigger a warning dialog about missing functionality from newer minor versions
|
||||
var v = 'v' + this.nbformat + '.';
|
||||
var orig_vs = v + this.nbformat_minor;
|
||||
var this_vs = v + this.current_nbformat_minor;
|
||||
var msg = "This notebook is version " + orig_vs + ", but we only fully support up to " +
|
||||
this_vs + ". You can still work with this notebook, but cell and output types " +
|
||||
"introduced in later notebook versions will not be available.";
|
||||
|
||||
dialog.modal({
|
||||
notebook: this,
|
||||
keyboard_manager: this.keyboard_manager,
|
||||
title : "Newer Notebook",
|
||||
body : msg,
|
||||
buttons : {
|
||||
OK : {
|
||||
"class" : "btn-danger"
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the dirty flag, and trigger the set_dirty.Notebook event
|
||||
@ -900,7 +932,8 @@ define([
|
||||
cell = new textcell.RawCell(cell_options);
|
||||
break;
|
||||
default:
|
||||
console.log("invalid cell type: ", type);
|
||||
console.log("Unrecognized cell type: ", type, cellmod);
|
||||
cell = new cellmod.UnrecognizedCell(cell_options);
|
||||
}
|
||||
|
||||
if(this._insert_element_at_index(cell.element,index)) {
|
||||
@ -2222,26 +2255,8 @@ define([
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (orig_nbformat_minor !== undefined && nbmodel.nbformat_minor < orig_nbformat_minor) {
|
||||
var that = this;
|
||||
var orig_vs = 'v' + nbmodel.nbformat + '.' + orig_nbformat_minor;
|
||||
var this_vs = 'v' + nbmodel.nbformat + '.' + this.nbformat_minor;
|
||||
msg = "This notebook is version " + orig_vs + ", but we only fully support up to " +
|
||||
this_vs + ". You can still work with this notebook, but some features " +
|
||||
"introduced in later notebook versions may not be available.";
|
||||
|
||||
dialog.modal({
|
||||
notebook: this,
|
||||
keyboard_manager: this.keyboard_manager,
|
||||
title : "Newer Notebook",
|
||||
body : msg,
|
||||
buttons : {
|
||||
OK : {
|
||||
class : "btn-danger"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
} else if (this.nbformat_minor < nbmodel.nbformat_minor) {
|
||||
this.nbformat_minor = nbmodel.nbformat_minor;
|
||||
}
|
||||
|
||||
// Create the session after the notebook is completely loaded to prevent
|
||||
|
@ -245,7 +245,7 @@ define([
|
||||
'text/plain'
|
||||
];
|
||||
|
||||
OutputArea.prototype.validate_output = function (json) {
|
||||
OutputArea.prototype.validate_mimebundle = function (json) {
|
||||
// scrub invalid outputs
|
||||
var data = json.data;
|
||||
$.map(OutputArea.output_types, function(key){
|
||||
@ -263,11 +263,6 @@ define([
|
||||
OutputArea.prototype.append_output = function (json) {
|
||||
this.expand();
|
||||
|
||||
// validate output data types
|
||||
if (json.data) {
|
||||
json = this.validate_output(json);
|
||||
}
|
||||
|
||||
// Clear the output if clear is queued.
|
||||
var needs_height_reset = false;
|
||||
if (this.clear_queued) {
|
||||
@ -276,14 +271,25 @@ define([
|
||||
}
|
||||
|
||||
var record_output = true;
|
||||
|
||||
if (json.output_type === 'execute_result') {
|
||||
this.append_execute_result(json);
|
||||
} else if (json.output_type === 'error') {
|
||||
this.append_error(json);
|
||||
} else if (json.output_type === 'stream') {
|
||||
// append_stream might have merged the output with earlier stream output
|
||||
record_output = this.append_stream(json);
|
||||
switch(json.output_type) {
|
||||
case 'execute_result':
|
||||
json = this.validate_mimebundle(json);
|
||||
this.append_execute_result(json);
|
||||
break;
|
||||
case 'stream':
|
||||
// append_stream might have merged the output with earlier stream output
|
||||
record_output = this.append_stream(json);
|
||||
break;
|
||||
case 'error':
|
||||
this.append_error(json);
|
||||
break;
|
||||
case 'display_data':
|
||||
// append handled below
|
||||
json = this.validate_mimebundle(json);
|
||||
break;
|
||||
default:
|
||||
console.log("unrecognized output type: " + json.output_type);
|
||||
this.append_unrecognized(json);
|
||||
}
|
||||
|
||||
// We must release the animation fixed height in a callback since Gecko
|
||||
@ -485,6 +491,23 @@ define([
|
||||
};
|
||||
|
||||
|
||||
OutputArea.prototype.append_unrecognized = function (json) {
|
||||
var that = this;
|
||||
var toinsert = this.create_output_area();
|
||||
var subarea = $('<div/>').addClass('output_subarea output_unrecognized');
|
||||
toinsert.append(subarea);
|
||||
subarea.append(
|
||||
$("<a>")
|
||||
.attr("href", "#")
|
||||
.text("Unrecognized output: " + json.output_type)
|
||||
.click(function () {
|
||||
that.events.trigger('unrecognized_output.OutputArea', {output: json})
|
||||
})
|
||||
);
|
||||
this._safe_append(toinsert);
|
||||
};
|
||||
|
||||
|
||||
OutputArea.prototype.append_display_data = function (json, handle_inserted) {
|
||||
var toinsert = this.create_output_area();
|
||||
if (this.append_mime_type(json, toinsert, handle_inserted)) {
|
||||
|
@ -338,7 +338,7 @@ define([
|
||||
var textcell = {
|
||||
TextCell: TextCell,
|
||||
MarkdownCell: MarkdownCell,
|
||||
RawCell: RawCell,
|
||||
RawCell: RawCell
|
||||
};
|
||||
return textcell;
|
||||
});
|
||||
|
@ -61,3 +61,34 @@ div.prompt:empty {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
div.unrecognized_cell {
|
||||
// from text_cell
|
||||
padding: 5px 5px 5px 0px;
|
||||
.hbox();
|
||||
|
||||
.inner_cell {
|
||||
.border-radius(@border-radius-base);
|
||||
padding: 5px;
|
||||
font-weight: bold;
|
||||
color: red;
|
||||
border: 1px solid @light_border_color;
|
||||
background: darken(@cell_background, 5%);
|
||||
// remove decoration from link
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
// remove prompt indentation on small screens
|
||||
div.unrecognized_cell > div.prompt {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
@ -172,3 +172,19 @@ input.raw_input:focus {
|
||||
p.p-space {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
div.output_unrecognized {
|
||||
padding: 5px;
|
||||
font-weight: bold;
|
||||
color: red;
|
||||
// remove decoration from link
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
51
IPython/html/static/style/ipython.min.css
vendored
51
IPython/html/static/style/ipython.min.css
vendored
@ -419,6 +419,44 @@ div.prompt:empty {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
div.unrecognized_cell {
|
||||
padding: 5px 5px 5px 0px;
|
||||
/* Old browsers */
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-align: stretch;
|
||||
display: -moz-box;
|
||||
-moz-box-orient: horizontal;
|
||||
-moz-box-align: stretch;
|
||||
display: box;
|
||||
box-orient: horizontal;
|
||||
box-align: stretch;
|
||||
/* Modern browsers */
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: stretch;
|
||||
}
|
||||
div.unrecognized_cell .inner_cell {
|
||||
border-radius: 4px;
|
||||
padding: 5px;
|
||||
font-weight: bold;
|
||||
color: red;
|
||||
border: 1px solid #cfcfcf;
|
||||
background: #eaeaea;
|
||||
}
|
||||
div.unrecognized_cell .inner_cell a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
div.unrecognized_cell .inner_cell a:hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
div.unrecognized_cell > div.prompt {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
/* any special styling for code cells that are currently running goes here */
|
||||
div.input {
|
||||
page-break-inside: avoid;
|
||||
@ -888,6 +926,19 @@ input.raw_input:focus {
|
||||
p.p-space {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
div.output_unrecognized {
|
||||
padding: 5px;
|
||||
font-weight: bold;
|
||||
color: red;
|
||||
}
|
||||
div.output_unrecognized a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
div.output_unrecognized a:hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
.rendered_html {
|
||||
color: #000000;
|
||||
/* any extras will just be numbers: */
|
||||
|
51
IPython/html/static/style/style.min.css
vendored
51
IPython/html/static/style/style.min.css
vendored
@ -8291,6 +8291,44 @@ div.prompt:empty {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
div.unrecognized_cell {
|
||||
padding: 5px 5px 5px 0px;
|
||||
/* Old browsers */
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-align: stretch;
|
||||
display: -moz-box;
|
||||
-moz-box-orient: horizontal;
|
||||
-moz-box-align: stretch;
|
||||
display: box;
|
||||
box-orient: horizontal;
|
||||
box-align: stretch;
|
||||
/* Modern browsers */
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: stretch;
|
||||
}
|
||||
div.unrecognized_cell .inner_cell {
|
||||
border-radius: 4px;
|
||||
padding: 5px;
|
||||
font-weight: bold;
|
||||
color: red;
|
||||
border: 1px solid #cfcfcf;
|
||||
background: #eaeaea;
|
||||
}
|
||||
div.unrecognized_cell .inner_cell a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
div.unrecognized_cell .inner_cell a:hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
div.unrecognized_cell > div.prompt {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
/* any special styling for code cells that are currently running goes here */
|
||||
div.input {
|
||||
page-break-inside: avoid;
|
||||
@ -8760,6 +8798,19 @@ input.raw_input:focus {
|
||||
p.p-space {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
div.output_unrecognized {
|
||||
padding: 5px;
|
||||
font-weight: bold;
|
||||
color: red;
|
||||
}
|
||||
div.output_unrecognized a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
div.output_unrecognized a:hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
.rendered_html {
|
||||
color: #000000;
|
||||
/* any extras will just be numbers: */
|
||||
|
Loading…
Reference in New Issue
Block a user