Skip to content

Commit

Permalink
Merge pull request #269 from takluyver/multicell-ccp
Browse files Browse the repository at this point in the history
Cut, copy, paste and delete acting on multiple cells
  • Loading branch information
Carreau committed Aug 11, 2015
2 parents 4cb2b78 + 474b124 commit 53c3826
Showing 1 changed file with 135 additions and 81 deletions.
216 changes: 135 additions & 81 deletions notebook/static/notebook/js/notebook.js
Original file line number Diff line number Diff line change
Expand Up @@ -899,76 +899,112 @@ define(function (require) {
return this;
};


/**
* Delete a cell from the notebook.
*
* @param {integer} [index] - cell's numeric index
* Delete cells from the notebook
*
* @param {Array} [indices] - the numeric indices of cells to delete.
* @return {Notebook} This notebook
*/
Notebook.prototype.delete_cell = function (index) {
var i = this.index_or_selected(index);
var cell = this.get_cell(i);
if (!cell.is_deletable()) {
return this;
Notebook.prototype.delete_cells = function(indices) {
if (indices === undefined) {
indices = this.get_selected_indices();
}

this.undelete_backup = cell.toJSON();
$('#undelete_cell').removeClass('disabled');
if (this.is_valid_cell_index(i)) {
var old_ncells = this.ncells();
var ce = this.get_cell_element(i);
ce.remove();
if (i === 0) {
// Always make sure we have at least one cell.
if (old_ncells === 1) {
this.insert_cell_below('code');
}
this.select(0);
this.undelete_index = 0;
this.undelete_below = false;
} else if (i === old_ncells-1 && i !== 0) {
this.select(i-1);
this.undelete_index = i - 1;
this.undelete_backup = [];

var cursor_ix_before = this.get_selected_index();
var deleting_before_cursor = 0;
for (var i=0; i < indices.length; i++) {
if (!this.get_cell(indices[i]).is_deletable()) {
// If any cell is marked undeletable, cancel
return this;
}

if (indices[i] < cursor_ix_before) {
deleting_before_cursor++;
}
}

// If we started deleting cells from the top, the later indices would
// get offset. We sort them into descending order to avoid that.
indices.sort(function(a, b) {return b-a;});
for (i=0; i < indices.length; i++) {
var cell = this.get_cell(indices[i]);
this.undelete_backup.push(cell.toJSON());
this.get_cell_element(indices[i]).remove();
this.events.trigger('delete.Cell', {'cell': cell, 'index': indices[i]});
}

// Flip the backup copy of cells back to first-to-last order
this.undelete_backup.reverse();

var new_ncells = this.ncells();
// Always make sure we have at least one cell.
if (new_ncells === 0) {
this.insert_cell_below('code');
new_ncells = 1;
}

this.undelete_below = false;
var cursor_ix_after = this.get_selected_index();
if (cursor_ix_after === null) {
// Selected cell was deleted
cursor_ix_after = cursor_ix_before - deleting_before_cursor;
if (cursor_ix_after >= new_ncells) {
cursor_ix_after = new_ncells - 1;
this.undelete_below = true;
} else {
this.select(i);
this.undelete_index = i;
this.undelete_below = false;
}
this.events.trigger('delete.Cell', {'cell': cell, 'index': i});
this.set_dirty(true);
this.select(cursor_ix_after);
}

// This will put all the deleted cells back in one location, rather than
// where they came from. It will do until we have proper undo support.
this.undelete_index = cursor_ix_after;
$('#undelete_cell').removeClass('disabled');

this.set_dirty(true);

return this;
};

/**
* Restore the most recently deleted cell.
* Delete a cell from the notebook.
*
* @param {integer} [index] - cell's numeric index
* @return {Notebook} This notebook
*/
Notebook.prototype.delete_cell = function (index) {
if (index === undefined) {
return this.delete_cells();
} else {
return this.delete_cells([index]);
}
};

/**
* Restore the most recently deleted cells.
*/
Notebook.prototype.undelete_cell = function() {
if (this.undelete_backup !== null && this.undelete_index !== null) {
var current_index = this.get_selected_index();
if (this.undelete_index < current_index) {
current_index = current_index + 1;
}
if (this.undelete_index >= this.ncells()) {
this.select(this.ncells() - 1);
}
else {
this.select(this.undelete_index);
}
var cell_data = this.undelete_backup;
var new_cell = null;
var i, cell_data, new_cell;
if (this.undelete_below) {
new_cell = this.insert_cell_below(cell_data.cell_type);
} else {
new_cell = this.insert_cell_above(cell_data.cell_type);
}
new_cell.fromJSON(cell_data);
if (this.undelete_below) {
this.select(current_index+1);
for (i = this.undelete_backup.length-1; i >= 0; i--) {
cell_data = this.undelete_backup[i];
new_cell = this.insert_cell_below(cell_data.cell_type,
this.undelete_index);
new_cell.fromJSON(cell_data);
}
} else {
this.select(current_index);
for (i=0; i < this.undelete_backup.length; i++) {
cell_data = this.undelete_backup[i];
new_cell = this.insert_cell_above(cell_data.cell_type,
this.undelete_index);
new_cell.fromJSON(cell_data);
}
}

this.set_dirty(true);
this.undelete_backup = null;
this.undelete_index = null;
}
Expand Down Expand Up @@ -1302,53 +1338,76 @@ define(function (require) {
};

/**
* Copy a cell.
* Copy cells.
*/
Notebook.prototype.copy_cell = function () {
var cell = this.get_selected_cell();
this.clipboard = cell.toJSON();
// remove undeletable status from the copied cell
if (this.clipboard.metadata.deletable !== undefined) {
delete this.clipboard.metadata.deletable;
var cells = this.get_selected_cells();
this.clipboard = [];
var cell_json;
for (var i=0; i < cells.length; i++) {
cell_json = cells[i].toJSON();
if (cell_json.metadata.deletable !== undefined) {
delete cell_json.metadata.deletable;
}
this.clipboard.push(cell_json);
}
this.enable_paste();
};

/**
* Replace the selected cell with the cell in the clipboard.
* Replace the selected cell with the cells in the clipboard.
*/
Notebook.prototype.paste_cell_replace = function () {
if (this.clipboard !== null && this.paste_enabled) {
var cell_data = this.clipboard;
var new_cell = this.insert_cell_above(cell_data.cell_type);
new_cell.fromJSON(cell_data);
var old_cell = this.get_next_cell(new_cell);
this.delete_cell(this.find_cell_index(old_cell));
this.select(this.find_cell_index(new_cell));
var first_inserted = null;
for (var i=0; i < this.clipboard.length; i++) {
var cell_data = this.clipboard;
var new_cell = this.insert_cell_above(cell_data.cell_type);
new_cell.fromJSON(cell_data);
if (first_inserted === null) {
first_inserted = new_cell;
}
}
var old_selected = this.get_selected_index();
this.select(this.find_cell_index(first_inserted));
this.delete_cell(old_selected);
}
};

/**
* Paste a cell from the clipboard above the selected cell.
* Paste cells from the clipboard above the selected cell.
*/
Notebook.prototype.paste_cell_above = function () {
if (this.clipboard !== null && this.paste_enabled) {
var cell_data = this.clipboard;
var new_cell = this.insert_cell_above(cell_data.cell_type);
new_cell.fromJSON(cell_data);
new_cell.focus_cell();
var first_inserted = null;
for (var i=0; i < this.clipboard.length; i++) {
var cell_data = this.clipboard[i];
var new_cell = this.insert_cell_above(cell_data.cell_type);
new_cell.fromJSON(cell_data);
if (first_inserted === null) {
first_inserted = new_cell;
}

}
first_inserted.focus_cell();
}
};

/**
* Paste a cell from the clipboard below the selected cell.
* Paste cells from the clipboard below the selected cell.
*/
Notebook.prototype.paste_cell_below = function () {
if (this.clipboard !== null && this.paste_enabled) {
var cell_data = this.clipboard;
var new_cell = this.insert_cell_below(cell_data.cell_type);
new_cell.fromJSON(cell_data);
new_cell.focus_cell();
var first_inserted = null;
for (var i = this.clipboard.length-1; i >= 0; i--) {
var cell_data = this.clipboard[i];
var new_cell = this.insert_cell_below(cell_data.cell_type);
new_cell.fromJSON(cell_data);
if (first_inserted === null) {
first_inserted = new_cell;
}
}
first_inserted.focus_cell();
}
};

Expand Down Expand Up @@ -1413,12 +1472,7 @@ define(function (require) {
}

// Delete the other cells
// If we started deleting cells from the top, the later indices would
// get offset. We sort them into descending order to avoid that.
indices.sort(function(a, b) {return b-a;});
for (i=0; i < indices.length; i++) {
this.delete_cell(indices[i]);
}
this.delete_cells(indices);

this.select(this.find_cell_index(target));
};
Expand Down

0 comments on commit 53c3826

Please sign in to comment.