From 5114c80ee1c6e400d0da38f587aaf0d71ba04f00 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Wed, 4 Jun 2014 14:11:08 -0600 Subject: [PATCH 001/139] added separate xhr request for offline detect --- samples/appcache-tiles.html | 40 +++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/samples/appcache-tiles.html b/samples/appcache-tiles.html index 9ee027a..7bab8ce 100644 --- a/samples/appcache-tiles.html +++ b/samples/appcache-tiles.html @@ -73,11 +73,11 @@ } - + - + - - - - - - - - + + + + + + + + + else{ + console.log("success deleting tile cache"); + var self = this.data; + + if( globalState.downloadState == 'downloading') + { + console.log("cancel!"); + _wantToCancel = true; + btnGetTiles.innerHTML = "cancelling.."; + } + else + { + var zoom = getMinMaxZoom(); + + var extent = baseMapLayer.getExtentBuffer(EXTENT_BUFFER,map.extent); + _wantToCancel = false; + baseMapLayer.prepareForOffline(zoom.min, zoom.max, extent, reportProgress.bind(this)); + globalState.downloadState = 'downloading'; + } + } + }.bind(this)) +} + +function goOnlineOffline(){ + if(imgOfflineIndicator.offlineColor == "blue"){ + btnOnlineOffline.innerHTML = "2. Go Online"; + imgOfflineIndicator.src = redPinPath; + imgOfflineIndicator.offlineColor = "red"; + baseMapLayer.goOffline(); + } + else{ + btnOnlineOffline.innerHTML = "2. Go Offline"; + imgOfflineIndicator.src = bluePinPath; + imgOfflineIndicator.offlineColor = "blue"; + baseMapLayer.goOnline(); + } +} + +function panLeft(){ + map.panLeft(); +} + @@ -371,5 +341,4 @@ console.log("STATE OFFLINE: " + Offline.state)
- - \ No newline at end of file + \ No newline at end of file From d07c26590719de3c833d2b21451d9672e0ebfb0b Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Thu, 5 Jun 2014 10:52:34 -0600 Subject: [PATCH 009/139] added manifest reference to popup-sprite --- samples/Gruntfile.js | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/Gruntfile.js b/samples/Gruntfile.js index 0f130b5..67ffee8 100644 --- a/samples/Gruntfile.js +++ b/samples/Gruntfile.js @@ -29,6 +29,7 @@ module.exports = function(grunt) { "<%= pkg.optimizedApiURL %>/dojo/nls/dojo_en-us.js", "<%= pkg.optimizedApiURL %>/dojo/selector/acme.js", "#", + "<%= pkg.arcGISBaseURL %>/js/esri/dijit/images/popup-sprite.png", "<%= pkg.arcGISBaseURL %>/js/dojo/dojox/gfx/svg.js", "<%= pkg.arcGISBaseURL %>/js/dojo/dojo/resources/blank.gif", "<%= pkg.arcGISBaseURL %>/js/esri/dijit/images/ajax-loader.gif", From 7e8018c4d950a7c09eab7d933917b63bb37ce881 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Thu, 5 Jun 2014 17:19:32 -0600 Subject: [PATCH 010/139] added a check for offline state. Changes life cycle of library --- lib/tiles/offlineTilesEnabler.js | 144 +++++++++++++++++-------------- 1 file changed, 77 insertions(+), 67 deletions(-) diff --git a/lib/tiles/offlineTilesEnabler.js b/lib/tiles/offlineTilesEnabler.js index 1635ac3..0172d12 100644 --- a/lib/tiles/offlineTilesEnabler.js +++ b/lib/tiles/offlineTilesEnabler.js @@ -26,9 +26,10 @@ define([ * After extending one layer, you can call layer.goOffline() or layer.goOnline() * @param layer * @param callback + * @param state Optional Recommended. Whether or not the application is online or offline. * @returns {callback} callback(boolean, string) */ - extend: function(layer,callback) + extend: function(layer,callback,/* boolean */ state) { console.log("extending layer", layer.url); @@ -40,85 +41,94 @@ define([ /* we also add some additional attributes inside an "offline" object */ layer._getTileUrl = layer.getTileUrl; + + var isOnline = true; + if(typeof state != "undefined"){ + isOnline = state; console.log("STATE IS: " + state) + } + layer.offline = { - online: true, + online: isOnline, store: new TilesStore(), proxyPath: "../lib/resource-proxy/proxy.php" }; if( /*false &&*/ layer.offline.store.isSupported() ) { - layer.offline.store.init(callback); + // Important: wait to load tiles until after database has initialized! + layer.offline.store.init(function(success){ + if(success){ + layer.resampling = false; + + /** + * Internal method that overrides the getTileUrl() method. + * If application is offline then tiles are written to local storage. + * Retrieves tiles as requested by the ArcGIS API for JavaScript. + * If a tile is in cache it is returned. + * If it is not in cache then one is retrieved over the internet. + * @param level + * @param row + * @param col + * @returns {String} URL + */ + layer.getTileUrl = function(level,row,col) + { + console.assert(!isNaN(level) && !isNaN(row) && !isNaN(col), "bad tile requested"); + + console.log("looking for tile",level,row,col); + var url = this._getTileUrl(level,row,col); + console.log("LIBRARY ONLINE " + this.offline.online) + if( this.offline.online ) + { + if(layer._imageType == "")layer._imageType = this.tileInfo.format.toLowerCase(); + console.log("fetching url online: ", url); + layer._lastTileUrl = url; + return url; + } + + url = url.split("?")[0]; + + /* temporary URL returned immediately, as we haven't retrieved the image from the indexeddb yet */ + var tileid = "void:/"+level+"/"+row+"/"+col; + + this.offline.store.retrieve(url, function(success, offlineTile) + { console.log("TILE RETURN " + success + ", " + offlineTile) + /* when the .get() callback is called we replace the temporary URL originally returned by the data:image url */ + // search for the img with src="void:"+level+"-"+row+"-"+col and replace with actual url + var img = query("img[src="+tileid+"]")[0]; + var imgURL; + + console.assert(img !== "undefined", "undefined image detected"); + + if( success ) + { + img.style.borderColor = "blue"; + console.log("found tile offline", url); + imgURL = "data:image/" + layer._imageType +";base64," + offlineTile.img; + } + else + { + img.style.borderColor = "green"; + console.log("tile is not in the offline store", url); + imgURL = "data:image/png;base64,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pmk0TROPj48Hn3l4eIimaSJN06O3A4NJwDMxm82ibdtXo4D5fB6r1Sp+//4dz8/Pw5H+6ekpdrtdJEkS8/n8S/9f713ie3vaceo9x557QAB451Sgfyin34HKshweunk5HzAej2MymXz5+f9nbjJyI9L39Wu5XP55+XQZ39uxR4Z3u90wSXjqEV0wAjhjx47oaZq63Me/ZhIQBAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEAAbAJQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEAvqe/BwCeKjUweoA8pQAAAABJRU5ErkJggg=="; + } + // when we return a nonexistent url to the image, the TiledMapServiceLayer::_tileErrorHandler() method + // sets img visibility to 'hidden', so we need to show the image back once we have put the data:image + img.style.visibility = "visible"; + img.src = imgURL; + return ""; /* this result goes nowhere, seriously */ + }); + + return tileid; + }; + } + }.bind(this)); } else { return callback(false, "indexedDB not supported"); } - layer.resampling = false; - - /** - * Internal method that overrides the getTileUrl() method. - * If application is offline then tiles are written to local storage. - * Retrieves tiles as requested by the ArcGIS API for JavaScript. - * If a tile is in cache it is returned. - * If it is not in cache then one is retrieved over the internet. - * @param level - * @param row - * @param col - * @returns {String} URL - */ - layer.getTileUrl = function(level,row,col) - { - console.assert(!isNaN(level) && !isNaN(row) && !isNaN(col), "bad tile requested"); - - console.log("looking for tile",level,row,col); - var url = this._getTileUrl(level,row,col); -console.log("LIBRARY ONLINE " + this.offline.online) - if( this.offline.online ) - { - if(layer._imageType == "")layer._imageType = this.tileInfo.format.toLowerCase(); - console.log("fetching url online: ", url); - layer._lastTileUrl = url; - return url; - } - - url = url.split("?")[0]; - - /* temporary URL returned immediately, as we haven't retrieved the image from the indexeddb yet */ - var tileid = "void:/"+level+"/"+row+"/"+col; - - this.offline.store.retrieve(url, function(success, offlineTile) - { - /* when the .get() callback is called we replace the temporary URL originally returned by the data:image url */ - // search for the img with src="void:"+level+"-"+row+"-"+col and replace with actual url - var img = query("img[src="+tileid+"]")[0]; - var imgURL; - - console.assert(img !== "undefined", "undefined image detected"); - - if( success ) - { - img.style.borderColor = "blue"; - console.log("found tile offline", url); - imgURL = "data:image/" + layer._imageType +";base64," + offlineTile.img; - } - else - { - img.style.borderColor = "green"; - console.log("tile is not in the offline store", url); - imgURL = "data:image/png;base64,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pmk0TROPj48Hn3l4eIimaSJN06O3A4NJwDMxm82ibdtXo4D5fB6r1Sp+//4dz8/Pw5H+6ekpdrtdJEkS8/n8S/9f713ie3vaceo9x557QAB451Sgfyin34HKshweunk5HzAej2MymXz5+f9nbjJyI9L39Wu5XP55+XQZ39uxR4Z3u90wSXjqEV0wAjhjx47oaZq63Me/ZhIQBAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEAAbAJQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEAvqe/BwCeKjUweoA8pQAAAABJRU5ErkJggg=="; - } - // when we return a nonexistent url to the image, the TiledMapServiceLayer::_tileErrorHandler() method - // sets img visibility to 'hidden', so we need to show the image back once we have put the data:image - img.style.visibility = "visible"; - img.src = imgURL; - return ""; /* this result goes nowhere, seriously */ - }); - - return tileid; - }; - /** * Returns an object that contains the number of tiles that would need to be downloaded * for the specified extent and zoom level, and the estimated byte size of such tiles. From 5a8196d655204c48cc1e2a44e91c5a35523ae139 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Thu, 5 Jun 2014 17:20:33 -0600 Subject: [PATCH 011/139] added new offline verification sequencing --- samples/appcache-tiles.html | 65 +++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 17 deletions(-) diff --git a/samples/appcache-tiles.html b/samples/appcache-tiles.html index 65765b4..9310a58 100644 --- a/samples/appcache-tiles.html +++ b/samples/appcache-tiles.html @@ -94,6 +94,7 @@ ask if you want to reload the application. var map,offlineTileEnabler,baseMapLayer,zoom = 18; var globalState = {}; var _wantToCancel; +var _isOnline = true; var minZoomAdjust = -1, maxZoomAdjust = 1, mMinZoom, mMaxZoom; var imgOfflineIndicator,btnGetTiles,btnOnlineOffline,btnZoom; var tiles,appCacheManager,tileInfo; @@ -108,23 +109,32 @@ require(["esri/map","utils/appCacheManager","tiles/offlineTilesEnabler","dojo/on imgOfflineIndicator.offlineColor = "blue"; Offline.check(); + Offline.on('up down', updateState ); - //Make sure map shows up after a browser refresh - Offline.state === 'up' ? zoom = 18 : zoom = 17; + verifyOnline(function(result){ console.log("VERIFY ONLINE " + result) + result == true ? _isOnline = true : _isOnline = false; + startMap(); - map = new Map("map", { - basemap: "topo", - center: [-122.45,37.75], // long, lat - zoom: zoom, - sliderStyle: "small" - }); - - map.on("load",function(evt){ - init(); - initOfflineTileEnabler(); - console.log("level: " + map.getLevel() + ", maxZoom: " + map.getMaxZoom()); }) + function startMap(){ + //Make sure map shows up after a browser refresh + Offline.state === 'up' ? zoom = 18 : zoom = 17; + + map = new Map("map", { + basemap: "topo", + center: [-122.45,37.75], // long, lat + zoom: zoom, + sliderStyle: "small" + }); + + map.on("load",function(evt){ + init(); + initOfflineTileEnabler(); + console.log("level: " + map.getLevel() + ", maxZoom: " + map.getMaxZoom()); + }) + } + function init(){ map.on("extent-change",function(evt){ // updateOfflineUsage(); @@ -151,8 +161,7 @@ require(["esri/map","utils/appCacheManager","tiles/offlineTilesEnabler","dojo/on mMinZoom = map.getMinZoom(); offlineTileEnabler = new OfflineTileEnabler(); - baseMapLayer = offlineTileEnabler.getBasemapLayer(map); - baseMapLayer.offline.online = + baseMapLayer = offlineTileEnabler.getBasemapLayer(map); console.log("Offline State: " + Offline.state) offlineTileEnabler.extend(baseMapLayer,function(success) { @@ -160,7 +169,6 @@ require(["esri/map","utils/appCacheManager","tiles/offlineTilesEnabler","dojo/on { console.log("Offline tile lib is enabled"); Offline.check(); - Offline.on('up down', updateState ); console.log("LIBRARY STATUS IS: " + Offline.state); //using null sets this for CORS baseMapLayer.offline.proxyPath = null; @@ -171,7 +179,7 @@ console.log("LIBRARY STATUS IS: " + Offline.state); { alert("error initializing storage - browser doesn't support indexeddb or websql") } - }.bind(this)); + }.bind(this),_isOnline); } function cacheEventHandler(evt){ @@ -311,6 +319,29 @@ function downloadTiles(){ }.bind(this)) } +function verifyOnline(callback){ + var req = new XMLHttpRequest(); + req.open("GET", "images/blue-pin.png?" + (Math.floor(Math.random() * 1000000000)), true); + req.onload = function() + { + if( req.status === 200 && req.responseText !== "") + { + callback(true); + } + else + { + console.log("verifyOffline failed"); + callback(false); + } + }; + req.onerror = function(e) + { + console.log("verifyOffline failed: " + e); + callback(false); + }; + req.send(null); +} + function goOnlineOffline(){ if(imgOfflineIndicator.offlineColor == "blue"){ btnOnlineOffline.innerHTML = "2. Go Online"; From c3aba631b1f83a08b961d2b51b972378a64a9769 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Thu, 5 Jun 2014 17:25:43 -0600 Subject: [PATCH 012/139] added checks for undefined object --- samples/appcache-tiles.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/appcache-tiles.html b/samples/appcache-tiles.html index 9310a58..c5c6521 100644 --- a/samples/appcache-tiles.html +++ b/samples/appcache-tiles.html @@ -194,11 +194,11 @@ console.log("LIBRARY STATUS IS: " + Offline.state); if(Offline.state === 'up'){ // updateOfflineUsage(); imgOfflineIndicator.src = bluePinPath; - baseMapLayer.goOnline(); + if(typeof baseMapLayer != "undefined") baseMapLayer.goOnline(); } else{ imgOfflineIndicator.src = redPinPath; - baseMapLayer.goOffline(); + if(typeof baseMapLayer != "undefined") baseMapLayer.goOffline(); } } From d8aa79cc39773be83c71212b09719a7becedb46f Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Thu, 5 Jun 2014 17:27:15 -0600 Subject: [PATCH 013/139] doc tweak --- samples/appcache-tiles.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/samples/appcache-tiles.html b/samples/appcache-tiles.html index c5c6521..1541af7 100644 --- a/samples/appcache-tiles.html +++ b/samples/appcache-tiles.html @@ -11,6 +11,9 @@ This sample demonstrates using an application manifest to store tiles locally. The use cases for using this sample are to ensure you can reload and restart you application one it is offline. +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/ + Use the included Grunt task to help generate the manifest file. There is manual work involved in determining which files need to go into the manifest. The included manifest file should work with this sample to give you an idea of what goes into the manifest. From 6e26fe1b48a3596afde2e35ab5cf24e0346ed664 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 09:29:08 -0600 Subject: [PATCH 014/139] tweaked code comment --- lib/tiles/offlineTilesEnabler.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/tiles/offlineTilesEnabler.js b/lib/tiles/offlineTilesEnabler.js index 0172d12..0500abb 100644 --- a/lib/tiles/offlineTilesEnabler.js +++ b/lib/tiles/offlineTilesEnabler.js @@ -26,7 +26,8 @@ define([ * After extending one layer, you can call layer.goOffline() or layer.goOnline() * @param layer * @param callback - * @param state Optional Recommended. Whether or not the application is online or offline. + * @param state Optional Recommended. Pre-sets whether or not the application is online or offline. + * Specifically used for applications that need to protect against browser reload/restart while offline. * @returns {callback} callback(boolean, string) */ extend: function(layer,callback,/* boolean */ state) From 74bf9c03bccdc5afc51d7fcad5e7082842b1e77b Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 10:08:06 -0600 Subject: [PATCH 015/139] added cache-loaded event --- utils/appCacheManager.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/utils/appCacheManager.js b/utils/appCacheManager.js index f98a01d..0f27c7d 100644 --- a/utils/appCacheManager.js +++ b/utils/appCacheManager.js @@ -14,6 +14,7 @@ define([ UPDATE_READY: "update-ready", UPDATE_NONE: "no-update", CACHE_EVENT: "cache-event", + CACHE_LOADED: "cache-loaded", CACHE_ERROR: "cache-error", appCache: window.applicationCache, @@ -101,6 +102,12 @@ define([ }, _handleCacheEvents:function(evt){ + if(evt.hasOwnProperty("total") && evt.hasOwnProperty("loaded")){ + if(evt.total == evt.loaded){ + console.log("appCacheManager: cache has finished loading.") + this.emit(this.CACHE_LOADED,"cache-loaded"); + } + } this.emit(this.CACHE_EVENT,evt); }, From 58250bdc261d006f82be22bf31d84e815f8aa7b9 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 10:10:22 -0600 Subject: [PATCH 016/139] code comment tweaks --- utils/appCacheManager.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/utils/appCacheManager.js b/utils/appCacheManager.js index 0f27c7d..6e2312f 100644 --- a/utils/appCacheManager.js +++ b/utils/appCacheManager.js @@ -1,5 +1,12 @@ /** * Helper Class for working with the application cache. + * + * Listen for the following events: + * UPDATE_READY - an update to the cache is ready + * UPDATE_NONE - the cache hasn't changed since the last app load. + * CACHE_LOADED - the cache has finished loading. + * CACHE_ERROR - an error was thrown by the browser while attempting to load the cache. + * * For more information on application cache: * https://developer.mozilla.org/en-US/docs/HTML/Using_the_application_cache * Many thanks and all kudos go to the following blog posts: From 39493e87882d19b7db34e1bc815b192ce46b0364 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 10:32:28 -0600 Subject: [PATCH 017/139] added detect and verify for websql --- lib/tiles/TilesStore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tiles/TilesStore.js b/lib/tiles/TilesStore.js index 8690cdd..cedcbf5 100644 --- a/lib/tiles/TilesStore.js +++ b/lib/tiles/TilesStore.js @@ -26,7 +26,7 @@ define([],function() */ this.isSupported = function(){ - if(!window.indexedDB){ + if(!window.indexedDB && !window.openDatabase){ return false; } From d70d3f3ea726698cac1fd115f6d1d80cc256ef3c Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 11:01:20 -0600 Subject: [PATCH 018/139] moved callback to after db init --- lib/tiles/offlineTilesEnabler.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/tiles/offlineTilesEnabler.js b/lib/tiles/offlineTilesEnabler.js index 0500abb..a74e5b8 100644 --- a/lib/tiles/offlineTilesEnabler.js +++ b/lib/tiles/offlineTilesEnabler.js @@ -59,6 +59,7 @@ define([ // Important: wait to load tiles until after database has initialized! layer.offline.store.init(function(success){ if(success){ + callback(true); layer.resampling = false; /** From ce47cb1178e56d725842b05cbc3918704fcfab50 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 11:01:47 -0600 Subject: [PATCH 019/139] changed how no. of tiles are calc'd --- samples/appcache-tiles.html | 85 ++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 34 deletions(-) diff --git a/samples/appcache-tiles.html b/samples/appcache-tiles.html index 1541af7..0b8f2f4 100644 --- a/samples/appcache-tiles.html +++ b/samples/appcache-tiles.html @@ -170,13 +170,13 @@ require(["esri/map","utils/appCacheManager","tiles/offlineTilesEnabler","dojo/on { if( success ) { - console.log("Offline tile lib is enabled"); + console.log("Offline tile lib is enabled. Application state is: " + Offline.state); Offline.check(); -console.log("LIBRARY STATUS IS: " + Offline.state); + //using null sets this for CORS baseMapLayer.offline.proxyPath = null; -// updateOfflineUsage(); + updateOfflineUsage(); } else { @@ -195,7 +195,7 @@ console.log("LIBRARY STATUS IS: " + Offline.state); function updateState(){ if(Offline.state === 'up'){ -// updateOfflineUsage(); + updateOfflineUsage(); imgOfflineIndicator.src = bluePinPath; if(typeof baseMapLayer != "undefined") baseMapLayer.goOnline(); } @@ -207,15 +207,23 @@ console.log("LIBRARY STATUS IS: " + Offline.state); function updateOfflineUsage() { - var count = getEstimateTileCount(function(info,err){ - if(info != null){ - console.log("COUNT " + info) - tileInfo.innerHTML = "Tile count: " + info.tileCount + "\r\nBytes: " + info.sizeBytes; +// var count = getEstimateTileCount(function(count){ +// if(count != null){ +// console.log("COUNT " + count) +// tileInfo.innerHTML = "Tile count: " + count + "\r\nBytes: " + count.sizeBytes; +// } +// }); + + var count = 0; + baseMapLayer.offline.store.getAllTiles(function(tiles){ + if(tiles != null) { + count++; } else{ - console.log("ERROR updateOfflineUsage(): " + JSON.stringify(err)); + console.log("COUNT " + count) + tileInfo.innerHTML = "Tile count: " + count + "\r\nBytes: " + count.sizeBytes; } - }); + }) } /** @@ -224,33 +232,42 @@ console.log("LIBRARY STATUS IS: " + Offline.state); */ function getEstimateTileCount(callback) { - var extent = baseMapLayer.getExtentBuffer(EXTENT_BUFFER,map.extent); - var level = map.getLevel(); - var url = baseMapLayer.getTileUrlsByExtent(extent,level)[0]; - baseMapLayer._lastTileUrl = url; - baseMapLayer.estimateTileSize(function(tileSize,err){ - - if(tileSize != null){ - var totalEstimation = {tileCount:0,sizeBytes:0}; - - var zoom = getMinMaxZoom(); - - for(var level = zoom.min; level<= zoom.max; level++) - { - var levelEstimation = baseMapLayer.getLevelEstimation(baseMapLayer.getExtentBuffer(EXTENT_BUFFER,map.extent),level,tileSize); - - totalEstimation.tileCount += levelEstimation.tileCount; - totalEstimation.sizeBytes += levelEstimation.sizeBytes; - } - - console.log("Size estimate: " + totalEstimation.sizeBytes + ", tile count: " + totalEstimation.tileCount) - callback(totalEstimation,null); + var count = 0; + baseMapLayer.offline.store.getAllTiles(function(tiles){ + if(tiles != null) { + count++; } else{ - callback(null,err); + callback(count); } - - }.bind(this)) + }) +// var extent = baseMapLayer.getExtentBuffer(EXTENT_BUFFER,map.extent); +// var level = map.getLevel(); +// var url = baseMapLayer.getTileUrlsByExtent(extent,level)[0]; +// baseMapLayer._lastTileUrl = url; +// baseMapLayer.estimateTileSize(function(tileSize,err){ +// +// if(tileSize != null){ +// var totalEstimation = {tileCount:0,sizeBytes:0}; +// +// var zoom = getMinMaxZoom(); +// +// for(var level = zoom.min; level<= zoom.max; level++) +// { +// var levelEstimation = baseMapLayer.getLevelEstimation(baseMapLayer.getExtentBuffer(EXTENT_BUFFER,map.extent),level,tileSize); +// +// totalEstimation.tileCount += levelEstimation.tileCount; +// totalEstimation.sizeBytes += levelEstimation.sizeBytes; +// } +// +// console.log("Size estimate: " + totalEstimation.sizeBytes + ", tile count: " + totalEstimation.tileCount) +// callback(totalEstimation,null); +// } +// else{ +// callback(null,err); +// } +// +// }.bind(this)) } } ); From c9bc31af3a773e8666adaa907534baffe58c7fdf Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 11:02:57 -0600 Subject: [PATCH 020/139] removed old code --- samples/appcache-tiles.html | 51 ------------------------------------- 1 file changed, 51 deletions(-) diff --git a/samples/appcache-tiles.html b/samples/appcache-tiles.html index 0b8f2f4..bd24cc7 100644 --- a/samples/appcache-tiles.html +++ b/samples/appcache-tiles.html @@ -207,13 +207,6 @@ require(["esri/map","utils/appCacheManager","tiles/offlineTilesEnabler","dojo/on function updateOfflineUsage() { -// var count = getEstimateTileCount(function(count){ -// if(count != null){ -// console.log("COUNT " + count) -// tileInfo.innerHTML = "Tile count: " + count + "\r\nBytes: " + count.sizeBytes; -// } -// }); - var count = 0; baseMapLayer.offline.store.getAllTiles(function(tiles){ if(tiles != null) { @@ -225,50 +218,6 @@ require(["esri/map","utils/appCacheManager","tiles/offlineTilesEnabler","dojo/on } }) } - - /** - * Gets tile count and size estimates. Not perfect. - * @param callback - */ - function getEstimateTileCount(callback) - { - var count = 0; - baseMapLayer.offline.store.getAllTiles(function(tiles){ - if(tiles != null) { - count++; - } - else{ - callback(count); - } - }) -// var extent = baseMapLayer.getExtentBuffer(EXTENT_BUFFER,map.extent); -// var level = map.getLevel(); -// var url = baseMapLayer.getTileUrlsByExtent(extent,level)[0]; -// baseMapLayer._lastTileUrl = url; -// baseMapLayer.estimateTileSize(function(tileSize,err){ -// -// if(tileSize != null){ -// var totalEstimation = {tileCount:0,sizeBytes:0}; -// -// var zoom = getMinMaxZoom(); -// -// for(var level = zoom.min; level<= zoom.max; level++) -// { -// var levelEstimation = baseMapLayer.getLevelEstimation(baseMapLayer.getExtentBuffer(EXTENT_BUFFER,map.extent),level,tileSize); -// -// totalEstimation.tileCount += levelEstimation.tileCount; -// totalEstimation.sizeBytes += levelEstimation.sizeBytes; -// } -// -// console.log("Size estimate: " + totalEstimation.sizeBytes + ", tile count: " + totalEstimation.tileCount) -// callback(totalEstimation,null); -// } -// else{ -// callback(null,err); -// } -// -// }.bind(this)) - } } ); From 5dfcbae0fc5acb4fc0432cb5457cb01c1bf27e99 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 11:26:23 -0600 Subject: [PATCH 021/139] moved javascript block to bottom --- samples/appcache-tiles.html | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/samples/appcache-tiles.html b/samples/appcache-tiles.html index bd24cc7..ea84070 100644 --- a/samples/appcache-tiles.html +++ b/samples/appcache-tiles.html @@ -93,6 +93,18 @@ ask if you want to reload the application. } } + + + +
+ + + + + +
+
+ - - -
- - - - - -
-
\ No newline at end of file From 5b2680bf0db0d34167ecba5f99ecc6adc2c0c7cd Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 11:41:20 -0600 Subject: [PATCH 022/139] moved code inside require closure --- samples/appcache-tiles.html | 171 ++++++++++++++++++------------------ 1 file changed, 87 insertions(+), 84 deletions(-) diff --git a/samples/appcache-tiles.html b/samples/appcache-tiles.html index ea84070..f5d91d7 100644 --- a/samples/appcache-tiles.html +++ b/samples/appcache-tiles.html @@ -97,10 +97,10 @@ ask if you want to reload the application.
- + - +
@@ -161,6 +161,7 @@ require(["esri/map","utils/appCacheManager","tiles/offlineTilesEnabler","dojo/on btnGetTiles = document.getElementById("btn-get-tiles"); btnOnlineOffline = document.getElementById("btn-online-offline"); + btnZoom = document.getElementById("btn-zoom-out"); tileInfo = document.getElementById("tile-info") @@ -188,6 +189,7 @@ require(["esri/map","utils/appCacheManager","tiles/offlineTilesEnabler","dojo/on //using null sets this for CORS baseMapLayer.offline.proxyPath = null; + on(btnOnlineOffline,"click",goOnlineOffline); updateOfflineUsage(); } else @@ -228,76 +230,92 @@ require(["esri/map","utils/appCacheManager","tiles/offlineTilesEnabler","dojo/on } }) } + + function getMinMaxZoom(){ + + var zoom = {}; + var min = map.getLevel() + minZoomAdjust; + var max = map.getLevel() + maxZoomAdjust; + zoom.max = Math.min(mMaxZoom, max); //prevent errors by setting the tile layer floor + zoom.min = Math.max(mMinZoom, min); //prevent errors by setting the tile layer ceiling + + return zoom; + } + + function reportProgress(progress) + { + console.log("downloading tiles..."); + if(progress.hasOwnProperty("countNow")){ + var percent = Math.floor(progress.countNow / progress.countMax * 100); + btnGetTiles.innerHTML = 'Saving to phone ' + percent + "% - Tap to Cancel"; + } + + if( progress.finishedDownloading ) + { + btnGetTiles.innerHTML = "Saving to phone 100% - Tap to Cancel"; + updateOfflineUsage(); + + if( progress.cancelRequested ) + { + globalState.downloadState = 'cancelled'; + alert("Tile download was cancelled"); + } + else + { + globalState.downloadState = 'downloaded'; + alert("Tile download complete"); + } + + btnGetTiles.innerHTML = '1. Download Tiles'; + } + return _wantToCancel; //determines if a cancel request has been issued + } + + function goOnlineOffline(){ + if(imgOfflineIndicator.offlineColor == "blue"){ + btnOnlineOffline.innerHTML = "2. Go Online"; + imgOfflineIndicator.src = redPinPath; + imgOfflineIndicator.offlineColor = "red"; + baseMapLayer.goOffline(); + } + else{ + btnOnlineOffline.innerHTML = "2. Go Offline"; + imgOfflineIndicator.src = bluePinPath; + imgOfflineIndicator.offlineColor = "blue"; + baseMapLayer.goOnline(); + } + } + + function downloadTiles(){ + baseMapLayer.deleteAllTiles(function(success,err){ + if(success == false){ + alert("There was a problem deleting the tile cache"); + } + else{ + console.log("success deleting tile cache"); + var self = this.data; + + if( globalState.downloadState == 'downloading') + { + console.log("cancel!"); + _wantToCancel = true; + btnGetTiles.innerHTML = "cancelling.."; + } + else + { + var zoom = getMinMaxZoom(); + + var extent = baseMapLayer.getExtentBuffer(EXTENT_BUFFER,map.extent); + _wantToCancel = false; + baseMapLayer.prepareForOffline(zoom.min, zoom.max, extent, reportProgress.bind(this)); + globalState.downloadState = 'downloading'; + } + } + }.bind(this)) + } } ); -function getMinMaxZoom(){ - - var zoom = {}; - var min = map.getLevel() + minZoomAdjust; - var max = map.getLevel() + maxZoomAdjust; - zoom.max = Math.min(mMaxZoom, max); //prevent errors by setting the tile layer floor - zoom.min = Math.max(mMinZoom, min); //prevent errors by setting the tile layer ceiling - - return zoom; -} - -function reportProgress(progress) -{ - console.log("downloading tiles..."); - if(progress.hasOwnProperty("countNow")){ - var percent = Math.floor(progress.countNow / progress.countMax * 100); - btnGetTiles.innerHTML = 'Saving to phone ' + percent + "% - Tap to Cancel"; - } - - if( progress.finishedDownloading ) - { - btnGetTiles.innerHTML = "Saving to phone 100% - Tap to Cancel"; - - if( progress.cancelRequested ) - { - globalState.downloadState = 'cancelled'; - alert("Tile download was cancelled"); - } - else - { - globalState.downloadState = 'downloaded'; - alert("Tile download complete"); - } - - btnGetTiles.innerHTML = '1. Download Tiles'; - } - return _wantToCancel; //determines if a cancel request has been issued -} - -function downloadTiles(){ - baseMapLayer.deleteAllTiles(function(success,err){ - if(success == false){ - alert("There was a problem deleting the tile cache"); - } - else{ - console.log("success deleting tile cache"); - var self = this.data; - - if( globalState.downloadState == 'downloading') - { - console.log("cancel!"); - _wantToCancel = true; - btnGetTiles.innerHTML = "cancelling.."; - } - else - { - var zoom = getMinMaxZoom(); - - var extent = baseMapLayer.getExtentBuffer(EXTENT_BUFFER,map.extent); - _wantToCancel = false; - baseMapLayer.prepareForOffline(zoom.min, zoom.max, extent, reportProgress.bind(this)); - globalState.downloadState = 'downloading'; - } - } - }.bind(this)) -} - function verifyOnline(callback){ var req = new XMLHttpRequest(); req.open("GET", "images/blue-pin.png?" + (Math.floor(Math.random() * 1000000000)), true); @@ -321,21 +339,6 @@ function verifyOnline(callback){ req.send(null); } -function goOnlineOffline(){ - if(imgOfflineIndicator.offlineColor == "blue"){ - btnOnlineOffline.innerHTML = "2. Go Online"; - imgOfflineIndicator.src = redPinPath; - imgOfflineIndicator.offlineColor = "red"; - baseMapLayer.goOffline(); - } - else{ - btnOnlineOffline.innerHTML = "2. Go Offline"; - imgOfflineIndicator.src = bluePinPath; - imgOfflineIndicator.offlineColor = "blue"; - baseMapLayer.goOnline(); - } -} - function panLeft(){ map.panLeft(); } From bf0004fce6ad8944e0fec59f7e0b5559e51116fa Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 11:42:14 -0600 Subject: [PATCH 023/139] moved verifyOnline into closure --- samples/appcache-tiles.html | 46 ++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/samples/appcache-tiles.html b/samples/appcache-tiles.html index f5d91d7..9217919 100644 --- a/samples/appcache-tiles.html +++ b/samples/appcache-tiles.html @@ -313,32 +313,32 @@ require(["esri/map","utils/appCacheManager","tiles/offlineTilesEnabler","dojo/on } }.bind(this)) } + + function verifyOnline(callback){ + var req = new XMLHttpRequest(); + req.open("GET", "images/blue-pin.png?" + (Math.floor(Math.random() * 1000000000)), true); + req.onload = function() + { + if( req.status === 200 && req.responseText !== "") + { + callback(true); + } + else + { + console.log("verifyOffline failed"); + callback(false); + } + }; + req.onerror = function(e) + { + console.log("verifyOffline failed: " + e); + callback(false); + }; + req.send(null); + } } ); -function verifyOnline(callback){ - var req = new XMLHttpRequest(); - req.open("GET", "images/blue-pin.png?" + (Math.floor(Math.random() * 1000000000)), true); - req.onload = function() - { - if( req.status === 200 && req.responseText !== "") - { - callback(true); - } - else - { - console.log("verifyOffline failed"); - callback(false); - } - }; - req.onerror = function(e) - { - console.log("verifyOffline failed: " + e); - callback(false); - }; - req.send(null); -} - function panLeft(){ map.panLeft(); } From 9a63ebc62e8d264ae8ce7f817946ce81407086fb Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 11:50:44 -0600 Subject: [PATCH 024/139] moved listener on btn-get-tiles into closure --- samples/appcache-tiles.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/samples/appcache-tiles.html b/samples/appcache-tiles.html index 9217919..e2d6d2e 100644 --- a/samples/appcache-tiles.html +++ b/samples/appcache-tiles.html @@ -99,7 +99,7 @@ ask if you want to reload the application.
- +
@@ -190,6 +190,8 @@ require(["esri/map","utils/appCacheManager","tiles/offlineTilesEnabler","dojo/on baseMapLayer.offline.proxyPath = null; on(btnOnlineOffline,"click",goOnlineOffline); + on(btnGetTiles,"click",downloadTiles); + updateOfflineUsage(); } else From 7c454b68f8784211978345076fdfc0d08f58fefe Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 11:52:09 -0600 Subject: [PATCH 025/139] tweak code comments --- samples/appcache-tiles.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/samples/appcache-tiles.html b/samples/appcache-tiles.html index e2d6d2e..54589a8 100644 --- a/samples/appcache-tiles.html +++ b/samples/appcache-tiles.html @@ -12,7 +12,8 @@ The use cases for using this sample are to ensure you can reload and restart you one it is offline. 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/ +using the Web Optimizer: http://jso.arcgis.com/. You can reference the CDN or host it on your +own web server. Use the included Grunt task to help generate the manifest file. There is manual work involved in determining which files need to go into the manifest. The included manifest @@ -191,7 +192,7 @@ require(["esri/map","utils/appCacheManager","tiles/offlineTilesEnabler","dojo/on on(btnOnlineOffline,"click",goOnlineOffline); on(btnGetTiles,"click",downloadTiles); - + updateOfflineUsage(); } else From 9b905ee11896ef63812defcccd4e650ef0a926de Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 11:58:47 -0600 Subject: [PATCH 026/139] added cache loaded event handler --- samples/appcache-tiles.html | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/samples/appcache-tiles.html b/samples/appcache-tiles.html index 54589a8..7865a4e 100644 --- a/samples/appcache-tiles.html +++ b/samples/appcache-tiles.html @@ -153,12 +153,13 @@ require(["esri/map","utils/appCacheManager","tiles/offlineTilesEnabler","dojo/on function init(){ map.on("extent-change",function(evt){ -// updateOfflineUsage(); + updateOfflineUsage(); console.log("Zoom level = " + map.getLevel()) }) appCacheManager = new AppCacheManager(true,true); appCacheManager.on(appCacheManager.CACHE_EVENT,cacheEventHandler); appCacheManager.on(appCacheManager.CACHE_ERROR,cacheErrorHandler); + appCacheManager.on(appCacheManager.CACHE_LOADED,cacheLoaderHandler); btnGetTiles = document.getElementById("btn-get-tiles"); btnOnlineOffline = document.getElementById("btn-online-offline"); @@ -202,6 +203,10 @@ require(["esri/map","utils/appCacheManager","tiles/offlineTilesEnabler","dojo/on }.bind(this),_isOnline); } + function cacheLoaderHandler(evt){ + if(evt == appCacheManager.CACHE_LOADED) console.log("Application cache successfully loaded!") + } + function cacheEventHandler(evt){ console.log("CACHE EVENT: " + JSON.stringify(evt)); } From f29fe2c547ebb64747f43b11f8ee9df549f1dadd Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 12:08:41 -0600 Subject: [PATCH 027/139] added a bunch of code comments to clarify functionality --- samples/appcache-tiles.html | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/samples/appcache-tiles.html b/samples/appcache-tiles.html index 7865a4e..9c9da76 100644 --- a/samples/appcache-tiles.html +++ b/samples/appcache-tiles.html @@ -127,6 +127,11 @@ require(["esri/map","utils/appCacheManager","tiles/offlineTilesEnabler","dojo/on Offline.check(); Offline.on('up down', updateState ); + /** + * There have been a few bugs in the offline detection library (offline.min.js) + * This is a utility check to 100% validate if the application is online or + * offline prior to launching any map functionality. + */ verifyOnline(function(result){ console.log("VERIFY ONLINE " + result) result == true ? _isOnline = true : _isOnline = false; startMap(); @@ -155,7 +160,8 @@ require(["esri/map","utils/appCacheManager","tiles/offlineTilesEnabler","dojo/on map.on("extent-change",function(evt){ updateOfflineUsage(); console.log("Zoom level = " + map.getLevel()) - }) + }); + appCacheManager = new AppCacheManager(true,true); appCacheManager.on(appCacheManager.CACHE_EVENT,cacheEventHandler); appCacheManager.on(appCacheManager.CACHE_ERROR,cacheErrorHandler); @@ -239,6 +245,9 @@ require(["esri/map","utils/appCacheManager","tiles/offlineTilesEnabler","dojo/on }) } + /** + * Utility function to validate min and max zoom settings of the map + */ function getMinMaxZoom(){ var zoom = {}; @@ -250,6 +259,9 @@ require(["esri/map","utils/appCacheManager","tiles/offlineTilesEnabler","dojo/on return zoom; } + /** + * Reports the process while downloading tiles. + */ function reportProgress(progress) { console.log("downloading tiles..."); @@ -279,6 +291,10 @@ require(["esri/map","utils/appCacheManager","tiles/offlineTilesEnabler","dojo/on return _wantToCancel; //determines if a cancel request has been issued } + /** + * Forces offlineTileEnabler to go online or offline. + * If it is offline it will try to find a tile in the local database. + */ function goOnlineOffline(){ if(imgOfflineIndicator.offlineColor == "blue"){ btnOnlineOffline.innerHTML = "2. Go Online"; @@ -294,6 +310,10 @@ require(["esri/map","utils/appCacheManager","tiles/offlineTilesEnabler","dojo/on } } + /** + * Manually starts the process to download and store tiles + * in the local database + */ function downloadTiles(){ baseMapLayer.deleteAllTiles(function(success,err){ if(success == false){ @@ -322,6 +342,11 @@ require(["esri/map","utils/appCacheManager","tiles/offlineTilesEnabler","dojo/on }.bind(this)) } + /** + * Attempts an http request to verify if app is online or offline. + * Use this in conjunction with the offline checker library: offline.min.js + * @param callback + */ function verifyOnline(callback){ var req = new XMLHttpRequest(); req.open("GET", "images/blue-pin.png?" + (Math.floor(Math.random() * 1000000000)), true); From a2c1aa6167a7a0fca23cb183578d407c17f08f50 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 12:10:40 -0600 Subject: [PATCH 028/139] moved script block to bottom --- samples/appcache-features.html | 339 +++++++++++++++++---------------- 1 file changed, 170 insertions(+), 169 deletions(-) diff --git a/samples/appcache-features.html b/samples/appcache-features.html index 4711e9c..01a886e 100644 --- a/samples/appcache-features.html +++ b/samples/appcache-features.html @@ -135,9 +135,22 @@ } - - + function goOnline(){ - -
- -
- -
Pending edits: 0
-
-
-
-
+ offlineFeaturesManager.goOnline(function(success,error){ + if(error === undefined){ + btnOnlineOffline.innerHTML = "Go Offline"; + imgOfflineIndicator.src = bluePinPath; + imgOfflineIndicator.offlineColor = "blue"; + console.log("Online."); + } + else{ + alert("There was a problem syncing offline edits: " + JSON.stringify(error)); + } + }); + } + + function goOffline(){ + btnOnlineOffline.innerHTML = "Go Online"; + imgOfflineIndicator.src = redPinPath; + imgOfflineIndicator.offlineColor = "red"; + offlineFeaturesManager.goOffline(); + + } + + function goOnlineOffline(){ + if(offlineFeaturesManager.getOnlineStatus() == offlineFeaturesManager.ONLINE){ + goOffline(); + } + else{ + goOnline(); + } + } + + function cacheEventHandler(evt){ + console.log("CACHE EVENT: " + JSON.stringify(evt)); + } + + function cacheErrorHandler(evt){ + console.log("CACHE ERROR: " + JSON.stringify(evt)); + } + } +); + + \ No newline at end of file From bf55ec70a89c80f48af97d87b7030b7c203b9154 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 12:11:58 -0600 Subject: [PATCH 029/139] tweaked code comment --- samples/appcache-features.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/samples/appcache-features.html b/samples/appcache-features.html index 01a886e..5a93cee 100644 --- a/samples/appcache-features.html +++ b/samples/appcache-features.html @@ -12,6 +12,10 @@ The use cases for using this sample are to ensure you can reload and restart you application one it is offline. + 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. + Use the included Grunt task to help generate the manifest file. There is manual work involved in determining which files need to go into the manifest. The included manifest file should work with this sample to give you an idea of what goes into the manifest. From bee76389d1c297146b54abca54b55fb7e384e12f Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 12:17:50 -0600 Subject: [PATCH 030/139] minor code rearrangement --- samples/appcache-features.html | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/samples/appcache-features.html b/samples/appcache-features.html index 5a93cee..9adb2b8 100644 --- a/samples/appcache-features.html +++ b/samples/appcache-features.html @@ -171,6 +171,7 @@ require([ function(Map,Query,FeatureLayer,OfflineFeaturesManager,editsStore,AppCacheManager,AttributeInspector,domConstruct,on,dom,Button,SimpleTextArea) { var textTimer; + var appCacheManager; var offlineFeaturesManager; var map,busStopsFeatureLayer,currentFeature; var imgOfflineIndicator,btnOnlineOffline; @@ -200,12 +201,6 @@ require([ map.addLayers([busStopsFeatureLayer]); - function initAppCacheManager(){ - appCacheManager = new AppCacheManager(true,true); - appCacheManager.on(appCacheManager.CACHE_EVENT,cacheEventHandler); - appCacheManager.on(appCacheManager.CACHE_ERROR,cacheErrorHandler); - } - function initOffline(){ offlineFeaturesManager = new OfflineFeaturesManager(); offlineFeaturesManager.on(offlineFeaturesManager.events.EDITS_ENQUEUED, updateStatus); @@ -222,6 +217,13 @@ require([ on(dom.byId('btn-online-offline'), 'click', goOnlineOffline); } + function initAppCacheManager(){ + appCacheManager = new AppCacheManager(true,true); + appCacheManager.on(appCacheManager.CACHE_EVENT,cacheEventHandler); + appCacheManager.on(appCacheManager.CACHE_ERROR,cacheErrorHandler); + appCacheManager.on(appCacheManager.CACHE_LOADED,cacheLoadedHandler); + } + function initEditing(evt){ offlineFeaturesManager.extend(busStopsFeatureLayer); @@ -346,6 +348,10 @@ require([ } } + function cacheLoadedHandler(evt){ + if(evt == appCacheManager.CACHE_LOADED) console.log("Application cache successfully loaded!") + } + function cacheEventHandler(evt){ console.log("CACHE EVENT: " + JSON.stringify(evt)); } From ab750c6f17d40d9382156312a022cdb5bdd67ffb Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 12:41:54 -0600 Subject: [PATCH 031/139] tweaked code comments --- samples/appcache-features.html | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/samples/appcache-features.html b/samples/appcache-features.html index 9adb2b8..817a48d 100644 --- a/samples/appcache-features.html +++ b/samples/appcache-features.html @@ -7,7 +7,9 @@ + + + From 7afd7c2a2d68d4b06d81df21a71ebec1dee7b479 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 12:42:07 -0600 Subject: [PATCH 032/139] added edit libs --- samples/Gruntfile.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/samples/Gruntfile.js b/samples/Gruntfile.js index 67ffee8..452b9a7 100644 --- a/samples/Gruntfile.js +++ b/samples/Gruntfile.js @@ -36,6 +36,7 @@ module.exports = function(grunt) { "<%= pkg.arcGISBaseURL %>/js/esri/images/map/logo-sm.png", "<%= pkg.arcGISBaseURL %>/js/esri/images/map/logo-med.png", "<%= pkg.arcGISBaseURL %>/js/esri/css/esri.css", + "<%= pkg.arcGISBaseURL %>/js/dojo/dijit/themes/claro/claro.css", "<%= pkg.arcGISBaseURL %>/js/esri/nls/jsapi_en-us.js", "#", "//services.arcgisonline.com/ArcGIS/rest/info?f=json", @@ -65,6 +66,7 @@ module.exports = function(grunt) { "../lib/tiles/*.js", "../lib/tiles/*.png", "../lib/tiles/*.psd", + "../lib/edit/*.js", "../utils/*.js" /* "images/*", From 510ff5441d292190a97b1b1dc95f3d66ad281827 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 12:42:25 -0600 Subject: [PATCH 033/139] updated feature sample app cache --- samples/appcache-features.appcache | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/samples/appcache-features.appcache b/samples/appcache-features.appcache index daf4929..543c66d 100644 --- a/samples/appcache-features.appcache +++ b/samples/appcache-features.appcache @@ -1,6 +1,6 @@ CACHE MANIFEST # This manifest was generated by grunt-manifest HTML5 Cache Manifest Generator -# Time: Mon May 19 2014 13:37:55 GMT-0600 (MDT) +# Time: Fri Jun 06 2014 12:37:46 GMT-0600 (MDT) CACHE: # manifest-generator, version: 0.0.1 @@ -9,14 +9,18 @@ CACHE: appcache-features.html # # ArcGIS API for JavaScript files -http://js.arcgis.com/o/agup_hack4co/appcache2/dojo/dojo.js +http://js.arcgis.com/o/agup_hack4co/appcacheFeatures/dojo/dojo.js +http://js.arcgis.com/o/agup_hack4co/appcacheFeatures/dojo/nls/dojo_en-us.js +http://js.arcgis.com/o/agup_hack4co/appcacheFeatures/dojo/selector/acme.js # +http://js.arcgis.com/3.9/js/esri/dijit/images/popup-sprite.png http://js.arcgis.com/3.9/js/dojo/dojox/gfx/svg.js http://js.arcgis.com/3.9/js/dojo/dojo/resources/blank.gif http://js.arcgis.com/3.9/js/esri/dijit/images/ajax-loader.gif http://js.arcgis.com/3.9/js/esri/images/map/logo-sm.png http://js.arcgis.com/3.9/js/esri/images/map/logo-med.png http://js.arcgis.com/3.9/js/esri/css/esri.css +http://js.arcgis.com/3.9/js/dojo/dijit/themes/claro/claro.css http://js.arcgis.com/3.9/js/esri/nls/jsapi_en-us.js # //services.arcgisonline.com/ArcGIS/rest/info?f=json @@ -26,7 +30,7 @@ http://js.arcgis.com/3.9/js/esri/nls/jsapi_en-us.js # required for web maps http://js.arcgis.com/3.9/js/esri/dijit/images/ajax-loader.gif # -# required custom libs +# required local html # /xyz/style.css # /img/1.png appcache-features.html @@ -36,6 +40,23 @@ attachments-editor.html military-offline.html service-inspector.html tiles-indexed-db.html +tpk-layer.html +../samples/images/blue-pin.png +../samples/images/red-pin.png +../vendor/IndexedDBShim/dist/IndexedDBShim.min.js +../vendor/offline/offline.min.js +../lib/tiles/FileSaver.js +../lib/tiles/TilesStore.js +../lib/tiles/base64utils.js +../lib/tiles/offlineTilesEnabler.js +../lib/tiles/tilingScheme.js +../lib/tiles/notile.png +../lib/tiles/notile.psd +../lib/edit/attachmentsStore.js +../lib/edit/editsStore.js +../lib/edit/offlineFeaturesManager.js +../utils/appCacheManager.js +../utils/debouncer.js NETWORK: * From 4f8b2fbbfc7910476ed65e23f728185b2c253ce3 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 12:42:45 -0600 Subject: [PATCH 034/139] updated feature sample app cache --- samples/appcache-tiles.appcache | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/samples/appcache-tiles.appcache b/samples/appcache-tiles.appcache index 242e2c4..5cf018f 100644 --- a/samples/appcache-tiles.appcache +++ b/samples/appcache-tiles.appcache @@ -1,6 +1,6 @@ CACHE MANIFEST # This manifest was generated by grunt-manifest HTML5 Cache Manifest Generator -# Time: Mon May 19 2014 13:19:05 GMT-0600 (MDT) +# Time: Wed Jun 04 2014 17:49:41 GMT-0600 (MDT) CACHE: # manifest-generator, version: 0.0.1 @@ -10,7 +10,10 @@ appcache-tiles.html # # ArcGIS API for JavaScript files http://js.arcgis.com/o/agup_hack4co/appcache2/dojo/dojo.js +http://js.arcgis.com/o/agup_hack4co/appcache2/dojo/nls/dojo_en-us.js +http://js.arcgis.com/o/agup_hack4co/appcache2/dojo/selector/acme.js # +http://js.arcgis.com/3.9/js/esri/dijit/images/popup-sprite.png http://js.arcgis.com/3.9/js/dojo/dojox/gfx/svg.js http://js.arcgis.com/3.9/js/dojo/dojo/resources/blank.gif http://js.arcgis.com/3.9/js/esri/dijit/images/ajax-loader.gif @@ -26,7 +29,7 @@ http://js.arcgis.com/3.9/js/esri/nls/jsapi_en-us.js # required for web maps http://js.arcgis.com/3.9/js/esri/dijit/images/ajax-loader.gif # -# required custom libs +# required local html # /xyz/style.css # /img/1.png appcache-features.html @@ -36,6 +39,20 @@ attachments-editor.html military-offline.html service-inspector.html tiles-indexed-db.html +tpk-layer.html +../samples/images/blue-pin.png +../samples/images/red-pin.png +../vendor/IndexedDBShim/dist/IndexedDBShim.min.js +../vendor/offline/offline.min.js +../lib/tiles/FileSaver.js +../lib/tiles/TilesStore.js +../lib/tiles/base64utils.js +../lib/tiles/offlineTilesEnabler.js +../lib/tiles/tilingScheme.js +../lib/tiles/notile.png +../lib/tiles/notile.psd +../utils/appCacheManager.js +../utils/debouncer.js NETWORK: * From c5515d8b8e6ce629d3b8740947770df3b5b0bc3b Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 12:43:03 -0600 Subject: [PATCH 035/139] updated package.json --- samples/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/package.json b/samples/package.json index 418c5d3..16ae9d3 100644 --- a/samples/package.json +++ b/samples/package.json @@ -5,9 +5,9 @@ "https://www.npmjs.org/doc/cli/npm-init.html" ], "name": "manifest-generator", - "manifestName": "appcache-tiles.appcache", - "appHomePage": "appcache-tiles.html", - "optimizedApiURL": "http://js.arcgis.com/o/agup_hack4co/appcache2", + "manifestName": "appcache-features.appcache", + "appHomePage": "appcache-features.html", + "optimizedApiURL": "http://js.arcgis.com/o/agup_hack4co/appcacheFeatures", "arcGISBaseURL": "http://js.arcgis.com/3.9", "version": "0.0.1", "private": true, @@ -16,7 +16,7 @@ "type": "git", "url": "https://github.com/Esri/offline-editor-js.git" }, - "author": "Lloyd Heberlie", + "author": "Andy Gup", "license": "Apache 2", "bugs": { "url": "https://github.com/Esri/offline-editor-js/issues" From 955a93d068545a04fae4f1d4ecdbe90a692ecde1 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 13:46:56 -0600 Subject: [PATCH 036/139] changed symbology to ugly red clickable squares --- samples/appcache-features.html | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/samples/appcache-features.html b/samples/appcache-features.html index 817a48d..582ef81 100644 --- a/samples/appcache-features.html +++ b/samples/appcache-features.html @@ -1,5 +1,6 @@ - + + @@ -163,6 +164,9 @@ require([ "esri/map", "esri/tasks/query", "esri/layers/FeatureLayer", + "esri/Color", + "esri/symbols/SimpleMarkerSymbol", + "esri/renderers/SimpleRenderer", "edit/offlineFeaturesManager", "edit/editsStore", "utils/appCacheManager", @@ -173,7 +177,8 @@ require([ "dijit/form/Button", "dijit/form/SimpleTextarea", "dojo/domReady!"], - function(Map,Query,FeatureLayer,OfflineFeaturesManager,editsStore,AppCacheManager,AttributeInspector,domConstruct,on,dom,Button,SimpleTextArea) { + function(Map,Query,FeatureLayer,Color,SimpleMarkerSymbol,SimpleRenderer, + OfflineFeaturesManager,editsStore,AppCacheManager,AttributeInspector,domConstruct,on,dom,Button,SimpleTextArea) { var textTimer; var appCacheManager; @@ -184,6 +189,10 @@ require([ var redPinPath = "../samples/images/red-pin.png"; var bluePinPath = "../samples/images/blue-pin.png" + var defaultSymbol = new SimpleMarkerSymbol().setStyle( + SimpleMarkerSymbol.STYLE_SQUARE).setColor( + new Color([255,0,0,0.5])); + initOffline(); map = new Map("map", { @@ -196,7 +205,9 @@ require([ busStopsFeatureLayer = new FeatureLayer("http://services.arcgis.com/IZtlGBUe4KTzLOl4/arcgis/rest/services/BPX_RTD_BusStops2/FeatureServer/0",{ mode: FeatureLayer.MODE_SNAPSHOT, outFields: ["OBJECTID","BSID","ROUTES","STOPNAME"] - }) + }); + + busStopsFeatureLayer.setRenderer(new SimpleRenderer(defaultSymbol)); map.on("load",function(evt){ initAppCacheManager(); From c6cf194079f837e5ae284fce5c970431bd25e08b Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 13:53:36 -0600 Subject: [PATCH 037/139] tweaked symbol and added doc comments --- samples/appcache-features.html | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/samples/appcache-features.html b/samples/appcache-features.html index 582ef81..3fc26d2 100644 --- a/samples/appcache-features.html +++ b/samples/appcache-features.html @@ -190,7 +190,7 @@ require([ var bluePinPath = "../samples/images/blue-pin.png" var defaultSymbol = new SimpleMarkerSymbol().setStyle( - SimpleMarkerSymbol.STYLE_SQUARE).setColor( + SimpleMarkerSymbol.STYLE_DIAMOND).setColor( new Color([255,0,0,0.5])); initOffline(); @@ -207,6 +207,8 @@ require([ outFields: ["OBJECTID","BSID","ROUTES","STOPNAME"] }); + // Set the graphics to red boxes to make it easy to click on them + // on a mobile device. busStopsFeatureLayer.setRenderer(new SimpleRenderer(defaultSymbol)); map.on("load",function(evt){ @@ -311,6 +313,10 @@ require([ console.log("ERROR " + JSON.stringify(err)); }); + // NOTE: To make the info window for mobile use you would need + // to switch a mobile friendly 'view' containing all the attributes. + // This pattern is for testing only. It's on the TO-DO list to make + // this mobile friendly. map.infoWindow.setTitle(currentFeature.attributes.STOPNAME); map.infoWindow.show(evt.screenPoint,map.getInfoWindowAnchor(evt.screenPoint)); }.bind(this)); From 66a7c9feb955ffcc93c8eb43bdb38baf7a525735 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 14:26:46 -0600 Subject: [PATCH 038/139] minor rearrangement --- samples/appcache-tiles.html | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/samples/appcache-tiles.html b/samples/appcache-tiles.html index 9c9da76..968d0fa 100644 --- a/samples/appcache-tiles.html +++ b/samples/appcache-tiles.html @@ -209,18 +209,6 @@ require(["esri/map","utils/appCacheManager","tiles/offlineTilesEnabler","dojo/on }.bind(this),_isOnline); } - function cacheLoaderHandler(evt){ - if(evt == appCacheManager.CACHE_LOADED) console.log("Application cache successfully loaded!") - } - - function cacheEventHandler(evt){ - console.log("CACHE EVENT: " + JSON.stringify(evt)); - } - - function cacheErrorHandler(evt){ - console.log("CACHE ERROR: " + JSON.stringify(evt)); - } - function updateState(){ if(Offline.state === 'up'){ updateOfflineUsage(); @@ -369,6 +357,18 @@ require(["esri/map","utils/appCacheManager","tiles/offlineTilesEnabler","dojo/on }; req.send(null); } + + function cacheLoaderHandler(evt){ + if(evt == appCacheManager.CACHE_LOADED) console.log("Application cache successfully loaded!") + } + + function cacheEventHandler(evt){ + console.log("CACHE EVENT: " + JSON.stringify(evt)); + } + + function cacheErrorHandler(evt){ + console.log("CACHE ERROR: " + JSON.stringify(evt)); + } } ); From 6f69db18165118a9b3c6dae175bb122a5e5f1d05 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 14:27:36 -0600 Subject: [PATCH 039/139] added verifyOffline method --- samples/appcache-features.html | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/samples/appcache-features.html b/samples/appcache-features.html index 3fc26d2..6417097 100644 --- a/samples/appcache-features.html +++ b/samples/appcache-features.html @@ -1,6 +1,6 @@ - - + + @@ -370,6 +370,34 @@ require([ } } + /** + * Attempts an http request to verify if app is online or offline. + * Use this in conjunction with the offline checker library: offline.min.js + * @param callback + */ + function verifyOnline(callback){ + var req = new XMLHttpRequest(); + req.open("GET", "images/blue-pin.png?" + (Math.floor(Math.random() * 1000000000)), true); + req.onload = function() + { + if( req.status === 200 && req.responseText !== "") + { + callback(true); + } + else + { + console.log("verifyOffline failed"); + callback(false); + } + }; + req.onerror = function(e) + { + console.log("verifyOffline failed: " + e); + callback(false); + }; + req.send(null); + } + function cacheLoadedHandler(evt){ if(evt == appCacheManager.CACHE_LOADED) console.log("Application cache successfully loaded!") } From c5392c0128e443f57c378ec4ada7010386564721 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 14:32:25 -0600 Subject: [PATCH 040/139] added download tiles button --- samples/appcache-features.html | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/samples/appcache-features.html b/samples/appcache-features.html index 6417097..236b815 100644 --- a/samples/appcache-features.html +++ b/samples/appcache-features.html @@ -1,6 +1,6 @@ - - + + @@ -149,7 +149,8 @@
- + +
Pending edits: 0
From a9ad2dc8883da9ec1fe7b7722ec65e70c21f01c8 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 14:37:09 -0600 Subject: [PATCH 041/139] add offlineTileEnabler module --- samples/appcache-features.html | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/samples/appcache-features.html b/samples/appcache-features.html index 236b815..1bcf5d0 100644 --- a/samples/appcache-features.html +++ b/samples/appcache-features.html @@ -137,7 +137,8 @@ paths: { edit: locationPath + "/../lib/edit", vendor: locationPath + "/../vendor", - utils: locationPath + "/../utils" + utils: locationPath + "/../utils", + tiles: locationPath + "/../lib/tiles" } } @@ -168,18 +169,19 @@ require([ "esri/Color", "esri/symbols/SimpleMarkerSymbol", "esri/renderers/SimpleRenderer", + "esri/dijit/AttributeInspector", "edit/offlineFeaturesManager", + "tiles/offlineTilesEnabler", "edit/editsStore", "utils/appCacheManager", - "esri/dijit/AttributeInspector", "dojo/dom-construct", "dojo/on", "dojo/dom", "dijit/form/Button", "dijit/form/SimpleTextarea", "dojo/domReady!"], - function(Map,Query,FeatureLayer,Color,SimpleMarkerSymbol,SimpleRenderer, - OfflineFeaturesManager,editsStore,AppCacheManager,AttributeInspector,domConstruct,on,dom,Button,SimpleTextArea) { + function(Map,Query,FeatureLayer,Color,SimpleMarkerSymbol,SimpleRenderer,AttributeInspector, + OfflineFeaturesManager,offlineTilesEnabler,editsStore,AppCacheManager,domConstruct,on,dom,Button,SimpleTextArea) { var textTimer; var appCacheManager; From 13c7f6638afc2fc29e70254264c8c52dbcbed3e4 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 14:41:07 -0600 Subject: [PATCH 042/139] added verifyOnline method --- samples/appcache-features.html | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/samples/appcache-features.html b/samples/appcache-features.html index 1bcf5d0..88ac2a8 100644 --- a/samples/appcache-features.html +++ b/samples/appcache-features.html @@ -184,10 +184,14 @@ require([ OfflineFeaturesManager,offlineTilesEnabler,editsStore,AppCacheManager,domConstruct,on,dom,Button,SimpleTextArea) { var textTimer; + var _isOnline = true; var appCacheManager; var offlineFeaturesManager; var map,busStopsFeatureLayer,currentFeature; var imgOfflineIndicator,btnOnlineOffline; + + var minZoomAdjust = -1, maxZoomAdjust = 1, mMinZoom, mMaxZoom, zoom = 18; + var pendingEdits = document.getElementById("pending-edits"); var redPinPath = "../samples/images/red-pin.png"; var bluePinPath = "../samples/images/blue-pin.png" @@ -196,6 +200,18 @@ require([ SimpleMarkerSymbol.STYLE_DIAMOND).setColor( new Color([255,0,0,0.5])); + /** + * There have been a few bugs in the offline detection library (offline.min.js) + * This is a utility check to 100% validate if the application is online or + * offline prior to launching any map functionality. + */ + verifyOnline(function(result){ console.log("VERIFY ONLINE " + result) + result == true ? _isOnline = true : _isOnline = false; + startMap(); + + }) + + initOffline(); map = new Map("map", { @@ -222,6 +238,11 @@ require([ map.addLayers([busStopsFeatureLayer]); + function startMap(){ + //Make sure map shows up after a browser refresh +// Offline.state === 'up' ? zoom = 18 : zoom = 17; + } + function initOffline(){ offlineFeaturesManager = new OfflineFeaturesManager(); offlineFeaturesManager.on(offlineFeaturesManager.events.EDITS_ENQUEUED, updateStatus); From f6dfad358ace748a4fbc503e3ec7e56f0afdb210 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 14:46:20 -0600 Subject: [PATCH 043/139] moved all map initialization code to startMap() --- samples/appcache-features.html | 56 +++++++++++++++++----------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/samples/appcache-features.html b/samples/appcache-features.html index 88ac2a8..ffa728d 100644 --- a/samples/appcache-features.html +++ b/samples/appcache-features.html @@ -200,6 +200,8 @@ require([ SimpleMarkerSymbol.STYLE_DIAMOND).setColor( new Color([255,0,0,0.5])); + initOffline(); + /** * There have been a few bugs in the offline detection library (offline.min.js) * This is a utility check to 100% validate if the application is online or @@ -211,36 +213,34 @@ require([ }) - - initOffline(); - - map = new Map("map", { - basemap: "topo", - center: [-104.98,39.74], // long, lat - zoom: 10, - sliderStyle: "small" - }); - - busStopsFeatureLayer = new FeatureLayer("http://services.arcgis.com/IZtlGBUe4KTzLOl4/arcgis/rest/services/BPX_RTD_BusStops2/FeatureServer/0",{ - mode: FeatureLayer.MODE_SNAPSHOT, - outFields: ["OBJECTID","BSID","ROUTES","STOPNAME"] - }); - - // Set the graphics to red boxes to make it easy to click on them - // on a mobile device. - busStopsFeatureLayer.setRenderer(new SimpleRenderer(defaultSymbol)); - - map.on("load",function(evt){ - initAppCacheManager(); - }) - - map.on("layers-add-result",initEditing); - - map.addLayers([busStopsFeatureLayer]); - function startMap(){ //Make sure map shows up after a browser refresh -// Offline.state === 'up' ? zoom = 18 : zoom = 17; + Offline.check(); + Offline.state === 'up' ? zoom = 18 : zoom = 17; + + map = new Map("map", { + basemap: "topo", + center: [-104.98,39.74], // long, lat + zoom: 10, + sliderStyle: "small" + }); + + busStopsFeatureLayer = new FeatureLayer("http://services.arcgis.com/IZtlGBUe4KTzLOl4/arcgis/rest/services/BPX_RTD_BusStops2/FeatureServer/0",{ + mode: FeatureLayer.MODE_SNAPSHOT, + outFields: ["OBJECTID","BSID","ROUTES","STOPNAME"] + }); + + // Set the graphics to red boxes to make it easy to click on them + // on a mobile device. + busStopsFeatureLayer.setRenderer(new SimpleRenderer(defaultSymbol)); + + map.on("load",function(evt){ + initAppCacheManager(); + }) + + map.on("layers-add-result",initEditing); + + map.addLayers([busStopsFeatureLayer]); } function initOffline(){ From 8ee06f011d7f205b0bb45167ba0e039cc1b44831 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 14:48:06 -0600 Subject: [PATCH 044/139] added getMinMaxZoom() --- samples/appcache-features.html | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/samples/appcache-features.html b/samples/appcache-features.html index ffa728d..acd7393 100644 --- a/samples/appcache-features.html +++ b/samples/appcache-features.html @@ -394,6 +394,26 @@ require([ } } + /** + * ************************************ + * TILE MANAGEMENT CODE GOES BELOW HERE + * ************************************ + */ + + /** + * Utility function to validate min and max zoom settings of the map + */ + function getMinMaxZoom(){ + + var zoom = {}; + var min = map.getLevel() + minZoomAdjust; + var max = map.getLevel() + maxZoomAdjust; + zoom.max = Math.min(mMaxZoom, max); //prevent errors by setting the tile layer floor + zoom.min = Math.max(mMinZoom, min); //prevent errors by setting the tile layer ceiling + + return zoom; + } + /** * Attempts an http request to verify if app is online or offline. * Use this in conjunction with the offline checker library: offline.min.js From 98a4496d025b118033368df3042045a56ef6f315 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 14:53:59 -0600 Subject: [PATCH 045/139] added initOfflineTileEnabler() --- samples/appcache-features.html | 35 +++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/samples/appcache-features.html b/samples/appcache-features.html index acd7393..795d688 100644 --- a/samples/appcache-features.html +++ b/samples/appcache-features.html @@ -181,7 +181,7 @@ require([ "dijit/form/SimpleTextarea", "dojo/domReady!"], function(Map,Query,FeatureLayer,Color,SimpleMarkerSymbol,SimpleRenderer,AttributeInspector, - OfflineFeaturesManager,offlineTilesEnabler,editsStore,AppCacheManager,domConstruct,on,dom,Button,SimpleTextArea) { + OfflineFeaturesManager,OfflineTileEnabler,editsStore,AppCacheManager,domConstruct,on,dom,Button,SimpleTextArea) { var textTimer; var _isOnline = true; @@ -190,9 +190,13 @@ require([ var map,busStopsFeatureLayer,currentFeature; var imgOfflineIndicator,btnOnlineOffline; + var offlineTileEnabler, baseMapLayer; + var minZoomAdjust = -1, maxZoomAdjust = 1, mMinZoom, mMaxZoom, zoom = 18; var pendingEdits = document.getElementById("pending-edits"); + var btnGetTiles = document.getElementById("btn-get-tiles"); + var redPinPath = "../samples/images/red-pin.png"; var bluePinPath = "../samples/images/blue-pin.png" @@ -400,6 +404,35 @@ require([ * ************************************ */ + function initOfflineTileEnabler(){ + + mMaxZoom = map.getMaxZoom(); + mMinZoom = map.getMinZoom(); + + offlineTileEnabler = new OfflineTileEnabler(); + baseMapLayer = offlineTileEnabler.getBasemapLayer(map); console.log("Offline State: " + Offline.state) + + offlineTileEnabler.extend(baseMapLayer,function(success) + { + if( success ) + { + console.log("Offline tile lib is enabled. Application state is: " + Offline.state); + Offline.check(); + + //using null sets this for CORS + baseMapLayer.offline.proxyPath = null; + + on(btnGetTiles,"click",downloadTiles); + + updateOfflineUsage(); + } + else + { + alert("error initializing storage - browser doesn't support indexeddb or websql") + } + }.bind(this),_isOnline); + } + /** * Utility function to validate min and max zoom settings of the map */ From 7f4ef6a8b90ae0d9cb2d4c7dc70ef254ff68c7c2 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Fri, 6 Jun 2014 14:56:47 -0600 Subject: [PATCH 046/139] added updateOfflineUsage() --- samples/appcache-features.html | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/samples/appcache-features.html b/samples/appcache-features.html index 795d688..e6ef91c 100644 --- a/samples/appcache-features.html +++ b/samples/appcache-features.html @@ -118,6 +118,12 @@ padding: 8px; position: relative; float: right; } + #tile-info{ + background-color: #000000; + color: white; + padding: 8px; + position: relative; float: right; + } + @@ -165,6 +188,45 @@
+ +
+ From 616431167e35e0cea7ce5f8c1d80d6a60b163825 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Sun, 8 Jun 2014 12:18:18 -0600 Subject: [PATCH 076/139] renamed btw text and initOffline --- samples/appcache-features.html | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/samples/appcache-features.html b/samples/appcache-features.html index 45a33fd..9d2cf06 100644 --- a/samples/appcache-features.html +++ b/samples/appcache-features.html @@ -1,6 +1,6 @@ - - + + @@ -147,8 +147,8 @@
- - + +
Pending edits: 0
@@ -271,7 +271,7 @@ require([ var btnOnlineOffline = document.getElementById("btn-online-offline"); setClickListeners(); - initOffline(); + initOfflineFeatures(); /** * There have been a few bugs in the offline detection library (offline.min.js) @@ -381,7 +381,7 @@ require([ } } - function initOffline(){ + function initOfflineFeatures(){ offlineFeaturesManager = new OfflineFeaturesManager(); offlineFeaturesManager.on(offlineFeaturesManager.events.EDITS_ENQUEUED, updateStatus); offlineFeaturesManager.on(offlineFeaturesManager.events.EDITS_SENT, updateStatus); @@ -478,7 +478,7 @@ require([ offlineFeaturesManager.goOnline(function(success,error){ if(error === undefined){ - btnOnlineOffline.innerHTML = "1. Go Offline"; + btnOnlineOffline.innerHTML = "2. Go Offline"; imgOfflineIndicator.src = bluePinPath; imgOfflineIndicator.offlineColor = "blue"; console.log("Online."); @@ -493,7 +493,7 @@ require([ } function goOffline(){ - btnOnlineOffline.innerHTML = "1. Go Online"; + btnOnlineOffline.innerHTML = "2. Go Online"; imgOfflineIndicator.src = redPinPath; imgOfflineIndicator.offlineColor = "red"; offlineFeaturesManager.goOffline(); @@ -613,7 +613,7 @@ require([ alert("Tile download complete"); } - btnGetTiles.innerHTML = '2. Download Tiles'; + btnGetTiles.innerHTML = '1. Download Tiles'; } return _wantToCancel; //determines if a cancel request has been issued } @@ -677,7 +677,7 @@ require([ } function cacheEventHandler(evt){ - console.log("CACHE EVENT: " + JSON.stringify(evt)); + if(evt.hasOwnProperty("total")) console.log("CACHE EVENT loaded #:" + evt.loaded + ", out of " + evt.total); } function cacheErrorHandler(evt){ From 43c92cc47b6012d00d7c41d96c6327b680380e72 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Sun, 8 Jun 2014 12:55:46 -0600 Subject: [PATCH 077/139] test switch callback location --- lib/tiles/offlineTilesEnabler.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/tiles/offlineTilesEnabler.js b/lib/tiles/offlineTilesEnabler.js index a74e5b8..33e55c2 100644 --- a/lib/tiles/offlineTilesEnabler.js +++ b/lib/tiles/offlineTilesEnabler.js @@ -59,7 +59,7 @@ define([ // Important: wait to load tiles until after database has initialized! layer.offline.store.init(function(success){ if(success){ - callback(true); +// callback(true); layer.resampling = false; /** @@ -123,6 +123,8 @@ define([ return tileid; }; + + callback(true); } }.bind(this)); } From c5f75421557a7fe1ea449de741c061cc49c47594 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Sun, 8 Jun 2014 21:24:56 -0600 Subject: [PATCH 078/139] test to fully extend TiledMapServiceLayer. Some minor errors --- lib/tiles/offlineTilesEnabler2.js | 625 ++++++++++++++++++++++++++ samples/test.html | 701 ++++++++++++++++++++++++++++++ 2 files changed, 1326 insertions(+) create mode 100644 lib/tiles/offlineTilesEnabler2.js create mode 100644 samples/test.html diff --git a/lib/tiles/offlineTilesEnabler2.js b/lib/tiles/offlineTilesEnabler2.js new file mode 100644 index 0000000..e121b74 --- /dev/null +++ b/lib/tiles/offlineTilesEnabler2.js @@ -0,0 +1,625 @@ +define([ + "dojo/query", + "dojo/request", + "dojo/_base/declare", + "tiles/base64utils", + "tiles/TilesStore", + "tiles/tilingScheme", + "tiles/FileSaver", + "esri/layers/LOD", + "esri/geometry/Point", + "esri/geometry/Extent", + "esri/layers/TileInfo", + "esri/SpatialReference", + "esri/layers/TiledMapServiceLayer" +], function(query, request, declare,Base64Utils,TilesStore,TilingScheme, + FileSaver,LOD,Point,Extent,TileInfo,SpatialReference,TiledMapServerLayer) +{ + "use strict"; + return declare("test",[TiledMapServerLayer],{ + + tileInfo: null, + _imageType:"", + + /** + * Utility method to get the basemap layer reference + * @param map + * @returns {Number} layerId + */ + getBasemapLayer: function(map) + { + var layerId = map.layerIds[0]; + return map.getLayer(layerId); + }, + + constructor:function(url,callback,state){ + + this._self = this; + this._lastTileUrl = ""; + this._imageType = ""; + + /* we add some methods to the layer object */ + /* we don't want to extend the tiled layer class, as it is a capability that we want to add only to one instance */ + /* we also add some additional attributes inside an "offline" object */ + + this._getTileUrl = this.getTileUrl;http://web.local/offline-editor-js/samples/test.html + + var isOnline = true; + if(typeof state != "undefined"){ + isOnline = state; console.log("STATE IS: " + state) + } + + this.offline = { + online: isOnline, + store: new TilesStore(), + proxyPath: "../lib/resource-proxy/proxy.php" + }; + + if( /*false &&*/ this.offline.store.isSupported() ) + { + this.offline.store.init(function(success){ + if(success){ + this._getTileInfoPrivate(url,function(result){ + console.log("RESULT BABY " + result) + this.parseGetTileInfo(result,function(result){ + this.layerInfos = result.resultObj.layers; +// this.version = result.resultObj.currentVersion; +// this.visibleAtMapScale = false; +// this.tileServers = [url]; +// this.resampling = false; +// this._displayLevels = null; +// this._resamplingTolerance = null; +// this._patchIE = false; +// this._hasMin = true; +// this._hasMax = true; +// this.visibleLayer = []; +// this._tileH = result.tileInfo.rows; +// this._tileW = result.tileInfo.cols; +// this.resourceInfo = JSON.stringify(result.resultObjj); + +// var t = this; +// for (var attrname in result.resultObj) { t[attrname] = result.resultObj[attrname]; } + +// var scales = []; +// for (var i = 0; i < result.tileInfo.lods.length; i++){ +// scales.push(result.tileInfo.lods[i].scale); +// } +// +// this.scales = scales; + + this.minScale = result.resultObj.minScale; + this.maxScale = result.resultObj.maxScale; + this.tileInfo = result.tileInfo; + this.fullExtent = result.fullExtent; + + this.initialExtent = result.initExtent; + this.loaded = true; + this.onLoad(this); + callback(true); + }.bind(this._self)); + }.bind(this._self)) + } + }.bind(this._self)); + } + else + { + return callback(false, "indexedDB not supported"); + } + }, + + /** + * Internal method that overrides the getTileUrl() method. + * If application is offline then tiles are written to local storage. + * Retrieves tiles as requested by the ArcGIS API for JavaScript. + * If a tile is in cache it is returned. + * If it is not in cache then one is retrieved over the internet. + * @param level + * @param row + * @param col + * @returns {String} URL + */ + getTileUrl: function(level,row,col) + { + console.assert(!isNaN(level) && !isNaN(row) && !isNaN(col), "bad tile requested"); + + console.log("looking for tile",level,row,col); +// var url = this._self._getTileUrl(level,row,col); + var url = this.url + "/tile/" + level + "/" + row + "/" + col; + console.log("LIBRARY ONLINE " + this.offline.online) + if( this.offline.online ) + { + if(this._imageType == "")this._imageType = this.tileInfo.format.toLowerCase(); + console.log("fetching url online: ", url); + this._lastTileUrl = url; + return url; + } + + url = url.split("?")[0]; + + /* temporary URL returned immediately, as we haven't retrieved the image from the indexeddb yet */ + var tileid = "void:/"+level+"/"+row+"/"+col; + + this.offline.store.retrieve(url, function(success, offlineTile) + { console.log("TILE RETURN " + success + ", " + offlineTile) + /* when the .get() callback is called we replace the temporary URL originally returned by the data:image url */ + // search for the img with src="void:"+level+"-"+row+"-"+col and replace with actual url + var img = query("img[src="+tileid+"]")[0]; + var imgURL; + + console.assert(img !== "undefined", "undefined image detected"); + + if( success ) + { + img.style.borderColor = "blue"; + console.log("found tile offline", url); + imgURL = "data:image/" + this._imageType +";base64," + offlineTile.img; + } + else + { + img.style.borderColor = "green"; + console.log("tile is not in the offline store", url); + imgURL = "data:image/png;base64,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pmk0TROPj48Hn3l4eIimaSJN06O3A4NJwDMxm82ibdtXo4D5fB6r1Sp+//4dz8/Pw5H+6ekpdrtdJEkS8/n8S/9f713ie3vaceo9x557QAB451Sgfyin34HKshweunk5HzAej2MymXz5+f9nbjJyI9L39Wu5XP55+XQZ39uxR4Z3u90wSXjqEV0wAjhjx47oaZq63Me/ZhIQBAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEAAbAJQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAQAAAAQAEABAAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEABAAAABAAQAEAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEABAAQAEAAAAEAvqe/BwCeKjUweoA8pQAAAABJRU5ErkJggg=="; + } + // when we return a nonexistent url to the image, the TiledMapServiceLayer::_tileErrorHandler() method + // sets img visibility to 'hidden', so we need to show the image back once we have put the data:image + img.style.visibility = "visible"; + img.src = imgURL; + return ""; /* this result goes nowhere, seriously */ + }); + + return tileid; + }, + + /** + * Returns an object that contains the number of tiles that would need to be downloaded + * for the specified extent and zoom level, and the estimated byte size of such tiles. + * This method is useful to give the user an indication of the required time and space + * before launching the actual download operation. The byte size estimation is very rough. + * @param extent + * @param level + * @param tileSize + * @returns {{level: *, tileCount: Number, sizeBytes: number}} + */ + getLevelEstimation: function(extent, level, tileSize) + { + var tilingScheme = new TilingScheme(this); + var cellIds = tilingScheme.getAllCellIdsInExtent(extent,level); + + var levelEstimation = { + level: level, + tileCount: cellIds.length, + sizeBytes: cellIds.length * tileSize + }; + + return levelEstimation; + }, + + /** + * Retrieves tiles and stores them in the local cache. + * @param minLevel + * @param maxLevel + * @param extent + * @param reportProgress + */ + prepareForOffline : function(minLevel, maxLevel, extent, reportProgress) + { + /* create list of tiles to store */ + var tilingScheme = new TilingScheme(this); + var cells = []; + var level; + + for(level=minLevel; level<=maxLevel; level++) + { + var level_cell_ids = tilingScheme.getAllCellIdsInExtent(extent,level); + + level_cell_ids.forEach(function(cell_id) + { + cells.push({ level: level, row: cell_id[1], col: cell_id[0]}); + }); + + // if the number of requested tiles is excessive, we just stop + if( cells.length > 5000 && level !== maxLevel) + { + console.log("enough is enough!"); + break; + } + } + + /* launch tile download */ + this._doNextTile(0, cells, reportProgress); + }, + + /** + * This method puts the layer in offline mode. When in offline mode, + * the layer will not fetch any tile from the remote server. It + * will look up the tiles in the indexed db database and display them in the + * If the tile can't be found in the local database it will show up blank + * (even if there is actual connectivity). The pair of methods goOffline() and + * goOnline()allows the developer to manually control the behaviour of the + * Used in conjunction with the offline dectection library, you can put the layer in + * the appropriate mode when the offline condition changes. + */ + goOffline : function() + { + this.offline.online = false; + }, + + /** + * This method puts the layer in online mode. When in online mode, the layer will + * behave as regular layers, fetching all tiles from the remote server. + * If there is no internet connectivity the tiles may appear thanks to the browsers cache, + * but no attempt will be made to look up tiles in the local database. + */ + goOnline : function() + { + this.offline.online = true; + this.refresh(); + }, + + /** + * Determines if application is online or offline + * @returns {boolean} + */ + isOnline : function() + { + return this.offline.online; + }, + + /** + * Clears the local cache of tiles. + * @param callback callback(boolean, errors) + */ + deleteAllTiles : function(callback) // callback(success) or callback(false, error) + { + var store = this.offline.store; + store.deleteAll(callback); + }, + + /** + * Gets the size in bytes of the local tile cache. + * @param callback callback(size, error) + */ + getOfflineUsage : function(callback) // callback({size: <>, tileCount: <>}) or callback(null,error) + { + var store = this.offline.store; + store.usedSpace(callback); + }, + + /** + * Gets polygons representing all cached cell ids within a particular + * zoom level and bounded by an extent. + * @param callback callback(polygon, error) + */ + getTilePolygons : function(callback) // callback(Polygon polygon) or callback(null, error) + { + var store = this.offline.store; + var tilingScheme = new TilingScheme(this); + store.getAllTiles(function(url,img,err) + { + if(url) + { + var components = url.split("/"); + var level = parseInt(components[ components.length - 3],10); + var col = parseInt(components[ components.length - 2],10); + var row = parseInt(components[ components.length - 1],10); + var cellId = [row,col]; + var polygon = tilingScheme.getCellPolygonFromCellId(cellId, level); + //if( level == 15) + callback(polygon); + } + else + { + callback(null,err); + } + }); + }, + + /** + * Saves tile cache into a portable csv format. + * @param fileName + * @param callback callback( boolean, error) + */ + saveToFile : function(fileName, callback) // callback(success, msg) + { + var store = this.offline.store; + var csv = []; + + csv.push("url,img"); + store.getAllTiles(function(url,img,evt) + { + if(evt==="end") + { + var blob = new Blob([ csv.join("\r\n") ], {type:"text/plain;charset=utf-8"}); + var saver = FileSaver.saveAs(blob, fileName); + + if( saver.readyState === saver.DONE ) + { + if( saver.error ) + { + return callback(false,"Error saving file " + fileName); + } + return callback(true, "Saved " + (csv.length-1) + " tiles (" + Math.floor(blob.size / 1024 / 1024 * 100) / 100 + " Mb) into " + fileName); + } + saver.onerror = function() { + callback(false,"Error saving file " + fileName); + }; + saver.onwriteend = function() + { + callback(true, "Saved " + (csv.length-1) + " tiles (" + Math.floor(blob.size / 1024 / 1024 * 100) / 100 + " Mb) into " + fileName); + }; + } + else + { + csv.push(url+","+img); + } + }); + }, + + /** + * Reads a csv file into local tile cache. + * @param file + * @param callback callback( boolean, error) + */ + loadFromFile : function(file, callback) // callback(success,msg) + { + console.log("reading",file); + + var store = this.offline.store; + var i; + + if (window.File && window.FileReader && window.FileList && window.Blob) + { + // Great success! All the File APIs are supported. + var reader = new FileReader(); + reader.onload = function(evt) + { + var csvContent = evt.target.result; + var tiles = csvContent.split("\r\n"); + var tileCount = 0; + var pair, tile; + + if(tiles[0] !== "url,img") + { + return callback(false, "File " + file.name + " doesn't contain tiles that can be loaded"); + } + + for(i=1; i + + + + + + Cache Features Sample + + + + + + + + + + + + + + + + + +
+ + +
+ +
Pending edits: 0
+
+
+ + + +
+ + + + \ No newline at end of file From ded97da733a009f3de7ba8ee96d1a461ca6b29dc Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Mon, 9 Jun 2014 13:14:21 -0600 Subject: [PATCH 079/139] tweaked order of execution --- samples/test.html | 74 +++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 38 deletions(-) diff --git a/samples/test.html b/samples/test.html index 0f08ab7..9080ec2 100644 --- a/samples/test.html +++ b/samples/test.html @@ -270,9 +270,6 @@ require([ var appCacheManager; var btnOnlineOffline = document.getElementById("btn-online-offline"); - setClickListeners(); - initOfflineFeatures(); - /** * There have been a few bugs in the offline detection library (offline.min.js) * This is a utility check to 100% validate if the application is online or @@ -295,13 +292,13 @@ require([ sliderStyle: "small" }); - var tiledMapLayer = new OfflineTileEnabler("http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer",function(evt){ + baseMapLayer = new OfflineTileEnabler("http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer",function(evt){ console.log("TEST") },true); - map.addLayer(tiledMapLayer); + map.addLayer(baseMapLayer); - tiledMapLayer.on("load",function(evt){ + baseMapLayer.on("load",function(evt){ busStopsFeatureLayer = new FeatureLayer("http://services.arcgis.com/IZtlGBUe4KTzLOl4/arcgis/rest/services/BPX_RTD_BusStops2/FeatureServer/0",{ mode: FeatureLayer.MODE_SNAPSHOT, @@ -334,9 +331,8 @@ require([ map.addLayers([busStopsFeatureLayer]); - initEditing(); +// initEditing(); initAppCacheManager(); - initOfflineTileEnabler(); if(_isOnline == false){ var fLayer = JSON.parse(localStorage.offlineLayerDef); var fFeatures = JSON.parse(localStorage.offlineFeature); @@ -346,7 +342,7 @@ require([ } }) -// map.on("layers-add-result",initEditing); + map.on("layers-add-result",initEditing); } @@ -415,8 +411,10 @@ require([ function initEditing(evt){ + setClickListeners(); + initOfflineFeatures(); offlineFeaturesManager.extend(busStopsFeatureLayer); - setFeatureLayerClickHandler() + setFeatureLayerClickHandler(); } function setFeatureLayerClickHandler(){ @@ -534,34 +532,34 @@ require([ * ************************************ */ - function initOfflineTileEnabler(){ - - mMaxZoom = map.getMaxZoom(); - mMinZoom = map.getMinZoom(); - - offlineTileEnabler = new OfflineTileEnabler(); - baseMapLayer = offlineTileEnabler.getBasemapLayer(map); console.log("Offline State: " + Offline.state) - - offlineTileEnabler.extend(baseMapLayer,function(success) - { - if( success ) - { - console.log("Offline tile lib is enabled. Application state is: " + Offline.state); - Offline.check(); - - //using null sets this for CORS - baseMapLayer.offline.proxyPath = null; - - on(btnGetTiles,"click",downloadTiles); - - updateOfflineUsage(); - } - else - { - alert("error initializing storage - browser doesn't support indexeddb or websql") - } - }.bind(this),_isOnline); - } +// function initOfflineTileEnabler(){ +// +// mMaxZoom = map.getMaxZoom(); +// mMinZoom = map.getMinZoom(); +// +// offlineTileEnabler = new OfflineTileEnabler(); +// baseMapLayer = offlineTileEnabler.getBasemapLayer(map); console.log("Offline State: " + Offline.state) +// +// offlineTileEnabler.extend(baseMapLayer,function(success) +// { +// if( success ) +// { +// console.log("Offline tile lib is enabled. Application state is: " + Offline.state); +// Offline.check(); +// +// //using null sets this for CORS +// baseMapLayer.offline.proxyPath = null; +// +// on(btnGetTiles,"click",downloadTiles); +// +// updateOfflineUsage(); +// } +// else +// { +// alert("error initializing storage - browser doesn't support indexeddb or websql") +// } +// }.bind(this),_isOnline); +// } /** * Manually starts the process to download and store tiles From 177dacdae1006b9f7111b13e622e7ca507ed2251 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Mon, 9 Jun 2014 13:18:19 -0600 Subject: [PATCH 080/139] minor cleanup --- lib/tiles/offlineTilesEnabler2.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/tiles/offlineTilesEnabler2.js b/lib/tiles/offlineTilesEnabler2.js index e121b74..d90d0e1 100644 --- a/lib/tiles/offlineTilesEnabler2.js +++ b/lib/tiles/offlineTilesEnabler2.js @@ -16,7 +16,7 @@ define([ FileSaver,LOD,Point,Extent,TileInfo,SpatialReference,TiledMapServerLayer) { "use strict"; - return declare("test",[TiledMapServerLayer],{ + return declare("OfflineTileEnablerLayer",[TiledMapServerLayer],{ tileInfo: null, _imageType:"", @@ -60,7 +60,6 @@ define([ this.offline.store.init(function(success){ if(success){ this._getTileInfoPrivate(url,function(result){ - console.log("RESULT BABY " + result) this.parseGetTileInfo(result,function(result){ this.layerInfos = result.resultObj.layers; // this.version = result.resultObj.currentVersion; @@ -121,9 +120,8 @@ define([ getTileUrl: function(level,row,col) { console.assert(!isNaN(level) && !isNaN(row) && !isNaN(col), "bad tile requested"); - console.log("looking for tile",level,row,col); -// var url = this._self._getTileUrl(level,row,col); + var url = this.url + "/tile/" + level + "/" + row + "/" + col; console.log("LIBRARY ONLINE " + this.offline.online) if( this.offline.online ) From 3f9171558d1a9944b1abc7a1e3832364d5a5bc05 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Mon, 9 Jun 2014 13:18:36 -0600 Subject: [PATCH 081/139] read min/max zoom var's --- samples/test.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/samples/test.html b/samples/test.html index 9080ec2..5282d6c 100644 --- a/samples/test.html +++ b/samples/test.html @@ -300,6 +300,9 @@ require([ baseMapLayer.on("load",function(evt){ + mMaxZoom = map.getMaxZoom(); + mMinZoom = map.getMinZoom(); + busStopsFeatureLayer = new FeatureLayer("http://services.arcgis.com/IZtlGBUe4KTzLOl4/arcgis/rest/services/BPX_RTD_BusStops2/FeatureServer/0",{ mode: FeatureLayer.MODE_SNAPSHOT, outFields: ["OBJECTID","BSID","ROUTES","STOPNAME"] From 30267af9992e10ace51c4b98f9ff74f097f2d3fd Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Mon, 9 Jun 2014 13:31:11 -0600 Subject: [PATCH 082/139] cleanup, removed unused code --- samples/test.html | 51 +++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/samples/test.html b/samples/test.html index 5282d6c..ec8b48b 100644 --- a/samples/test.html +++ b/samples/test.html @@ -199,28 +199,25 @@ + + + + + +
+ + +
+ +
Pending edits: 0
+
+
+
+ + + + + \ No newline at end of file From 26f9ceed3f5841e0895b95b4885926acd8f086af Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Mon, 9 Jun 2014 17:58:56 -0600 Subject: [PATCH 088/139] Buggy. Rebuilding from ground up using test2 --- samples/test.html | 66 ++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/samples/test.html b/samples/test.html index ec8b48b..13eefe4 100644 --- a/samples/test.html +++ b/samples/test.html @@ -138,7 +138,7 @@ } - + @@ -291,57 +291,59 @@ require([ baseMapLayer = new OfflineTileEnabler("http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer",function(evt){ console.log("Tile layer has been initialized") + on(btnGetTiles,"click",downloadTiles); + mMaxZoom = map.getMaxZoom(); + mMinZoom = map.getMinZoom(); },true); map.addLayer(baseMapLayer); - baseMapLayer.on("load",function(evt){ + busStopsFeatureLayer = new FeatureLayer("http://services.arcgis.com/IZtlGBUe4KTzLOl4/arcgis/rest/services/BPX_RTD_BusStops2/FeatureServer/0",{ + mode: FeatureLayer.MODE_SNAPSHOT, + outFields: ["OBJECTID","BSID","ROUTES","STOPNAME"] + }); - mMaxZoom = map.getMaxZoom(); - mMinZoom = map.getMinZoom(); + //Set the graphics to red boxes to make it easy to click on them + //on a mobile device. + busStopsFeatureLayer.setRenderer(new SimpleRenderer(defaultSymbol)); - busStopsFeatureLayer = new FeatureLayer("http://services.arcgis.com/IZtlGBUe4KTzLOl4/arcgis/rest/services/BPX_RTD_BusStops2/FeatureServer/0",{ - mode: FeatureLayer.MODE_SNAPSHOT, - outFields: ["OBJECTID","BSID","ROUTES","STOPNAME"] - }); + busStopsFeatureLayer.on("update-end",function(evt){ + layerDefinition.objectIdFieldName = evt.target.objectIdField; + layerDefinition.globalIdFieldName = evt.target.globalIdField; + layerDefinition.geometryType = evt.target.geometryType; + layerDefinition.spatialReference = evt.target.spatialReference; + layerDefinition.fields = evt.target.fields; + features = evt.target.graphics; - // Set the graphics to red boxes to make it easy to click on them - // on a mobile device. - busStopsFeatureLayer.setRenderer(new SimpleRenderer(defaultSymbol)); - - busStopsFeatureLayer.on("update-end",function(evt){ - layerDefinition.objectIdFieldName = evt.target.objectIdField; - layerDefinition.globalIdFieldName = evt.target.globalIdField; - layerDefinition.geometryType = evt.target.geometryType; - layerDefinition.spatialReference = evt.target.spatialReference; - layerDefinition.fields = evt.target.fields; - features = evt.target.graphics; - - convertGraphicLayerToJSON(features,function(result){ - var featureJSON = JSON.stringify(result); - if(typeof(Storage) !== "undefined") { - localStorage.offlineLayerDef = JSON.stringify(layerDefinition); - localStorage.offlineFeature = featureJSON; - console.log("Done pushing layerDef and features to localStorage.") - } else { - alert("The offline library is not supported on this browser.") - } - }) + convertGraphicLayerToJSON(features,function(result){ + var featureJSON = JSON.stringify(result); + if(typeof(Storage) !== "undefined") { + localStorage.offlineLayerDef = JSON.stringify(layerDefinition); + localStorage.offlineFeature = featureJSON; + console.log("Done pushing layerDef and features to localStorage.") + } else { + alert("The offline library is not supported on this browser.") + } }) + }) - map.addLayers([busStopsFeatureLayer]); + map.on("load",function(evt){ + + updateOfflineUsage(); initAppCacheManager(); if(_isOnline == false){ var fLayer = JSON.parse(localStorage.offlineLayerDef); var fFeatures = JSON.parse(localStorage.offlineFeature); reconstituteGraphicsLayer(fLayer,fFeatures,function(result){ - initEditing(result); + offlineFeaturesManager.extend(busStopsFeatureLayer); + setFeatureLayerClickHandler() }); } }) map.on("layers-add-result",initEditing); + map.addLayer(busStopsFeatureLayer); } From 1ee42ff4bcf2503fc082865f02f3b3f12b41bfbc Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Tue, 10 Jun 2014 09:10:10 -0600 Subject: [PATCH 089/139] renamed offlineTilesEnabler2.js to OfflineTilesEnablerLayer --- .../{offlineTilesEnabler2.js => OfflineTilesEnablerLayer.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/tiles/{offlineTilesEnabler2.js => OfflineTilesEnablerLayer.js} (100%) diff --git a/lib/tiles/offlineTilesEnabler2.js b/lib/tiles/OfflineTilesEnablerLayer.js similarity index 100% rename from lib/tiles/offlineTilesEnabler2.js rename to lib/tiles/OfflineTilesEnablerLayer.js From ee1e8d9b4a04dc624d15af20c4c129361c2a4541 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Tue, 10 Jun 2014 09:46:22 -0600 Subject: [PATCH 090/139] added restartOfflineFeaturesManager --- lib/edit/restartOfflineFeaturesManager.js | 59 +++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 lib/edit/restartOfflineFeaturesManager.js diff --git a/lib/edit/restartOfflineFeaturesManager.js b/lib/edit/restartOfflineFeaturesManager.js new file mode 100644 index 0000000..fbd07c9 --- /dev/null +++ b/lib/edit/restartOfflineFeaturesManager.js @@ -0,0 +1,59 @@ +define(["esri/graphic"], function(Graphic) { + "use strict"; + + return { + + convertGraphicLayerToJSON: function(features,updateEndEvent,callback){ + var layerDefinition = {}; + layerDefinition.objectIdFieldName = updateEndEvent.target.objectIdField; + layerDefinition.globalIdFieldName = updateEndEvent.target.globalIdField; + layerDefinition.geometryType = updateEndEvent.target.geometryType; + layerDefinition.spatialReference = updateEndEvent.target.spatialReference; + layerDefinition.fields = updateEndEvent.target.fields; + + var length = features.length; + var jsonArray = []; + for(var i=0; i < length; i++){ + var jsonGraphic = features[i].toJson(); + jsonArray.push(jsonGraphic); + if(i == (length - 1)) { + callback(jsonArray,layerDefinition); + break; + } + } + }, + + reconstituteGraphicsLayer: function(featureLayer,featuresArr,callback){ + + if(featureLayer == null){ + alert("No features available available locally.") + } + else{ + var featureDefinition = { + "layerDefinition":featureLayer, + "featureSet":{ + "features": featuresArr, + "geometryType": "esriGeometryPoint" + } + + } + + var newFeatureLayer = new FeatureLayer(featureDefinition,{ + mode: FeatureLayer.MODE_SNAPSHOT, + outFields: ["OBJECTID","BSID","ROUTES","STOPNAME"] + }); + + // Set the graphics to red boxes to make it easy to click on them + // on a mobile device. + newFeatureLayer.setRenderer(new SimpleRenderer(defaultSymbol)); + +// var mapListen = map.on("update-end",function(evt){ +// console.log("Feature has been added back to the map while offline.") +// mapListen.remove(); +// }) +// map.addLayer(busStopsFeatureLayer); + callback(newFeatureLayer); + } + } + } +}) \ No newline at end of file From 554ef1795755ee5c0d28d62504e969d317f9b00d Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Tue, 10 Jun 2014 09:46:47 -0600 Subject: [PATCH 091/139] capture update-end event --- samples/test2.html | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/samples/test2.html b/samples/test2.html index 012f3f2..2019548 100644 --- a/samples/test2.html +++ b/samples/test2.html @@ -63,6 +63,9 @@ var locationPath = location.pathname.replace(/\/[^/]+$/, ""); var dojoConfig = { paths: { + edit: locationPath + "/../lib/edit", + vendor: locationPath + "/../vendor", + utils: locationPath + "/../utils", tiles: locationPath + "/../lib/tiles" } } @@ -83,10 +86,11 @@
+ + @@ -94,6 +97,7 @@ var _isOnline = true; var defaultSymbol; + var busStopFeatureLayer; // Modify symbol size based on screen size. // Bigger screens get smaller symbols. Smaller screens get larger symbols. @@ -131,7 +135,7 @@ map.addLayer(tileLayer); - var busStopFeatureLayer = new FeatureLayer("http://services.arcgis.com/IZtlGBUe4KTzLOl4/arcgis/rest/services/BPX_RTD_BusStops2/FeatureServer/0", { + busStopFeatureLayer = new FeatureLayer("http://services.arcgis.com/IZtlGBUe4KTzLOl4/arcgis/rest/services/BPX_RTD_BusStops2/FeatureServer/0", { mode: FeatureLayer.MODE_SNAPSHOT, outFields: ["OBJECTID","BSID","ROUTES","STOPNAME"] }); @@ -142,9 +146,52 @@ busStopFeatureLayer.on("update-end",function(evt){ var features = evt.target.graphics; - restartOfflineFeaturesMgr.convertGraphicLayerToJSON(features,evt,function(jsonArr,layerDef){ - console.log("HIYA!") + + // Convert existing feature graphics into JSON. + // These are then stored in localStorage. + // If you want you can store multiple feature layers. + // Just be aware of the localStorage limitations. + restartOfflineFeaturesMgr.convertGraphicLayerToJSON(features,evt,function(features,layerDef){ + + if(typeof(Storage) !== "undefined") { + localStorage.offlineLayerDef = layerDef; + localStorage.offlineFeature = features; + console.log("Done pushing layerDef and features to localStorage.") + } else { + alert("The offline library is not supported on this browser.") + } }) + }); + + map.on("load",function(evt){ + +// updateOfflineUsage(); +// +// initAppCacheManager(); + if(_isOnline == false){ + var featureLayer = JSON.parse(localStorage.offlineLayerDef); + var featuresArray = JSON.parse(localStorage.offlineFeature); + var geometryType = "esriGeometryPoint"; + + restartOfflineFeaturesMgr.getFeatureDefinition(featureLayer,featuresArray,geometryType,function(featureDef){ + + busStopsFeatureLayer = new FeatureLayer(featureDef,{ + mode: FeatureLayer.MODE_SNAPSHOT, + outFields: ["OBJECTID","BSID","ROUTES","STOPNAME"] + }); + // Set the graphics to red boxes to make it easy to click on them + // on a mobile device. + busStopsFeatureLayer.setRenderer(new SimpleRenderer(defaultSymbol)); + var mapListen = map.on("update-end",function(evt){ + console.log("Feature has been added back to the map while offline.") + mapListen.remove(); + }) + map.addLayer(busStopsFeatureLayer); + +// offlineFeaturesManager.extend(busStopsFeatureLayer); +// setFeatureLayerClickHandler() + }); + } }) map.addLayer(busStopFeatureLayer); From 3a30ac39f0920779c620c0b5a91dcb763cd595b4 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Tue, 10 Jun 2014 10:19:14 -0600 Subject: [PATCH 094/139] added app cache manager --- samples/test2.html | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/samples/test2.html b/samples/test2.html index 95e199d..664ab81 100644 --- a/samples/test2.html +++ b/samples/test2.html @@ -90,14 +90,16 @@ @@ -98,6 +130,46 @@
Pending edits: 0
+ + +
- - + -
@@ -197,495 +174,472 @@
+ \ No newline at end of file diff --git a/samples/test.html b/samples/test.html deleted file mode 100644 index 13eefe4..0000000 --- a/samples/test.html +++ /dev/null @@ -1,703 +0,0 @@ - - - - - - - Cache Features Sample - - - - - - - - - - - - - - - - - -
- - -
- -
Pending edits: 0
-
-
- - - -
- - - - \ No newline at end of file diff --git a/samples/test2.html b/samples/test2.html deleted file mode 100644 index cdc8893..0000000 --- a/samples/test2.html +++ /dev/null @@ -1,647 +0,0 @@ - - - - - - - - AppCache Tiles and Features - - - - - - - - - - - - - - - - -
- - -
- -
Pending edits: 0
-
-
- - - -
- - - - - \ No newline at end of file From aab0da7bc4b9eca36ffa504c567eabcf28adbe3f Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Wed, 11 Jun 2014 09:32:14 -0600 Subject: [PATCH 122/139] more cleanup --- lib/edit/restartOfflineFeaturesManager.js | 40 ++++++++--------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/lib/edit/restartOfflineFeaturesManager.js b/lib/edit/restartOfflineFeaturesManager.js index b7c2476..420073b 100644 --- a/lib/edit/restartOfflineFeaturesManager.js +++ b/lib/edit/restartOfflineFeaturesManager.js @@ -34,37 +34,25 @@ define(["esri/graphic"], function(Graphic) { } }, + /** + * Create a featureDefinition + * @param featureLayer + * @param featuresArr + * @param geometryType + * @param callback + */ getFeatureDefinition: function(/* Object */ featureLayer,/* Array */ featuresArr,/* String */ geometryType,callback){ - if(featureLayer == null){ - alert("No features available available locally.") - } - else{ - var featureDefinition = { - "layerDefinition":featureLayer, - "featureSet":{ - "features": featuresArr, - "geometryType": geometryType - } - + var featureDefinition = { + "layerDefinition":featureLayer, + "featureSet":{ + "features": featuresArr, + "geometryType": geometryType } -// var newFeatureLayer = new FeatureLayer(featureDefinition,{ -// mode: FeatureLayer.MODE_SNAPSHOT, -// outFields: ["OBJECTID","BSID","ROUTES","STOPNAME"] -// }); -// -// // Set the graphics to red boxes to make it easy to click on them -// // on a mobile device. -// newFeatureLayer.setRenderer(new SimpleRenderer(defaultSymbol)); -// -//// var mapListen = map.on("update-end",function(evt){ -//// console.log("Feature has been added back to the map while offline.") -//// mapListen.remove(); -//// }) -//// map.addLayer(busStopsFeatureLayer); - callback(featureDefinition); } + + callback(featureDefinition); } } }) \ No newline at end of file From 6cd37cf89e6029ab860f5b1c82d45a034890d749 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Wed, 11 Jun 2014 11:22:49 -0600 Subject: [PATCH 123/139] replaced offlineTileEnabler with OfflineTilesEnablerLayer --- samples/appcache-tiles.html | 138 ++++++++++++++++++++++-------------- 1 file changed, 83 insertions(+), 55 deletions(-) diff --git a/samples/appcache-tiles.html b/samples/appcache-tiles.html index 968d0fa..b3b0e41 100644 --- a/samples/appcache-tiles.html +++ b/samples/appcache-tiles.html @@ -107,19 +107,24 @@ ask if you want to reload the application.
- + ``` @@ -124,3 +129,72 @@ It calculates the geographic boundary of each of the tiles stored in the indexed } } ``` + +## Approach #2 - Custom TileLayer + +This approach is best if you have requirements for restarting or reloading your application while offline. For this approach use the `OfflineTilesEnablerLayer.js` library. This library extends TileMapServiceLayer and you can use it with any Esri tiled basemap layer. + + +**Step 1** Configure paths for dojo loader to find the tiles and vendor modules (you need to set paths relative to the location of your html document), before loading ArcGIS JavaScript API + +```html + + + +``` + +**Step 2** Include the `tiles/offlineTilesEnabler` library in your app. + +```js + require([ + "esri/map", + "tiles/OfflineTilesEnablerLayer"], + function(Map,OfflineTilesEnablerLayer) + { + ... + }); +``` + +**Step 3** Create a new instance of OfflineTilesEnablerLayer. Note, when you instantiate the Map leave off the `basemap` property because we are adding a customer tile layer as our basemap. + +```js + tileLayer = new OfflineTilesEnablerLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer",function(evt){ + console.log("Tile Layer Loaded."); + },_isOnline); + + var map = new Map("map",{ + center: [-104.98,39.74], // long, lat + zoom: 8, + sliderStyle: "small" + }); + + map.addLayer(tileLayer); + + +``` + +All map events will continue to work normally. Although some methods that are typically available will now have to be accessed through the OfflineTilesEnablerLayer such as `getLevel()`, `getMaxZoom()`, and `getMinZoom()`. + +To get the current extent you will need to monitor the `zoom-end` and `pan-end` events like this: + +```js + + + map.on("zoom-end",function(evt){ + _currentExtent = evt.extent; + }); + + map.on("pan-end",function(evt){ + _currentExtent = evt.extent; + }); + +``` \ No newline at end of file From 23d6396bcb302597597cc8ec4f033f26d20c6a45 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Wed, 11 Jun 2014 12:32:53 -0600 Subject: [PATCH 128/139] few more doc tweaks --- doc/howtousetiles.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/howtousetiles.md b/doc/howtousetiles.md index 58ebb1f..9a41c4e 100644 --- a/doc/howtousetiles.md +++ b/doc/howtousetiles.md @@ -164,7 +164,7 @@ This approach is best if you have requirements for restarting or reloading your }); ``` -**Step 3** Create a new instance of OfflineTilesEnablerLayer. Note, when you instantiate the Map leave off the `basemap` property because we are adding a customer tile layer as our basemap. +**Step 3** Create a new instance of `OfflineTilesEnablerLayer`. Note, when you instantiate the `Map` leave off the `basemap` property because we are adding a customer tile layer as our basemap. `OfflineTilesEnablerLayer` has three properties in the constructor. The first is the REST endpoint of the basemap you want to use, the second is the callback and the last is an optional parameter to preset the layer as online or offline. This will help with with drawing tiles correctly during offline restarts or reloads. ```js tileLayer = new OfflineTilesEnablerLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer",function(evt){ From 472d7889f6e1d104b1fd9b026793223e89c9cf54 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Wed, 11 Jun 2014 12:34:37 -0600 Subject: [PATCH 129/139] minor tweak to state property checking --- lib/tiles/OfflineTilesEnablerLayer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tiles/OfflineTilesEnablerLayer.js b/lib/tiles/OfflineTilesEnablerLayer.js index c6ce7b6..af43db3 100644 --- a/lib/tiles/OfflineTilesEnablerLayer.js +++ b/lib/tiles/OfflineTilesEnablerLayer.js @@ -45,7 +45,7 @@ define([ this._getTileUrl = this.getTileUrl; var isOnline = true; - if(typeof state != "undefined"){ + if(typeof state != "undefined" || state != null){ isOnline = state; console.log("STATE IS: " + state) } From 4e017c9f952f2846e977a03f02147a1903b16c44 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Wed, 11 Jun 2014 12:43:58 -0600 Subject: [PATCH 130/139] adding in tests for OfflineTilesEnablerLayer --- test/SpecRunner.offlineTilesEnablerLayer.html | 97 ++++++++ test/spec/offlineTilesEnablerLayerSpec.js | 209 ++++++++++++++++++ 2 files changed, 306 insertions(+) create mode 100644 test/SpecRunner.offlineTilesEnablerLayer.html create mode 100644 test/spec/offlineTilesEnablerLayerSpec.js diff --git a/test/SpecRunner.offlineTilesEnablerLayer.html b/test/SpecRunner.offlineTilesEnablerLayer.html new file mode 100644 index 0000000..0b2e5a2 --- /dev/null +++ b/test/SpecRunner.offlineTilesEnablerLayer.html @@ -0,0 +1,97 @@ + + + + Jasmine Spec Runner - Tiles + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/test/spec/offlineTilesEnablerLayerSpec.js b/test/spec/offlineTilesEnablerLayerSpec.js new file mode 100644 index 0000000..23d18f6 --- /dev/null +++ b/test/spec/offlineTilesEnablerLayerSpec.js @@ -0,0 +1,209 @@ +"use strict" + +describe("offline enabler library", function() +{ + var async = new AsyncSpec(this); + + async.it("validate map", function(done) + { + expect(g_map).toEqual(jasmine.any(Object)); + expect(g_map.id).toEqual("map"); + done(); + }); + + async.it("validate tiled layer", function(done) + { + expect(g_basemapLayer).toEqual(jasmine.any(Object)); + expect(g_basemapLayer.tileInfo).toEqual(jasmine.any(Object)); + done(); + }); + + async.it("extends the tiled layer object", function(done) + { + expect(g_basemapLayer.goOffline).toBeUndefined(); + g_offlineTilesEnabler.extend(g_basemapLayer,function(success) + { + expect(success).toEqual(true); + expect(g_basemapLayer.goOffline).toEqual(jasmine.any(Function)); + expect(g_basemapLayer.goOnline).toEqual(jasmine.any(Function)); + expect(g_basemapLayer.getTileUrl).toEqual(jasmine.any(Function)); + expect(g_basemapLayer._getTileUrl).toEqual(jasmine.any(Function)); + expect(g_basemapLayer.prepareForOffline).toEqual(jasmine.any(Function)); + expect(g_basemapLayer._storeTile).toEqual(jasmine.any(Function)); + expect(g_basemapLayer.deleteAllTiles).toEqual(jasmine.any(Function)); + expect(g_basemapLayer.offline).toEqual(jasmine.any(Object)); + expect(g_basemapLayer.offline.store).toEqual(jasmine.any(Object)); + + g_basemapLayer.offline.proxyPath = "../lib/resource-proxy/proxy.php"; + done(); + }); + }); + + async.it("can go offline", function(done) + { + expect(g_basemapLayer.goOffline).toEqual(jasmine.any(Function)); + expect(g_basemapLayer.offline.online).toEqual(true); + g_basemapLayer.goOffline(); + expect(g_basemapLayer.offline.online).toEqual(false); + done(); + }); + + async.it("can go online", function(done) + { + expect(g_basemapLayer.goOffline).toEqual(jasmine.any(Function)); + expect(g_basemapLayer.offline.online).toEqual(false); + g_basemapLayer.goOnline(); + expect(g_basemapLayer.offline.online).toEqual(true); + done(); + }) + + async.it("delete all tiles", function(done) + { + g_basemapLayer.deleteAllTiles(function(success) + { + expect(success).toEqual(true); + setTimeout(function() + { + g_basemapLayer.getOfflineUsage(function(usage) + { + expect(usage.tileCount).toEqual(0); + done(); + }); + },1); + }); + }); + + async.it("stores one tile", function(done) + { + g_basemapLayer.getOfflineUsage(function(usage) + { + expect(usage.tileCount).toEqual(0); + g_basemapLayer._storeTile(14,6177,8023, function(success) + { + expect(success).toEqual(true); + g_basemapLayer.getOfflineUsage(function(usage) + { + expect(usage.tileCount).toEqual(1); + done(); + }); + }); + }); + }); + + async.it("stores one tile again", function(done) + { + g_basemapLayer.getOfflineUsage(function(usage) + { + expect(usage.tileCount).toEqual(1); + g_basemapLayer._storeTile(14,6177,8023, function(success) + { + expect(success).toEqual(true); + g_basemapLayer.getOfflineUsage(function(usage) + { + expect(usage.tileCount).toEqual(1); + done(); + }); + }); + }); + }); + + async.it("gets level estimation", function(done) + { + require(["esri/geometry/Extent"],function(Extent) + { + var extent = new Extent({"xmin":-822542.2830377579,"ymin":4580841.761960262,"xmax":94702.05638410954,"ymax":5131188.365613382,"spatialReference":{"wkid":102100}}); + g_basemapLayer.estimateTileSize(function(tileSize){ + var estimation = g_basemapLayer.getLevelEstimation(extent,10,tileSize); + expect(estimation.tileCount).toEqual(375); + expect(estimation.sizeBytes).toEqual(estimation.tileCount * tileSize); + + var estimation = g_basemapLayer.getLevelEstimation(extent,8,tileSize); + expect(estimation.tileCount).toEqual(28); + expect(estimation.sizeBytes).toEqual(estimation.tileCount * tileSize); + var estimation = g_basemapLayer.getLevelEstimation(extent,2,tileSize); + expect(estimation.tileCount).toEqual(2); + expect(estimation.sizeBytes).toEqual(estimation.tileCount * tileSize); + done(); + }.bind(this)); + }); + }); + + async.it("prepares the layer for offline usage", function(done) + { + require(["esri/geometry/Extent"], function(Extent) + { + g_basemapLayer.deleteAllTiles(function(success) + { + expect(success).toEqual(true); + var extent = new Extent({"xmin":-822542.2830377579,"ymin":4580841.761960262,"xmax":94702.05638410954,"ymax":5131188.365613382,"spatialReference":{"wkid":102100}}); + var callCount = 0; + var reportProgress = function(progress) + { + callCount += 1; + expect(progress.error).not.toBeDefined(); + + if( progress.finishedDownloading ) + { + g_basemapLayer.getOfflineUsage(function(usage) + { + expect(usage.tileCount).toEqual(28); + expect(callCount).toEqual(29); + done(); + }); + } + + return false; // cancelRequested = false; + } + + g_basemapLayer.prepareForOffline(8,8,extent,reportProgress); + }); + }); + }); + + async.it("get tile urls",function(done) + { + require(["esri/geometry/Extent"],function(Extent){ + var extent = new Extent({"xmin":-822542.2830377579,"ymin":4580841.761960262,"xmax":94702.05638410954,"ymax":5131188.365613382,"spatialReference":{"wkid":102100}}); + var cells = g_basemapLayer.getTileUrlsByExtent(extent,3); + var regexp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/; + for(var i = 0; i < cells.length; i++){ + var isUrl = regexp.test(cells[i]); + expect(isUrl).toBe(true); + } + expect(cells.length).toBeGreaterThan(0); + done(); + }); + }); + + async.it("get extent buffer",function(done) + { + require(["esri/geometry/Extent"],function(Extent){ + var extent = new Extent({"xmin":-822542.2830377579,"ymin":4580841.761960262,"xmax":94702.05638410954,"ymax":5131188.365613382,"spatialReference":{"wkid":102100}}); + var newExtent = g_basemapLayer.getExtentBuffer(1000,extent); + expect(newExtent.xmin).toBe(-823542.2830377579); + done(); + }); + }); + + async.it("returns placeholder urls when offline", function(done) + { + require(["dojo/dom"], function(dom) + { + var fakeTile = dom.byId('fakeTile'); + + g_basemapLayer.goOnline(); + var onlineUrl = g_basemapLayer.getTileUrl(14,6178,8023); + + //NOTE: We are getting new attributes at ArcGIS JS API v3.8 : blankTile=false&_ts=1393031666639 + // http://services.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/14/6178/8023?blankTile=false&_ts=1393031666639" + var tempUrl = onlineUrl.slice( 0, onlineUrl.indexOf('?')) + expect(tempUrl).toEqual('http://services.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/14/6178/8023'); + + g_basemapLayer.goOffline(); + var offlineUrl = fakeTile.src = g_basemapLayer.getTileUrl(14,6178,8023); + expect(offlineUrl).toEqual('void:/14/6178/8023'); + done(); + }) + }); + +}); From a068e05cd9b4ca123a5046e4315c97da02e8929b Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Wed, 11 Jun 2014 13:09:13 -0600 Subject: [PATCH 131/139] fixed scope on _lastTileUrl --- lib/tiles/OfflineTilesEnablerLayer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tiles/OfflineTilesEnablerLayer.js b/lib/tiles/OfflineTilesEnablerLayer.js index af43db3..76e42bf 100644 --- a/lib/tiles/OfflineTilesEnablerLayer.js +++ b/lib/tiles/OfflineTilesEnablerLayer.js @@ -485,9 +485,9 @@ define([ */ estimateTileSize : function(callback) { - if(_lastTileUrl) + if(this._lastTileUrl) { - var url = this.offline.proxyPath? this.offline.proxyPath + "?" + _lastTileUrl : _lastTileUrl; + var url = this.offline.proxyPath? this.offline.proxyPath + "?" + this._lastTileUrl : this._lastTileUrl; request.get(url,{ handleAs: "text/plain; charset=x-user-defined", headers: { From 40963cb79b5b6d2464daad037378df73e63e7c04 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Wed, 11 Jun 2014 13:19:00 -0600 Subject: [PATCH 132/139] fixed minor scope issue --- lib/tiles/OfflineTilesEnablerLayer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tiles/OfflineTilesEnablerLayer.js b/lib/tiles/OfflineTilesEnablerLayer.js index 76e42bf..fbaa720 100644 --- a/lib/tiles/OfflineTilesEnablerLayer.js +++ b/lib/tiles/OfflineTilesEnablerLayer.js @@ -524,13 +524,13 @@ define([ * @returns Array */ getTileUrlsByExtent : function(extent,level){ - var tilingScheme = new TilingScheme(layer); + var tilingScheme = new TilingScheme(this); var level_cell_ids = tilingScheme.getAllCellIdsInExtent(extent,level); var cells = []; level_cell_ids.forEach(function(cell_id) { - cells.push(url + "/" + level + "/" + cell_id[1] + "/" + cell_id[0]); + cells.push(this.url + "/" + level + "/" + cell_id[1] + "/" + cell_id[0]); }.bind(this)); return cells; From edecdbfae58a31faacb6f999ce5d4122715f43e2 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Wed, 11 Jun 2014 13:40:37 -0600 Subject: [PATCH 133/139] spec done --- test/spec/offlineTilesEnablerLayerSpec.js | 78 ++++++++++++++++------- 1 file changed, 54 insertions(+), 24 deletions(-) diff --git a/test/spec/offlineTilesEnablerLayerSpec.js b/test/spec/offlineTilesEnablerLayerSpec.js index 23d18f6..6ec1c88 100644 --- a/test/spec/offlineTilesEnablerLayerSpec.js +++ b/test/spec/offlineTilesEnablerLayerSpec.js @@ -1,11 +1,11 @@ "use strict" -describe("offline enabler library", function() +describe("offline enabler custom layer library", function() { var async = new AsyncSpec(this); async.it("validate map", function(done) - { + { console.log("VALIDATE !!!!!") expect(g_map).toEqual(jasmine.any(Object)); expect(g_map.id).toEqual("map"); done(); @@ -18,27 +18,27 @@ describe("offline enabler library", function() done(); }); - async.it("extends the tiled layer object", function(done) - { - expect(g_basemapLayer.goOffline).toBeUndefined(); - g_offlineTilesEnabler.extend(g_basemapLayer,function(success) - { - expect(success).toEqual(true); - expect(g_basemapLayer.goOffline).toEqual(jasmine.any(Function)); - expect(g_basemapLayer.goOnline).toEqual(jasmine.any(Function)); - expect(g_basemapLayer.getTileUrl).toEqual(jasmine.any(Function)); - expect(g_basemapLayer._getTileUrl).toEqual(jasmine.any(Function)); - expect(g_basemapLayer.prepareForOffline).toEqual(jasmine.any(Function)); - expect(g_basemapLayer._storeTile).toEqual(jasmine.any(Function)); - expect(g_basemapLayer.deleteAllTiles).toEqual(jasmine.any(Function)); - expect(g_basemapLayer.offline).toEqual(jasmine.any(Object)); - expect(g_basemapLayer.offline.store).toEqual(jasmine.any(Object)); - - g_basemapLayer.offline.proxyPath = "../lib/resource-proxy/proxy.php"; - done(); - }); - }); - +// async.it("extends the tiled layer object", function(done) +// { +// expect(g_basemapLayer.goOffline).toBeUndefined(); +// g_offlineTilesEnabler.extend(g_basemapLayer,function(success) +// { +// expect(success).toEqual(true); +// expect(g_basemapLayer.goOffline).toEqual(jasmine.any(Function)); +// expect(g_basemapLayer.goOnline).toEqual(jasmine.any(Function)); +// expect(g_basemapLayer.getTileUrl).toEqual(jasmine.any(Function)); +// expect(g_basemapLayer._getTileUrl).toEqual(jasmine.any(Function)); +// expect(g_basemapLayer.prepareForOffline).toEqual(jasmine.any(Function)); +// expect(g_basemapLayer._storeTile).toEqual(jasmine.any(Function)); +// expect(g_basemapLayer.deleteAllTiles).toEqual(jasmine.any(Function)); +// expect(g_basemapLayer.offline).toEqual(jasmine.any(Object)); +// expect(g_basemapLayer.offline.store).toEqual(jasmine.any(Object)); +// +// g_basemapLayer.offline.proxyPath = "../lib/resource-proxy/proxy.php"; +// done(); +// }); +// }); +// async.it("can go offline", function(done) { expect(g_basemapLayer.goOffline).toEqual(jasmine.any(Function)); @@ -197,7 +197,7 @@ describe("offline enabler library", function() //NOTE: We are getting new attributes at ArcGIS JS API v3.8 : blankTile=false&_ts=1393031666639 // http://services.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/14/6178/8023?blankTile=false&_ts=1393031666639" var tempUrl = onlineUrl.slice( 0, onlineUrl.indexOf('?')) - expect(tempUrl).toEqual('http://services.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/14/6178/8023'); + expect(tempUrl).toEqual('http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/14/6178/802'); g_basemapLayer.goOffline(); var offlineUrl = fakeTile.src = g_basemapLayer.getTileUrl(14,6178,8023); @@ -206,4 +206,34 @@ describe("offline enabler library", function() }) }); + async.it("getMaxZoom", function(done){ + g_basemapLayer.getMaxZoom(function(result){ + expect(result).toBe(19); + done(); + }) + }); + + async.it("getMinZoom", function(done){ + g_basemapLayer.getMinZoom(function(result){ + expect(result).toBe(0); + done(); + }) + }); + + it("verifies ability to retrieve layer info",function(done){ + g_basemapLayer._getTileInfoPrivate("http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer",function(result){ + var fixedResponse = result.replace(/\\'/g, "'"); + var resultObj = JSON.parse(fixedResponse); + expect(resultObj).toEqual(jasmine.any(Object)); + }) + }); + + it("verifies ability to parse layer info",function(done){ + g_basemapLayer._getTileInfoPrivate("http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer",function(result){ + g_basemapLayer.parseGetTileInfo(result,function(result){ + expect(result).toEqual(jasmine.any(Object)); + }) + }) + }); + }); From 53779a17d3c0683eb91ab0696724ac840aeedfa8 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Wed, 11 Jun 2014 13:40:53 -0600 Subject: [PATCH 134/139] spec enabler done --- test/SpecRunner.offlineTilesEnablerLayer.html | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/test/SpecRunner.offlineTilesEnablerLayer.html b/test/SpecRunner.offlineTilesEnablerLayer.html index 0b2e5a2..c7e758f 100644 --- a/test/SpecRunner.offlineTilesEnablerLayer.html +++ b/test/SpecRunner.offlineTilesEnablerLayer.html @@ -21,13 +21,12 @@ - + - - - + + + From b786df6054e3a162eedeea91792b1b3d3ada2243 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Wed, 11 Jun 2014 14:14:43 -0600 Subject: [PATCH 137/139] fixed typos --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 973dc48..53df06a 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Extends and overrides a feature layer. This library allows you to extend esri.la ##offlineTilesEnabler -Extends and overrides a tiled map service. Provides the ability to customize the extent used to cut the tiles. See the detailed description of basemap.prepareForOffline() in the "How To Use" section below to learn different options. +Extends and overrides a tiled map service. Provides the ability to customize the extent used to cut the tiles. See the detailed description of basemap.prepareForOffline() in the "How To Use" section to learn different options. * __Click [here](doc/offlinetilesenabler.md) to see the full API doc for `offlineTilesEnabler`__ @@ -57,7 +57,7 @@ Extends TileMapServiceLayer. You can display TPK files with this library. * [Learn more about using the `tile` library](doc/howtousetiles.md) * [Learn more about using the `edit` library](doc/howtouseeditlibrary.md) * [Learn more about using the `tpk` library](doc/howtousetpklibrary.md) -* [Learn more aobut using an application cache with this library](doc/howtouseappcache.md) +* [Learn more abuut using an application cache with this library](doc/howtouseappcache.md) ##Setup Instructions From 47bd92a0fb61c48706ff4f53c021571d37ef6e9a Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Wed, 11 Jun 2014 14:15:00 -0600 Subject: [PATCH 138/139] updated how to use app cache --- doc/howtouseappcache.md | 54 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/doc/howtouseappcache.md b/doc/howtouseappcache.md index 2dd971f..ba71f7d 100644 --- a/doc/howtouseappcache.md +++ b/doc/howtouseappcache.md @@ -1,12 +1,60 @@ Tips on using application cache =============================== -If you have a requirement to reload your application or restart the browser while offline then you will need to use the [application cache](http://appcachefacts.info/). +If you have a requirement to reload your application or restart the browser while offline then you will need to use the [application cache](http://appcachefacts.info/). Some developers also use application caches to speed up page reload performance. For example, Google uses an application cache when load their main web page. -The application cache will allow you to store any file that is required for offline use. The list includes html files, JavaScript libraries, CSS and images. Any file that your application requires to run normally will have to be referenced in the application cache. +The application cache will allow you to store any file that is required for offline use. The list includes html files, JavaScript libraries, CSS and images. Any file that your application requires to run normally will have to be referenced in the application cache. + +Once an application is stored in the application cache it will be available the next time an application restarts. + +## Using AppCaches with your ArcGIS web app + +**Step 1** Make sure you are using an optimized build of the ArcGIS API for JavaScript. You can create an optimized build at [http://jso.arcgis.com/](http://jso.arcgis.com/). This will create a single file that contains all the necessary modules for your app. There are options to host the build via CDN or locally. Either approach will work. + +NOTE: You cannot use the regular CDN for the ArcGIS API for JavaScript because the URL contains a redirect. Redirects are not allowed in an application cache and it will fail to load. + +**Step 2** Create the application cache file. We have a [Grunt.js](http://gruntjs.com/) task included in the /samples directory to assist with this step. You will need to make some adjustments to the package.json file. It acts as the configuration file for the Grunt task. + +**Step 3** Reference the application cache file from within your application. Here's an example of the syntax: + +```html + + +``` + +**Step 4** Be sure to include and use the `/utils/appCacheManager.js` library as a module in your application. This will enable you to monitor what's going on in the application cache and capture specific events. Here is a psuedo code example of how to instantiate it: + +```js + + appCacheManager = new AppCacheManager(true,true); + appCacheManager.on(appCacheManager.CACHE_EVENT,cacheEventHandler); + appCacheManager.on(appCacheManager.CACHE_ERROR,cacheErrorHandler); + appCacheManager.on(appCacheManager.CACHE_LOADED,cacheLoadedHandler); + +``` + +In the `/samples` directory there are two examples, `appcache-features.html` and `appcache-tiles.html` that demonstrate how to use tiles, features and the appCacheManager with the application cache. ###Configuring your web server -Your web server must be able to serve up the MIME TYPE `TEXT/cache-manifest`. +Your web server must be able to serve up the MIME TYPE `TEXT/cache-manifest`. If this is missing there's a really good chance that the application cache file won't be served up to your app. + +### Clearing the application cache in a browser + +When you do testing with an application cache, any time you make a change to your application HTML, CSS or JS you will need to delete the existing application cache. Otherwise, any changes you make will not be reflected in the app. + +**Simply deleting your web cache the normal way won't clear an application cache!** + +In Chrome you can navigate to chrome://appcache-internals/ then select the appropriate cache and delete it. If you are testing on an Android device you can remotely debug from your laptop's Chrome instance. + +In Safari iPhone and iPad go to settings and select "Clear Cookies and Data." + +If you want to test on Firefox then try Tools > Options > Advanced > Network > Offline data > Clear Now. More info is available [here](https://developer.mozilla.org/en-US/docs/Web/HTML/Using_the_application_cache#Storage_location_and_clearing_the_offline_cache). + +As for IE, this library doesn't currently support any versions. + +### Where to place the file + +The application cache file can live anywhere in your web directory. It's common to see it to be placed in the root. ###Support Most modern browsers support application cache including IE v10 and v11, Firefox v28+, Chrome v33+, Safari v7+, iOS Safari v3.2+, and Android browser 2.1+. For more detailed info refer to [caniuse.com](http://caniuse.com/#search=appcache). From b6ffc9f87957fed5df471ecabfc5975545ec8d58 Mon Sep 17 00:00:00 2001 From: Andy Gup Date: Wed, 11 Jun 2014 14:33:48 -0600 Subject: [PATCH 139/139] updated offlineTileEnabler api doc --- doc/offlinetilesenabler.md | 62 ++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/doc/offlinetilesenabler.md b/doc/offlinetilesenabler.md index d59d815..e417cc3 100644 --- a/doc/offlinetilesenabler.md +++ b/doc/offlinetilesenabler.md @@ -1,30 +1,25 @@ API Doc for offlineTilesEnabler =============================== +There are two different libraries for taking tiles offline: offlineTilesEnabler.js and OfflineTilesEnablerLayer.js. The first one, offlineTilesEnabler.js, is for use with ArcGIS.com web maps and partial offline scenario. You won't be able to restart or reload your app when using this library. + +If you have a requirement to allow restarting or reloading then you should use OfflineTilesEnablerLayer.js. The OfflineTilesEnablerLayer.js library lets you create a custom basemap layer that extends TiledMapServiceLayer. To view the docs for this library scroll down on this page. + ##offlineTilesEnabler -Extends and overrides a tiled map service. Provides the ability to customize the extent used to cut the tiles. See the detailed description of basemap.prepareForOffline() in the "How To Use" section below to learn different options. +Extends and overrides a tiled map service. For use with ArcGIS.com maps or partial-offline situations that don't require a browser restart or reload. + +Provides the ability to customize the extent used to cut the tiles. See the detailed description of basemap.prepareForOffline() in the "How To Use" section below to learn different options. ###Constructor Constructor | Description --- | --- -`OfflineTilesEnabler()` | Creates an instance of the offlineTilesEnabler class. This library allows you to extend an ArcGISTiledMapServiceLayer with offline capability as well as manage the online/offline resynchronization process. +`OfflineTilesEnabler()` | Creates an instance of the offlineTilesEnabler class. This library allows you to extend an ArcGISTiledMapServiceLayer with partial offline capability as well as manage the online/offline resynchronization process. ###Methods Methods | Returns | Description --- | --- | --- `extend(layer, callback)`|`callback(boolean, string)` |Overrides an ArcGISTiledMapServiceLayer. Callback is called after indexedDb store is initialized and informs the application whether it is indexedDb is supported or not. - -###Properties -Property | Description ---- | --- -`layer.offline.proxyPath`| For CORS enabled servers this can be set to `null`. The default is to use the internal resource-proxy path: `libs/offline-editor-js/resource-proxy/proxy.php.` Don't forget to check your proxy configuration to allow connections for all possible services that you might be using. More information on using proxies with ArcGIS can be found here: [https://developers.arcgis.com/javascript/jshelp/ags_proxy.html](https://developers.arcgis.com/javascript/jshelp/ags_proxy.html). - -###ArcGISTiledMapServiceLayer Overrides - -Methods | Returns | Description ---- | --- | --- -`getTileUrl(level, row, col)` | Url | Use the tile url's level, row and column. Retrieves tiles as requested by the ArcGIS API for JavaScript. If a tile is in cache it is returned. If it is not in cache then one is retrieved over the internet. `goOffline()` | nothing | This method puts the layer in offline mode. When in offline mode, the layer will not fetch any tile from the remote server. It will look up the tiles in the indexed db database and display them in the layer. If the tile can't be found in the local database it will show up blank (even if there is actual connectivity). The pair of methods `goOffline()` and `goOnline() `allows the developer to manually control the behaviour of the layer. Used in conjunction with the offline dectection library, you can put the layer in the appropriate mode when the offline condition changes. `goOnline()` | nothing | This method puts the layer in online mode. When in online mode, the layer will behave as regular layers, fetching all tiles from the remote server. If there is no internet connectivity the tiles may appear thanks to the browsers cache, but no attempt will be made to look up tiles in the local database. `getLevelEstimation(extent,` `level, tileSize)` | {level, tileCount, sizeBytes} | Returns an object that contains the number of tiles that would need to be downloaded for the specified extent and zoom level, and the estimated byte size of such tiles. This method is useful to give the user an indication of the required time and space before launching the actual download operation. The byte size estimation is very rough. @@ -38,3 +33,44 @@ Methods | Returns | Description `estimateTileSize(callback)` | `callback(number)` | Retrieves one tile from a layer and then returns its size. `prepareForOffline(` `minLevel, maxLevel, extent, ` `reportProgress)` | `callback(number)` | Retrieves tiles and stores them in the local cache. See the "How To Use" section below to learn more about customizing the use of this method. +###Properties +Property | Description +--- | --- +`layer.offline.proxyPath`| For CORS enabled servers this can be set to `null`. The default is to use the internal resource-proxy path: `libs/offline-editor-js/resource-proxy/proxy.php.` Don't forget to check your proxy configuration to allow connections for all possible services that you might be using. More information on using proxies with ArcGIS can be found here: [https://developers.arcgis.com/javascript/jshelp/ags_proxy.html](https://developers.arcgis.com/javascript/jshelp/ags_proxy.html). + + + +##OfflineTilesEnablerLayer +Extends and overrides a tiled map service. This library creates a custom tiled map layer. It can be used in situations where a browser restart or reload is required. + +###Constructor +Constructor | Description +--- | --- +`OfflineTilesEnablerLayer(url,callback,state)` | Creates an instance of the offlineTilesEnabler class. This library allows you to extend an ArcGISTiledMapServiceLayer with offline capability as well as manage the online/offline resynchronization process. Any Esri basemap REST endpoint should work. The state property is a boolean for specifying if the application is intializing the layer online (true) or offline (false). When you first load the map you should set this property to `true`. + + +###Methods +Methods | Returns | Description +--- | --- | --- +`goOffline()` | nothing | This method puts the layer in offline mode. When in offline mode, the layer will not fetch any tile from the remote server. It will look up the tiles in the indexed db database and display them in the layer. If the tile can't be found in the local database it will show up blank (even if there is actual connectivity). The pair of methods `goOffline()` and `goOnline() `allows the developer to manually control the behaviour of the layer. Used in conjunction with the offline dectection library, you can put the layer in the appropriate mode when the offline condition changes. +`goOnline()` | nothing | This method puts the layer in online mode. When in online mode, the layer will behave as regular layers, fetching all tiles from the remote server. If there is no internet connectivity the tiles may appear thanks to the browsers cache, but no attempt will be made to look up tiles in the local database. +`getLevelEstimation(extent,` `level, tileSize)` | {level, tileCount, sizeBytes} | Returns an object that contains the number of tiles that would need to be downloaded for the specified extent and zoom level, and the estimated byte size of such tiles. This method is useful to give the user an indication of the required time and space before launching the actual download operation. The byte size estimation is very rough. +`getExtentBuffer(buffer,extent)`| Extent | Returns a new extent buffered by a given measurement that's based on map units. For example, if you are using mercator map projection then the buffer property would be in meters and the new extent would be returned in mercactor. +`getTileUrlsByExtent(extent, level)` | Array | Returns an array of tile urls within a given map extent and zoom level. +`deleteAllTiles(callback)` | `callback(boolean, errors)` | Clears the local cache of tiles. +`getOfflineUsage(callback)` | `callback(size, error)` | Gets the size in bytes of the local tile cache. +`getTilePolygons(callback)` | `callback(polygon, error)` | Gets polygons representing all cached tiles. This is helpful to give users a visual feedback of the current content of the tile cache. +`saveToFile(filename, callback)` | `callback( boolean, error)` | Saves tile cache into a portable csv format. +`loadFromFile(filename, callback)` | `callback( boolean, error)` | Reads a csv file into local tile cache. +`estimateTileSize(callback)` | `callback(number)` | Retrieves one tile from a layer and then returns its size. +`prepareForOffline(` `minLevel, maxLevel, extent, ` `reportProgress)` | `callback(number)` | Retrieves tiles and stores them in the local cache. See the "How To Use" section below to learn more about customizing the use of this method. +`getMaxZoom(callback)` | `callback(number)` | Returns the maximum zoom level of the layer. +`getMinZoom(callback)` | `callback(number)` | Returns the minimum zoom level of the layer. + + +###Properties +Property | Description +--- | --- +`layer.offline.proxyPath`| For CORS enabled servers this can be set to `null`. The default is to use the internal resource-proxy path: `libs/offline-editor-js/resource-proxy/proxy.php.` Don't forget to check your proxy configuration to allow connections for all possible services that you might be using. More information on using proxies with ArcGIS can be found here: [https://developers.arcgis.com/javascript/jshelp/ags_proxy.html](https://developers.arcgis.com/javascript/jshelp/ags_proxy.html). + +