diff --git a/IPython/html/static/notebook/js/cell.js b/IPython/html/static/notebook/js/cell.js index 9e2aac1..26ecbd2 100644 --- a/IPython/html/static/notebook/js/cell.js +++ b/IPython/html/static/notebook/js/cell.js @@ -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 @@ -255,6 +257,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 * @return is the action being taken @@ -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,61 @@ 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').text("Unrecognized cell type: " + data.cell_type); + }; + + UnrecognizedCell.prototype.create_element = function () { + Cell.prototype.create_element.apply(this, arguments); + var cell = this.element = $("
").addClass('cell unrecognized_cell'); + cell.attr('tabindex','2'); + + var prompt = $('
').addClass('prompt input_prompt'); + cell.append(prompt); + var inner_cell = $('
').addClass('inner_cell'); + inner_cell.text("Unrecognized cell type"); + cell.append(inner_cell); + this.element = cell; + }; + // Backwards compatibility. IPython.Cell = Cell; - return {'Cell': Cell}; + return { + Cell: Cell, + UnrecognizedCell: UnrecognizedCell + }; }); diff --git a/IPython/html/static/notebook/js/notebook.js b/IPython/html/static/notebook/js/notebook.js index 5bd4315..9bb3b00 100644 --- a/IPython/html/static/notebook/js/notebook.js +++ b/IPython/html/static/notebook/js/notebook.js @@ -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, @@ -894,7 +896,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)) { diff --git a/IPython/html/static/notebook/js/outputarea.js b/IPython/html/static/notebook/js/outputarea.js index ae56b94..55bac95 100644 --- a/IPython/html/static/notebook/js/outputarea.js +++ b/IPython/html/static/notebook/js/outputarea.js @@ -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,26 @@ 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); + console.log("appending", 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 @@ -482,6 +489,15 @@ define([ }; + OutputArea.prototype.append_unrecognized = function (json) { + var toinsert = this.create_output_area(); + var subarea = $('
').addClass('output_subarea output_unrecognized'); + toinsert.append(subarea); + subarea.text("Unrecognized output: " + json.output_type); + 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)) { diff --git a/IPython/html/static/notebook/js/textcell.js b/IPython/html/static/notebook/js/textcell.js index 24bd1e4..fb466b7 100644 --- a/IPython/html/static/notebook/js/textcell.js +++ b/IPython/html/static/notebook/js/textcell.js @@ -340,7 +340,7 @@ define([ var textcell = { TextCell: TextCell, MarkdownCell: MarkdownCell, - RawCell: RawCell, + RawCell: RawCell }; return textcell; }); diff --git a/IPython/html/static/notebook/less/cell.less b/IPython/html/static/notebook/less/cell.less index 8bf3f85..1a5c541 100644 --- a/IPython/html/static/notebook/less/cell.less +++ b/IPython/html/static/notebook/less/cell.less @@ -61,3 +61,24 @@ 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%); + } +} +@media (max-width: 480px) { + // remove prompt indentation on small screens + div.unrecognized_cell > div.prompt { + display: none; + } +} diff --git a/IPython/html/static/notebook/less/outputarea.less b/IPython/html/static/notebook/less/outputarea.less index 033359b..a9f15ed 100644 --- a/IPython/html/static/notebook/less/outputarea.less +++ b/IPython/html/static/notebook/less/outputarea.less @@ -172,3 +172,9 @@ input.raw_input:focus { p.p-space { margin-bottom: 10px; } + +div.output_unrecognized { + padding: 5px; + font-weight: bold; + color: red; +} \ No newline at end of file diff --git a/IPython/html/static/style/ipython.min.css b/IPython/html/static/style/ipython.min.css index 09e2df2..0acc29b 100644 --- a/IPython/html/static/style/ipython.min.css +++ b/IPython/html/static/style/ipython.min.css @@ -419,6 +419,36 @@ 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; +} +@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 +918,12 @@ input.raw_input:focus { p.p-space { margin-bottom: 10px; } +div.output_unrecognized { + border-radius: 4px; + padding: 5px; + font-weight: bold; + color: red; +} .rendered_html { color: #000000; /* any extras will just be numbers: */ diff --git a/IPython/html/static/style/style.min.css b/IPython/html/static/style/style.min.css index 2430e1f..f0b94db 100644 --- a/IPython/html/static/style/style.min.css +++ b/IPython/html/static/style/style.min.css @@ -8288,6 +8288,36 @@ 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; +} +@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; @@ -8757,6 +8787,12 @@ input.raw_input:focus { p.p-space { margin-bottom: 10px; } +div.output_unrecognized { + border-radius: 4px; + padding: 5px; + font-weight: bold; + color: red; +} .rendered_html { color: #000000; /* any extras will just be numbers: */