From 0e5047e75daae30b2ed2c31b4734e6ba191ebb30 Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 12 Sep 2016 14:42:48 +0200 Subject: [PATCH 1/4] allow returning full class config data, merged with defaults and merge object config values with defaults (e.g. Cell.cm_config) --- notebook/static/services/config.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/notebook/static/services/config.js b/notebook/static/services/config.js index 9c5d7dda8..822306d9f 100644 --- a/notebook/static/services/config.js +++ b/notebook/static/services/config.js @@ -102,7 +102,21 @@ function(utils) { */ ConfigWithDefaults.prototype.get_sync = function(key) { var data = this._class_data(); - return key in data ? data[key] : this.defaults[key]; + if (key === undefined) { + // no key specified, return full config data + return $.extend(true, {}, this.defaults, data); + } + + var value = data[key]; + if (value !== undefined) { + if (typeof value == 'object') { + // merge with defaults if it's an object + return $.extend(true, {}, this.defaults[key], value); + } else { + return value; + } + } + return this.defaults[key]; }; /** From d52e1e24199ca753f8cbf34c8e0d0fbff4ca0b6c Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 12 Sep 2016 15:05:12 +0200 Subject: [PATCH 2/4] Restore loading of options_default in text cells fixes omitted codemirror config due to ignoring options_default. load options_default via config defaults (modifying options_default at runtime has no effect). --- notebook/static/notebook/js/cell.js | 25 ++++++++++---------- notebook/static/notebook/js/codecell.js | 4 +--- notebook/static/notebook/js/textcell.js | 18 +++++--------- notebook/tests/notebook/dualmode_cellmode.js | 10 ++++++++ 4 files changed, 30 insertions(+), 27 deletions(-) diff --git a/notebook/static/notebook/js/cell.js b/notebook/static/notebook/js/cell.js index 9b6379a68..eceda62a1 100644 --- a/notebook/static/notebook/js/cell.js +++ b/notebook/static/notebook/js/cell.js @@ -49,10 +49,9 @@ define([ options = options || {}; this.keyboard_manager = options.keyboard_manager; this.events = options.events; - var config = utils.mergeopt(Cell, options.config); + var config = options.config; // superclass default overwrite our default - this.placeholder = config.placeholder || ''; this.selected = false; this.anchor = false; this.rendered = false; @@ -83,19 +82,21 @@ define([ // load this from metadata later ? this.user_highlight = 'auto'; - - var _local_cm_config = {}; - if(this.class_config){ - _local_cm_config = this.class_config.get_sync('cm_config'); + // merge my class-specific config data with general cell-level config + var class_config_data = {}; + if (this.class_config) { + class_config_data = this.class_config.get_sync(); } - - var local = new configmod.ConfigWithDefaults(options.config, - {}, 'Cell'); - var llcm = local.get_sync('cm_config'); - config.cm_config = utils.mergeopt({}, config.cm_config, utils.mergeopt({}, llcm, _local_cm_config)); + var cell_config = new configmod.ConfigWithDefaults(options.config, + Cell.options_default, 'Cell'); + var cell_config_data = cell_config.get_sync(); + + // this._options is a merge of SomeCell and Cell config data: + this._options = utils.mergeopt({}, cell_config_data, class_config_data); + this.placeholder = this._options.placeholder || ''; + this.cell_id = utils.uuid(); - this._options = config; // For JS VM engines optimization, attributes should be all set (even // to null) in the constructor, and if possible, if different subclass diff --git a/notebook/static/notebook/js/codecell.js b/notebook/static/notebook/js/codecell.js index ef69791c1..11e6a087e 100644 --- a/notebook/static/notebook/js/codecell.js +++ b/notebook/static/notebook/js/codecell.js @@ -96,7 +96,7 @@ define([ this.tooltip = options.tooltip; this.config = options.config; this.class_config = new configmod.ConfigWithDefaults(this.config, - CodeCell.config_defaults, 'CodeCell'); + CodeCell.options_default, 'CodeCell'); // create all attributed in constructor function // even if null for V8 VM optimisation @@ -141,8 +141,6 @@ define([ }, }; - CodeCell.config_defaults = CodeCell.options_default; - CodeCell.msg_cells = {}; CodeCell.prototype = Object.create(Cell.prototype); diff --git a/notebook/static/notebook/js/textcell.js b/notebook/static/notebook/js/textcell.js index 9ba54b4ae..7900a9783 100644 --- a/notebook/static/notebook/js/textcell.js +++ b/notebook/static/notebook/js/textcell.js @@ -279,9 +279,8 @@ define([ * notebook: Notebook instance */ options = options || {}; - var config = utils.mergeopt(MarkdownCell, {}); this.class_config = new configmod.ConfigWithDefaults(options.config, - {}, 'MarkdownCell'); + MarkdownCell.options_default, 'MarkdownCell'); TextCell.apply(this, [$.extend({}, options, {config: options.config})]); this.cell_type = 'markdown'; @@ -527,24 +526,19 @@ define([ * notebook: Notebook instance */ options = options || {}; - var config = utils.mergeopt(RawCell, {}); - TextCell.apply(this, [$.extend({}, options, {config: options.config})]); - this.class_config = new configmod.ConfigWithDefaults(options.config, - RawCell.config_defaults, 'RawCell'); + RawCell.options_default, 'RawCell'); + TextCell.apply(this, [$.extend({}, options, {config: options.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.config_defaults = { highlight_modes : { 'diff' :{'reg':[/^diff/]} }, + 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); diff --git a/notebook/tests/notebook/dualmode_cellmode.js b/notebook/tests/notebook/dualmode_cellmode.js index 3701792d3..459d18a74 100644 --- a/notebook/tests/notebook/dualmode_cellmode.js +++ b/notebook/tests/notebook/dualmode_cellmode.js @@ -2,17 +2,26 @@ // Test casper.notebook_test(function () { + function get_cell_cm_mode(index) { + return casper.evaluate(function (index) { + return Jupyter.notebook.get_cell(index).code_mirror.getMode().name; + }, {index: index}); + } + this.then(function () { // Cell mode change + var that = this; var index = 0; this.select_cell(index); var a = 'hello\nmulti\nline'; this.set_cell_text(index, a); this.trigger_keydown('esc','r'); this.test.assertEquals(this.get_cell(index).cell_type, 'raw', 'r; cell is raw'); + this.test.assertEquals(get_cell_cm_mode(index), 'null', 'raw cell codemirror mode is null'); this.trigger_keydown('1'); this.test.assertEquals(this.get_cell(index).cell_type, 'markdown', '1; cell is markdown'); this.test.assertEquals(this.get_cell_text(index), '# ' + a, '1; markdown heading'); + this.test.assertEquals(get_cell_cm_mode(index), 'ipythongfm', 'codemirror cell mode is ipythongfm'); this.trigger_keydown('2'); this.test.assertEquals(this.get_cell(index).cell_type, 'markdown', '2; cell is markdown'); this.test.assertEquals(this.get_cell_text(index), '## ' + a, '2; markdown heading'); @@ -34,6 +43,7 @@ casper.notebook_test(function () { this.trigger_keydown('y'); this.test.assertEquals(this.get_cell(index).cell_type, 'code', 'y; cell is code'); this.test.assertEquals(this.get_cell_text(index), '###### ' + a, 'y; still has hashes'); + this.test.assertEquals(get_cell_cm_mode(index), 'ipython', 'code cell mode is ipython'); this.trigger_keydown('1'); this.test.assertEquals(this.get_cell(index).cell_type, 'markdown', '1; cell is markdown'); this.test.assertEquals(this.get_cell_text(index), '# ' + a, '1; markdown heading'); From f1fc424b1980689fea1d75e270beb31af478939d Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 12 Sep 2016 15:06:01 +0200 Subject: [PATCH 3/4] add async workaround for slow load of ipythongfm definition if ipythongfm is defined after notebook is loaded, re-load it in all cells that are using it. --- .../static/notebook/js/codemirror-ipythongfm.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/notebook/static/notebook/js/codemirror-ipythongfm.js b/notebook/static/notebook/js/codemirror-ipythongfm.js index 293d17dca..f840964e2 100644 --- a/notebook/static/notebook/js/codemirror-ipythongfm.js +++ b/notebook/static/notebook/js/codemirror-ipythongfm.js @@ -55,5 +55,16 @@ }, 'gfm'); CodeMirror.defineMIME("text/x-ipythongfm", "ipythongfm"); + + // async workaround: + // Cells may be loaded before this mode is defined. + // If that happens, trigger re-load of the mode: + if (Jupyter && Jupyter.notebook) { + Jupyter.notebook.get_cells().map(function (cell) { + if (cell.code_mirror && cell.code_mirror.getOption('mode') === 'ipythongfm') { + cell.code_mirror.setOption('mode', 'ipythongfm'); + } + }); + } }); -}) +}); From 460d3027cedcfcaee4159b5aac94fa5e4cc73ba3 Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 12 Sep 2016 15:18:12 +0200 Subject: [PATCH 4/4] merge TextCell options_default into MarkdownCell, RawCell --- notebook/static/notebook/js/textcell.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/notebook/static/notebook/js/textcell.js b/notebook/static/notebook/js/textcell.js index 7900a9783..fdb7e48ce 100644 --- a/notebook/static/notebook/js/textcell.js +++ b/notebook/static/notebook/js/textcell.js @@ -56,7 +56,6 @@ define([ this.notebook = options.notebook; // we cannot put this as a class key as it has handle to "this". - var config = utils.mergeopt(TextCell, this.config); Cell.apply(this, [{ config: options.config, keyboard_manager: options.keyboard_manager, @@ -279,8 +278,9 @@ define([ * notebook: Notebook instance */ options = options || {}; + var config_default = utils.mergeopt(TextCell, MarkdownCell.options_default); this.class_config = new configmod.ConfigWithDefaults(options.config, - MarkdownCell.options_default, 'MarkdownCell'); + config_default, 'MarkdownCell'); TextCell.apply(this, [$.extend({}, options, {config: options.config})]); this.cell_type = 'markdown'; @@ -526,8 +526,9 @@ define([ * notebook: Notebook instance */ options = options || {}; + var config_default = utils.mergeopt(TextCell, RawCell.options_default); this.class_config = new configmod.ConfigWithDefaults(options.config, - RawCell.options_default, 'RawCell'); + config_default, 'RawCell'); TextCell.apply(this, [$.extend({}, options, {config: options.config})]); this.cell_type = 'raw'; };