mirror of
https://github.com/Esri/offline-editor-js.git
synced 2025-12-15 15:20:05 +00:00
commit
42e49f137a
@ -1,5 +1,14 @@
|
||||
# offline-editor-js - Changelog
|
||||
|
||||
## Version 2.9 - May 27, 2015
|
||||
|
||||
No breaking changes.
|
||||
|
||||
**Enhancements**
|
||||
* Closes #341 - Improved use of keys and indexes in editsStore.js. Minor tweaks at this time.
|
||||
* Closes #342 - Automates featureCollection management. New method `offlineFeaturesManager.getFeatureCollections()`.
|
||||
|
||||
|
||||
## Version 2.8.2 - May 19, 2015
|
||||
|
||||
No breaking changes. Recommended update.
|
||||
|
||||
@ -5,7 +5,7 @@ Offline-editor-js is an open source family of libraries for building offline cap
|
||||
|
||||
Online samples and getting started tutorials are available here: **[http://esri.github.io/offline-editor-js/demo/](http://esri.github.io/offline-editor-js/demo/)**
|
||||
|
||||
*IMPORTANT:* This is an R&D project. If you need a fully integrated, robust offline solution then you should be using our ArcGIS Runtime SDKs for .NET, WPF, Java, iOS, Android and Qt.
|
||||
*IMPORTANT:* If you need a fully integrated, robust offline solution then you should be using our ArcGIS Runtime SDKs for .NET, WPF, Java, iOS, Android and Qt.
|
||||
|
||||
This repo contains the following libraries:
|
||||
|
||||
|
||||
7
dist/offline-edit-min.js
vendored
7
dist/offline-edit-min.js
vendored
File diff suppressed because one or more lines are too long
284
dist/offline-edit-src.js
vendored
284
dist/offline-edit-src.js
vendored
@ -1,4 +1,4 @@
|
||||
/*! offline-editor-js - v2.8.2 - 2015-05-19
|
||||
/*! offline-editor-js - v2.9.0 - 2015-05-27
|
||||
* Copyright (c) 2015 Environmental Systems Research Institute, Inc.
|
||||
* Apache License*/
|
||||
/*jshint -W030 */
|
||||
@ -502,6 +502,8 @@ define([
|
||||
}
|
||||
}
|
||||
|
||||
layer._pushFeatureCollections();
|
||||
|
||||
// we already pushed the edits into the database, now we let the FeatureLayer to do the local updating of the layer graphics
|
||||
// EDITS_ENQUEUED = callback(true, edit), and EDITS_ENQUEUED_ERROR = callback(false, /*String */ error)
|
||||
this._editHandler(results, adds, updatesMap, callback, errback, deferred1);
|
||||
@ -749,6 +751,74 @@ define([
|
||||
|
||||
/* internal methods */
|
||||
|
||||
/**
|
||||
* Automatically creates a set of featureLayerCollections. This is specifically for
|
||||
* use with offline browser restarts. You can retrieve the collections and use them
|
||||
* to reconstitute a featureLayer and then redisplay all the associated features.
|
||||
*
|
||||
* To retrieve use OfflineFeaturesManager.getFeatureCollections().
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
layer._pushFeatureCollections = function(){
|
||||
|
||||
// First let's see if any collections exists
|
||||
self._editStore._getFeatureCollections(function(success, result) {
|
||||
|
||||
var featureCollection =
|
||||
{
|
||||
featureLayerUrl: layer.url,
|
||||
featureLayerCollection: layer.toJson()
|
||||
};
|
||||
|
||||
// An array of feature collections, of course :-)
|
||||
var featureCollectionsArray = [
|
||||
featureCollection
|
||||
];
|
||||
|
||||
// An object for storing multiple feature collections
|
||||
var featureCollectionsObject = {
|
||||
// The id is required because the editsStore keypath
|
||||
// uses it as a UID for all entries in the database
|
||||
id: self._editStore.FEATURE_COLLECTION_ID,
|
||||
featureCollections: featureCollectionsArray
|
||||
};
|
||||
|
||||
// If the featureCollectionsObject already exists
|
||||
if(success){
|
||||
var count = 0;
|
||||
for(var i = 0; i < result.featureCollections.length; i++) {
|
||||
|
||||
// Update the current feature collection
|
||||
if(result.featureCollections[i].featureLayerUrl === layer.url) {
|
||||
count++;
|
||||
result.featureCollections[i] = featureCollection;
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a new feature layer then add it to the featureCollections array
|
||||
if(count === 0) {
|
||||
result.featureCollections.push(featureCollectionsArray);
|
||||
}
|
||||
}
|
||||
// If it does not exist then we need to add a featureCollectionsObject
|
||||
else if(!success && result === null) {
|
||||
result = featureCollectionsObject;
|
||||
}
|
||||
else {
|
||||
console.error("There was a problem retrieving the featureCollections from editStore.");
|
||||
}
|
||||
|
||||
// Automatically update the featureCollectionsObject in the database with every ADD, UPDATE
|
||||
// and DELETE. It can be retrieved via OfflineFeaturesManager.getFeatureCollections();
|
||||
self._editStore._pushFeatureCollections(result, function(success, error) {
|
||||
if(!success){
|
||||
console.error("There was a problem creating the featureCollectionObject: " + error);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Pushes a DELETE request to the database after it's been validated
|
||||
* @param layer
|
||||
@ -1152,6 +1222,36 @@ define([
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves the feature collection object. Specifically used in offline browser restarts.
|
||||
* This is an object created automatically by the library and is updated with every ADD, UPDATE and DELETE.
|
||||
* Attachments are handled separately and not part of the feature collection created here.
|
||||
*
|
||||
* It has the following signature: {id: "feature-collection-object-1001",
|
||||
* featureLayerCollections: [{ featureCollection: [Object], featureLayerUrl: String }]}
|
||||
*
|
||||
* @param callback
|
||||
*/
|
||||
getFeatureCollections: function(callback){
|
||||
if(!this._editStore._isDBInit){
|
||||
|
||||
this._initializeDB(null,null).then(function(result){
|
||||
if(result.success){
|
||||
this._editStore._getFeatureCollections(function(success,message){
|
||||
callback(success,message);
|
||||
});
|
||||
}
|
||||
}.bind(this), function(err){
|
||||
callback(false, err);
|
||||
});
|
||||
}
|
||||
else {
|
||||
this._editStore._getFeatureCollections(function(success,message){
|
||||
callback(success,message);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves the optional feature layer storage object
|
||||
* For use in full offline scenarios.
|
||||
@ -1944,27 +2044,7 @@ define([
|
||||
req.send(data);
|
||||
|
||||
//return dfd.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Deprecated @ v2.5. Internal-use only
|
||||
* @returns {string}
|
||||
* @private
|
||||
*/
|
||||
_optimizeEditsQueue: function(){
|
||||
return "DEPRECATED at v2.5!";
|
||||
},
|
||||
|
||||
/**
|
||||
* DEPRECATED @ v2.5. Use getAllEditsArray() and parse the results
|
||||
* A string value representing human readable information on pending edits
|
||||
* @param edit
|
||||
* @returns {string}
|
||||
*/
|
||||
getReadableEdit: function (edit) {
|
||||
return "DEPRECATED at v2.5!";
|
||||
}
|
||||
|
||||
}); // declare
|
||||
}); // define
|
||||
|
||||
@ -1996,7 +2076,7 @@ O.esri.Edit.EditStore = function () {
|
||||
this.objectStoreName = "features";
|
||||
this.objectId = "objectid"; // set this depending on how your feature service is configured;
|
||||
|
||||
var _dbIndex = "featureId"; // @private
|
||||
//var _dbIndex = "featureId"; // @private
|
||||
|
||||
// ENUMs
|
||||
|
||||
@ -2005,6 +2085,7 @@ O.esri.Edit.EditStore = function () {
|
||||
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 = "|@|";
|
||||
|
||||
@ -2531,30 +2612,27 @@ O.esri.Edit.EditStore = function () {
|
||||
console.assert(this._db !== null, "indexeddb not initialized");
|
||||
var objectStore = this._db.transaction([this.objectStoreName], "readwrite").objectStore(this.objectStoreName);
|
||||
|
||||
require(["dojo/Deferred"], function (Deferred) {
|
||||
if(typeof id === "undefined"){
|
||||
callback(false,"id is undefined.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof id === "undefined"){
|
||||
callback(false,"id is undefined.");
|
||||
return;
|
||||
//Get the entry associated with the graphic
|
||||
var objectStoreGraphicRequest = objectStore.get(id);
|
||||
|
||||
objectStoreGraphicRequest.onsuccess = function () {
|
||||
var graphic = objectStoreGraphicRequest.result;
|
||||
if (graphic && (graphic.id == id)) {
|
||||
callback(true,graphic);
|
||||
}
|
||||
else {
|
||||
callback(false,"Id not found");
|
||||
}
|
||||
};
|
||||
|
||||
//Get the entry associated with the graphic
|
||||
var objectStoreGraphicRequest = objectStore.get(id);
|
||||
|
||||
objectStoreGraphicRequest.onsuccess = function () {
|
||||
var graphic = objectStoreGraphicRequest.result;
|
||||
if (graphic && (graphic.id == id)) {
|
||||
callback(true,graphic);
|
||||
}
|
||||
else {
|
||||
callback(false,"Id not found");
|
||||
}
|
||||
};
|
||||
|
||||
objectStoreGraphicRequest.onerror = function (msg) {
|
||||
callback(false,msg);
|
||||
};
|
||||
});
|
||||
objectStoreGraphicRequest.onerror = function (msg) {
|
||||
callback(false,msg);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2568,6 +2646,7 @@ O.esri.Edit.EditStore = function () {
|
||||
if (this._db !== null) {
|
||||
|
||||
var fLayerJSONId = this.FEATURE_LAYER_JSON_ID;
|
||||
var fCollectionId = this.FEATURE_COLLECTION_ID;
|
||||
var phantomGraphicPrefix = this.PHANTOM_GRAPHIC_PREFIX;
|
||||
|
||||
var transaction = this._db.transaction([this.objectStoreName])
|
||||
@ -2579,7 +2658,7 @@ O.esri.Edit.EditStore = function () {
|
||||
if (cursor && cursor.hasOwnProperty("value") && cursor.value.hasOwnProperty("id")) {
|
||||
|
||||
// Make sure we are not return FeatureLayer JSON data or a Phantom Graphic
|
||||
if (cursor.value.id !== fLayerJSONId && cursor.value.id.indexOf(phantomGraphicPrefix) == -1) {
|
||||
if (cursor.value.id !== fLayerJSONId && cursor.value.id !== fCollectionId && cursor.value.id.indexOf(phantomGraphicPrefix) == -1) {
|
||||
callback(cursor.value, null);
|
||||
}
|
||||
cursor.continue();
|
||||
@ -2609,6 +2688,7 @@ O.esri.Edit.EditStore = function () {
|
||||
if (this._db !== null) {
|
||||
|
||||
var fLayerJSONId = this.FEATURE_LAYER_JSON_ID;
|
||||
var fCollectionId = this.FEATURE_COLLECTION_ID;
|
||||
var phantomGraphicPrefix = this.PHANTOM_GRAPHIC_PREFIX;
|
||||
|
||||
var transaction = this._db.transaction([this.objectStoreName])
|
||||
@ -2620,7 +2700,7 @@ O.esri.Edit.EditStore = function () {
|
||||
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.indexOf(phantomGraphicPrefix) == -1) {
|
||||
if (cursor.value.id !== fLayerJSONId && cursor.value.id !== fCollectionId && cursor.value.id.indexOf(phantomGraphicPrefix) == -1) {
|
||||
editsArray.push(cursor.value);
|
||||
|
||||
}
|
||||
@ -2779,6 +2859,7 @@ O.esri.Edit.EditStore = function () {
|
||||
|
||||
var count = 0;
|
||||
var id = this.FEATURE_LAYER_JSON_ID;
|
||||
var fCollectionId = this.FEATURE_COLLECTION_ID;
|
||||
var phantomGraphicPrefix = this.PHANTOM_GRAPHIC_PREFIX;
|
||||
|
||||
var transaction = this._db.transaction([this.objectStoreName], "readwrite");
|
||||
@ -2789,7 +2870,7 @@ O.esri.Edit.EditStore = function () {
|
||||
// IMPORTANT:
|
||||
// Remember that we have feature layer JSON and Phantom Graphics in the same database
|
||||
if (cursor && cursor.value && cursor.value.id && cursor.value.id.indexOf(phantomGraphicPrefix) == -1) {
|
||||
if (cursor.value.id !== id) {
|
||||
if (cursor.value.id !== id && cursor.value.id !== fCollectionId) {
|
||||
count++;
|
||||
}
|
||||
cursor.continue();
|
||||
@ -2848,6 +2929,7 @@ O.esri.Edit.EditStore = function () {
|
||||
console.assert(this._db !== null, "indexeddb not initialized");
|
||||
|
||||
var id = this.FEATURE_LAYER_JSON_ID;
|
||||
var fCollectionId = this.FEATURE_COLLECTION_ID;
|
||||
var phantomGraphicPrefix = this.PHANTOM_GRAPHIC_PREFIX;
|
||||
|
||||
var usage = {sizeBytes: 0, editCount: 0};
|
||||
@ -2865,7 +2947,7 @@ O.esri.Edit.EditStore = function () {
|
||||
var json = JSON.stringify(storedObject);
|
||||
usage.sizeBytes += json.length;
|
||||
|
||||
if (cursor.value.id.indexOf(phantomGraphicPrefix) == -1 && cursor.value.id !== id) {
|
||||
if (cursor.value.id.indexOf(phantomGraphicPrefix) == -1 && cursor.value.id !== id && cursor.value.id !== fCollectionId) {
|
||||
usage.editCount += 1;
|
||||
}
|
||||
|
||||
@ -2880,7 +2962,54 @@ O.esri.Edit.EditStore = function () {
|
||||
};
|
||||
};
|
||||
|
||||
//
|
||||
// internal methods
|
||||
//
|
||||
|
||||
/**
|
||||
* The library automatically keeps a copy of the featureLayerCollection and its
|
||||
* associated layer.url.
|
||||
*
|
||||
* There should be only one featureLayerCollection Object per feature layer.
|
||||
* @param featureCollectionObject
|
||||
* @param callback
|
||||
* @private
|
||||
*/
|
||||
this._pushFeatureCollections = function(featureCollectionObject, callback){
|
||||
var transaction = this._db.transaction([this.objectStoreName], "readwrite");
|
||||
|
||||
transaction.oncomplete = function (event) {
|
||||
callback(true);
|
||||
};
|
||||
|
||||
transaction.onerror = function (event) {
|
||||
callback(false, event.target.error.message);
|
||||
};
|
||||
|
||||
var objectStore = transaction.objectStore(this.objectStoreName);
|
||||
objectStore.put(featureCollectionObject);
|
||||
};
|
||||
|
||||
this._getFeatureCollections = function(callback){
|
||||
var objectStore = this._db.transaction([this.objectStoreName], "readonly").objectStore(this.objectStoreName);
|
||||
|
||||
//Get the entry associated with the graphic
|
||||
var objectStoreGraphicRequest = objectStore.get(this.FEATURE_COLLECTION_ID);
|
||||
|
||||
objectStoreGraphicRequest.onsuccess = function () {
|
||||
var object = objectStoreGraphicRequest.result;
|
||||
if (typeof object != "undefined") {
|
||||
callback(true, object);
|
||||
}
|
||||
else {
|
||||
callback(false, null);
|
||||
}
|
||||
};
|
||||
|
||||
objectStoreGraphicRequest.onerror = function (msg) {
|
||||
callback(false, msg);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Save space in the database...don't need to store the entire Graphic object just its public properties!
|
||||
@ -2932,8 +3061,7 @@ O.esri.Edit.EditStore = function () {
|
||||
db.deleteObjectStore(this.objectStoreName);
|
||||
}
|
||||
|
||||
var objectStore = db.createObjectStore(this.objectStoreName, {keyPath: "id"});
|
||||
objectStore.createIndex(_dbIndex, _dbIndex, {unique: false});
|
||||
db.createObjectStore(this.objectStoreName, {keyPath: "id"});
|
||||
}.bind(this);
|
||||
|
||||
request.onsuccess = function (event) {
|
||||
@ -2943,64 +3071,6 @@ O.esri.Edit.EditStore = function () {
|
||||
callback(true, null);
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
///
|
||||
/// DEPRECATED @ v2.5
|
||||
/// Subject to complete removal at the next release.
|
||||
/// Many of these were undocumented and for internal use.
|
||||
///
|
||||
|
||||
/**
|
||||
* Deprecated @ v2.5. Use pendingEditsCount().
|
||||
*/
|
||||
this.hasPendingEdits = function () {
|
||||
return "DEPRECATED at v2.5!";
|
||||
};
|
||||
|
||||
/**
|
||||
* Deprecated @ v2.5. Use public function editExists() instead.
|
||||
*/
|
||||
this._isEditDuplicated = function (newEdit, edits) {
|
||||
return "DEPRECATED at v2.5!";
|
||||
};
|
||||
|
||||
/**
|
||||
* Deprecated @ v2.5. Use pushEdit()
|
||||
*/
|
||||
this._storeEditsQueue = function (edits) {
|
||||
return "DEPRECATED at v2.5!";
|
||||
};
|
||||
|
||||
/**
|
||||
* Deprecated @ v2.5.
|
||||
*/
|
||||
this._unpackArrayOfEdits = function (edits) {
|
||||
return "DEPRECATED at v2.5!";
|
||||
};
|
||||
|
||||
/**
|
||||
* Deprecated @ v2.5. Use getUsage().
|
||||
* @returns {string}
|
||||
*/
|
||||
this.getLocalStorageSizeBytes = function(){
|
||||
return "DEPRECATED at v2.5!";
|
||||
};
|
||||
|
||||
/**
|
||||
* Deprecated @ v2.5.
|
||||
* @returns {string}
|
||||
*/
|
||||
this.peekFirstEdit = function(){
|
||||
return "DEPRECATED at v2.5!";
|
||||
};
|
||||
|
||||
/**
|
||||
* Deprecated @ v2.5.
|
||||
* @returns {string}
|
||||
*/
|
||||
this.popFirstEdit = function(){
|
||||
return "DEPRECATED at v2.5!";
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
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.8.2 - 2015-05-19
|
||||
/*! offline-editor-js - v2.9.0 - 2015-05-27
|
||||
* 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.8.2 - 2015-05-19
|
||||
/*! offline-editor-js - v2.9.0 - 2015-05-27
|
||||
* 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.8.2 - 2015-05-19
|
||||
/*! offline-editor-js - v2.9.0 - 2015-05-27
|
||||
* 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.8.2 - 2015-05-19
|
||||
/*! offline-editor-js - v2.9.0 - 2015-05-27
|
||||
* Copyright (c) 2015 Environmental Systems Research Institute, Inc.
|
||||
* Apache License*/
|
||||
/**
|
||||
|
||||
@ -75,7 +75,24 @@ 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 if you want full control of what is stored. You can also access an automatically created data store via the `getFeatureCollections()` method. If you use the `getFeatureCollections()` pattern you can simply ignore the `dataStore` property in the constructor. Here is an example of the Object returned in the `getFeatureCollections()` callback:
|
||||
|
||||
```js
|
||||
{
|
||||
id: "feature-collection-object-1001",
|
||||
featureLayerCollections: [
|
||||
{
|
||||
featureLayerUrl: "http://...",
|
||||
featureLayerCollection: { . . . }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
The `featureLayerCollection` is equivalent to `featureLayer.toJson()`.
|
||||
|
||||
Note: the `layer.extend()` callback only indicates that the edits database has been successfully initialized.
|
||||
|
||||
@ -160,6 +177,28 @@ You can then retrieve this data after an offline restart by using the following
|
||||
|
||||
```
|
||||
|
||||
If you don't want to deal with creating and managing your own data store when working with offline browser restarts, then here's the pattern for using the built-in `featureLayerCollections`. This pattern is ideal if you are using Esri's pre-built widgets such as `AttributeInspector` and you don't have access to the necessary events for creating and updating the `dataStore`.
|
||||
|
||||
```js
|
||||
|
||||
offlinefeaturesManager.getFeatureCollections(function(success, collection) {
|
||||
if(success) {
|
||||
myFeatureLayer = new
|
||||
FeatureLayer(collection.featureCollections[0].featureLayerCollection),{
|
||||
mode: FeatureLayer.MODE_SNAPSHOT,
|
||||
outFields: ["GlobalID","BSID","ROUTES","STOPNAME"]
|
||||
});
|
||||
|
||||
offlineFeaturesManager.extend(myFeatureLayer,function(result, error) {
|
||||
if(result) {
|
||||
console.log("Layer has been successfully rebuilt while offline!");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
**Step 5** Once a layer has been extended the offline library will enable it with new methods. Here are a few examples that include code snippets of how to take advantage of some of the library's methods. You can also use a combination of methods from `editsStore` and `offlineFeaturesManager`.
|
||||
|
||||
####offlineFeaturesManager.proxyPath
|
||||
|
||||
@ -16,8 +16,8 @@ Property | Value | Description
|
||||
`DB_NAME` | "features_store" | Sets the database name. You can instantiate multiple databases within the same application by creating seperate instances of OfflineFeaturesManager.
|
||||
`DB_OBJECTSTORE_NAME` | "features" | Represents an object store that allows access to a set of data in the database.
|
||||
`DB_UID` | "objectid" | IMPORTANT!** This tells the database what id to use as a unique identifier. This depends on how your feature service was created. ArcGIS Online services may use something different such as `GlobalID`.
|
||||
`ATTACHMENTS_DB_NAME` | "attachments_store" | **New @ v2.7** Sets the attachments database name.
|
||||
`ATTACHMENTS_DB_OBJECTSTORE_NAME` | "attachments" | **New @ v2.7** Sets the attachments database object store name.
|
||||
`ATTACHMENTS_DB_NAME` | "attachments_store" | (Added @ v2.7) Sets the attachments database name.
|
||||
`ATTACHMENTS_DB_OBJECTSTORE_NAME` | "attachments" | (Added @ v2.7) Sets the attachments database object store name.
|
||||
`proxyPath` | null | Default is `null`. If you are using a Feature Service that is not CORS-enabled then you will need to set this path.
|
||||
`attachmentsStore` | null | Default is `null`. If you are using attachments, this property gives you access to the associated database.
|
||||
|
||||
@ -42,7 +42,8 @@ Methods | Returns | Description
|
||||
`goOffline()` | nothing | Forces library into an offline state. Any edits applied to extended FeatureLayers during this condition will be stored locally.
|
||||
`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 )` | `callback( boolean, Object)` | **New @ v2.7.1** Returns the feature layer's dataStore Object.
|
||||
`getFeatureCollections( callback )` | `callback( boolean, Object)` | (Added @ v2.9) Returns and Object that contains the latest `featureLayerCollection` snapshot for each feature layer that is using the library. Each collection is updated automatically by the library when there is an associated `ADD`, `UPDATE` or `DELETE` operation.<br><br>This method should be used when working with pre-built Esri widgets such as the `AttributeInspector.`
|
||||
`getFeatureLayerJSONDataStore( callback )` | `callback( boolean, Object)` | (Added @ v2.7.1) Returns the feature layer's dataStore Object that was created using the `offlineFeaturesManager()` constructor. Offers more control what is provided by `getFeatureCollections()`.
|
||||
`getReadableEdit()` | String | **DEPRECATED** @ v2.5. A string value representing human readable information on pending edits. Use `featureLayer.getAllEditsArray()`.
|
||||
|
||||
|
||||
@ -90,12 +91,12 @@ Methods | Returns | Description
|
||||
--- | --- | ---
|
||||
`applyEdits(` `adds, updates, deletes,` `callback, errback)` | `deferred` | applyEdits() method is replaced by this library. It's behaviour depends upon online state of the manager. You need to pass the same arguments as to the original applyEdits() method and it returns a deferred object, that will be resolved in the same way as the original, as well as the callbacks will be called under the same conditions. This method looks the same as the original to calling code, the only difference is internal. Listen for `EDITS_ENQUEUED` or `EDITS_ENQUEUED_ERROR`.
|
||||
`addAttachment( objectId, formNode,` `callback,errback)` | `deferred` | Adds a single attachment.
|
||||
`updateAttachment( objectId, attachmentId,` `formNode, callback, errback)` | `deferred` | **New @ v2.7** Updates an existing attachment.
|
||||
`updateAttachment( objectId, attachmentId,` `formNode, callback, errback)` | `deferred` | (Added @ v2.7) Updates an existing attachment.
|
||||
`deleteAttachments( objectId, attachmentsIds,` `callback, errback)`| `deferred` | Deletes existing attachments as well as attachments that were created while offline.
|
||||
`getAttachmentsUsage(callback)` | `callback(usageObject,error)` | **New @ v2.7** Returns the approximate size of the attachments database. The usage Object is {sizeBytes: number, attachmentCount: number}.
|
||||
`resetAttachmentsDatabase( callback)` | `callback(boolean, error)` | **New @ v2.7** Resets the entire attachments database -- use with **caution**.
|
||||
`convertGraphicLayerToJSON(` `features, updateEndEvent, callback)` | `callback( featureJSON, layerDefJSON)` | Not really needed @ v2.5 when you can store the entire feature layer's JSON using the `dataStore` property in the `OfflineFeatureManager` contructor. Used with offline browser restarts. In order to reconstitute the feature layer and map you'll need to store the featureJSON and layerDefJSON in local storage and then it read back upon an offline restart. The `updateEndEvent` is the Feature Layer's `update-end` event object. The appcache-features.html sample demonstrates this pattern.
|
||||
`getFeatureDefinition(` `featureLayer, featuresArr` `geometryType, callback)` | `Object` | Used with offline browser restarts. Not really needed @ v2.5 when you can store the entire feature layer's JSON using the `dataStore` property in the `OfflineFeatureManager` contructor. Pass it a FeatureLayer instance, an array of features and specify the Esri geometry type. It will return a FeatureLayer Definition object that can be used to reconstitute a Feature Layer from scratch. The appcache-features.html sample demonstrates this pattern. Go here for more info on the ArcGIS REST API [layerDefinition](http://resources.arcgis.com/en/help/arcgis-rest-api/index.html#//02r30000004v000000), and [Layer](http://resources.arcgis.com/en/help/arcgis-rest-api/index.html#/Layer/02r30000004q000000/).
|
||||
`getAttachmentsUsage(callback)` | `callback(usageObject,error)` | (Added @ v2.7) Returns the approximate size of the attachments database. The usage Object is {sizeBytes: number, attachmentCount: number}.
|
||||
`resetAttachmentsDatabase( callback)` | `callback(boolean, error)` | (Added @ v2.7) Resets the entire attachments database -- use with **caution**.
|
||||
`convertGraphicLayerToJSON(` `features, updateEndEvent, callback)` | `callback( featureJSON, layerDefJSON)` | You can also store the entire feature layer's JSON using the `dataStore` property in the `OfflineFeatureManager` contructor. Used with offline browser restarts. In order to reconstitute the feature layer and map you'll need to store the featureJSON and layerDefJSON in local storage and then it read back upon an offline restart. The `updateEndEvent` is the Feature Layer's `update-end` event object. The appcache-features.html sample demonstrates this pattern.
|
||||
`getFeatureDefinition(` `featureLayer, featuresArr` `geometryType, callback)` | `Object` | Used with offline browser restarts. You can also store the entire feature layer's JSON using the `dataStore` property in the `OfflineFeatureManager` contructor. Pass it a FeatureLayer instance, an array of features and specify the Esri geometry type. It will return a FeatureLayer Definition object that can be used to reconstitute a Feature Layer from scratch. The appcache-features.html sample demonstrates this pattern. Go here for more info on the ArcGIS REST API [layerDefinition](http://resources.arcgis.com/en/help/arcgis-rest-api/index.html#//02r30000004v000000), and [Layer](http://resources.arcgis.com/en/help/arcgis-rest-api/index.html#/Layer/02r30000004q000000/).
|
||||
`setPhantomLayerGraphics( graphicsArray) ` | nothing | Used with offline browser restarts. Adds the graphics in the `graphicsArray` to the internal phantom graphics layer. This layer is designed to indicate to the user any graphic that has been modified while offline. The appcache-features.html sample demonstrates this pattern.
|
||||
`getPhantomLayerGraphics( callback) ` | `callback( graphicsLayerJSON)` | Used with offline browser restarts. Returns a JSON representation of the internal phantom graphics layer. This layer is designed to indicate to the user any graphic that has been modified while offline. The appcache-features.html sample demonstrates this pattern.
|
||||
`resetDatabase(callback)` | `callback( boolean, error)` | Full edits database reset -- use with **caution**. If some edits weren't successfully sent, then the record will still exist in the database. If you use this function then those pending records will also be deleted.
|
||||
@ -164,9 +165,9 @@ Constructor | Description
|
||||
|
||||
Property | Value | Description
|
||||
--- | --- | ---
|
||||
`dbName` | "attachments_store" | **Updated @ v2.7** Represents a FeatureLayer.add() operation.
|
||||
`objectStoreName` | "attachments" | **Updated @ v2.7** Represents a FeatureLayer.update() operation.
|
||||
`TYPE` | "ADD", "UPDATE" or "DELETE" | **New @ v2.7** Specifies the type of operation against an attachment.
|
||||
`dbName` | "attachments_store" | Represents a FeatureLayer.add() operation.
|
||||
`objectStoreName` | "attachments" | Represents a FeatureLayer.update() operation.
|
||||
`TYPE` | "ADD", "UPDATE" or "DELETE" | (Added @ v2.7) Specifies the type of operation against an attachment.
|
||||
|
||||
###Public Methods
|
||||
Methods | Returns | Description
|
||||
|
||||
@ -13,7 +13,7 @@ O.esri.Edit.EditStore = function () {
|
||||
this.objectStoreName = "features";
|
||||
this.objectId = "objectid"; // set this depending on how your feature service is configured;
|
||||
|
||||
var _dbIndex = "featureId"; // @private
|
||||
//var _dbIndex = "featureId"; // @private
|
||||
|
||||
// ENUMs
|
||||
|
||||
@ -22,6 +22,7 @@ O.esri.Edit.EditStore = function () {
|
||||
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 = "|@|";
|
||||
|
||||
@ -548,30 +549,27 @@ O.esri.Edit.EditStore = function () {
|
||||
console.assert(this._db !== null, "indexeddb not initialized");
|
||||
var objectStore = this._db.transaction([this.objectStoreName], "readwrite").objectStore(this.objectStoreName);
|
||||
|
||||
require(["dojo/Deferred"], function (Deferred) {
|
||||
if(typeof id === "undefined"){
|
||||
callback(false,"id is undefined.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof id === "undefined"){
|
||||
callback(false,"id is undefined.");
|
||||
return;
|
||||
//Get the entry associated with the graphic
|
||||
var objectStoreGraphicRequest = objectStore.get(id);
|
||||
|
||||
objectStoreGraphicRequest.onsuccess = function () {
|
||||
var graphic = objectStoreGraphicRequest.result;
|
||||
if (graphic && (graphic.id == id)) {
|
||||
callback(true,graphic);
|
||||
}
|
||||
else {
|
||||
callback(false,"Id not found");
|
||||
}
|
||||
};
|
||||
|
||||
//Get the entry associated with the graphic
|
||||
var objectStoreGraphicRequest = objectStore.get(id);
|
||||
|
||||
objectStoreGraphicRequest.onsuccess = function () {
|
||||
var graphic = objectStoreGraphicRequest.result;
|
||||
if (graphic && (graphic.id == id)) {
|
||||
callback(true,graphic);
|
||||
}
|
||||
else {
|
||||
callback(false,"Id not found");
|
||||
}
|
||||
};
|
||||
|
||||
objectStoreGraphicRequest.onerror = function (msg) {
|
||||
callback(false,msg);
|
||||
};
|
||||
});
|
||||
objectStoreGraphicRequest.onerror = function (msg) {
|
||||
callback(false,msg);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
@ -585,6 +583,7 @@ O.esri.Edit.EditStore = function () {
|
||||
if (this._db !== null) {
|
||||
|
||||
var fLayerJSONId = this.FEATURE_LAYER_JSON_ID;
|
||||
var fCollectionId = this.FEATURE_COLLECTION_ID;
|
||||
var phantomGraphicPrefix = this.PHANTOM_GRAPHIC_PREFIX;
|
||||
|
||||
var transaction = this._db.transaction([this.objectStoreName])
|
||||
@ -596,7 +595,7 @@ O.esri.Edit.EditStore = function () {
|
||||
if (cursor && cursor.hasOwnProperty("value") && cursor.value.hasOwnProperty("id")) {
|
||||
|
||||
// Make sure we are not return FeatureLayer JSON data or a Phantom Graphic
|
||||
if (cursor.value.id !== fLayerJSONId && cursor.value.id.indexOf(phantomGraphicPrefix) == -1) {
|
||||
if (cursor.value.id !== fLayerJSONId && cursor.value.id !== fCollectionId && cursor.value.id.indexOf(phantomGraphicPrefix) == -1) {
|
||||
callback(cursor.value, null);
|
||||
}
|
||||
cursor.continue();
|
||||
@ -626,6 +625,7 @@ O.esri.Edit.EditStore = function () {
|
||||
if (this._db !== null) {
|
||||
|
||||
var fLayerJSONId = this.FEATURE_LAYER_JSON_ID;
|
||||
var fCollectionId = this.FEATURE_COLLECTION_ID;
|
||||
var phantomGraphicPrefix = this.PHANTOM_GRAPHIC_PREFIX;
|
||||
|
||||
var transaction = this._db.transaction([this.objectStoreName])
|
||||
@ -637,7 +637,7 @@ O.esri.Edit.EditStore = function () {
|
||||
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.indexOf(phantomGraphicPrefix) == -1) {
|
||||
if (cursor.value.id !== fLayerJSONId && cursor.value.id !== fCollectionId && cursor.value.id.indexOf(phantomGraphicPrefix) == -1) {
|
||||
editsArray.push(cursor.value);
|
||||
|
||||
}
|
||||
@ -796,6 +796,7 @@ O.esri.Edit.EditStore = function () {
|
||||
|
||||
var count = 0;
|
||||
var id = this.FEATURE_LAYER_JSON_ID;
|
||||
var fCollectionId = this.FEATURE_COLLECTION_ID;
|
||||
var phantomGraphicPrefix = this.PHANTOM_GRAPHIC_PREFIX;
|
||||
|
||||
var transaction = this._db.transaction([this.objectStoreName], "readwrite");
|
||||
@ -806,7 +807,7 @@ O.esri.Edit.EditStore = function () {
|
||||
// IMPORTANT:
|
||||
// Remember that we have feature layer JSON and Phantom Graphics in the same database
|
||||
if (cursor && cursor.value && cursor.value.id && cursor.value.id.indexOf(phantomGraphicPrefix) == -1) {
|
||||
if (cursor.value.id !== id) {
|
||||
if (cursor.value.id !== id && cursor.value.id !== fCollectionId) {
|
||||
count++;
|
||||
}
|
||||
cursor.continue();
|
||||
@ -865,6 +866,7 @@ O.esri.Edit.EditStore = function () {
|
||||
console.assert(this._db !== null, "indexeddb not initialized");
|
||||
|
||||
var id = this.FEATURE_LAYER_JSON_ID;
|
||||
var fCollectionId = this.FEATURE_COLLECTION_ID;
|
||||
var phantomGraphicPrefix = this.PHANTOM_GRAPHIC_PREFIX;
|
||||
|
||||
var usage = {sizeBytes: 0, editCount: 0};
|
||||
@ -882,7 +884,7 @@ O.esri.Edit.EditStore = function () {
|
||||
var json = JSON.stringify(storedObject);
|
||||
usage.sizeBytes += json.length;
|
||||
|
||||
if (cursor.value.id.indexOf(phantomGraphicPrefix) == -1 && cursor.value.id !== id) {
|
||||
if (cursor.value.id.indexOf(phantomGraphicPrefix) == -1 && cursor.value.id !== id && cursor.value.id !== fCollectionId) {
|
||||
usage.editCount += 1;
|
||||
}
|
||||
|
||||
@ -897,7 +899,54 @@ O.esri.Edit.EditStore = function () {
|
||||
};
|
||||
};
|
||||
|
||||
//
|
||||
// internal methods
|
||||
//
|
||||
|
||||
/**
|
||||
* The library automatically keeps a copy of the featureLayerCollection and its
|
||||
* associated layer.url.
|
||||
*
|
||||
* There should be only one featureLayerCollection Object per feature layer.
|
||||
* @param featureCollectionObject
|
||||
* @param callback
|
||||
* @private
|
||||
*/
|
||||
this._pushFeatureCollections = function(featureCollectionObject, callback){
|
||||
var transaction = this._db.transaction([this.objectStoreName], "readwrite");
|
||||
|
||||
transaction.oncomplete = function (event) {
|
||||
callback(true);
|
||||
};
|
||||
|
||||
transaction.onerror = function (event) {
|
||||
callback(false, event.target.error.message);
|
||||
};
|
||||
|
||||
var objectStore = transaction.objectStore(this.objectStoreName);
|
||||
objectStore.put(featureCollectionObject);
|
||||
};
|
||||
|
||||
this._getFeatureCollections = function(callback){
|
||||
var objectStore = this._db.transaction([this.objectStoreName], "readonly").objectStore(this.objectStoreName);
|
||||
|
||||
//Get the entry associated with the graphic
|
||||
var objectStoreGraphicRequest = objectStore.get(this.FEATURE_COLLECTION_ID);
|
||||
|
||||
objectStoreGraphicRequest.onsuccess = function () {
|
||||
var object = objectStoreGraphicRequest.result;
|
||||
if (typeof object != "undefined") {
|
||||
callback(true, object);
|
||||
}
|
||||
else {
|
||||
callback(false, null);
|
||||
}
|
||||
};
|
||||
|
||||
objectStoreGraphicRequest.onerror = function (msg) {
|
||||
callback(false, msg);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Save space in the database...don't need to store the entire Graphic object just its public properties!
|
||||
@ -949,8 +998,7 @@ O.esri.Edit.EditStore = function () {
|
||||
db.deleteObjectStore(this.objectStoreName);
|
||||
}
|
||||
|
||||
var objectStore = db.createObjectStore(this.objectStoreName, {keyPath: "id"});
|
||||
objectStore.createIndex(_dbIndex, _dbIndex, {unique: false});
|
||||
db.createObjectStore(this.objectStoreName, {keyPath: "id"});
|
||||
}.bind(this);
|
||||
|
||||
request.onsuccess = function (event) {
|
||||
@ -960,64 +1008,6 @@ O.esri.Edit.EditStore = function () {
|
||||
callback(true, null);
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
///
|
||||
/// DEPRECATED @ v2.5
|
||||
/// Subject to complete removal at the next release.
|
||||
/// Many of these were undocumented and for internal use.
|
||||
///
|
||||
|
||||
/**
|
||||
* Deprecated @ v2.5. Use pendingEditsCount().
|
||||
*/
|
||||
this.hasPendingEdits = function () {
|
||||
return "DEPRECATED at v2.5!";
|
||||
};
|
||||
|
||||
/**
|
||||
* Deprecated @ v2.5. Use public function editExists() instead.
|
||||
*/
|
||||
this._isEditDuplicated = function (newEdit, edits) {
|
||||
return "DEPRECATED at v2.5!";
|
||||
};
|
||||
|
||||
/**
|
||||
* Deprecated @ v2.5. Use pushEdit()
|
||||
*/
|
||||
this._storeEditsQueue = function (edits) {
|
||||
return "DEPRECATED at v2.5!";
|
||||
};
|
||||
|
||||
/**
|
||||
* Deprecated @ v2.5.
|
||||
*/
|
||||
this._unpackArrayOfEdits = function (edits) {
|
||||
return "DEPRECATED at v2.5!";
|
||||
};
|
||||
|
||||
/**
|
||||
* Deprecated @ v2.5. Use getUsage().
|
||||
* @returns {string}
|
||||
*/
|
||||
this.getLocalStorageSizeBytes = function(){
|
||||
return "DEPRECATED at v2.5!";
|
||||
};
|
||||
|
||||
/**
|
||||
* Deprecated @ v2.5.
|
||||
* @returns {string}
|
||||
*/
|
||||
this.peekFirstEdit = function(){
|
||||
return "DEPRECATED at v2.5!";
|
||||
};
|
||||
|
||||
/**
|
||||
* Deprecated @ v2.5.
|
||||
* @returns {string}
|
||||
*/
|
||||
this.popFirstEdit = function(){
|
||||
return "DEPRECATED at v2.5!";
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -499,6 +499,8 @@ define([
|
||||
}
|
||||
}
|
||||
|
||||
layer._pushFeatureCollections();
|
||||
|
||||
// we already pushed the edits into the database, now we let the FeatureLayer to do the local updating of the layer graphics
|
||||
// EDITS_ENQUEUED = callback(true, edit), and EDITS_ENQUEUED_ERROR = callback(false, /*String */ error)
|
||||
this._editHandler(results, adds, updatesMap, callback, errback, deferred1);
|
||||
@ -746,6 +748,74 @@ define([
|
||||
|
||||
/* internal methods */
|
||||
|
||||
/**
|
||||
* Automatically creates a set of featureLayerCollections. This is specifically for
|
||||
* use with offline browser restarts. You can retrieve the collections and use them
|
||||
* to reconstitute a featureLayer and then redisplay all the associated features.
|
||||
*
|
||||
* To retrieve use OfflineFeaturesManager.getFeatureCollections().
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
layer._pushFeatureCollections = function(){
|
||||
|
||||
// First let's see if any collections exists
|
||||
self._editStore._getFeatureCollections(function(success, result) {
|
||||
|
||||
var featureCollection =
|
||||
{
|
||||
featureLayerUrl: layer.url,
|
||||
featureLayerCollection: layer.toJson()
|
||||
};
|
||||
|
||||
// An array of feature collections, of course :-)
|
||||
var featureCollectionsArray = [
|
||||
featureCollection
|
||||
];
|
||||
|
||||
// An object for storing multiple feature collections
|
||||
var featureCollectionsObject = {
|
||||
// The id is required because the editsStore keypath
|
||||
// uses it as a UID for all entries in the database
|
||||
id: self._editStore.FEATURE_COLLECTION_ID,
|
||||
featureCollections: featureCollectionsArray
|
||||
};
|
||||
|
||||
// If the featureCollectionsObject already exists
|
||||
if(success){
|
||||
var count = 0;
|
||||
for(var i = 0; i < result.featureCollections.length; i++) {
|
||||
|
||||
// Update the current feature collection
|
||||
if(result.featureCollections[i].featureLayerUrl === layer.url) {
|
||||
count++;
|
||||
result.featureCollections[i] = featureCollection;
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a new feature layer then add it to the featureCollections array
|
||||
if(count === 0) {
|
||||
result.featureCollections.push(featureCollectionsArray);
|
||||
}
|
||||
}
|
||||
// If it does not exist then we need to add a featureCollectionsObject
|
||||
else if(!success && result === null) {
|
||||
result = featureCollectionsObject;
|
||||
}
|
||||
else {
|
||||
console.error("There was a problem retrieving the featureCollections from editStore.");
|
||||
}
|
||||
|
||||
// Automatically update the featureCollectionsObject in the database with every ADD, UPDATE
|
||||
// and DELETE. It can be retrieved via OfflineFeaturesManager.getFeatureCollections();
|
||||
self._editStore._pushFeatureCollections(result, function(success, error) {
|
||||
if(!success){
|
||||
console.error("There was a problem creating the featureCollectionObject: " + error);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Pushes a DELETE request to the database after it's been validated
|
||||
* @param layer
|
||||
@ -1149,6 +1219,36 @@ define([
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves the feature collection object. Specifically used in offline browser restarts.
|
||||
* This is an object created automatically by the library and is updated with every ADD, UPDATE and DELETE.
|
||||
* Attachments are handled separately and not part of the feature collection created here.
|
||||
*
|
||||
* It has the following signature: {id: "feature-collection-object-1001",
|
||||
* featureLayerCollections: [{ featureCollection: [Object], featureLayerUrl: String }]}
|
||||
*
|
||||
* @param callback
|
||||
*/
|
||||
getFeatureCollections: function(callback){
|
||||
if(!this._editStore._isDBInit){
|
||||
|
||||
this._initializeDB(null,null).then(function(result){
|
||||
if(result.success){
|
||||
this._editStore._getFeatureCollections(function(success,message){
|
||||
callback(success,message);
|
||||
});
|
||||
}
|
||||
}.bind(this), function(err){
|
||||
callback(false, err);
|
||||
});
|
||||
}
|
||||
else {
|
||||
this._editStore._getFeatureCollections(function(success,message){
|
||||
callback(success,message);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves the optional feature layer storage object
|
||||
* For use in full offline scenarios.
|
||||
@ -1941,26 +2041,6 @@ define([
|
||||
req.send(data);
|
||||
|
||||
//return dfd.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Deprecated @ v2.5. Internal-use only
|
||||
* @returns {string}
|
||||
* @private
|
||||
*/
|
||||
_optimizeEditsQueue: function(){
|
||||
return "DEPRECATED at v2.5!";
|
||||
},
|
||||
|
||||
/**
|
||||
* DEPRECATED @ v2.5. Use getAllEditsArray() and parse the results
|
||||
* A string value representing human readable information on pending edits
|
||||
* @param edit
|
||||
* @returns {string}
|
||||
*/
|
||||
getReadableEdit: function (edit) {
|
||||
return "DEPRECATED at v2.5!";
|
||||
}
|
||||
|
||||
}); // declare
|
||||
}); // define
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "offline-editor-js",
|
||||
"version": "2.8.2",
|
||||
"version": "2.9.0",
|
||||
"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",
|
||||
|
||||
@ -9,16 +9,20 @@
|
||||
|
||||
<!--
|
||||
|
||||
This sample demonstrates using an application manifest to store features and tiles locally.
|
||||
This sample demonstrates using an application manifest to store features and tiles locally with a custom-built
|
||||
editor widget. If you are planning on using one of Esri's pre-built widgets such as the AttributeInspector
|
||||
then you'll need to use a different pattern for reconstituting the feature layer. See the How-To for more details:
|
||||
https://github.com/Esri/offline-editor-js/blob/master/doc/howtouseeditlibrary.md
|
||||
|
||||
The use cases for using this sample are to ensure you can reload and restart you application
|
||||
one it is offline.
|
||||
while it is offline and then continue working.
|
||||
|
||||
It is strongly recommended that you use your own optimized build of the ArcGIS API for JavaScript
|
||||
using the Web Optimizer: http://jso.arcgis.com/. You can reference the CDN or host it on your
|
||||
own web server.
|
||||
|
||||
Here is the node list for the optimized file used in this sample app: https://github.com/Esri/offline-editor-js/issues/284
|
||||
Here is the list of contents for the optimized ArcGIS JS API file used in this sample app:
|
||||
https://github.com/Esri/offline-editor-js/issues/284
|
||||
|
||||
Use the Grunt task in the /samples directory to help generate the manifest file. There is manual
|
||||
work involved in determining which files need to go into the manifest. The included manifest
|
||||
@ -445,7 +449,7 @@
|
||||
|
||||
// IMPORTANT!!!
|
||||
// This tells the database which graphic.attribute property to use as a unique identifier
|
||||
// You can lok this information up in your feature service directory under the "Fields" category.
|
||||
// You can look this information up in your feature service directory under the "Fields" category.
|
||||
// Example: http://services1.arcgis.com/M8KJPUwAXP8jhtnM/arcgis/rest/services/Denver_Bus_Stops/FeatureServer/0
|
||||
offlineFeaturesManager.DB_UID = "FID";
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
"appHomePage": "appcache-features.html",
|
||||
"optimizedApiURL": "../samples/jsolib",
|
||||
"arcGISBaseURL": "http://js.arcgis.com/3.11",
|
||||
"version": "2.8.2",
|
||||
"version": "2.9.0",
|
||||
"private": true,
|
||||
"description": "manifest generator project",
|
||||
"repository": {
|
||||
|
||||
@ -115,30 +115,30 @@
|
||||
|
||||
try
|
||||
{
|
||||
var jasmineEnv = jasmine.getEnv();
|
||||
jasmineEnv.updateInterval = 1000;
|
||||
jasmineEnv.defaultTimeoutInterval = 10000; // 10 sec
|
||||
var htmlReporter = new jasmine.HtmlReporter();
|
||||
var jasmineEnv = jasmine.getEnv();
|
||||
jasmineEnv.updateInterval = 1000;
|
||||
jasmineEnv.defaultTimeoutInterval = 10000; // 10 sec
|
||||
var htmlReporter = new jasmine.HtmlReporter();
|
||||
|
||||
jasmineEnv.addReporter(htmlReporter);
|
||||
jasmineEnv.addReporter(htmlReporter);
|
||||
|
||||
jasmineEnv.specFilter = function(spec) {
|
||||
return htmlReporter.specFilter(spec);
|
||||
};
|
||||
jasmineEnv.specFilter = function(spec) {
|
||||
return htmlReporter.specFilter(spec);
|
||||
};
|
||||
|
||||
/*
|
||||
var currentWindowOnload = window.onload;
|
||||
/*
|
||||
var currentWindowOnload = window.onload;
|
||||
|
||||
window.onload = function() {
|
||||
if (currentWindowOnload) {
|
||||
currentWindowOnload();
|
||||
window.onload = function() {
|
||||
if (currentWindowOnload) {
|
||||
currentWindowOnload();
|
||||
}
|
||||
execJasmine();
|
||||
};
|
||||
*/
|
||||
function execJasmine() {
|
||||
jasmineEnv.execute();
|
||||
}
|
||||
execJasmine();
|
||||
};
|
||||
*/
|
||||
function execJasmine() {
|
||||
jasmineEnv.execute();
|
||||
}
|
||||
|
||||
execJasmine();
|
||||
}
|
||||
@ -146,8 +146,6 @@
|
||||
{
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
|
||||
}; // test()
|
||||
|
||||
}); // require()
|
||||
|
||||
@ -428,6 +428,53 @@ describe("Public Interface", function()
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
describe("Handle built-in feature collection in database", function(){
|
||||
async.it("Get null featureCollection", function(done) {
|
||||
g_editsStore._getFeatureCollections(function(success, result){
|
||||
expect(success).toBe(false);
|
||||
expect(result).toBeNull();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
async.it("Set featureCollection", function(done) {
|
||||
var featureCollectionObject = {
|
||||
// The id is required because the editsStore keypath
|
||||
// uses it as a UID for all entries in the database
|
||||
id: g_editsStore.FEATURE_COLLECTION_ID,
|
||||
featureCollections: [
|
||||
{
|
||||
featureLayerUrl: "TEST_URL1",
|
||||
featureLayerCollection: "featureCollectionFeature"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
g_editsStore._pushFeatureCollections(featureCollectionObject, function(success) {
|
||||
console.log("SUCCESS IS " + success);
|
||||
expect(success).toBe(true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
async.it("Get new featureCollection", function(done) {
|
||||
g_editsStore._getFeatureCollections(function(success, result){
|
||||
expect(success).toBe(true);
|
||||
expect(result.featureCollections[0].featureLayerUrl).toBe("TEST_URL1");
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
async.it("get size", function(done){
|
||||
g_editsStore.getUsage(function(success){
|
||||
expect(success).toEqual(jasmine.any(Object));
|
||||
expect(success.sizeBytes).toEqual(1695);
|
||||
expect(success.editCount).toEqual(3);
|
||||
done();
|
||||
})
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
@ -419,6 +419,14 @@ describe("Offline Editing", function()
|
||||
|
||||
});
|
||||
|
||||
async.it("Get empty featureCollections Object", function(done) {
|
||||
g_offlineFeaturesManager.getFeatureCollections(function(success, result) {
|
||||
expect(success).toBe(false);
|
||||
expect(result).toBeNull();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
async.it("update existing features - points", function(done)
|
||||
{
|
||||
expect(getObjectIds(g_featureLayers[0].graphics)).toEqual(getObjectIds([g1,g2,g3]));
|
||||
@ -449,6 +457,16 @@ describe("Offline Editing", function()
|
||||
});
|
||||
});
|
||||
|
||||
async.it("Get featureCollections Object", function(done) {
|
||||
g_offlineFeaturesManager.getFeatureCollections(function(success, result) {
|
||||
expect(success).toBe(true);
|
||||
expect(result.featureCollections.length).toBe(1);
|
||||
expect(result.featureCollections[0].featureLayerCollection).toEqual(g_featureLayers[0].toJson());
|
||||
expect(result.featureCollections[0].featureLayerUrl).toEqual("http://services1.arcgis.com/M8KJPUwAXP8jhtnM/arcgis/rest/services/Simple_Point_Service/FeatureServer/0");
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// NOTE: We are only dealing with points!
|
||||
//async.it("update existing features - lines", function(done)
|
||||
//{
|
||||
@ -656,12 +674,22 @@ describe("Offline Editing", function()
|
||||
|
||||
async.it("check db size", function(done){
|
||||
g_featureLayers[0].getUsage(function(usage,error){
|
||||
expect(usage.sizeBytes).toBe(3847);
|
||||
expect(usage.sizeBytes).toBe(9203);
|
||||
expect(usage.editCount).toBe(5);
|
||||
expect(error).toBe(null);
|
||||
done();
|
||||
})
|
||||
});
|
||||
|
||||
async.it("Validate featureCollections Object", function(done) {
|
||||
g_offlineFeaturesManager.getFeatureCollections(function(success, result) {
|
||||
expect(success).toBe(true);
|
||||
expect(result.featureCollections.length).toBe(1);
|
||||
expect(result.featureCollections[0].featureLayerCollection).toEqual(g_featureLayers[0].toJson());
|
||||
expect(result.featureCollections[0].featureLayerUrl).toEqual("http://services1.arcgis.com/M8KJPUwAXP8jhtnM/arcgis/rest/services/Simple_Point_Service/FeatureServer/0");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// TO-DO!!
|
||||
@ -1095,6 +1123,16 @@ describe("Offline Editing", function()
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
async.it("Validate featureCollections Object", function(done) {
|
||||
g_offlineFeaturesManager.getFeatureCollections(function(success, result) {
|
||||
expect(success).toBe(true);
|
||||
expect(result.featureCollections.length).toBe(1);
|
||||
expect(result.featureCollections[0].featureLayerCollection).toEqual(g_featureLayers[0].toJson());
|
||||
expect(result.featureCollections[0].featureLayerUrl).toEqual("http://services1.arcgis.com/M8KJPUwAXP8jhtnM/arcgis/rest/services/Simple_Point_Service/FeatureServer/0");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("go Online", function()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user