diff --git a/notebook/static/base/js/dialog.js b/notebook/static/base/js/dialog.js
index 02c113597..8492c431c 100644
--- a/notebook/static/base/js/dialog.js
+++ b/notebook/static/base/js/dialog.js
@@ -80,6 +80,9 @@ define(function(require) {
.addClass("btn btn-default btn-sm")
.attr("data-dismiss", "modal")
.text(label);
+ if (btn_opts.id) {
+ button.attr('id', btn_opts.id);
+ }
if (btn_opts.click) {
button.click($.proxy(btn_opts.click, dialog_content));
}
@@ -269,12 +272,58 @@ define(function(require) {
modal_obj.on('shown.bs.modal', function(){ editor.refresh(); });
};
+ var insert_image = function (options) {
+ var message =
+ "Select a file to insert.";
+ var file_input = $('')
+ .attr('type', 'file')
+ .attr('accept', 'image/*')
+ .attr('name', 'file')
+ .on('change', function(file) {
+ var $btn = $(modal_obj).find('#btn_ok');
+ if (this.files.length > 0) {
+ $btn.removeClass('disabled');
+ } else {
+ $btn.addClass('disabled');
+ }
+ });
+ var dialogform = $('
').attr('title', 'Edit attachments')
+ .append(
+ $('').append(
+ $('').append(
+ $('')
+ .attr('for','file')
+ .text(message)
+ )
+ .append($('
'))
+ .append(file_input)
+ )
+ );
+ var modal_obj = modal({
+ title: "Pick a file",
+ body: dialogform,
+ buttons: {
+ OK: {
+ id : 'btn_ok',
+ class : "btn-primary disabled",
+ click: function() {
+ options.callback(file_input[0].files[0]);
+ }
+ },
+ Cancel: {}
+ },
+ notebook: options.notebook,
+ keyboard_manager: options.keyboard_manager,
+ });
+ };
+
var dialog = {
modal : modal,
kernel_modal : kernel_modal,
edit_metadata : edit_metadata,
- edit_attachments : edit_attachments
+ edit_attachments : edit_attachments,
+ insert_image : insert_image
};
return dialog;
diff --git a/notebook/static/notebook/js/actions.js b/notebook/static/notebook/js/actions.js
index 152b6fbfc..682c8d0da 100644
--- a/notebook/static/notebook/js/actions.js
+++ b/notebook/static/notebook/js/actions.js
@@ -153,6 +153,13 @@ define(function(require){
env.notebook.command_mode();
}
},
+ 'insert-image': {
+ help : 'insert image',
+ help_index : 'dz',
+ handler : function (env) {
+ env.notebook.insert_image();
+ }
+ },
'split-cell-at-cursor': {
help : 'split cell',
help_index : 'ea',
diff --git a/notebook/static/notebook/js/menubar.js b/notebook/static/notebook/js/menubar.js
index 32ca35238..94912c943 100644
--- a/notebook/static/notebook/js/menubar.js
+++ b/notebook/static/notebook/js/menubar.js
@@ -228,6 +228,7 @@ define([
'#toggle_all_output': 'toggle-all-cells-output-collapsed',
'#toggle_all_output_scroll': 'toggle-all-cells-output-scrolled',
'#clear_all_output': 'clear-all-cells-output',
+ '#insert_image': 'insert-image',
};
for(var idx in id_actions_dict){
diff --git a/notebook/static/notebook/js/notebook.js b/notebook/static/notebook/js/notebook.js
index a37e83e11..1c0d80d4a 100644
--- a/notebook/static/notebook/js/notebook.js
+++ b/notebook/static/notebook/js/notebook.js
@@ -1673,6 +1673,46 @@ define(function (require) {
this.merge_cells([index, index+1], false);
};
+ // Image insertion
+
+ /**
+ * Shows a dialog letting the user pick an image from her computer and
+ * insert it into the edited markdown cell
+ */
+ Notebook.prototype.insert_image = function () {
+ var that = this;
+ var cell = this.get_selected_cell();
+ // The following should not happen as the menu item is greyed out
+ // when those conditions are not fullfilled (see MarkdownCell
+ // unselect/select/unrender handlers)
+ if (cell.cell_type != 'markdown') {
+ console.log('Error: insert_image called on non-markdown cell');
+ return;
+ }
+ if (cell.rendered) {
+ console.log('Error: insert_image called on rendered cell');
+ return;
+ }
+ dialog.insert_image({
+ callback: function(file) {
+ cell.edit_mode();
+ cell.insert_inline_image_from_blob(file);
+ },
+ notebook: this,
+ keyboard_manager: this.keyboard_manager
+ });
+ };
+
+ /**
+ * Enable/disable the "Insert image" menu item
+ */
+ Notebook.prototype.set_insert_image_enabled = function(enabled) {
+ if (enabled) {
+ $('#insert_image').removeClass('disabled');
+ } else {
+ $('#insert_image').addClass('disabled');
+ }
+ };
// Cell collapsing and output clearing
diff --git a/notebook/static/notebook/js/textcell.js b/notebook/static/notebook/js/textcell.js
index 351fb7855..516c8d4ae 100644
--- a/notebook/static/notebook/js/textcell.js
+++ b/notebook/static/notebook/js/textcell.js
@@ -51,6 +51,7 @@ define([
this.notebook = options.notebook;
this.events = options.events;
this.config = options.config;
+ 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);
@@ -256,6 +257,24 @@ define([
}
};
+ MarkdownCell.prototype.unselect = function () {
+ var cont = TextCell.prototype.unselect.apply(this);
+ this.notebook.set_insert_image_enabled(false);
+ };
+
+ MarkdownCell.prototype.select = function () {
+ var cont = TextCell.prototype.select.apply(this);
+ if (cont) {
+ this.notebook.set_insert_image_enabled(!this.rendered);
+ }
+ };
+
+ MarkdownCell.prototype.unrender = function () {
+ var cont = TextCell.prototype.unrender.apply(this);
+ this.notebook.set_insert_image_enabled(true);
+ };
+
+
// TODO(julienr): Move to cell if the attachments is accepted as a cell
// attribute (not markdown specific)
MarkdownCell.prototype.add_attachment = function (key, mime_type, b64_data) {
diff --git a/notebook/templates/notebook.html b/notebook/templates/notebook.html
index 31fd510f6..efa614b2c 100644
--- a/notebook/templates/notebook.html
+++ b/notebook/templates/notebook.html
@@ -143,6 +143,8 @@ data-notebook-path="{{notebook_path | urlencode}}"
Edit Notebook Metadata
Find and Replace
+
+ Insert Image
View