Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update chrome-clipboard to 5.x #1003

Merged
merged 1 commit into from
Jun 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
Type: IPython Notebook Extension
Name: Chrome Clipboard
Description: This extension allows using the system-wide clipboard to copy cells and images
Description: This extension allows using the system-wide clipboard to paste images into a notebook
Link: readme.md
Icon: chrome.png
Main: main.js
Compatibility: 4.x
Compatibility: 4.x, 5.x
Parameters:
- name: dragdrop.subdirectory
description: Subdirectory to put images to
input_type: string
default:
153 changes: 63 additions & 90 deletions src/jupyter_contrib_nbextensions/nbextensions/chrome-clipboard/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,56 +5,83 @@ define([
'base/js/namespace',
'jquery',
'base/js/utils',
'services/config',
'base/js/events'
], function(IPython, $, utils, events) {
], function(IPython, $, utils, configmod, events) {
"use strict";
if (window.chrome === undefined) return;

var params = {
subdirectory : '',
};

var base_url = utils.get_body_data("baseUrl");
var config = new configmod.ConfigSection('notebook', {base_url: base_url});

/* http://stackoverflow.com/questions/3231459/create-unique-id-with-javascript */
function uniqueid() {
function uniqueid(){
// always start with a letter (for DOM friendlyness)
var idstr = String.fromCharCode(Math.floor((Math.random() * 25) + 65));
var idstr=String.fromCharCode(Math.floor((Math.random()*25)+65));
do {
// between numbers and characters (48 is 0 and 90 is Z (42-48 = 90)
var ascicode = Math.floor((Math.random() * 42) + 48);
if (ascicode < 58 || ascicode > 64) {
var ascicode=Math.floor((Math.random()*42)+48);
if (ascicode<58 || ascicode>64){
// exclude all chars between : (58) and @ (64)
idstr += String.fromCharCode(ascicode);
idstr+=String.fromCharCode(ascicode);
}
} while (idstr.length < 32);
} while (idstr.length<32);

return (idstr);
}

var send_to_server = function (name, path, msg) {
var create_dir = function(path) {
var options = {type:'directory'};

var data = JSON.stringify({
ext: options.ext,
type: options.type
});

var settings = {
processData : false,
type : "PUT",
data: data,
contentType: 'application/json',
dataType : "json"
};
utils.promising_ajax(IPython.contents.api_url(path), settings);
};

var send_to_server = function(name, msg) {
var path = utils.url_path_join(utils.url_path_split(IPython.notebook.notebook_path)[0], params.subdirectory);
if (name == '') {
name = uniqueid() + '.' + msg.match(/data:image\/(\S+);/)[1];
}
var path = path.substring(0, path.lastIndexOf('/')) + '/';
if (path === '/') path = '';
var url = '//' + location.host + '/api/contents/' + path + name;
}
create_dir(path);
var url = '//' + location.host + utils.url_path_join(base_url, 'api/contents', path, name);

var img = msg.replace(/(^\S+,)/, ''); // strip header
var data = {'name': name, 'format': 'base64', 'content': img, 'type': 'file'};
//console.log("send_to_server:", url, img);
var data = {'name': name, 'format':'base64', 'content': img, 'type': 'file'};
var settings = {
processData: false,
cache: false,
type: "PUT",
dataType: "json",
data: JSON.stringify(data),
headers: {'Content-Type': 'text/plain'},
async: false,
error : function() {console.log('Data transfer for copy-paste has failed.');
}
processData : false,
cache : false,
type : "PUT",
dataType : "json",
data : JSON.stringify(data),
headers : {'Content-Type': 'text/plain'},
async : false,
error : function() {console.log('Data transfer for clipboard paste failed.'); }
};
utils.promising_ajax(url, settings).then(
utils.promising_ajax(url, settings).then(
function on_success (data, status, xhr) {
var new_cell = IPython.notebook.insert_cell_below('markdown');
var str = '<img src="' + name + '"/>';
var str = '![](' + utils.url_path_join(params.subdirectory, name) + ')';
new_cell.set_text(str);
new_cell.execute();
},
function on_error (reason) {
console.log('Data transfer for copy-paste has failed.');
console.log('Data transfer for clipboard paste has failed.');
});
};

Expand All @@ -63,6 +90,15 @@ define([
*/
var load_ipython_extension = function() {

config.load();
config.loaded
.then(function () {
$.extend(true, params, config.data.dragdrop); // update params
if (params.subdirectory) {
console.log('subdir:', params.subdirectory)
}
})

/*
* override clipboard 'paste' and insert new cell from json data in clipboard
*/
Expand All @@ -71,84 +107,21 @@ define([
if (cell.mode == "command") {
var items = event.clipboardData.items;
for (var i = 0; i < items.length; i++) {
if (items[i].type == 'notebook-cell/json') {
event.preventDefault();
/* json data adds a new notebook cell */
var data = event.clipboardData.getData('notebook-cell/json').split("\n").filter(Boolean);
for (var i = 0; i < data.length; i++) {
var ix = data.length - 1 - i;
var new_cell_data = JSON.parse(data[ix]);
var new_cell = IPython.notebook.insert_cell_below(new_cell_data.cell_type);
new_cell.fromJSON(new_cell_data);
if (new_cell.cell_type === "markdown") {
new_cell.execute();
};
}
} else if (items[i].type.indexOf('image/') !== -1) {
if (items[i].type.indexOf('image/') !== -1) {
event.preventDefault();
/* images are transferred to the server as file and linked to */
var blob = items[i].getAsFile();
var reader = new FileReader();
reader.onload = ( function (evt) {
var filename = '';
send_to_server(filename, IPython.notebook.notebook_path, evt.target.result);
send_to_server(filename, evt.target.result);
event.preventDefault();
} );
reader.readAsDataURL(blob);
}
}
}
});

/*
* override clipboard 'copy' and copy current cell as json and text to clipboard
*/
window.addEventListener('copy', function (event) {
var cell = IPython.notebook.get_selected_cell();
if (cell.mode == "command") {
var sel = window.getSelection();
if (sel.type == "Range") return;
/* default: copy marked text */
event.preventDefault();
var json = "";
var text = "";
var selected_cells = IPython.notebook.get_selected_cells();
for (var i in selected_cells) {
var j = selected_cells[i].toJSON();
json += JSON.stringify(j) + '\n';
text += selected_cells[i].code_mirror.getValue() + '\n';
}
/* copy cell as json and cell contents as text */
event.clipboardData.setData('notebook-cell/json', json);
event.clipboardData.setData("Text", text);
}
});

/*
* override clipboard 'cut' and copy current cell as json and text to clipboard
*/
window.addEventListener('cut', function (event) {
var cell = IPython.notebook.get_selected_cell();
if (cell.mode == "command") {
var sel = window.getSelection();
if (sel.type == "Range") return;
/* default: copy marked text */
event.preventDefault();
var json = "";
var text = "";
var selected_cells = IPython.notebook.get_selected_cells();
for (var i in selected_cells) {
var j = selected_cells[i].toJSON();
json += JSON.stringify(j) + '\n';
text += selected_cells[i].code_mirror.getValue() + '\n';
IPython.notebook.delete_cell(IPython.notebook.find_cell_index(selected_cells[i]));
}
/* copy cell as json and cell contents as text */
event.clipboardData.setData('notebook-cell/json', json);
event.clipboardData.setData("Text", text);
}
});

};

var extension = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ Chrome Clipboard

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

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

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

Hotkeys:

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

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

Internals
---------

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