Merge pull request #260 from andygup/gh-pages

v2.3 gh-pages
This commit is contained in:
Andy 2014-10-13 15:43:19 -06:00
commit 945741c3e0
46 changed files with 9395 additions and 1402 deletions

View File

@ -1,5 +1,22 @@
# offline-editor-js - Changelog
## Version 2.3 - Oct 13, 2014
- Closes #74 - Build sample with nice UX for editing
- Closes #257 - Build getting started pages for AGOL, editing and TPK. All samples show basic functionality and are responsive. Also integrated a new launch page for the API and How To Use docs.
- Closes #258 - Convert modal popup to widget
- The following samples were updated to be responsive:
- appcache-features.html
- appcache-tiles.html
- tpk-layer.html
New functionality:
- Closes #256 - Add getMaxZoom and getMinZoom to offlineTilesEnabler
- Added getMinMaxLOD() to offlineTilesEnabler and OfflineTilesEnablerLayer
Breaking Changes - None.
## Version 2.2.1 - Oct 1, 2014
Added a Getting Started for Tiles tutorial.

View File

@ -3,17 +3,17 @@ offline-editor-js
Offline-editor-js is a set of JavaScript libraries for using the ArcGIS API for JavaScript offline. It offers both lightweight editing and tile management capabilities while offline or intermittently offline. It's a work-in-progress so if you have suggestions open an issue or if you want to make a pull request we welcome your proposed modifications.
Online samples and tutorials are available here: [http://esri.github.io/offline-editor-js/demo/](http://esri.github.io/offline-editor-js/demo/)
Online samples and getting started tutorials are available here: **[http://esri.github.io/offline-editor-js/demo/](http://esri.github.io/offline-editor-js/demo/)**
*IMPORTANT:* If you need a fully integrated robust offline solution then you should be using our ArcGIS Runtime SDKs for .NET, WPF, Java, iOS, Android and Qt.
This repo contains the following libraries:
- `/dist`:
* `offline-edit-min.js` - _(replaces v1.x of OfflineFeaturesManager.js)_ stores adds, updates and deletes of features as well as limited attachment support while offline. Resync's edits with server once connection is reestablished.
* `offline-tiles-basic-min.js` - _(replaces v1.x of offlineTilesEnabler.js)_ caches map tiles for partial offline use cases. Use this library with ArcGIS Online Web maps as well as with tiled map services. This repo will not work with browser restarts or reloads while offline.
* `offline-tiles-advanced-min.js` - _(replaces v1.x of OfflineTilesEnablerLayer.js)_ Extends any ArcGIS Tiled Map Service that has a requirement for offline browser reload and/or restart. This library should be used in conjunction with an HTML5 application cache coding pattern.
* `offline-tpk-min.js` - _(replaces v1.x of TPKLayer.js)_ parses a TPK file and displays it as a tiled map layer.
* `offline-edit-min.js` - stores adds, updates and deletes of features as well as limited attachment support while offline. Resync's edits with server once connection is reestablished.
* `offline-tiles-basic-min.js` - caches map tiles for partial offline use cases. Use this library with ArcGIS Online Web maps as well as with tiled map services. This repo will not work with browser restarts or reloads while offline.
* `offline-tiles-advanced-min.js` - Extends any ArcGIS Tiled Map Service that has a requirement for offline browser reload and/or restart. This library should be used in conjunction with an HTML5 application cache coding pattern.
* `offline-tpk-min.js` - parses a TPK file and displays it as a tiled map layer.
- `/utils`: contains various helper library modules. These modules are all AMD compliant.
- `/samples`: samples that show how to use the different offline libraries capabilities.
@ -33,31 +33,9 @@ Using an [application manifest](https://developer.mozilla.org/en-US/docs/HTML/Us
__Attachment Support__: Attachments are supported with some limitations. See documentation [here](./doc/attachments.md)
#API Doc
#API and How To Use Docs
##Offline Editing of Geographic Features
Extends and overrides an ArcGIS Feature Layer. This library allows you to extend esri.layers.FeatureLayer with offline capabilities and to manage the resync process.
* __Click [here](doc/offlinefeaturesmanager.md) to see the full API doc for `offline-edit-min.js`__
##Offline Mapping Tiles
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 `offline-tiles-basic-min.js and offline-tiles-advanced-min.js`__
##TPKLayer
You can display TPK files with this library. TPK's are binary tile package files. Extends TileMapServiceLayer. Go [here](http://resources.arcgis.com/en/help/main/10.1/index.html#//00170000017w000000) for more information on how to create a TPK file.
* __Click [here](doc/tpklayer.md) to see the full API doc for `offline-tpk-min.js`__
##How to use
* [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 about using an application cache with this library](doc/howtouseappcache.md)
Go __[here](demo/api-doc.html)__ to get links to the API docs and How to use docs.
## Migrating from v1 to v2
@ -76,18 +54,6 @@ If you are migrating your v1 code to v2 then go [here](doc/migratefromv1tov2.md)
1. From the root directory run `npm install`
2. Run `Grunt build`. If there are no errors, the minimized _(min)_ and source _(src)_ versions of the libraries will be output to `\dist`
##Samples
* `appcache-features.html` - shows how to work with the application manifest, tiles and features. This sample works with browser reloads and restarts.
* `appcache-tiles.html` - shows how to work with the application manifest and map tiles. This sample works with browser reloads and restarts.
* `attachments-editor.html` - demonstrates how to work with this library using feature attachments.
* `draw-pointlinepoly-offline.html` shows working with points, lines and polygons locally.
* `tpklayer.html` - shows how to work with TPK files.
* `tiles-indexed-db.html` - shows how to work with storing tiles locally.
* `Gruntfile.js` - a node.js app and its associated `package.json` file to help with creating an application manifest file.
##Dependencies
* ArcGIS API for JavaScript (v3.8+)

167
demo/api-doc.html Normal file
View File

@ -0,0 +1,167 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!--<link rel="shortcut icon" href="../images/favicon.ico">-->
<title>Offline-editor-js</title>
<!-- Bootstrap core CSS -->
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="http://js.arcgis.com/3.10/js/esri/css/esri.css">
<link rel="stylesheet" type="text/css" href="http://esri.github.io/bootstrap-map-js/src/css/bootstrapmap.css">
<!-- Custom styles for this template -->
<link href="css/style.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<style>
#mapDiv {
min-height: 300px;
max-height: 1000px;
}
pre {
overflow: auto;
word-wrap: normal;
white-space: pre;
font-family: Courier,"Courier New";
font-size: 13px;
background-color: #fee9cc;
}
pre.prettyprint {
border: 1px solid #cccccc !important;
}
#img-offline-indicator {
padding: 8px;
position: relative; float: right;
}
</style>
</head>
<body>
<a class="hidden-xs" href="https://github.com/Esri/offline-editor-js">
<img style="position: absolute; top: 50; right: 0; border: 0; width:150px;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_green_007200.png" alt="Fork me on GitHub">
</a>
<header id="header"></header>
<!-- Main jumbotron for a primary marketing message or call to action -->
<div class="jumbotron">
<div class="container">
<h1>API Docs</h1>
<p>Documentation for the <i>offline-editor-js</i> JavaScript libraries.</p>
</div>
</div>
<div class="container">
<!-- Example row of columns -->
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12">
<div class="panel panel-default">
<div class="panel-heading">
<h3>Offline Tiles - Basic</h3>
<p>The <i>offline-tiles-basic-min.js</i> library is for use with ArcGIS.com web maps and partial/intermittently offline use cases.
You won't be able to restart or reload your app when using this library offline.
</p>
</div>
<div class="panel-body">
<ul>
<li>
<a href="../doc/offlinetilesenabler.md">O.esri.Tiles.OfflineTilesEnabler</a>
</li>
<li>
<a href="../doc/howtousetiles.md">How to use.</a>
</li>
</ul>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h3>Offline Tiles - Advanced</h3>
<p>The <i>offline-tiles-advanced-min.js</i> library is for use with tiled map services in partial or fully offline use cases.
If you have a requirement to reload or restart your app while offline you should use this library.
</p>
</div>
<div class="panel-body">
<ul>
<li>
<a href="../doc/offlinetilesenablerlayer.md">O.esri.Tiles.OfflineTilesEnablerLayer</a>
</li>
<li>
<a href="../doc/howtousetiles.md">How to use.</a>
</li>
</ul>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h3>Offline Features</h3>
<p>The <i>offline-edit-min.js</i> library is for working with ArcGIS JS API points, lines and polygons in partial or fully offline use cases.
</p>
</div>
<div class="panel-body">
<ul>
<li>
<a href="../doc/offlinefeaturesmanager.md">O.esri.Edit.OfflineFeaturesManager</a>
</li>
<li>
<a href="../doc/howtouseeditlibrary.md">How to use.</a>
</li>
</ul>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h3>Offline TPK</h3>
<p>The <i>offline-tpk-min.js</i> library is for working with TPK files in partial or fully offline use cases.
TPK files are binary tile image packages. They can be used stand-alone or alongside tiled base maps.
</p>
</div>
<div class="panel-body">
<ul>
<li>
<a href="../doc/tpklayer.md">O.esri.TPK.TPKLayer</a>
</li>
<li>
<a href="../doc/howtousetpklibrary.md">How to use.</a>
</li>
</ul>
</div>
</div>
</div><!-- class="col-sm-12 col-md-12 col-lg-12" -->
<hr>
</div> <!-- /container -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
$("#header").load("../demo/header.html");
});
</script>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<!-- add syntax highlighting to code snippts -->
<script src="https://google-code-prettify.googlecode.com/svn/loader/run_prettify.js"></script>
</body>
</html>

862
demo/getstarted-agol.html Normal file
View File

@ -0,0 +1,862 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!--<link rel="shortcut icon" href="../images/favicon.ico">-->
<title>Offline-editor-js</title>
<!-- Bootstrap core CSS -->
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="http://js.arcgis.com/3.11/esri/css/esri.css"">
<link rel="stylesheet" type="text/css" href="http://esri.github.io/bootstrap-map-js/src/css/bootstrapmap.css">
<!-- Custom styles for this template -->
<link href="css/style.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<style>
#mapDiv {
min-height: 300px;
max-height: 1000px;
}
pre {
overflow: auto;
word-wrap: normal;
white-space: pre;
font-family: Courier,"Courier New";
font-size: 13px;
background-color: #fee9cc;
}
pre.prettyprint {
border: 1px solid #cccccc !important;
}
.floatRight {float: right;}
</style>
</head>
<body>
<a class="hidden-xs" href="https://github.com/Esri/offline-editor-js">
<img style="position: absolute; top: 50; right: 0; border: 0; width:150px;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_green_007200.png" alt="Fork me on GitHub">
</a>
<header id="header"></header>
<!-- Main jumbotron for a primary marketing message or call to action -->
<div class="jumbotron">
<div class="container">
<h1>Getting Started with ArcGIS.com</h1>
<p>Basic steps for working with <b>ArcGIS.com base maps</b> for offline.</p>
<!--<p><a class="btn btn-primary btn-lg" role="button">Samples &raquo;</a></p>-->
</div>
</div>
<div class="container">
<!-- Example row of columns -->
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12">
<ul class="nav nav-pills">
<li class="active"><a href="#Step1" data-toggle="tab">Step 1</a></li>
<li><a href="#Step2" data-toggle="tab">Step 2</a></li>
<li><a href="#Step3" data-toggle="tab">Step 3</a></li>
</ul>
<div class="tab-content well">
<div class="tab-pane active" id="Step1">
<h3>Step 1: Fill in the basics</h3>
<p>Add the basic library references. Then test to make sure map loads.</p>
<br>
<pre class="prettyprint">
<code>
&lt;!DOCTYPE html>
&lt;html>
&lt;head>
&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8">
&lt;meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
&lt;title>Offline ArcGIS.com&lt;/title>
&lt;!-- Bootstrap core CSS -->
&lt;link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
&lt;link rel="stylesheet" href="http://js.arcgis.com/3.11/esri/css/esri.css"">
&lt;link rel="stylesheet" type="text/css" href="http://esri.github.io/bootstrap-map-js/src/css/bootstrapmap.css">
&lt;style>
#mapDiv {
min-height: 500px;
max-height: 1000px;
}
body {
background-color: #ffffff;
overflow: hidden;
font-family: "Trebuchet MS";
}
.floatRight {float: right;}
.container { padding: 20px;}
&lt;/style>
&lt;!-- Include a reference to offline.js which detects online/offline conditions -->
&lt;script src="../vendor/offline/offline.min.js">&lt;/script>
&lt;script>
// Set the online/offline detection options.
// More info at: http://github.hubspot.com/offline/docs/welcome/
Offline.options = {
checks: {
image: {
url: function() {
return 'http://esri.github.io/offline-editor-js/tiny-image.png?_=' +
(Math.floor(Math.random() * 1000000000));
}
},
active: 'image'
}
}
&lt;/script>
&lt;!-- Include a reference to IndexedDBShim for library to work on Safari 7.x -->
&lt;script src="../vendor/IndexedDBShim/dist/IndexedDBShim.js">&lt;/script>
&lt;script src="http://js.arcgis.com/3.11/">&lt;/script>
&lt;/head>
&lt;body>
&lt;div class="container">
&lt;div class="row">
&lt;div class="col-xs-12">
&lt;div id="mapDiv">&lt;/div>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;script>
// Make sure to reference the tiles library within the require statement!
require([
"esri/map",
"dojo/on",
"esri/arcgis/utils",
"//esri.github.com/bootstrap-map-js/src/js/bootstrapmap.js",
"../dist/offline-tiles-basic-src.js",
"dojo/domReady!"],
function(Map,on,arcgisUtils,BootstrapMap) {
var map;
// Load the map
arcgisUtils.createMap("bbc1a04a3eca4430be144d7a08b43a17","mapDiv").then(function(response){
var map = response.map;
map = response.map;
// Initialize BootstrapMap to make the map responsive
BootstrapMap.create(map);
});
});
&lt;/script>
&lt;!-- Bootstrap core JavaScript
================================================== -->
&lt;!-- Placed at the end of the document so the pages load faster -->
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">&lt;/script>
&lt;script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js">&lt;/script>
&lt;/body>
&lt;/html>
</code>
</pre>
<div class="alert alert-info">NOTE: Replace paths with your references. Or build your app in the /demo directory</div>
</div>
<div class="tab-pane" id="Step2">
<h3>Step 2: Extend basemap using the offline library</h3>
<p>This initializes the OfflineTilesEnabler library and tells it which tiled map service layer to use for offline. Test to make sure map loads.</p>
<br>
<pre class="prettyprint">
<code>
&lt;!DOCTYPE html>
&lt;html>
&lt;head>
&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8">
&lt;meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
&lt;title>Offline ArcGIS.com&lt;/title>
&lt;!-- Bootstrap core CSS -->
&lt;link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
&lt;link rel="stylesheet" href="http://js.arcgis.com/3.11/esri/css/esri.css">
&lt;link rel="stylesheet" type="text/css" href="http://esri.github.io/bootstrap-map-js/src/css/bootstrapmap.css">
&lt;style>
html, body, #map {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
body {
background-color: #000000;
overflow: hidden;
font-family: "Trebuchet MS";
}
.floatRight {float: right;}
.container { padding: 20px;}
&lt;/style>
&lt;!-- Include a reference to offline.js which detects online/offline conditions -->
&lt;script src="../vendor/offline/offline.min.js">&lt;/script>
&lt;script>
// Set the online/offline detection options.
// More info at: http://github.hubspot.com/offline/docs/welcome/
Offline.options = {
checks: {
image: {
url: function() {
return 'http://esri.github.io/offline-editor-js/tiny-image.png?_=' +
(Math.floor(Math.random() * 1000000000));
}
},
active: 'image'
}
}
&lt;/script>
&lt;!-- Include a reference to IndexedDBShim for library to work on Safari 7.x -->
&lt;script src="../vendor/IndexedDBShim/dist/IndexedDBShim.js">&lt;/script>
&lt;script src="http://js.arcgis.com/3.11/">&lt;/script>
&lt;/head>
&lt;body>
&lt;div class="row">
&lt;div class="col-xs-12">
&lt;div id="mapDiv">&lt;/div>
&lt;/div>
&lt;/div>
&lt;script>
// Make sure to reference the tiles library within the require statement!
require([
"esri/map",
"dojo/on",
"esri/arcgis/utils",
"//esri.github.com/bootstrap-map-js/src/js/bootstrapmap.js",
"../dist/offline-tiles-basic-src.js",
"dojo/domReady!"],
function(Map,on,arcgisUtils,BootstrapMap) {
var map, basemapLayer;
var offlineTilesEnabler = new O.esri.Tiles.OfflineTilesEnabler();
showMap();
function showMap(){
// Load the map
arcgisUtils.createMap("bbc1a04a3eca4430be144d7a08b43a17","mapDiv").then(function(response){
map = response.map;
// Initialize BootstrapMap to make the map responsive
BootstrapMap.create(map);
// Get the ArcGIS.com basemap that we want to use offline.
// And then extend it for offline use.
if(map.loaded)
{
basemapLayer = map.getLayer( map.layerIds[0] );
initializeOfflineTiles();
}
else
{
map.on("load",function()
{
basemapLayer = map.getLayer( map.layerIds[0] );
initializeOfflineTiles();
});
}
});
}
function initializeOfflineTiles(){
offlineTilesEnabler.extend(basemapLayer,function(success) {
if (success) {
console.log("ArcGIS.com map extended for offline!")
}
})
}
});
&lt;/script>
&lt;!-- Bootstrap core JavaScript
================================================== -->
&lt;!-- Placed at the end of the document so the pages load faster -->
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">&lt;/script>
&lt;script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js">&lt;/script>
&lt;/body>
&lt;/html>
</code>
</pre>
<div class="alert alert-info">NOTE: Replace paths with your references. Or build your app in the /demo directory</div>
</div>
<div class="tab-pane" id="Step3">
<h3>Step 3: Configure tiles download.</h3>
<p>Enable the ability to download tiles as well the ability to toggle online and offline.</p>
<br>
<ul id="myTab" class="nav nav-tabs">
<li class="active"><a href="#code" data-toggle="tab">Code</a></li>
<li class=""><a href="#mapTab" data-toggle="tab">Map</a></li>
</ul>
</br>
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade in active" id="code">
<pre class="prettyprint">
<code>
&lt;!DOCTYPE html>
&lt;html>
&lt;head>
&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8">
&lt;meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
&lt;title>Offline ArcGIS.com&lt;/title>
&lt;!-- Bootstrap core CSS -->
&lt;link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
&lt;link rel="stylesheet" href="http://js.arcgis.com/3.11/esri/css/esri.css">
&lt;link rel="stylesheet" type="text/css" href="http://esri.github.io/bootstrap-map-js/src/css/bootstrapmap.css">
&lt;style>
#mapDiv {
min-height: 500px;
max-height: 1000px;
}
body {
background-color: #ffffff;
overflow: hidden;
font-family: "Trebuchet MS";
}
.floatRight {float: right;}
.container { padding: 20px;}
&lt;/style>
&lt;!-- Include a reference to offline.js which detects online/offline conditions -->
&lt;script src="../vendor/offline/offline.min.js">&lt;/script>
&lt;script>
// Set the online/offline detection options.
// More info at: http://github.hubspot.com/offline/docs/welcome/
Offline.options = {
checks: {
image: {
url: function() {
return 'http://esri.github.io/offline-editor-js/tiny-image.png?_=' +
(Math.floor(Math.random() * 1000000000));
}
},
active: 'image'
}
}
&lt;/script>
&lt;!-- Include a reference to IndexedDBShim for library to work on Safari 7.x -->
&lt;script src="../vendor/IndexedDBShim/dist/IndexedDBShim.js">&lt;/script>
&lt;script src="http://js.arcgis.com/3.11/">&lt;/script>
&lt;/head>
&lt;body>
&lt;div class="container">
&lt;div class="row">
&lt;div class="col-xs-10">
&lt;div class="form form-group btn-group" data-toggle="buttons">
&lt;button class="btn btn-success" id="btn-get-tiles">1. Download Tiles&lt;/button>
&lt;button class="btn btn-success" disabled id="btn-online-offline">2. Go Offline&lt;/button>
&lt;button class="btn btn-success" disabled id="btn-pan-left">3. Pan left&lt;/button>
&lt;/div>
&lt;/div>
&lt;div class="col-xs-2">
&lt;!-- this indicates whether app is offline (down) or online (up) -->
&lt;button id="btn-state" class="btn btn-success btn-large floatRight">
&lt;span id="state-span" class="glyphicon glyphicon-link"> Up&lt;/span>
&lt;/button>
&lt;/div>
&lt;/div>
&lt;div class="row">
&lt;div class="col-xs-12">
&lt;div id="mapDiv">&lt;/div>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;script>
// Make sure to reference the tiles library within the require statement!
require([
"esri/map",
"dojo/on",
"esri/arcgis/utils",
"//esri.github.com/bootstrap-map-js/src/js/bootstrapmap.js",
"../dist/offline-tiles-basic-src.js",
"dojo/domReady!"],
function(Map,on,arcgisUtils,BootstrapMap) {
var map, basemapLayer;
var offlineTilesEnabler = new O.esri.Tiles.OfflineTilesEnabler();
// Check if browser state is online or offline
Offline.check();
Offline.on('up down', updateState );
// For cancelling the download of tiles
var _wantToCancel;
var _downloadState = "downloaded";
// Set up min and max boundaries for retrieving tiles
var minZoomAdjust = -1, maxZoomAdjust = 1, mMinZoom, mMaxZoom;
// Set up button click listeners.
var btnGetTiles = document.getElementById("btn-get-tiles");
var btnOnlineOffline = document.getElementById("btn-online-offline");
var btnPanLeft = document.getElementById("btn-pan-left");
var imgOfflineIndicator = document.getElementById("state-span");
var btnState = document.getElementById("btn-state");
on(btnGetTiles,"click",downloadTiles);
on(btnOnlineOffline,"click",goOnlineOffline);
on(btnPanLeft,"click",panLeft);
showMap();
function showMap(){
// Load the map
arcgisUtils.createMap("bbc1a04a3eca4430be144d7a08b43a17","mapDiv").then(function(response){
map = response.map;
// Initialize BootstrapMap to make the map responsive
BootstrapMap.create(map);
// Get the ArcGIS.com basemap that we want to use offline.
// And then extend it for offline use.
if(map.loaded)
{
basemapLayer = map.getLayer( map.layerIds[0] );
initializeOfflineTiles();
}
else
{
map.on("load",function()
{
basemapLayer = map.getLayer( map.layerIds[0] );
initializeOfflineTiles();
});
}
});
}
function initializeOfflineTiles(){
offlineTilesEnabler.extend(basemapLayer,function(success) {
if (success) {
console.log("ArcGIS.com map extended for offline!")
}
})
}
function downloadTiles(){
if(_downloadState == "downloading"){
_wantToCancel = true;
}
else{
_wantToCancel = false;
// First delete any existing tiles from database
basemapLayer.deleteAllTiles(function(success,err){
var zoom = basemapLayer.getMinMaxLOD(minZoomAdjust,maxZoomAdjust);
// Now download tiles
basemapLayer.prepareForOffline(zoom.min, zoom.max, map.extent, function(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 )
{
alert("Tile download was cancelled");
_downloadState = "cancelled";
}
else
{
alert("Tile download complete");
_downloadState = "downloaded";
btnOnlineOffline.disabled = false;
}
btnGetTiles.innerHTML = '1. Download Tiles';
}
return _wantToCancel; //determines if a cancel request has been issued
});
_downloadState = "downloading";
});
}
}
// Force the tileLayer between online and offline
function goOnlineOffline(){
btnPanLeft.disabled = false;
if(btnOnlineOffline.innerHTML == "2. Go Offline"){
toggleStateUp(false);
console.log("Map is offline");
}
else{
toggleStateUp(true);
console.log("Map is online");
}
}
function toggleStateUp(state){
if(state){
btnOnlineOffline.innerHTML = "2. Go Offline";
basemapLayer.goOnline();
imgOfflineIndicator.className = "glyphicon glyphicon-link";
imgOfflineIndicator.innerHTML = " Up";
btnState.className = "btn btn-success btn-large floatRight";
}
else{
btnOnlineOffline.innerHTML = "2. Go Online";
basemapLayer.goOffline();
imgOfflineIndicator.className = "glyphicon glyphicon-thumbs-down";
imgOfflineIndicator.innerHTML = " Down";
btnState.className = "btn btn-danger btn-large floatRight";
}
}
// Set the ArcGIS.com map online or offline.
// When set offline it will look for tiles in the tiles database
function updateState(){
if(Offline.state === 'up'){
if(typeof basemapLayer != "undefined") basemapLayer.goOnline();
toggleStateUp(true);
}
else{
if(typeof basemapLayer != "undefined") basemapLayer.goOffline();
toggleStateUp(false);
}
}
// Pan left when "offline" to view only tiles that have been stored locally
function panLeft(){
map.panLeft();
}
});
&lt;/script>
&lt;!-- Bootstrap core JavaScript
================================================== -->
&lt;!-- Placed at the end of the document so the pages load faster -->
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">&lt;/script>
&lt;script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js">&lt;/script>
&lt;/body>
&lt;/html>
</code>
</pre>
<div class="alert alert-info">NOTE: Replace paths with your references. Or build your app in the /demo directory</div>
</div>
<div class="tab-pane fade in" id="mapTab">
<div class="row">
<div class="col-xs-10">
<div class="form form-group btn-group" data-toggle="buttons">
<button class="btn btn-success" id="btn-get-tiles">1. Download Tiles</button>
<button class="btn btn-success" disabled id="btn-online-offline">2. Go Offline</button>
<button class="btn btn-success" disabled id="btn-pan-left">3. Pan left</button>
</div>
</div>
<div class="col-xs-2">
<!-- this indicates whether app is offline (down) or online (up) -->
<button id="btn-state" class="btn btn-success btn-large floatRight">
<span id="state-span" class="glyphicon glyphicon-link"> Up</span>
</button>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div id="mapDiv"></div>
</div>
</div>
</div>
</div><!-- id="code" -->
</div><!-- id="myTabContent" -->
</div><!-- id="step4" -->
</br>
</div><!-- class="tab-content well" -->
</div><!-- class="col-sm-12 col-md-12 col-lg-12" -->
<hr>
</div> <!-- /container -->
<!-- mapping code -->
<script src="../vendor/offline/offline.min.js"></script>
<script>
// Set the online/offline detection options.
// More info at: http://github.hubspot.com/offline/docs/welcome/
Offline.options = {
checks: {
image: {
url: function() {
return 'http://esri.github.io/offline-editor-js/tiny-image.png?_=' +
(Math.floor(Math.random() * 1000000000));
}
},
active: 'image'
}
}
</script>
<!-- Include a reference to IndexedDBShim for library to work on Safari 7.x -->
<script src="../vendor/IndexedDBShim/dist/IndexedDBShim.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://js.arcgis.com/3.11/"></script>
<script>
$(document).ready(function() {
$("#header").load("../demo/header.html");
});
// Make sure to reference the tiles library within the require statement!
require([
"esri/map",
"dojo/on",
"esri/arcgis/utils",
"//esri.github.com/bootstrap-map-js/src/js/bootstrapmap.js",
"../dist/offline-tiles-basic-src.js",
"dojo/domReady!"],
function(Map,on,arcgisUtils,BootstrapMap) {
var map, basemapLayer;
var offlineTilesEnabler = new O.esri.Tiles.OfflineTilesEnabler();
// Check if browser state is online or offline
Offline.check();
Offline.on('up down', updateState );
// For cancelling the download of tiles
var _wantToCancel;
var _downloadState = "downloaded";
// Set up min and max boundaries for retrieving tiles
var minZoomAdjust = -1, maxZoomAdjust = 1, mMinZoom, mMaxZoom;
// Set up button click listeners.
var btnGetTiles = document.getElementById("btn-get-tiles");
var btnOnlineOffline = document.getElementById("btn-online-offline");
var btnPanLeft = document.getElementById("btn-pan-left");
var imgOfflineIndicator = document.getElementById("state-span");
var btnState = document.getElementById("btn-state");
on(btnGetTiles,"click",downloadTiles);
on(btnOnlineOffline,"click",goOnlineOffline);
on(btnPanLeft,"click",panLeft);
$(document).ready(function () {
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
if (e.target.text === "Map") {
showMap("mapDiv");
}
});
});
function showMap(){
// Load the map
arcgisUtils.createMap("bbc1a04a3eca4430be144d7a08b43a17","mapDiv").then(function(response){
map = response.map;
// Initialize BootstrapMap to make the map responsive
BootstrapMap.create(map);
// Get the ArcGIS.com basemap that we want to use offline.
// And then extend it for offline use.
if(map.loaded)
{
basemapLayer = map.getLayer( map.layerIds[0] );
initializeOfflineTiles();
}
else
{
map.on("load",function()
{
basemapLayer = map.getLayer( map.layerIds[0] );
initializeOfflineTiles();
});
}
});
}
function initializeOfflineTiles(){
offlineTilesEnabler.extend(basemapLayer,function(success) {
if (success) {
console.log("ArcGIS.com map extended for offline!")
}
})
}
function downloadTiles(){
if(_downloadState == "downloading"){
_wantToCancel = true;
}
else{
_wantToCancel = false;
// First delete any existing tiles from database
basemapLayer.deleteAllTiles(function(success,err){
var zoom = basemapLayer.getMinMaxLOD(minZoomAdjust,maxZoomAdjust);
// Now download tiles
basemapLayer.prepareForOffline(zoom.min, zoom.max, map.extent, function(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 )
{
alert("Tile download was cancelled");
_downloadState = "cancelled";
}
else
{
alert("Tile download complete");
_downloadState = "downloaded";
btnOnlineOffline.disabled = false;
}
btnGetTiles.innerHTML = '1. Download Tiles';
}
return _wantToCancel; //determines if a cancel request has been issued
});
_downloadState = "downloading";
});
}
}
// Force the tileLayer between online and offline
function goOnlineOffline(){
btnPanLeft.disabled = false;
if(btnOnlineOffline.innerHTML == "2. Go Offline"){
toggleStateUp(false);
console.log("Map is offline");
}
else{
toggleStateUp(true);
console.log("Map is online");
}
}
function toggleStateUp(state){
if(state){
btnOnlineOffline.innerHTML = "2. Go Offline";
basemapLayer.goOnline();
imgOfflineIndicator.className = "glyphicon glyphicon-link";
imgOfflineIndicator.innerHTML = " Up";
btnState.className = "btn btn-success btn-large floatRight";
}
else{
btnOnlineOffline.innerHTML = "2. Go Online";
basemapLayer.goOffline();
imgOfflineIndicator.className = "glyphicon glyphicon-thumbs-down";
imgOfflineIndicator.innerHTML = " Down";
btnState.className = "btn btn-danger btn-large floatRight";
}
}
// Set the ArcGIS.com map online or offline.
// When set offline it will look for tiles in the tiles database
function updateState(){
if(Offline.state === 'up'){
if(typeof basemapLayer != "undefined") basemapLayer.goOnline();
toggleStateUp(true);
}
else{
if(typeof basemapLayer != "undefined") basemapLayer.goOffline();
toggleStateUp(false);
}
}
function panLeft(){
map.panLeft();
}
});
</script>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<!-- add syntax highlighting to code snippts -->
<script src="https://google-code-prettify.googlecode.com/svn/loader/run_prettify.js"></script>
</body>
</html>

1190
demo/getstarted-editing.html Normal file

File diff suppressed because it is too large Load Diff

785
demo/getstarted-tiles.html Normal file
View File

@ -0,0 +1,785 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!--<link rel="shortcut icon" href="../images/favicon.ico">-->
<title>Offline-editor-js</title>
<!-- Bootstrap core CSS -->
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="http://js.arcgis.com/3.11/esri/css/esri.css"">
<link rel="stylesheet" type="text/css" href="http://esri.github.io/bootstrap-map-js/src/css/bootstrapmap.css">
<!-- Custom styles for this template -->
<link href="css/style.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<style>
#mapDiv {
min-height: 300px;
max-height: 1000px;
}
pre {
overflow: auto;
word-wrap: normal;
white-space: pre;
font-family: Courier,"Courier New";
font-size: 13px;
background-color: #fee9cc;
}
pre.prettyprint {
border: 1px solid #cccccc !important;
}
.floatRight {float: right;}
</style>
</head>
<body>
<a class="hidden-xs" href="https://github.com/Esri/offline-editor-js">
<img style="position: absolute; top: 50; right: 0; border: 0; width:150px;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_green_007200.png" alt="Fork me on GitHub">
</a>
<header id="header"></header>
<!-- Main jumbotron for a primary marketing message or call to action -->
<div class="jumbotron">
<div class="container">
<h1>Getting Started with Tiles</h1>
<p>Basic steps for working with <b>tiled base map services</b> for offline.</p>
<!--<p><a class="btn btn-primary btn-lg" role="button">Samples &raquo;</a></p>-->
</div>
</div>
<div class="container">
<!-- Example row of columns -->
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12">
<ul class="nav nav-pills">
<li class="active"><a href="#Step1" data-toggle="tab">Step 1</a></li>
<li><a href="#Step2" data-toggle="tab">Step 2</a></li>
<li><a href="#Step3" data-toggle="tab">Step 3</a></li>
</ul>
<div class="tab-content well">
<div class="tab-pane active" id="Step1">
<h3>Step 1: Fill in the basics</h3>
<p>Add the basic library references. Then test to make sure map loads.</p>
<br>
<pre class="prettyprint">
<code>
&lt;!DOCTYPE html>
&lt;html>
&lt;head>
&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8">
&lt;meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
&lt;title>Offline Tiles&lt;/title>
&lt;!-- Bootstrap core CSS -->
&lt;link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
&lt;link rel="stylesheet" href="http://js.arcgis.com/3.11/esri/css/esri.css">
&lt;link rel="stylesheet" type="text/css" href="http://esri.github.io/bootstrap-map-js/src/css/bootstrapmap.css">
&lt;style>
#mapDiv {
min-height: 500px;
max-height: 1000px;
}
body {
background-color: #ffffff;
overflow: hidden;
font-family: "Trebuchet MS";
}
.floatRight {float: right;}
.container { padding: 20px;}
&lt;/style>
&lt;!-- Include a reference to offline.js which detects online/offline conditions -->
&lt;script src="../vendor/offline/offline.min.js">&lt;/script>
&lt;script>
// Set the online/offline detection options.
// More info at: http://github.hubspot.com/offline/docs/welcome/
Offline.options = {
checks: {
image: {
url: function() {
return 'http://esri.github.io/offline-editor-js/tiny-image.png?_=' +
(Math.floor(Math.random() * 1000000000));
}
},
active: 'image'
}
}
&lt;/script>
&lt;!-- Include a reference to IndexedDBShim for library to work on Safari 7.x -->
&lt;script src="../vendor/IndexedDBShim/dist/IndexedDBShim.js">&lt;/script>
&lt;script src="http://js.arcgis.com/3.11/">&lt;/script>
&lt;/head>
&lt;body>
&lt;div class="row">
&lt;div class="col-xs-12">
&lt;div id="mapDiv">&lt;/div>
&lt;/div>
&lt;/div>
&lt;script>
// Make sure to reference the tiles library within the require statement!
require(["esri/map","dojo/on","//esri.github.com/bootstrap-map-js/src/js/bootstrapmap.js","../dist/offline-tiles-advanced-min.js", "dojo/domReady!"],
function(Map,on,Bootstrapmap) {
// Initialize our map to be responsive
var map = Bootstrapmap.create("mapDiv",{
basemap: "topo",
center: [-122.45, 37.75], // longitude, latitude
zoom: 15
});
});
&lt;/script>
&lt;!-- Bootstrap core JavaScript
================================================== -->
&lt;!-- Placed at the end of the document so the pages load faster -->
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">&lt;/script>
&lt;script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js">&lt;/script>
&lt;/body>
&lt;/html>
</code>
</pre>
<div class="alert alert-info">NOTE: Replace paths with your references. Or build your app in the /demo directory</div>
</div>
<div class="tab-pane" id="Step2">
<h3>Step 2: Configure tiled basemap to work offline</h3>
<p>This initializes the offline-editor-js library. Test to make sure map loads.</p>
<br>
<pre class="prettyprint">
<code>
&lt;!DOCTYPE html>
&lt;html>
&lt;head>
&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8">
&lt;meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
&lt;title>Offline Tiles&lt;/title>
&lt;!-- Bootstrap core CSS -->
&lt;link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
&lt;link rel="stylesheet" href="http://js.arcgis.com/3.11/esri/css/esri.css">
&lt;link rel="stylesheet" type="text/css" href="http://esri.github.io/bootstrap-map-js/src/css/bootstrapmap.css">
&lt;style>
#mapDiv {
min-height: 500px;
max-height: 1000px;
}
body {
background-color: #ffffff;
overflow: hidden;
font-family: "Trebuchet MS";
}
.floatRight {float: right;}
.container { padding: 20px;}
&lt;/style>
&lt;!-- Include a reference to offline.js which detects online/offline conditions -->
&lt;script src="../vendor/offline/offline.min.js">&lt;/script>
&lt;script>
// Set the online/offline detection options.
// More info at: http://github.hubspot.com/offline/docs/welcome/
Offline.options = {
checks: {
image: {
url: function() {
return 'http://esri.github.io/offline-editor-js/tiny-image.png?_=' +
(Math.floor(Math.random() * 1000000000));
}
},
active: 'image'
}
}
&lt;/script>
&lt;!-- Include a reference to IndexedDBShim for library to work on Safari 7.x -->
&lt;script src="../vendor/IndexedDBShim/dist/IndexedDBShim.js">&lt;/script>
&lt;script src="http://js.arcgis.com/3.11/">&lt;/script>
&lt;/head>
&lt;body>
&lt;div class="row">
&lt;div class="col-xs-12">
&lt;div id="mapDiv">&lt;/div>
&lt;/div>
&lt;/div>
&lt;script>
// Make sure to reference the tiles library within the require statement!
require(["esri/map","dojo/on","//esri.github.com/bootstrap-map-js/src/js/bootstrapmap.js","../dist/offline-tiles-advanced-min.js", "dojo/domReady!"],
function(Map,on,Bootstrapmap) {
// Check if browser state is online or offline
Offline.check();
Offline.on('up down', updateState );
// Initialize our map to be responsive
var map = Bootstrapmap.create("mapDiv",{
//basemap: "topo", // comment out this basemap!
center: [-122.45, 37.75], // longitude, latitude
zoom: 15
});
// Now we initialize a topo tiled basemap service to be offline-enabled.
var tileLayer = O.esri.Tiles.OfflineTileEnablerLayer(
"http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer",
function(evt){
console.log("Offline tile lib enabled. App is: " + Offline.state);
},
true);
// Add our offline tile layer to the map instead of using the default basemap!
map.addLayer(tileLayer);
// Set the tileLayer online or offline.
// When set to offline, the map will look for tiles in the local tiles database
function updateState(){
if(Offline.state === 'up'){
if(typeof tileLayer != "undefined") tileLayer.goOnline();
}
else{
if(typeof tileLayer != "undefined") tileLayer.goOffline();
}
}
});
&lt;/script>
&lt;!-- Bootstrap core JavaScript
================================================== -->
&lt;!-- Placed at the end of the document so the pages load faster -->
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">&lt;/script>
&lt;script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js">&lt;/script>
&lt;/body>
&lt;/html>
</code>
</pre>
<div class="alert alert-info">NOTE: Replace paths with your references. Or build your app in the /demo directory</div>
</div>
<div class="tab-pane" id="Step3">
<h3>Step 3: Configure tiles download.</h3>
<p>Enable the ability to download tiles as well the ability to toggle online and offline.</p>
<br>
<ul id="myTab" class="nav nav-tabs">
<li class="active"><a href="#code" data-toggle="tab">Code</a></li>
<li class=""><a href="#mapTab" data-toggle="tab">Map</a></li>
</ul>
</br>
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade in active" id="code">
<pre class="prettyprint">
<code>
&lt;!DOCTYPE html>
&lt;html>
&lt;head>
&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8">
&lt;meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
&lt;title>Offline Tiles&lt;/title>
&lt;!-- Bootstrap core CSS -->
&lt;link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
&lt;link rel="stylesheet" href="http://js.arcgis.com/3.11/esri/css/esri.css">
&lt;link rel="stylesheet" type="text/css" href="http://esri.github.io/bootstrap-map-js/src/css/bootstrapmap.css">
&lt;style>
#mapDiv {
min-height: 500px;
max-height: 1000px;
}
body {
background-color: #ffffff;
overflow: hidden;
font-family: "Trebuchet MS";
}
.floatRight { float: right;}
.container { padding: 20px;}
&lt;/style>
&lt;!-- Include a reference to offline.js which detects online/offline conditions -->
&lt;script src="../vendor/offline/offline.min.js">&lt;/script>
&lt;script>
// Set the online/offline detection options.
// More info at: http://github.hubspot.com/offline/docs/welcome/
Offline.options = {
checks: {
image: {
url: function() {
return 'http://esri.github.io/offline-editor-js/tiny-image.png?_=' +
(Math.floor(Math.random() * 1000000000));
}
},
active: 'image'
}
}
&lt;/script>
&lt;!-- Include a reference to IndexedDBShim for library to work on Safari 7.x -->
&lt;script src="../vendor/IndexedDBShim/dist/IndexedDBShim.js">&lt;/script>
&lt;script src="http://js.arcgis.com/3.11/">&lt;/script>
&lt;/head>
&lt;body>
&lt;!-- Our buttons and online/offline indicator -->
&lt;div class="container">
&lt;div class="row">
&lt;div class="col-xs-10">
&lt;div class="form form-group btn-group" data-toggle="buttons">
&lt;button class="btn btn-success" id="btn-get-tiles">1. Download Tiles&lt;/button>
&lt;button class="btn btn-success" disabled id="btn-online-offline">2. Go Offline&lt;/button>
&lt;button class="btn btn-success" disabled id="btn-pan-left">3. Pan left&lt;/button>
&lt;/div>
&lt;/div>
&lt;div class="col-xs-2">
&lt;!-- this indicates whether app is offline (down) or online (up) -->
&lt;button id="btn-state" class="btn btn-success btn-large floatRight">
&lt;span id="state-span" class="glyphicon glyphicon-link"> Up&lt;/span>
&lt;/button>
&lt;/div>
&lt;/div>
&lt;div class="row">
&lt;div class="col-xs-12">
&lt;div id="mapDiv">&lt;/div>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;script>
// Make sure to reference the tiles library within the require statement!
require(["esri/map","dojo/on","//esri.github.com/bootstrap-map-js/src/js/bootstrapmap.js",
"../dist/offline-tiles-advanced-min.js", "dojo/domReady!"],
function(Map,on,Bootstrapmap){
var map,basemapLayer;
// Check if browser state is online or offline
Offline.check();
Offline.on('up down', updateState );
// For cancelling the download of tiles
var _wantToCancel = false;
var _downloadState = "downloaded";
// Set up min and max boundaries for retrieving tiles
var minZoomAdjust = -1, maxZoomAdjust = 1;
// Set up button click listeners.
var btnGetTiles = document.getElementById("btn-get-tiles");
var btnOnlineOffline = document.getElementById("btn-online-offline");
var btnPanLeft = document.getElementById("btn-pan-left");
on(btnGetTiles,"click",downloadTiles);
on(btnOnlineOffline,"click",goOnlineOffline);
on(btnPanLeft,"click",panLeft);
var imgOfflineIndicator = document.getElementById("state-span");
var btnState = document.getElementById("btn-state");
showMap();
function showMap(){
// Initialize our map to be responsive
map = Bootstrapmap.create("mapDiv",{
//basemap: "topo", // comment out this basemap!
center: [-122.45, 37.75], // longitude, latitude
zoom: 15
});
// Now we initialize the basemap to be offline-enabled. This is out new basemap.
basemapLayer = O.esri.Tiles.OfflineTileEnablerLayer(
"http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer",
function(evt){
console.log("Offline tile lib enabled. App is: " + Offline.state);
},
true);
// Add our offline tile layer to the map instead of using the default basemap!
map.addLayer(basemapLayer);
}
function downloadTiles(){
if(_downloadState == "downloading"){
_wantToCancel = true;
}
else{
_wantToCancel = false;
// First delete any existing tiles from database
basemapLayer.deleteAllTiles(function(success,err){
var zoom = basemapLayer.getMinMaxLOD(minZoomAdjust,maxZoomAdjust);
// Now download tiles
basemapLayer.prepareForOffline(zoom.min, zoom.max, map.extent, function(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 )
{
alert("Tile download was cancelled");
_downloadState = "cancelled";
}
else
{
alert("Tile download complete");
_downloadState = "downloaded";
btnOnlineOffline.disabled = false;
}
btnGetTiles.innerHTML = '1. Download Tiles';
}
return _wantToCancel; //determines if a cancel request has been issued
});
_downloadState = "downloading";
});
}
}
// Force the tileLayer between online and offline
function goOnlineOffline(){
btnPanLeft.disabled = false;
if(btnOnlineOffline.innerHTML == "2. Go Offline"){
toggleStateUp(false);
console.log("Map is offline");
}
else{
toggleStateUp(true);
console.log("Map is online");
}
}
function toggleStateUp(state){
if(state){
btnOnlineOffline.innerHTML = "2. Go Offline";
basemapLayer.goOnline();
imgOfflineIndicator.className = "glyphicon glyphicon-link";
imgOfflineIndicator.innerHTML = " Up";
btnState.className = "btn btn-success btn-large floatRight";
}
else{
btnOnlineOffline.innerHTML = "2. Go Online";
basemapLayer.goOffline();
imgOfflineIndicator.className = "glyphicon glyphicon-thumbs-down";
imgOfflineIndicator.innerHTML = " Down";
btnState.className = "btn btn-danger btn-large floatRight";
}
}
// Set the ArcGIS.com map online or offline.
// When set offline it will look for tiles in the tiles database
function updateState(){
if(Offline.state === 'up'){
if(typeof basemapLayer != "undefined") basemapLayer.goOnline();
toggleStateUp(true);
}
else{
if(typeof basemapLayer != "undefined") basemapLayer.goOffline();
toggleStateUp(false);
}
}
// Pan left when "offline" to view only tiles that have been stored locally
function panLeft(){
map.panLeft();
}
});
&lt;/script>
&lt;!-- Bootstrap core JavaScript
================================================== -->
&lt;!-- Placed at the end of the document so the pages load faster -->
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">&lt;/script>
&lt;script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js">&lt;/script>
&lt;/body>
&lt;/html>
</code>
</pre>
<div class="alert alert-info">NOTE: Replace paths with your references. Or build your app in the /demo directory</div>
</div>
<div class="tab-pane fade in" id="mapTab">
<div class="row">
<div class="col-xs-10">
<div class="form form-group btn-group" data-toggle="buttons">
<button class="btn btn-success" id="btn-get-tiles">1. Download Tiles</button>
<button class="btn btn-success" disabled id="btn-online-offline">2. Go Offline</button>
<button class="btn btn-success" disabled id="btn-pan-left">3. Pan left</button>
</div>
</div>
<div class="col-xs-2">
<!-- this indicates whether app is offline (down) or online (up) -->
<button id="btn-state" class="btn btn-success btn-large floatRight"><span id="state-span" class="glyphicon glyphicon-link"> Up</span></button>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div id="mapDiv"></div>
</div>
</div>
</div>
</div><!-- id="code" -->
</div><!-- id="myTabContent" -->
</div><!-- id="step4" -->
</br>
</div><!-- class="tab-content well" -->
</div><!-- class="col-sm-12 col-md-12 col-lg-12" -->
<hr>
</div> <!-- /container -->
<!-- mapping code -->
<script src="../vendor/offline/offline.min.js"></script>
<script>
// Set the online/offline detection options.
// More info at: http://github.hubspot.com/offline/docs/welcome/
Offline.options = {
checks: {
image: {
url: function() {
return 'http://esri.github.io/offline-editor-js/tiny-image.png?_=' +
(Math.floor(Math.random() * 1000000000));
}
},
active: 'image'
}
}
</script>
<!-- Include a reference to IndexedDBShim for library to work on Safari 7.x -->
<script src="../vendor/IndexedDBShim/dist/IndexedDBShim.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://js.arcgis.com/3.11/"></script>
<script>
$(document).ready(function() {
$("#header").load("../demo/header.html");
});
// Make sure to reference the offline tiles library within the require statement!
require(["esri/map","dojo/on","//esri.github.com/bootstrap-map-js/src/js/bootstrapmap.js","../dist/offline-tiles-advanced-min.js", "dojo/domReady!"],
function(Map,on,Bootstrapmap){
var map, basemapLayer;
// Check if browser state is online or offline
Offline.check();
Offline.on('up down', updateState );
// For cancelling the download of tiles
var _wantToCancel;
var _downloadState = "downloaded";
// Set up min and max boundaries for retrieving tiles
var minZoomAdjust = -1, maxZoomAdjust = 1;
// Set up button click listeners.
var btnGetTiles = document.getElementById("btn-get-tiles");
var btnOnlineOffline = document.getElementById("btn-online-offline");
var btnPanLeft = document.getElementById("btn-pan-left");
var imgOfflineIndicator = document.getElementById("state-span");
var btnState = document.getElementById("btn-state");
on(btnGetTiles,"click",downloadTiles);
on(btnOnlineOffline,"click",goOnlineOffline);
on(btnPanLeft,"click",panLeft);
$(document).ready(function () {
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
if (e.target.text === "Map") {
showMap("mapDiv");
}
});
});
function showMap(){
// Initialize our map to be responsive
map = Bootstrapmap.create("mapDiv",{
//basemap: "topo", // comment out this basemap!
center: [-122.45, 37.75], // longitude, latitude
zoom: 17
});
// Now we initialize the basemap to be offline-enabled. This is out new basemap.
basemapLayer = O.esri.Tiles.OfflineTileEnablerLayer(
"http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer",
function(evt){
console.log("Offline tile lib enabled. App is: " + Offline.state);
},
true);
// Add our offline tile layer to the map instead of using the default basemap!
map.addLayer(basemapLayer);
}
function downloadTiles(){
if(_downloadState == "downloading"){
_wantToCancel = true;
}
else{
_wantToCancel = false;
// First delete any existing tiles from database
basemapLayer.deleteAllTiles(function(success,err){
var zoom = basemapLayer.getMinMaxLOD(minZoomAdjust,maxZoomAdjust);
// Now download tiles
basemapLayer.prepareForOffline(zoom.min, zoom.max, map.extent, function(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 )
{
alert("Tile download was cancelled");
_downloadState = "cancelled";
}
else
{
alert("Tile download complete");
_downloadState = "downloaded";
btnOnlineOffline.disabled = false;
}
btnGetTiles.innerHTML = '1. Download Tiles';
}
return _wantToCancel; //determines if a cancel request has been issued
});
_downloadState = "downloading";
});
}
}
// Force the tileLayer between online and offline
function goOnlineOffline(){
btnPanLeft.disabled = false;
if(btnOnlineOffline.innerHTML == "2. Go Offline"){
toggleStateUp(false);
console.log("Map is offline");
}
else{
toggleStateUp(true);
console.log("Map is online");
}
}
function toggleStateUp(state){
if(state){
btnOnlineOffline.innerHTML = "2. Go Offline";
basemapLayer.goOnline();
imgOfflineIndicator.className = "glyphicon glyphicon-link";
imgOfflineIndicator.innerHTML = " Up";
btnState.className = "btn btn-success btn-large floatRight";
}
else{
btnOnlineOffline.innerHTML = "2. Go Online";
basemapLayer.goOffline();
imgOfflineIndicator.className = "glyphicon glyphicon-thumbs-down";
imgOfflineIndicator.innerHTML = " Down";
btnState.className = "btn btn-danger btn-large floatRight";
}
}
// Set the ArcGIS.com map online or offline.
// When set offline it will look for tiles in the tiles database
function updateState(){
if(Offline.state === 'up'){
if(typeof basemapLayer != "undefined") basemapLayer.goOnline();
toggleStateUp(true);
}
else{
if(typeof basemapLayer != "undefined") basemapLayer.goOffline();
toggleStateUp(false);
}
}
function panLeft(){
map.panLeft();
}
});
</script>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<!-- add syntax highlighting to code snippts -->
<script src="https://google-code-prettify.googlecode.com/svn/loader/run_prettify.js"></script>
</body>
</html>

574
demo/getstarted-tpk.html Normal file
View File

@ -0,0 +1,574 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!--<link rel="shortcut icon" href="../images/favicon.ico">-->
<title>Offline-editor-js</title>
<!-- Bootstrap core CSS -->
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="http://js.arcgis.com/3.10/js/esri/css/esri.css">
<link rel="stylesheet" type="text/css" href="http://esri.github.io/bootstrap-map-js/src/css/bootstrapmap.css">
<!-- Custom styles for this template -->
<link href="css/style.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<style>
#mapDiv {
min-height: 300px;
max-height: 1000px;
}
pre {
overflow: auto;
word-wrap: normal;
white-space: pre;
font-family: Courier,"Courier New";
font-size: 13px;
background-color: #fee9cc;
}
pre.prettyprint {
border: 1px solid #cccccc !important;
}
</style>
</head>
<body>
<a class="hidden-xs" href="https://github.com/Esri/offline-editor-js">
<img style="position: absolute; top: 50; right: 0; border: 0; width:150px;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_green_007200.png" alt="Fork me on GitHub">
</a>
<header id="header"></header>
<!-- Main jumbotron for a primary marketing message or call to action -->
<div class="jumbotron">
<div class="container">
<h1>Getting Started with TPKs</h1>
<p>Basic steps for working with <b>TPK packages</b> for offline.</p>
<!--<p><a class="btn btn-primary btn-lg" role="button">Samples &raquo;</a></p>-->
</div>
</div>
<div class="container">
<!-- Example row of columns -->
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12">
<ul class="nav nav-pills">
<li class="active"><a href="#Step1" data-toggle="tab">Step 1</a></li>
<li><a href="#Step2" data-toggle="tab">Step 2</a></li>
<li><a href="#Step3" data-toggle="tab">Step 3</a></li>
</ul>
<div class="tab-content well">
<div class="tab-pane active" id="Step1">
<h3>Step 1: Fill in the basics</h3>
<p>Add the basic library references and CSS. Then test to make sure application loads.
There won't be a map to display just yet, you'll only see the header bar.</p>
<br>
<pre class="prettyprint">
<code>
&lt;!DOCTYPE html>
&lt;html>
&lt;head>
&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8">
&lt;meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
&lt;title>Offline TPK&lt;/title>
&lt;link href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet" media="screen">
&lt;link rel="stylesheet" href="http://js.arcgis.com/3.11/esri/css/esri.css"">
&lt;link rel="stylesheet" type="text/css" href="http://esri.github.io/bootstrap-map-js/src/css/bootstrapmap.css">
&lt;style>
#mapDiv {
min-height: 300px;
max-height: 1000px;
}
.container { padding: 20px;}
&lt;/style>
&lt;!-- Include a reference to IndexedDBShim for library to work on Safari 7.x -->
&lt;script src="../vendor/IndexedDBShim/dist/IndexedDBShim.js">&lt;/script>
&lt;script src="http://js.arcgis.com/3.11/">&lt;/script>
&lt;/head>
&lt;body>
&lt;div class="container">
&lt;div class="row">
&lt;div class="col-lg-12">
&lt;div class="form form-group input-group">
&lt;input id="url-input" type="text" class="form-control"
value="../samples/tpks/Beirut.zip">
&lt;span class="input-group-btn">
&lt;button id="url-btn" class="btn btn-success" type="button">Go!&lt;/button>
&lt;/span>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;div class="row">
&lt;div class="col-xs-12">
&lt;div id="mapDiv">&lt;/div>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;script>
// Make sure to reference the tpk library within the require statement!
require([
"esri/map",
"dojo/on",
"//esri.github.com/bootstrap-map-js/src/js/bootstrapmap.js",
"../dist/offline-tpk-src.js", "dojo/domReady!"],
function(Map,on,BootstrapMap) {
var map, tpkLayer;
var url = document.getElementById("url-input");
var urlInputBtn = document.getElementById("url-btn");
}
);
&lt;/script>
&lt;!-- Bootstrap core JavaScript
================================================== -->
&lt;!-- Placed at the end of the document so the pages load faster -->
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">&lt;/script>
&lt;script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js">&lt;/script>
&lt;/body>
&lt;/html>
</code>
</pre>
<div class="alert alert-info">NOTE: Replace paths with your references.</div>
</div>
<div class="tab-pane" id="Step2">
<h3>Step 2: Retrieve TPK.</h3>
<p>Download and unzip the TPK. You should get an alert when TPK is fully downloaded. </p>
<p>NOTE: If you have a TPK file you will have to change its type to .zip for the browser to recognize it. </p>
<br>
<pre class="prettyprint">
<code>
&lt;!DOCTYPE html>
&lt;html>
&lt;head>
&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8">
&lt;meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
&lt;title>Offline TPK&lt;/title>
&lt;link href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet" media="screen">
&lt;link rel="stylesheet" href="http://js.arcgis.com/3.11/esri/css/esri.css">
&lt;link rel="stylesheet" type="text/css" href="http://esri.github.io/bootstrap-map-js/src/css/bootstrapmap.css">
&lt;style>
#mapDiv {
min-height: 300px;
max-height: 1000px;
}
.container { padding: 20px;}
&lt;/style>
&lt;!-- Include a reference to IndexedDBShim for library to work on Safari 7.x -->
&lt;script src="../vendor/IndexedDBShim/dist/IndexedDBShim.js">&lt;/script>
&lt;script src="http://js.arcgis.com/3.11/">&lt;/script>
&lt;/head>
&lt;body>
&lt;div class="container">
&lt;div class="row">
&lt;div class="col-lg-12">
&lt;div class="form form-group input-group">
&lt;input id="url-input" type="text" class="form-control"
value="../samples/tpks/Beirut.zip">
&lt;span class="input-group-btn">
&lt;button id="url-btn" class="btn btn-success" type="button">Go!&lt;/button>
&lt;/span>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;div class="row">
&lt;div class="col-xs-12">
&lt;div id="mapDiv">&lt;/div>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;script>
// Make sure to reference the tpk library within the require statement!
require([
"esri/map",
"dojo/on",
"//esri.github.com/bootstrap-map-js/src/js/bootstrapmap.js",
"../dist/offline-tpk-src.js", "dojo/domReady!"],
function(Map,on,BootstrapMap) {
var map, tpkLayer;
var url = document.getElementById("url-input");
var urlInputBtn = document.getElementById("url-btn");
urlInputBtn.onclick = function(){
getTPK();
};
// Retrieve the TPK file via an HTTP request
function getTPK(){
urlInputBtn.innerHTML = "Get file via url";
var xhrRequest = new XMLHttpRequest();
xhrRequest.open("GET", url.value, true);
xhrRequest.responseType = "blob";
xhrRequest.onprogress = function(evt){
var percent = (parseFloat(evt.loaded / evt.totalSize) * 100).toFixed(0);
urlInputBtn.innerHTML = "Get file via url " + percent + "%";
console.log("Begin downloading remote tpk file...")
}
xhrRequest.error = function(err){console.log("ERROR")}
xhrRequest.onload = function(oEvent) {
if(this.status == 200) {
console.log("Remote tpk download finished.")
zipParser(this.response);
}
else{
alert("There was a problem loading the file. " + this.status + ": " + this.statusText )
}
};
xhrRequest.send();
}
// Parse the zip file contents into a zip.Entries object
function zipParser(blob){
O.esri.zip.createReader(new O.esri.zip.BlobReader(blob), function (zipReader) {
zipReader.getEntries(function (entries) {
if(entries) alert("TPK downloaded and unzipped!");
zipReader.close(function(evt){
console.log("Done reading zip file.")
})
}, function (err) {
alert("There was a problem reading the file!: " + err);
})
})
}
}
);
&lt;/script>
&lt;!-- Bootstrap core JavaScript
================================================== -->
&lt;!-- Placed at the end of the document so the pages load faster -->
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">&lt;/script>
&lt;script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js">&lt;/script>
&lt;/body>
&lt;/html>
</code>
</pre>
<div class="alert alert-info">NOTE: Replace paths with your references.</div>
</div>
<div class="tab-pane" id="Step3">
<h3>Step 3: Display TPK tiles.</h3>
<p>In this step we hand the zip file entries over to TPKLayer to inflate the map.</p>
<br>
<ul id="myTab" class="nav nav-tabs">
<li class="active"><a href="#code" data-toggle="tab">Code</a></li>
<li class=""><a href="#mapTab" data-toggle="tab">Map</a></li>
</ul>
</br>
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade in active" id="code">
<pre class="prettyprint">
<code>
&lt;!DOCTYPE html>
&lt;html>
&lt;head>
&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8">
&lt;meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
&lt;title>Offline TPK&lt;/title>
&lt;link href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet" media="screen">
&lt;link rel="stylesheet" href="http://js.arcgis.com/3.11/esri/css/esri.css">
&lt;link rel="stylesheet" type="text/css" href="http://esri.github.io/bootstrap-map-js/src/css/bootstrapmap.css">
&lt;style>
#mapDiv {
min-height: 300px;
max-height: 1000px;
}
.container { padding: 20px;}
&lt;/style>
&lt;!-- Include a reference to IndexedDBShim for library to work on Safari 7.x -->
&lt;script src="../vendor/IndexedDBShim/dist/IndexedDBShim.js">&lt;/script>
&lt;script src="http://js.arcgis.com/3.11/">&lt;/script>
&lt;/head>
&lt;body>
&lt;div class="container">
&lt;div class="row">
&lt;div class="col-lg-12">
&lt;div class="form form-group input-group">
&lt;input id="url-input" type="text" class="form-control"
value="../samples/tpks/Beirut.zip">
&lt;span class="input-group-btn">
&lt;button id="url-btn" class="btn btn-success" type="button">Go!&lt;/button>
&lt;/span>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;div class="row">
&lt;div class="col-xs-12">
&lt;div id="mapDiv">&lt;/div>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;script>
// Make sure to reference the tpk library within the require statement!
require([
"esri/map",
"dojo/on",
"//esri.github.com/bootstrap-map-js/src/js/bootstrapmap.js",
"../dist/offline-tpk-src.js", "dojo/domReady!"],
function(Map,on,BootstrapMap) {
var map, tpkLayer;
var url = document.getElementById("url-input");
var urlInputBtn = document.getElementById("url-btn");
urlInputBtn.onclick = function(){
getTPK();
};
// Retrieve the TPK file via an HTTP request
function getTPK(){
urlInputBtn.innerHTML = "Get file via url";
var xhrRequest = new XMLHttpRequest();
xhrRequest.open("GET", url.value, true);
xhrRequest.responseType = "blob";
xhrRequest.onprogress = function(evt){
var percent = (parseFloat(evt.loaded / evt.totalSize) * 100).toFixed(0);
urlInputBtn.innerHTML = "Get file via url " + percent + "%";
console.log("Begin downloading remote tpk file...")
}
xhrRequest.error = function(err){console.log("ERROR")}
xhrRequest.onload = function(oEvent) {
if(this.status == 200) {
console.log("Remote tpk download finished.")
zipParser(this.response);
}
else{
alert("There was a problem loading the file. " + this.status + ": " + this.statusText )
}
};
xhrRequest.send();
}
// Parse the zip file contents into a zip.Entries object
function zipParser(blob){
O.esri.zip.createReader(new O.esri.zip.BlobReader(blob), function (zipReader) {
zipReader.getEntries(function (entries) {
initMap(entries);
//if(entries)alert("TPK downloaded and unzipped!");
zipReader.close(function(evt){
console.log("Done reading zip file.")
})
}, function (err) {
alert("There was a problem reading the file!: " + err);
})
})
}
// Initialize the Map and the TPKLayer
function initMap(entries){
map = BootstrapMap.create("mapDiv",{});
tpkLayer = new O.esri.TPK.TPKLayer();
tpkLayer.on("progress", function (evt) {
console.log("TPK loading...");
})
tpkLayer.extend(entries);
map.addLayer(tpkLayer);
}
}
);
&lt;/script>
&lt;!-- Bootstrap core JavaScript
================================================== -->
&lt;!-- Placed at the end of the document so the pages load faster -->
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">&lt;/script>
&lt;script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js">&lt;/script>
&lt;/body>
&lt;/html>
</code>
</pre>
<div class="alert alert-info"><b>NOTE:</b> Replace paths with your references. This sample may look different than our live sample.</div>
</div>
<div class="tab-pane fade in" id="mapTab">
<div class="row">
<div class="col-lg-12">
<div class="form form-group input-group">
<input id="url-input" type="text" class="form-control" value="../samples/tpks/Beirut.zip">
<span class="input-group-btn">
<button id="url-btn" class="btn btn-default" type="button">Go!</button>
</span>
</div><!-- /input-group -->
</div><!-- /.col-lg-12 -->
</div>
<div class="row">
<div class="col-xs-12">
<div id="mapDiv"></div>
</div>
</div>
</div>
</div><!-- id="myTabContent" -->
</div><!-- id="step4" -->
</br>
</div><!-- class="tab-content well" -->
</div><!-- class="col-sm-12 col-md-12 col-lg-12" -->
<hr>
</div> <!-- /container -->
<!-- Include a reference to IndexedDBShim for library to work on Safari 7.x -->
<script src="../vendor/IndexedDBShim/dist/IndexedDBShim.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://js.arcgis.com/3.10/"></script>
<script>
$(document).ready(function() {
$("#header").load("../demo/header.html");
});
var map;
// Make sure to reference the offline tiles library within the require statement!
require(
["esri/map",
"dojo/on",
"//esri.github.com/bootstrap-map-js/src/js/bootstrapmap.js",
"../dist/offline-tpk-min.js", "dojo/domReady!"],
function(Map,on,Bootstrapmap){
var map, tpkLayer;
var url = document.getElementById("url-input");
var urlInputBtn = document.getElementById("url-btn");
urlInputBtn.onclick = function(){
getTPK();
};
// Initialize the Map and the TPKLayer
function initMap(entries){
if(map){
map.destroy();
}
map = Bootstrapmap.create("mapDiv",{
//basemap: "topo", // comment out this basemap!
});
tpkLayer = new O.esri.TPK.TPKLayer();
tpkLayer.on("progress", function (evt) {
console.log("TPK loading...");
})
tpkLayer.extend(entries);
map.addLayer(tpkLayer);
}
function getTPK(){
urlInputBtn.innerHTML = "Get file via url";
var xhrRequest = new XMLHttpRequest();
xhrRequest.open("GET", url.value, true);
xhrRequest.responseType = "blob";
xhrRequest.onprogress = function(evt){
var percent = (parseFloat(evt.loaded / evt.totalSize) * 100).toFixed(0);
urlInputBtn.innerHTML = "Get file via url " + percent + "%";
console.log("Begin downloading remote tpk file...")
}
xhrRequest.error = function(err){console.log("ERRROR")}
xhrRequest.onload = function(oEvent) {
if(this.status == 200) {
console.log("Remote tpk download finished.");
zipParser(this.response)
}
else{
alert("There was a problem loading the file. " + this.status + ": " + this.statusText )
}
};
xhrRequest.send();
}
function zipParser(blob){
O.esri.zip.createReader(new O.esri.zip.BlobReader(blob), function (zipReader) {
zipReader.getEntries(function (entries) {
initMap(entries);
zipReader.close(function(evt){
console.log("Done reading zip file.")
})
}, function (err) {
alert("There was a problem reading the file!: " + err);
})
})
}
});
</script>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<!-- add syntax highlighting to code snippts -->
<script src="https://google-code-prettify.googlecode.com/svn/loader/run_prettify.js"></script>
</body>
</html>

View File

@ -47,6 +47,8 @@
padding: 8px;
position: relative; float: right;
}
.blue-link {color: blue !important;}
</style>
</head>
@ -56,662 +58,60 @@
<img style="position: absolute; top: 50; right: 0; border: 0; width:150px;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_green_007200.png" alt="Fork me on GitHub">
</a>
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand-title" href="index.html">Offline-editor-js</a>
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li><a href="getstarted.html">Get Started - Tiles</a></li>
</ul>
</div>
</div>
</div>
<header id="header"></header>
<!-- Main jumbotron for a primary marketing message or call to action -->
<div class="jumbotron">
<div class="container">
<h1>Getting Started</h1>
<p>Basic steps for working with web map tiles while offline.</p>
<h1>Getting Started Samples</h1>
<p>Basic responsive samples on how to work with the <b>ArcGIS API for JavaScript</b> while offline.</p>
<!--<p><a class="btn btn-primary btn-lg" role="button">Samples &raquo;</a></p>-->
</div>
</div>
<div class="container">
<!-- Example row of columns -->
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12">
<ul class="nav nav-pills">
<li class="active"><a href="#Step1" data-toggle="tab">Step 1</a></li>
<li><a href="#Step2" data-toggle="tab">Step 2</a></li>
<li><a href="#Step3" data-toggle="tab">Step 3</a></li>
<li><a href="#Step4" data-toggle="tab">Step 4</a></li>
</ul>
<div class="tab-content well">
<div class="tab-pane active" id="Step1">
<h3>Step 1: Fork or clone <i>offline-editor-js</i></h3>
<p>Here are the important directories to know:</p>
<ul>
<li><b>\dist</b> - concatenated library source and minified library files.</li>
<li><b>\samples</b> - examples that demonstrate the library's functionality.</li>
<li><b>\vendor</b> - contains IndexedDBShim and offline.js libraries</li>
</ul>
<br>
<a href="http://github.com/Esri/offline-editor-js"><button type="button" class="btn btn-md btn-success">Fork on GitHub</button></a>
</div>
<div class="tab-pane" id="Step2">
<h3>Step 2: Fill in the basics</h3>
<p>Add the basic library references. Then test to make sure map loads.</p>
<br>
<pre class="prettyprint">
<code>
&lt;!DOCTYPE html>
&lt;html>
&lt;head>
&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8">
&lt;meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
&lt;title>Simple Map&lt;/title>
&lt;link rel="stylesheet" href="http://js.arcgis.com/3.10/js/esri/css/esri.css">
&lt;style>
html, body, #map {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
body {
background-color: #000000;
overflow: hidden;
font-family: "Trebuchet MS";
}
&lt;/style>
&lt;!-- Include a reference to offline.js which detects online/offline conditions -->
&lt;script src="../vendor/offline/offline.min.js">&lt;/script>
&lt;script>
// Set the online/offline detection options.
// More info at: http://github.hubspot.com/offline/docs/welcome/
Offline.options = {
checks: {
image: {
url: function() {
return 'http://esri.github.io/offline-editor-js/tiny-image.png?_=' +
(Math.floor(Math.random() * 1000000000));
}
},
active: 'image'
}
}
&lt;/script>
&lt;!-- Include a reference to IndexedDBShim for library to work on Safari 7.x -->
&lt;script src="../vendor/IndexedDBShim/dist/IndexedDBShim.js">&lt;/script>
&lt;script src="http://js.arcgis.com/3.10/">&lt;/script>
&lt;/head>
&lt;body>
&lt;div id="map">&lt;/div>
&lt;script>
var map;
// Make sure to reference the tiles library within the require statement!
require(["esri/map","../dist/offline-tiles-advanced-min.js", "dojo/domReady!"], function(Map) {
map = new Map("map", {
basemap: "topo",
center: [-122.45, 37.75], // longitude, latitude
zoom: 13
});
});
&lt;&#47;script&gt;
&lt;/body>
&lt;/html>
</code>
</pre>
<div class="alert alert-info">NOTE: Replace paths with your references.</div>
</div>
<div class="tab-pane" id="Step3">
<h3>Step 3: Configure tiled basemap to work offline</h3>
<p>This initializes the offline-editor-js library. Test to make sure map loads.</p>
<br>
<pre class="prettyprint">
<code>
&lt;!DOCTYPE html>
&lt;html>
&lt;head>
&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8">
&lt;meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
&lt;title>Simple Map&lt;/title>
&lt;link rel="stylesheet" href="http://js.arcgis.com/3.10/js/esri/css/esri.css">
&lt;style>
html, body, #map {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
body {
background-color: #000000;
overflow: hidden;
font-family: "Trebuchet MS";
}
&lt;/style>
&lt;!-- Include a reference to offline.js which detects online/offline conditions -->
&lt;script src="../vendor/offline/offline.min.js">&lt;/script>
&lt;script>
// Set the online/offline detection options.
// More info at: http://github.hubspot.com/offline/docs/welcome/
Offline.options = {
checks: {
image: {
url: function() {
return 'http://esri.github.io/offline-editor-js/tiny-image.png?_=' +
(Math.floor(Math.random() * 1000000000));
}
},
active: 'image'
}
}
&lt;/script>
&lt;!-- Include a reference to IndexedDBShim for library to work on Safari 7.x -->
&lt;script src="../vendor/IndexedDBShim/dist/IndexedDBShim.js">&lt;/script>
&lt;script src="http://js.arcgis.com/3.10/">&lt;/script>
&lt;/head>
&lt;body>
&lt;div id="map">&lt;/div>
&lt;script>
var map;
// Make sure to reference the offline tiles library within the require statement!
require(["esri/map","../dist/offline-tiles-advanced-min.js", "dojo/domReady!"], function(Map) {
// Check if browser state is online or offline
Offline.check();
Offline.on('up down', updateState );
// Initialize Esri.Map
map = new Map("map", {
//basemap: "topo", // comment out this basemap!
center: [-122.45, 37.75], // longitude, latitude
zoom: 13
});
// Now we initialize a topo tiled basemap service to be offline-enabled.
tileLayer = O.esri.Tiles.OfflineTileEnablerLayer(
"http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer",
function(evt){
console.log("Offline tile lib enabled. App is: " + Offline.state);
},
true);
// Add our offline tile layer to the map instead of using the default basemap!
map.addLayer(tileLayer);
// Set the tileLayer online or offline.
// When set to offline, the map will look for tiles in the tiles database
function updateState(){
if(Offline.state === 'up'){
if(typeof tileLayer != "undefined") tileLayer.goOnline();
}
else{
if(typeof tileLayer != "undefined") tileLayer.goOffline();
}
}
});
&lt;&#47;script&gt;
&lt;/body>
&lt;/html>
</code>
</pre>
<div class="alert alert-info">NOTE: Replace paths with your references.</div>
</div>
<div class="tab-pane" id="Step4">
<h3>Step 4: Configure tiles download.</h3>
<p>Enable the ability to download tiles as well the ability to toggle online and offline.</p>
<br>
<ul id="myTab" class="nav nav-tabs">
<li class="active"><a href="#code" data-toggle="tab">Code</a></li>
<li class=""><a href="#mapTab" data-toggle="tab">Map</a></li>
</ul>
</br>
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade in active" id="code">
<pre class="prettyprint">
<code>
&lt;!DOCTYPE html>
&lt;html>
&lt;head>
&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8">
&lt;meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
&lt;title>Simple Map&lt;/title>
&lt;link rel="stylesheet" href="http://js.arcgis.com/3.10/js/esri/css/esri.css">
&lt;style>
html, body, #map {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
body {
background-color: #000000;
overflow: hidden;
font-family: "Trebuchet MS";
}
&lt;/style>
&lt;!-- Include a reference to offline.js which detects online/offline conditions -->
&lt;script src="../vendor/offline/offline.min.js">&lt;/script>
&lt;script>
// Set the online/offline detection options.
// More info at: http://github.hubspot.com/offline/docs/welcome/
Offline.options = {
checks: {
image: {
url: function() {
return 'http://esri.github.io/offline-editor-js/tiny-image.png?_=' +
(Math.floor(Math.random() * 1000000000));
}
},
active: 'image'
}
}
&lt;/script>
&lt;!-- Include a reference to IndexedDBShim for library to work on Safari 7.x -->
&lt;script src="../vendor/IndexedDBShim/dist/IndexedDBShim.js">&lt;/script>
&lt;script src="http://js.arcgis.com/3.10/">&lt;/script>
&lt;/head>
&lt;body>
&lt;!-- Create two buttons -->
&lt;button class="basic-btn" id="btn-get-tiles">1. Download Tiles&lt;/button>
&lt;button class="basic-btn" id="btn-online-offline">2. Go Offline&lt;/button>
&lt;button class="basic-btn" id="btn-pan-left">3. Pan left&lt;/button>
&lt;div id="map">&lt;/div>
&lt;script>
var map;
// Make sure to reference the offline tiles library within the require statement!
require(["esri/map","dojo/on","../dist/offline-tiles-advanced-min.js", "dojo/domReady!"],
function(Map,on){
// Check if browser state is online or offline
Offline.check();
Offline.on('up down', updateState );
// For cancelling the download of tiles
var _wantToCancel;
// Set up min and max boundaries for retrieving tiles
var minZoomAdjust = -1, maxZoomAdjust = 1, mMinZoom, mMaxZoom;
// Set up button click listeners.
var btnGetTiles = document.getElementById("btn-get-tiles");
var btnOnlineOffline = document.getElementById("btn-online-offline");
var btnPanLeft = document.getElementById("btn-pan-left");
on(btnGetTiles,"click",downloadTiles);
on(btnOnlineOffline,"click",goOnlineOffline);
on(btnPanLeft,"click",panLeft);
// Initialize Esri.Map
map = new Map("map", {
//basemap: "topo", // comment out this basemap!
center: [-122.45, 37.75], // longitude, latitude
zoom: 13
});
// Now we initialize a topo tiled basemap service to be offline-enabled.
tileLayer = O.esri.Tiles.OfflineTileEnablerLayer(
"http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer",
function(evt){
console.log("Offline tile lib enabled. App is: " + Offline.state);
},
true);
// Set the min and max zoom levels for when retrieving tiles
// This helps manage the amount of database space used.
map.on("load",function(evt){
tileLayer.getMaxZoom(function(result){
mMaxZoom = result;
});
tileLayer.getMinZoom(function(result){
mMinZoom = result;
});
})
// Add our offline tile layer to the map instead of using the default basemap!
map.addLayer(tileLayer);
function downloadTiles(){
// First we need to empty the database.
tileLayer.deleteAllTiles(function(success,err){
var zoom = getMinMaxZoom();
var extent = tileLayer.getExtentBuffer(0,map.extent);
// Begin downloading tiles
tileLayer.prepareForOffline(zoom.min, zoom.max, extent, function(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 )
{
alert("Tile download was cancelled");
}
else
{
alert("Tile download complete");
}
btnGetTiles.innerHTML = '1. Download Tiles';
}
return _wantToCancel; //determines if a cancel request has been issued
});
});
}
// Force the tileLayer between online and offline
function goOnlineOffline(){
if(btnOnlineOffline.innerHTML == "2. Go Offline"){
btnOnlineOffline.innerHTML = "2. Go Online";
tileLayer.goOffline();
document.body.style.backgroundColor = "red";
console.log("tileLayer is offline");
}
else{
btnOnlineOffline.innerHTML = "2. Go Offline";
tileLayer.goOnline();
document.body.style.backgroundColor = "black";
console.log("tileLayer is online");
}
}
// Set the tileLayer online or offline.
// When set to offline, the map will look for tiles in the tiles database
function updateState(){
if(Offline.state === 'up'){
if(typeof tileLayer != "undefined") tileLayer.goOnline();
}
else{
if(typeof tileLayer != "undefined") tileLayer.goOffline();
}
}
// Utility function to validate min and max zoom settings of the map
function getMinMaxZoom(){
var zoom = {};
var min = tileLayer.getLevel() + minZoomAdjust;
var max = tileLayer.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 panLeft(){
map.panLeft();
}
});
&lt;&#47;script&gt;
&lt;/body>
&lt;/html>
</code>
</pre>
<div class="alert alert-info">NOTE: Replace paths with your references.</div>
</div>
<div class="tab-pane fade in" id="mapTab">
<div class="row">
<div class="col-xs-12">
<div class="form form-group btn-group" data-toggle="buttons">
<button class="btn btn-success" id="btn-get-tiles">1. Download Tiles</button>
<button class="btn btn-success" disabled id="btn-online-offline">2. Go Offline</button>
<button class="btn btn-success" disabled id="btn-pan-left">3. Pan left</button>
</div>
<img id="img-offline-indicator" src="../samples/images/blue-pin.png"/>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div id="mapDiv"></div>
</div>
</div>
</div>
</div><!-- id="code" -->
</div><!-- id="myTabContent" -->
</div><!-- id="step4" -->
</br>
</div><!-- class="tab-content well" -->
</div><!-- class="col-sm-12 col-md-12 col-lg-12" -->
<hr>
</div> <!-- /container -->
<!-- mapping code -->
<script src="../vendor/offline/offline.min.js"></script>
<div class="panel-body">
<div class="panel panel-default">
<div class="panel-heading">
<h4><b>Choose</b> from the following tutorials</h4>
</div>
<div class="list-group">
<a href="getstarted-tiles.html" class="list-group-item blue-link">Offline Tiled Map Services</a>
<a href="getstarted-agol.html" class="list-group-item blue-link">Offline ArcGIS Online tiled maps</a>
<a href="getstarted-editing.html" class="list-group-item blue-link">Offline Editing</a>
<a href="getstarted-tpk.html" class="list-group-item blue-link">Offline TPKs (Tile Packages)</a>
</div>
</div>
</div>
<div class="panel-body">
<div class="panel panel-default">
<div class="panel-heading">
<h4><b>Fork or clone</b> <i>offline-editor-js</i></h4>
</div>
<div class="panel-body">
<p>Here are the important directories to know:</p>
<ul>
<li><b>\dist</b> - minified library files and concatenated source (for debugging).</li>
<li><b>\samples</b> - more examples that demonstrate the library's functionality.</li>
<li><b>\vendor</b> - contains IndexedDBShim and offline.js helper libraries</li>
</ul>
<br>
<a href="http://github.com/Esri/offline-editor-js"><button type="button" class="btn btn-md btn-success">Fork on GitHub</button></a>
</div>
</div>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
// Set the online/offline detection options.
// More info at: http://github.hubspot.com/offline/docs/welcome/
Offline.options = {
checks: {
image: {
url: function() {
return 'http://esri.github.io/offline-editor-js/tiny-image.png?_=' +
(Math.floor(Math.random() * 1000000000));
}
},
active: 'image'
}
}
$(document).ready(function() {
$("#header").load("../demo/header.html");
});
</script>
<!-- Include a reference to IndexedDBShim for library to work on Safari 7.x -->
<script src="../vendor/IndexedDBShim/dist/IndexedDBShim.js"></script>
<script src="http://js.arcgis.com/3.10/"></script>
<script>
var map;
// Make sure to reference the offline tiles library within the require statement!
require(["esri/map","dojo/on","//esri.github.com/bootstrap-map-js/src/js/bootstrapmap.js","../dist/offline-tiles-advanced-min.js", "dojo/domReady!"],
function(Map,on,Bootstrapmap){
// Check if browser state is online or offline
Offline.check();
Offline.on('up down', updateState );
// For cancelling the download of tiles
var _wantToCancel;
// Set up min and max boundaries for retrieving tiles
var minZoomAdjust = -1, maxZoomAdjust = 1, mMinZoom, mMaxZoom;
// Set up button click listeners.
var btnGetTiles = document.getElementById("btn-get-tiles");
var btnOnlineOffline = document.getElementById("btn-online-offline");
var btnPanLeft = document.getElementById("btn-pan-left");
var imgOfflineIndicator = document.getElementById("img-offline-indicator");
var redPinPath = "../samples/images/red-pin.png";
var bluePinPath = "../samples/images/blue-pin.png"
on(btnGetTiles,"click",downloadTiles);
on(btnOnlineOffline,"click",goOnlineOffline);
on(btnPanLeft,"click",panLeft);
$(document).ready(function () {
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
if (e.target.text === "Map") {
showMap("mapDiv");
}
});
});
function showMap(){
if(map){
map.destroy();
}
map = Bootstrapmap.create("mapDiv",{
//basemap: "topo", // comment out this basemap!
center: [-122.45, 37.75], // longitude, latitude
zoom: 15
});
// Now we initialize the basemap to be offline-enabled. This is out new basemap.
tileLayer = O.esri.Tiles.OfflineTileEnablerLayer(
"http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer",
function(evt){
console.log("Offline tile lib enabled. App is: " + Offline.state);
},
true);
// Set the min and max zoom for when retrieving tiles
map.on("load",function(evt){
tileLayer.getMaxZoom(function(result){
mMaxZoom = result;
});
tileLayer.getMinZoom(function(result){
mMinZoom = result;
});
})
// Add our offline tile layer to the map instead of using the default basemap!
map.addLayer(tileLayer);
}
function downloadTiles(){
// First we need to empty the database.
tileLayer.deleteAllTiles(function(success,err){
var zoom = getMinMaxZoom();
var extent = tileLayer.getExtentBuffer(0,map.extent);
// Begin downloading tiles
tileLayer.prepareForOffline(zoom.min, zoom.max, extent, function(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 )
{
alert("Tile download was cancelled");
}
else
{
alert("Tile download complete");
}
btnGetTiles.innerHTML = '1. Download Tiles';
btnOnlineOffline.disabled = false;
btnGetTiles.disabled = true;
}
return _wantToCancel; //determines if a cancel request has been issued
});
});
}
// Force the tileLayer between online and offline
function goOnlineOffline(){
btnPanLeft.disabled = false;
if(btnOnlineOffline.innerHTML == "2. Go Offline"){
btnOnlineOffline.innerHTML = "2. Go Online";
tileLayer.goOffline();
imgOfflineIndicator.src = redPinPath;
console.log("tileLayer is offline");
}
else{
btnOnlineOffline.innerHTML = "2. Go Offline";
tileLayer.goOnline();
imgOfflineIndicator.src = bluePinPath;
console.log("tileLayer is online");
}
}
// Set the tileLayer online or offline.
// When set to offline, the map will look for tiles in the tiles database
function updateState(){
if(Offline.state === 'up'){
if(typeof tileLayer != "undefined") tileLayer.goOnline();
imgOfflineIndicator.src = bluePinPath;
}
else{
if(typeof tileLayer != "undefined") tileLayer.goOffline();
imgOfflineIndicator.src = redPinPath;
}
}
// Utility function to validate min and max zoom settings of the map
function getMinMaxZoom(){
var zoom = {};
var min = tileLayer.getLevel() + minZoomAdjust;
var max = tileLayer.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 panLeft(){
map.panLeft();
}
});
</script>
<!-- Bootstrap core JavaScript
================================================== -->

15
demo/header.html Normal file
View File

@ -0,0 +1,15 @@
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand-title" href="index.html">Offline-editor-js</a>
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li class="active dropdown" id="tutorialList">
<a href="getstarted.html">Get Started </a>
</li>
<li><a href="api-doc.html">API Docs</a></li>
</ul>
</div>
</div>
</div>

View File

@ -19,6 +19,9 @@
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<style>
.voffset20px {padding-top: 20px;}
</style>
</head>
<body>
@ -27,18 +30,7 @@
<img style="position: absolute; top: 50; right: 0; border: 0; width:150px;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_green_007200.png" alt="Fork me on GitHub">
</a>
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand-title" href="#">Offline-editor-js</a>
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li><a href="getstarted.html">Get Started</a></li>
</ul>
</div>
</div>
</div>
<header id="header"></header>
<!-- Main jumbotron for a primary marketing message or call to action -->
<div class="jumbotron">
@ -67,27 +59,34 @@
</div>
<hr>
<div class="container">
<div class="row">
<h1 id="examples" class="page-header">Get Started</h1>
<p class="lead">Go <a href="../demo/getstarted.html"> here</a> to try out basic step-by-step samples. </p>
</div>
</div>
</div> <!-- /container -->
<div class="container">
<div class="bs-docs-section">
<h1 id="examples" class="page-header">Examples</h1>
<p class="lead">Use the following applications as building blocks. </p>
<p class="lead">Check out the following full-featured applications. </p>
<div class="row bs-examples">
<div class="col-xs-6 col-md-4">
<div class="col-xs-4 col-md-4">
<a class="thumbnail" href="../samples/tiles-indexed-db.html">
<img src="images/tiles-demo-thumb.png">
</a>
<h3>Tiles Only</h3>
<p>Gives you an overview of the functionality related to storing and managing multiple layers of tiles.</p>
</div>
<div class="col-xs-6 col-md-4">
<div class="col-xs-4 col-md-4">
<a class="thumbnail" href="../samples/draw-pointlinepoly-offline.html">
<img src="images/cop-demo-thumb.png">
</a>
<h3>Feature Editing</h3>
<p>This app shows how add, update and delete geographic features while offline and auto-resync when internet is reestablished. </p>
</div>
<div class="col-xs-6 col-md-4">
<div class="col-xs-4 col-md-4">
<a class="thumbnail" href="../samples/attachments-editor.html">
<img src="images/attachments-demo-thumb.png">
</a>
@ -95,22 +94,22 @@
<p>Demonstrates working with geographic feature attachments such as images and associating them with a feature while offline.</p>
</div>
</div>
<div class="row bs-examples">
<div class="col-xs-6 col-md-4">
<div class="row bs-examples voffset20px">
<div class="col-xs-4 col-md-4">
<a class="thumbnail" href="../samples/tpk-layer.html">
<img src="images/tpk-demo-thumb.png">
</a>
<h3>TPK Only</h3>
<p>Shows how to integrate <a href="http://resources.arcgis.com/en/help/main/10.1/index.html#//006600000457000000">.tpk files</a> into your mapping app. Tile packages are a set of tile images from a map compressed into a single binary file.</p>
</div>
<div class="col-xs-6 col-md-4">
<div class="col-xs-4 col-md-4">
<a class="thumbnail" href="../samples/appcache-features.html">
<img src="images/appcachefeatures-demo-thumb.png">
</a>
<h3>AppCache Features and Tiles</h3>
<p>This mobile feature editing demo is configured to maintain your edits and tiles after offline browser reloads and restarts.</p>
</div>
<div class="col-xs-6 col-md-4">
<div class="col-xs-4 col-md-4">
<a class="thumbnail" href="../samples/appcache-tiles.html">
<img src="images/appcachetiles-demo-thumb.png">
</a>
@ -173,12 +172,17 @@
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
$("#header").load("../demo/header.html");
});
</script>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
</body>
</html>

View File

@ -0,0 +1,162 @@
.mod-popup-div {
opacity: 0;
height: 0;
width: 0;
z-index: 98;
font-size: x-large;
position: absolute;
top: 0px;
left: -1000px;
}
.mod-popup-body {
position: relative;
top: 10%;
left: 10%;
z-index: 100;
height: 80%;
width: 80%;
border-radius: 10px;
background-color: black;
display: table;
opacity: 0.7;
}
.mod-popup-modal-background {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
opacity: 0.5;
background-color: black;
z-index: 99;
display: table;
}
.mod-popup-input {
border-bottom: solid #ffffff 1px;
width: 80%;
display: table-cell;
vertical-align: middle;
padding: 12px;
}
.mod-popup-label {
padding: 12px;
width: 20%;
display: table-cell;
vertical-align: middle;
background-color: dimgrey;
}
.mod-popup-label-top-left {
padding: 12px;
width: 20%;
display: table-cell;
vertical-align: middle;
background-color: dimgray;
border-top-left-radius: 10px;
}
.mod-popup-table-row {
color: white;
border-radius: 10px;
display: table-row;
}
.mod-popup-stop-input {
border-radius: 5px;
font-size: x-large;
width: 90%;
height: 75%;
padding: 5px;
}
.mod-popup-stop-input-disabled {
color: white;
border-radius: 5px;
font-size: x-large;
background-color: dimgray;
opacity: 1.0; /* For safari display bug */
padding: 5px;
width: 90%;
height: 75%;
}
.mod-popup-button {
position: relative;
float: left;
color: #ffffff;
font-size: x-large;
border-radius: 10px;
width: 45%;
padding: 8px;
background-color: #000000;
border: solid #ffffff 2px;
}
.mod-popup-button:active {
position: relative;
float: left;
color: #000000;
font-size: x-large;
border-radius: 10px;
width: 45%;
padding: 8px;
background-color: lightyellow;
border: solid #ffffff 2px;
}
.mod-popup-button-cancel {
position: relative;
float: left;
color: lightgray;
font-size: x-large;
border-radius: 10px;
width: 100%;
padding: 8px;
background-color: #000000;
border: solid lightgray 1px;
}
.mod-popup-button-cancel:active {
position: relative;
float: left;
color: #000000;
font-size: x-large;
border-radius: 10px;
width: 100%;
padding: 8px;
background-color: lightyellow;
border: solid lightgray 1px;
}
.mod-popup-button-div {
padding: 12px;
display: table-cell;
vertical-align: middle;
background-color: #000000;
}
.mod-popup-button-div-bottom-left {
padding: 12px;
display: table-cell;
vertical-align: middle;
background-color: #000000;
border-bottom-left-radius: 8px;
}
@media (max-width: 500px) {
.mod-popup-button {
font-size: small;
}
.mod-popup-button:active{
font-size: small;
}
.mod-popup-button-cancel {
font-size: small;
}
.mod-popup-button-cancel:active {
font-size: small;
}
}
@media (max-width: 450px) {
.mod-popup-button {
font-size: x-small;
}
.mod-popup-button:active{
font-size: x-small;
}
.mod-popup-button-cancel {
font-size: x-small;
}
.mod-popup-button-cancel:active {
font-size: x-small;
}
}

View File

@ -0,0 +1,71 @@
/**
* Modal Popup Widget
* This widget provides a basic framework for building modal popups
* for mobile GIS web applications.
* @author @agup
*/
define([
"dojo/_base/declare", "dojo/parser", "dojo/ready",
"dijit/_WidgetBase", "dijit/_TemplatedMixin","dojo/query",
"dojo/text!./template/popup.html","dojo/NodeList-manipulate"
], function(declare, parser, ready, _WidgetBase, _TemplatedMixin,query,template){
return declare("ModalPopup", [_WidgetBase, _TemplatedMixin], {
options: {
animation: false,
animationDuration: 1
},
templateString: template,
constructor: function (options, srcRefNode) {
// mix in settings and defaults
declare.safeMixin(this.options, options);
// widget node
this.domNode = srcRefNode;
// Set properties
this.set("animation", this.options.animation);
this.set("animationDuration", this.options.animationDuration);
},
show: function () {
if(this.animation){
// You can design any animation you want!
this.domNode.style.opacity = 1;
this.domNode.style.left = 0;
this.domNode.style.top = 0;
this.domNode.style.width = "100%";
this.domNode.style.height = "100%";
this.domNode.style.transition = "all " + this.animationDuration + "s linear 0s";
}
else{
this.domNode.style.position = "static";
}
},
hide: function () {
if(this.animation){
// You can design any animation you want!
this.domNode.style.height = 0;
this.domNode.style.width = 0;
this.domNode.style.opacity = 0;
this.domNode.style.top = "0px";
this.domNode.style.left = -1000 + "px";
this.domNode.style.transition = "all " + this.animationDuration + "s ease-in-out 0s";
}
else{
this.domNode.style.position = "absolute";
}
},
// connections/subscriptions will be cleaned up during the destroy() lifecycle phase
destroy: function () {
this.inherited(arguments);
}
});
});

View File

@ -0,0 +1,46 @@
<div id="mod-popup" class="mod-popup-div">
<!--
MODAL POPUP TEMPLATE
This is a customizable template for creating modal popups.
Feel free to modify this to fit the properties of your own feature service.
-->
<div id="mod-popup-b" class="mod-popup-body">
<div id="row1" class="mod-popup-table-row">
<div class="mod-popup-label-top-left">ID</div>
<div class="mod-popup-input">
<input id="stop-main-id" type="text" disabled class="mod-popup-stop-input-disabled" value="test"/>
</div>
</div>
<div id="row2" class="mod-popup-table-row">
<div class="mod-popup-label">Bustop ID</div>
<div class="mod-popup-input">
<input id="stop-id" disabled class="mod-popup-stop-input-disabled" value="test"/>
</div>
</div>
<div id="row3" class="mod-popup-table-row">
<div class="mod-popup-label">Routes</div>
<div class="mod-popup-input">
<input id="stop-routes" class="mod-popup-stop-input" value="test"/>
</div>
</div>
<div id="row4" class="mod-popup-table-row">
<div class="mod-popup-label">Stopnames</div>
<div class="mod-popup-input">
<input id="stop-names" class="mod-popup-stop-input" value="test"/>
</div>
</div>
<div id="row5" class="mod-popup-table-row">
<div class="mod-popup-button-div-bottom-left">
<button id="mod-popup-close-btn" class="mod-popup-button-cancel" >Close</button>
</div>
<div class="mod-popup-button-div">
<button id="mod-popup-save-btn" class="mod-popup-button" style="margin-right: 10px;">Save</button>
<button id="mod-popup-delete-btn" disabled class="mod-popup-button" style="background-color: grey; text-decoration:line-through;">Delete</button>
</div>
</div>
</div>
<div id="modal-background" class="mod-popup-modal-background"></div>
</div>

View File

@ -1,4 +1,4 @@
/*! offline-editor - v2.2 - 2014-09-30
/*! offline-editor-js - v2.3 - 2014-10-13
* Copyright (c) 2014 Environmental Systems Research Institute, Inc.
* Apache License*/

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
/*! offline-editor - v2.2 - 2014-09-30
/*! offline-editor-js - v2.3 - 2014-10-13
* Copyright (c) 2014 Environmental Systems Research Institute, Inc.
* Apache License*/
define([
@ -193,22 +193,9 @@ define([
getMaxZoom: function(callback){
if(this._maxZoom == null){
var lods = this.tileInfo.lods;
var length = this.tileInfo.lods.length;
var tempArr = [];
for(var i=0; i < length; i++){
tempArr.push(lods[i].level);
if(i == length -1){
tempArr.sortNumber();
this._maxZoom = tempArr[i];
callback(tempArr[i]);
}
}
this._maxZoom = this.tileInfo.lods[this.tileInfo.lods.length-1].level;
}
else{
callback(this._maxZoom);
}
callback(this._maxZoom);
},
/**
@ -218,21 +205,38 @@ define([
getMinZoom: function(callback){
if(this._minZoom == null){
var lods = this.tileInfo.lods;
var length = this.tileInfo.lods.length;
var tempArr = [];
for(var i=0; i < length; i++){
tempArr.push(lods[i].level);
if(i == length -1){
tempArr.sortNumber();
this._minZoom = tempArr[0];
callback(tempArr[0]);
}
}
this._minZoom = this.tileInfo.lods[0].level;
}
callback(this._minZoom);
},
/**
* Utility method for bracketing above and below your current Level of Detail. Use
* this in conjunction with setting the minLevel and maxLevel in prepareForOffline().
* @param minZoomAdjust An Integer specifying how far above the current layer you want to retrieve tiles
* @param maxZoomAdjust An Integer specifying how far below (closer to earth) the current layer you want to retrieve tiles
*/
getMinMaxLOD: function(minZoomAdjust,maxZoomAdjust){
var zoom = {};
var map = this.getMap();
var min = map.getLevel() + minZoomAdjust;
var max = map.getLevel() + maxZoomAdjust;
if(this._maxZoom != null && this._minZoom != null){
zoom.max = Math.min(this._maxZoom, max); //prevent errors by setting the tile layer floor
zoom.min = Math.max(this._minZoom, min); //prevent errors by setting the tile layer ceiling
}
else{
callback(this._minZoom);
this.getMinZoom(function(result){
zoom.min = Math.max(result, min); //prevent errors by setting the tile layer ceiling
});
this.getMaxZoom(function(result){
zoom.max = Math.min(result, max); //prevent errors by setting the tile layer floor
});
}
return zoom;
},
/**
@ -805,7 +809,7 @@ O.esri.Tiles.TilesCore = function(){
*/
this._getTiles = function(image,imageType,url,tileid,store,query){
store.retrieve(url, function(success, offlineTile)
{ console.log("TILE RETURN " + success + ", " + offlineTile)
{ console.log("TILE RETURN " + success + ", " + offlineTile.url)
/* when the .getTileUrl() callback is triggered 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
image = query("img[src="+tileid+"]")[0];

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
/*! offline-editor - v2.2 - 2014-09-30
/*! offline-editor-js - v2.3 - 2014-10-13
* Copyright (c) 2014 Environmental Systems Research Institute, Inc.
* Apache License*/
define([
@ -37,6 +37,8 @@ define([
layer._tilesCore = new O.esri.Tiles.TilesCore();
layer._lastTileUrl = "";
layer._imageType = "";
layer._minZoom = null;
layer._maxZoom = null;
/* 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 */
@ -242,6 +244,59 @@ define([
layer._tilesCore._loadFromFile(file,this.offline.store,callback);
};
/**
* Returns the maximum zoom level for this layer
* @param callback number
*/
layer.getMaxZoom = function(callback){
// TO-DO make this a simple return rather than a callback
if(this._maxZoom == null){
this._maxZoom = layer.tileInfo.lods[layer.tileInfo.lods.length-1].level;
}
callback(this._maxZoom);
},
/**
* Returns the minimum zoom level for this layer
* @param callback number
*/
layer.getMinZoom = function(callback){
// TO-DO make this a simple return rather than a callback
if(this._minZoom == null){
this._minZoom = layer.tileInfo.lods[0].level;
}
callback(this._minZoom);
};
/**
* Utility method for bracketing above and below your current Level of Detail. Use
* this in conjunction with setting the minLevel and maxLevel in prepareForOffline().
* @param minZoomAdjust An Integer specifying how far above the current layer you want to retrieve tiles
* @param maxZoomAdjust An Integer specifying how far below (closer to earth) the current layer you want to retrieve tiles
*/
layer.getMinMaxLOD = function(minZoomAdjust,maxZoomAdjust){
var zoom = {};
var map = layer.getMap();
var min = map.getLevel() + minZoomAdjust;
var max = map.getLevel() + maxZoomAdjust;
if(this._maxZoom != null && this._minZoom != null){
zoom.max = Math.min(this._maxZoom, max); //prevent errors by setting the tile layer floor
zoom.min = Math.max(this._minZoom, min); //prevent errors by setting the tile layer ceiling
}
else{
layer.getMinZoom(function(result){
zoom.min = Math.max(result, min); //prevent errors by setting the tile layer ceiling
});
layer.getMaxZoom(function(result){
zoom.max = Math.min(result, max); //prevent errors by setting the tile layer floor
});
}
return zoom;
};
/* internal methods */
/**
@ -668,7 +723,7 @@ O.esri.Tiles.TilesCore = function(){
*/
this._getTiles = function(image,imageType,url,tileid,store,query){
store.retrieve(url, function(success, offlineTile)
{ console.log("TILE RETURN " + success + ", " + offlineTile)
{ console.log("TILE RETURN " + success + ", " + offlineTile.url)
/* when the .getTileUrl() callback is triggered 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
image = query("img[src="+tileid+"]")[0];

View File

@ -1,4 +1,4 @@
/*! offline-editor - v2.2 - 2014-09-30
/*! offline-editor-js - v2.3 - 2014-10-13
* Copyright (c) 2014 Environmental Systems Research Institute, Inc.
* Apache License*/
/**

View File

@ -3,7 +3,7 @@ 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/). 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, also sometimes referred to as the 'manifest file', will allow you to store any file that is required for offline use. The list of acceptable files includes html, 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, also sometimes referred to as the 'manifest file', will allow you to store any file that is required for offline use. The list of acceptable files that you can store includes html, JavaScript libraries, CSS and images. Any file that your application requires to run normally will have to be referenced in the application cache. This is not to be confused with the Local Storage API.
Once an application and its associated files are stored in the application cache it will be available from the cache the next time an application restarts.
@ -35,6 +35,27 @@ NOTE: You cannot use the regular CDN for the ArcGIS API for JavaScript because t
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.
### IMPORTANT Usage Tips
The application cache isn't ready until the `CACHE_LOADED` event fires. After that event a user can safely take the application offline. Sometimes files can load very slowwwwwly, and sometimes they can timeout. Be sure to take this into account.
If ANY file specified in the application cache fails to load for any reason, then the entire load will be rejected by the browser. The entire application cache will fail to load and no files will from the loading process will be cached.
There may be differences in the amount of application cache storage available between desktop browsers, mobile browsers and browsers that use WebView (e.g. PhoneGap). If this is mission critical for you, we strongly recommend that you do your own testing to verify the facts.
Use an application cache validator, for example: [http://manifest-validator.com/](http://manifest-validator.com/)
Too large of an application can cause a mobile browser to run slugglishly or crash frequently. Be aware of how large the application cache is. To check the size:
* Chrome - [chrome://appcache-internals/](chrome://appcache-internals/). This gives you access to all files stored for each application, and the total size of each cache.
* Firefox - Menu (or on Mac go to Firefox > preferences) > advanced > Network.
* For firefox Mobile user will be prompted after first 5MBs have been consumed.
* Note, you can also increase the amount of storage here by checking 'Override automatic cache manage' and enter a new limit value. Or, type about:config in address bar > modify the value field for `browser.cache.disk.capacity`.
* Note: firefox has a theoretical upper bound of [1GB](http://mxr.mozilla.org/mozilla-central/source/netwerk/cache/nsCacheService.cpp#607) and apparently a tested/verified(?) upper bound of [500MB](http://www.html5rocks.com/en/tutorials/offline/quota-research/) on Android.
* Safari - Developer Tools > Show Web Inspector > Application Cache (click on the cookie crumbs at the top left of the console window). this won't give you the total size, but you can at least see what is in the cache and each objects size.
###Configuring your web server
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.
@ -65,8 +86,12 @@ Most modern browsers support application cache including IE v10 and v11, Firefox
### References
[Offline web applications - Quota Research](http://www.html5rocks.com/en/tutorials/offline/quota-research/)
[Support for application cache](http://caniuse.com/#search=appcache)
[Appcache Facts](http://appcachefacts.info/)
[Using the application cache - Mozilla Developer Network](https://developer.mozilla.org/en-US/docs/Web/HTML/Using_the_application_cache)
[Using the application cache - Mozilla Developer Network](https://developer.mozilla.org/en-US/docs/Web/HTML/Using_the_application_cache)
[Safari Client-side Storage and Offline Applications](https://developer.apple.com/library/safari/documentation/iPhone/Conceptual/SafariJSDatabaseGuide/OfflineApplicationCache/OfflineApplicationCache.html)

View File

@ -1,8 +1,8 @@
API OfflineFeaturesManager
==================================
==========================
##O.esri.Edit.OfflineFeaturesManager
Extends and overrides a feature layer. This library allows you to extend esri.layers.FeatureLayer objects with offline capability and manage the resync process.
The `offline-edit-min.js` library provides the following tools for working with esri.layers.FeatureLayer objects while partially or fully offline.
###Constructor

View File

@ -3,74 +3,37 @@ API Doc for OfflineTilesEnabler
There are two different libraries for taking tiles offline: `offline-tiles-basic-min.js` and `offline-tiles-advanced-min.js`. The basic library is for use with ArcGIS.com web maps and partial/intermittently offline use cases. You won't be able to restart or reload your app when using this library offline.
If you have a requirement for restarting or reloading the app while offline then you should use the advanced library. The `offline-tiles-advanced-min.js` library lets you create a custom basemap layer that extends TiledMapServiceLayer. To view the docs for this library scroll down on this page.
If you have a requirement for restarting or reloading the app while offline then you should use the advanced library. The `offline-tiles-advanced-min.js` library lets you create a custom basemap layer that extends TiledMapServiceLayer.
##O.esri.Tiles.OfflineTilesEnabler
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.
The `offline-tiles-basic-min.js` library provides the following tools for working with with ArcGIS.com maps or tiled map services in partial-offline situations that don't require a browser restart or reload.
###Constructor
Constructor | Description
--- | ---
`O.esri.Tiles.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.
###Properties
Property | Description
--- | ---
`layer.offline.proxyPath`| The default is `null`. If you have a CORS-enabled service then use the default. 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).
###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.
`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.
`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.
`prepareForOffline(` `minLevel, maxLevel, extent, ` `reportProgress)` | `callback(number)` | Retrieves tiles and stores them in the local cache. For more information see [How To Use Tiles Library](howtousetiles.md).
`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 IndexedDB 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.
`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 `"esri/geometry/Extent"`, zoom level `integer`, and the estimated byte size `integer`. 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 | `buffer` property is an `integer`. `extent` property is an `"esri/geometry/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 `"esri/geometry/Extent"` and zoom level `integer`.
`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.
###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).
##O.esri.Tiles.OfflineTilesEnablerLayer
Extends and overrides a tiled map service. This library can be used in situations where an offline browser restart or reload is required.
###Constructor
Constructor | Description
--- | ---
`O.esri.Tiles.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).
`getMinZoom(callback)` | `callback(number)` | Returns the minimum zoom level of the layer. This is the zoom level farther away from the earth.
`getMaxZoom(callback)` | `callback(number)` | Returns the maximum zoom level of the layer. This is the zoom level closest to the earth.
`getMinMaxLOD(minZoomAdjust,` `maxZoomAdjust)` | `{min: zoomLevel, max: zoomLevel}` | Utility method for bracketing above and below your current Level of Detail. Use this in conjunction with setting the minLevel and maxLevel in `prepareForOffline()`. `minZoomAdjust` is an Integer specifying how far above the current layer you want to retrieve tiles. `maxZoomAdjust` is an Integer specifying how far below (closer to earth) the current layer you want to retrieve tiles

View File

@ -0,0 +1,40 @@
API Doc for OfflineTilesEnablerLayer
====================================
There are two different libraries for taking tiles offline: `offline-tiles-basic-min.js` and `offline-tiles-advanced-min.js`. The basic library is for use with ArcGIS.com web maps and partial/intermittently offline use cases. You won't be able to restart or reload your app when using this library offline.
If you have a requirement for restarting or reloading the app while offline then you should use the advanced library. The `offline-tiles-advanced-min.js` library lets you create a custom basemap layer that extends TiledMapServiceLayer.
##O.esri.Tiles.OfflineTilesEnablerLayer
The `offline-tiles-advanced-min.js` library provides the following tools for working with tiled map services. This library is designed for both partial and full offline use cases, and it will work if you have a requirement for browser reloads or restarts while offline.
###Constructor
Constructor | Description
--- | ---
`O.esri.Tiles.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`.
###Properties
Property | Description
--- | ---
`layer.offline.proxyPath`| For CORS enabled servers this can be set to `null`. The default is null. All ArcGIS Online-based services uses CORS. If you are using a non-CORS enabled server you'll need a proxy. 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).
###Methods
Methods | Returns | Description
--- | --- | ---
`prepareForOffline(` `minLevel, maxLevel, extent, ` `reportProgress)` | `callback(number)` | Retrieves tiles and stores them in the local cache. For more information see [How To Use Tiles Library](howtousetiles.md).
`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 `"esri/geometry/Extent"`, zoom level `integer`, and the estimated byte size `integer`. 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 | `buffer` property is an `integer`. `extent` property is an `"esri/geometry/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.
`getMaxZoom(callback)` | `callback(number)` | Returns the maximum zoom level of the layer.
`getMinZoom(callback)` | `callback(number)` | Returns the minimum zoom level of the layer.
`getMinMaxLOD(minZoomAdjust,` `maxZoomAdjust)` | `{min: zoomLevel, max: zoomLevel}` | Utility method for bracketing above and below your current Level of Detail. Use this in conjunction with setting the minLevel and maxLevel in `prepareForOffline()`. `minZoomAdjust` is an Integer specifying how far above the current layer you want to retrieve tiles. `maxZoomAdjust` is an Integer specifying how far below (closer to earth) the current layer you want to retrieve tiles

View File

@ -3,7 +3,7 @@ API Doc for TPKLayer
##O.esri.TPK.TPKLayer
Extends a tiled map service and provides the ability to display tiles from a .tpk (ArcGIS Tile Page).
The `offline-tpk-min.js` library extends a tiled map service and provides the following tools for working with and displaying tiles from a .tpk file (ArcGIS Tile Package).
###Constructor

View File

@ -190,22 +190,9 @@ define([
getMaxZoom: function(callback){
if(this._maxZoom == null){
var lods = this.tileInfo.lods;
var length = this.tileInfo.lods.length;
var tempArr = [];
for(var i=0; i < length; i++){
tempArr.push(lods[i].level);
if(i == length -1){
tempArr.sortNumber();
this._maxZoom = tempArr[i];
callback(tempArr[i]);
}
}
this._maxZoom = this.tileInfo.lods[this.tileInfo.lods.length-1].level;
}
else{
callback(this._maxZoom);
}
callback(this._maxZoom);
},
/**
@ -215,21 +202,38 @@ define([
getMinZoom: function(callback){
if(this._minZoom == null){
var lods = this.tileInfo.lods;
var length = this.tileInfo.lods.length;
var tempArr = [];
for(var i=0; i < length; i++){
tempArr.push(lods[i].level);
if(i == length -1){
tempArr.sortNumber();
this._minZoom = tempArr[0];
callback(tempArr[0]);
}
}
this._minZoom = this.tileInfo.lods[0].level;
}
callback(this._minZoom);
},
/**
* Utility method for bracketing above and below your current Level of Detail. Use
* this in conjunction with setting the minLevel and maxLevel in prepareForOffline().
* @param minZoomAdjust An Integer specifying how far above the current layer you want to retrieve tiles
* @param maxZoomAdjust An Integer specifying how far below (closer to earth) the current layer you want to retrieve tiles
*/
getMinMaxLOD: function(minZoomAdjust,maxZoomAdjust){
var zoom = {};
var map = this.getMap();
var min = map.getLevel() + minZoomAdjust;
var max = map.getLevel() + maxZoomAdjust;
if(this._maxZoom != null && this._minZoom != null){
zoom.max = Math.min(this._maxZoom, max); //prevent errors by setting the tile layer floor
zoom.min = Math.max(this._minZoom, min); //prevent errors by setting the tile layer ceiling
}
else{
callback(this._minZoom);
this.getMinZoom(function(result){
zoom.min = Math.max(result, min); //prevent errors by setting the tile layer ceiling
});
this.getMaxZoom(function(result){
zoom.max = Math.min(result, max); //prevent errors by setting the tile layer floor
});
}
return zoom;
},
/**

View File

@ -16,7 +16,7 @@ O.esri.Tiles.TilesCore = function(){
*/
this._getTiles = function(image,imageType,url,tileid,store,query){
store.retrieve(url, function(success, offlineTile)
{ console.log("TILE RETURN " + success + ", " + offlineTile)
{ console.log("TILE RETURN " + success + ", " + offlineTile.url)
/* when the .getTileUrl() callback is triggered 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
image = query("img[src="+tileid+"]")[0];

View File

@ -34,6 +34,8 @@ define([
layer._tilesCore = new O.esri.Tiles.TilesCore();
layer._lastTileUrl = "";
layer._imageType = "";
layer._minZoom = null;
layer._maxZoom = null;
/* 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 */
@ -239,6 +241,59 @@ define([
layer._tilesCore._loadFromFile(file,this.offline.store,callback);
};
/**
* Returns the maximum zoom level for this layer
* @param callback number
*/
layer.getMaxZoom = function(callback){
// TO-DO make this a simple return rather than a callback
if(this._maxZoom == null){
this._maxZoom = layer.tileInfo.lods[layer.tileInfo.lods.length-1].level;
}
callback(this._maxZoom);
},
/**
* Returns the minimum zoom level for this layer
* @param callback number
*/
layer.getMinZoom = function(callback){
// TO-DO make this a simple return rather than a callback
if(this._minZoom == null){
this._minZoom = layer.tileInfo.lods[0].level;
}
callback(this._minZoom);
};
/**
* Utility method for bracketing above and below your current Level of Detail. Use
* this in conjunction with setting the minLevel and maxLevel in prepareForOffline().
* @param minZoomAdjust An Integer specifying how far above the current layer you want to retrieve tiles
* @param maxZoomAdjust An Integer specifying how far below (closer to earth) the current layer you want to retrieve tiles
*/
layer.getMinMaxLOD = function(minZoomAdjust,maxZoomAdjust){
var zoom = {};
var map = layer.getMap();
var min = map.getLevel() + minZoomAdjust;
var max = map.getLevel() + maxZoomAdjust;
if(this._maxZoom != null && this._minZoom != null){
zoom.max = Math.min(this._maxZoom, max); //prevent errors by setting the tile layer floor
zoom.min = Math.max(this._minZoom, min); //prevent errors by setting the tile layer ceiling
}
else{
layer.getMinZoom(function(result){
zoom.min = Math.max(result, min); //prevent errors by setting the tile layer ceiling
});
layer.getMaxZoom(function(result){
zoom.max = Math.min(result, max); //prevent errors by setting the tile layer floor
});
}
return zoom;
};
/* internal methods */
/**

View File

@ -1,6 +1,6 @@
{
"name": "offline-editor",
"version": "2.2",
"name": "offline-editor-js",
"version": "2.3",
"description": "Lighweight set of libraries for working offline with map tiles and ArcGIS feature services",
"author": "Andy Gup <agup@esri.com> (http://blog.andygup.net)",
"license": "Apache 2",

View File

@ -25,27 +25,35 @@ module.exports = function(grunt) {
"<%= pkg.appHomePage %>",
"#",
"# ArcGIS API for JavaScript files",
"<%= pkg.optimizedApiURL %>/dojo/dojo.js",
"<%= pkg.optimizedApiURL %>/dojo/nls/dojo_en-us.js",
"<%= pkg.optimizedApiURL %>/dojo/selector/acme.js",
"<%= pkg.optimizedApiURL %>/dojo.js",
"<%= pkg.optimizedApiURL %>/selector/acme.js",
"<%= pkg.optimizedApiURL %>/nls/dojo_en.js",
"<%= pkg.optimizedApiURL %>/resources/blank.gif",
"#",
"#<%= pkg.arcGISBaseURL %>/js/esri/dijit/images/popup-sprite.png",
"<%= pkg.arcGISBaseURL %>/js/esri/dijit/images/attribute_inspector_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",
"<%= 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",
"#<%= pkg.arcGISBaseURL %>/esri/dijit/images/popup-sprite.png",
"<%= pkg.arcGISBaseURL %>/esri/dijit/images/attribute_inspector_sprite.png",
"#<%= pkg.arcGISBaseURL %>/dojo/resources/blank.gif",
"<%= pkg.arcGISBaseURL %>/esri/dijit/images/ajax-loader.gif",
"<%= pkg.arcGISBaseURL %>/esri/images/map/logo-sm.png",
"<%= pkg.arcGISBaseURL %>/esri/images/map/logo-med.png",
"<%= pkg.arcGISBaseURL %>/esri/css/esri.css",
"<%= pkg.arcGISBaseURL %>/dijit/themes/claro/claro.css",
"<%= pkg.arcGISBaseURL %>/esri/nls/jsapi_en-us.js",
"#",
"//services.arcgisonline.com/ArcGIS/rest/info?f=json",
"//static.arcgis.com/attribution/World_Topo_Map?f=json",
"//server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer?f=pjson",
"//services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer?f=json&callback=dojo.io.script.jsonp_dojoIoScript1._jsonpCallback",
"#",
"# required for web maps",
"<%= pkg.arcGISBaseURL %>/js/esri/dijit/images/ajax-loader.gif",
"# Bootstrap files",
"//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css",
"//esri.github.io/bootstrap-map-js/src/css/bootstrapmap.css",
"//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js",
"//esri.github.io/bootstrap-map-js/src/js/bootstrapmap.js",
"https://code.jquery.com/jquery-2.1.1.min.js",
"",
"# Custom feature service",
"http://services.arcgis.com/IZtlGBUe4KTzLOl4/arcgis/rest/services/BPX_RTD_BusStops2/FeatureServer/0?f=json",
"#",
"# required local html",
"# /xyz/style.css",
@ -70,7 +78,14 @@ module.exports = function(grunt) {
"../utils/*.js",
"../dist/offline-edit-src.js",
"../dist/offline-tiles-advanced-src.js",
"../dist/offline-tiles-basic-src.js"
"../dist/offline-tiles-basic-src.js",
"../samples/widgets/modal/css/*.css",
"../samples/widgets/modal/template/*.html",
"../samples/widgets/modal/popup.js",
"<%= pkg.optimizedApiURL %>/nls/*.js",
"<%= pkg.optimizedApiURL %>/resources/*.gif",
"<%= pkg.optimizedApiURL %>/dojo.js",
"<%= pkg.optimizedApiURL %>/selector/*.js"
/*
"images/*",
"css/*.css"

View File

@ -1,35 +1,41 @@
CACHE MANIFEST
# This manifest was generated by grunt-manifest HTML5 Cache Manifest Generator
# Time: Mon Sep 08 2014 11:50:44 GMT-0600 (MDT)
# Time: Fri Oct 10 2014 16:02:50 GMT-0600 (MDT)
CACHE:
# manifest-generator, version: 0.0.1
# manifest-generator, version: 2.3
#
# Home Page
appcache-features.html
#
# ArcGIS API for JavaScript files
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/o/agup_hack4co/appcacheFeatures2/dojo/dojo.js
# http://js.arcgis.com/o/agup_hack4co/appcacheFeatures2/dojo/selector/acme.js
#
#http://js.arcgis.com/3.10/js/esri/dijit/images/popup-sprite.png
http://js.arcgis.com/3.10/js/esri/dijit/images/attribute_inspector_sprite.png
http://js.arcgis.com/3.10/js/dojo/dojox/gfx/svg.js
http://js.arcgis.com/3.10/js/dojo/dojo/resources/blank.gif
http://js.arcgis.com/3.10/js/esri/dijit/images/ajax-loader.gif
http://js.arcgis.com/3.10/js/esri/images/map/logo-sm.png
http://js.arcgis.com/3.10/js/esri/images/map/logo-med.png
http://js.arcgis.com/3.10/js/esri/css/esri.css
http://js.arcgis.com/3.10/js/dojo/dijit/themes/claro/claro.css
http://js.arcgis.com/3.10/js/esri/nls/jsapi_en-us.js
#http://js.arcgis.com/3.11/esri/dijit/images/popup-sprite.png
http://js.arcgis.com/3.11/esri/dijit/images/attribute_inspector_sprite.png
http://js.arcgis.com/3.11/dojo/resources/blank.gif
http://js.arcgis.com/3.11/esri/dijit/images/ajax-loader.gif
http://js.arcgis.com/3.11/esri/images/map/logo-sm.png
http://js.arcgis.com/3.11/esri/images/map/logo-med.png
http://js.arcgis.com/3.11/esri/css/esri.css
http://js.arcgis.com/3.11/dijit/themes/claro/claro.css
http://js.arcgis.com/3.11/esri/nls/jsapi_en-us.js
#
//services.arcgisonline.com/ArcGIS/rest/info?f=json
//static.arcgis.com/attribution/World_Topo_Map?f=json
//server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer?f=pjson
//services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer?f=json&callback=dojo.io.script.jsonp_dojoIoScript1._jsonpCallback
#
# required for web maps
http://js.arcgis.com/3.10/js/esri/dijit/images/ajax-loader.gif
# Bootstrap files
//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css
//esri.github.io/bootstrap-map-js/src/css/bootstrapmap.css
//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js
http://esri.github.io/bootstrap-map-js/src/js/bootstrapmap.js
https://code.jquery.com/jquery-2.1.1.min.js
# Custom feature service
http://services.arcgis.com/IZtlGBUe4KTzLOl4/arcgis/rest/services/BPX_RTD_BusStops2/FeatureServer/0?f=json
#
# required local html
# /xyz/style.css
@ -47,6 +53,14 @@ http://js.arcgis.com/3.10/js/esri/dijit/images/ajax-loader.gif
../dist/offline-edit-src.js
../dist/offline-tiles-advanced-src.js
../dist/offline-tiles-basic-src.js
../samples/widgets/modal/css/modal-popup.css
../samples/widgets/modal/template/popup.html
../samples/widgets/modal/popup.js
../samples/jsolib/nls/dojo_en.js
../samples/jsolib/resources/blank.gif
../samples/jsolib/dojo.js
../samples/jsolib/selector/acme.js
../samples/jsolib/selector/lite.js
NETWORK:
*

View File

@ -1,98 +1,77 @@
<!DOCTYPE html>
<!--<html>-->
<html manifest="appcache-features.appcache">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<!--The viewport meta tag is used to improve the presentation and behavior of the samples
on iOS devices-->
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
<!--
This sample demonstrates using an application manifest to store features and 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/. You can reference the CDN or host it on your
own web server.
Use the Grunt task in the /samples diretory 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.
A few things to know about manifest files:
- You cannot load an online url that has a redirect.
- If there is an error encountered, the manifest file will stop loading
- The /utils/appCacheManager.js library will auto detect if the manifest changed and
ask if you want to reload the application.
-->
<title>AppCache Tiles and Features</title>
<link rel="stylesheet" href="../samples/css/modular-popup.css">
<!-- Bootstrap core CSS -->
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" href="../samples/widgets/modal/css/modal-popup.css">
<link rel="stylesheet" href="http://js.arcgis.com/3.10/js/dojo/dijit/themes/claro/claro.css">
<link rel="stylesheet" href="http://js.arcgis.com/3.10/js/esri/css/esri.css">
<link rel="stylesheet" href="http://js.arcgis.com/3.11/esri/css/esri.css">
<link rel="stylesheet" href="http://esri.github.io/bootstrap-map-js/src/css/bootstrapmap.css">
<style>
html, body, #map {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
#mapDiv {
min-height: 500px;
max-height: 1000px;
}
body {
background-color: #FFF;
background-color: #ffffff;
overflow: hidden;
font-family: "Trebuchet MS";
}
#map {
z-index: 1;
position: absolute;
top: 50px;
left: 0;
}
#button-div1{
position: absolute;
top: 0;
z-index: 2;
background: #000000;
color: #ffffff;
width: 100%;
height: 50px;
}
#right-div{
height: 50px;
position: relative; float: right;
}
#img-offline-indicator{
/*padding: 8px;*/
position: relative; float: right;
position: relative; float: right;
#loader-gif{
visibility: hidden;
}
#popup {
height: 100%;
width: 100%;
z-index: 98;
font-size: x-large;
position: absolute;
top: -9999px !important;
left: -9999px !important;
}
#popup-body {
position: relative;
top: 10%;
left: 10%;
z-index: 100;
height: 80%;
width: 80%;
border-radius: 10px;
background-color: black;
display: table;
opacity: 0.7;
}
.basic-btn{
background-color: #000000;
border-color: #ffffff 1px;
color: #ffffff;
padding: 8px;
position: relative; float: left;
}
#pending-edits{
padding: 8px;
position: relative; float: right;
}
@media (max-width: 500px) {
#pending-edits {
font-size: small;
}
}
@media (max-width: 450px) {
#pending-edits {
font-size: x-small;
}
}
/* Override mod-popup default */
.mod-popup-stop-input {color: black;}
.span-pending {color: blue; padding-left: 1em;}
.floatRight { float: right;}
.container { padding: 20px;}
</style>
<!--<script>-->
<!--// If you need to catch AppCache errors as early as possible to troubleshoot errors.-->
<!--window.applicationCache.addEventListener("error",function(err){-->
<!--console.log("ApplicationCache listener: " + err.toString());-->
<!--if (confirm('There was a problem setting this app up for offline. Reload?')) {-->
<!--window.location.reload();-->
<!--console.log("App cache reloaded");-->
<!--}-->
<!--},false)-->
<!--</script>-->
<script src="../vendor/offline/offline.min.js"></script>
<script>
Offline.options = {
@ -110,79 +89,66 @@
var dojoConfig = {
paths: {
vendor: locationPath + "/../vendor",
utils: locationPath + "/../utils"
utils: locationPath + "/../utils",
widgets: locationPath + "/widgets"
}
}
</script>
<!-- Required when using the offline-editor-js library with Safari -->
<script src="../vendor/IndexedDBShim/dist/IndexedDBShim.js"></script>
<script src="http://js.arcgis.com/o/agup_hack4co/appcacheFeatures/dojo/dojo.js" data-dojo-config="async: true"></script>
<!-- Use this tag below if you are hosting your ArcGIS API for JavaScript files locally -->
<!--<script src="libs/dojo/dojo/dojo.js" data-dojo-config="async: true"></script>-->
<!--
This is a locally hosted optimized build of the ArcGIS JS API
To create your own optimized build go to: http://http://jso.arcgis.com/
-->
<script src="../samples/jsolib/dojo.js" data-dojo-config="async: true"></script>
</head>
<body>
<div id="button-div1">
<button class="basic-btn" id="btn-get-tiles">1. Download Tiles</button>
<button class="basic-btn" data-dojo-type="dijit/form/ToggleButton" id="btn-online-offline">2. Go Offline</button>
<div id="right-div">
<img id="img-offline-indicator" src="../samples/images/blue-pin.png"/>
<div id="pending-edits">Pending edits: 0</div>
<!-- Our buttons and online/offline indicator -->
<div class="container">
<div class="row">
<div class="col-xs-10">
<div class="form form-group btn-group" data-toggle="buttons">
<button class="btn btn-success" id="btn-get-tiles">1. Download Tiles</button>
<button class="btn btn-success" disabled id="btn-online-offline">2. Go Offline</button>
</div>
<span class="span-pending">Pending Edits <span id="span-pending-edits" class="badge">0</span></span>
<img id="loader-gif" src="images/loading.gif"/>
</div>
<div class="col-xs-2">
<!-- this indicates whether app is offline (down) or online (up) -->
<button id="btn-state" class="btn btn-success btn-large floatRight">
<span id="state-span" class="glyphicon glyphicon-link"> Up</span>
</button>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div id="mapDiv"></div>
</div>
</div>
</div>
<div id="popup">
<div id="popup-body">
<div id="row1" class="mod-popup-table-row">
<div class="mod-popup-label-top-left">ID</div>
<div class="mod-popup-input">
<input id="stop-main-id" type="text" disabled class="mod-popup-stop-input-disabled" value="test"/>
</div>
</div>
<div id="row2" class="mod-popup-table-row">
<div class="mod-popup-label">Bustop ID</div>
<div class="mod-popup-input">
<input id="stop-id" disabled class="mod-popup-stop-input-disabled" value="test"/>
</div>
</div>
<div id="row3" class="mod-popup-table-row">
<div class="mod-popup-label">Routes</div>
<div class="mod-popup-input">
<input id="stop-routes" class="mod-popup-stop-input" value="test"/>
</div>
</div>
<div id="row4" class="mod-popup-table-row">
<div class="mod-popup-label">Stopnames</div>
<div class="mod-popup-input">
<input id="stop-names" class="mod-popup-stop-input" value="test"/>
</div>
</div>
<div id="row5" class="mod-popup-table-row">
<div class="mod-popup-button-div-bottom-left">
<button id="mod-popup-close-btn" class="mod-popup-button-cancel" >Close</button>
</div>
<div class="mod-popup-button-div">
<button id="mod-popup-save-btn" class="mod-popup-button" style="margin-right: 10px;">Save</button>
<button id="mod-popup-delete-btn" disabled class="mod-popup-button" style="background-color: grey; text-decoration:line-through;">Delete</button>
</div>
</div>
</div>
<div id="modal-background" class="mod-popup-modal-background"></div>
</div>
<div id="map"></div>
<!-- Stub for modal popup -->
<div id="modal-popup"></div>
<script>
require(["esri/map","esri/layers/FeatureLayer",
"utils/appCacheManager",
"esri/renderers/SimpleRenderer","esri/symbols/SimpleMarkerSymbol","esri/Color","esri/tasks/query",
"esri/renderers/SimpleRenderer","esri/symbols/SimpleMarkerSymbol",
"esri/Color",
"esri/tasks/query",
"dojo/on",
"esri/graphic",
"widgets/modal/popup",
"//esri.github.io/bootstrap-map-js/src/js/bootstrapmap.js",
"../dist/offline-tiles-advanced-min.js",
"../dist/offline-edit-min.js",
"dojo/domReady!"],
function(Map,FeatureLayer,AppCacheManager,
SimpleRenderer,SimpleMarkerSymbol,Color,Query,
on,Graphic) {
on,Graphic,ModalPopup,BootstrapMap) {
initAppCacheManager();
@ -190,12 +156,10 @@
var defaultSymbol;
// Variables for editing handling
var currentFeature;
var busStopFeatureLayer;
var offlineFeaturesManager;
var modPopup = document.getElementById("popup");
var pendingEdits = document.getElementById("pending-edits");
var imgOfflineIndicator = document.getElementById("img-offline-indicator");
var currentFeature, busStopFeatureLayer, offlineFeaturesManager;
var pendingEdits = document.getElementById("span-pending-edits");
var imgOfflineIndicator = document.getElementById("state-span");
var btnState = document.getElementById("btn-state");
// Variables for handling tiles
var tileLayer;
@ -203,35 +167,33 @@
var _wantToCancel;
var globalState = {};
var btnGetTiles = document.getElementById("btn-get-tiles");
var btnOnlineOffline = document.getElementById("btn-online-offline");
// Important settings for determining which tile layers gets stored for offline use.
var minZoomAdjust = -1, maxZoomAdjust = 1, resetZoom = 18;
var EXTENT_BUFFER = 0; //buffers the map extent in meters
// Misc.
var appCacheManager;
var btnOnlineOffline = document.getElementById("btn-online-offline");
var loading = document.getElementById("loader-gif");
// Variables for modal popup
var modPopup = document.getElementById("popup");
var closeBtn = document.getElementById("mod-popup-close-btn");
var saveBtn = document.getElementById("mod-popup-save-btn");
var deleteBtn = document.getElementById("mod-popup-delete-btn");
var stopMainID = document.getElementById("stop-main-id");
var stopID = document.getElementById("stop-id");
var stopRoutes = document.getElementById("stop-routes");
var stopNames = document.getElementById("stop-names");
// Symbols and images
var redPinPath = "../samples/images/red-pin.png";
var redPinImage = new Image().src = redPinPath;
var bluePinPath = "../samples/images/blue-pin.png";
var popup,closeBtn,saveBtn,deleteBtn,stopMainID,stopID,stopRoutes,stopNames;
// Modify symbol size based on screen size.
// Bigger screens get smaller symbols. Smaller screens get larger symbols.
if (document.documentElement.clientHeight > 768 || document.documentElement.clientWidth > 1024) {
var width = window.innerWidth
|| document.documentElement.clientWidth
|| document.body.clientWidth;
var height = window.innerHeight
|| document.documentElement.clientHeight
|| document.body.clientHeight;
if (height > 768 || width > 1024) {
defaultSymbol= new SimpleMarkerSymbol().setStyle(
SimpleMarkerSymbol.STYLE_DIAMOND).setColor(
new Color([255,0,0,0.5])).setSize(20); // scripts
new Color([255,0,0,0.5])).setSize(20);
}
else{
defaultSymbol= new SimpleMarkerSymbol().setStyle(
@ -239,7 +201,9 @@
new Color([255,0,0,0.5])).setSize(35);
}
var editsStore = new O.esri.Edit.EditStore(Graphic);
var editsStore = new O.esri.Edit.EditStore();
initModalPopup();
/**
* There have been a few bugs in the offline detection library (offline.min.js)
@ -249,7 +213,20 @@
verifyOnline(function(result){ console.log("VERIFY ONLINE " + result)
result == true ? _isOnline = true : _isOnline = false;
startMap();
})
});
function initModalPopup(){
popup = new ModalPopup({animation: true, animationDuration: 1},"modal-popup");
// Variables for modal popup
closeBtn = document.getElementById("mod-popup-close-btn");
saveBtn = document.getElementById("mod-popup-save-btn");
deleteBtn = document.getElementById("mod-popup-delete-btn");
stopMainID = document.getElementById("stop-main-id");
stopID = document.getElementById("stop-id");
stopRoutes = document.getElementById("stop-routes");
stopNames = document.getElementById("stop-names");
}
function startMap(){
@ -258,14 +235,14 @@
Offline.state === 'up' ? resetZoom = 18 : resetZoom = 17;
tileLayer = new O.esri.Tiles.OfflineTileEnablerLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer",function(evt){
console.log("Tile Layer Loaded.");
console.log("Tile Layer initialized for offline. App state is: " + Offline.state);
},_isOnline);
tileLayer.offline.proxyPath = null;
var map = new Map("map",{
center: [-104.98,39.74], // long, lat
zoom: 8,
var map = BootstrapMap.create("mapDiv",{
center: [-104.99,39.75], // long, lat
zoom: 17,
sliderStyle: "small"
});
@ -282,6 +259,7 @@
busStopFeatureLayer.on("update-end",function(evt){
// Set click listeners
on(btnGetTiles,"click",downloadTiles);
on(btnOnlineOffline, 'click', goOnlineOffline);
@ -319,6 +297,7 @@
_currentExtent = evt.map.extent;
updateOfflineUsage();
updateStatus();
if(_isOnline == false){
@ -386,11 +365,11 @@
if( editsStore.hasPendingEdits())
{
var edits = editsStore.retrieveEditsQueue();
pendingEdits.innerHTML = "Pending edits: " + edits.length;
pendingEdits.innerHTML = edits.length;
}
else
{
pendingEdits.innerHTML = "Pending edits: 0";
pendingEdits.innerHTML = "0";
}
}
@ -425,36 +404,36 @@
saveBtn.onclick = function(evt){
modPopup.graphic.attributes.ROUTES = stopRoutes.value;
modPopup.graphic.attributes.STOPNAME = stopNames.value;
popup.graphic.attributes.ROUTES = stopRoutes.value;
popup.graphic.attributes.STOPNAME = stopNames.value;
busStopFeatureLayer.applyEdits(null,[modPopup.graphic],null,function(result){
console.log("Successfully saved changes to: " + modPopup.graphic.attributes.STOPNAME);
busStopFeatureLayer.applyEdits(null,[popup.graphic],null,function(result){
console.log("Successfully saved changes to: " + popup.graphic.attributes.STOPNAME);
hideModalPopup();
},
function(err){
alert("There was a problem while trying to save: " + modPopup.graphic.attributes.STOPNAME);
alert("There was a problem while trying to save: " + popup.graphic.attributes.STOPNAME);
})
}
deleteBtn.onclick = function(evt){
busStopFeatureLayer.applyEdits(null,null,[modPopup.graphic],function(result){
console.log("Successfully deleted: " + modPopup.graphic.attributes.STOPNAME);
busStopFeatureLayer.applyEdits(null,null,[popup.graphic],function(result){
console.log("Successfully deleted: " + popup.graphic.attributes.STOPNAME);
hideModalPopup();
},
function(err){
alert("There was a problem while trying to delete: " + modPopup.graphic.attributes.STOPNAME);
alert("There was a problem while trying to delete: " + popup.graphic.attributes.STOPNAME);
})
}
}
function showModalPopup(graphic){
modPopup.style.position = "static";
modPopup.graphic = graphic; // assign graphic to modPopup as a property.
popup.graphic = graphic; // assign graphic to popup as a property.
popup.show();
}
function hideModalPopup(){
modPopup.style.position = "absolute";
popup.hide();
}
/**
@ -483,7 +462,7 @@
}
else
{
var zoom = getMinMaxZoom();
var zoom = tileLayer.getMinMaxLOD(minZoomAdjust,maxZoomAdjust);
var extent = tileLayer.getExtentBuffer(EXTENT_BUFFER,_currentExtent);
_wantToCancel = false;
@ -518,6 +497,7 @@
else
{
globalState.downloadState = 'downloaded';
btnOnlineOffline.disabled = false;
alert("Tile download complete");
}
@ -526,45 +506,30 @@
return _wantToCancel; //determines if a cancel request has been issued
}
/**
* Utility function to validate min and max zoom settings of the map
*/
function getMinMaxZoom(){
var zoom = {};
var min = tileLayer.getLevel() + minZoomAdjust;
var max = tileLayer.getLevel() + maxZoomAdjust;
var mMaxZoom;
tileLayer.getMaxZoom(function(result){
mMaxZoom = result;
});
var mMinZoom;
tileLayer.getMinZoom(function(result){
mMinZoom = result;
});
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;
}
/**
* ************************************
* MISC. CODE
* HANDLE GOING ONLINE/OFFLINE
* ************************************
*/
function goOnline(){
console.log("Going online...");
loading.style.visibility = "visible";
offlineFeaturesManager.goOnline(function(success,error){
if(error === undefined){
btnOnlineOffline.innerHTML = "2. Go Offline";
imgOfflineIndicator.src = bluePinPath;
imgOfflineIndicator.className = "glyphicon glyphicon-link";
imgOfflineIndicator.innerHTML = " Up";
btnState.className = "btn btn-success btn-large floatRight";
console.log("offlineFeatureManager is online.");
}
else{
alert("There was a problem syncing offline edits: " + JSON.stringify(error));
}
loading.style.visibility = "hidden";
});
updateOfflineUsage();
@ -574,7 +539,9 @@
function goOffline(){
console.log("Going offline...");
btnOnlineOffline.innerHTML = "2. Go Online";
imgOfflineIndicator.src = redPinPath;
imgOfflineIndicator.className = "glyphicon glyphicon-thumbs-down";
imgOfflineIndicator.innerHTML = " Down";
btnState.className = "btn btn-danger btn-large floatRight";
offlineFeaturesManager.goOffline();
if(typeof tileLayer != "undefined") tileLayer.goOffline();
}
@ -603,29 +570,6 @@
})
}
/**
* Listen for app cache events.
*/
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 cacheLoadedHandler(evt){
if(evt == appCacheManager.CACHE_LOADED) console.log("Application cache successfully loaded!")
}
function cacheEventHandler(evt){
if(evt.hasOwnProperty("total")) console.log("CACHE EVENT loaded #:" + evt.loaded + ", out of " + evt.total);
}
function cacheErrorHandler(evt){
console.log("CACHE ERROR: " + JSON.stringify(evt));
alert("There was a problem loading the cache. Try reloading the app. ")
}
/**
* Attempts an http request to verify if app is online or offline.
* Use this in conjunction with the offline checker library: offline.min.js
@ -653,8 +597,42 @@
};
req.send(null);
}
/**
* ************************************
* APPCACHE MANAGEMENT CODE
* ************************************
*/
/**
* Listen for app cache events.
*/
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 cacheLoadedHandler(evt){
if(evt == appCacheManager.CACHE_LOADED) console.log("Application cache successfully loaded!")
}
function cacheEventHandler(evt){
if(evt.hasOwnProperty("total")) console.log("CACHE EVENT loaded #:" + evt.loaded + ", out of " + evt.total);
}
function cacheErrorHandler(evt){
console.log("CACHE ERROR: " + JSON.stringify(evt));
alert("There was a problem loading the cache. Try reloading the app. ")
}
});
</script>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
</body>
</html>

View File

@ -1,35 +1,43 @@
CACHE MANIFEST
# This manifest was generated by grunt-manifest HTML5 Cache Manifest Generator
# Time: Mon Sep 08 2014 13:44:30 GMT-0600 (MDT)
# Time: Mon Oct 13 2014 12:42:42 GMT-0600 (MDT)
CACHE:
# manifest-generator, version: 0.0.1
# manifest-generator, version: 2.3
#
# Home Page
appcache-tiles.html
#
# ArcGIS API for JavaScript files
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
../samples/jsolib/dojo.js
../samples/jsolib/selector/acme.js
../samples/jsolib/nls/dojo_en.js
../samples/jsolib/resources/blank.gif
#
#http://js.arcgis.com/3.10/js/esri/dijit/images/popup-sprite.png
http://js.arcgis.com/3.10/js/esri/dijit/images/attribute_inspector_sprite.png
http://js.arcgis.com/3.10/js/dojo/dojox/gfx/svg.js
http://js.arcgis.com/3.10/js/dojo/dojo/resources/blank.gif
http://js.arcgis.com/3.10/js/esri/dijit/images/ajax-loader.gif
http://js.arcgis.com/3.10/js/esri/images/map/logo-sm.png
http://js.arcgis.com/3.10/js/esri/images/map/logo-med.png
http://js.arcgis.com/3.10/js/esri/css/esri.css
http://js.arcgis.com/3.10/js/dojo/dijit/themes/claro/claro.css
http://js.arcgis.com/3.10/js/esri/nls/jsapi_en-us.js
#http://js.arcgis.com/3.11/esri/dijit/images/popup-sprite.png
http://js.arcgis.com/3.11/esri/dijit/images/attribute_inspector_sprite.png
#http://js.arcgis.com/3.11/dojo/resources/blank.gif
http://js.arcgis.com/3.11/esri/dijit/images/ajax-loader.gif
http://js.arcgis.com/3.11/esri/images/map/logo-sm.png
http://js.arcgis.com/3.11/esri/images/map/logo-med.png
http://js.arcgis.com/3.11/esri/css/esri.css
http://js.arcgis.com/3.11/dijit/themes/claro/claro.css
http://js.arcgis.com/3.11/esri/nls/jsapi_en-us.js
#
//services.arcgisonline.com/ArcGIS/rest/info?f=json
//static.arcgis.com/attribution/World_Topo_Map?f=json
//server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer?f=pjson
//services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer?f=json&callback=dojo.io.script.jsonp_dojoIoScript1._jsonpCallback
#
# required for web maps
http://js.arcgis.com/3.10/js/esri/dijit/images/ajax-loader.gif
# Bootstrap files
//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css
//esri.github.io/bootstrap-map-js/src/css/bootstrapmap.css
//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js
//esri.github.io/bootstrap-map-js/src/js/bootstrapmap.js
https://code.jquery.com/jquery-2.1.1.min.js
# Custom feature service
http://services.arcgis.com/IZtlGBUe4KTzLOl4/arcgis/rest/services/BPX_RTD_BusStops2/FeatureServer/0?f=json
#
# required local html
# /xyz/style.css
@ -47,6 +55,14 @@ http://js.arcgis.com/3.10/js/esri/dijit/images/ajax-loader.gif
../dist/offline-edit-src.js
../dist/offline-tiles-advanced-src.js
../dist/offline-tiles-basic-src.js
../samples/widgets/modal/css/modal-popup.css
../samples/widgets/modal/template/popup.html
../samples/widgets/modal/popup.js
../samples/jsolib/nls/dojo_en.js
../samples/jsolib/resources/blank.gif
../samples/jsolib/dojo.js
../samples/jsolib/selector/acme.js
../samples/jsolib/selector/lite.js
NETWORK:
*

View File

@ -1,5 +1,6 @@
<!DOCTYPE html>
<html manifest="appcache-tiles.appcache">
<!--<html>-->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
@ -28,43 +29,31 @@ ask if you want to reload the application.
-->
<title>Cache Tiles</title>
<link rel="stylesheet" href="http://js.arcgis.com/3.9/js/esri/css/esri.css">
<!-- Bootstrap core CSS -->
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="http://js.arcgis.com/3.11/esri/css/esri.css">
<link rel="stylesheet" type="text/css" href="http://esri.github.io/bootstrap-map-js/src/css/bootstrapmap.css">
<style>
html, body, #map {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
#mapDiv {
min-height: 500px;
max-height: 1000px;
}
body {
background-color: #FFF;
overflow: hidden;
font-family: "Trebuchet MS";
}
#button-div1{
position: relative;
background: #000000;
color: #ffffff;
width: 100%;
height: 50px;
}
.basic-btn{
background-color: #000000;
border-color: #ffffff 1px;
color: #ffffff;
padding: 8px;
position: relative; float: left;
}
#img-offline-indicator{
padding: 8px;
position: relative; float: right;
}
#tile-info{
background-color: #000000;
color: white;
padding: 8px;
position: relative; float: right;
}
.floatRight { float: right;}
.container { padding: 20px;}
.span-dbsize {color: blue; padding-left: 1em;}
</style>
<script>
var locationPath = location.pathname.replace(/\/[^/]+$/, "");
@ -76,7 +65,7 @@ ask if you want to reload the application.
}
</script>
<!-- This is a custom build of the ArcGIS API for JavaScript using the new Web Optimizer Tool -->
<script src="http://js.arcgis.com/o/agup_hack4co/appcacheFeatures/dojo/dojo.js" data-dojo-config="async: true"></script>
<script src="../samples/jsolib/dojo.js" data-dojo-config="async: true"></script>
<!-- Use this tag below if you are hosting your ArcGIS API for JavaScript files locally -->
<!--<script src="libs/dojo/dojo/dojo.js" data-dojo-config="async: true"></script>-->
<script src="../vendor/IndexedDBShim/dist/IndexedDBShim.min.js"></script>
@ -96,37 +85,61 @@ ask if you want to reload the application.
</head>
<body>
<div id="button-div1">
<img id="img-offline-indicator" src="../samples/images/blue-pin.png"/>
<textarea contenteditable="false" id="tile-info"></textarea>
<button class="basic-btn" id="btn-get-tiles">1. Download Tiles</button>
<button class="basic-btn" id="btn-online-offline">2. Go Offline</button>
<button class="basic-btn" id="btn-zoom-out" onclick="panLeft()">3. Pan left</button>
<!-- Our buttons and online/offline indicator -->
<div class="container">
<div class="row">
<div class="col-xs-10">
<div class="form form-group btn-group" data-toggle="buttons">
<button class="btn btn-success" id="btn-get-tiles">1. Download Tiles</button>
<button class="btn btn-success" disabled id="btn-online-offline">2. Go Offline</button>
<button class="btn btn-success" disabled id="btn-pan-left">3. Pan left</button>
</div>
<span class="span-dbsize">Database Size (MBs) <span id="span-dbsize-value" class="badge">0</span></span>
</div>
<div class="col-xs-2">
<!-- this indicates whether app is offline (down) or online (up) -->
<button id="btn-state" class="btn btn-success btn-large floatRight">
<span id="state-span" class="glyphicon glyphicon-link"> Up</span>
</button>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div id="mapDiv"></div>
</div>
</div>
</div>
<div id="map"></div>
<script>
var map;
require(["esri/map","utils/appCacheManager","dojo/on","../dist/offline-tiles-advanced-min.js","dojo/domReady!"],
function(Map,AppCacheManager,on) {
require([
"esri/map",
"utils/appCacheManager",
"dojo/on",
"//esri.github.io/bootstrap-map-js/src/js/bootstrapmap.js",
"../dist/offline-tiles-advanced-src.js",
"dojo/domReady!"],
function(Map,AppCacheManager,on,BootstrapMap) {
var map;
var tileLayer = null;
var 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;
var redPinPath = "../samples/images/red-pin.png";
var bluePinPath = "../samples/images/blue-pin.png"
var EXTENT_BUFFER = 0; //buffers the map extent in meters
var minZoomAdjust = -1, maxZoomAdjust = 1;
imgOfflineIndicator = document.getElementById("img-offline-indicator");
imgOfflineIndicator.offlineColor = "blue";
var tiles,appCacheManager;
var EXTENT_BUFFER = 0; //buffers the map extent in meters
var dbsize = document.getElementById("span-dbsize-value");
var btnGetTiles = document.getElementById("btn-get-tiles");
var btnOnlineOffline = document.getElementById("btn-online-offline");
var imgOfflineIndicator = document.getElementById("state-span");
var btnState = document.getElementById("btn-state");
var btnPanLeft = document.getElementById("btn-pan-left");
Offline.check();
Offline.on('up down', updateState );
@ -155,8 +168,8 @@ require(["esri/map","utils/appCacheManager","dojo/on","../dist/offline-tiles-adv
//Make sure map shows up after a browser refresh
Offline.state === 'up' ? zoom = 18 : zoom = 17;
map = new Map("map", {
center: [-122.45,37.75], // long, lat
map = BootstrapMap.create("mapDiv", {
center: [-104.99,39.75], // long, lat
zoom: zoom,
sliderStyle: "small"
});
@ -177,17 +190,11 @@ require(["esri/map","utils/appCacheManager","dojo/on","../dist/offline-tiles-adv
on(btnOnlineOffline,"click",goOnlineOffline);
on(btnGetTiles,"click",downloadTiles);
on(btnPanLeft,"click",panLeft);
updateOfflineUsage();
tileLayer.getMaxZoom(function(result){
mMaxZoom = result;
});
tileLayer.getMinZoom(function(result){
mMinZoom = result;
});
console.log("level: " + tileLayer.getLevel() + ", maxZoom: " + mMaxZoom);
console.log("level: " + tileLayer.getLevel());
})
map.addLayer(tileLayer);
@ -199,54 +206,100 @@ require(["esri/map","utils/appCacheManager","dojo/on","../dist/offline-tiles-adv
console.log("Zoom level = " + tileLayer.getLevel())
});
btnGetTiles = document.getElementById("btn-get-tiles");
btnOnlineOffline = document.getElementById("btn-online-offline");
btnZoom = document.getElementById("btn-zoom-out");
tileInfo = document.getElementById("tile-info")
tileInfo.innerHTML = "Tile count: 0\r\nBytes: 0";
map.reposition();
map.resize();
}
function updateState(){
if(Offline.state === 'up'){
updateOfflineUsage();
imgOfflineIndicator.src = bluePinPath;
if(typeof tileLayer != "undefined") tileLayer.goOnline();
}
else{
imgOfflineIndicator.src = redPinPath;
if(typeof tileLayer != "undefined") tileLayer.goOffline();
}
}
function updateOfflineUsage()
{
tileLayer.offline.store.usedSpace(function(result,err){
if(result != null){
tileInfo.innerHTML = "DB Tile count: " + result.tileCount + "\r\nDB Bytes: " + result.sizeBytes;
var mb = (result.sizeBytes >>> 20 ) + '.' + ( result.sizeBytes & (2*0x3FF ) );
dbsize.innerHTML = mb;
}
else{
tileInfo.innerHTML = "DB Tile count: " + count + "\r\nDB Bytes: Error";
dbsize.innerHTML = "??";
}
})
}
function updateState(){
if(Offline.state === 'up'){
updateOfflineUsage();
toggleStateUp(true);
if(typeof tileLayer != "undefined") tileLayer.goOnline();
}
else{
toggleStateUp(false);
if(typeof tileLayer != "undefined") tileLayer.goOffline();
}
}
function toggleStateUp(state){
if(state){
btnOnlineOffline.innerHTML = "2. Go Offline";
tileLayer.goOnline();
imgOfflineIndicator.className = "glyphicon glyphicon-link";
imgOfflineIndicator.innerHTML = " Up";
btnState.className = "btn btn-success btn-large floatRight";
}
else{
btnOnlineOffline.innerHTML = "2. Go Online";
tileLayer.goOffline();
imgOfflineIndicator.className = "glyphicon glyphicon-thumbs-down";
imgOfflineIndicator.innerHTML = " Down";
btnState.className = "btn btn-danger btn-large floatRight";
}
}
/**
* Utility function to validate min and max zoom settings of the map
* Forces offlineTileEnabler to go online or offline.
* If it is offline it will try to find a tile in the local database.
*/
function getMinMaxZoom(){
function goOnlineOffline(){
var zoom = {};
var min = tileLayer.getLevel() + minZoomAdjust;
var max = tileLayer.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
btnPanLeft.disabled = false;
return zoom;
if(btnOnlineOffline.innerHTML == "2. Go Offline"){
toggleStateUp(false);
console.log("Map is offline");
}
else{
toggleStateUp(true);
console.log("Map is online");
}
}
/**
* Manually starts the process to download and store tiles
* in the local database
*/
function downloadTiles(){
tileLayer.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 = tileLayer.getMinMaxLOD(minZoomAdjust,maxZoomAdjust);
var extent = tileLayer.getExtentBuffer(EXTENT_BUFFER,map.extent);
_wantToCancel = false;
tileLayer.prepareForOffline(zoom.min, zoom.max, extent, reportProgress.bind(this));
globalState.downloadState = 'downloading';
}
}
}.bind(this))
}
/**
@ -273,6 +326,7 @@ require(["esri/map","utils/appCacheManager","dojo/on","../dist/offline-tiles-adv
else
{
globalState.downloadState = 'downloaded';
btnOnlineOffline.disabled = false;
alert("Tile download complete");
}
@ -281,57 +335,6 @@ require(["esri/map","utils/appCacheManager","dojo/on","../dist/offline-tiles-adv
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";
imgOfflineIndicator.src = redPinPath;
imgOfflineIndicator.offlineColor = "red";
tileLayer.goOffline();
}
else{
btnOnlineOffline.innerHTML = "2. Go Offline";
imgOfflineIndicator.src = bluePinPath;
imgOfflineIndicator.offlineColor = "blue";
tileLayer.goOnline();
}
}
/**
* Manually starts the process to download and store tiles
* in the local database
*/
function downloadTiles(){
tileLayer.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 = tileLayer.getExtentBuffer(EXTENT_BUFFER,map.extent);
_wantToCancel = false;
tileLayer.prepareForOffline(zoom.min, zoom.max, extent, reportProgress.bind(this));
globalState.downloadState = 'downloading';
}
}
}.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
@ -371,12 +374,19 @@ require(["esri/map","utils/appCacheManager","dojo/on","../dist/offline-tiles-adv
function cacheErrorHandler(evt){
console.log("CACHE ERROR: " + JSON.stringify(evt));
}
function panLeft(){
map.panLeft();
}
}
);
function panLeft(){
map.panLeft();
}
</script>
</body>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
</body>
</html>

2477
samples/jsolib/dojo.js vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 B

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,283 @@
define("dojo/selector/lite", ["../has", "../_base/kernel"], function(has, dojo){
"use strict";
var testDiv = document.createElement("div");
var matchesSelector = testDiv.matches || testDiv.webkitMatchesSelector || testDiv.mozMatchesSelector || testDiv.msMatchesSelector || testDiv.oMatchesSelector;
var querySelectorAll = testDiv.querySelectorAll;
var unionSplit = /([^\s,](?:"(?:\\.|[^"])+"|'(?:\\.|[^'])+'|[^,])*)/g;
has.add("dom-matches-selector", !!matchesSelector);
has.add("dom-qsa", !!querySelectorAll);
// this is a simple query engine. It has handles basic selectors, and for simple
// common selectors is extremely fast
var liteEngine = function(selector, root){
// summary:
// A small lightweight query selector engine that implements CSS2.1 selectors
// minus pseudo-classes and the sibling combinator, plus CSS3 attribute selectors
if(combine && selector.indexOf(',') > -1){
return combine(selector, root);
}
// use the root's ownerDocument if provided, otherwise try to use dojo.doc. Note
// that we don't use dojo/_base/window's doc to reduce dependencies, and
// fallback to plain document if dojo.doc hasn't been defined (by dojo/_base/window).
// presumably we will have a better way to do this in 2.0
var doc = root ? root.ownerDocument || root : dojo.doc || document,
match = (querySelectorAll ?
/^([\w]*)#([\w\-]+$)|^(\.)([\w\-\*]+$)|^(\w+$)/ : // this one only matches on simple queries where we can beat qSA with specific methods
/^([\w]*)#([\w\-]+)(?:\s+(.*))?$|(?:^|(>|.+\s+))([\w\-\*]+)(\S*$)/) // this one matches parts of the query that we can use to speed up manual filtering
.exec(selector);
root = root || doc;
if(match){
// fast path regardless of whether or not querySelectorAll exists
if(match[2]){
// an #id
// use dojo.byId if available as it fixes the id retrieval in IE, note that we can't use the dojo namespace in 2.0, but if there is a conditional module use, we will use that
var found = dojo.byId ? dojo.byId(match[2], doc) : doc.getElementById(match[2]);
if(!found || (match[1] && match[1] != found.tagName.toLowerCase())){
// if there is a tag qualifer and it doesn't match, no matches
return [];
}
if(root != doc){
// there is a root element, make sure we are a child of it
var parent = found;
while(parent != root){
parent = parent.parentNode;
if(!parent){
return [];
}
}
}
return match[3] ?
liteEngine(match[3], found)
: [found];
}
if(match[3] && root.getElementsByClassName){
// a .class
return root.getElementsByClassName(match[4]);
}
var found;
if(match[5]){
// a tag
found = root.getElementsByTagName(match[5]);
if(match[4] || match[6]){
selector = (match[4] || "") + match[6];
}else{
// that was the entirety of the query, return results
return found;
}
}
}
if(querySelectorAll){
// qSA works strangely on Element-rooted queries
// We can work around this by specifying an extra ID on the root
// and working up from there (Thanks to Andrew Dupont for the technique)
// IE 8 doesn't work on object elements
if (root.nodeType === 1 && root.nodeName.toLowerCase() !== "object"){
return useRoot(root, selector, root.querySelectorAll);
}else{
// we can use the native qSA
return root.querySelectorAll(selector);
}
}else if(!found){
// search all children and then filter
found = root.getElementsByTagName("*");
}
// now we filter the nodes that were found using the matchesSelector
var results = [];
for(var i = 0, l = found.length; i < l; i++){
var node = found[i];
if(node.nodeType == 1 && jsMatchesSelector(node, selector, root)){
// keep the nodes that match the selector
results.push(node);
}
}
return results;
};
var useRoot = function(context, query, method){
// this function creates a temporary id so we can do rooted qSA queries, this is taken from sizzle
var oldContext = context,
old = context.getAttribute("id"),
nid = old || "__dojo__",
hasParent = context.parentNode,
relativeHierarchySelector = /^\s*[+~]/.test(query);
if(relativeHierarchySelector && !hasParent){
return [];
}
if(!old){
context.setAttribute("id", nid);
}else{
nid = nid.replace(/'/g, "\\$&");
}
if(relativeHierarchySelector && hasParent){
context = context.parentNode;
}
var selectors = query.match(unionSplit);
for(var i = 0; i < selectors.length; i++){
selectors[i] = "[id='" + nid + "'] " + selectors[i];
}
query = selectors.join(",");
try{
return method.call(context, query);
}finally{
if(!old){
oldContext.removeAttribute("id");
}
}
};
if(!has("dom-matches-selector")){
var jsMatchesSelector = (function(){
// a JS implementation of CSS selector matching, first we start with the various handlers
var caseFix = testDiv.tagName == "div" ? "toLowerCase" : "toUpperCase";
var selectorTypes = {
"": function(tagName){
tagName = tagName[caseFix]();
return function(node){
return node.tagName == tagName;
};
},
".": function(className){
var classNameSpaced = ' ' + className + ' ';
return function(node){
return node.className.indexOf(className) > -1 && (' ' + node.className + ' ').indexOf(classNameSpaced) > -1;
};
},
"#": function(id){
return function(node){
return node.id == id;
};
}
};
var attrComparators = {
"^=": function(attrValue, value){
return attrValue.indexOf(value) == 0;
},
"*=": function(attrValue, value){
return attrValue.indexOf(value) > -1;
},
"$=": function(attrValue, value){
return attrValue.substring(attrValue.length - value.length, attrValue.length) == value;
},
"~=": function(attrValue, value){
return (' ' + attrValue + ' ').indexOf(' ' + value + ' ') > -1;
},
"|=": function(attrValue, value){
return (attrValue + '-').indexOf(value + '-') == 0;
},
"=": function(attrValue, value){
return attrValue == value;
},
"": function(attrValue, value){
return true;
}
};
function attr(name, value, type){
var firstChar = value.charAt(0);
if(firstChar == '"' || firstChar == "'"){
// it is quoted, remove the quotes
value = value.slice(1, -1);
}
value = value.replace(/\\/g,'');
var comparator = attrComparators[type || ""];
return function(node){
var attrValue = node.getAttribute(name);
return attrValue && comparator(attrValue, value);
};
}
function ancestor(matcher){
return function(node, root){
while((node = node.parentNode) != root){
if(matcher(node, root)){
return true;
}
}
};
}
function parent(matcher){
return function(node, root){
node = node.parentNode;
return matcher ?
node != root && matcher(node, root)
: node == root;
};
}
var cache = {};
function and(matcher, next){
return matcher ?
function(node, root){
return next(node) && matcher(node, root);
}
: next;
}
return function(node, selector, root){
// this returns true or false based on if the node matches the selector (optionally within the given root)
var matcher = cache[selector]; // check to see if we have created a matcher function for the given selector
if(!matcher){
// create a matcher function for the given selector
// parse the selectors
if(selector.replace(/(?:\s*([> ])\s*)|(#|\.)?((?:\\.|[\w-])+)|\[\s*([\w-]+)\s*(.?=)?\s*("(?:\\.|[^"])+"|'(?:\\.|[^'])+'|(?:\\.|[^\]])*)\s*\]/g, function(t, combinator, type, value, attrName, attrType, attrValue){
if(value){
matcher = and(matcher, selectorTypes[type || ""](value.replace(/\\/g, '')));
}
else if(combinator){
matcher = (combinator == " " ? ancestor : parent)(matcher);
}
else if(attrName){
matcher = and(matcher, attr(attrName, attrValue, attrType));
}
return "";
})){
throw new Error("Syntax error in query");
}
if(!matcher){
return true;
}
cache[selector] = matcher;
}
// now run the matcher function on the node
return matcher(node, root);
};
})();
}
if(!has("dom-qsa")){
var combine = function(selector, root){
// combined queries
var selectors = selector.match(unionSplit);
var indexed = [];
// add all results and keep unique ones, this only runs in IE, so we take advantage
// of known IE features, particularly sourceIndex which is unique and allows us to
// order the results
for(var i = 0; i < selectors.length; i++){
selector = new String(selectors[i].replace(/\s*$/,''));
selector.indexOf = escape; // keep it from recursively entering combine
var results = liteEngine(selector, root);
for(var j = 0, l = results.length; j < l; j++){
var node = results[j];
indexed[node.sourceIndex] = node;
}
}
// now convert from a sparse array to a dense array
var totalResults = [];
for(i in indexed){
totalResults.push(indexed[i]);
}
return totalResults;
};
}
liteEngine.match = matchesSelector ? function(node, selector, root){
if(root && root.nodeType != 9){
// doesn't support three args, use rooted id trick
return useRoot(root, selector, function(query){
return matchesSelector.call(node, query);
});
}
// we have a native matchesSelector, use that
return matchesSelector.call(node, selector);
} : jsMatchesSelector; // otherwise use the JS matches impl
return liteEngine;
});

View File

@ -7,9 +7,9 @@
"name": "manifest-generator",
"manifestName": "appcache-tiles.appcache",
"appHomePage": "appcache-tiles.html",
"optimizedApiURL": "http://js.arcgis.com/o/agup_hack4co/appcacheFeatures",
"arcGISBaseURL": "http://js.arcgis.com/3.10",
"version": "0.0.1",
"optimizedApiURL": "../samples/jsolib",
"arcGISBaseURL": "http://js.arcgis.com/3.11",
"version": "2.3",
"private": true,
"description": "manifest generator project",
"repository": {

View File

@ -187,7 +187,6 @@
<button id="show-stored-tiles" type="button" class="btn btn-default"><i class="fa fa-th"></i> <span id="show-stored-tiles-caption">Show Stored Tiles</span></button>
<button id="save-file" type="button" class="btn btn-default"><i class="fa fa-download"></i> Save to File</button>
<span id="load-file" type="button" class="btn btn-default"><i class="fa fa-upload"></i> Load from File <input type="file" id="file-select" name="file-select"></span>
<button id="use-proxy" type="button" class="btn btn-default"> Using proxy: <span id="using-proxy">Yes</span></button>
</div>
</div>
<div id="downloading-ui">
@ -236,7 +235,6 @@
bootstrapmap: "//esri.github.io/bootstrap-map-js/src/js/bootstrapmap"
}
}
window.proxyPath = "../lib/resource-proxy/proxy.php";
</script>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
@ -339,6 +337,9 @@ require(
on(map,"load",function()
{
basemapLayer = map.getLayer( map.layerIds[0] );
initMapParts();
initEvents();
initOffline();
});
}
@ -423,7 +424,6 @@ require(
on(dojo.byId('show-stored-tiles'),'click', toggleShowStoredTiles);
on(dojo.byId('save-file'),'click', saveToFile);
on(dojo.byId('file-select'),'change', loadFromFile);
on(dojo.byId('use-proxy'),'click', toggleProxy);
dojo.byId('go-online-btn').style.display = "none";
esri.show(dojo.byId('ready-to-download-ui'));
esri.hide(dojo.byId('downloading-ui'));
@ -447,7 +447,6 @@ require(
esri.hide(dojo.byId('go-online-btn'));
dojo.byId('update-offline-usage').disabled = true;
dojo.byId('show-stored-tiles').disabled = true;
dojo.byId('use-proxy').disabled = true;
esri.hide(dojo.byId('downloading-ui'));
showAlert("alert-danger","Failed initializing storage, probably your browser doesn't support <a href='http://caniuse.com/#feat=indexeddb'>IndexedDB</a> nor <a href='http://caniuse.com/#feat=sql-storage'>WebSQL</a>");
@ -750,16 +749,6 @@ require(
});
}
function toggleProxy()
{
if( basemapLayer.offline.proxyPath !== null )
basemapLayer.offline.proxyPath = null;
else
basemapLayer.offline.proxyPath = window.proxyPath || "../lib/resource-proxy/proxy.php";
dojo.byId('using-proxy').innerHTML = basemapLayer.offline.proxyPath? "Yes" : "No";
}
function showAlert(type, msg)
{
var icon = "";

View File

@ -3,136 +3,160 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
<title>TPKLayer</title>
<link rel="stylesheet" href="http://js.arcgis.com/3.10/js/esri/css/esri.css">
<title>Offline TPK</title>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet" media="screen">
<link rel="stylesheet" href="http://js.arcgis.com/3.11/esri/css/esri.css">
<link rel="stylesheet" type="text/css" href="http://esri.github.io/bootstrap-map-js/src/css/bootstrapmap.css">
<style>
html, body, #map {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
body {
background-color: #FFF;
background-color: #000000;
}
#mapDiv {
min-height: 300px;
max-height: 1000px;
}
.btn-file {
position: relative;
overflow: hidden;
font-family: "Trebuchet MS";
}
#header-div{
font-family: helvetica, serif;
background: #000000;
color: #ffffff;
width: 100%;
height: 90px;
display:inline-block;
vertical-align:middle;
line-height: 50px;
padding-left: 8px;
}
#input-container{
.btn-file input[type=file] {
position: absolute;
}
#file-input{
margin-top: 10px;
margin-left: 10px;
position: absolute;
float: left;
margin-bottom: 15px;
}
#url-input{
position: relative;
/* float: left; */
padding-left: 10px;
margin-left: 10px;
margin-top: 40px;
width: 250px;
}
#url-btn{
position: relative;
/*float: left;*/
}
#header-title{
position: relative;
float: right;
padding-right: 15px;
}
#loader-gif{
top: 0;
right: 0;
min-width: 100%;
min-height: 100%;
font-size: 100px;
text-align: right;
filter: alpha(opacity=0);
opacity: 0;
background: red;
cursor: inherit;
display: block;
visibility: hidden;
position: relative;
float: left;
padding-left: 50%;
padding-top: 25%;
z-index: 10;
}
#map{
position: absolute;
left: 0;
z-index: 1;
}
/* Portrait */
@media screen and (orientation:portrait) {
#loader-gif{
display: block;
visibility: hidden;
position: relative;
float: left;
padding-left: 50%;
padding-top: 25%;
z-index: 10;
}
}
/* Landscape */
@media screen and (orientation:landscape) {
#loader-gif{
display: block;
visibility: hidden;
position: relative;
float: left;
padding-left: 50%;
padding-top: 25%;
z-index: 10;
}
input[readonly] {
background-color: white !important;
cursor: text !important;
}
.container { padding: 20px;}
.blackBack { color: #ffffff; background-color: #000000;}
.pad-top-20px { padding-top: 20px;}
</style>
<!-- Include a reference to IndexedDBShim for library to work on Safari 7.x -->
<script src="../vendor/IndexedDBShim/dist/IndexedDBShim.js"></script>
<script src="http://js.arcgis.com/3.11/"></script>
</head>
<body>
<div id="header-div">
<div id="input-container">
<input type="file" id="file-input" name="files[]" accept="application/zip"/>
<input type="text" id="url-input" value="tpks/Beirut.zip" />
<button id="url-btn">Get file via url</button>
<div class="container">
<div class="well blackBack">
<h4>Browse for a zipped .TPK file locally or retrieve a URL</h4>
</div>
<!-- We provide two input types for demonstration purposes. Choose whichever one you want. -->
<div class="row">
<div class="col-lg-12">
<div class="input-group">
<span class="input-group-btn">
<span class="btn btn-primary btn-file">
Browse... <input type="file" id="file-input" name="files[]" accept="application/zip">
</span>
</span>
<input id="file-input-field" type="text" class="form-control" readonly>
</div>
</div>
</div>
<div class="row pad-top-20px">
<div class="col-lg-12">
<div class="form form-group input-group">
<span class="input-group-btn">
<button id="url-btn" class="btn btn-success" type="button">Go!</button>
</span>
<input id="url-input" type="text" class="form-control"
value="../samples/tpks/Beirut.zip">
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div id="mapDiv"></div>
</div>
</div>
<div id="header-title">TPKLayer demo</div>
</div>
<img id="loader-gif" src="images/loading.gif"/>
<div id="map"></div>
<script src="../vendor/IndexedDBShim/dist/IndexedDBShim.min.js"></script>
<script src="http://js.arcgis.com/3.10/"></script>
<script>
require(["esri/map","dojo/on","dojo/_base/window","../dist/offline-tpk-min.js","dojo/domReady!"],
function(Map,on,win) {
var map;
var fileInput,tpkLayer, urlInputBtn;
var loading = dojo.byId("loader-gif");
var getFileBtn = dojo.byId("url-btn");
// Make sure to reference the tpk library within the require statement!
require([
"esri/map",
"dojo/on",
"//esri.github.com/bootstrap-map-js/src/js/bootstrapmap.js",
"../dist/offline-tpk-src.js", "dojo/domReady!"],
function(Map,on,BootstrapMap) {
var map, tpkLayer;
var fileInput, fileInputField;
var url = document.getElementById("url-input");
var urlInputBtn = document.getElementById("url-btn");
urlInputBtn.onclick = function(){
getTPK();
};
initChooseLocalFile();
initGetRemoteFile();
/**
* Parse zipped TPK file and get the individual files.
* Choose a TPK file from your local filesystem
*/
function initChooseLocalFile(){
fileInputField = document.getElementById("file-input-field");
fileInput = document.getElementById("file-input");
fileInput.addEventListener('change', function() {
console.log("File success");
fileInputField.value = fileInput.files[0].name;
zipParser(fileInput.files[0]);
},false);
}
// Retrieve the TPK file via an HTTP request
function getTPK(){
urlInputBtn.innerHTML = "Get file via url";
var xhrRequest = new XMLHttpRequest();
xhrRequest.open("GET", url.value, true);
xhrRequest.responseType = "blob";
xhrRequest.onprogress = function(evt){
var percent = (parseFloat(evt.loaded / evt.totalSize) * 100).toFixed(0);
urlInputBtn.innerHTML = "Get file via url " + percent + "%";
console.log("Begin downloading remote tpk file...")
}
xhrRequest.error = function(err){console.log("ERROR")}
xhrRequest.onload = function(oEvent) {
if(this.status == 200) {
console.log("Remote tpk download finished.")
zipParser(this.response);
}
else{
alert("There was a problem loading the file. " + this.status + ": " + this.statusText )
}
};
xhrRequest.send();
}
// Parse the zip file contents into a zip.Entries object
function zipParser(blob){
O.esri.zip.createReader(new O.esri.zip.BlobReader(blob), function (zipReader) {
zipReader.getEntries(function (entries) {
initMap(entries);
//if(entries)alert("TPK downloaded and unzipped!");
zipReader.close(function(evt){
console.log("Done reading zip file.")
})
@ -142,68 +166,27 @@
})
}
/**
* Initialize the Map and the TPKLayer
*/
// Initialize the Map and the TPKLayer
function initMap(entries){
map = BootstrapMap.create("mapDiv",{});
tpkLayer = new O.esri.TPK.TPKLayer();
tpkLayer.on("progress", function (evt) {
evt == "start" ? loading.style.visibility = "visible" : loading.style.visibility = "hidden";
console.log("TPK loading...");
})
tpkLayer.extend(entries);
map = new Map("map");
map.addLayer(tpkLayer);
}
/**
* Choose a TPK file from your local filesystem
*/
function initChooseLocalFile(){
fileInput = document.getElementById("file-input");
fileInput.addEventListener('change', function() {
console.log("File success");
zipParser(fileInput.files[0]);
},false);
}
/**
* Get a TPK file from a remote server via a URL
*/
function initGetRemoteFile(){
getFileBtn.innerHTML = "Get file via url";
var url = document.getElementById("url-input");
urlInputBtn = document.getElementById("url-btn");
urlInputBtn.onclick = function(){
var xhrRequest = new XMLHttpRequest();
xhrRequest.open("GET", url.value, true);
xhrRequest.responseType = "blob";
xhrRequest.onprogress = function(evt){
loading.style.visibility = "visible";
var percent = (parseFloat(evt.loaded / evt.totalSize) * 100).toFixed(0);
getFileBtn.innerHTML = "Get file via url " + percent + "%";
console.log("Begin downloading remote tpk file...")
}
xhrRequest.error = function(err){console.log("ERRROR")}
xhrRequest.onload = function(oEvent) {
if(this.status == 200) {
loading.style.visibility = "hidden";
console.log("Remote tpk download finished.")
zipParser(this.response)
}
else{
loading.style.visibility = "hidden";
alert("There was a problem loading the file. " + this.status + ": " + this.statusText )
}
};
xhrRequest.send();
}
}
}
);
</script>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
</body>
</html>

View File

@ -0,0 +1,162 @@
.mod-popup-div {
opacity: 0;
height: 0;
width: 0;
z-index: 98;
font-size: x-large;
position: absolute;
top: 0px;
left: -1000px;
}
.mod-popup-body {
position: relative;
top: 10%;
left: 10%;
z-index: 100;
height: 80%;
width: 80%;
border-radius: 10px;
background-color: black;
display: table;
opacity: 0.7;
}
.mod-popup-modal-background {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
opacity: 0.5;
background-color: black;
z-index: 99;
display: table;
}
.mod-popup-input {
border-bottom: solid #ffffff 1px;
width: 80%;
display: table-cell;
vertical-align: middle;
padding: 12px;
}
.mod-popup-label {
padding: 12px;
width: 20%;
display: table-cell;
vertical-align: middle;
background-color: dimgrey;
}
.mod-popup-label-top-left {
padding: 12px;
width: 20%;
display: table-cell;
vertical-align: middle;
background-color: dimgray;
border-top-left-radius: 10px;
}
.mod-popup-table-row {
color: white;
border-radius: 10px;
display: table-row;
}
.mod-popup-stop-input {
border-radius: 5px;
font-size: x-large;
width: 90%;
height: 75%;
padding: 5px;
}
.mod-popup-stop-input-disabled {
color: white;
border-radius: 5px;
font-size: x-large;
background-color: dimgray;
opacity: 1.0; /* For safari display bug */
padding: 5px;
width: 90%;
height: 75%;
}
.mod-popup-button {
position: relative;
float: left;
color: #ffffff;
font-size: x-large;
border-radius: 10px;
width: 45%;
padding: 8px;
background-color: #000000;
border: solid #ffffff 2px;
}
.mod-popup-button:active {
position: relative;
float: left;
color: #000000;
font-size: x-large;
border-radius: 10px;
width: 45%;
padding: 8px;
background-color: lightyellow;
border: solid #ffffff 2px;
}
.mod-popup-button-cancel {
position: relative;
float: left;
color: lightgray;
font-size: x-large;
border-radius: 10px;
width: 100%;
padding: 8px;
background-color: #000000;
border: solid lightgray 1px;
}
.mod-popup-button-cancel:active {
position: relative;
float: left;
color: #000000;
font-size: x-large;
border-radius: 10px;
width: 100%;
padding: 8px;
background-color: lightyellow;
border: solid lightgray 1px;
}
.mod-popup-button-div {
padding: 12px;
display: table-cell;
vertical-align: middle;
background-color: #000000;
}
.mod-popup-button-div-bottom-left {
padding: 12px;
display: table-cell;
vertical-align: middle;
background-color: #000000;
border-bottom-left-radius: 8px;
}
@media (max-width: 500px) {
.mod-popup-button {
font-size: small;
}
.mod-popup-button:active{
font-size: small;
}
.mod-popup-button-cancel {
font-size: small;
}
.mod-popup-button-cancel:active {
font-size: small;
}
}
@media (max-width: 450px) {
.mod-popup-button {
font-size: x-small;
}
.mod-popup-button:active{
font-size: x-small;
}
.mod-popup-button-cancel {
font-size: x-small;
}
.mod-popup-button-cancel:active {
font-size: x-small;
}
}

View File

@ -0,0 +1,71 @@
/**
* Modal Popup Widget
* This widget provides a basic framework for building modal popups
* for mobile GIS web applications.
* @author @agup
*/
define([
"dojo/_base/declare", "dojo/parser", "dojo/ready",
"dijit/_WidgetBase", "dijit/_TemplatedMixin","dojo/query",
"dojo/text!../modal/template/popup.html","dojo/NodeList-manipulate"
], function(declare, parser, ready, _WidgetBase, _TemplatedMixin,query,template){
return declare("ModalPopup", [_WidgetBase, _TemplatedMixin], {
options: {
animation: false,
animationDuration: 1
},
templateString: template,
constructor: function (options, srcRefNode) {
// mix in settings and defaults
declare.safeMixin(this.options, options);
// widget node
this.domNode = srcRefNode;
// Set properties
this.set("animation", this.options.animation);
this.set("animationDuration", this.options.animationDuration);
},
show: function () {
if(this.animation){
// You can design any animation you want!
this.domNode.style.opacity = 1;
this.domNode.style.left = 0;
this.domNode.style.top = 0;
this.domNode.style.width = "100%";
this.domNode.style.height = "100%";
this.domNode.style.transition = "all " + this.animationDuration + "s linear 0s";
}
else{
this.domNode.style.position = "static";
}
},
hide: function () {
if(this.animation){
// You can design any animation you want!
this.domNode.style.height = 0;
this.domNode.style.width = 0;
this.domNode.style.opacity = 0;
this.domNode.style.top = "0px";
this.domNode.style.left = -1000 + "px";
this.domNode.style.transition = "all " + this.animationDuration + "s ease-in-out 0s";
}
else{
this.domNode.style.position = "absolute";
}
},
// connections/subscriptions will be cleaned up during the destroy() lifecycle phase
destroy: function () {
this.inherited(arguments);
}
});
});

View File

@ -0,0 +1,46 @@
<div id="mod-popup" class="mod-popup-div">
<!--
MODAL POPUP TEMPLATE
This is a customizable template for creating modal popups.
Feel free to modify this to fit the properties of your own feature service.
-->
<div id="mod-popup-b" class="mod-popup-body">
<div id="row1" class="mod-popup-table-row">
<div class="mod-popup-label-top-left">ID</div>
<div class="mod-popup-input">
<input id="stop-main-id" type="text" disabled class="mod-popup-stop-input-disabled" value="test"/>
</div>
</div>
<div id="row2" class="mod-popup-table-row">
<div class="mod-popup-label">Bustop ID</div>
<div class="mod-popup-input">
<input id="stop-id" disabled class="mod-popup-stop-input-disabled" value="test"/>
</div>
</div>
<div id="row3" class="mod-popup-table-row">
<div class="mod-popup-label">Routes</div>
<div class="mod-popup-input">
<input id="stop-routes" class="mod-popup-stop-input" value="test"/>
</div>
</div>
<div id="row4" class="mod-popup-table-row">
<div class="mod-popup-label">Stopnames</div>
<div class="mod-popup-input">
<input id="stop-names" class="mod-popup-stop-input" value="test"/>
</div>
</div>
<div id="row5" class="mod-popup-table-row">
<div class="mod-popup-button-div-bottom-left">
<button id="mod-popup-close-btn" class="mod-popup-button-cancel" >Close</button>
</div>
<div class="mod-popup-button-div">
<button id="mod-popup-save-btn" class="mod-popup-button" style="margin-right: 10px;">Save</button>
<button id="mod-popup-delete-btn" disabled class="mod-popup-button" style="background-color: grey; text-decoration:line-through;">Delete</button>
</div>
</div>
</div>
<div id="modal-background" class="mod-popup-modal-background"></div>
</div>

View File

@ -205,6 +205,14 @@ describe("offline enabler custom layer library", function()
})
});
async.it("getMinMaxLOD", function(done){
var object = g_basemapLayer.getMinMaxLOD(-1,1);
console.log("OBJECT " + JSON.stringify(object));
expect(object.min).toBe(13);
expect(object.max).toBe(15);
done();
})
async.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, "'");

View File

@ -255,4 +255,26 @@ describe("offline enabler library", function()
})
});
async.it("getMaxZoom", function(done){
g_basemapLayer.getMaxZoom(function(result){
expect(result).toBe(16);
done();
})
});
async.it("getMinZoom", function(done){
g_basemapLayer.getMinZoom(function(result){
expect(result).toBe(0);
done();
})
});
async.it("getMinMaxLOD", function(done){
var object = g_basemapLayer.getMinMaxLOD(-1,1);
console.log("OBJECT " + JSON.stringify(object));
expect(object.min).toBe(13);
expect(object.max).toBe(15);
done();
})
});