offline-editor-js/lib/edit/editsStore.js
Javier Abadia 0bbf9ca83a take care of updates for features added offline (replace negative tmp id by final id)
still has the problem with the Editor that removes the graphic from the layer after the update
2014-01-28 23:20:39 +01:00

321 lines
7.1 KiB
JavaScript

"use strict"
define(["esri/graphic"], function(Graphic)
{
/* private consts */
var EDITS_QUEUE_KEY = "esriEditsQueue";
var REDO_STACK_KEY = "esriRedoStack";
var SEPARATOR = "|@|";
return {
//
// public interface
//
// enum
ADD: "add",
UPDATE: "update",
DELETE:"delete",
isSupported: function()
{
// http://stackoverflow.com/questions/11214404/how-to-detect-if-browser-supports-html5-local-storage
var mod = 'esriLocalStorageTest';
try {
window.localStorage.setItem(mod, mod);
window.localStorage.removeItem(mod);
return true;
} catch(e) {
return false;
}
},
pushEdit: function(operation,layer,graphic)
{
var edit = {
operation: operation,
layer: layer,
graphic: this._serialize(graphic)
}
var edits = this._retrieveEditsQueue();
if( this._isEditDuplicated(edit,edits) )
{
// I still think that we shouldn't be concerned with duplicates:
// they just shouldn't exist, and if they do, then it is a bug in upper level code
console.log("duplicated", edit);
console.log("current store is", edits);
return false; // fail
}
else
{
edits.push(edit);
var success =
this._storeRedoStack([]) &&
this._storeEditsQueue(edits);
return success;
}
},
peekFirstEdit: function()
{
var edits = this._retrieveEditsQueue();
if( edits )
{
var firstEdit = edits[0]
firstEdit.graphic = this._deserialize(firstEdit.graphic);
return firstEdit;
}
else
return null;
},
popFirstEdit: function()
{
var edits = this._retrieveEditsQueue();
if( edits )
{
var firstEdit = edits.shift();
this._storeEditsQueue(edits);
firstEdit.graphic = this._deserialize(firstEdit.graphic);
return firstEdit;
}
else
return null;
},
replaceTempId: function(tempId, newObjectId, objectIdField)
{
var edits = this._retrieveEditsQueue();
var replaceCount = 0;
edits.forEach(function(edit)
{
var graphic = this._deserialize(edit.graphic);
if( graphic.attributes[ objectIdField] == tempId )
{
graphic.attributes[objectIdField] = newObjectId;
edit.graphic = this._serialize(graphic);
replaceCount += 1;
}
},this);
var success = this._storeEditsQueue(edits);
return success? replaceCount : false;
},
hasPendingEdits: function()
{
var storedValue = window.localStorage.getItem(EDITS_QUEUE_KEY) || "";
return ( storedValue != "" )
},
pendingEditsCount: function()
{
var storedValue = window.localStorage.getItem(EDITS_QUEUE_KEY) || "";
if( storedValue == "" )
return 0; // fast easy case
var editsArray = this._unpackArrayOfEdits(storedValue);
return editsArray.length;
},
resetEditsQueue: function()
{
window.localStorage.setItem(EDITS_QUEUE_KEY, "");
window.localStorage.setItem(REDO_STACK_KEY,"");
},
getReadableEdit: function(edit)
{
var graphic = this._deserialize(edit.graphic);
var readableGraphic = "";
switch(edit.operation)
{
case this.ADD:
readableGraphic = graphic.geometry.type;
break;
case this.UPDATE:
case this.DELETE:
readableGraphic = graphic.geometry.type + " [id=" + graphic.attributes.objectid + "]"; // jabadia: objectid name hardcoded
break;
readableGraphic = graphic.geometry.type + " [id=" + graphic.attributes.objectid + "]";
break;
}
return "o:" + edit.operation + ", l:" + edit.layer + ", g:" + readableGraphic;
},
// undo / redo
canUndoEdit: function()
{
return this.hasPendingEdits();
},
undoEdit: function()
{
if(!this.canUndoEdit())
return null;
var edits = this._retrieveEditsQueue();
var redoStack = this._retrieveRedoStack();
var editToUndo = edits.pop();
redoStack.push(editToUndo);
this._storeEditsQueue(edits);
this._storeRedoStack(redoStack);
return editToUndo;
},
canRedoEdit: function()
{
var storedValue = window.localStorage.getItem(REDO_STACK_KEY) || "";
return ( storedValue != "" )
},
redoEdit: function()
{
if(!this.canRedoEdit())
return null;
var edits = this._retrieveEditsQueue();
var redoStack = this._retrieveRedoStack();
var editToRedo = redoStack.pop();
edits.push(editToRedo);
this._storeRedoStack(redoStack);
this._storeEditsQueue(edits);
return editToRedo;
},
getEditsStoreSizeBytes: function()
{
var editsQueueValue = window.localStorage.getItem(EDITS_QUEUE_KEY);
var redoStackValue = window.localStorage.getItem(REDO_STACK_KEY);
return (editsQueueValue? EDITS_QUEUE_KEY.length + editsQueueValue.length : 0) +
(redoStackValue? REDO_STACK_KEY.length + redoStackValue.length : 0);
},
getLocalStorageSizeBytes: function()
{
var bytes = 0;
for( var key in window.localStorage )
{
var value = window.localStorage.getItem(key);
bytes += key.length + value.length;
}
return bytes;
},
//
// internal methods
//
//
// graphic serialization/deserialization
//
_serialize: function(graphic)
{
// keep only attributes and geometry, that are the values that get sent to the server by applyEdits()
// see http://resources.arcgis.com/en/help/arcgis-rest-api/index.html#/Apply_Edits_Feature_Service_Layer/02r3000000r6000000/
// use graphic's built-in serializing method
var json = graphic.toJson();
var jsonClean =
{
attributes: json.attributes,
geometry: json.geometry
}
return JSON.stringify(jsonClean);
},
_deserialize: function(json)
{
var graphic = new Graphic(JSON.parse(json));
return graphic;
},
_retrieveEditsQueue: function()
{
var storedValue = window.localStorage.getItem(EDITS_QUEUE_KEY) || "";
return this._unpackArrayOfEdits(storedValue);
},
_storeEditsQueue: function(edits)
{
try
{
var serializedEdits = this._packArrayOfEdits(edits);
window.localStorage.setItem(EDITS_QUEUE_KEY, serializedEdits);
return true;
}
catch(err)
{
return false;
}
},
_retrieveRedoStack: function()
{
var storedValue = window.localStorage.getItem(REDO_STACK_KEY) || "";
return this._unpackArrayOfEdits(storedValue);
},
_storeRedoStack: function(edits)
{
try
{
var serializedEdits = this._packArrayOfEdits(edits);
window.localStorage.setItem(REDO_STACK_KEY, serializedEdits);
return true;
}
catch(err)
{
return false;
}
},
_packArrayOfEdits: function(edits)
{
var serializedEdits = [];
edits.forEach(function(edit)
{
serializedEdits.push( JSON.stringify(edit) );
});
return serializedEdits.join(SEPARATOR);
},
_unpackArrayOfEdits: function(serializedEdits)
{
if( !serializedEdits )
return [];
var edits = [];
serializedEdits.split(SEPARATOR).forEach( function(serializedEdit)
{
edits.push( JSON.parse(serializedEdit) );
});
return edits;
},
_isEditDuplicated: function(newEdit,edits)
{
for(var i=0; i<edits.length; i++)
{
var edit = edits[i];
if( edit.operation == newEdit.operation &&
edit.layer == newEdit.layer &&
edit.graphic == newEdit.graphic )
{
return true;
}
}
return false;
}
}
});