From 6532ade7fdff04b32fd684fc73349f04982e334a Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Tue, 24 Mar 2015 09:59:22 -0600 Subject: [PATCH] delete temp features --- lib/edit/editsStore.js | 2 +- lib/edit/offlineFeaturesManager.js | 159 +++++++++++++++++------- test/spec/offlineFeaturesManagerSpec.js | 107 +++++++++++----- 3 files changed, 187 insertions(+), 81 deletions(-) diff --git a/lib/edit/editsStore.js b/lib/edit/editsStore.js index 7bc3835..39e8368 100644 --- a/lib/edit/editsStore.js +++ b/lib/edit/editsStore.js @@ -363,7 +363,7 @@ O.esri.Edit.EditStore = function () { /** * Deletes an individual graphic from the phantom layer - * @param id + * @param id Internal ID * @param callback callback(boolean, message) */ this.deletePhantomGraphic = function (id, callback) { diff --git a/lib/edit/offlineFeaturesManager.js b/lib/edit/offlineFeaturesManager.js index 79d5384..555d7a8 100644 --- a/lib/edit/offlineFeaturesManager.js +++ b/lib/edit/offlineFeaturesManager.js @@ -277,8 +277,6 @@ define([ var results = {addResults: [], updateResults: [], deleteResults: []}; var updatesMap = {}; - if(this.onBeforeApplyEdits)this.onBeforeApplyEdits(adds, updates, deletes); - adds = adds || []; adds.forEach(function (addEdit) { var deferred = new Deferred(); @@ -351,43 +349,24 @@ define([ var thisLayer = this; - self._editStore.pushEdit(self._editStore.DELETE, this.url, deleteEdit, function (result, error) { + // We need to run some validation tests against each feature being added. + // If graphic doesn't exist return false and we will add a phantom graphic + // If graphic DOES exist then return true and we do not need to add a phantom graphic + this._validateFeature(deleteEdit,this.url,self._editStore.DELETE).then(function(result){ + console.log("EDIT DELETE IS BACK!!! " ); - if(result == true){ - results.deleteResults.push({success: true, error: null, objectId: objectId}); - - var phantomDelete = new Graphic( - deleteEdit.geometry, - self._getPhantomSymbol(deleteEdit.geometry, self._editStore.DELETE), - { - objectId: objectId - }); - thisLayer._phantomLayer.add(phantomDelete); - - // Add phantom graphic to the database - self._editStore.pushPhantomGraphic(phantomDelete, function (result) { - if (!result)console.log("There was a problem adding phantom graphic id: " + objectId); - console.log("Phantom graphic " + objectId + " added to database as a deletion."); - }); - - domAttr.set(phantomDelete.getNode(), "stroke-dasharray", "4,4"); - domStyle.set(phantomDelete.getNode(), "pointer-events", "none"); - - if (self.attachmentsStore) { - // delete local attachments of this feature, if any... we just launch the delete and don't wait for it to complete - self.attachmentsStore.deleteAttachmentsByFeatureId(this.url, objectId, function (deletedCount) { - console.log("deleted", deletedCount, "attachments of feature", objectId); - }); - } - - deferred.resolve(result); + if(result.success){ + thisLayer._pushValidatedDeleteFeatureToDB(thisLayer,deleteEdit,result.operation,results,objectId,deferred); } else{ - // If we can't push edit to database then we don't create a phantom graphic - results.addResults.push({success: false, error: error, objectId: objectId}); - deferred.reject(error); + // If we get here then we deleted an edit that was added offline. + // We also have deleted the phantom graphic. + deferred.resolve(true); } + },function(error){ + console.log("_validateFeature: Unable to validate!"); + deferred.reject(error); }); promises.push(deferred); @@ -615,6 +594,57 @@ define([ /* internal methods */ + /** + * Pushes an DELETE request to the database after it's been validated + * @param layer + * @param deleteEdit + * @param operation + * @param resultsArray + * @param objectId + * @param deferred + * @private + */ + layer._pushValidatedDeleteFeatureToDB = function(layer,deleteEdit,operation,resultsArray,objectId,deferred){ + self._editStore.pushEdit(operation, layer.url, deleteEdit, function (result, error) { + + if(result == true){ + resultsArray.deleteResults.push({success: true, error: null, objectId: objectId}); + + var phantomDelete = new Graphic( + deleteEdit.geometry, + self._getPhantomSymbol(deleteEdit.geometry, self._editStore.DELETE), + { + objectId: objectId + }); + layer._phantomLayer.add(phantomDelete); + + // Add phantom graphic to the database + self._editStore.pushPhantomGraphic(phantomDelete, function (result) { + if (!result)console.log("There was a problem adding phantom graphic id: " + objectId); + console.log("Phantom graphic " + objectId + " added to database as a deletion."); + }); + + domAttr.set(phantomDelete.getNode(), "stroke-dasharray", "4,4"); + domStyle.set(phantomDelete.getNode(), "pointer-events", "none"); + + if (self.attachmentsStore) { + // delete local attachments of this feature, if any... we just launch the delete and don't wait for it to complete + self.attachmentsStore.deleteAttachmentsByFeatureId(layer.url, objectId, function (deletedCount) { + console.log("deleted", deletedCount, "attachments of feature", objectId); + }); + } + + deferred.resolve(result); + } + else{ + // If we can't push edit to database then we don't create a phantom graphic + resultsArray.addResults.push({success: false, error: error, objectId: objectId}); + deferred.reject(error); + } + + }); + }; + /** * Pushes an UPDATE request to the database after it's been validated * @param layer @@ -732,7 +762,7 @@ define([ // and not an UPDATE. This avoids the potential for an error if we submit // an update operation on a feature that has not been added to the // database yet. - if(result.operation = self._editStore.ADD){ + if(result.operation == self._editStore.ADD){ graphic.operation = self._editStore.ADD; operation = self._editStore.ADD; } @@ -740,12 +770,14 @@ define([ break; case self._editStore.DELETE: - if(result.operation = this._editStore.ADD){ + var resolved = true; + + if(result.operation == self._editStore.ADD){ // If we are deleting a new feature that has not been added to the // server yet we need to delete it and its phantom graphic. - deferred.resolve({"success":false,"graphic":graphic,"operation":operation}); + resolved = false; } - deferred.resolve({"success":true,"graphic":graphic,"operation":operation}); + deferred.resolve({"success":resolved,"graphic":graphic,"operation":operation}); break; } } @@ -763,6 +795,48 @@ define([ return deferred; }; + /** + * Delete a graphic and its associated phantom graphic that has been added while offline. + * @param graphic + * @param callback + * @private + */ + layer._deleteTemporaryFeature = function(graphic,callback){ + + var phantomGraphicId = self._editStore.PHANTOM_GRAPHIC_PREFIX + self._editStore._PHANTOM_PREFIX_TOKEN + graphic.attributes.objectid; + + function _deleteGraphic(){ + var deferred = new Deferred(); + self._editStore.delete(layer.url,graphic,function(success,error){ + if(success){ + deferred.resolve(true); + } + else{ + deferred.resolve(false); + } + }); + return deferred.promise; + } + + function _deletePhantomGraphic(){ + var deferred = new Deferred(); + self._editStore.deletePhantomGraphic(phantomGraphicId,function(success){ + if(success){ + deferred.resolve(true); + } + else{ + deferred.resolve(false); + } + }); + return deferred.promise; + } + + all([_deleteGraphic(),_deletePhantomGraphic()]).then(function (results) { + callback(results); + }); + + }; + layer._getFilesFromForm = function (formNode) { var files = []; var inputNodes = array.filter(formNode.elements, function (node) { @@ -1165,10 +1239,6 @@ define([ layer.onEditsComplete = function () { console.log("intercepting events onEditsComplete"); }; - layer.__onBeforeApplyEdits = layer.onBeforeApplyEdits; - layer.onBeforeApplyEdits = function () { - console.log("intercepting events onBeforeApplyEdits"); - }; // Let's zero everything out adds = [], updates = [], deletes = [], tempObjectIds = []; @@ -1396,8 +1466,6 @@ define([ function (addResults, updateResults, deleteResults) { layer._phantomLayer.clear(); - layer.onBeforeApplyEdits = layer.__onBeforeApplyEdits; - delete layer.__onBeforeApplyEdits; var newObjectIds = addResults.map(function (r) { return r.objectId; }); @@ -1429,8 +1497,7 @@ define([ function (error) { layer.onEditsComplete = layer.__onEditsComplete; delete layer.__onEditsComplete; - layer.onBeforeApplyEdits = layer.__onBeforeApplyEdits; - delete layer.__onBeforeApplyEdits; + dfd.reject(error); } ); diff --git a/test/spec/offlineFeaturesManagerSpec.js b/test/spec/offlineFeaturesManagerSpec.js index df23314..9858bf0 100644 --- a/test/spec/offlineFeaturesManagerSpec.js +++ b/test/spec/offlineFeaturesManagerSpec.js @@ -483,10 +483,41 @@ describe("Offline Editing", function() }); }); + // Checking for errors and error handling + async.it("delete a non-existing feature directly from db", function(done){ + + var fakeGraphic = new g_modules.Graphic({"geometry":{"x":-10910,"y":513700,"spatialReference":{"wkid":102100}},"attributes":{"symbolname":"Reference Point 1234","z":null,"additionalinformation":null,"eny":null,"datetimevalid":null,"datetimeexpired":null,"distance":null,"azimuth":null,"uniquedesignation":null,"x":null,"y":null}} ); + g_editsStore.delete(g_featureLayers[0].url,fakeGraphic,function(success,error){ + expect(success).toBe(false); + done(); + }); + }); + + // Checking for errors and error handling + async.it("delete a non-existing feature using extended feature layer", function(done){ + + var fakeGraphic = new g_modules.Graphic({"geometry":{"x":-10910,"y":513700,"spatialReference":{"wkid":102100}},"attributes":{"symbolname":"Reference Point 1234","z":null,"additionalinformation":null,"eny":null,"datetimevalid":null,"datetimeexpired":null,"distance":null,"azimuth":null,"uniquedesignation":null,"x":null,"y":null}} ); + g_featureLayers[0]._deleteTemporaryFeature(fakeGraphic,function(results){ + expect(results[0]).toBe(false); + expect(results[1]).toBe(false); + done(); + }); + }); + + // This private function deletes a temporary graphic and it's associated phantom graphic + async.it("delete an existing feature using extended feature layer", function(done){ + + g_featureLayers[0]._deleteTemporaryFeature(g5,function(results){ + expect(results[0]).toBe(true); + expect(results[1]).toBe(true); + done(); + }); + }); + async.it("check db size", function(done){ g_featureLayers[0].getUsage(function(usage,error){ - expect(usage.sizeBytes).toBe(7982); - expect(usage.editCount).toBe(9); + expect(usage.sizeBytes).toBe(7083); + expect(usage.editCount).toBe(8); expect(error).toBe(null); done(); }) @@ -503,16 +534,16 @@ describe("Offline Editing", function() g_editsStore.getPhantomGraphicsArray(function(results,errors){ // Should be the same size as the number of edits!! - expect(results.length).toBe(9); + expect(results.length).toBe(8); expect(results[0].id).toBe("phantom-layer|@|-1"); - expect(results[1].id).toBe("phantom-layer|@|-2"); - expect(results[2].id).toBe("phantom-layer|@|-3"); + //expect(results[1].id).toBe("phantom-layer|@|-2"); + expect(results[1].id).toBe("phantom-layer|@|-3"); + expect((results[2].id).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); expect((results[3].id).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); expect((results[4].id).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); expect((results[5].id).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); expect((results[6].id).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); - expect((results[7].id).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); - expect((results[8].id).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); + //expect((results[8].id).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); expect(errors).toBe("end"); done(); }) @@ -523,16 +554,16 @@ describe("Offline Editing", function() g_featureLayers[0].getPhantomGraphicsArray(function(result,array){ expect(result).toBe(true); expect(typeof array).toBe("object"); - expect(array.length).toBe(9); + expect(array.length).toBe(8); expect(array[0].id).toBe("phantom-layer|@|-1"); - expect(array[1].id).toBe("phantom-layer|@|-2"); - expect(array[2].id).toBe("phantom-layer|@|-3"); + //expect(results[1].id).toBe("phantom-layer|@|-2"); + expect(array[1].id).toBe("phantom-layer|@|-3"); + expect((array[2].id).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); expect((array[3].id).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); expect((array[4].id).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); expect((array[5].id).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); expect((array[6].id).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); - expect((array[7].id).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); - expect((array[8].id).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); + //expect((results[8].id).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); done(); }); }); @@ -550,17 +581,17 @@ describe("Offline Editing", function() g_editsStore._getPhantomGraphicsArraySimple(function(results,errors){ // Should be the previous size + 1 additional phantom graphic. - expect(results.length).toBe(10); + expect(results.length).toBe(9); expect(results[0]).toBe("phantom-layer|@|-1"); - expect(results[1]).toBe("phantom-layer|@|-2"); - expect(results[2]).toBe("phantom-layer|@|-3"); + //expect(results[1]).toBe("phantom-layer|@|-2"); + expect(results[1]).toBe("phantom-layer|@|-3"); + expect((results[2]).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); expect((results[3]).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); expect((results[4]).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); expect((results[5]).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); expect((results[6]).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); expect((results[7]).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); - expect((results[8]).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); - expect(results[9]).toBe("phantom-layer|@|test001"); + expect(results[8]).toBe("phantom-layer|@|test001"); expect(errors).toBe("end"); done(); }) @@ -587,19 +618,19 @@ describe("Offline Editing", function() g_editsStore._getPhantomGraphicsArraySimple(function(results,errors){ // We added two phantom graphics to previous result - expect(results.length).toBe(12); + expect(results.length).toBe(11); expect(results[0]).toBe("phantom-layer|@|-1"); - expect(results[1]).toBe("phantom-layer|@|-2"); - expect(results[2]).toBe("phantom-layer|@|-3"); + //expect(results[1]).toBe("phantom-layer|@|-2"); + expect(results[1]).toBe("phantom-layer|@|-3"); + expect((results[2]).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); expect((results[3]).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); expect((results[4]).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); expect((results[5]).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); expect((results[6]).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); expect((results[7]).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); - expect((results[8]).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); - expect(results[9]).toBe("phantom-layer|@|test001"); - expect(results[10]).toBe("phantom-layer|@|test002"); - expect(results[11]).toBe("phantom-layer|@|test003"); + expect(results[8]).toBe("phantom-layer|@|test001"); + expect(results[9]).toBe("phantom-layer|@|test002"); + expect(results[10]).toBe("phantom-layer|@|test003"); expect(errors).toBe("end"); done(); }) @@ -612,24 +643,32 @@ describe("Offline Editing", function() g_editsStore._getPhantomGraphicsArraySimple(function(results,errors){ // We remove one graphic from the previous result of 12 - expect(results.length).toBe(11); + expect(results.length).toBe(10); expect(results[0]).toBe("phantom-layer|@|-1"); - expect(results[1]).toBe("phantom-layer|@|-2"); - expect(results[2]).toBe("phantom-layer|@|-3"); + //expect(results[1]).toBe("phantom-layer|@|-2"); + expect(results[1]).toBe("phantom-layer|@|-3"); + expect((results[2]).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); expect((results[3]).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); expect((results[4]).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); expect((results[5]).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); expect((results[6]).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); expect((results[7]).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); - expect((results[8]).indexOf(g_editsStore.PHANTOM_GRAPHIC_PREFIX)).toBe(0); - expect(results[9]).toBe("phantom-layer|@|test002"); - expect(results[10]).toBe("phantom-layer|@|test003"); + expect(results[8]).toBe("phantom-layer|@|test002"); + expect(results[9]).toBe("phantom-layer|@|test003"); expect(errors).toBe("end"); done(); }) }) }); + //async.it("delete temporary feature", function(done){ + // g_featureLayers[0]._deleteTemporaryFeature(g6,function(results){ + // expect(results[0]).toBe(true); + // expect(results[1]).toBe(true); + // done(); + // }); + //}); + async.it("Delete all PhantomLayerGraphics", function(done){ g_editsStore.resetPhantomGraphicsQueue(function(result){ @@ -726,7 +765,7 @@ describe("Offline Editing", function() async.it("Retrieve edits array from the layer", function(done){ g_featureLayers[0].getAllEditsArray(function(success,array){ expect(success).toBe(true); console.log("ARRAY " + JSON.stringify(array)) - expect(array.length).toBe(9); + expect(array.length).toBe(8); done(); }); }); @@ -750,7 +789,7 @@ describe("Offline Editing", function() //console.log("RESPONSES " + JSON.stringify(responses) + ", " + JSON.stringify(results)) - expect(Object.keys(results.features.responses).length).toBe(9); + expect(Object.keys(results.features.responses).length).toBe(8); for (var key in results.features.responses) { var response = results.features.responses[key]; @@ -787,14 +826,14 @@ describe("Offline Editing", function() describe("After online", function(){ async.it("After online - verify feature layer graphic counts",function(done){ // all of them are positive - expect(getObjectIds(g_featureLayers[0].graphics).filter(function(id){ return id<0; })).toEqual([]); + expect(getObjectIds(g_featureLayers[0].graphics).filter(function(id){ return id<0; })).toEqual([-2]); expect(getObjectIds(g_featureLayers[1].graphics).filter(function(id){ return id<0; })).toEqual([]); expect(g_featureLayers[0].graphics.length).toBe(5); expect(g_featureLayers[1].graphics.length).toBe(3); countFeatures(g_featureLayers[0], function(success,result) { expect(success).toBeTruthy(); - expect(result.count).toBe(5); + expect(result.count).toBe(4); countFeatures(g_featureLayers[1], function(success,result) { expect(success).toBeTruthy();