|
|
|
|
@ -899,76 +899,111 @@ 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');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
@ -1302,53 +1337,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();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
@ -1413,12 +1471,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));
|
|
|
|
|
};
|
|
|
|
|
|