mirror of
https://github.com/Esri/offline-editor-js.git
synced 2025-12-15 15:20:05 +00:00
commit
1fa1bb8c1a
14
CHANGELOG.md
14
CHANGELOG.md
@ -1,5 +1,19 @@
|
||||
# offline-editor-js - Changelog
|
||||
|
||||
## Version 2.8 - May 4, 2015
|
||||
|
||||
This release focused on updating full offline editing capabilities. Recommended update. No breaking changes.
|
||||
|
||||
**Enhancements**
|
||||
* Added functionality to `offlineFeaturesManager.js` to detect and handle when a feature layer is created using a feature collection.
|
||||
* Addresses browser changes in Chrome 42.x and Firefox 37.x with respect to how they handle HTML/JS apps when going offline and
|
||||
then transitioning back online.
|
||||
* Updated `appcache-features.html` sample.
|
||||
|
||||
**Bug Fix**
|
||||
* Closes #336 - problem with appcache-features sample. The application now correctly syncs when going back online after
|
||||
a full offline restart. It also contains improvements in how the app life-cycle is handled.
|
||||
|
||||
## Version 2.7.1 - April 29, 2015
|
||||
|
||||
This release has enhancements and has no breaking changes.
|
||||
|
||||
6
dist/offline-edit-min.js
vendored
6
dist/offline-edit-min.js
vendored
File diff suppressed because one or more lines are too long
290
dist/offline-edit-src.js
vendored
290
dist/offline-edit-src.js
vendored
@ -1,4 +1,4 @@
|
||||
/*! offline-editor-js - v2.7.1 - 2015-04-29
|
||||
/*! offline-editor-js - v2.8 - 2015-05-05
|
||||
* Copyright (c) 2015 Environmental Systems Research Institute, Inc.
|
||||
* Apache License*/
|
||||
/*jshint -W030 */
|
||||
@ -14,17 +14,19 @@ define([
|
||||
"esri/config",
|
||||
"esri/layers/GraphicsLayer",
|
||||
"esri/graphic",
|
||||
"esri/request",
|
||||
"esri/symbols/SimpleMarkerSymbol",
|
||||
"esri/symbols/SimpleLineSymbol",
|
||||
"esri/symbols/SimpleFillSymbol",
|
||||
"esri/urlUtils"],
|
||||
function (Evented, Deferred, all, declare, array, domAttr, domStyle, query,
|
||||
esriConfig, GraphicsLayer, Graphic, SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol, urlUtils) {
|
||||
esriConfig, GraphicsLayer, Graphic, esriRequest, SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol, urlUtils) {
|
||||
"use strict";
|
||||
return declare("O.esri.Edit.OfflineFeaturesManager", [Evented],
|
||||
{
|
||||
_onlineStatus: "online",
|
||||
_featureLayers: {},
|
||||
_featureCollectionUsageFlag: false, // if a feature collection was used to create the feature layer.
|
||||
_editStore: new O.esri.Edit.EditStore(),
|
||||
|
||||
ONLINE: "online", // all edits will directly go to the server
|
||||
@ -40,7 +42,7 @@ define([
|
||||
|
||||
ATTACHMENTS_DB_NAME: "attachments_store", //Sets attachments database name
|
||||
ATTACHMENTS_DB_OBJECTSTORE_NAME: "attachments",
|
||||
// NOTE: attachments don't have the same issues as Graphics as related to UIDs.
|
||||
// NOTE: attachments don't have the same issues as Graphics as related to UIDs (e.g. the need for DB_UID).
|
||||
// You can manually create a graphic, but it would be very rare for someone to
|
||||
// manually create an attachment. So, we don't provide a public property for
|
||||
// the attachments database UID.
|
||||
@ -53,7 +55,8 @@ define([
|
||||
EDITS_SENT_ERROR: "edits-sent-error", // ...there was a problem with one or more edits!
|
||||
ALL_EDITS_SENT: "all-edits-sent", // ...after going online and there are no pending edits in the queue
|
||||
ATTACHMENT_ENQUEUED: "attachment-enqueued",
|
||||
ATTACHMENTS_SENT: "attachments-sent"
|
||||
ATTACHMENTS_SENT: "attachments-sent",
|
||||
EXTEND_COMPLETE: "extend-complete" // ...when the libary has completed its initialization
|
||||
},
|
||||
|
||||
/**
|
||||
@ -101,23 +104,44 @@ define([
|
||||
* @returns deferred
|
||||
*/
|
||||
extend: function (layer, callback, dataStore) {
|
||||
|
||||
var extendPromises = []; // deferred promises related to initializing this method
|
||||
|
||||
var self = this;
|
||||
layer.offlineExtended = true; // to identify layer has been extended
|
||||
|
||||
// NOTE: At v2.6.1 we've discovered that not all feature layers support objectIdField.
|
||||
// However, we want to try to be consistent here with how the library is managing Ids.
|
||||
// So, we force the layer.objectIdField to DB_UID. This should be consistent with
|
||||
// However, to try to be consistent here with how the library is managing Ids
|
||||
// we force the layer.objectIdField to DB_UID. This should be consistent with
|
||||
// how esri.Graphics assign a unique ID to a graphic. If it is not, then this
|
||||
// library will break and we'll have to re-architect how we manage UIDs.
|
||||
// library will break and we'll have to re-architect how it manages UIDs.
|
||||
layer.objectIdField = this.DB_UID;
|
||||
|
||||
var url = null;
|
||||
|
||||
// There have been reproducible use cases showing when a browser is restarted offline that
|
||||
// for some reason the layer.url may be undefined.
|
||||
// This is an attempt to minimize the possibility of that situation causing errors.
|
||||
if(layer.url) {
|
||||
url = layer.url;
|
||||
// we keep track of the FeatureLayer object
|
||||
this._featureLayers[layer.url] = layer;
|
||||
}
|
||||
|
||||
// This is a potentially brittle solution to detecting if a feature layer collection
|
||||
// was used to create the feature layer.
|
||||
// Is there a better way??
|
||||
if(layer._mode.featureLayer.hasOwnProperty("_collection")){
|
||||
// This means a feature collection was used to create the feature layer and it will
|
||||
// require different handling when running applyEdit()
|
||||
this._featureCollectionUsageFlag = true;
|
||||
}
|
||||
|
||||
// Initialize the database as well as set offline data.
|
||||
if(!this._editStore._isDBInit) {
|
||||
this._initializeDB(dataStore,callback);
|
||||
extendPromises.push(this._initializeDB(dataStore, url));
|
||||
}
|
||||
|
||||
// we keep track of the FeatureLayer object
|
||||
this._featureLayers[layer.url] = layer;
|
||||
|
||||
// replace the applyEdits() method
|
||||
layer._applyEdits = layer.applyEdits;
|
||||
|
||||
@ -135,7 +159,7 @@ define([
|
||||
3. remove an attachment that is already in the server... (DONE)
|
||||
4. remove an attachment that is not in the server yet (DONE)
|
||||
5. update an existing attachment to an existing feature (DONE)
|
||||
6. update a new attachment (NOT YET)
|
||||
6. update a new attachment (DONE)
|
||||
|
||||
concerns:
|
||||
- manage the relationship between offline features and attachments: what if the user wants to add
|
||||
@ -143,9 +167,6 @@ define([
|
||||
the feature is sent to the server and receives a final objectid we replace the temporary negative id
|
||||
by its final objectid (DONE)
|
||||
- what if the user deletes an offline feature that had offline attachments? we need to discard the attachment (DONE)
|
||||
|
||||
pending tasks:
|
||||
- check for hasAttachments attribute in the FeatureLayer (NOT YET)
|
||||
*/
|
||||
|
||||
//
|
||||
@ -284,7 +305,7 @@ define([
|
||||
}
|
||||
|
||||
if (!self.attachmentsStore) {
|
||||
console.log("in order to support attachments you need to call initAttachments() method of offlineFeaturesManager");
|
||||
console.error("in order to support attachments you need to call initAttachments() method of offlineFeaturesManager");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -468,8 +489,7 @@ define([
|
||||
all(promises).then(function (r) {
|
||||
// Make sure all edits were successful. If not throw an error.
|
||||
var success = true;
|
||||
var length = r.length;
|
||||
for (var v = 0; v < length; v++) {
|
||||
for (var v = 0; v < r.length; v++) {
|
||||
if (r[v] === false) {
|
||||
success = false;
|
||||
}
|
||||
@ -723,7 +743,7 @@ define([
|
||||
/* internal methods */
|
||||
|
||||
/**
|
||||
* Pushes an DELETE request to the database after it's been validated
|
||||
* Pushes a DELETE request to the database after it's been validated
|
||||
* @param layer
|
||||
* @param deleteEdit
|
||||
* @param operation
|
||||
@ -1035,6 +1055,33 @@ define([
|
||||
|
||||
_initPhantomLayer();
|
||||
|
||||
// We are currently only passing in a single deferred.
|
||||
all(extendPromises).then(function (r) {
|
||||
if(r.length === 0){
|
||||
callback(true, null);
|
||||
}
|
||||
else if(r[0].success && !url){
|
||||
|
||||
// This functionality is specifically for offline restarts
|
||||
// and attempts to retrieve a feature layer url.
|
||||
// It's a hack because layer.toJson() doesn't convert layer.url.
|
||||
this._editStore.getFeatureLayerJSON(function(success,message){
|
||||
if(success) {
|
||||
this._featureLayers[message.__featureLayerURL] = layer;
|
||||
layer.url = message.__featureLayerURL;
|
||||
callback(true, null);
|
||||
}
|
||||
else {
|
||||
console.error("getFeatureLayerJSON() failed.");
|
||||
callback(false, message);
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
else if(r[0].success){
|
||||
callback(true, null);
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
}, // extend
|
||||
|
||||
/**
|
||||
@ -1054,7 +1101,7 @@ define([
|
||||
console.log("offlineFeaturesManager going online");
|
||||
this._onlineStatus = this.RECONNECTING;
|
||||
this._replayStoredEdits(function (success, responses) {
|
||||
var result = {features: {success: success, responses: responses}};
|
||||
var result = {success: success, responses: responses};
|
||||
this._onlineStatus = this.ONLINE;
|
||||
if (this.attachmentsStore != null) {
|
||||
console.log("sending attachments");
|
||||
@ -1105,13 +1152,16 @@ define([
|
||||
*/
|
||||
getFeatureLayerJSONDataStore: function(callback){
|
||||
if(!this._editStore._isDBInit){
|
||||
this._initializeDB(null,function(success) {
|
||||
if(success){
|
||||
|
||||
this._initializeDB(null,null).then(function(result){
|
||||
if(result.success){
|
||||
this._editStore.getFeatureLayerJSON(function(success,message){
|
||||
callback(success,message);
|
||||
});
|
||||
}
|
||||
}.bind(this));
|
||||
}.bind(this), function(err){
|
||||
callback(false, err);
|
||||
});
|
||||
}
|
||||
else {
|
||||
this._editStore.getFeatureLayerJSON(function(success,message){
|
||||
@ -1123,12 +1173,16 @@ define([
|
||||
/* internal methods */
|
||||
|
||||
/**
|
||||
* Intialize the database and push featureLayer JSON to DB if required
|
||||
* Initialize the database and push featureLayer JSON to DB if required.
|
||||
* NOTE: also stores feature layer url in hidden dataStore property dataStore.__featureLayerURL.
|
||||
* @param dataStore Object
|
||||
* @param url Feature Layer's url. This is used by this library for internal feature identification.
|
||||
* @param callback
|
||||
* @private
|
||||
*/
|
||||
_initializeDB: function(dataStore,callback){
|
||||
//_initializeDB: function(dataStore,url,callback){
|
||||
_initializeDB: function(dataStore,url){
|
||||
var deferred = new Deferred();
|
||||
|
||||
var editStore = this._editStore;
|
||||
|
||||
@ -1153,22 +1207,32 @@ define([
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
if (typeof dataStore === "object" && result === true && (dataStore !== undefined) && (dataStore !== null)) {
|
||||
|
||||
// Add a hidden property to hold the feature layer's url
|
||||
// When converting a feature layer to json (layer.toJson()) we lose this information.
|
||||
// This library needs to know the feature layer url.
|
||||
if(url) {
|
||||
dataStore.__featureLayerURL = url;
|
||||
}
|
||||
|
||||
editStore.pushFeatureLayerJSON(dataStore, function (success, err) {
|
||||
if (success) {
|
||||
callback(true, null);
|
||||
deferred.resolve({success:true, error: null});
|
||||
}
|
||||
else {
|
||||
callback(false, err);
|
||||
deferred.reject({success:false, error: err});
|
||||
}
|
||||
});
|
||||
}
|
||||
else if(result){
|
||||
callback(true, null);
|
||||
deferred.resolve({success:true, error: null});
|
||||
}
|
||||
else{
|
||||
callback(false, error);
|
||||
deferred.reject({success:false, error: null});
|
||||
}
|
||||
});
|
||||
|
||||
return deferred;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1416,23 +1480,7 @@ define([
|
||||
attachments.forEach(function (attachment) {
|
||||
console.log("sending attachment", attachment.id, "to feature", attachment.featureId);
|
||||
|
||||
var uploadAttachmentComplete =
|
||||
this._uploadAttachment(attachment);
|
||||
//.then(function (uploadResult) {
|
||||
// if (uploadResult.addAttachmentResult && uploadResult.addAttachmentResult.success === true) {
|
||||
// console.log("upload success", uploadResult.addAttachmentResult.success);
|
||||
// return this._deleteAttachment(attachment.id, uploadResult);
|
||||
// }
|
||||
// else {
|
||||
// console.log("upload failed", uploadResult);
|
||||
// return null;
|
||||
// }
|
||||
//}.bind(this),
|
||||
//function (err) {
|
||||
// console.log("failed uploading attachment", attachment);
|
||||
// return null;
|
||||
//}
|
||||
//);
|
||||
var uploadAttachmentComplete = this._uploadAttachment(attachment);
|
||||
promises.push(uploadAttachmentComplete);
|
||||
}, this);
|
||||
console.log("promises", promises.length);
|
||||
@ -1447,20 +1495,6 @@ define([
|
||||
callback && callback(true, uploadResults,dbResults);
|
||||
}
|
||||
});
|
||||
//results.forEach(function(value){
|
||||
// if(value.attachmentResult.success){
|
||||
// // Delete an attachment from the database if it was successfully
|
||||
// // submitted to the server.
|
||||
// self._deleteAttachmentFromDB(value.id,null).then(function(result){
|
||||
// if(result.success){
|
||||
// callback && callback(true, results);
|
||||
// }
|
||||
// else{
|
||||
// callback && callback(false, results);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
//});
|
||||
},
|
||||
function (err) {
|
||||
console.log("error!", err);
|
||||
@ -1508,10 +1542,6 @@ define([
|
||||
if (attachmentsStore == null && layer.hasAttachments) {
|
||||
console.log("NOTICE: you may need to run OfflineFeaturesManager.initAttachments(). Check the Attachments doc for more info. Layer id: " + layer.id + " accepts attachments");
|
||||
}
|
||||
else if(layer.hasAttachments === false){
|
||||
console.error("WARNING: Layer " + layer.id + "doesn't seem to accept attachments. Recheck the layer permissions.");
|
||||
callback(false,"WARNING: Attachments not supported in layer: " + layer.id);
|
||||
}
|
||||
|
||||
// Assign the attachmentsStore to the layer as a private var so we can access it from
|
||||
// the promises applyEdits() method.
|
||||
@ -1550,7 +1580,13 @@ define([
|
||||
break;
|
||||
}
|
||||
|
||||
promises[n] = that._internalApplyEdits(layer, tempArray[n].id, tempObjectIds, adds, updates, deletes);
|
||||
if(that._featureCollectionUsageFlag){
|
||||
// Note: when the feature layer is created with a feature collection we have to handle applyEdits() differently
|
||||
promises[n] = that._internalApplyEditsFeatureCollection(layer, tempArray[n].id, tempObjectIds, adds, updates, deletes);
|
||||
}
|
||||
else {
|
||||
promises[n] = that._internalApplyEdits(layer, tempArray[n].id, tempObjectIds, adds, updates, deletes);
|
||||
}
|
||||
}
|
||||
|
||||
// wait for all requests to finish
|
||||
@ -1735,7 +1771,7 @@ define([
|
||||
},
|
||||
|
||||
/**
|
||||
* Executes the _applyEdits() method
|
||||
* Executes the _applyEdits() method when a feature layer is created using a REST endpoint
|
||||
* @param layer
|
||||
* @param id the unique id that identifies the Graphic in the database
|
||||
* @param tempObjectIds
|
||||
@ -1790,6 +1826,126 @@ define([
|
||||
return dfd.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Executes the _applyEdits() method when a feature layer is created using a feature collection.
|
||||
* This works around specific behaviors in esri.layers.FeatureLayer when using the pattern
|
||||
* new FeatureLayer(featureCollectionObject).
|
||||
*
|
||||
* Details on the specific behaviors can be found here:
|
||||
* https://developers.arcgis.com/javascript/jsapi/featurelayer-amd.html#featurelayer2
|
||||
*
|
||||
* @param layer
|
||||
* @param id
|
||||
* @param tempObjectIds
|
||||
* @param adds
|
||||
* @param updates
|
||||
* @param deletes
|
||||
* @returns {*|r}
|
||||
* @private
|
||||
*/
|
||||
_internalApplyEditsFeatureCollection: function (layer, id, tempObjectIds, adds, updates, deletes) {
|
||||
var dfd = new Deferred();
|
||||
|
||||
this._makeEditRequest(layer.url, adds, updates, deletes,
|
||||
function (addResults, updateResults, deleteResults) {
|
||||
layer._phantomLayer.clear();
|
||||
|
||||
var newObjectIds = addResults.map(function (r) {
|
||||
return r.objectId;
|
||||
});
|
||||
|
||||
// We use a different pattern if the attachmentsStore is valid and the layer has attachments
|
||||
if (layer._attachmentsStore != null && layer.hasAttachments && tempObjectIds.length > 0) {
|
||||
layer._replaceFeatureIds(tempObjectIds, newObjectIds, function (success) {
|
||||
dfd.resolve({
|
||||
id: id,
|
||||
layer: layer.url,
|
||||
tempId: tempObjectIds, // let's us internally match an ADD to it's new ObjectId
|
||||
addResults: addResults,
|
||||
updateResults: updateResults,
|
||||
deleteResults: deleteResults
|
||||
}); // wrap three arguments in a single object
|
||||
});
|
||||
}
|
||||
else {
|
||||
dfd.resolve({
|
||||
id: id,
|
||||
layer: layer.url,
|
||||
tempId: tempObjectIds, // let's us internally match an ADD to it's new ObjectId
|
||||
addResults: addResults,
|
||||
updateResults: updateResults,
|
||||
deleteResults: deleteResults
|
||||
}); // wrap three arguments in a single object
|
||||
}
|
||||
},
|
||||
function (error) {
|
||||
layer.onEditsComplete = layer.__onEditsComplete;
|
||||
delete layer.__onEditsComplete;
|
||||
|
||||
dfd.reject(error);
|
||||
}
|
||||
);
|
||||
return dfd.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Used when a feature layer is created with a feature collection.
|
||||
*
|
||||
* In the current version of the ArcGIS JSAPI 3.12+ the applyEdit() method doesn't send requests
|
||||
* to the server when a feature layer is created with a feature collection.
|
||||
*
|
||||
* The use case for using this is: clean start app > go offline and make edits > offline restart browser >
|
||||
* go online.
|
||||
*
|
||||
* @param url
|
||||
* @param adds
|
||||
* @param updates
|
||||
* @param deletes
|
||||
* @returns {*|r}
|
||||
* @private
|
||||
*/
|
||||
_makeEditRequest: function(url,adds, updates, deletes, callback, errback) {
|
||||
|
||||
//var dfd = new Deferred();
|
||||
|
||||
var data = new FormData();
|
||||
data.append("f", "json");
|
||||
if(adds.length > 0) {
|
||||
data.append("adds", JSON.stringify(adds));
|
||||
}
|
||||
if(updates.length > 0) {
|
||||
data.append("updates", JSON.stringify(updates));
|
||||
}
|
||||
if(deletes.length > 0) {
|
||||
data.append("deletes", JSON.stringify(deletes));
|
||||
}
|
||||
|
||||
var req = new XMLHttpRequest();
|
||||
req.open("POST", url + "/applyEdits", true);
|
||||
req.onload = function()
|
||||
{
|
||||
if( req.status === 200 && req.responseText !== "")
|
||||
{
|
||||
var obj = JSON.parse(this.response);
|
||||
//dfd.resolve(obj);
|
||||
callback(obj.addResults, obj.updateResults, obj.deleteResults);
|
||||
//callback(this.response);
|
||||
//Object.keys(this.response).forEach(function(key) {
|
||||
// console.log(key, this.response[key]);
|
||||
//});
|
||||
}
|
||||
};
|
||||
req.onerror = function(e)
|
||||
{
|
||||
console.log("_getTileInfoPrivate failed: " + e);
|
||||
errback(e);
|
||||
//dfd.error(e);
|
||||
};
|
||||
req.send(data);
|
||||
|
||||
//return dfd.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Deprecated @ v2.5. Internal-use only
|
||||
* @returns {string}
|
||||
@ -2784,7 +2940,7 @@ O.esri.Edit.EditStore = function () {
|
||||
this._db = event.target.result;
|
||||
this._isDBInit = true;
|
||||
console.log("database opened successfully");
|
||||
callback(true);
|
||||
callback(true, null);
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
|
||||
2
dist/offline-tiles-advanced-min.js
vendored
2
dist/offline-tiles-advanced-min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/offline-tiles-advanced-src.js
vendored
2
dist/offline-tiles-advanced-src.js
vendored
@ -1,4 +1,4 @@
|
||||
/*! offline-editor-js - v2.7.1 - 2015-04-29
|
||||
/*! offline-editor-js - v2.8 - 2015-05-05
|
||||
* Copyright (c) 2015 Environmental Systems Research Institute, Inc.
|
||||
* Apache License*/
|
||||
define([
|
||||
|
||||
2
dist/offline-tiles-basic-min.js
vendored
2
dist/offline-tiles-basic-min.js
vendored
@ -1,4 +1,4 @@
|
||||
/*! offline-editor-js - v2.7.1 - 2015-04-29
|
||||
/*! offline-editor-js - v2.8 - 2015-05-05
|
||||
* Copyright (c) 2015 Environmental Systems Research Institute, Inc.
|
||||
* Apache License*/
|
||||
define(["dojo/query","dojo/request","esri/geometry/Polygon","dojo/_base/declare"],function(a,b,c,d){"use strict";return d("O.esri.Tiles.OfflineTilesEnabler",[],{getBasemapLayer:function(a){var b=a.layerIds[0];return a.getLayer(b)},extend:function(c,d,e){c._tilesCore=new O.esri.Tiles.TilesCore,c._lastTileUrl="",c._imageType="",c._minZoom=null,c._maxZoom=null,c._getTileUrl=c.getTileUrl;var f=!0;return"undefined"!=typeof e&&(f=e),c.offline={online:f,store:new O.esri.Tiles.TilesStore,proxyPath:null},c.offline.store.isSupported()?(c.offline.store.init(function(b){b&&(c.resampling=!1,c.getTileUrl=function(b,d,e){var f=this._getTileUrl(b,d,e);if(this.offline.online)return""==c._imageType&&(c._imageType=this.tileInfo.format.toLowerCase()),c._lastTileUrl=f,f;f=f.split("?")[0];var g="void:/"+b+"/"+d+"/"+e,h=null;return c._tilesCore._getTiles(h,this._imageType,f,g,this.offline.store,a),g},d&&d(!0))}.bind(this)),c.getLevelEstimation=function(a,b,c){var d=new O.esri.Tiles.TilingScheme(this),e=d.getAllCellIdsInExtent(a,b),f={level:b,tileCount:e.length,sizeBytes:e.length*c};return f},c.prepareForOffline=function(a,b,d,e){c._tilesCore._createCellsForOffline(this,a,b,d,function(a){this._doNextTile(0,a,e)}.bind(this))},c.goOffline=function(){this.offline.online=!1},c.goOnline=function(){this.offline.online=!0,this.refresh()},c.isOnline=function(){return this.offline.online},c.deleteAllTiles=function(a){var b=this.offline.store;b.deleteAll(a)},c.getOfflineUsage=function(a){var b=this.offline.store;b.usedSpace(a)},c.getTilePolygons=function(a){c._tilesCore._getTilePolygons(this.offline.store,c.url,this,a)},c.saveToFile=function(a,b){c._tilesCore._saveToFile(a,this.offline.store,b)},c.loadFromFile=function(a,b){c._tilesCore._loadFromFile(a,this.offline.store,b)},c.getMaxZoom=function(a){null==this._maxZoom&&(this._maxZoom=c.tileInfo.lods[c.tileInfo.lods.length-1].level),a(this._maxZoom)},c.getMinZoom=function(a){null==this._minZoom&&(this._minZoom=c.tileInfo.lods[0].level),a(this._minZoom)},c.getMinMaxLOD=function(a,b){var d={},e=c.getMap(),f=e.getLevel()+a,g=e.getLevel()+b;return null!=this._maxZoom&&null!=this._minZoom?(d.max=Math.min(this._maxZoom,g),d.min=Math.max(this._minZoom,f)):(c.getMinZoom(function(a){d.min=Math.max(a,f)}),c.getMaxZoom(function(a){d.max=Math.min(a,g)})),d},c.estimateTileSize=function(a){c._tilesCore._estimateTileSize(b,this._lastTileUrl,this.offline.proxyPath,a)},c.getExtentBuffer=function(a,b){return b.xmin-=a,b.ymin-=a,b.xmax+=a,b.ymax+=a,b},c.getTileUrlsByExtent=function(a,b){var d=new O.esri.Tiles.TilingScheme(c),e=d.getAllCellIdsInExtent(a,b),f=[];return e.forEach(function(a){f.push(c.url+"/"+b+"/"+a[1]+"/"+a[0])}.bind(this)),f},void(c._doNextTile=function(a,b,d){var e=b[a],f=this._getTileUrl(e.level,e.row,e.col);c._tilesCore._storeTile(f,this.offline.proxyPath,this.offline.store,function(c,f){c||(f={cell:e,msg:f});var g=d({countNow:a,countMax:b.length,cell:e,error:f,finishedDownloading:!1});g||a===b.length-1?d({finishedDownloading:!0,cancelRequested:g}):this._doNextTile(a+1,b,d)}.bind(this))})):d(!1,"indexedDB not supported")}})}),"undefined"!=typeof O?O.esri.Tiles={}:(O={},O.esri={Tiles:{}}),O.esri.Tiles.Base64Utils={},O.esri.Tiles.Base64Utils.outputTypes={Base64:0,Hex:1,String:2,Raw:3},O.esri.Tiles.Base64Utils.addWords=function(a,b){var c=(65535&a)+(65535&b),d=(a>>16)+(b>>16)+(c>>16);return d<<16|65535&c},O.esri.Tiles.Base64Utils.stringToWord=function(a){for(var b=8,c=(1<<b)-1,d=[],e=0,f=a.length*b;f>e;e+=b)d[e>>5]|=(a.charCodeAt(e/b)&c)<<e%32;return d},O.esri.Tiles.Base64Utils.wordToString=function(a){for(var b=8,c=(1<<b)-1,d=[],e=0,f=32*a.length;f>e;e+=b)d.push(String.fromCharCode(a[e>>5]>>>e%32&c));return d.join("")},O.esri.Tiles.Base64Utils.wordToHex=function(a){for(var b="0123456789abcdef",c=[],d=0,e=4*a.length;e>d;d++)c.push(b.charAt(a[d>>2]>>d%4*8+4&15)+b.charAt(a[d>>2]>>d%4*8&15));return c.join("")},O.esri.Tiles.Base64Utils.wordToBase64=function(a){for(var b="=",c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",d=[],e=0,f=4*a.length;f>e;e+=3)for(var g=(a[e>>2]>>8*(e%4)&255)<<16|(a[e+1>>2]>>8*((e+1)%4)&255)<<8|a[e+2>>2]>>8*((e+2)%4)&255,h=0;4>h;h++)d.push(8*e+6*h>32*a.length?b:c.charAt(g>>6*(3-h)&63));return d.join("")},/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
|
||||
|
||||
2
dist/offline-tiles-basic-src.js
vendored
2
dist/offline-tiles-basic-src.js
vendored
@ -1,4 +1,4 @@
|
||||
/*! offline-editor-js - v2.7.1 - 2015-04-29
|
||||
/*! offline-editor-js - v2.8 - 2015-05-05
|
||||
* Copyright (c) 2015 Environmental Systems Research Institute, Inc.
|
||||
* Apache License*/
|
||||
define([
|
||||
|
||||
2
dist/offline-tpk-min.js
vendored
2
dist/offline-tpk-min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/offline-tpk-src.js
vendored
2
dist/offline-tpk-src.js
vendored
@ -1,4 +1,4 @@
|
||||
/*! offline-editor-js - v2.7.1 - 2015-04-29
|
||||
/*! offline-editor-js - v2.8 - 2015-05-05
|
||||
* Copyright (c) 2015 Environmental Systems Research Institute, Inc.
|
||||
* Apache License*/
|
||||
/**
|
||||
|
||||
@ -75,7 +75,9 @@ NOTE: You can also monitor standard ArcGIS API for JavaScript layer events using
|
||||
|
||||
```
|
||||
|
||||
**Step 4** After the `layers-add-result` event fires extend the feature layer using the `extend()` method. Optionally, if you are building a fully offline app then you will also need to set the `dataStore` property in the constructor.
|
||||
**Step 4** After the `layers-add-result` event fires extend the feature layer using the `extend()` method. Optionally, if you are building a fully offline app then you will also need to set the `dataStore` property in the constructor.
|
||||
|
||||
Note: the `layer.extend()` callback only indicates that the edits database has been successfully initialized.
|
||||
|
||||
```js
|
||||
|
||||
@ -86,7 +88,7 @@ NOTE: You can also monitor standard ArcGIS API for JavaScript layer events using
|
||||
// options.graphics = JSON.stringify(layer1.toJson());
|
||||
// options.zoom = map.getZoom();
|
||||
|
||||
offlineFeaturesManager.extend(layer1,function(success,error){
|
||||
offlineFeaturesManager.extend(layer1,function(success, error){
|
||||
if(success){
|
||||
console.log("layer1 has been extended for offline use.");
|
||||
}
|
||||
@ -95,6 +97,34 @@ NOTE: You can also monitor standard ArcGIS API for JavaScript layer events using
|
||||
|
||||
```
|
||||
|
||||
When working with fully offline browser restarts you should wait until the layer has been successfully extended before forcing the library to go back online. The workflow for this coding pattern is you start out online > offline > browser restart > then back online.
|
||||
|
||||
```js
|
||||
|
||||
offlineFeaturesManager.extend(layer1, function(success, error) {
|
||||
if(success) {
|
||||
// If the app is online then force offlineFeaturesManager to its online state
|
||||
// This will force the library to check for pending edits and attempt to
|
||||
// resend them to the Feature Service.
|
||||
if(_isOnline){ // Check if app is online or offline
|
||||
offlineFeaturesManager.goOnline(function(result){
|
||||
if(!result.success){
|
||||
alert("There was a problem when attempting to go back online.");
|
||||
}
|
||||
else {
|
||||
// Do somthing good!
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
offlineFeaturesManager.goOffline();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
|
||||
The `dataStore` property is an object that is used to store any data related to your app that will assist in restoring it and any feature layers after a full offline browser restart. The `dataStore` object has one reserved key and that is `id`. If you overwrite the `id` key the application will fail to update the `dataStore` object correctly. Here is an example of one possible `dataStore` object:
|
||||
|
||||
```js
|
||||
@ -160,9 +190,9 @@ Force the library to return to an online condition. If there are pending edits,
|
||||
```js
|
||||
function goOnline()
|
||||
{
|
||||
offlineFeaturesManager.goOnline(function(success,results)
|
||||
offlineFeaturesManager.goOnline(function(result)
|
||||
{
|
||||
if(success){
|
||||
if(result.success){
|
||||
//Modify user inteface depending on success/failure
|
||||
}
|
||||
});
|
||||
|
||||
@ -38,11 +38,11 @@ OfflineFeaturesManager provides the following functionality.
|
||||
|
||||
Methods | Returns | Description
|
||||
--- | --- | ---
|
||||
`extend(layer,callback,dataStore)`|`callback( boolean, errors )`| Overrides a feature layer, by replacing the `applyEdits()` method of the layer. You can use the FeatureLayer as always, but it's behaviour will be enhanced according to the online status of the manager and the capabilities included in this library. `Callback` is related to initialization the library. <br><br>`dataStore` is an optional Object that contains any information you need when reconsistuting the layer after an offline browser restart. Refer to the [How to use the edit library doc](howtouseeditlibrary.md) for addition information.
|
||||
`extend( layer,` `callback, dataStore)`|`callback( boolean, errors )`| Overrides a feature layer, by replacing the `applyEdits()` method of the layer. You can use the FeatureLayer as always, but it's behaviour will be enhanced according to the online status of the manager and the capabilities included in this library.<br><br> `Callback` indicates the layer has been extended. <br><br>`dataStore` is an optional Object that contains any information you need when reconsistuting the layer after an offline browser restart. Refer to the [How to use the edit library doc](howtouseeditlibrary.md) for addition information.
|
||||
`goOffline()` | nothing | Forces library into an offline state. Any edits applied to extended FeatureLayers during this condition will be stored locally.
|
||||
`goOnline(callback)` | `callback( boolean, results )` | Forces library to return to an online state. If there are pending edits, an attempt will be made to sync them with the remote feature server. Callback function will be called when resync process is done. <br><br>Refer to the [How to use the edit library doc](howtouseeditlibrary.md) for addition information on the `results` object.
|
||||
`goOnline(callback)` | No attachments: `callback( {success: boolean, responses: Object } )`<br><br> With attachments: `callback( {success: boolean, responses: uploadedResponses, dbResponses: dbResponses })` | Forces library to return to an online state. If there are pending edits, an attempt will be made to sync them with the remote feature server. Callback function will be called when resync process is done. <br><br>Refer to the [How to use the edit library doc](howtouseeditlibrary.md) for addition information on the `results` object.
|
||||
`getOnlineStatus()` | `ONLINE`, `OFFLINE` or `RECONNECTING`| Determines the current state of the manager. Please, note that this library doesn't detect actual browser offline/online condition. You need to use the `offline.min.js` library included in `vendor\offline` directory to detect connection status and connect events to goOffline() and goOnline() methods. See `military-offline.html` sample.
|
||||
`getFeatureLayerJSONDataStore` | `callback( boolean, Object)` | **New @ v2.7.1** Returns the feature layer's dataStore Object.
|
||||
`getFeatureLayerJSONDataStore( callback )` | `callback( boolean, Object)` | **New @ v2.7.1** Returns the feature layer's dataStore Object.
|
||||
`getReadableEdit()` | String | **DEPRECATED** @ v2.5. A string value representing human readable information on pending edits. Use `featureLayer.getAllEditsArray()`.
|
||||
|
||||
|
||||
|
||||
@ -957,7 +957,7 @@ O.esri.Edit.EditStore = function () {
|
||||
this._db = event.target.result;
|
||||
this._isDBInit = true;
|
||||
console.log("database opened successfully");
|
||||
callback(true);
|
||||
callback(true, null);
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
|
||||
@ -11,17 +11,19 @@ define([
|
||||
"esri/config",
|
||||
"esri/layers/GraphicsLayer",
|
||||
"esri/graphic",
|
||||
"esri/request",
|
||||
"esri/symbols/SimpleMarkerSymbol",
|
||||
"esri/symbols/SimpleLineSymbol",
|
||||
"esri/symbols/SimpleFillSymbol",
|
||||
"esri/urlUtils"],
|
||||
function (Evented, Deferred, all, declare, array, domAttr, domStyle, query,
|
||||
esriConfig, GraphicsLayer, Graphic, SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol, urlUtils) {
|
||||
esriConfig, GraphicsLayer, Graphic, esriRequest, SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol, urlUtils) {
|
||||
"use strict";
|
||||
return declare("O.esri.Edit.OfflineFeaturesManager", [Evented],
|
||||
{
|
||||
_onlineStatus: "online",
|
||||
_featureLayers: {},
|
||||
_featureCollectionUsageFlag: false, // if a feature collection was used to create the feature layer.
|
||||
_editStore: new O.esri.Edit.EditStore(),
|
||||
|
||||
ONLINE: "online", // all edits will directly go to the server
|
||||
@ -37,7 +39,7 @@ define([
|
||||
|
||||
ATTACHMENTS_DB_NAME: "attachments_store", //Sets attachments database name
|
||||
ATTACHMENTS_DB_OBJECTSTORE_NAME: "attachments",
|
||||
// NOTE: attachments don't have the same issues as Graphics as related to UIDs.
|
||||
// NOTE: attachments don't have the same issues as Graphics as related to UIDs (e.g. the need for DB_UID).
|
||||
// You can manually create a graphic, but it would be very rare for someone to
|
||||
// manually create an attachment. So, we don't provide a public property for
|
||||
// the attachments database UID.
|
||||
@ -50,7 +52,8 @@ define([
|
||||
EDITS_SENT_ERROR: "edits-sent-error", // ...there was a problem with one or more edits!
|
||||
ALL_EDITS_SENT: "all-edits-sent", // ...after going online and there are no pending edits in the queue
|
||||
ATTACHMENT_ENQUEUED: "attachment-enqueued",
|
||||
ATTACHMENTS_SENT: "attachments-sent"
|
||||
ATTACHMENTS_SENT: "attachments-sent",
|
||||
EXTEND_COMPLETE: "extend-complete" // ...when the libary has completed its initialization
|
||||
},
|
||||
|
||||
/**
|
||||
@ -98,23 +101,44 @@ define([
|
||||
* @returns deferred
|
||||
*/
|
||||
extend: function (layer, callback, dataStore) {
|
||||
|
||||
var extendPromises = []; // deferred promises related to initializing this method
|
||||
|
||||
var self = this;
|
||||
layer.offlineExtended = true; // to identify layer has been extended
|
||||
|
||||
// NOTE: At v2.6.1 we've discovered that not all feature layers support objectIdField.
|
||||
// However, we want to try to be consistent here with how the library is managing Ids.
|
||||
// So, we force the layer.objectIdField to DB_UID. This should be consistent with
|
||||
// However, to try to be consistent here with how the library is managing Ids
|
||||
// we force the layer.objectIdField to DB_UID. This should be consistent with
|
||||
// how esri.Graphics assign a unique ID to a graphic. If it is not, then this
|
||||
// library will break and we'll have to re-architect how we manage UIDs.
|
||||
// library will break and we'll have to re-architect how it manages UIDs.
|
||||
layer.objectIdField = this.DB_UID;
|
||||
|
||||
var url = null;
|
||||
|
||||
// There have been reproducible use cases showing when a browser is restarted offline that
|
||||
// for some reason the layer.url may be undefined.
|
||||
// This is an attempt to minimize the possibility of that situation causing errors.
|
||||
if(layer.url) {
|
||||
url = layer.url;
|
||||
// we keep track of the FeatureLayer object
|
||||
this._featureLayers[layer.url] = layer;
|
||||
}
|
||||
|
||||
// This is a potentially brittle solution to detecting if a feature layer collection
|
||||
// was used to create the feature layer.
|
||||
// Is there a better way??
|
||||
if(layer._mode.featureLayer.hasOwnProperty("_collection")){
|
||||
// This means a feature collection was used to create the feature layer and it will
|
||||
// require different handling when running applyEdit()
|
||||
this._featureCollectionUsageFlag = true;
|
||||
}
|
||||
|
||||
// Initialize the database as well as set offline data.
|
||||
if(!this._editStore._isDBInit) {
|
||||
this._initializeDB(dataStore,callback);
|
||||
extendPromises.push(this._initializeDB(dataStore, url));
|
||||
}
|
||||
|
||||
// we keep track of the FeatureLayer object
|
||||
this._featureLayers[layer.url] = layer;
|
||||
|
||||
// replace the applyEdits() method
|
||||
layer._applyEdits = layer.applyEdits;
|
||||
|
||||
@ -132,7 +156,7 @@ define([
|
||||
3. remove an attachment that is already in the server... (DONE)
|
||||
4. remove an attachment that is not in the server yet (DONE)
|
||||
5. update an existing attachment to an existing feature (DONE)
|
||||
6. update a new attachment (NOT YET)
|
||||
6. update a new attachment (DONE)
|
||||
|
||||
concerns:
|
||||
- manage the relationship between offline features and attachments: what if the user wants to add
|
||||
@ -140,9 +164,6 @@ define([
|
||||
the feature is sent to the server and receives a final objectid we replace the temporary negative id
|
||||
by its final objectid (DONE)
|
||||
- what if the user deletes an offline feature that had offline attachments? we need to discard the attachment (DONE)
|
||||
|
||||
pending tasks:
|
||||
- check for hasAttachments attribute in the FeatureLayer (NOT YET)
|
||||
*/
|
||||
|
||||
//
|
||||
@ -281,7 +302,7 @@ define([
|
||||
}
|
||||
|
||||
if (!self.attachmentsStore) {
|
||||
console.log("in order to support attachments you need to call initAttachments() method of offlineFeaturesManager");
|
||||
console.error("in order to support attachments you need to call initAttachments() method of offlineFeaturesManager");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -465,8 +486,7 @@ define([
|
||||
all(promises).then(function (r) {
|
||||
// Make sure all edits were successful. If not throw an error.
|
||||
var success = true;
|
||||
var length = r.length;
|
||||
for (var v = 0; v < length; v++) {
|
||||
for (var v = 0; v < r.length; v++) {
|
||||
if (r[v] === false) {
|
||||
success = false;
|
||||
}
|
||||
@ -720,7 +740,7 @@ define([
|
||||
/* internal methods */
|
||||
|
||||
/**
|
||||
* Pushes an DELETE request to the database after it's been validated
|
||||
* Pushes a DELETE request to the database after it's been validated
|
||||
* @param layer
|
||||
* @param deleteEdit
|
||||
* @param operation
|
||||
@ -1032,6 +1052,33 @@ define([
|
||||
|
||||
_initPhantomLayer();
|
||||
|
||||
// We are currently only passing in a single deferred.
|
||||
all(extendPromises).then(function (r) {
|
||||
if(r.length === 0){
|
||||
callback(true, null);
|
||||
}
|
||||
else if(r[0].success && !url){
|
||||
|
||||
// This functionality is specifically for offline restarts
|
||||
// and attempts to retrieve a feature layer url.
|
||||
// It's a hack because layer.toJson() doesn't convert layer.url.
|
||||
this._editStore.getFeatureLayerJSON(function(success,message){
|
||||
if(success) {
|
||||
this._featureLayers[message.__featureLayerURL] = layer;
|
||||
layer.url = message.__featureLayerURL;
|
||||
callback(true, null);
|
||||
}
|
||||
else {
|
||||
console.error("getFeatureLayerJSON() failed.");
|
||||
callback(false, message);
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
else if(r[0].success){
|
||||
callback(true, null);
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
}, // extend
|
||||
|
||||
/**
|
||||
@ -1051,7 +1098,7 @@ define([
|
||||
console.log("offlineFeaturesManager going online");
|
||||
this._onlineStatus = this.RECONNECTING;
|
||||
this._replayStoredEdits(function (success, responses) {
|
||||
var result = {features: {success: success, responses: responses}};
|
||||
var result = {success: success, responses: responses};
|
||||
this._onlineStatus = this.ONLINE;
|
||||
if (this.attachmentsStore != null) {
|
||||
console.log("sending attachments");
|
||||
@ -1102,13 +1149,16 @@ define([
|
||||
*/
|
||||
getFeatureLayerJSONDataStore: function(callback){
|
||||
if(!this._editStore._isDBInit){
|
||||
this._initializeDB(null,function(success) {
|
||||
if(success){
|
||||
|
||||
this._initializeDB(null,null).then(function(result){
|
||||
if(result.success){
|
||||
this._editStore.getFeatureLayerJSON(function(success,message){
|
||||
callback(success,message);
|
||||
});
|
||||
}
|
||||
}.bind(this));
|
||||
}.bind(this), function(err){
|
||||
callback(false, err);
|
||||
});
|
||||
}
|
||||
else {
|
||||
this._editStore.getFeatureLayerJSON(function(success,message){
|
||||
@ -1120,12 +1170,16 @@ define([
|
||||
/* internal methods */
|
||||
|
||||
/**
|
||||
* Intialize the database and push featureLayer JSON to DB if required
|
||||
* Initialize the database and push featureLayer JSON to DB if required.
|
||||
* NOTE: also stores feature layer url in hidden dataStore property dataStore.__featureLayerURL.
|
||||
* @param dataStore Object
|
||||
* @param url Feature Layer's url. This is used by this library for internal feature identification.
|
||||
* @param callback
|
||||
* @private
|
||||
*/
|
||||
_initializeDB: function(dataStore,callback){
|
||||
//_initializeDB: function(dataStore,url,callback){
|
||||
_initializeDB: function(dataStore,url){
|
||||
var deferred = new Deferred();
|
||||
|
||||
var editStore = this._editStore;
|
||||
|
||||
@ -1150,22 +1204,32 @@ define([
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
if (typeof dataStore === "object" && result === true && (dataStore !== undefined) && (dataStore !== null)) {
|
||||
|
||||
// Add a hidden property to hold the feature layer's url
|
||||
// When converting a feature layer to json (layer.toJson()) we lose this information.
|
||||
// This library needs to know the feature layer url.
|
||||
if(url) {
|
||||
dataStore.__featureLayerURL = url;
|
||||
}
|
||||
|
||||
editStore.pushFeatureLayerJSON(dataStore, function (success, err) {
|
||||
if (success) {
|
||||
callback(true, null);
|
||||
deferred.resolve({success:true, error: null});
|
||||
}
|
||||
else {
|
||||
callback(false, err);
|
||||
deferred.reject({success:false, error: err});
|
||||
}
|
||||
});
|
||||
}
|
||||
else if(result){
|
||||
callback(true, null);
|
||||
deferred.resolve({success:true, error: null});
|
||||
}
|
||||
else{
|
||||
callback(false, error);
|
||||
deferred.reject({success:false, error: null});
|
||||
}
|
||||
});
|
||||
|
||||
return deferred;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1413,23 +1477,7 @@ define([
|
||||
attachments.forEach(function (attachment) {
|
||||
console.log("sending attachment", attachment.id, "to feature", attachment.featureId);
|
||||
|
||||
var uploadAttachmentComplete =
|
||||
this._uploadAttachment(attachment);
|
||||
//.then(function (uploadResult) {
|
||||
// if (uploadResult.addAttachmentResult && uploadResult.addAttachmentResult.success === true) {
|
||||
// console.log("upload success", uploadResult.addAttachmentResult.success);
|
||||
// return this._deleteAttachment(attachment.id, uploadResult);
|
||||
// }
|
||||
// else {
|
||||
// console.log("upload failed", uploadResult);
|
||||
// return null;
|
||||
// }
|
||||
//}.bind(this),
|
||||
//function (err) {
|
||||
// console.log("failed uploading attachment", attachment);
|
||||
// return null;
|
||||
//}
|
||||
//);
|
||||
var uploadAttachmentComplete = this._uploadAttachment(attachment);
|
||||
promises.push(uploadAttachmentComplete);
|
||||
}, this);
|
||||
console.log("promises", promises.length);
|
||||
@ -1444,20 +1492,6 @@ define([
|
||||
callback && callback(true, uploadResults,dbResults);
|
||||
}
|
||||
});
|
||||
//results.forEach(function(value){
|
||||
// if(value.attachmentResult.success){
|
||||
// // Delete an attachment from the database if it was successfully
|
||||
// // submitted to the server.
|
||||
// self._deleteAttachmentFromDB(value.id,null).then(function(result){
|
||||
// if(result.success){
|
||||
// callback && callback(true, results);
|
||||
// }
|
||||
// else{
|
||||
// callback && callback(false, results);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
//});
|
||||
},
|
||||
function (err) {
|
||||
console.log("error!", err);
|
||||
@ -1505,10 +1539,6 @@ define([
|
||||
if (attachmentsStore == null && layer.hasAttachments) {
|
||||
console.log("NOTICE: you may need to run OfflineFeaturesManager.initAttachments(). Check the Attachments doc for more info. Layer id: " + layer.id + " accepts attachments");
|
||||
}
|
||||
else if(layer.hasAttachments === false){
|
||||
console.error("WARNING: Layer " + layer.id + "doesn't seem to accept attachments. Recheck the layer permissions.");
|
||||
callback(false,"WARNING: Attachments not supported in layer: " + layer.id);
|
||||
}
|
||||
|
||||
// Assign the attachmentsStore to the layer as a private var so we can access it from
|
||||
// the promises applyEdits() method.
|
||||
@ -1547,7 +1577,13 @@ define([
|
||||
break;
|
||||
}
|
||||
|
||||
promises[n] = that._internalApplyEdits(layer, tempArray[n].id, tempObjectIds, adds, updates, deletes);
|
||||
if(that._featureCollectionUsageFlag){
|
||||
// Note: when the feature layer is created with a feature collection we have to handle applyEdits() differently
|
||||
promises[n] = that._internalApplyEditsFeatureCollection(layer, tempArray[n].id, tempObjectIds, adds, updates, deletes);
|
||||
}
|
||||
else {
|
||||
promises[n] = that._internalApplyEdits(layer, tempArray[n].id, tempObjectIds, adds, updates, deletes);
|
||||
}
|
||||
}
|
||||
|
||||
// wait for all requests to finish
|
||||
@ -1732,7 +1768,7 @@ define([
|
||||
},
|
||||
|
||||
/**
|
||||
* Executes the _applyEdits() method
|
||||
* Executes the _applyEdits() method when a feature layer is created using a REST endpoint
|
||||
* @param layer
|
||||
* @param id the unique id that identifies the Graphic in the database
|
||||
* @param tempObjectIds
|
||||
@ -1787,6 +1823,126 @@ define([
|
||||
return dfd.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Executes the _applyEdits() method when a feature layer is created using a feature collection.
|
||||
* This works around specific behaviors in esri.layers.FeatureLayer when using the pattern
|
||||
* new FeatureLayer(featureCollectionObject).
|
||||
*
|
||||
* Details on the specific behaviors can be found here:
|
||||
* https://developers.arcgis.com/javascript/jsapi/featurelayer-amd.html#featurelayer2
|
||||
*
|
||||
* @param layer
|
||||
* @param id
|
||||
* @param tempObjectIds
|
||||
* @param adds
|
||||
* @param updates
|
||||
* @param deletes
|
||||
* @returns {*|r}
|
||||
* @private
|
||||
*/
|
||||
_internalApplyEditsFeatureCollection: function (layer, id, tempObjectIds, adds, updates, deletes) {
|
||||
var dfd = new Deferred();
|
||||
|
||||
this._makeEditRequest(layer.url, adds, updates, deletes,
|
||||
function (addResults, updateResults, deleteResults) {
|
||||
layer._phantomLayer.clear();
|
||||
|
||||
var newObjectIds = addResults.map(function (r) {
|
||||
return r.objectId;
|
||||
});
|
||||
|
||||
// We use a different pattern if the attachmentsStore is valid and the layer has attachments
|
||||
if (layer._attachmentsStore != null && layer.hasAttachments && tempObjectIds.length > 0) {
|
||||
layer._replaceFeatureIds(tempObjectIds, newObjectIds, function (success) {
|
||||
dfd.resolve({
|
||||
id: id,
|
||||
layer: layer.url,
|
||||
tempId: tempObjectIds, // let's us internally match an ADD to it's new ObjectId
|
||||
addResults: addResults,
|
||||
updateResults: updateResults,
|
||||
deleteResults: deleteResults
|
||||
}); // wrap three arguments in a single object
|
||||
});
|
||||
}
|
||||
else {
|
||||
dfd.resolve({
|
||||
id: id,
|
||||
layer: layer.url,
|
||||
tempId: tempObjectIds, // let's us internally match an ADD to it's new ObjectId
|
||||
addResults: addResults,
|
||||
updateResults: updateResults,
|
||||
deleteResults: deleteResults
|
||||
}); // wrap three arguments in a single object
|
||||
}
|
||||
},
|
||||
function (error) {
|
||||
layer.onEditsComplete = layer.__onEditsComplete;
|
||||
delete layer.__onEditsComplete;
|
||||
|
||||
dfd.reject(error);
|
||||
}
|
||||
);
|
||||
return dfd.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Used when a feature layer is created with a feature collection.
|
||||
*
|
||||
* In the current version of the ArcGIS JSAPI 3.12+ the applyEdit() method doesn't send requests
|
||||
* to the server when a feature layer is created with a feature collection.
|
||||
*
|
||||
* The use case for using this is: clean start app > go offline and make edits > offline restart browser >
|
||||
* go online.
|
||||
*
|
||||
* @param url
|
||||
* @param adds
|
||||
* @param updates
|
||||
* @param deletes
|
||||
* @returns {*|r}
|
||||
* @private
|
||||
*/
|
||||
_makeEditRequest: function(url,adds, updates, deletes, callback, errback) {
|
||||
|
||||
//var dfd = new Deferred();
|
||||
|
||||
var data = new FormData();
|
||||
data.append("f", "json");
|
||||
if(adds.length > 0) {
|
||||
data.append("adds", JSON.stringify(adds));
|
||||
}
|
||||
if(updates.length > 0) {
|
||||
data.append("updates", JSON.stringify(updates));
|
||||
}
|
||||
if(deletes.length > 0) {
|
||||
data.append("deletes", JSON.stringify(deletes));
|
||||
}
|
||||
|
||||
var req = new XMLHttpRequest();
|
||||
req.open("POST", url + "/applyEdits", true);
|
||||
req.onload = function()
|
||||
{
|
||||
if( req.status === 200 && req.responseText !== "")
|
||||
{
|
||||
var obj = JSON.parse(this.response);
|
||||
//dfd.resolve(obj);
|
||||
callback(obj.addResults, obj.updateResults, obj.deleteResults);
|
||||
//callback(this.response);
|
||||
//Object.keys(this.response).forEach(function(key) {
|
||||
// console.log(key, this.response[key]);
|
||||
//});
|
||||
}
|
||||
};
|
||||
req.onerror = function(e)
|
||||
{
|
||||
console.log("_getTileInfoPrivate failed: " + e);
|
||||
errback(e);
|
||||
//dfd.error(e);
|
||||
};
|
||||
req.send(data);
|
||||
|
||||
//return dfd.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Deprecated @ v2.5. Internal-use only
|
||||
* @returns {string}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "offline-editor-js",
|
||||
"version": "2.7.1",
|
||||
"version": "2.8",
|
||||
"description": "Lightweight set of libraries for working offline with map tiles and ArcGIS feature services",
|
||||
"author": "Andy Gup <agup@esri.com> (http://blog.andygup.net)",
|
||||
"license": "Apache 2",
|
||||
|
||||
@ -143,8 +143,8 @@
|
||||
<div class="row">
|
||||
<div class="col-xs-10">
|
||||
<div class="form form-group btn-group" data-toggle="buttons">
|
||||
<button class="btn btn-success" id="btn-get-tiles">1. Download Tiles</button>
|
||||
<button class="btn btn-success" disabled id="btn-online-offline">2. Go Offline</button>
|
||||
<button class="btn btn-primary" id="btn-get-tiles">1. Download Tiles</button>
|
||||
<button class="btn btn-primary" id="btn-online-offline">2. Go Offline</button>
|
||||
</div>
|
||||
<span class="span-pending">Pending Edits <span id="span-pending-edits" class="badge">0</span></span>
|
||||
<img id="loader-gif" src="images/loading.gif"/>
|
||||
@ -185,6 +185,7 @@
|
||||
var map = null;
|
||||
var _isOnline = true;
|
||||
var defaultSymbol;
|
||||
var _listener;
|
||||
|
||||
// Variables for editing handling
|
||||
var currentFeature, busStopFeatureLayer = null, offlineFeaturesManager = null;
|
||||
@ -221,7 +222,7 @@
|
||||
* This is a utility check to 100% validate if the application is online or
|
||||
* offline prior to launching any map functionality.
|
||||
*/
|
||||
verifyOnline(function(result) {
|
||||
validateOnline(function(result) {
|
||||
if(result) {
|
||||
_isOnline = true;
|
||||
setUIOnline();
|
||||
@ -271,9 +272,6 @@
|
||||
*/
|
||||
function startMap() {
|
||||
|
||||
//Make sure map shows up after a browser refresh
|
||||
Offline.check();
|
||||
|
||||
tileLayer = new O.esri.Tiles.OfflineTileEnablerLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer",function(evt){
|
||||
console.log("Tile Layer initialized for offline. App state is: " + Offline.state);
|
||||
},_isOnline);
|
||||
@ -288,6 +286,10 @@
|
||||
sliderStyle: "small"
|
||||
});
|
||||
|
||||
map.on("load",function(evt) {
|
||||
_currentExtent = evt.map.extent;
|
||||
});
|
||||
|
||||
// Add our offline enabled tile layer to the map
|
||||
map.addLayer(tileLayer);
|
||||
|
||||
@ -301,8 +303,7 @@
|
||||
//on a mobile device.
|
||||
busStopFeatureLayer.setRenderer(new SimpleRenderer(defaultSymbol));
|
||||
|
||||
initFeatureUpdateEndListener();
|
||||
initMapLoadListener();
|
||||
_listener = busStopFeatureLayer.on("update-end",initFeatureUpdateEndListener);
|
||||
|
||||
map.addLayer(busStopFeatureLayer);
|
||||
}
|
||||
@ -315,62 +316,56 @@
|
||||
*/
|
||||
function initFeatureUpdateEndListener() {
|
||||
|
||||
busStopFeatureLayer.on("update-end",function(evt){
|
||||
_listener.remove();
|
||||
|
||||
//**************************************************
|
||||
//
|
||||
// This is where we detect an offline condition
|
||||
// within the lifecycle of the "mapping" application.
|
||||
// If we are offline then run our offline
|
||||
// specific code for reconstituting our map.
|
||||
//
|
||||
//**************************************************
|
||||
//**************************************************
|
||||
//
|
||||
// This is where we detect an offline condition
|
||||
// within the lifecycle of the "mapping" application.
|
||||
// If we are offline then run our offline
|
||||
// specific code for reconstituting our map.
|
||||
//
|
||||
//**************************************************
|
||||
|
||||
//
|
||||
// Extend the feature layer with offline capabilities.
|
||||
//
|
||||
//
|
||||
// Extend the feature layer with offline capabilities.
|
||||
//
|
||||
|
||||
initOfflineFeaturesMgr();
|
||||
initOfflineFeaturesMgr();
|
||||
|
||||
// If app is online then we ONLY need to extend the feature layer.
|
||||
if(_isOnline){
|
||||
extendFeatureLayer(_isOnline, function(success) {
|
||||
if(success){
|
||||
// If app is online then we ONLY need to extend the feature layer.
|
||||
if(_isOnline){
|
||||
extendFeatureLayer(_isOnline, function(success) {
|
||||
if(success){
|
||||
|
||||
// Set click listeners
|
||||
on(btnGetTiles,"click",downloadTiles);
|
||||
on(btnOnlineOffline, 'click', goOnlineOffline);
|
||||
// Set click listeners
|
||||
on(btnGetTiles,"click",downloadTiles);
|
||||
on(btnOnlineOffline, 'click', goOnlineOffline);
|
||||
|
||||
initPanZoomListeners();
|
||||
setFeatureLayerClickHandler();
|
||||
setModalPopupClickListeners();
|
||||
}
|
||||
else{
|
||||
alert("There was a problem initializing the map for offline.");
|
||||
}
|
||||
});
|
||||
}
|
||||
// If the app is offline then we need to retrieve the dataStore from OfflineFeaturesManager
|
||||
// and then extend the feature layer using that information.
|
||||
else {
|
||||
loadFeatureLayerOffline(function(success) {
|
||||
if(success) {
|
||||
extendFeatureLayer(_isOnline, function(success) {
|
||||
console.log("Feature Layer extended successfully OFFLINE!");
|
||||
});
|
||||
}
|
||||
else {
|
||||
alert("There was a problem initializing the map for offline.");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
initPanZoomListeners();
|
||||
setFeatureLayerClickHandler();
|
||||
setModalPopupClickListeners();
|
||||
}
|
||||
else{
|
||||
alert("There was a problem initializing the map for offline.");
|
||||
}
|
||||
});
|
||||
}
|
||||
// If the app is offline then we need to retrieve the dataStore from OfflineFeaturesManager
|
||||
// and then extend the feature layer using that information.
|
||||
else {
|
||||
loadFeatureLayerOffline(function(success) {
|
||||
if(success) {
|
||||
extendFeatureLayer(_isOnline, function(success) {
|
||||
console.log("Feature Layer extended successfully OFFLINE!");
|
||||
});
|
||||
}
|
||||
else {
|
||||
alert("There was a problem initializing the map for offline.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function initMapLoadListener() {
|
||||
map.on("load",function(evt) {
|
||||
_currentExtent = evt.map.extent;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -404,33 +399,33 @@
|
||||
function loadFeatureLayerOffline(callback) {
|
||||
offlineFeaturesManager.getFeatureLayerJSONDataStore(function(success,dataStore) {
|
||||
if(success){
|
||||
|
||||
// Use the feature layer returns from getFeatureDefinition() to reconstitute the layer
|
||||
busStopFeatureLayer = new FeatureLayer(JSON.parse(dataStore.featureLayerCollection), {
|
||||
mode: FeatureLayer.MODE_SNAPSHOT,
|
||||
outFields: ["GlobalID","BSID","ROUTES","STOPNAME"]
|
||||
});
|
||||
// We don't have to set any other properties on the layer because we are using it
|
||||
// in SNAPSHOT mode which downloads all features within the given extent.
|
||||
busStopFeatureLayer = new FeatureLayer(JSON.parse(dataStore.featureLayerCollection));
|
||||
|
||||
if(busStopFeatureLayer.url == null){
|
||||
busStopFeatureLayer.url = dataStore.featureLayerUrl;
|
||||
}
|
||||
|
||||
// Set the graphic symbols to red diamond to make it easy to click on them
|
||||
// on a mobile device.
|
||||
busStopFeatureLayer.setRenderer(new SimpleRenderer(defaultSymbol));
|
||||
|
||||
// If/when the update-end event has been thrown then let's finish initializing
|
||||
var mapListen = map.on("update-end",function(evt) {
|
||||
console.log("Feature has been added back to the map while offline.");
|
||||
on(btnGetTiles,"click",downloadTiles);
|
||||
on(btnOnlineOffline, 'click', goOnlineOffline);
|
||||
|
||||
setFeatureLayerClickHandler();
|
||||
setModalPopupClickListeners();
|
||||
|
||||
map.centerAt(dataStore.centerPt);
|
||||
map.setZoom(dataStore.zoom);
|
||||
|
||||
mapListen.remove();
|
||||
callback(true);
|
||||
});
|
||||
|
||||
map.addLayer(busStopFeatureLayer);
|
||||
|
||||
console.log("Feature has been added back to the map while offline.");
|
||||
on(btnGetTiles,"click",downloadTiles);
|
||||
on(btnOnlineOffline, 'click', goOnlineOffline);
|
||||
|
||||
setFeatureLayerClickHandler();
|
||||
setModalPopupClickListeners();
|
||||
|
||||
map.centerAt(dataStore.centerPt);
|
||||
map.setZoom(dataStore.zoom);
|
||||
|
||||
callback(true);
|
||||
}
|
||||
else{
|
||||
alert("There was a problem retrieving feature layer options object. " + dataStore);
|
||||
@ -461,16 +456,16 @@
|
||||
// Refer to "Using the Proxy Page" for more information: https://developers.arcgis.com/en/javascript/jshelp/ags_proxy.html
|
||||
offlineFeaturesManager.proxyPath = null;
|
||||
|
||||
offlineFeaturesManager.on(offlineFeaturesManager.events.EDITS_ENQUEUED, editsEnqueued);
|
||||
offlineFeaturesManager.on(offlineFeaturesManager.events.EDITS_ENQUEUED, updateStatus);
|
||||
offlineFeaturesManager.on(offlineFeaturesManager.events.EDITS_SENT, updateStatus);
|
||||
offlineFeaturesManager.on(offlineFeaturesManager.events.ALL_EDITS_SENT, allEditsSent);
|
||||
offlineFeaturesManager.on(offlineFeaturesManager.events.ALL_EDITS_SENT, updateStatus);
|
||||
offlineFeaturesManager.on(offlineFeaturesManager.events.EDITS_SENT_ERROR, editsError);
|
||||
}
|
||||
|
||||
function extendFeatureLayer(online,callback){
|
||||
var featureLayerJSON = null;
|
||||
|
||||
if(online === true) {
|
||||
if(online) {
|
||||
|
||||
// This object contains everything we need to restore the map and feature layer after an offline restart
|
||||
//
|
||||
@ -488,16 +483,26 @@
|
||||
console.log("offlineFeaturesManager initialized.");
|
||||
|
||||
// This sets listeners to detect if the app goes online or offline.
|
||||
Offline.check();
|
||||
Offline.on('up', goOnline);
|
||||
Offline.on('down', goOffline);
|
||||
|
||||
// If the app is online then force offlineFeaturesManager to its online state
|
||||
// This will force the library to check for pending edits and attempt to
|
||||
// resend them to the Feature Service.
|
||||
if(_isOnline == true){
|
||||
offlineFeaturesManager.goOnline();
|
||||
}
|
||||
// If the app is online then force offlineFeaturesManager to its online state
|
||||
// This will force the library to check for pending edits and attempt to
|
||||
// resend them to the Feature Service.
|
||||
if(_isOnline){
|
||||
offlineFeaturesManager.goOnline(function(result){
|
||||
if(!result.success){
|
||||
alert("There was a problem when attempting to go back online.");
|
||||
}
|
||||
else {
|
||||
updateStatus();
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
offlineFeaturesManager.goOffline();
|
||||
updateStatus();
|
||||
}
|
||||
|
||||
callback(true);
|
||||
}
|
||||
@ -505,7 +510,7 @@
|
||||
callback(false);
|
||||
alert("Unable to initialize the database. " + error);
|
||||
}
|
||||
},/* This is the optional offline configuration property */featureLayerJSON);
|
||||
}.bind(this),/* This is the optional offline configuration property */featureLayerJSON);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -572,10 +577,12 @@
|
||||
}
|
||||
|
||||
function getFeatureLayerJSON() {
|
||||
|
||||
return {
|
||||
"featureLayerCollection": JSON.stringify(busStopFeatureLayer.toJson()),
|
||||
"zoomLevel": map.getZoom(),
|
||||
"centerPt" : (map.extent.getCenter()).toJson()
|
||||
"centerPt" : (map.extent.getCenter()).toJson(),
|
||||
"featureLayerUrl": busStopFeatureLayer.url
|
||||
}
|
||||
}
|
||||
|
||||
@ -644,7 +651,6 @@
|
||||
}
|
||||
else {
|
||||
globalState.downloadState = 'downloaded';
|
||||
btnOnlineOffline.disabled = false;
|
||||
alert("Tile download complete");
|
||||
}
|
||||
|
||||
@ -669,6 +675,10 @@
|
||||
|
||||
loading.style.visibility = "visible";
|
||||
|
||||
if(busStopFeatureLayer && busStopFeatureLayer.offlineExtended) {
|
||||
|
||||
}
|
||||
|
||||
offlineFeaturesManager.goOnline(function(success,error) {
|
||||
if(error === undefined) {
|
||||
setUIOnline();
|
||||
@ -735,33 +745,22 @@
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces a check of the Offline.js state
|
||||
*/
|
||||
function forceInternalOfflineCheck() {
|
||||
Offline.check();
|
||||
if(Offline.state == "up") {
|
||||
goOnline();
|
||||
}
|
||||
if(Offline.state == "down") {
|
||||
goOffline();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts a manual http request to verify if app is online or offline.
|
||||
* Use this in conjunction with the offline checker library: offline.min.js
|
||||
* @param callback
|
||||
*/
|
||||
function verifyOnline(callback) {
|
||||
function validateOnline(callback) {
|
||||
var req = new XMLHttpRequest();
|
||||
req.open("GET", "http://esri.github.io/offline-editor-js/samples/images/blue-pin.png?" + (Math.floor(Math.random() * 1000000000)), true);
|
||||
req.onload = function() {
|
||||
if( req.status === 200 && req.responseText !== "") {
|
||||
req = null;
|
||||
callback(true);
|
||||
}
|
||||
else {
|
||||
console.log("verifyOffline failed");
|
||||
req = null;
|
||||
callback(false);
|
||||
}
|
||||
};
|
||||
@ -778,28 +777,19 @@
|
||||
* ***********************************************å
|
||||
*/
|
||||
|
||||
function editsEnqueued() {
|
||||
|
||||
busStopFeatureLayer.pendingEditsCount(function(count) {
|
||||
pendingEdits.innerHTML = count;
|
||||
});
|
||||
}
|
||||
|
||||
function allEditsSent(){
|
||||
|
||||
busStopFeatureLayer.pendingEditsCount(function(count) {
|
||||
pendingEdits.innerHTML = count;
|
||||
});
|
||||
}
|
||||
|
||||
function editsError(evt) {
|
||||
alert("There was a problem. Not all edits were synced with the server. " + JSON.stringify(evt));
|
||||
}
|
||||
|
||||
function updateStatus() {
|
||||
busStopFeatureLayer.pendingEditsCount(function(count) {
|
||||
pendingEdits.innerHTML = count;
|
||||
});
|
||||
|
||||
// Depending on application life cycle busStopFeatureLayer may or may not be extended
|
||||
// So we have to protect pendingEditsCount() from throwing an "is not a function" error.
|
||||
if("pendingEditsCount" in busStopFeatureLayer) {
|
||||
busStopFeatureLayer.pendingEditsCount(function(count) {
|
||||
pendingEdits.innerHTML = count;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
"appHomePage": "appcache-features.html",
|
||||
"optimizedApiURL": "../samples/jsolib",
|
||||
"arcGISBaseURL": "http://js.arcgis.com/3.11",
|
||||
"version": "2.7.1",
|
||||
"version": "2.8",
|
||||
"private": true,
|
||||
"description": "manifest generator project",
|
||||
"repository": {
|
||||
|
||||
@ -631,9 +631,9 @@ describe("Attachments", function()
|
||||
console.log("went online");
|
||||
expect(g_offlineFeaturesManager.getOnlineStatus()).toBe(g_offlineFeaturesManager.ONLINE);
|
||||
expect(listener).toHaveBeenCalled();
|
||||
expect(result.features.success).toBeTruthy();
|
||||
expect(result.success).toBeTruthy();
|
||||
expect(result.attachments.success).toBeTruthy();
|
||||
expect(Object.keys(result.features.responses).length).toBe(1);
|
||||
expect(Object.keys(result.responses).length).toBe(1);
|
||||
expect(Object.keys(result.attachments.responses).length).toBe(4);
|
||||
|
||||
var attachmentResults = result.attachments.responses;
|
||||
@ -644,8 +644,8 @@ describe("Attachments", function()
|
||||
//expect(attachmentResults[1].addAttachmentResult).not.toBeUndefined();
|
||||
//expect(attachmentResults[1].addAttachmentResult.success).toBeTruthy();
|
||||
|
||||
expect(result.features.responses[0]).not.toBeUndefined();
|
||||
var featureResults = result.features.responses[0];
|
||||
expect(result.responses[0]).not.toBeUndefined();
|
||||
var featureResults = result.responses[0];
|
||||
expect(featureResults.addResults.length).toBe(1);
|
||||
expect(featureResults.updateResults.length).toBe(0);
|
||||
expect(featureResults.deleteResults.length).toBe(0);
|
||||
|
||||
@ -1111,14 +1111,14 @@ describe("Offline Editing", function()
|
||||
console.log("Library is now back online");
|
||||
expect(g_offlineFeaturesManager.getOnlineStatus()).toBe(g_offlineFeaturesManager.ONLINE);
|
||||
expect(listener).toHaveBeenCalled();
|
||||
expect(results.features.success).toBeTruthy();
|
||||
expect(results.success).toBeTruthy();
|
||||
|
||||
//console.log("RESPONSES " + JSON.stringify(responses) + ", " + JSON.stringify(results))
|
||||
|
||||
expect(Object.keys(results.features.responses).length).toBe(5);
|
||||
for (var key in results.features.responses) {
|
||||
expect(Object.keys(results.responses).length).toBe(5);
|
||||
for (var key in results.responses) {
|
||||
|
||||
var response = results.features.responses[key];
|
||||
var response = results.responses[key];
|
||||
|
||||
console.log("RESPONSE " + JSON.stringify(response))
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user