add Protocol.SQL.Gears, and go do editing while being offline! r=crschmidt (closes #1699)
git-svn-id: http://svn.openlayers.org/trunk/openlayers@8005 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
@@ -52,3 +52,41 @@
|
|||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains portions of Gears <http://code.google.com/apis/gears/>
|
||||||
|
*
|
||||||
|
* Copyright 2007, Google Inc.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of Google Inc. nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* Sets up google.gears.*, which is *the only* supported way to access Gears.
|
||||||
|
*
|
||||||
|
* Circumvent this file at your own risk!
|
||||||
|
*
|
||||||
|
* In the future, Gears may automatically define google.gears.* without this
|
||||||
|
* file. Gears may use these objects to transparently fix bugs and compatibility
|
||||||
|
* issues. Applications that use the code below will continue to work seamlessly
|
||||||
|
* when that happens.
|
||||||
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,261 @@
|
|||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="../theme/default/style.css" type="text/css" />
|
||||||
|
<link rel="stylesheet" href="style.css" type="text/css" />
|
||||||
|
<style type="text/css">
|
||||||
|
.float-left {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.clear-left {
|
||||||
|
clear: left;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script src="../lib/OpenLayers.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var map, vector, protocol, modify;
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
// create Gears protocol
|
||||||
|
protocol = new OpenLayers.Protocol.SQL.Gears({
|
||||||
|
databaseName: "db_name",
|
||||||
|
tableName: "table_name",
|
||||||
|
saveFeatureState: false
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!GearsIsSupported()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
map = new OpenLayers.Map("map");
|
||||||
|
|
||||||
|
// create base layer
|
||||||
|
var layer = new OpenLayers.Layer.WMS("OpenLayers WMS",
|
||||||
|
"http://labs.metacarta.com/wms/vmap0",
|
||||||
|
{"layers": "basic"}
|
||||||
|
);
|
||||||
|
map.addLayer(layer);
|
||||||
|
|
||||||
|
// create vector layer
|
||||||
|
vector = new OpenLayers.Layer.Vector("Vector", {
|
||||||
|
protocol: protocol,
|
||||||
|
strategies : [new OpenLayers.Strategy.Fixed()],
|
||||||
|
eventListeners: {
|
||||||
|
featuremodified: function(obj) {
|
||||||
|
if (obj.feature.state != OpenLayers.State.INSERT &&
|
||||||
|
obj.feature.state != OpenLayers.State.DELETE) {
|
||||||
|
|
||||||
|
obj.feature.state = OpenLayers.State.UPDATE;
|
||||||
|
}
|
||||||
|
displayStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
map.addLayer(vector);
|
||||||
|
|
||||||
|
// create modify feature control
|
||||||
|
modify = new OpenLayers.Control.ModifyFeature(vector);
|
||||||
|
|
||||||
|
// create editing panel
|
||||||
|
var panel = new OpenLayers.Control.Panel({
|
||||||
|
displayClass: "olControlEditingToolbar"
|
||||||
|
});
|
||||||
|
|
||||||
|
var navigation = new OpenLayers.Control.Navigation({
|
||||||
|
eventListeners: {
|
||||||
|
activate: function(obj) {
|
||||||
|
modify.activate();
|
||||||
|
},
|
||||||
|
deactivate: function(obj) {
|
||||||
|
modify.deactivate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var editing = new OpenLayers.Control.DrawFeature(
|
||||||
|
vector, OpenLayers.Handler.Polygon, {
|
||||||
|
displayClass: "olControlDrawFeaturePolygon",
|
||||||
|
eventListeners: {
|
||||||
|
featureadded: function(obj) {
|
||||||
|
obj.feature.state = OpenLayers.State.INSERT;
|
||||||
|
displayStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
panel.addControls([navigation, editing]);
|
||||||
|
panel.defaultControl = navigation;
|
||||||
|
|
||||||
|
// add controls to the map
|
||||||
|
map.addControl(modify);
|
||||||
|
map.addControl(panel);
|
||||||
|
|
||||||
|
// center the map
|
||||||
|
map.setCenter(new OpenLayers.LonLat(5, 40), 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayResult(txt) {
|
||||||
|
if (window.resultDomElement === undefined) {
|
||||||
|
window.resultDomElement = OpenLayers.Util.getElement("last-result");
|
||||||
|
}
|
||||||
|
resultDomElement.innerHTML = txt;
|
||||||
|
displayStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayStatus() {
|
||||||
|
if (window.statusDomElement === undefined) {
|
||||||
|
window.statusDomElement = OpenLayers.Util.getElement("status");
|
||||||
|
}
|
||||||
|
|
||||||
|
var createCnt = 0;
|
||||||
|
var updateCnt = 0;
|
||||||
|
var deleteCnt = 0;
|
||||||
|
var i, len, state;
|
||||||
|
for (i = 0, len = vector.features.length; i < len; i++) {
|
||||||
|
state = vector.features[i].state;
|
||||||
|
if (state == OpenLayers.State.INSERT) {
|
||||||
|
createCnt++;
|
||||||
|
} else if (state == OpenLayers.State.UPDATE) {
|
||||||
|
updateCnt++;
|
||||||
|
} else if (state == OpenLayers.State.DELETE) {
|
||||||
|
deleteCnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statusDomElement.innerHTML = createCnt + " features to create, " +
|
||||||
|
updateCnt + " features to update, " +
|
||||||
|
deleteCnt + " features to delete";
|
||||||
|
}
|
||||||
|
|
||||||
|
function GearsIsSupported() {
|
||||||
|
if (!protocol.supported()) {
|
||||||
|
OpenLayers.Console.userError("You must install Gears prior to using this example");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function featuresWithState(state) {
|
||||||
|
var list = [];
|
||||||
|
var i, len, feature;
|
||||||
|
for (i = 0, len = vector.features.length; i < len; i++) {
|
||||||
|
feature = vector.features[i];
|
||||||
|
if (feature.state == state) {
|
||||||
|
list.push(feature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _sync() {
|
||||||
|
if (!GearsIsSupported()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var resp = protocol.read();
|
||||||
|
if (!resp.success()) {
|
||||||
|
OpenLayers.Console.error("reading from Gears DB failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vector.destroyFeatures();
|
||||||
|
if (!resp.features || resp.features.length <= 0) {
|
||||||
|
displayResult("No features to read");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vector.addFeatures(resp.features);
|
||||||
|
displayResult("features successfully read");
|
||||||
|
}
|
||||||
|
|
||||||
|
function _commit() {
|
||||||
|
if (!GearsIsSupported()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var error = false;
|
||||||
|
function callback(resp) {
|
||||||
|
if (error) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!resp.success()) {
|
||||||
|
OpenLayers.Console.error("Commiting to Gears DB failed");
|
||||||
|
error = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
modify.selectControl.unselectAll()
|
||||||
|
|
||||||
|
if (resp.reqFeatures) {
|
||||||
|
vector.destroyFeatures(resp.reqFeatures);
|
||||||
|
}
|
||||||
|
if (resp.features) {
|
||||||
|
vector.addFeatures(resp.features);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (vector.features.length > 0) {
|
||||||
|
protocol.commit(vector.features, {
|
||||||
|
"create": {
|
||||||
|
callback: callback
|
||||||
|
},
|
||||||
|
"update": {
|
||||||
|
callback: callback
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
callback: callback
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!error) {
|
||||||
|
displayResult("features successfully committed");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
displayResult("no features to commit");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _delete() {
|
||||||
|
if (!GearsIsSupported()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var feature = vector.selectedFeatures[0];
|
||||||
|
if (feature) {
|
||||||
|
modify.selectControl.unselectAll()
|
||||||
|
feature.state = OpenLayers.State.DELETE;
|
||||||
|
displayStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body onload="init()">
|
||||||
|
<h1 id="title">Gears Protocol Example</h1>
|
||||||
|
|
||||||
|
<div id="tags">
|
||||||
|
</div>
|
||||||
|
<p id="shortdesc">
|
||||||
|
Shows the usage of the Gears protocol.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="float-left">
|
||||||
|
<div id="map" class="smallmap"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<a href="javascript:_sync()">Sync</a>
|
||||||
|
<p>The Sync link destroys the features currently in the layer, reads
|
||||||
|
features from the Gears database, and adds them to the layer.
|
||||||
|
Uncommitted features will be lost.</p>
|
||||||
|
|
||||||
|
<a href="javascript:_commit()">Commit</a>
|
||||||
|
<p>The Commit link commits to the Gears database the features that are
|
||||||
|
marked as INSERT, UPDATE or DELETE.</p>
|
||||||
|
|
||||||
|
<a href="javascript:_delete()">Delete</a>
|
||||||
|
<p>The Delete link marks the selected feature as DELETE. To select a feature
|
||||||
|
click choose the navigation control in the editing toolbar.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="margin-top: 30px">
|
||||||
|
<p>Status: <span id="status"></span></p>
|
||||||
|
<p>Result: <span id="last-result"></span></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clear-left" id="docs">
|
||||||
|
<p>This example demonstrates the usage of OpenLayers Gears protocol to
|
||||||
|
read/create/update/delete features from/to the Gears database.
|
||||||
|
<a href="http://gears.google.com/">Gears</a> must obviously be installed
|
||||||
|
in your browser for this example to work.</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2007, Google Inc.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of Google Inc. nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* Sets up google.gears.*, which is *the only* supported way to access Gears.
|
||||||
|
*
|
||||||
|
* Circumvent this file at your own risk!
|
||||||
|
*
|
||||||
|
* In the future, Gears may automatically define google.gears.* without this
|
||||||
|
* file. Gears may use these objects to transparently fix bugs and compatibility
|
||||||
|
* issues. Applications that use the code below will continue to work seamlessly
|
||||||
|
* when that happens.
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
// We are already defined. Hooray!
|
||||||
|
if (window.google && google.gears) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var factory = null;
|
||||||
|
|
||||||
|
// Firefox
|
||||||
|
if (typeof GearsFactory != 'undefined') {
|
||||||
|
factory = new GearsFactory();
|
||||||
|
} else {
|
||||||
|
// IE
|
||||||
|
try {
|
||||||
|
factory = new ActiveXObject('Gears.Factory');
|
||||||
|
// privateSetGlobalObject is only required and supported on WinCE.
|
||||||
|
if (factory.getBuildInfo().indexOf('ie_mobile') != -1) {
|
||||||
|
factory.privateSetGlobalObject(this);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Safari
|
||||||
|
if ((typeof navigator.mimeTypes != 'undefined')
|
||||||
|
&& navigator.mimeTypes["application/x-googlegears"]) {
|
||||||
|
factory = document.createElement("object");
|
||||||
|
factory.style.display = "none";
|
||||||
|
factory.width = 0;
|
||||||
|
factory.height = 0;
|
||||||
|
factory.type = "application/x-googlegears";
|
||||||
|
document.documentElement.appendChild(factory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// *Do not* define any objects if Gears is not installed. This mimics the
|
||||||
|
// behavior of Gears defining the objects in the future.
|
||||||
|
if (!factory) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now set up the objects, being careful not to overwrite anything.
|
||||||
|
//
|
||||||
|
// Note: In Internet Explorer for Windows Mobile, you can't add properties to
|
||||||
|
// the window object. However, global objects are automatically added as
|
||||||
|
// properties of the window object in all browsers.
|
||||||
|
if (!window.google) {
|
||||||
|
google = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!google.gears) {
|
||||||
|
google.gears = {factory: factory};
|
||||||
|
}
|
||||||
|
})();
|
||||||
@@ -83,6 +83,7 @@
|
|||||||
"OpenLayers/Tween.js",
|
"OpenLayers/Tween.js",
|
||||||
"Rico/Corner.js",
|
"Rico/Corner.js",
|
||||||
"Rico/Color.js",
|
"Rico/Color.js",
|
||||||
|
"Gears/gears_init.js",
|
||||||
"OpenLayers/Ajax.js",
|
"OpenLayers/Ajax.js",
|
||||||
"OpenLayers/Request.js",
|
"OpenLayers/Request.js",
|
||||||
"OpenLayers/Request/XMLHttpRequest.js",
|
"OpenLayers/Request/XMLHttpRequest.js",
|
||||||
@@ -190,6 +191,8 @@
|
|||||||
"OpenLayers/Strategy/BBOX.js",
|
"OpenLayers/Strategy/BBOX.js",
|
||||||
"OpenLayers/Protocol.js",
|
"OpenLayers/Protocol.js",
|
||||||
"OpenLayers/Protocol/HTTP.js",
|
"OpenLayers/Protocol/HTTP.js",
|
||||||
|
"OpenLayers/Protocol/SQL.js",
|
||||||
|
"OpenLayers/Protocol/SQL/Gears.js",
|
||||||
"OpenLayers/Layer/PointTrack.js",
|
"OpenLayers/Layer/PointTrack.js",
|
||||||
"OpenLayers/Layer/GML.js",
|
"OpenLayers/Layer/GML.js",
|
||||||
"OpenLayers/Style.js",
|
"OpenLayers/Style.js",
|
||||||
|
|||||||
@@ -0,0 +1,559 @@
|
|||||||
|
/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
|
||||||
|
* license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
|
||||||
|
* full text of the license. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @requires Gears/gears_init.js
|
||||||
|
* @requires OpenLayers/Protocol/SQL.js
|
||||||
|
* @requires OpenLayers/Format/JSON.js
|
||||||
|
* @requires OpenLayers/Format/WKT.js
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class: OpenLayers.Protocol.SQL.Gears
|
||||||
|
* This Protocol stores feature in the browser via the Gears Database module
|
||||||
|
* <http://code.google.com/apis/gears/api_database.html>.
|
||||||
|
*
|
||||||
|
* The main advantage is that all the read, create, update and delete operations
|
||||||
|
* can be done offline.
|
||||||
|
*
|
||||||
|
* Inherits from:
|
||||||
|
* - <OpenLayers.Protocol.SQL>
|
||||||
|
*/
|
||||||
|
OpenLayers.Protocol.SQL.Gears = OpenLayers.Class(OpenLayers.Protocol.SQL, {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property: FID_PREFIX
|
||||||
|
* {String}
|
||||||
|
*/
|
||||||
|
FID_PREFIX: '__gears_fid__',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property: NULL_GEOMETRY
|
||||||
|
* {String}
|
||||||
|
*/
|
||||||
|
NULL_GEOMETRY: '__gears_null_geometry__',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property: NULL_FEATURE_STATE
|
||||||
|
* {String}
|
||||||
|
*/
|
||||||
|
NULL_FEATURE_STATE: '__gears_null_feature_state__',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property: jsonParser
|
||||||
|
* {<OpenLayers.Format.JSON>}
|
||||||
|
*/
|
||||||
|
jsonParser: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property: wktParser
|
||||||
|
* {<OpenLayers.Format.WKT>}
|
||||||
|
*/
|
||||||
|
wktParser: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property: fidRegExp
|
||||||
|
* {RegExp} Regular expression to know whether a feature was
|
||||||
|
* created in offline mode.
|
||||||
|
*/
|
||||||
|
fidRegExp: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property: saveFeatureState
|
||||||
|
* {Boolean} Whether to save the feature state (<OpenLayers.State>)
|
||||||
|
* into the database, defaults to true.
|
||||||
|
*/
|
||||||
|
saveFeatureState: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property: typeOfFid
|
||||||
|
* {String} The type of the feature identifier, either "number" or
|
||||||
|
* "string", defaults to "string".
|
||||||
|
*/
|
||||||
|
typeOfFid: "string",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property: db
|
||||||
|
* {GearsDatabase}
|
||||||
|
*/
|
||||||
|
db: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor: OpenLayers.Protocol.SQL.Gears
|
||||||
|
*/
|
||||||
|
initialize: function(options) {
|
||||||
|
if (!this.supported()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
OpenLayers.Protocol.SQL.prototype.initialize.apply(this, [options]);
|
||||||
|
this.jsonParser = new OpenLayers.Format.JSON();
|
||||||
|
this.wktParser = new OpenLayers.Format.WKT();
|
||||||
|
|
||||||
|
this.fidRegExp = new RegExp('^' + this.FID_PREFIX);
|
||||||
|
this.initializeDatabase();
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: initializeDatabase
|
||||||
|
*/
|
||||||
|
initializeDatabase: function() {
|
||||||
|
this.db = google.gears.factory.create('beta.database');
|
||||||
|
this.db.open(this.databaseName);
|
||||||
|
this.db.execute(
|
||||||
|
"CREATE TABLE IF NOT EXISTS " + this.tableName +
|
||||||
|
" (fid TEXT UNIQUE, geometry TEXT, properties TEXT," +
|
||||||
|
" state TEXT)");
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APIMethod: destroy
|
||||||
|
* Clean up the protocol.
|
||||||
|
*/
|
||||||
|
destroy: function() {
|
||||||
|
this.db.close();
|
||||||
|
this.db = null;
|
||||||
|
|
||||||
|
this.jsonParser = null;
|
||||||
|
this.wktParser = null;
|
||||||
|
|
||||||
|
OpenLayers.Protocol.SQL.prototype.destroy.apply(this);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APIMethod: supported
|
||||||
|
* Determine whether a browser supports Gears
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {Boolean} The browser supports Gears
|
||||||
|
*/
|
||||||
|
supported: function() {
|
||||||
|
return !!(window.google && google.gears);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: read
|
||||||
|
* Read all features from the database and return a
|
||||||
|
* <OpenLayers.Protocol.Response> instance. If the options parameter
|
||||||
|
* contains a callback attribute, the function is called with the response
|
||||||
|
* as a parameter.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* options - {Object} Optional object for configuring the request; it
|
||||||
|
* can have the {Boolean} property "noFeatureStateReset" which
|
||||||
|
* specifies if the state of features read from the Gears
|
||||||
|
* database must be reset to null, if "noFeatureStateReset"
|
||||||
|
* is undefined or false then each feature's state is reset
|
||||||
|
* to null, if "noFeatureStateReset" is true the feature state
|
||||||
|
* is preserved.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
|
||||||
|
* object.
|
||||||
|
*/
|
||||||
|
read: function(options) {
|
||||||
|
options = OpenLayers.Util.applyDefaults(options, this.options);
|
||||||
|
|
||||||
|
var feature, features = [];
|
||||||
|
var rs = this.db.execute("SELECT * FROM " + this.tableName);
|
||||||
|
while (rs.isValidRow()) {
|
||||||
|
feature = this.unfreezeFeature(rs);
|
||||||
|
if (this.evaluateFilter(feature, options.filter)) {
|
||||||
|
if (!options.noFeatureStateReset) {
|
||||||
|
feature.state = null;
|
||||||
|
}
|
||||||
|
features.push(feature);
|
||||||
|
}
|
||||||
|
rs.next();
|
||||||
|
}
|
||||||
|
rs.close();
|
||||||
|
|
||||||
|
var resp = new OpenLayers.Protocol.Response({
|
||||||
|
code: OpenLayers.Protocol.Response.SUCCESS,
|
||||||
|
requestType: "read",
|
||||||
|
features: features
|
||||||
|
});
|
||||||
|
|
||||||
|
if (options && options.callback) {
|
||||||
|
options.callback.call(options.scope, resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: unfreezeFeature
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* row - {ResultSet}
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {<OpenLayers.Feature.Vector>}
|
||||||
|
*/
|
||||||
|
unfreezeFeature: function(row) {
|
||||||
|
var feature;
|
||||||
|
var wkt = row.fieldByName('geometry');
|
||||||
|
if (wkt == this.NULL_GEOMETRY) {
|
||||||
|
feature = new OpenLayers.Feature.Vector();
|
||||||
|
} else {
|
||||||
|
feature = this.wktParser.read(wkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
feature.attributes = this.jsonParser.read(
|
||||||
|
row.fieldByName('properties'));
|
||||||
|
|
||||||
|
feature.fid = this.extractFidFromField(row.fieldByName('fid'));
|
||||||
|
|
||||||
|
var state = row.fieldByName('state');
|
||||||
|
if (state == this.NULL_FEATURE_STATE) {
|
||||||
|
state = null;
|
||||||
|
}
|
||||||
|
feature.state = state;
|
||||||
|
|
||||||
|
return feature;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: extractFidFromField
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* field - {String}
|
||||||
|
*
|
||||||
|
* Returns
|
||||||
|
* {String} or {Number} The fid.
|
||||||
|
*/
|
||||||
|
extractFidFromField: function(field) {
|
||||||
|
if (!field.match(this.fidRegExp) && this.typeOfFid == "number") {
|
||||||
|
field = parseFloat(field);
|
||||||
|
}
|
||||||
|
return field;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: create
|
||||||
|
* Create new features into the database.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* features - {Array({<OpenLayers.Feature.Vector>})} or
|
||||||
|
* {<OpenLayers.Feature.Vector>} The features to create in
|
||||||
|
* the database.
|
||||||
|
* options - {Object} Optional object for configuring the request.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
|
||||||
|
* object.
|
||||||
|
*/
|
||||||
|
create: function(features, options) {
|
||||||
|
options = OpenLayers.Util.applyDefaults(options, this.options);
|
||||||
|
|
||||||
|
var resp = this.createOrUpdate(features);
|
||||||
|
resp.requestType = "create";
|
||||||
|
|
||||||
|
if (options && options.callback) {
|
||||||
|
options.callback.call(options.scope, resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: update
|
||||||
|
* Construct a request updating modified feature.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* features - {Array({<OpenLayers.Feature.Vector>})} or
|
||||||
|
* {<OpenLayers.Feature.Vector>} The features to update in
|
||||||
|
* the database.
|
||||||
|
* options - {Object} Optional object for configuring the request.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
|
||||||
|
* object.
|
||||||
|
*/
|
||||||
|
update: function(features, options) {
|
||||||
|
options = OpenLayers.Util.applyDefaults(options, this.options);
|
||||||
|
|
||||||
|
var resp = this.createOrUpdate(features);
|
||||||
|
resp.requestType = "update";
|
||||||
|
|
||||||
|
if (options && options.callback) {
|
||||||
|
options.callback.call(options.scope, resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: createOrUpdate
|
||||||
|
* Construct a request for updating or creating features in the
|
||||||
|
* database.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* features - {Array({<OpenLayers.Feature.Vector>})} or
|
||||||
|
* {<OpenLayers.Feature.Vector>} The feature to create or update
|
||||||
|
* in the database.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
|
||||||
|
* object.
|
||||||
|
*/
|
||||||
|
createOrUpdate: function(features) {
|
||||||
|
if (!(features instanceof Array)) {
|
||||||
|
features = [features];
|
||||||
|
}
|
||||||
|
|
||||||
|
var i, len = features.length, feature;
|
||||||
|
var insertedFeatures = new Array(len);
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
feature = features[i];
|
||||||
|
var params = this.freezeFeature(feature);
|
||||||
|
this.db.execute(
|
||||||
|
"REPLACE INTO " + this.tableName +
|
||||||
|
" (fid, geometry, properties, state)" +
|
||||||
|
" VALUES (?, ?, ?, ?)",
|
||||||
|
params);
|
||||||
|
|
||||||
|
var clone = feature.clone();
|
||||||
|
clone.fid = this.extractFidFromField(params[0]);
|
||||||
|
insertedFeatures[i] = clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new OpenLayers.Protocol.Response({
|
||||||
|
code: OpenLayers.Protocol.Response.SUCCESS,
|
||||||
|
features: insertedFeatures,
|
||||||
|
reqFeatures: features
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: freezeFeature
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* feature - {<OpenLayers.Feature.Vector>}
|
||||||
|
* state - {String} The feature state to store in the database.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {Array}
|
||||||
|
*/
|
||||||
|
freezeFeature: function(feature) {
|
||||||
|
// 2 notes:
|
||||||
|
// - fid might not be a string
|
||||||
|
// - getFeatureStateForFreeze needs the feature fid to it's stored
|
||||||
|
// in the feature here
|
||||||
|
feature.fid = feature.fid != null ?
|
||||||
|
"" + feature.fid : OpenLayers.Util.createUniqueID(this.FID_PREFIX);
|
||||||
|
|
||||||
|
var geometry = feature.geometry != null ?
|
||||||
|
feature.geometry.toString() : this.NULL_GEOMETRY;
|
||||||
|
|
||||||
|
var properties = this.jsonParser.write(feature.attributes);
|
||||||
|
|
||||||
|
var state = this.getFeatureStateForFreeze(feature);
|
||||||
|
|
||||||
|
return [feature.fid, geometry, properties, state];
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: getFeatureStateForFreeze
|
||||||
|
* Get the state of the feature to store into the database.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* feature - {<OpenLayers.Feature.Vector>} The feature.
|
||||||
|
*
|
||||||
|
* Returns
|
||||||
|
* {String} The state
|
||||||
|
*/
|
||||||
|
getFeatureStateForFreeze: function(feature) {
|
||||||
|
var state;
|
||||||
|
if (!this.saveFeatureState) {
|
||||||
|
state = this.NULL_FEATURE_STATE;
|
||||||
|
} else if (this.createdOffline(feature)) {
|
||||||
|
// if the feature was created in offline mode, its
|
||||||
|
// state must remain INSERT
|
||||||
|
state = OpenLayers.State.INSERT;
|
||||||
|
} else {
|
||||||
|
state = feature.state;
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: delete
|
||||||
|
* Delete features from the database.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* features - {Array({<OpenLayers.Feature.Vector>})} or
|
||||||
|
* {<OpenLayers.Feature.Vector>}
|
||||||
|
* options - {Object} Optional object for configuring the request.
|
||||||
|
* This object is modified and should not be reused.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
|
||||||
|
* object.
|
||||||
|
*/
|
||||||
|
"delete": function(features, options) {
|
||||||
|
if (!(features instanceof Array)) {
|
||||||
|
features = [features];
|
||||||
|
}
|
||||||
|
|
||||||
|
options = OpenLayers.Util.applyDefaults(options, this.options);
|
||||||
|
|
||||||
|
var i, len, feature;
|
||||||
|
for (i = 0, len = features.length; i < len; i++) {
|
||||||
|
feature = features[i];
|
||||||
|
|
||||||
|
// if saveFeatureState is set to true and if the feature wasn't created
|
||||||
|
// in offline mode we don't delete it in the database but just update
|
||||||
|
// it state column
|
||||||
|
if (this.saveFeatureState && !this.createdOffline(feature)) {
|
||||||
|
var toDelete = feature.clone();
|
||||||
|
toDelete.fid = feature.fid;
|
||||||
|
if (toDelete.geometry) {
|
||||||
|
toDelete.geometry.destroy();
|
||||||
|
toDelete.geometry = null;
|
||||||
|
}
|
||||||
|
toDelete.state = feature.state;
|
||||||
|
this.createOrUpdate(toDelete);
|
||||||
|
} else {
|
||||||
|
this.db.execute(
|
||||||
|
"DELETE FROM " + this.tableName +
|
||||||
|
" WHERE fid = ?", [feature.fid]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var resp = new OpenLayers.Protocol.Response({
|
||||||
|
code: OpenLayers.Protocol.Response.SUCCESS,
|
||||||
|
requestType: "delete",
|
||||||
|
reqFeatures: features
|
||||||
|
});
|
||||||
|
|
||||||
|
if (options && options.callback) {
|
||||||
|
options.callback.call(options.scope, resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: createdOffline
|
||||||
|
* Returns true if the feature had a feature id when it was created in
|
||||||
|
* the Gears database, false otherwise; this is determined by
|
||||||
|
* checking the form of the feature's fid value.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* feature - {<OpenLayers.Feature.Vector>}
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {Boolean}
|
||||||
|
*/
|
||||||
|
createdOffline: function(feature) {
|
||||||
|
return (typeof feature.fid == "string" &&
|
||||||
|
!!(feature.fid.match(this.fidRegExp)));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: commit
|
||||||
|
* Go over the features and for each take action
|
||||||
|
* based on the feature state. Possible actions are create,
|
||||||
|
* update and delete.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* features - {Array({<OpenLayers.Feature.Vector>})}
|
||||||
|
* options - {Object} Object whose possible keys are "create", "update",
|
||||||
|
* "delete", "callback" and "scope", the values referenced by the
|
||||||
|
* first three are objects as passed to the "create", "update", and
|
||||||
|
* "delete" methods, the value referenced by the "callback" key is
|
||||||
|
* a function which is called when the commit operation is complete
|
||||||
|
* using the scope referenced by the "scope" key.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* {Array({<OpenLayers.Protocol.Response>})} An array of
|
||||||
|
* <OpenLayers.Protocol.Response> objects, one per request made
|
||||||
|
* to the database.
|
||||||
|
*/
|
||||||
|
commit: function(features, options) {
|
||||||
|
var opt, resp = [], nRequests = 0, nResponses = 0;
|
||||||
|
|
||||||
|
function callback(resp) {
|
||||||
|
if (++nResponses < nRequests) {
|
||||||
|
resp.last = false;
|
||||||
|
}
|
||||||
|
this.callUserCallback(options, resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
var feature, toCreate = [], toUpdate = [], toDelete = [];
|
||||||
|
for (var i = features.length - 1; i >= 0; i--) {
|
||||||
|
feature = features[i];
|
||||||
|
switch (feature.state) {
|
||||||
|
case OpenLayers.State.INSERT:
|
||||||
|
toCreate.push(feature);
|
||||||
|
break;
|
||||||
|
case OpenLayers.State.UPDATE:
|
||||||
|
toUpdate.push(feature);
|
||||||
|
break;
|
||||||
|
case OpenLayers.State.DELETE:
|
||||||
|
toDelete.push(feature);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (toCreate.length > 0) {
|
||||||
|
nRequests++;
|
||||||
|
opt = OpenLayers.Util.applyDefaults(
|
||||||
|
{"callback": callback, "scope": this},
|
||||||
|
options.create
|
||||||
|
);
|
||||||
|
resp.push(this.create(toCreate, opt));
|
||||||
|
}
|
||||||
|
if (toUpdate.length > 0) {
|
||||||
|
nRequests++;
|
||||||
|
opt = OpenLayers.Util.applyDefaults(
|
||||||
|
{"callback": callback, "scope": this},
|
||||||
|
options.update
|
||||||
|
);
|
||||||
|
resp.push(this.update(toUpdate, opt));
|
||||||
|
}
|
||||||
|
if (toDelete.length > 0) {
|
||||||
|
nRequests++;
|
||||||
|
opt = OpenLayers.Util.applyDefaults(
|
||||||
|
{"callback": callback, "scope": this},
|
||||||
|
options["delete"]
|
||||||
|
);
|
||||||
|
resp.push(this["delete"](toDelete, opt));
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: clear
|
||||||
|
* Removes all rows of the table.
|
||||||
|
*/
|
||||||
|
clear: function() {
|
||||||
|
this.db.execute("DELETE FROM " + this.tableName);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method: callUserCallback
|
||||||
|
* This method is called from within commit each time a request is made
|
||||||
|
* to the database, it is responsible for calling the user-supplied
|
||||||
|
* callbacks.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* options - {Object} The map of options passed to the commit call.
|
||||||
|
* resp - {<OpenLayers.Protocol.Response>}
|
||||||
|
*/
|
||||||
|
callUserCallback: function(options, resp) {
|
||||||
|
var opt = options[resp.requestType];
|
||||||
|
if (opt && opt.callback) {
|
||||||
|
opt.callback.call(opt.scope, resp);
|
||||||
|
}
|
||||||
|
if (resp.last && options.callback) {
|
||||||
|
options.callback.call(options.scope);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
CLASS_NAME: "OpenLayers.Protocol.SQL.Gears"
|
||||||
|
});
|
||||||
@@ -0,0 +1,473 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script src="../../../lib/OpenLayers.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
function test_initialize(t) {
|
||||||
|
var protocol = new OpenLayers.Protocol.SQL.Gears();
|
||||||
|
if (!protocol.supported()) {
|
||||||
|
t.plan(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.plan(5);
|
||||||
|
|
||||||
|
t.eq(protocol.CLASS_NAME, "OpenLayers.Protocol.SQL.Gears",
|
||||||
|
"ctor returns correct value");
|
||||||
|
|
||||||
|
t.eq(protocol.jsonParser.CLASS_NAME,
|
||||||
|
"OpenLayers.Format.JSON",
|
||||||
|
"ctor creates a JSON parser");
|
||||||
|
|
||||||
|
t.eq(protocol.wktParser.CLASS_NAME,
|
||||||
|
"OpenLayers.Format.WKT",
|
||||||
|
"ctor creates a WKT parser");
|
||||||
|
|
||||||
|
var str = protocol.FID_PREFIX + "foo_bar";
|
||||||
|
t.ok(str.match(protocol.fidRegExp),
|
||||||
|
"ctor creates correct regexp");
|
||||||
|
|
||||||
|
t.ok(typeof protocol.db == "object",
|
||||||
|
"ctor creates a db object");
|
||||||
|
|
||||||
|
protocol.clear();
|
||||||
|
protocol.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_destroy(t) {
|
||||||
|
var protocol = new OpenLayers.Protocol.SQL.Gears();
|
||||||
|
if (!protocol.supported()) {
|
||||||
|
t.plan(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.plan(3);
|
||||||
|
|
||||||
|
protocol.destroy();
|
||||||
|
|
||||||
|
t.eq(protocol.db, null,
|
||||||
|
"destroy nullifies db");
|
||||||
|
t.eq(protocol.jsonParser, null,
|
||||||
|
"destroy nullifies jsonParser");
|
||||||
|
t.eq(protocol.wktParser, null,
|
||||||
|
"destroy nullifies wktParser");
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_read(t) {
|
||||||
|
var protocolCallback, readCallback;
|
||||||
|
var protocolOptions = {callback: protocolCallback};
|
||||||
|
var readOptions = {callback: readCallback};
|
||||||
|
|
||||||
|
var protocol = new OpenLayers.Protocol.SQL.Gears(protocolOptions);
|
||||||
|
if (!protocol.supported()) {
|
||||||
|
t.plan(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function okCallback(resp) {
|
||||||
|
t.eq(resp.CLASS_NAME, "OpenLayers.Protocol.Response",
|
||||||
|
"read calls correct callback with a response object");
|
||||||
|
}
|
||||||
|
|
||||||
|
function failCallback(resp) {
|
||||||
|
t.fail("read calls incorrect callback");
|
||||||
|
}
|
||||||
|
|
||||||
|
t.plan(4);
|
||||||
|
|
||||||
|
var resp;
|
||||||
|
|
||||||
|
// 2 tests
|
||||||
|
protocolOptions.callback = okCallback;
|
||||||
|
readOptions.callback = failCallback;
|
||||||
|
resp = protocol.read();
|
||||||
|
t.eq(resp.CLASS_NAME, "OpenLayers.Protocol.Response",
|
||||||
|
"read returns a response object");
|
||||||
|
|
||||||
|
// 2 test
|
||||||
|
protocolOptions.callback = failCallback;
|
||||||
|
readOptions.callback = okCallback;
|
||||||
|
resp = protocol.read(readOptions);
|
||||||
|
t.eq(resp.CLASS_NAME, "OpenLayers.Protocol.Response",
|
||||||
|
"read returns a response object");
|
||||||
|
|
||||||
|
protocol.clear();
|
||||||
|
protocol.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_unfreezeFeature(t) {
|
||||||
|
var protocol = new OpenLayers.Protocol.SQL.Gears();
|
||||||
|
if (!protocol.supported()) {
|
||||||
|
t.plan(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.plan(10);
|
||||||
|
|
||||||
|
var feature;
|
||||||
|
var wkt, json, fid, state;
|
||||||
|
|
||||||
|
json = "{\"fake\":\"properties\"}";
|
||||||
|
fid = "1000";
|
||||||
|
state = OpenLayers.State.INSERT;
|
||||||
|
|
||||||
|
var row = {
|
||||||
|
fieldByName: function(str) {
|
||||||
|
if (str == "geometry") {
|
||||||
|
return wkt;
|
||||||
|
}
|
||||||
|
if (str == "properties") {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
if (str == "fid") {
|
||||||
|
return fid;
|
||||||
|
}
|
||||||
|
if (str == "state") {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 5 tests
|
||||||
|
wkt = "POINT(1 2)";
|
||||||
|
feature = protocol.unfreezeFeature(row);
|
||||||
|
t.eq(feature.CLASS_NAME, "OpenLayers.Feature.Vector",
|
||||||
|
"unfreezeFeature returns an OpenLayers.Feature.Vector");
|
||||||
|
t.ok(feature.geometry.x == 1 && feature.geometry.y == 2,
|
||||||
|
"unfreezeFeature returns a feature with correct geometry");
|
||||||
|
t.eq(feature.attributes.fake, "properties",
|
||||||
|
"unfreezeFeature returns a feature with correct attributes");
|
||||||
|
t.eq(feature.fid, fid,
|
||||||
|
"unfreezeFeature returns a feature with fid");
|
||||||
|
t.eq(feature.state, state,
|
||||||
|
"unfreezeFeature returns a feature with state");
|
||||||
|
|
||||||
|
// 5 tests
|
||||||
|
wkt = protocol.NULL_GEOMETRY;
|
||||||
|
state = protocol.NULL_FEATURE_STATE;
|
||||||
|
feature = protocol.unfreezeFeature(row);
|
||||||
|
t.eq(feature.CLASS_NAME, "OpenLayers.Feature.Vector",
|
||||||
|
"unfreezeFeature returns an OpenLayers.Feature.Vector");
|
||||||
|
t.eq(feature.geometry, null,
|
||||||
|
"unfreezeFeature returns a feature with correct geometry");
|
||||||
|
t.eq(feature.attributes.fake, "properties",
|
||||||
|
"unfreezeFeature returns a feature with correct attributes");
|
||||||
|
t.eq(feature.fid, fid,
|
||||||
|
"unfreezeFeature returns a feature with fid");
|
||||||
|
t.eq(feature.state, null,
|
||||||
|
"unfreezeFeature returns a feature with state");
|
||||||
|
|
||||||
|
protocol.clear();
|
||||||
|
protocol.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_extractFidFromField(t) {
|
||||||
|
var protocol = new OpenLayers.Protocol.SQL.Gears();
|
||||||
|
if (!protocol.supported()) {
|
||||||
|
t.plan(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.plan(4);
|
||||||
|
|
||||||
|
var field, fid;
|
||||||
|
|
||||||
|
// fid is a string, field is not prefixed with FID_PREFIX
|
||||||
|
// 1 test
|
||||||
|
field = "10";
|
||||||
|
res = protocol.extractFidFromField(field);
|
||||||
|
t.eq(res, "10",
|
||||||
|
"extractFidFromField returns expected string");
|
||||||
|
|
||||||
|
// fid is a string, field is prefixed with FID_PREFIX
|
||||||
|
// 1 test
|
||||||
|
field = protocol.FIX_PREFIX + "10";
|
||||||
|
res = protocol.extractFidFromField(field);
|
||||||
|
t.eq(res, protocol.FIX_PREFIX + "10",
|
||||||
|
"extractFidFromField returns expected prefixed string");
|
||||||
|
|
||||||
|
// fid is a number, field is not prefixed with FIX_PREFIX
|
||||||
|
// 1 test
|
||||||
|
protocol.typeOfFid = "number";
|
||||||
|
field = "10";
|
||||||
|
res = protocol.extractFidFromField(field);
|
||||||
|
t.eq(res, 10,
|
||||||
|
"extractFidFromField returns expected number");
|
||||||
|
|
||||||
|
// fid is a number, field is prefixed with FIX_PREFIX
|
||||||
|
// 1 test
|
||||||
|
protocol.typeOfFid = "number";
|
||||||
|
field = protocol.FID_PREFIX + "10";
|
||||||
|
res = protocol.extractFidFromField(field);
|
||||||
|
t.eq(res, protocol.FID_PREFIX + "10",
|
||||||
|
"extractFidFromField returns expected prefixed string");
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_freezeFeature(t) {
|
||||||
|
var protocol = new OpenLayers.Protocol.SQL.Gears();
|
||||||
|
if (!protocol.supported()) {
|
||||||
|
t.plan(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.plan(8);
|
||||||
|
|
||||||
|
var feature, res;
|
||||||
|
|
||||||
|
// 4 tests
|
||||||
|
feature = new OpenLayers.Feature.Vector();
|
||||||
|
feature.geometry = new OpenLayers.Geometry.Point(1, 2);
|
||||||
|
feature.attributes.fake = "properties";
|
||||||
|
feature.fid = "1000";
|
||||||
|
feature.state = OpenLayers.State.INSERT;
|
||||||
|
res = protocol.freezeFeature(feature);
|
||||||
|
t.eq(res[0], feature.fid,
|
||||||
|
"freezeFeature returns correct fid");
|
||||||
|
t.eq(res[1], "POINT(1 2)",
|
||||||
|
"freezeFeature returns correct WKT");
|
||||||
|
t.eq(res[2], "{\"fake\":\"properties\"}",
|
||||||
|
"freezeFeature returns correct JSON");
|
||||||
|
t.eq(res[3], feature.state,
|
||||||
|
"freezeFeature returns correct feature state");
|
||||||
|
|
||||||
|
// 4 tests
|
||||||
|
protocol.saveFeatureState = false;
|
||||||
|
feature = new OpenLayers.Feature.Vector();
|
||||||
|
feature.attributes.fake = "properties";
|
||||||
|
feature.fid = "1000";
|
||||||
|
feature.state = OpenLayers.State.INSERT;
|
||||||
|
res = protocol.freezeFeature(feature);
|
||||||
|
t.eq(res[0], feature.fid,
|
||||||
|
"freezeFeature returns correct fid");
|
||||||
|
t.eq(res[1], protocol.NULL_GEOMETRY,
|
||||||
|
"freezeFeature returns expected null geom string");
|
||||||
|
t.eq(res[2], "{\"fake\":\"properties\"}",
|
||||||
|
"freezeFeature returns correct JSON");
|
||||||
|
t.eq(res[3], protocol.NULL_FEATURE_STATE,
|
||||||
|
"freezeFeature returns expected null feature state string");
|
||||||
|
|
||||||
|
protocol.clear();
|
||||||
|
protocol.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_create(t) {
|
||||||
|
var protocol = new OpenLayers.Protocol.SQL.Gears();
|
||||||
|
if (!protocol.supported()) {
|
||||||
|
t.plan(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.plan(8);
|
||||||
|
|
||||||
|
var resp;
|
||||||
|
var scope = {"fake": "scope"};
|
||||||
|
|
||||||
|
var options = {
|
||||||
|
callback: function(resp) {
|
||||||
|
t.eq(resp.CLASS_NAME, "OpenLayers.Protocol.Response",
|
||||||
|
"user callback is passed a response");
|
||||||
|
t.eq(resp.requestType, "create",
|
||||||
|
"user callback is passed correct request type in resp");
|
||||||
|
t.ok(this == scope,
|
||||||
|
"user callback called with correct scope");
|
||||||
|
},
|
||||||
|
scope: scope
|
||||||
|
};
|
||||||
|
|
||||||
|
// 4 tests
|
||||||
|
var feature = new OpenLayers.Feature.Vector();
|
||||||
|
feature.fid = "1000";
|
||||||
|
feature.attributes.fake = "properties";
|
||||||
|
feature.state = OpenLayers.State.INSERT;
|
||||||
|
resp = protocol.create([feature], options);
|
||||||
|
t.eq(resp.CLASS_NAME, "OpenLayers.Protocol.Response",
|
||||||
|
"create returns a response");
|
||||||
|
|
||||||
|
// check what we have in the DB
|
||||||
|
// 4 tests
|
||||||
|
resp = protocol.read({"noFeatureStateReset": true});
|
||||||
|
t.eq(resp.features.length, 1,
|
||||||
|
"create inserts feature in the DB");
|
||||||
|
t.eq(resp.features[0].fid, feature.fid,
|
||||||
|
"create inserts feature with correct fid");
|
||||||
|
t.eq(resp.features[0].attributes.fake, feature.attributes.fake,
|
||||||
|
"create inserts feature with correct attributes");
|
||||||
|
t.eq(resp.features[0].state, feature.state,
|
||||||
|
"create inserts feature with correct state");
|
||||||
|
|
||||||
|
protocol.clear();
|
||||||
|
protocol.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_createOrUpdate(t) {
|
||||||
|
var protocol = new OpenLayers.Protocol.SQL.Gears();
|
||||||
|
if (!protocol.supported()) {
|
||||||
|
t.plan(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.plan(5);
|
||||||
|
|
||||||
|
// 1 test
|
||||||
|
var feature = new OpenLayers.Feature.Vector();
|
||||||
|
feature.fid = "1000";
|
||||||
|
feature.attributes.fake = "properties";
|
||||||
|
feature.state = OpenLayers.State.INSERT;
|
||||||
|
resp = protocol.createOrUpdate([feature]);
|
||||||
|
t.eq(resp.CLASS_NAME, "OpenLayers.Protocol.Response",
|
||||||
|
"createOrUpdate returns a response");
|
||||||
|
|
||||||
|
// check what we have in the DB
|
||||||
|
// 4 tests
|
||||||
|
resp = protocol.read({"noFeatureStateReset": true});
|
||||||
|
t.eq(resp.features.length, 1,
|
||||||
|
"createOrUpdate inserts feature in the DB");
|
||||||
|
t.eq(resp.features[0].fid, feature.fid,
|
||||||
|
"createOrUpdate inserts feature with correct fid");
|
||||||
|
t.eq(resp.features[0].attributes.fake, feature.attributes.fake,
|
||||||
|
"createOrUpdate inserts feature with correct attributes");
|
||||||
|
t.eq(resp.features[0].state, feature.state,
|
||||||
|
"createOrUpdate inserts feature with correct state");
|
||||||
|
|
||||||
|
protocol.clear();
|
||||||
|
protocol.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_delete(t) {
|
||||||
|
var protocol = new OpenLayers.Protocol.SQL.Gears();
|
||||||
|
if (!protocol.supported()) {
|
||||||
|
t.plan(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.plan(4);
|
||||||
|
|
||||||
|
function createOneAndDeleteOne(fid, deleteOptions) {
|
||||||
|
var feature = new OpenLayers.Feature.Vector();
|
||||||
|
feature.fid = fid;
|
||||||
|
feature.attributes.fake = "properties";
|
||||||
|
feature.state = OpenLayers.State.INSERT;
|
||||||
|
var r = protocol.create([feature]);
|
||||||
|
protocol["delete"](r.reqFeatures, deleteOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
var resp, fid;
|
||||||
|
|
||||||
|
// 1 test
|
||||||
|
fid = 1000;
|
||||||
|
protocol.saveFeatureState = false;
|
||||||
|
createOneAndDeleteOne(fid)
|
||||||
|
resp = protocol.read();
|
||||||
|
t.eq(resp.features.length, 0,
|
||||||
|
"delete deletes feature if saveFeatureState is false");
|
||||||
|
protocol.clear();
|
||||||
|
|
||||||
|
// 1 test
|
||||||
|
fid = 1000;
|
||||||
|
protocol.saveFeatureState = true;
|
||||||
|
createOneAndDeleteOne(fid);
|
||||||
|
resp = protocol.read();
|
||||||
|
t.eq(resp.features.length, 1,
|
||||||
|
"delete does not delete feature if saveFeatureState is true");
|
||||||
|
protocol.clear();
|
||||||
|
|
||||||
|
// 1 test
|
||||||
|
fid = "1000";
|
||||||
|
protocol.saveFeatureState = true;
|
||||||
|
createOneAndDeleteOne(fid);
|
||||||
|
resp = protocol.read();
|
||||||
|
t.eq(resp.features.length, 1,
|
||||||
|
"delete does not delete feature if saveFeatureState is true");
|
||||||
|
protocol.clear();
|
||||||
|
|
||||||
|
// 1 test
|
||||||
|
fid = protocol.FID_PREFIX + "1000";
|
||||||
|
protocol.saveFeatureState = true;
|
||||||
|
createOneAndDeleteOne(fid, {dontDelete: true});
|
||||||
|
resp = protocol.read();
|
||||||
|
t.eq(resp.features.length, 0,
|
||||||
|
"delete deletes feature if saveFeatureState is true and fid is prefixed");
|
||||||
|
protocol.clear();
|
||||||
|
|
||||||
|
protocol.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_callUserCallback(t) {
|
||||||
|
var protocol = new OpenLayers.Protocol.SQL.Gears();
|
||||||
|
if (!protocol.supported()) {
|
||||||
|
t.plan(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.plan(6);
|
||||||
|
|
||||||
|
var options, resp;
|
||||||
|
var scope = {'fake': 'scope'};
|
||||||
|
|
||||||
|
// test commit callback
|
||||||
|
// 1 tests
|
||||||
|
options = {
|
||||||
|
'callback': function() {
|
||||||
|
t.ok(this == scope, 'callback called with correct scope');
|
||||||
|
},
|
||||||
|
'scope': scope
|
||||||
|
};
|
||||||
|
resp = {'requestType': 'create', 'last': true};
|
||||||
|
protocol.callUserCallback(options, resp);
|
||||||
|
// 0 test
|
||||||
|
resp = {'requestType': 'create', 'last': false};
|
||||||
|
protocol.callUserCallback(options, resp);
|
||||||
|
|
||||||
|
// test create callback
|
||||||
|
// 2 tests
|
||||||
|
options = {
|
||||||
|
'create': {
|
||||||
|
'callback': function(r) {
|
||||||
|
t.ok(this == scope, 'callback called with correct scope');
|
||||||
|
t.ok(r == resp, 'callback called with correct response');
|
||||||
|
},
|
||||||
|
'scope': scope
|
||||||
|
}
|
||||||
|
};
|
||||||
|
resp = {'requestType': 'create'};
|
||||||
|
protocol.callUserCallback(options, resp);
|
||||||
|
|
||||||
|
// test with both callbacks set
|
||||||
|
// 3 tests
|
||||||
|
options = {
|
||||||
|
'create': {
|
||||||
|
'callback': function(r) {
|
||||||
|
t.ok(this == scope, 'callback called with correct scope');
|
||||||
|
t.ok(r == resp, 'callback called with correct response');
|
||||||
|
},
|
||||||
|
'scope': scope
|
||||||
|
},
|
||||||
|
'callback': function() {
|
||||||
|
t.ok(this == scope, 'callback called with correct scope');
|
||||||
|
},
|
||||||
|
'scope': scope
|
||||||
|
};
|
||||||
|
resp = {'requestType': 'create', 'last': true};
|
||||||
|
protocol.callUserCallback(options, resp);
|
||||||
|
|
||||||
|
// no callback set
|
||||||
|
// 0 test
|
||||||
|
options = {
|
||||||
|
'delete': {
|
||||||
|
'callback': function(resp) {
|
||||||
|
t.fail('callback should not get called');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
resp = {'requestType': 'create'};
|
||||||
|
protocol.callUserCallback(options, resp);
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
protocol.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -115,6 +115,8 @@
|
|||||||
<li>Projection.html</li>
|
<li>Projection.html</li>
|
||||||
<li>Protocol.html</li>
|
<li>Protocol.html</li>
|
||||||
<li>Protocol/HTTP.html</li>
|
<li>Protocol/HTTP.html</li>
|
||||||
|
<li>Protocol/SQL.html</li>
|
||||||
|
<li>Protocol/SQL/Gears.html</li>
|
||||||
<li>Renderer.html</li>
|
<li>Renderer.html</li>
|
||||||
<li>Renderer/Canvas.html</li>
|
<li>Renderer/Canvas.html</li>
|
||||||
<li>Renderer/Elements.html</li>
|
<li>Renderer/Elements.html</li>
|
||||||
|
|||||||
Reference in New Issue
Block a user