Begin to work undo functionality into data layer -- currently just for Item.save()
History.undo()/redo() now reload the item, though changes won't show in open metadata pane due to #71 refs #67
This commit is contained in:
parent
f897564f0e
commit
b8ad832e74
2 changed files with 154 additions and 12 deletions
|
@ -366,9 +366,14 @@ Scholar.Item.prototype.save = function(){
|
|||
try {
|
||||
Scholar.DB.beginTransaction();
|
||||
|
||||
// Begin history transaction
|
||||
Scholar.History.begin('modify-item', this.getID());
|
||||
|
||||
//
|
||||
// Primary fields
|
||||
//
|
||||
Scholar.History.modify('items', 'itemID', this.getID());
|
||||
|
||||
var sql = "UPDATE items SET ";
|
||||
var sql2;
|
||||
var sqlValues = [];
|
||||
|
@ -408,6 +413,9 @@ Scholar.Item.prototype.save = function(){
|
|||
var creator = this.getCreator(orderIndex);
|
||||
|
||||
// Delete at position
|
||||
Scholar.History.remove('itemCreators', 'itemID-orderIndex',
|
||||
[this.getID(), orderIndex]);
|
||||
|
||||
sql2 = 'DELETE FROM itemCreators'
|
||||
+ ' WHERE itemID=' + this.getID()
|
||||
+ ' AND orderIndex=' + orderIndex;
|
||||
|
@ -430,15 +438,21 @@ Scholar.Item.prototype.save = function(){
|
|||
creator['firstName'],
|
||||
creator['lastName']
|
||||
);
|
||||
Scholar.History.add('creators', 'creatorID', creatorID);
|
||||
}
|
||||
|
||||
// If this creator and creatorType exists elsewhere, move it
|
||||
|
||||
sql2 = 'SELECT COUNT(*) FROM itemCreators'
|
||||
+ ' WHERE itemID=' + this.getID()
|
||||
+ ' AND creatorID=' + creatorID
|
||||
+ ' AND creatorTypeID=' + creator['creatorTypeID'];
|
||||
|
||||
// If this creator and creatorType exists elsewhere, move it
|
||||
if (Scholar.DB.valueQuery(sql2)){
|
||||
Scholar.History.modify('itemCreators',
|
||||
'itemID-creatorID-creatorTypeID',
|
||||
[this.getID(), creatorID, creator['creatorTypeID']]);
|
||||
|
||||
sql = 'UPDATE itemCreators SET orderIndex=? '
|
||||
+ "WHERE itemID=? AND creatorID=? AND "
|
||||
+ "creatorTypeID=?";
|
||||
|
@ -452,6 +466,7 @@ Scholar.Item.prototype.save = function(){
|
|||
|
||||
Scholar.DB.query(sql, sqlValues);
|
||||
}
|
||||
|
||||
// Otherwise insert
|
||||
else {
|
||||
sql = "INSERT INTO itemCreators VALUES (?,?,?,?)";
|
||||
|
@ -464,11 +479,21 @@ Scholar.Item.prototype.save = function(){
|
|||
];
|
||||
|
||||
Scholar.DB.query(sql, sqlValues);
|
||||
|
||||
Scholar.History.add('itemCreators',
|
||||
'itemID-creatorID-creatorTypeID',
|
||||
[this.getID(), creatorID, creator['creatorTypeID']]);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete obsolete creators
|
||||
Scholar.Creators.purge();
|
||||
var deleted;
|
||||
if (deleted = Scholar.Creators.purge()){
|
||||
for (var i in deleted){
|
||||
// Add purged creators to history
|
||||
Scholar.History.remove('creators', 'creatorID', i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -484,9 +509,13 @@ Scholar.Item.prototype.save = function(){
|
|||
+ 'WHERE itemID=' + this.getID()
|
||||
+ ' AND fieldID=' + fieldID;
|
||||
|
||||
// Update
|
||||
if (Scholar.DB.valueQuery(sql2)){
|
||||
sqlValues = [];
|
||||
|
||||
Scholar.History.modify('itemData', 'itemID-fieldID',
|
||||
[this.getID(), fieldID]);
|
||||
|
||||
sql = "UPDATE itemData SET value=?";
|
||||
// Take advantage of SQLite's manifest typing
|
||||
if (Scholar.ItemFields.isInteger(fieldID)){
|
||||
|
@ -504,7 +533,12 @@ Scholar.Item.prototype.save = function(){
|
|||
|
||||
Scholar.DB.query(sql, sqlValues);
|
||||
}
|
||||
|
||||
// Insert
|
||||
else {
|
||||
Scholar.History.add('itemData', 'itemID-fieldID',
|
||||
[this.getID(), fieldID]);
|
||||
|
||||
sql = "INSERT INTO itemData VALUES (?,?,?)";
|
||||
|
||||
sqlValues = [
|
||||
|
@ -522,6 +556,7 @@ Scholar.Item.prototype.save = function(){
|
|||
Scholar.DB.query(sql, sqlValues);
|
||||
}
|
||||
}
|
||||
|
||||
// If field changed and is empty, mark row for deletion
|
||||
else {
|
||||
del.push(fieldID);
|
||||
|
@ -530,6 +565,12 @@ Scholar.Item.prototype.save = function(){
|
|||
|
||||
// Delete blank fields
|
||||
if (del.length){
|
||||
// Add to history
|
||||
for (var i in del){
|
||||
Scholar.History.remove('itemData', 'itemID-fieldID',
|
||||
[this.getID(), del[i]]);
|
||||
}
|
||||
|
||||
sql = 'DELETE from itemData '
|
||||
+ 'WHERE itemID=' + this.getID() + ' '
|
||||
+ 'AND fieldID IN (' + del.join() + ")";
|
||||
|
@ -537,9 +578,11 @@ Scholar.Item.prototype.save = function(){
|
|||
}
|
||||
}
|
||||
|
||||
Scholar.History.commit();
|
||||
Scholar.DB.commitTransaction();
|
||||
}
|
||||
catch (e){
|
||||
Scholar.History.cancel();
|
||||
Scholar.DB.rollbackTransaction();
|
||||
throw(e);
|
||||
}
|
||||
|
@ -569,8 +612,12 @@ Scholar.Item.prototype.save = function(){
|
|||
try {
|
||||
Scholar.DB.beginTransaction();
|
||||
|
||||
// Begin history transaction
|
||||
// No associated id yet, so we use false
|
||||
Scholar.History.begin('add-item', false);
|
||||
|
||||
//
|
||||
// itemData fields
|
||||
// Primary fields
|
||||
//
|
||||
var sql = "INSERT INTO items (" + sqlColumns.join() + ')'
|
||||
+ ' VALUES (';
|
||||
|
@ -584,7 +631,12 @@ Scholar.Item.prototype.save = function(){
|
|||
var itemID = Scholar.DB.query(sql,sqlValues);
|
||||
this._data['itemID'] = itemID;
|
||||
|
||||
// Set itemData
|
||||
Scholar.History.setAssociatedID(itemID);
|
||||
Scholar.History.add('items', 'itemID', itemID);
|
||||
|
||||
//
|
||||
// ItemData
|
||||
//
|
||||
if (this._changedItemData.length){
|
||||
for (fieldID in this._changedItemData.items){
|
||||
if (!this.getField(fieldID)){
|
||||
|
@ -609,6 +661,9 @@ Scholar.Item.prototype.save = function(){
|
|||
}
|
||||
|
||||
Scholar.DB.query(sql, sqlValues);
|
||||
|
||||
Scholar.History.add('itemData', 'itemID-fieldID',
|
||||
this.getField(fieldID));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -636,6 +691,7 @@ Scholar.Item.prototype.save = function(){
|
|||
creator['firstName'],
|
||||
creator['lastName']
|
||||
);
|
||||
Scholar.History.add('creators', 'creatorID', creatorID);
|
||||
}
|
||||
|
||||
sql = 'INSERT INTO itemCreators VALUES ('
|
||||
|
@ -643,9 +699,14 @@ Scholar.Item.prototype.save = function(){
|
|||
+ creator['creatorTypeID'] + ', ' + orderIndex
|
||||
+ ")";
|
||||
Scholar.DB.query(sql);
|
||||
|
||||
Scholar.History.add('itemCreators',
|
||||
'itemID-creatorID-creatorTypeID',
|
||||
[this.getID(), creatorID, creator['creatorTypeID']]);
|
||||
}
|
||||
}
|
||||
|
||||
Scholar.History.commit();
|
||||
Scholar.DB.commitTransaction();
|
||||
|
||||
// Reload collection to update isEmpty,
|
||||
|
@ -653,6 +714,7 @@ Scholar.Item.prototype.save = function(){
|
|||
Scholar.Collections.reloadAll();
|
||||
}
|
||||
catch (e){
|
||||
Scholar.History.cancel();
|
||||
Scholar.DB.rollbackTransaction();
|
||||
throw(e);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
Scholar.History = new function(){
|
||||
this.begin = begin;
|
||||
this.setAssociatedID = setAssociatedID;
|
||||
this.add = add;
|
||||
this.modify = modify;
|
||||
this.remove = remove;
|
||||
|
@ -18,12 +19,15 @@ Scholar.History = new function(){
|
|||
var _activeEvent;
|
||||
var _maxID = 0;
|
||||
|
||||
// event: ('item-add', 'item-delete', 'item-modify', 'collection-add', 'collection-modify', 'collection-delete')
|
||||
// context: (itemCreators.itemID-creatorID.1-1)
|
||||
// action: ('add', 'delete', 'modify')
|
||||
|
||||
/**
|
||||
* Begin a transaction set
|
||||
*
|
||||
* event: 'item-add', 'item-delete', 'item-modify', 'collection-add',
|
||||
* 'collection-modify', 'collection-delete'...
|
||||
*
|
||||
* id: An id or array of ids that will be passed to
|
||||
* Scholar.Notifier.trigger() on an undo or redo
|
||||
**/
|
||||
function begin(event, id){
|
||||
if (_activeID){
|
||||
|
@ -40,8 +44,16 @@ Scholar.History = new function(){
|
|||
Scholar.debug('Beginning history transaction set ' + event);
|
||||
var sql = "INSERT INTO transactionSets (event, id) VALUES "
|
||||
+ "('" + event + "', ";
|
||||
// If integer, insert natively; if array, insert as string
|
||||
sql += (typeof id=='object') ? "'" + id.join('-') + "'" : id;
|
||||
if (!id){
|
||||
sql += '0';
|
||||
}
|
||||
// If array, insert hyphen-delimited string
|
||||
else if (typeof id=='object'){
|
||||
sql += "'" + id.join('-') + "'"
|
||||
}
|
||||
else {
|
||||
sql += id;
|
||||
}
|
||||
sql += ")";
|
||||
|
||||
Scholar.DB.beginTransaction();
|
||||
|
@ -50,8 +62,44 @@ Scholar.History = new function(){
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Associate an id or array of ids with the transaction set --
|
||||
* for use if the ids weren't available at when begin() was called
|
||||
*
|
||||
* id: An id or array of ids that will be passed to
|
||||
* Scholar.Notifier.trigger() on an undo or redo
|
||||
**/
|
||||
function setAssociatedID(id){
|
||||
if (!_activeID){
|
||||
throw('Cannot call setAssociatedID() with no history transaction set in progress');
|
||||
}
|
||||
|
||||
var sql = "UPDATE transactionSets SET id=";
|
||||
if (!id){
|
||||
sql += '0';
|
||||
}
|
||||
// If array, insert hyphen-delimited string
|
||||
else if (typeof id=='object'){
|
||||
sql += "'" + id.join('-') + "'"
|
||||
}
|
||||
else {
|
||||
sql += id;
|
||||
}
|
||||
sql += " WHERE transactionSetID=" + _activeID;
|
||||
Scholar.DB.query(sql);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add an add transaction to the current set
|
||||
*
|
||||
* Can be called before or after an INSERT statement
|
||||
*
|
||||
* key is a hyphen-delimited list of columns identifying the row
|
||||
* e.g. 'itemID-creatorID'
|
||||
*
|
||||
* keyValues is a hyphen-delimited list of values matching the key parts
|
||||
* e.g. '1-1'
|
||||
**/
|
||||
function add(table, key, keyValues){
|
||||
return _addTransaction('add', table, key, keyValues);
|
||||
|
@ -61,6 +109,14 @@ Scholar.History = new function(){
|
|||
/**
|
||||
* Add a modify transaction to the current set
|
||||
*
|
||||
* Must be called before an UPDATE statement
|
||||
*
|
||||
* key is a hyphen-delimited list of columns identifying the row
|
||||
* e.g. 'itemID-creatorID'
|
||||
*
|
||||
* keyValues is a hyphen-delimited list of values matching the key parts
|
||||
* e.g. '1-1'
|
||||
*
|
||||
* _field_ is optional -- otherwise all fields are saved
|
||||
**/
|
||||
function modify(table, key, keyValues, field){
|
||||
|
@ -70,6 +126,14 @@ Scholar.History = new function(){
|
|||
|
||||
/**
|
||||
* Add a remove transaction to the current set
|
||||
*
|
||||
* Must be called before a DELETE statement
|
||||
*
|
||||
* key is a hyphen-delimited list of columns identifying the row
|
||||
* e.g. 'itemID-creatorID'
|
||||
*
|
||||
* keyValues is a hyphen-delimited list of values matching the key parts
|
||||
* e.g. '1-1'
|
||||
**/
|
||||
function remove(table, key, keyValues){
|
||||
return _addTransaction('remove', table, key, keyValues);
|
||||
|
@ -139,7 +203,7 @@ Scholar.History = new function(){
|
|||
var undone = _do('undo');
|
||||
_currentID--;
|
||||
Scholar.DB.commitTransaction();
|
||||
_notifyEvent(id);
|
||||
_reloadAndNotify(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -154,7 +218,7 @@ Scholar.History = new function(){
|
|||
var redone = _do('redo');
|
||||
_currentID++;
|
||||
Scholar.DB.commitTransaction();
|
||||
_notifyEvent(id);
|
||||
_reloadAndNotify(id, true);
|
||||
return redone;
|
||||
}
|
||||
|
||||
|
@ -421,9 +485,25 @@ Scholar.History = new function(){
|
|||
}
|
||||
|
||||
|
||||
function _notifyEvent(transactionSetID){
|
||||
function _reloadAndNotify(transactionSetID, redo){
|
||||
var data = _getSetData(transactionSetID);
|
||||
var eventParts = data['event'].split('-'); // e.g. modify-item
|
||||
if (redo){
|
||||
switch (eventParts[0]){
|
||||
case 'add':
|
||||
eventParts[0] = 'remove';
|
||||
break;
|
||||
case 'remove':
|
||||
eventParts[0] = 'add';
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (eventParts[1]){
|
||||
case 'item':
|
||||
Scholar.Items.reload(data['id']);
|
||||
break;
|
||||
}
|
||||
|
||||
Scholar.Notifier.trigger(eventParts[0], eventParts[1], data['id']);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue