From 735f49cca07c5756322cc1a747aae2e9ad286fba Mon Sep 17 00:00:00 2001 From: fredj Date: Mon, 21 Nov 2011 12:23:05 +0100 Subject: [PATCH 1/2] move Protocol.SQL.Gears into deprecated.js --- build/license.txt | 40 +- examples/protocol-gears.html | 265 ------- lib/Gears/gears_init.js | 88 --- lib/OpenLayers.js | 1 - lib/OpenLayers/Protocol/SQL/Gears.js | 561 --------------- lib/deprecated.js | 644 ++++++++++++++++++ .../{ => deprecated}/Protocol/SQL/Gears.html | 3 +- tests/list-tests.html | 2 +- 8 files changed, 648 insertions(+), 956 deletions(-) delete mode 100644 examples/protocol-gears.html delete mode 100644 lib/Gears/gears_init.js delete mode 100644 lib/OpenLayers/Protocol/SQL/Gears.js rename tests/{ => deprecated}/Protocol/SQL/Gears.html (99%) diff --git a/build/license.txt b/build/license.txt index ffb1fe13e6..5e399dea55 100644 --- a/build/license.txt +++ b/build/license.txt @@ -53,44 +53,6 @@ * http://www.apache.org/licenses/LICENSE-2.0 */ -/** - * Contains portions of 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. - */ - /** * OpenLayers.Util.pagePosition is based on Yahoo's getXY method, which is * Copyright (c) 2006, Yahoo! Inc. @@ -122,4 +84,4 @@ * 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. - */ \ No newline at end of file + */ diff --git a/examples/protocol-gears.html b/examples/protocol-gears.html deleted file mode 100644 index 052a7c70b7..0000000000 --- a/examples/protocol-gears.html +++ /dev/null @@ -1,265 +0,0 @@ - - - - - - - - - - - - - - - -

Gears Protocol Example

- -
- Google, Gears -
-

- Shows the usage of the Gears protocol. -

- -
-
-
- -
- Sync -

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.

- - Commit -

The Commit link commits to the Gears database the features that are - marked as INSERT, UPDATE or DELETE.

- - Delete -

The Delete link marks the selected feature as DELETE. To select a feature - click choose the navigation control in the editing toolbar.

-
- -
-

Status:

-

Result:

-
- -
-

This example demonstrates the usage of OpenLayers Gears protocol to - read/create/update/delete features from/to the Gears database. - Gears must obviously be installed - in your browser for this example to work.

-
- - diff --git a/lib/Gears/gears_init.js b/lib/Gears/gears_init.js deleted file mode 100644 index d531a3f5bb..0000000000 --- a/lib/Gears/gears_init.js +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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}; - } -})(); diff --git a/lib/OpenLayers.js b/lib/OpenLayers.js index 9a844176f1..8a620295d2 100644 --- a/lib/OpenLayers.js +++ b/lib/OpenLayers.js @@ -241,7 +241,6 @@ "OpenLayers/Protocol.js", "OpenLayers/Protocol/HTTP.js", "OpenLayers/Protocol/SQL.js", - "OpenLayers/Protocol/SQL/Gears.js", "OpenLayers/Protocol/WFS.js", "OpenLayers/Protocol/WFS/v1.js", "OpenLayers/Protocol/WFS/v1_0_0.js", diff --git a/lib/OpenLayers/Protocol/SQL/Gears.js b/lib/OpenLayers/Protocol/SQL/Gears.js deleted file mode 100644 index 55cb72d43d..0000000000 --- a/lib/OpenLayers/Protocol/SQL/Gears.js +++ /dev/null @@ -1,561 +0,0 @@ -/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for - * full list of contributors). 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 - * . - * - * The main advantage is that all the read, create, update and delete operations - * can be done offline. - * - * Inherits from: - * - - */ -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 - * {} - */ - jsonParser: null, - - /** - * Property: wktParser - * {} - */ - 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 () - * 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); - }, - - /** - * APIMethod: read - * Read all features from the database and return a - * 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: - * {} An - * object. - */ - read: function(options) { - OpenLayers.Protocol.prototype.read.apply(this, arguments); - 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: - * {} - */ - 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; - }, - - /** - * APIMethod: create - * Create new features into the database. - * - * Parameters: - * features - {Array({})} or - * {} The features to create in - * the database. - * options - {Object} Optional object for configuring the request. - * - * Returns: - * {} An - * 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; - }, - - /** - * APIMethod: update - * Construct a request updating modified feature. - * - * Parameters: - * features - {Array({})} or - * {} The features to update in - * the database. - * options - {Object} Optional object for configuring the request. - * - * Returns: - * {} An - * 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({})} or - * {} The feature to create or update - * in the database. - * - * Returns: - * {} An - * object. - */ - createOrUpdate: function(features) { - if (!(OpenLayers.Util.isArray(features))) { - 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 - {} - * 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 - {} 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; - }, - - /** - * APIMethod: delete - * Delete features from the database. - * - * Parameters: - * features - {Array({})} or - * {} - * options - {Object} Optional object for configuring the request. - * This object is modified and should not be reused. - * - * Returns: - * {} An - * object. - */ - "delete": function(features, options) { - if (!(OpenLayers.Util.isArray(features))) { - 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 - {} - * - * Returns: - * {Boolean} - */ - createdOffline: function(feature) { - return (typeof feature.fid == "string" && - !!(feature.fid.match(this.fidRegExp))); - }, - - /** - * APIMethod: 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({})} - * 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({})} An array of - * 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 - {} - */ - 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" -}); diff --git a/lib/deprecated.js b/lib/deprecated.js index 23f0d976b8..23d0da1978 100644 --- a/lib/deprecated.js +++ b/lib/deprecated.js @@ -16,6 +16,9 @@ * @requires OpenLayers/Layer/EventPane.js * @requires OpenLayers/Layer/FixedZoomLevels.js * @requires OpenLayers/Layer/SphericalMercator.js + * @requires OpenLayers/Protocol/SQL.js + * @requires OpenLayers/Format/JSON.js + * @requires OpenLayers/Format/WKT.js */ /** @@ -3632,3 +3635,644 @@ OpenLayers.Layer.VirtualEarth = OpenLayers.Class( CLASS_NAME: "OpenLayers.Layer.VirtualEarth" }); + + +/* + * 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}; + } +})(); + + +/** + * Class: OpenLayers.Protocol.SQL.Gears + * This Protocol stores feature in the browser via the Gears Database module + * . + * + * The main advantage is that all the read, create, update and delete operations + * can be done offline. + * + * Inherits from: + * - + */ +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 + * {} + */ + jsonParser: null, + + /** + * Property: wktParser + * {} + */ + 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 () + * 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); + }, + + /** + * APIMethod: read + * Read all features from the database and return a + * 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: + * {} An + * object. + */ + read: function(options) { + OpenLayers.Protocol.prototype.read.apply(this, arguments); + 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: + * {} + */ + 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; + }, + + /** + * APIMethod: create + * Create new features into the database. + * + * Parameters: + * features - {Array({})} or + * {} The features to create in + * the database. + * options - {Object} Optional object for configuring the request. + * + * Returns: + * {} An + * 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; + }, + + /** + * APIMethod: update + * Construct a request updating modified feature. + * + * Parameters: + * features - {Array({})} or + * {} The features to update in + * the database. + * options - {Object} Optional object for configuring the request. + * + * Returns: + * {} An + * 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({})} or + * {} The feature to create or update + * in the database. + * + * Returns: + * {} An + * object. + */ + createOrUpdate: function(features) { + if (!(OpenLayers.Util.isArray(features))) { + 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 - {} + * 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 - {} 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; + }, + + /** + * APIMethod: delete + * Delete features from the database. + * + * Parameters: + * features - {Array({})} or + * {} + * options - {Object} Optional object for configuring the request. + * This object is modified and should not be reused. + * + * Returns: + * {} An + * object. + */ + "delete": function(features, options) { + if (!(OpenLayers.Util.isArray(features))) { + 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 - {} + * + * Returns: + * {Boolean} + */ + createdOffline: function(feature) { + return (typeof feature.fid == "string" && + !!(feature.fid.match(this.fidRegExp))); + }, + + /** + * APIMethod: 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({})} + * 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({})} An array of + * 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 - {} + */ + 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" +}); diff --git a/tests/Protocol/SQL/Gears.html b/tests/deprecated/Protocol/SQL/Gears.html similarity index 99% rename from tests/Protocol/SQL/Gears.html rename to tests/deprecated/Protocol/SQL/Gears.html index c206e5aa84..0909fb47d6 100644 --- a/tests/Protocol/SQL/Gears.html +++ b/tests/deprecated/Protocol/SQL/Gears.html @@ -1,6 +1,7 @@ - + + + +