Skip to content

Commit 85770eb

Browse files
authored
Merge pull request #1003 from juhasch/fix/chrome-clipboard2
Update chrome-clipboard to 5.x
2 parents a9f8845 + 5e53823 commit 85770eb

File tree

3 files changed

+77
-100
lines changed

3 files changed

+77
-100
lines changed
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
Type: IPython Notebook Extension
22
Name: Chrome Clipboard
3-
Description: This extension allows using the system-wide clipboard to copy cells and images
3+
Description: This extension allows using the system-wide clipboard to paste images into a notebook
44
Link: readme.md
55
Icon: chrome.png
66
Main: main.js
7-
Compatibility: 4.x
7+
Compatibility: 4.x, 5.x
8+
Parameters:
9+
- name: dragdrop.subdirectory
10+
description: Subdirectory to put images to
11+
input_type: string
12+
default:

src/jupyter_contrib_nbextensions/nbextensions/chrome-clipboard/main.js

Lines changed: 63 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -5,56 +5,83 @@ define([
55
'base/js/namespace',
66
'jquery',
77
'base/js/utils',
8+
'services/config',
89
'base/js/events'
9-
], function(IPython, $, utils, events) {
10+
], function(IPython, $, utils, configmod, events) {
1011
"use strict";
1112
if (window.chrome === undefined) return;
1213

14+
var params = {
15+
subdirectory : '',
16+
};
17+
18+
var base_url = utils.get_body_data("baseUrl");
19+
var config = new configmod.ConfigSection('notebook', {base_url: base_url});
20+
1321
/* http://stackoverflow.com/questions/3231459/create-unique-id-with-javascript */
14-
function uniqueid() {
22+
function uniqueid(){
1523
// always start with a letter (for DOM friendlyness)
16-
var idstr = String.fromCharCode(Math.floor((Math.random() * 25) + 65));
24+
var idstr=String.fromCharCode(Math.floor((Math.random()*25)+65));
1725
do {
1826
// between numbers and characters (48 is 0 and 90 is Z (42-48 = 90)
19-
var ascicode = Math.floor((Math.random() * 42) + 48);
20-
if (ascicode < 58 || ascicode > 64) {
27+
var ascicode=Math.floor((Math.random()*42)+48);
28+
if (ascicode<58 || ascicode>64){
2129
// exclude all chars between : (58) and @ (64)
22-
idstr += String.fromCharCode(ascicode);
30+
idstr+=String.fromCharCode(ascicode);
2331
}
24-
} while (idstr.length < 32);
32+
} while (idstr.length<32);
2533

2634
return (idstr);
2735
}
2836

29-
var send_to_server = function (name, path, msg) {
37+
var create_dir = function(path) {
38+
var options = {type:'directory'};
39+
40+
var data = JSON.stringify({
41+
ext: options.ext,
42+
type: options.type
43+
});
44+
45+
var settings = {
46+
processData : false,
47+
type : "PUT",
48+
data: data,
49+
contentType: 'application/json',
50+
dataType : "json"
51+
};
52+
utils.promising_ajax(IPython.contents.api_url(path), settings);
53+
};
54+
55+
var send_to_server = function(name, msg) {
56+
var path = utils.url_path_join(utils.url_path_split(IPython.notebook.notebook_path)[0], params.subdirectory);
3057
if (name == '') {
3158
name = uniqueid() + '.' + msg.match(/data:image\/(\S+);/)[1];
32-
}
33-
var path = path.substring(0, path.lastIndexOf('/')) + '/';
34-
if (path === '/') path = '';
35-
var url = '//' + location.host + '/api/contents/' + path + name;
59+
}
60+
create_dir(path);
61+
var url = '//' + location.host + utils.url_path_join(base_url, 'api/contents', path, name);
62+
3663
var img = msg.replace(/(^\S+,)/, ''); // strip header
37-
var data = {'name': name, 'format': 'base64', 'content': img, 'type': 'file'};
64+
//console.log("send_to_server:", url, img);
65+
var data = {'name': name, 'format':'base64', 'content': img, 'type': 'file'};
3866
var settings = {
39-
processData: false,
40-
cache: false,
41-
type: "PUT",
42-
dataType: "json",
43-
data: JSON.stringify(data),
44-
headers: {'Content-Type': 'text/plain'},
45-
async: false,
46-
error : function() {console.log('Data transfer for copy-paste has failed.');
47-
}
67+
processData : false,
68+
cache : false,
69+
type : "PUT",
70+
dataType : "json",
71+
data : JSON.stringify(data),
72+
headers : {'Content-Type': 'text/plain'},
73+
async : false,
74+
error : function() {console.log('Data transfer for clipboard paste failed.'); }
4875
};
49-
utils.promising_ajax(url, settings).then(
76+
utils.promising_ajax(url, settings).then(
5077
function on_success (data, status, xhr) {
5178
var new_cell = IPython.notebook.insert_cell_below('markdown');
52-
var str = '<img src="' + name + '"/>';
79+
var str = '![](' + utils.url_path_join(params.subdirectory, name) + ')';
5380
new_cell.set_text(str);
5481
new_cell.execute();
5582
},
5683
function on_error (reason) {
57-
console.log('Data transfer for copy-paste has failed.');
84+
console.log('Data transfer for clipboard paste has failed.');
5885
});
5986
};
6087

@@ -63,6 +90,15 @@ define([
6390
*/
6491
var load_ipython_extension = function() {
6592

93+
config.load();
94+
config.loaded
95+
.then(function () {
96+
$.extend(true, params, config.data.dragdrop); // update params
97+
if (params.subdirectory) {
98+
console.log('subdir:', params.subdirectory)
99+
}
100+
})
101+
66102
/*
67103
* override clipboard 'paste' and insert new cell from json data in clipboard
68104
*/
@@ -71,84 +107,21 @@ define([
71107
if (cell.mode == "command") {
72108
var items = event.clipboardData.items;
73109
for (var i = 0; i < items.length; i++) {
74-
if (items[i].type == 'notebook-cell/json') {
75-
event.preventDefault();
76-
/* json data adds a new notebook cell */
77-
var data = event.clipboardData.getData('notebook-cell/json').split("\n").filter(Boolean);
78-
for (var i = 0; i < data.length; i++) {
79-
var ix = data.length - 1 - i;
80-
var new_cell_data = JSON.parse(data[ix]);
81-
var new_cell = IPython.notebook.insert_cell_below(new_cell_data.cell_type);
82-
new_cell.fromJSON(new_cell_data);
83-
if (new_cell.cell_type === "markdown") {
84-
new_cell.execute();
85-
};
86-
}
87-
} else if (items[i].type.indexOf('image/') !== -1) {
110+
if (items[i].type.indexOf('image/') !== -1) {
88111
event.preventDefault();
89112
/* images are transferred to the server as file and linked to */
90113
var blob = items[i].getAsFile();
91114
var reader = new FileReader();
92115
reader.onload = ( function (evt) {
93116
var filename = '';
94-
send_to_server(filename, IPython.notebook.notebook_path, evt.target.result);
117+
send_to_server(filename, evt.target.result);
95118
event.preventDefault();
96119
} );
97120
reader.readAsDataURL(blob);
98121
}
99122
}
100123
}
101124
});
102-
103-
/*
104-
* override clipboard 'copy' and copy current cell as json and text to clipboard
105-
*/
106-
window.addEventListener('copy', function (event) {
107-
var cell = IPython.notebook.get_selected_cell();
108-
if (cell.mode == "command") {
109-
var sel = window.getSelection();
110-
if (sel.type == "Range") return;
111-
/* default: copy marked text */
112-
event.preventDefault();
113-
var json = "";
114-
var text = "";
115-
var selected_cells = IPython.notebook.get_selected_cells();
116-
for (var i in selected_cells) {
117-
var j = selected_cells[i].toJSON();
118-
json += JSON.stringify(j) + '\n';
119-
text += selected_cells[i].code_mirror.getValue() + '\n';
120-
}
121-
/* copy cell as json and cell contents as text */
122-
event.clipboardData.setData('notebook-cell/json', json);
123-
event.clipboardData.setData("Text", text);
124-
}
125-
});
126-
127-
/*
128-
* override clipboard 'cut' and copy current cell as json and text to clipboard
129-
*/
130-
window.addEventListener('cut', function (event) {
131-
var cell = IPython.notebook.get_selected_cell();
132-
if (cell.mode == "command") {
133-
var sel = window.getSelection();
134-
if (sel.type == "Range") return;
135-
/* default: copy marked text */
136-
event.preventDefault();
137-
var json = "";
138-
var text = "";
139-
var selected_cells = IPython.notebook.get_selected_cells();
140-
for (var i in selected_cells) {
141-
var j = selected_cells[i].toJSON();
142-
json += JSON.stringify(j) + '\n';
143-
text += selected_cells[i].code_mirror.getValue() + '\n';
144-
IPython.notebook.delete_cell(IPython.notebook.find_cell_index(selected_cells[i]));
145-
}
146-
/* copy cell as json and cell contents as text */
147-
event.clipboardData.setData('notebook-cell/json', json);
148-
event.clipboardData.setData("Text", text);
149-
}
150-
});
151-
152125
};
153126

154127
var extension = {

src/jupyter_contrib_nbextensions/nbextensions/chrome-clipboard/readme.md

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@ Chrome Clipboard
33

44
**Note**: Improved copy&paste functionality is now integrated in the main Jupyter notebook
55

6-
This notebook extension adds system clipboard actions for single or multiple cells.
7-
It allows cut/copy/paste operation of notebook cells and images. Images will be saved to the directory where the
8-
current notebook sits. There is currently no way to embed images in markdown cells, due to the google-caja sanitizer
9-
used to prevent malicous code execution. Multi-cell operation is possible with the latest Jupyter version, or using the `rubberband` extension in this repository.
6+
This notebook extension adds system clipboard actions pasting images.
107

118
A demo showing single-cell copy & paste operating in Chrome is available on youtube:
129
[youtu.be/iU9dNe4vMUY](http://youtu.be/iU9dNe4vMUY)
@@ -18,12 +15,14 @@ A demo showing single-cell copy & paste operating in Chrome is available on yout
1815

1916
Hotkeys:
2017

21-
* `CTRL+C` - Copy cell to system clipboard
22-
* `CTRL+X` - Cut cell and copy to system clipboard
23-
* `CTRL+V` - Paste cell or image from system clipboard
18+
* `CTRL+V` - Paste image from system clipboard
2419

20+
You can specify a target subdirectory using the `dragdrop.subdirectory`
21+
parameter in the notebook configurator. This is the same subdirectory
22+
as used in the `dragdrop` extension.
2523

2624
Internals
2725
---------
2826

29-
Regarding copying notebook cells over the clipboard, they are stored as mime-type `notebook-cell/json`.
27+
The image pasted from clipboard will be uploaded to the notebook
28+
directory. A unique ID will be generated as image filename.

0 commit comments

Comments
 (0)