Merge pull request #465 from andygup/gh-pages

Update gh-pages
This commit is contained in:
Andy 2016-05-12 09:32:33 -06:00
commit 075aba6f45
18 changed files with 432 additions and 183 deletions

View File

@ -1,5 +1,17 @@
# offline-editor-js - Changelog
## Version 3.2.0 - May 11, 2016
No breaking changes.
**Enhancements**
* Added CleanFeatureService.js util for deleting all features in a demo feature service
**Bug Fixes**
* Closes #461 - proxyPath not respected in OfflineEditAdvanced. Also fixed proxyPath in OfflineEditBasic
* Closes #462 - getNextLowestTempId does not exist in editStorePOLS.
* Closes #463 - sample feature service no longer allows editing. Complete rewrite.
## Version 3.1.0 - April 21, 2016
No breaking changes.

View File

@ -16,9 +16,11 @@ This project is also available on npm: **[https://www.npmjs.com/package/esri-off
This repo contains the following libraries in the `/dist` directory. The use of `basic` in the name indicates intermittent offline-only, and `advanced` indicates the library can be used for both intermittent and full offline.
Reference URLs are provided for developement only. It's recommended to use a CDN or host your own.
Use_Case | Name, Description and gh-pages URL
--- | ---
Basic editing | **`offline-edit-basic-min.js`** Simple, lightweight *(14k minimized)* offline editing library that automatically caches adds, updates and deletes when the internet is temporarily interrupted.<br><br>[`http://esri.github.io/offline-editor-js/dist/offline-edit-basic-min.js`](http://esri.github.io/offline-editor-js/dist/offline-edit-basic-min.js)
Basic editing | **`offline-edit-basic-min.js`** Simple, lightweight *(15k minimized)* offline editing library that automatically caches adds, updates and deletes when the internet is temporarily interrupted.<br><br>[`http://esri.github.io/offline-editor-js/dist/offline-edit-basic-min.js`](http://esri.github.io/offline-editor-js/dist/offline-edit-basic-min.js)
Advanced editing | **`offline-edit-advanced-min.js`** Used for intermittent and full offline editing workflows. Also includes limited support for attachments. <br><br>[`http://esri.github.io/offline-editor-js/dist/offline-edit-advanced-min.js`](http://esri.github.io/offline-editor-js/dist/offline-edit-advanced-min.js)
Basic map tiles | **`offline-tiles-basic-min.js`** Caches map tiles for simple, intermittent-only offline workflows. Use this library with ArcGIS Online Web maps as well as with tiled map services.<br><br> [`http://esri.github.io/offline-editor-js/dist/offline-tiles-basic-min.js`](http://esri.github.io/offline-editor-js/dist/offline-tiles-basic-min.js)
Advanced map tiles | **`offline-tiles-advanced-min.js`** Used for intermittent and full offline tile caching. Extends any ArcGIS Tiled Map Service. This library should be used in conjunction with an HTML5 Application Cache Manifest coding pattern.<br><br>[`http://esri.github.io/offline-editor-js/dist/offline-tiles-advanced-min.js`](http://esri.github.io/offline-editor-js/dist/offline-tiles-advanced-min.js)
@ -83,7 +85,7 @@ Go __[here](https://github.com/Esri/offline-editor-js/wiki/FAQ)__ for answers to
##Dependencies
* [ArcGIS API for JavaScript (v3.12+)](https://developers.arcgis.com/javascript/)
* [ArcGIS API for JavaScript (v3.14+)](https://developers.arcgis.com/javascript/)
* [Offline.js](http://github.hubspot.com/offline/docs/welcome/) - it allows detection of the online/offline condition and provides events to hook callbacks on when this condition changes
* Node.js required for building the source
* [IndexedDBShim](https://github.com/axemclion/IndexedDBShim) - polyfill to simulate indexedDB functionality in browsers/platforms where it is not supported notably older versions desktop Safari and iOS Safari.

View File

@ -123,9 +123,9 @@ this._editStore.deletePhantomGraphic(c,function(a,b){a?g.resolve({success:!0,err
if(b.length>0&&(e.forEach(b,function(a){a.hasOwnProperty("infoTemplate")&&delete a.infoTemplate},this),i="&adds="+JSON.stringify(b)),c.length>0&&(e.forEach(c,function(a){a.hasOwnProperty("infoTemplate")&&delete a.infoTemplate},this),j="&updates="+JSON.stringify(c)),d.length>0){var l=d[0].attributes[this.DB_UID]
k="&deletes="+l}var m=h+i+j+k
a.hasOwnProperty("credential")&&a.credential&&a.credential.hasOwnProperty("token")&&a.credential.token&&(m=m+"&token="+a.credential.token)
var n=new XMLHttpRequest
n.open("POST",a.url+"/applyEdits",!0),n.setRequestHeader("Content-type","application/x-www-form-urlencoded"),n.onload=function(){if(200===n.status&&""!==n.responseText)try{var a=JSON.parse(this.response)
f(a.addResults,a.updateResults,a.deleteResults)}catch(b){g("Unable to parse xhr response",n)}},n.onerror=function(a){g(a)},n.ontimeout=function(){g("xhr timeout error")},n.timeout=this._defaultXhrTimeout,n.send(m)},_parseResponsesArray:function(a){var c=new b,d=0
var n=this.proxyPath?this.proxyPath+"?"+a.url:a.url,o=new XMLHttpRequest
o.open("POST",n+"/applyEdits",!0),o.setRequestHeader("Content-type","application/x-www-form-urlencoded"),o.onload=function(){if(200===o.status&&""!==o.responseText)try{var a=JSON.parse(this.response)
f(a.addResults,a.updateResults,a.deleteResults)}catch(b){g("Unable to parse xhr response",o)}},o.onerror=function(a){g(a)},o.ontimeout=function(){g("xhr timeout error")},o.timeout=this._defaultXhrTimeout,o.send(m)},_parseResponsesArray:function(a){var c=new b,d=0
for(var e in a)a.hasOwnProperty(e)&&(a[e].addResults.map(function(a){a.success||d++}),a[e].updateResults.map(function(a){a.success||d++}),a[e].deleteResults.map(function(a){a.success||d++}))
return d>0?c.resolve(!1):c.resolve(!0),c.promise}})}),"undefined"!=typeof O?O.esri.Edit={}:(O={},O.esri={Edit:{}}),O.esri.Edit.EditStore=function(){"use strict"
this._db=null,this._isDBInit=!1,this.dbName="features_store",this.objectStoreName="features",this.objectId="objectid",this.ADD="add",this.UPDATE="update",this.DELETE="delete",this.FEATURE_LAYER_JSON_ID="feature-layer-object-1001",this.FEATURE_COLLECTION_ID="feature-collection-object-1001",this.PHANTOM_GRAPHIC_PREFIX="phantom-layer",this._PHANTOM_PREFIX_TOKEN="|@|",this.isSupported=function(){return!!window.indexedDB},this.pushEdit=function(a,b,c,d){var e={id:b+"/"+c.attributes[this.objectId],operation:a,layer:b,type:c.geometry.type,graphic:c.toJson()}

View File

@ -1,4 +1,4 @@
/*! esri-offline-maps - v3.1.0 - 2016-04-21
/*! esri-offline-maps - v3.2.0 - 2016-05-12
* Copyright (c) 2016 Environmental Systems Research Institute, Inc.
* Apache License*/
// Configure offline/online detection
@ -2056,8 +2056,11 @@ define([
}
}
// Respect the proxyPath if one has been set (Added at v3.2.0)
var url = this.proxyPath ? this.proxyPath + "?" + layer.url : layer.url;
var req = new XMLHttpRequest();
req.open("POST", layer.url + "/applyEdits", true);
req.open("POST", url + "/applyEdits", true);
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
req.onload = function()
{
@ -2068,7 +2071,7 @@ define([
callback(obj.addResults, obj.updateResults, obj.deleteResults);
}
catch(err) {
console.error("EDIT REQUEST REPONSE WAS NOT SUCCESSFUL:", req);
console.error("EDIT REQUEST RESPONSE WAS NOT SUCCESSFUL:", req);
errback("Unable to parse xhr response", req);
}
}
@ -2735,7 +2738,7 @@ O.esri.Edit.EditStore = function () {
else {
callback(null, "no db");
}
},
};
/**
* Returns all the edits as a single Array via the callback

View File

@ -30,7 +30,7 @@ case g._editStore.UPDATE:d.operation==g._editStore.ADD&&(c.operation=g._editStor
break
case g._editStore.DELETE:var h=!0
d.operation==g._editStore.ADD&&a._deleteTemporaryFeature(c,function(a,b){a||(h=!1)}),f.resolve({success:h,graphic:c,operation:e})}else"Id not found"==d?f.resolve({success:!0,graphic:c,operation:e}):f.reject(c)}),f},a._deleteTemporaryFeature=function(b,c){g._editStore["delete"](a.url,b,function(a,b){c(a,b)})},a._getFilesFromForm=function(a){var b=[],c=e.filter(a.elements,function(a){return"file"===a.type})
return c.forEach(function(a){b.push.apply(b,a.files)},this),b},this._editStore.getNextLowestTempId(a,function(b,c){"success"===c?a._nextTempId=b:a._nextTempId=-1}),a._getNextTempId=function(){return this._nextTempId--},c(f).then(function(a){g._autoOfflineDetect&&(Offline.on("up",function(){g.goOnline(function(a,b){})}),Offline.on("down",function(){g.goOffline()})),d(!0,null)})},goOffline:function(){this._onlineStatus=this.OFFLINE},goOnline:function(a){this._onlineStatus=this.RECONNECTING,this._replayStoredEdits(function(b,c){this._onlineStatus=this.ONLINE,a&&a(b,c)}.bind(this))},getOnlineStatus:function(){return this._onlineStatus},_initializeDB:function(a){var c=new b,d=this._editStore
return c.forEach(function(a){b.push.apply(b,a.files)},this),b},a._getNextTempId=function(){return this._nextTempId--},c(f).then(function(b){b[0].success?(g._editStore.getNextLowestTempId(a,function(b,c){"success"===c?a._nextTempId=b:a._nextTempId=-1}),g._autoOfflineDetect&&(Offline.on("up",function(){g.goOnline(function(a,b){})}),Offline.on("down",function(){g.goOffline()})),d(!0,null)):d(!1,b[0].error)})},goOffline:function(){this._onlineStatus=this.OFFLINE},goOnline:function(a){this._onlineStatus=this.RECONNECTING,this._replayStoredEdits(function(b,c){this._onlineStatus=this.ONLINE,a&&a(b,c)}.bind(this))},getOnlineStatus:function(){return this._onlineStatus},_initializeDB:function(a){var c=new b,d=this._editStore
return d.dbName=this.DB_NAME,d.objectStoreName=this.DB_OBJECTSTORE_NAME,d.objectId=this.DB_UID,d.init(function(a,b){a?c.resolve({success:!0,error:null}):c.reject({success:!1,error:null})}),c},_replayStoredEdits:function(a){var b,d={},e=this,f=[],g=[],h=[],i=[],j=[],k=this._featureLayers,l=this._editStore
this._editStore.getAllEditsArray(function(n,o){if(n.length>0){j=n
for(var p=j.length,q=0;p>q;q++){b=k[j[q].layer],b.__onEditsComplete=b.onEditsComplete,b.onEditsComplete=function(){},f=[],g=[],h=[],i=[]
@ -56,9 +56,9 @@ return i.attributes={},i.attributes[this.DB_UID]=h,this._editStore["delete"](a.u
if(b.length>0&&(e.forEach(b,function(a){a.hasOwnProperty("infoTemplate")&&delete a.infoTemplate},this),i="&adds="+JSON.stringify(b)),c.length>0&&(e.forEach(c,function(a){a.hasOwnProperty("infoTemplate")&&delete a.infoTemplate},this),j="&updates="+JSON.stringify(c)),d.length>0){var l=d[0].attributes[this.DB_UID]
k="&deletes="+l}var m=h+i+j+k
a.hasOwnProperty("credential")&&a.credential&&a.credential.hasOwnProperty("token")&&a.credential.token&&(m=m+"&token="+a.credential.token)
var n=new XMLHttpRequest
n.open("POST",a.url+"/applyEdits",!0),n.setRequestHeader("Content-type","application/x-www-form-urlencoded"),n.onload=function(){if(200===n.status&&""!==n.responseText)try{var a=JSON.parse(this.response)
f(a.addResults,a.updateResults,a.deleteResults)}catch(b){g("Unable to parse xhr response",n)}},n.onerror=function(a){g(a)},n.ontimeout=function(){g("xhr timeout error")},n.timeout=this._defaultXhrTimeout,n.send(m)},_parseResponsesArray:function(a,b){var c=0
var n=this.proxyPath?this.proxyPath+"?"+a.url:a.url,o=new XMLHttpRequest
o.open("POST",n+"/applyEdits",!0),o.setRequestHeader("Content-type","application/x-www-form-urlencoded"),o.onload=function(){if(200===o.status&&""!==o.responseText)try{var a=JSON.parse(this.response)
f(a.addResults,a.updateResults,a.deleteResults)}catch(b){g("Unable to parse xhr response",o)}},o.onerror=function(a){g(a)},o.ontimeout=function(){g("xhr timeout error")},o.timeout=this._defaultXhrTimeout,o.send(m)},_parseResponsesArray:function(a,b){var c=0
for(var d in a)a.hasOwnProperty(d)&&(a[d].addResults.forEach(function(a){a.success||c++}),a[d].updateResults.forEach(function(a){a.success||c++}),a[d].deleteResults.forEach(function(a){a.success||c++}))
b(!(c>0))}})}),"undefined"!=typeof O?O.esri.Edit={}:(O={},O.esri={Edit:{}}),O.esri.Edit.EditStorePOLS=function(){"use strict"
this._db=null,this._isDBInit=!1,this.dbName="features_store",this.objectStoreName="features",this.objectId="objectid",this.ADD="add",this.UPDATE="update",this.DELETE="delete",this.FEATURE_LAYER_JSON_ID="feature-layer-object-1001",this.FEATURE_COLLECTION_ID="feature-collection-object-1001",this.isSupported=function(){return!!window.indexedDB},this.pushEdit=function(a,b,c,d){var e={id:b+"/"+c.attributes[this.objectId],operation:a,layer:b,type:c.geometry.type,graphic:c.toJson()}
@ -73,7 +73,13 @@ d.onsuccess=function(){var c=d.result
c&&c.id==a?b(!0,c):b(!1,"Id not found")},d.onerror=function(a){b(!1,a)}},this.getAllEditsArray=function(a){var b=[]
if(null!==this._db){var c=this.FEATURE_LAYER_JSON_ID,d=this.FEATURE_COLLECTION_ID,e=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName).openCursor()
e.onsuccess=function(e){var f=e.target.result
f&&f.value&&f.value.id?(f.value.id!==c&&f.value.id!==d&&b.push(f.value),f["continue"]()):a(b,"end")}.bind(this),e.onerror=function(b){a(null,b)}}else a(null,"no db")},this.updateExistingEdit=function(a,b,c,d){var e=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName),f=e.get(c.attributes[this.objectId])
f&&f.value&&f.value.id?(f.value.id!==c&&f.value.id!==d&&b.push(f.value),f["continue"]()):a(b,"end")}.bind(this),e.onerror=function(b){a(null,b)}}else a(null,"no db")},this.getNextLowestTempId=function(a,b){var c=[],d=this
if(null!==this._db){var e=this.FEATURE_LAYER_JSON_ID,f=this.FEATURE_COLLECTION_ID,g=this._db.transaction([this.objectStoreName]).objectStore(this.objectStoreName).openCursor()
g.onsuccess=function(g){var h=g.target.result
if(h&&h.value&&h.value.id)h.value.id!==e&&h.value.id!==f&&h.value.layer===a.url&&"add"===h.value.operation&&c.push(h.value.graphic.attributes[d.objectId]),h["continue"]()
else if(0===c.length)b(-1,"success")
else{var i=c.filter(function(a){return!isNaN(a)}),j=Math.min.apply(Math,i)
b(j-1,"success")}}.bind(this),g.onerror=function(a){b(null,a)}}else b(null,"no db")},this.updateExistingEdit=function(a,b,c,d){var e=this._db.transaction([this.objectStoreName],"readwrite").objectStore(this.objectStoreName),f=e.get(c.attributes[this.objectId])
f.onsuccess=function(){f.result
var g={id:b+"/"+c.attributes[this.objectId],operation:a,layer:b,graphic:c.toJson()},h=e.put(g)
h.onsuccess=function(){d(!0)},h.onerror=function(a){d(!1,a)}}.bind(this)},this["delete"]=function(a,b,c){var d=this._db,e=null,f=this,g=a+"/"+b.attributes[this.objectId]

View File

@ -1,4 +1,4 @@
/*! esri-offline-maps - v3.1.0 - 2016-04-21
/*! esri-offline-maps - v3.2.0 - 2016-05-12
* Copyright (c) 2016 Environmental Systems Research Institute, Inc.
* Apache License*/
// Configure offline/online detection
@ -501,21 +501,6 @@ define([
}, this);
return files;
};
// we need to identify ADDs before sending them to the server
// we assign temporary ids (using negative numbers to distinguish them from real ids)
// query the database first to find any existing offline adds, and find the next lowest integer to start with.
this._editStore.getNextLowestTempId(layer, function(value, status){
if(status === "success"){
console.log("_nextTempId:", value);
layer._nextTempId = value;
}
else{
console.log("_nextTempId, not success:", value);
layer._nextTempId = -1;
console.debug(layer._nextTempId);
}
});
layer._getNextTempId = function () {
return this._nextTempId--;
@ -524,20 +509,39 @@ define([
// We are currently only passing in a single deferred.
all(extendPromises).then(function (r) {
if(self._autoOfflineDetect){
Offline.on('up', function(){ // jshint ignore:line
if(r[0].success){
self.goOnline(function(success,error){ // jshint ignore:line
console.log("GOING ONLINE");
// we need to identify ADDs before sending them to the server
// we assign temporary ids (using negative numbers to distinguish them from real ids)
// query the database first to find any existing offline adds, and find the next lowest integer to start with.
self._editStore.getNextLowestTempId(layer, function(value, status){
if(status === "success"){
layer._nextTempId = value;
}
else{
console.log("Set _nextTempId not found: " + value + ", resetting to -1");
layer._nextTempId = -1;
}
});
if(self._autoOfflineDetect){
Offline.on('up', function(){ // jshint ignore:line
self.goOnline(function(success,error){ // jshint ignore:line
console.log("GOING ONLINE");
});
});
});
Offline.on('down', function(){ // jshint ignore:line
self.goOffline(); // jshint ignore:line
});
Offline.on('down', function(){ // jshint ignore:line
self.goOffline(); // jshint ignore:line
});
}
callback(true, null);
}
else {
callback(false, r[0].error);
}
callback(true, null);
});
}, // extend
@ -963,8 +967,11 @@ define([
}
}
// Respect the proxyPath if one has been set (Added at v3.2.0)
var url = this.proxyPath ? this.proxyPath + "?" + layer.url : layer.url;
var req = new XMLHttpRequest();
req.open("POST", layer.url + "/applyEdits", true);
req.open("POST", url + "/applyEdits", true);
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
req.onload = function()
{
@ -1196,6 +1203,57 @@ O.esri.Edit.EditStorePOLS = function () {
}
};
/*
* Query the database, looking for any existing Add temporary OIDs, and return the nextTempId to be used.
* @param feature - extended layer from offline edit advanced
* @param callback {int, messageString} or {null, messageString}
*/
this.getNextLowestTempId = function (feature, callback) {
var addOIDsArray = [],
self = this;
if (this._db !== null) {
var fLayerJSONId = this.FEATURE_LAYER_JSON_ID;
var fCollectionId = this.FEATURE_COLLECTION_ID;
var transaction = this._db.transaction([this.objectStoreName])
.objectStore(this.objectStoreName)
.openCursor();
transaction.onsuccess = function (event) {
var cursor = event.target.result;
if (cursor && cursor.value && cursor.value.id) {
// Make sure we are not return FeatureLayer JSON data or a Phantom Graphic
if (cursor.value.id !== fLayerJSONId && cursor.value.id !== fCollectionId) {
if(cursor.value.layer === feature.url && cursor.value.operation === "add"){ // check to make sure the edit is for the feature we are looking for, and that the operation is an add.
addOIDsArray.push(cursor.value.graphic.attributes[self.objectId]); // add the temporary OID to the array
}
}
cursor.continue();
}
else {
if(addOIDsArray.length === 0){ // if we didn't find anything,
callback(-1, "success"); // we'll start with -1
}
else{
var filteredOIDsArray = addOIDsArray.filter(function(val){ // filter out any non numbers from the array...
return !isNaN(val); // .. should anything have snuck in or returned a NaN
});
var lowestTempId = Math.min.apply(Math, filteredOIDsArray); // then find the lowest number from the array
callback(lowestTempId-1, "success"); // and we'll start with one less than tat.
}
}
}.bind(this);
transaction.onerror = function (err) {
callback(null, err);
};
}
else {
callback(null, "no db");
}
};
/**
* Update an edit already exists in the database
* @param operation add, update or delete

View File

@ -1,4 +1,4 @@
/*! esri-offline-maps - v3.1.0 - 2016-04-21
/*! esri-offline-maps - v3.2.0 - 2016-05-12
* Copyright (c) 2016 Environmental Systems Research Institute, Inc.
* Apache License*/
define([

View File

@ -1,4 +1,4 @@
/*! esri-offline-maps - v3.1.0 - 2016-04-21
/*! esri-offline-maps - v3.2.0 - 2016-05-12
* Copyright (c) 2016 Environmental Systems Research Institute, Inc.
* Apache License*/
define([

View File

@ -1,4 +1,4 @@
/*! esri-offline-maps - v3.1.0 - 2016-04-21
/*! esri-offline-maps - v3.2.0 - 2016-05-12
* Copyright (c) 2016 Environmental Systems Research Institute, Inc.
* Apache License*/
/**

View File

@ -2040,8 +2040,11 @@ define([
}
}
// Respect the proxyPath if one has been set (Added at v3.2.0)
var url = this.proxyPath ? this.proxyPath + "?" + layer.url : layer.url;
var req = new XMLHttpRequest();
req.open("POST", layer.url + "/applyEdits", true);
req.open("POST", url + "/applyEdits", true);
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
req.onload = function()
{
@ -2052,7 +2055,7 @@ define([
callback(obj.addResults, obj.updateResults, obj.deleteResults);
}
catch(err) {
console.error("EDIT REQUEST REPONSE WAS NOT SUCCESSFUL:", req);
console.error("EDIT REQUEST RESPONSE WAS NOT SUCCESSFUL:", req);
errback("Unable to parse xhr response", req);
}
}

View File

@ -485,21 +485,6 @@ define([
}, this);
return files;
};
// we need to identify ADDs before sending them to the server
// we assign temporary ids (using negative numbers to distinguish them from real ids)
// query the database first to find any existing offline adds, and find the next lowest integer to start with.
this._editStore.getNextLowestTempId(layer, function(value, status){
if(status === "success"){
console.log("_nextTempId:", value);
layer._nextTempId = value;
}
else{
console.log("_nextTempId, not success:", value);
layer._nextTempId = -1;
console.debug(layer._nextTempId);
}
});
layer._getNextTempId = function () {
return this._nextTempId--;
@ -508,20 +493,39 @@ define([
// We are currently only passing in a single deferred.
all(extendPromises).then(function (r) {
if(self._autoOfflineDetect){
Offline.on('up', function(){ // jshint ignore:line
if(r[0].success){
self.goOnline(function(success,error){ // jshint ignore:line
console.log("GOING ONLINE");
// we need to identify ADDs before sending them to the server
// we assign temporary ids (using negative numbers to distinguish them from real ids)
// query the database first to find any existing offline adds, and find the next lowest integer to start with.
self._editStore.getNextLowestTempId(layer, function(value, status){
if(status === "success"){
layer._nextTempId = value;
}
else{
console.log("Set _nextTempId not found: " + value + ", resetting to -1");
layer._nextTempId = -1;
}
});
if(self._autoOfflineDetect){
Offline.on('up', function(){ // jshint ignore:line
self.goOnline(function(success,error){ // jshint ignore:line
console.log("GOING ONLINE");
});
});
});
Offline.on('down', function(){ // jshint ignore:line
self.goOffline(); // jshint ignore:line
});
Offline.on('down', function(){ // jshint ignore:line
self.goOffline(); // jshint ignore:line
});
}
callback(true, null);
}
else {
callback(false, r[0].error);
}
callback(true, null);
});
}, // extend
@ -947,8 +951,11 @@ define([
}
}
// Respect the proxyPath if one has been set (Added at v3.2.0)
var url = this.proxyPath ? this.proxyPath + "?" + layer.url : layer.url;
var req = new XMLHttpRequest();
req.open("POST", layer.url + "/applyEdits", true);
req.open("POST", url + "/applyEdits", true);
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
req.onload = function()
{

View File

@ -147,6 +147,57 @@ O.esri.Edit.EditStorePOLS = function () {
}
};
/*
* Query the database, looking for any existing Add temporary OIDs, and return the nextTempId to be used.
* @param feature - extended layer from offline edit advanced
* @param callback {int, messageString} or {null, messageString}
*/
this.getNextLowestTempId = function (feature, callback) {
var addOIDsArray = [],
self = this;
if (this._db !== null) {
var fLayerJSONId = this.FEATURE_LAYER_JSON_ID;
var fCollectionId = this.FEATURE_COLLECTION_ID;
var transaction = this._db.transaction([this.objectStoreName])
.objectStore(this.objectStoreName)
.openCursor();
transaction.onsuccess = function (event) {
var cursor = event.target.result;
if (cursor && cursor.value && cursor.value.id) {
// Make sure we are not return FeatureLayer JSON data or a Phantom Graphic
if (cursor.value.id !== fLayerJSONId && cursor.value.id !== fCollectionId) {
if(cursor.value.layer === feature.url && cursor.value.operation === "add"){ // check to make sure the edit is for the feature we are looking for, and that the operation is an add.
addOIDsArray.push(cursor.value.graphic.attributes[self.objectId]); // add the temporary OID to the array
}
}
cursor.continue();
}
else {
if(addOIDsArray.length === 0){ // if we didn't find anything,
callback(-1, "success"); // we'll start with -1
}
else{
var filteredOIDsArray = addOIDsArray.filter(function(val){ // filter out any non numbers from the array...
return !isNaN(val); // .. should anything have snuck in or returned a NaN
});
var lowestTempId = Math.min.apply(Math, filteredOIDsArray); // then find the lowest number from the array
callback(lowestTempId-1, "success"); // and we'll start with one less than tat.
}
}
}.bind(this);
transaction.onerror = function (err) {
callback(null, err);
};
}
else {
callback(null, "no db");
}
};
/**
* Update an edit already exists in the database
* @param operation add, update or delete

View File

@ -590,7 +590,7 @@ O.esri.Edit.EditStore = function () {
else {
callback(null, "no db");
}
},
};
/**
* Returns all the edits as a single Array via the callback

View File

@ -1,6 +1,6 @@
{
"name": "esri-offline-maps",
"version": "3.1.0",
"version": "3.2.0",
"description": "Lightweight set of libraries for working offline with map tiles and editing with ArcGIS feature services",
"author": "Andy Gup <agup@esri.com> (http://blog.andygup.net)",
"license": "Apache 2.0",

View File

@ -0,0 +1,36 @@
"use strict";
/*
* Utility library for deleting all features in a feature layer.
* Use this to reset demo feature layers.
* WARNING: this will delete EVERYTHING!
*/
function CleanFeatureLayer(featureLayer, callback)
{
require(["esri/request"], function (esriRequest) {
esriRequest({
url: featureLayer.url + "/deleteFeatures",
content: { f: 'json', where: '1=1'},
handleAs: 'json'
},{usePost:true}).then( function(response)
{
callback && callback(true,response);
},
function(error)
{
callback && callback(false,error);
});
});
}
function InitCleanFeatureLayer(featureLayer){
CleanFeatureLayer(featureLayer, function(success){
CleanFeatureLayer( featureLayer, function(success, response)
{
console.log("FeatureLayer cleaned: " + success);
featureLayer.refresh();
});
});
}

View File

@ -9,7 +9,7 @@
"appHomePage": "appcache-tiles.html",
"optimizedApiURL": "../samples/jsolib",
"arcGISBaseURL": "http://js.arcgis.com/3.14",
"version": "3.1.0",
"version": "3.2.0",
"private": true,
"description": "manifest generator project",
"repository": {

View File

@ -2,129 +2,199 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<!--The viewport meta tag is used to improve the presentation and behavior of the samples
on iOS devices-->
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
<title>Update Fire Perimeter</title>
<meta name="viewport" content="width=device-width,user-scalable=no">
<link rel="stylesheet" href="http://js.arcgis.com/3.14/dijit/themes/claro/claro.css">
<link rel="stylesheet" href="http://js.arcgis.com/3.14/esri/css/esri.css">
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
<title>Simple Edit</title>
<link rel="stylesheet" href="https://js.arcgis.com/3.16/dijit/themes/nihilo/nihilo.css">
<link rel="stylesheet" href="https://js.arcgis.com/3.16/esri/css/esri.css">
<style>
html, body { height: 100%; width: 100%; margin: 0; }
#map, #header {
border: 1px solid #444;
html, body, #mainWindow {
font-family: sans-serif;
height: 100%;
width: 100%;
}
#map {
html, body {
margin: 0;
padding: 0;
margin: 5px;
}
#button-holder {
width: 20%;
}
#btn-draw-line, #btn-online, #btn-offline {
text-align: left;
width: 100%;
margin-bottom: 5px;
}
#header {
height: 65px;
margin: 5px 5px 0 5px;
height: 80px;
overflow: auto;
padding: 0.5em;
font-family: sans-serif;
font-weight: 500;
color: #0f3b5f;
font-size: 1.1em;
}
.dj_ie .infowindow .window .top .right .user .content { position: relative; }
.dj_ie .simpleInfoWindow .content { position: relative; }
</style>
<script src="//github.hubspot.com/offline/offline.min.js"></script>
<script src="//js.arcgis.com/3.14/"></script>
<script>
var map;
require([
"esri/map",
"esri/toolbars/edit",
"esri/layers/FeatureLayer",
"esri/tasks/query",
"esri/config",
"dojo/_base/event",
"dojo/parser",
"dijit/layout/BorderContainer", "dijit/layout/ContentPane",
"../dist/offline-edit-basic-src.js",
"dojo/domReady!"
], function(
Map, Edit, FeatureLayer, Query, esriConfig,
event, parser
) {
parser.parse();
// refer to "Using the Proxy Page" for more information: https://developers.arcgis.com/javascript/jshelp/ags_proxy.html
esriConfig.defaults.io.proxyUrl = "/proxy/";
var offlineEdit = new O.esri.Edit.OfflineEditBasic();
map = new Map("map", {
basemap: "topo",
center: [-117.72, 34.352],
zoom: 11
});
map.on("layers-add-result", initEditing);
var firePerimeterFL = new FeatureLayer("http://sampleserver6.arcgisonline.com/arcgis/rest/services/Wildfire/FeatureServer/2", {
mode: FeatureLayer.MODE_SNAPSHOT,
outFields: ["*"],
id: "firePerimeterFL"
});
map.addLayers([firePerimeterFL]);
function initEditing(evt) {
offlineEdit.extend(firePerimeterFL,function(success,error){
if(success){
var editToolbar = new Edit(map);
editToolbar.on("deactivate", function(evt) {
if (evt.info.isModified) {
firePerimeterFL.applyEdits(null, [evt.graphic], null);
}
});
var editingEnabled = false;
firePerimeterFL.on("dbl-click", function(evt) {
event.stop(evt);
if (editingEnabled) {
editingEnabled = false;
editToolbar.deactivate();
firePerimeterFL.clearSelection();
}
else {
editingEnabled = true;
editToolbar.activate(Edit.EDIT_VERTICES, evt.graphic);
// select the feature to prevent it from being updated by map navigation
var query = new Query();
query.objectIds = [evt.graphic.attributes[firePerimeterFL.objectIdField]];
firePerimeterFL.selectFeatures(query);
}
});
}
else {
alert("unable to load feature layer for offline usage");
}
});
}
});
</script>
<!-- Required for online/offline status detection -->
<script src="http://github.hubspot.com/offline/offline.min.js"></script>
<script src="https://js.arcgis.com/3.16/"></script>
</head>
<body class="claro">
<div data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="design:'headline'" style="width:100%;height:100%;" gutters="false">
<div id="header" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'top'" >
1. Load app while online, zoom in to a fire perimeter<br>
2. Cut internet and double click a feature to edit its vertices. Double click again on the feature to stop editing and apply edits.<br>
3. Reestablish internet. You should be able to see the app resync edits in the developer console's network window.
<body class="nihilo">
<div id="mainWindow" data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="design:'headline'">
<div id="header" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'top'">
<div id="button-holder">
<button id="btn-offline">1. Go Offline</button><br>
<button id="btn-draw-line">2. Draw Polyline</button><br>
<button id="btn-online">3. Go Online</button>
</div>
</div>
<div id="map" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'"></div>
</div>
<script>
var map, toolbar, symbol, geomTask;
require([
"esri/map",
"esri/toolbars/draw",
"esri/graphic",
"esri/layers/FeatureLayer",
"esri/symbols/SimpleLineSymbol",
"dojo/parser",
"dijit/layout/BorderContainer", "dijit/layout/ContentPane", "dijit/form/Button",
"../dist/offline-edit-basic-src.js",
"dojo/domReady!"
], function(
Map, Draw, Graphic, FeatureLayer,
SimpleLineSymbol,
parser
) {
parser.parse();
var offlineEdit = new O.esri.Edit.OfflineEditBasic();
//
//
// Map and feature layer loading
//
//
map = new Map("map", {
basemap: "streets",
center: [-15.469, 36.428],
zoom: 3
});
var lineFeatureLayer = new FeatureLayer("https://services.arcgis.com/RkjCp6A0cLN4ubJm/arcgis/rest/services/line_edit_layer/FeatureServer/0", {
mode: FeatureLayer.MODE_SNAPSHOT,
outFields: ["*"],
id: "lineFeatureLayer"
});
var updateHandler = lineFeatureLayer.on("update-end", initEditing);
map.addLayers([lineFeatureLayer]);
var btnOffline = document.getElementById("btn-offline");
var btnOnline = document.getElementById("btn-online");
document.getElementById("btn-draw-line").onclick = function(){
activateDrawTool();
};
btnOnline.onclick = function(){
goOnline();
btnOffline.style.backgroundColor = "";
btnOffline.style.color = "black";
btnOnline.style.backgroundColor = "green";
};
btnOffline.onclick = function(){
goOffline();
btnOnline.style.backgroundColor = "";
btnOffline.style.backgroundColor = "red";
btnOffline.style.color = "white";
};
//
//
// Editing functionality
//
//
function initEditing() {
updateHandler.remove();
createDrawToolbar();
// Extend our feature layer for offline use
offlineEdit.extend(lineFeatureLayer,function(success,error){
if(success){
console.log("TEST layer loaded and extended for offline use!");
}
else {
console.warn("Unable to load FeatureLayer!");
}
});
}
function goOnline() {
offlineEdit.goOnline();
}
function goOffline() {
offlineEdit.goOffline();
}
//
//
// Drawing functionality
//
//
function activateDrawTool() {
toolbar.activate(Draw.POLYLINE);
map.hideZoomSlider();
}
function createDrawToolbar() {
toolbar = new Draw(map);
toolbar.on("draw-end", addPolylineToMap);
}
function addPolylineToMap(evt) {
var symbol;
toolbar.deactivate();
map.showZoomSlider();
switch (evt.geometry.type) {
case "polyline":
symbol = new SimpleLineSymbol();
symbol.width = 5; // make it wide enough to click on
break;
}
var graphic = new Graphic(evt.geometry, symbol, {"name":"test2"});
map.graphics.add(graphic);
applyEdits(graphic);
}
function applyEdits(graphic) {
lineFeatureLayer.applyEdits([graphic], null, null,function(addResults)
{
console.log("addResults length: " + addResults.length);
},
function(error)
{
console.log("SetupFeatureService error: " + error.message);
});
}
});
</script>
</body>
</html>

View File

@ -79,6 +79,7 @@ describe("Normal online editing - Exercise the feature services", function()
async.it("add test features", function(done)
{
expect(g_featureLayers[0].graphics.length).toBe(0);
expect(g_featureLayers[0]._nextTempId).toBe(-1);
g1 = new g_modules.Graphic({"geometry":{"x":-105400,"y":5137000,"spatialReference":{"wkid":102100}},"attributes":{"lat":0.0,"lng":0.0,"description":"g1"}});
g2 = new g_modules.Graphic({"geometry":{"x":-105600,"y":5137000,"spatialReference":{"wkid":102100}},"attributes":{"lat":0.0,"lng":0.0,"description":"g2"}});