From 7b974946ffc21d94dc65a4654b3d325fdbec8411 Mon Sep 17 00:00:00 2001 From: Julien Rebetez Date: Fri, 11 Mar 2016 20:17:34 +0100 Subject: [PATCH 1/5] Add a visual indicator that a drop is possible when dragging an image on a markdown cells --- bower.json | 2 +- notebook/static/notebook/js/textcell.js | 23 +++++++++++++++++++++ notebook/static/notebook/less/textcell.less | 4 ++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/bower.json b/bower.json index 114b4ab1a..82b552ec7 100644 --- a/bower.json +++ b/bower.json @@ -5,7 +5,7 @@ "backbone": "components/backbone#~1.2", "bootstrap": "components/bootstrap#~3.3", "bootstrap-tour": "0.9.0", - "codemirror": "~5.8", + "codemirror": "julienr/CodeMirror#fix_dragleave", "es6-promise": "~1.0", "font-awesome": "components/font-awesome#~4.2.0", "google-caja": "5669", diff --git a/notebook/static/notebook/js/textcell.js b/notebook/static/notebook/js/textcell.js index c6772b9fc..b9b376a24 100644 --- a/notebook/static/notebook/js/textcell.js +++ b/notebook/static/notebook/js/textcell.js @@ -110,6 +110,7 @@ define([ inner_cell.append(input_area).append(render_area); cell.append(inner_cell); this.element = cell; + this.inner_cell = inner_cell; }; @@ -282,6 +283,9 @@ define([ TextCell.apply(this, [$.extend({}, options, {config: config})]); this.cell_type = 'markdown'; + + // Used to keep track of drag events + this.drag_counter = 0; }; MarkdownCell.options_default = { @@ -461,7 +465,26 @@ define([ return true; }); + // We want to display a visual indicator that the drop is possible. + // The dragleave event is fired when we hover a child element (which + // is often immediatly after we got the dragenter), so we keep track + // of the number of dragenter/dragleave we got, as discussed here : + // http://stackoverflow.com/q/7110353/116067 + this.code_mirror.on("dragenter", function(cm, evt) { + that.drag_counter++; + that.inner_cell.addClass('droppable'); + evt.preventDefault(); + }); + + this.code_mirror.on("dragleave", function(cm, evt) { + that.drag_counter--; + if (that.drag_counter === 0) { + that.inner_cell.removeClass('droppable'); + } + }); + this.code_mirror.on("drop", function(cm, evt) { + that.inner_cell.removeClass('droppable'); var files = evt.dataTransfer.files; for (var i = 0; i < files.length; ++i) { var file = files[i]; diff --git a/notebook/static/notebook/less/textcell.less b/notebook/static/notebook/less/textcell.less index 6e3f6ee85..d7e355bad 100644 --- a/notebook/static/notebook/less/textcell.less +++ b/notebook/static/notebook/less/textcell.less @@ -48,6 +48,10 @@ h1,h2,h3,h4,h5,h6 { display:none; } +.text_cell .droppable{ + border: 1px solid #ff0000; +} + .cm-header-1, .cm-header-2, .cm-header-3, From 180ef74ff542656d8cc345cae6228c2a6b3419bc Mon Sep 17 00:00:00 2001 From: Julien Rebetez Date: Fri, 15 Apr 2016 22:51:04 +0200 Subject: [PATCH 2/5] Clear the dropzone indicator on cell render. Change the dropzone CSS effect to be on the input_area --- bower.json | 2 +- notebook/static/notebook/js/textcell.js | 29 +++++++++++++++------ notebook/static/notebook/less/textcell.less | 5 ++-- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/bower.json b/bower.json index 82b552ec7..201fcdcce 100644 --- a/bower.json +++ b/bower.json @@ -5,7 +5,7 @@ "backbone": "components/backbone#~1.2", "bootstrap": "components/bootstrap#~3.3", "bootstrap-tour": "0.9.0", - "codemirror": "julienr/CodeMirror#fix_dragleave", + "codemirror": "codemirror/CodeMirror#master", "es6-promise": "~1.0", "font-awesome": "components/font-awesome#~4.2.0", "google-caja": "5669", diff --git a/notebook/static/notebook/js/textcell.js b/notebook/static/notebook/js/textcell.js index b9b376a24..259453e6c 100644 --- a/notebook/static/notebook/js/textcell.js +++ b/notebook/static/notebook/js/textcell.js @@ -367,6 +367,11 @@ define([ * @method render */ MarkdownCell.prototype.render = function () { + // We clear the dropzone here just in case the dragenter/leave + // logic of bind_events wasn't 100% successful. + this.drag_counter = 0; + this.inner_cell.removeClass('dropzone'); + var cont = TextCell.prototype.render.apply(this); if (cont) { var that = this; @@ -465,26 +470,34 @@ define([ return true; }); + // We want to display a visual indicator that the drop is possible. // The dragleave event is fired when we hover a child element (which // is often immediatly after we got the dragenter), so we keep track // of the number of dragenter/dragleave we got, as discussed here : // http://stackoverflow.com/q/7110353/116067 + // This doesn't seem to be 100% reliable, so we clear the dropzone + // class when the cell is rendered as well this.code_mirror.on("dragenter", function(cm, evt) { - that.drag_counter++; - that.inner_cell.addClass('droppable'); - evt.preventDefault(); + that.drag_counter++; + that.inner_cell.addClass('dropzone'); + // prevent default to allow drop + evt.stopPropagation(); + evt.preventDefault(); }); this.code_mirror.on("dragleave", function(cm, evt) { - that.drag_counter--; - if (that.drag_counter === 0) { - that.inner_cell.removeClass('droppable'); - } + that.drag_counter--; + if (that.drag_counter === 0) { + that.inner_cell.removeClass('dropzone'); + } + evt.stopPropagation(); + evt.preventDefault(); }); this.code_mirror.on("drop", function(cm, evt) { - that.inner_cell.removeClass('droppable'); + that.drag_counter = 0; + that.inner_cell.removeClass('dropzone'); var files = evt.dataTransfer.files; for (var i = 0; i < files.length; ++i) { var file = files[i]; diff --git a/notebook/static/notebook/less/textcell.less b/notebook/static/notebook/less/textcell.less index d7e355bad..0c5450092 100644 --- a/notebook/static/notebook/less/textcell.less +++ b/notebook/static/notebook/less/textcell.less @@ -48,8 +48,9 @@ h1,h2,h3,h4,h5,h6 { display:none; } -.text_cell .droppable{ - border: 1px solid #ff0000; +.text_cell .dropzone .input_area { + border-color: #FCFF1E; + background-color: #FCFFE3; } .cm-header-1, From 14f7c2ccc04630f5db9788ef5c911ffe351cf792 Mon Sep 17 00:00:00 2001 From: Julien Rebetez Date: Sat, 23 Apr 2016 10:27:53 +0200 Subject: [PATCH 3/5] Better handling of dnd events to correctly remove the dropzone effect when escape is pressed. --- notebook/static/base/js/utils.js | 17 ++++++++++++++ notebook/static/notebook/js/textcell.js | 30 ++++++++++++------------- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/notebook/static/base/js/utils.js b/notebook/static/base/js/utils.js index 49178cfd4..cf9ed588a 100644 --- a/notebook/static/base/js/utils.js +++ b/notebook/static/base/js/utils.js @@ -946,6 +946,22 @@ define([ } }; + // Test if a drag'n'drop event contains a file (as opposed to an HTML + // element/text from the document) + var dnd_contain_file = function(event) { + // As per the HTML5 drag'n'drop spec, the dataTransfer.types should + // contain one "Files" type if a file is being dragged + // https://www.w3.org/TR/2011/WD-html5-20110113/dnd.html#dom-datatransfer-types + if (event.dataTransfer.types) { + for (var i = 0; i < event.dataTransfer.types.length; i++) { + if (event.dataTransfer.types[i] == "Files") { + return true; + } + } + } + return false; + }; + var utils = { is_loaded: is_loaded, load_extension: load_extension, @@ -990,6 +1006,7 @@ define([ time: time, format_datetime: format_datetime, datetime_sort_helper: datetime_sort_helper, + dnd_contain_file: dnd_contain_file, _ansispan:_ansispan }; diff --git a/notebook/static/notebook/js/textcell.js b/notebook/static/notebook/js/textcell.js index 259453e6c..64d613710 100644 --- a/notebook/static/notebook/js/textcell.js +++ b/notebook/static/notebook/js/textcell.js @@ -458,19 +458,15 @@ define([ } }); - // Allow drop event if the dragged file can be used as an attachment - this.code_mirror.on("dragstart", function(cm, evt) { - var files = evt.dataTransfer.files; - for (var i = 0; i < files.length; ++i) { - var file = files[i]; - if (attachment_regex.test(file.type)) { - return false; - } + // Allow drag event if the dragged file can be used as an attachment + // If we use this.code_mirror.on to register a "dragover" handler, we + // get an empty dataTransfer + this.code_mirror.on("dragover", function(cm, evt) { + if (utils.dnd_contain_file(evt)) { + evt.preventDefault(); } - return true; }); - // We want to display a visual indicator that the drop is possible. // The dragleave event is fired when we hover a child element (which // is often immediatly after we got the dragenter), so we keep track @@ -479,25 +475,27 @@ define([ // This doesn't seem to be 100% reliable, so we clear the dropzone // class when the cell is rendered as well this.code_mirror.on("dragenter", function(cm, evt) { - that.drag_counter++; - that.inner_cell.addClass('dropzone'); - // prevent default to allow drop - evt.stopPropagation(); + if (utils.dnd_contain_file(evt)) { + that.drag_counter++; + that.inner_cell.addClass('dropzone'); + } evt.preventDefault(); + evt.stopPropagation(); }); this.code_mirror.on("dragleave", function(cm, evt) { that.drag_counter--; - if (that.drag_counter === 0) { + if (that.drag_counter <= 0) { that.inner_cell.removeClass('dropzone'); } - evt.stopPropagation(); evt.preventDefault(); + evt.stopPropagation(); }); this.code_mirror.on("drop", function(cm, evt) { that.drag_counter = 0; that.inner_cell.removeClass('dropzone'); + var files = evt.dataTransfer.files; for (var i = 0; i < files.length; ++i) { var file = files[i]; From 65f1fae5ecf2527f6598b81eb664910d7690170d Mon Sep 17 00:00:00 2001 From: Julien Rebetez Date: Sat, 23 Apr 2016 10:28:26 +0200 Subject: [PATCH 4/5] Use a gray dashed border instead of yellow background to indicate dropzone --- notebook/static/notebook/less/textcell.less | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/notebook/static/notebook/less/textcell.less b/notebook/static/notebook/less/textcell.less index 0c5450092..3f49e8b24 100644 --- a/notebook/static/notebook/less/textcell.less +++ b/notebook/static/notebook/less/textcell.less @@ -49,8 +49,8 @@ h1,h2,h3,h4,h5,h6 { } .text_cell .dropzone .input_area { - border-color: #FCFF1E; - background-color: #FCFFE3; + border: 2px dashed #bababa; + margin: -1px; } .cm-header-1, From ac373f46fe81d2a3f2bedc5bc9daf8e609568531 Mon Sep 17 00:00:00 2001 From: Julien Rebetez Date: Sun, 24 Apr 2016 17:31:20 +0200 Subject: [PATCH 5/5] Bump codemirror version to 5.14, which includes the fix for the dragleave event. --- bower.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bower.json b/bower.json index 201fcdcce..ae39400c5 100644 --- a/bower.json +++ b/bower.json @@ -5,7 +5,7 @@ "backbone": "components/backbone#~1.2", "bootstrap": "components/bootstrap#~3.3", "bootstrap-tour": "0.9.0", - "codemirror": "codemirror/CodeMirror#master", + "codemirror": "~5.14", "es6-promise": "~1.0", "font-awesome": "components/font-awesome#~4.2.0", "google-caja": "5669",