OpenLayers OpenLayers

Ticket #1699: patch-1699-r7875-A0.diff

File patch-1699-r7875-A0.diff, 48.2 kB (added by elemoine, 2 years ago)
  • build/license.txt

    old new  
    5252 * You may obtain a copy of the License at 
    5353 * http://www.apache.org/licenses/LICENSE-2.0 
    5454 */ 
     55 
     56/** 
     57 * Contains portions of Gears <http://code.google.com/apis/gears/> 
     58 * 
     59 * Copyright 2007, Google Inc. 
     60 * 
     61 * Redistribution and use in source and binary forms, with or without 
     62 * modification, are permitted provided that the following conditions are met: 
     63 * 
     64 *  1. Redistributions of source code must retain the above copyright notice, 
     65 *     this list of conditions and the following disclaimer. 
     66 *  2. Redistributions in binary form must reproduce the above copyright notice, 
     67 *     this list of conditions and the following disclaimer in the documentation 
     68 *     and/or other materials provided with the distribution. 
     69 *  3. Neither the name of Google Inc. nor the names of its contributors may be 
     70 *     used to endorse or promote products derived from this software without 
     71 *     specific prior written permission. 
     72 * 
     73 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
     74 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
     75 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 
     76 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
     77 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
     78 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
     79 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
     80 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
     81 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
     82 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
     83 * 
     84 * Sets up google.gears.*, which is *the only* supported way to access Gears. 
     85 * 
     86 * Circumvent this file at your own risk! 
     87 * 
     88 * In the future, Gears may automatically define google.gears.* without this 
     89 * file. Gears may use these objects to transparently fix bugs and compatibility 
     90 * issues. Applications that use the code below will continue to work seamlessly 
     91 * when that happens. 
     92 */ 
  • tests/Protocol/SQL/Gears.html

    old new  
     1<html> 
     2<head> 
     3  <script src="../../../lib/OpenLayers.js"></script> 
     4  <script type="text/javascript"> 
     5 
     6    function test_initialize(t) { 
     7        var protocol = new OpenLayers.Protocol.SQL.Gears(); 
     8        if (!protocol.supported()) { 
     9            t.plan(0); 
     10            return; 
     11        } 
     12 
     13        t.plan(5); 
     14 
     15        t.eq(protocol.CLASS_NAME, "OpenLayers.Protocol.SQL.Gears", 
     16             "ctor returns correct value"); 
     17 
     18        t.eq(protocol.jsonParser.CLASS_NAME, 
     19             "OpenLayers.Format.JSON", 
     20             "ctor creates a JSON parser"); 
     21 
     22        t.eq(protocol.wktParser.CLASS_NAME, 
     23             "OpenLayers.Format.WKT", 
     24             "ctor creates a WKT parser"); 
     25 
     26        var str = protocol.FID_PREFIX + "foo_bar"; 
     27        t.ok(str.match(protocol.fidRegExp), 
     28             "ctor creates correct regexp"); 
     29 
     30        t.ok(typeof protocol.db == "object", 
     31             "ctor creates a db object"); 
     32 
     33        protocol.clear(); 
     34        protocol.destroy(); 
     35    } 
     36 
     37    function test_destroy(t) { 
     38        var protocol = new OpenLayers.Protocol.SQL.Gears(); 
     39        if (!protocol.supported()) { 
     40            t.plan(0); 
     41            return; 
     42        } 
     43 
     44        t.plan(3); 
     45 
     46        protocol.destroy(); 
     47 
     48        t.eq(protocol.db, null, 
     49             "destroy nullifies db"); 
     50        t.eq(protocol.jsonParser, null, 
     51             "destroy nullifies jsonParser"); 
     52        t.eq(protocol.wktParser, null, 
     53             "destroy nullifies wktParser"); 
     54     } 
     55 
     56    function test_read(t) { 
     57        var protocolCallback, readCallback; 
     58        var protocolOptions = {callback: protocolCallback}; 
     59        var readOptions = {callback: readCallback}; 
     60 
     61        var protocol = new OpenLayers.Protocol.SQL.Gears(protocolOptions); 
     62        if (!protocol.supported()) { 
     63            t.plan(0); 
     64            return; 
     65        } 
     66 
     67        function okCallback(resp) { 
     68            t.eq(resp.CLASS_NAME, "OpenLayers.Protocol.Response", 
     69                 "read calls correct callback with a response object"); 
     70        } 
     71 
     72        function failCallback(resp) { 
     73            t.fail("read calls incorrect callback"); 
     74        } 
     75 
     76        t.plan(4); 
     77 
     78        var resp; 
     79 
     80        // 2 tests 
     81        protocolOptions.callback = okCallback; 
     82        readOptions.callback = failCallback; 
     83        resp = protocol.read(); 
     84        t.eq(resp.CLASS_NAME, "OpenLayers.Protocol.Response", 
     85             "read returns a response object"); 
     86 
     87        // 2 test 
     88        protocolOptions.callback = failCallback; 
     89        readOptions.callback = okCallback; 
     90        resp = protocol.read(readOptions); 
     91        t.eq(resp.CLASS_NAME, "OpenLayers.Protocol.Response", 
     92             "read returns a response object"); 
     93 
     94        protocol.clear(); 
     95        protocol.destroy(); 
     96    } 
     97 
     98    function test_unfreezeFeature(t) { 
     99        var protocol = new OpenLayers.Protocol.SQL.Gears(); 
     100        if (!protocol.supported()) { 
     101            t.plan(0); 
     102            return; 
     103        } 
     104 
     105        t.plan(10); 
     106 
     107        var feature; 
     108        var wkt, json, fid, state; 
     109 
     110        json = "{\"fake\":\"properties\"}"; 
     111        fid = "1000"; 
     112        state = OpenLayers.State.INSERT; 
     113 
     114        var row = { 
     115            fieldByName: function(str) { 
     116                if (str == "geometry") { 
     117                    return wkt; 
     118                } 
     119                if (str == "properties") { 
     120                    return json; 
     121                } 
     122                if (str == "fid") { 
     123                    return fid; 
     124                } 
     125                if (str == "state") { 
     126                    return state; 
     127                } 
     128            } 
     129        }; 
     130 
     131        // 5 tests 
     132        wkt = "POINT(1 2)"; 
     133        feature = protocol.unfreezeFeature(row); 
     134        t.eq(feature.CLASS_NAME, "OpenLayers.Feature.Vector", 
     135             "unfreezeFeature returns an OpenLayers.Feature.Vector"); 
     136        t.ok(feature.geometry.x == 1 && feature.geometry.y == 2, 
     137             "unfreezeFeature returns a feature with correct geometry"); 
     138        t.eq(feature.attributes.fake, "properties", 
     139             "unfreezeFeature returns a feature with correct attributes"); 
     140        t.eq(feature.fid, fid, 
     141             "unfreezeFeature returns a feature with fid"); 
     142        t.eq(feature.state, state, 
     143             "unfreezeFeature returns a feature with state"); 
     144 
     145        // 5 tests 
     146        wkt = protocol.NULL_GEOMETRY; 
     147        state = protocol.NULL_FEATURE_STATE; 
     148        feature = protocol.unfreezeFeature(row); 
     149        t.eq(feature.CLASS_NAME, "OpenLayers.Feature.Vector", 
     150             "unfreezeFeature returns an OpenLayers.Feature.Vector"); 
     151        t.eq(feature.geometry, null, 
     152             "unfreezeFeature returns a feature with correct geometry"); 
     153        t.eq(feature.attributes.fake, "properties", 
     154             "unfreezeFeature returns a feature with correct attributes"); 
     155        t.eq(feature.fid, fid, 
     156             "unfreezeFeature returns a feature with fid"); 
     157        t.eq(feature.state, null, 
     158             "unfreezeFeature returns a feature with state"); 
     159 
     160        protocol.clear(); 
     161        protocol.destroy(); 
     162    } 
     163 
     164    function test_extractFidFromField(t) { 
     165        var protocol = new OpenLayers.Protocol.SQL.Gears(); 
     166        if (!protocol.supported()) { 
     167            t.plan(0); 
     168            return; 
     169        } 
     170 
     171        t.plan(4); 
     172 
     173        var field, fid; 
     174 
     175        // fid is a string, field is not prefixed with FID_PREFIX 
     176        // 1 test 
     177        field = "10"; 
     178        res = protocol.extractFidFromField(field); 
     179        t.eq(res, "10", 
     180             "extractFidFromField returns expected string"); 
     181 
     182        // fid is a string, field is prefixed with FID_PREFIX 
     183        // 1 test 
     184        field = protocol.FIX_PREFIX + "10"; 
     185        res = protocol.extractFidFromField(field); 
     186        t.eq(res, protocol.FIX_PREFIX + "10", 
     187             "extractFidFromField returns expected prefixed string"); 
     188 
     189        // fid is a number, field is not prefixed with FIX_PREFIX 
     190        // 1 test 
     191        protocol.typeOfFid = "number"; 
     192        field = "10"; 
     193        res = protocol.extractFidFromField(field); 
     194        t.eq(res, 10, 
     195             "extractFidFromField returns expected number"); 
     196 
     197        // fid is a number, field is prefixed with FIX_PREFIX 
     198        // 1 test 
     199        protocol.typeOfFid = "number"; 
     200        field = protocol.FID_PREFIX + "10"; 
     201        res = protocol.extractFidFromField(field); 
     202        t.eq(res, protocol.FID_PREFIX + "10", 
     203             "extractFidFromField returns expected prefixed string"); 
     204    } 
     205 
     206    function test_freezeFeature(t) { 
     207        var protocol = new OpenLayers.Protocol.SQL.Gears(); 
     208        if (!protocol.supported()) { 
     209            t.plan(0); 
     210            return; 
     211        } 
     212 
     213        t.plan(8); 
     214 
     215        var feature, res; 
     216 
     217        // 4 tests 
     218        feature = new OpenLayers.Feature.Vector(); 
     219        feature.geometry = new OpenLayers.Geometry.Point(1, 2); 
     220        feature.attributes.fake = "properties"; 
     221        feature.fid = "1000"; 
     222        feature.state = OpenLayers.State.INSERT; 
     223        res = protocol.freezeFeature(feature); 
     224        t.eq(res[0], feature.fid, 
     225             "freezeFeature returns correct fid"); 
     226        t.eq(res[1], "POINT(1 2)", 
     227             "freezeFeature returns correct WKT"); 
     228        t.eq(res[2], "{\"fake\":\"properties\"}", 
     229             "freezeFeature returns correct JSON"); 
     230        t.eq(res[3], feature.state, 
     231             "freezeFeature returns correct feature state"); 
     232 
     233        // 4 tests 
     234        protocol.saveFeatureState = false; 
     235        feature = new OpenLayers.Feature.Vector(); 
     236        feature.attributes.fake = "properties"; 
     237        feature.fid = "1000"; 
     238        feature.state = OpenLayers.State.INSERT; 
     239        res = protocol.freezeFeature(feature); 
     240        t.eq(res[0], feature.fid, 
     241             "freezeFeature returns correct fid"); 
     242        t.eq(res[1], protocol.NULL_GEOMETRY, 
     243             "freezeFeature returns expected null geom string"); 
     244        t.eq(res[2], "{\"fake\":\"properties\"}", 
     245             "freezeFeature returns correct JSON"); 
     246        t.eq(res[3], protocol.NULL_FEATURE_STATE, 
     247             "freezeFeature returns expected null feature state string"); 
     248 
     249        protocol.clear(); 
     250        protocol.destroy(); 
     251     } 
     252 
     253     function test_createOrUpdate(t) { 
     254        var protocol = new OpenLayers.Protocol.SQL.Gears(); 
     255        if (!protocol.supported()) { 
     256            t.plan(0); 
     257            return; 
     258        } 
     259 
     260        t.plan(8); 
     261 
     262        var resp; 
     263        var scope = {"fake": "scope"}; 
     264        var requestType = "create"; 
     265 
     266        var options = { 
     267            callback: function(resp) { 
     268                t.eq(resp.CLASS_NAME, "OpenLayers.Protocol.Response", 
     269                     "user callback is passed a response"); 
     270                t.eq(resp.requestType, requestType, 
     271                     "user callback is passed correct request type in resp"); 
     272                t.ok(this == scope, 
     273                     "user callback called with correct scope"); 
     274            }, 
     275            scope: scope 
     276        }; 
     277 
     278        // 4 tests 
     279        var feature = new OpenLayers.Feature.Vector(); 
     280        feature.fid = "1000"; 
     281        feature.attributes.fake = "properties"; 
     282        feature.state = OpenLayers.State.INSERT; 
     283        resp = protocol.createOrUpdate([feature], options, requestType); 
     284        t.eq(resp.CLASS_NAME, "OpenLayers.Protocol.Response", 
     285             "createOrUpdate returns a response"); 
     286 
     287        // check what we have in the DB 
     288        // 4 tests 
     289        resp = protocol.read(); 
     290        t.eq(resp.features.length, 1, 
     291             "createOrUpdate inserts feature in the DB"); 
     292        t.eq(resp.features[0].fid, feature.fid, 
     293             "createOrUpdate inserts feature with correct fid"); 
     294        t.eq(resp.features[0].attributes.fake, feature.attributes.fake, 
     295             "createOrUpdate inserts feature with correct attributes"); 
     296        t.eq(resp.features[0].state, feature.state, 
     297             "createOrUpdate inserts feature with correct state"); 
     298 
     299        protocol.clear(); 
     300        protocol.destroy(); 
     301    } 
     302 
     303    function test_delete(t) { 
     304        var protocol = new OpenLayers.Protocol.SQL.Gears(); 
     305        if (!protocol.supported()) { 
     306            t.plan(0); 
     307            return; 
     308        } 
     309 
     310        t.plan(4); 
     311 
     312        function createOneAndDeleteOne(fid, deleteOptions) { 
     313            var feature = new OpenLayers.Feature.Vector(); 
     314            feature.fid = fid; 
     315            feature.attributes.fake = "properties"; 
     316            feature.state = OpenLayers.State.INSERT; 
     317            var r = protocol.create([feature]); 
     318            protocol["delete"](r.reqFeatures, deleteOptions); 
     319        } 
     320 
     321        var resp, fid; 
     322 
     323        // 1 test 
     324        fid = 1000; 
     325        createOneAndDeleteOne(fid) 
     326        resp = protocol.read(); 
     327        t.eq(resp.features.length, 0, 
     328             "delete deletes feature in the DB"); 
     329        protocol.clear(); 
     330 
     331        // 1 test 
     332        fid = 1000; 
     333        createOneAndDeleteOne(fid, {dontDelete: true}); 
     334        resp = protocol.read(); 
     335        t.eq(resp.features.length, 1, 
     336             "delete does not delete feature if dontDelete is true"); 
     337        protocol.clear(); 
     338 
     339        // 1 test 
     340        fid = "1000"; 
     341        createOneAndDeleteOne(fid, {dontDelete: true}); 
     342        resp = protocol.read(); 
     343        t.eq(resp.features.length, 1, 
     344             "delete does not delete feature if dontDelete is true"); 
     345        protocol.clear(); 
     346 
     347        // 1 test 
     348        fid = protocol.FID_PREFIX + "1000"; 
     349        createOneAndDeleteOne(fid, {dontDelete: true}); 
     350        resp = protocol.read(); 
     351        t.eq(resp.features.length, 0, 
     352             "delete deletes feature if dontDelete is true and fid is prefixed"); 
     353        protocol.clear(); 
     354 
     355        protocol.destroy(); 
     356    } 
     357 
     358    function test_callUserCallback(t) { 
     359        var protocol = new OpenLayers.Protocol.SQL.Gears(); 
     360        if (!protocol.supported()) { 
     361            t.plan(0); 
     362            return; 
     363        } 
     364 
     365        t.plan(6); 
     366 
     367        var options, resp; 
     368        var scope = {'fake': 'scope'}; 
     369 
     370        // test commit callback 
     371        // 1 tests 
     372        options = { 
     373            'callback': function() { 
     374                t.ok(this == scope, 'callback called with correct scope'); 
     375            }, 
     376            'scope': scope 
     377        }; 
     378        resp = {'requestType': 'create', 'last': true}; 
     379        protocol.callUserCallback(options, resp); 
     380        // 0 test 
     381        resp = {'requestType': 'create', 'last': false}; 
     382        protocol.callUserCallback(options, resp); 
     383 
     384        // test create callback 
     385        // 2 tests 
     386        options = { 
     387            'create': { 
     388                'callback': function(r) { 
     389                    t.ok(this == scope, 'callback called with correct scope'); 
     390                    t.ok(r == resp, 'callback called with correct response'); 
     391                }, 
     392                'scope': scope 
     393            } 
     394        }; 
     395        resp = {'requestType': 'create'}; 
     396        protocol.callUserCallback(options, resp); 
     397 
     398        // test with both callbacks set 
     399        // 3 tests 
     400        options = { 
     401            'create': { 
     402                'callback': function(r) { 
     403                    t.ok(this == scope, 'callback called with correct scope'); 
     404                    t.ok(r == resp, 'callback called with correct response'); 
     405                }, 
     406                'scope': scope 
     407            }, 
     408            'callback': function() { 
     409                t.ok(this == scope, 'callback called with correct scope'); 
     410            }, 
     411            'scope': scope 
     412        }; 
     413        resp = {'requestType': 'create', 'last': true}; 
     414        protocol.callUserCallback(options, resp); 
     415 
     416        // no callback set 
     417        // 0 test 
     418        options = { 
     419            'delete': { 
     420                'callback': function(resp) { 
     421                    t.fail('callback should not get called'); 
     422                } 
     423            } 
     424        }; 
     425        resp = {'requestType': 'create'}; 
     426        protocol.callUserCallback(options, resp); 
     427 
     428        // cleanup 
     429        protocol.destroy(); 
     430    } 
     431 
     432  </script> 
     433</head> 
     434<body> 
     435</body> 
     436</html> 
  • tests/Protocol/SQL.html

    old new  
     1<html> 
     2<head> 
     3  <script src="../../lib/OpenLayers.js"></script> 
     4  <script type="text/javascript"> 
     5 
     6    function test_initialize(t) { 
     7        t.plan(3); 
     8        var options = {tableName: 'my_features',  
     9                       databaseName: 'my_database_name'} 
     10        var protocol = new OpenLayers.Protocol.SQL(options); 
     11 
     12        t.ok(protocol instanceof OpenLayers.Protocol.SQL, 
     13             "new OpenLayers.Protocol.SQL returns object"); 
     14 
     15        t.eq(protocol.tableName, options.tableName, "tableName property is set"); 
     16        t.eq(protocol.databaseName, options.databaseName, "databaseName property is set"); 
     17    } 
     18     
     19  </script> 
     20</head> 
     21<body> 
     22</body> 
     23</html> 
  • tests/list-tests.html

    old new  
    113113    <li>Popup/FramedCloud.html</li> 
    114114    <li>Projection.html</li> 
    115115    <li>Protocol.html</li> 
     116    <li>Protocol/SQL.html</li> 
     117    <li>Protocol/SQL/Gears.html</li> 
    116118    <li>Renderer.html</li> 
    117119    <li>Renderer/Canvas.html</li> 
    118120    <li>Renderer/Elements.html</li> 
  • lib/OpenLayers/Protocol/SQL/Gears.js

    old new  
     1/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD 
     2 * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the 
     3 * full text of the license. */ 
     4 
     5/** 
     6 * @requires Gears/gears_init.js 
     7 * @requires OpenLayers/Protocol/SQL.js 
     8 * @requires OpenLayers/Format/JSON.js 
     9 * @requires OpenLayers/Format/WKT.js 
     10 */ 
     11 
     12/** 
     13 * Class: OpenLayers.Protocol.SQL.Gears 
     14 * This Protocol stores feature in the browser via the Gears Database module  
     15 * <http://code.google.com/apis/gears/api_database.html>. 
     16 * 
     17 * The main advantage is that all the read, create, update and delete operations  
     18 * can be done offline. 
     19 * 
     20 * Inherits from: 
     21 *  - <OpenLayers.Protocol.SQL> 
     22 */ 
     23OpenLayers.Protocol.SQL.Gears = OpenLayers.Class(OpenLayers.Protocol.SQL, { 
     24 
     25    /** 
     26     * Property: FID_PREFIX 
     27     * {String} 
     28     */ 
     29    FID_PREFIX: '__gears_fid__', 
     30 
     31    /** 
     32     * Property: NULL_GEOMETRY 
     33     * {String} 
     34     */ 
     35    NULL_GEOMETRY: '__gears_null_geometry__', 
     36 
     37    /** 
     38     * Property: NULL_FEATURE_STATE 
     39     * {String} 
     40     */ 
     41    NULL_FEATURE_STATE: '__gears_null_feature_state__', 
     42 
     43    /** 
     44     * Property: jsonParser 
     45     * {<OpenLayers.Format.JSON>} 
     46     */ 
     47    jsonParser: null, 
     48 
     49    /** 
     50     * Property: wktParser 
     51     * {<OpenLayers.Format.WKT>} 
     52     */ 
     53    wktParser: null, 
     54 
     55    /** 
     56     * Property: fidRegExp 
     57     * {RegExp} Regular expression to know whether a feature was 
     58     *      created in offline mode. 
     59     */ 
     60    fidRegExp: null, 
     61 
     62    /** 
     63     * Property: saveFeatureState 
     64     * {Boolean} Whether to save the feature state (<OpenLayers.State>) 
     65     *      into the database. 
     66     */     
     67    saveFeatureState: true, 
     68 
     69    /** 
     70     * Property: typeOfFid 
     71     * {String} The type of the feature identifier, either "number" or 
     72     *      "string", defaults to "string". 
     73     */ 
     74    typeOfFid: "string", 
     75 
     76    /** 
     77     * Property: db 
     78     * {GearsDatabase} 
     79     */ 
     80    db: null, 
     81 
     82    /** 
     83     * Constructor: OpenLayers.Protocol.SQL.Gears 
     84     */ 
     85    initialize: function(options) { 
     86        if (!this.supported()) { 
     87            return; 
     88        } 
     89        OpenLayers.Protocol.SQL.prototype.initialize.apply(this, [options]); 
     90        this.jsonParser = new OpenLayers.Format.JSON(); 
     91        this.wktParser = new OpenLayers.Format.WKT(); 
     92 
     93        this.fidRegExp = new RegExp('^' + this.FID_PREFIX); 
     94        this.initializeDatabase(); 
     95 
     96         
     97    }, 
     98 
     99    /** 
     100     * Method: initializeDatabase 
     101     */ 
     102    initializeDatabase: function() { 
     103        this.db = google.gears.factory.create('beta.database'); 
     104        this.db.open(this.databaseName); 
     105        this.db.execute( 
     106            "CREATE TABLE IF NOT EXISTS " + this.tableName + 
     107            " (fid TEXT UNIQUE, geometry TEXT, properties TEXT," + 
     108            "  state TEXT)"); 
     109   }, 
     110 
     111    /** 
     112     * APIMethod: destroy 
     113     * Clean up the protocol. 
     114     */ 
     115    destroy: function() { 
     116        this.db.close(); 
     117        this.db = null; 
     118 
     119        this.jsonParser = null; 
     120        this.wktParser = null; 
     121 
     122        OpenLayers.Protocol.SQL.prototype.destroy.apply(this); 
     123    }, 
     124 
     125    /** 
     126     * APIMethod: supported 
     127     * Determine whether a browser supports Gears 
     128     * 
     129     * Returns: 
     130     * {Boolean} The browser supports Gears 
     131     */ 
     132    supported: function() { 
     133        return !!(window.google && google.gears); 
     134    }, 
     135 
     136    /** 
     137     * Method: read 
     138     * Read all features from the database and return a 
     139     * <OpenLayers.Protocol.Response> instance. If the options parameter 
     140     * contains a callback attribute, the function is called with the response 
     141     * as a parameter. 
     142     * 
     143     * Parameters: 
     144     * options - {Object} Optional parameter that may contain a callback 
     145     * attribute. 
     146     * 
     147     * Returns: 
     148     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response> 
     149     *      object. 
     150     */ 
     151    read: function(options) { 
     152        options = OpenLayers.Util.applyDefaults(options, this.options); 
     153 
     154        var features = []; 
     155        var rs = this.db.execute("SELECT * FROM " + this.tableName); 
     156        while (rs.isValidRow()) { 
     157            features.push(this.unfreezeFeature(rs)); 
     158            rs.next(); 
     159        } 
     160        rs.close(); 
     161 
     162        var resp = new OpenLayers.Protocol.Response({ 
     163            code: OpenLayers.Protocol.Response.SUCCESS, 
     164            requestType: "read", 
     165            features: features 
     166        }); 
     167 
     168        if (options && options.callback) { 
     169            options.callback.call(options.scope, resp); 
     170        } 
     171 
     172        return resp; 
     173    }, 
     174 
     175    /** 
     176     * Method: unfreezeFeature 
     177     * 
     178     * Parameters: 
     179     * row - {ResultSet} 
     180     * 
     181     * Returns: 
     182     * {<OpenLayers.Feature.Vector>} 
     183     */ 
     184    unfreezeFeature: function(row) { 
     185        var feature; 
     186        var wkt = row.fieldByName('geometry'); 
     187        if (wkt == this.NULL_GEOMETRY) { 
     188            feature = new OpenLayers.Feature.Vector(); 
     189        } else { 
     190            feature = this.wktParser.read(wkt); 
     191        } 
     192 
     193        feature.attributes = this.jsonParser.read( 
     194            row.fieldByName('properties')); 
     195 
     196        feature.fid = this.extractFidFromField(row.fieldByName('fid')); 
     197 
     198        var state = row.fieldByName('state'); 
     199        if (state == this.NULL_FEATURE_STATE) { 
     200            state = null; 
     201        } 
     202        feature.state = state; 
     203 
     204        return feature; 
     205    }, 
     206 
     207    /** 
     208     * Method: extractFidFromField 
     209     * 
     210     * Parameters: 
     211     * field - {String} 
     212     * 
     213     * Returns 
     214     * {String} or {Number} The fid. 
     215     */ 
     216    extractFidFromField: function(field) { 
     217        if (!field.match(this.fidRegExp) && this.typeOfFid == "number") { 
     218            field = parseFloat(field); 
     219        } 
     220        return field; 
     221    }, 
     222 
     223    /** 
     224     * Method: create 
     225     * Create new features into the database. 
     226     * 
     227     * Parameters: 
     228     * features - {Array({<OpenLayers.Feature.Vector>})} or 
     229     *            {<OpenLayers.Feature.Vector>}. 
     230     * options - {Object} Optional object for configuring the request. 
     231     * 
     232     * Returns: 
     233     *  {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response> 
     234     *          object. 
     235     */ 
     236    create: function(features, options) { 
     237        return this.createOrUpdate(features, options, "create"); 
     238    }, 
     239 
     240    /** 
     241     * Method: update 
     242     * Construct a request updating modified feature. 
     243     * 
     244     * Parameters: 
     245     * features - {Array({<OpenLayers.Feature.Vector>})} or 
     246     *            {<OpenLayers.Feature.Vector>}. 
     247     * options - {Object} Optional object for configuring the request. 
     248     * 
     249     * Returns: 
     250     *  {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response> 
     251     *          object. 
     252     */ 
     253    update: function(features, options) { 
     254        return this.createOrUpdate(features, options, "update"); 
     255    }, 
     256 
     257    /** 
     258     * Method: createOrUpdate 
     259     * Construct a request for updating or creating features in the 
     260     * database. 
     261     * 
     262     * Parameters: 
     263     * features - {Array({<OpenLayers.Feature.Vector>})} or 
     264     *            {<OpenLayers.Feature.Vector>}. 
     265     * options - {Object} Optional object for configuring the request. 
     266     * requestType - {String} Either "create" or "update". 
     267     * 
     268     * Returns: 
     269     *  {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response> 
     270     *          object. 
     271     */ 
     272    createOrUpdate: function(features, options, requestType) { 
     273        if (!(features instanceof Array)) { 
     274            features = [features]; 
     275        } 
     276 
     277        options = OpenLayers.Util.applyDefaults(options, this.options); 
     278 
     279        var i, len = features.length, feature; 
     280        var insertedFeatures = new Array(len); 
     281  
     282        for (i = 0; i < len; i++) { 
     283            feature = features[i]; 
     284            this.db.execute( 
     285                "REPLACE INTO " + this.tableName +  
     286                " (fid, geometry, properties, state)" +  
     287                " VALUES (?, ?, ?, ?)", 
     288                this.freezeFeature(feature) 
     289            ); 
     290            var clone = feature.clone(); 
     291            clone.fid = feature.fid; 
     292            insertedFeatures[i] = clone; 
     293        } 
     294 
     295        var resp = new OpenLayers.Protocol.Response({ 
     296            code: OpenLayers.Protocol.Response.SUCCESS, 
     297            requestType: requestType, 
     298            features: insertedFeatures, 
     299            reqFeatures: features 
     300        }); 
     301 
     302        if (options && options.callback) { 
     303            options.callback.call(options.scope, resp); 
     304        } 
     305 
     306        return resp; 
     307    }, 
     308 
     309    /** 
     310     * Method: freezeFeature 
     311     * 
     312     * Parameters: 
     313     * feature - {<OpenLayers.Feature.Vector>} 
     314     * 
     315     * Returns: 
     316     * {Array} 
     317     */ 
     318    freezeFeature: function(feature) { 
     319        feature.fid = feature.fid != null ? 
     320            feature.fid : OpenLayers.Util.createUniqueID(this.FID_PREFIX); 
     321 
     322        var geometry = feature.geometry ? 
     323            feature.geometry.toString() : this.NULL_GEOMETRY; 
     324        var state = this.saveFeatureState ? 
     325            feature.state : this.NULL_FEATURE_STATE; 
     326 
     327        return [ 
     328            feature.fid, 
     329            geometry, 
     330            this.jsonParser.write(feature.attributes), 
     331            state 
     332        ]; 
     333    }, 
     334 
     335    /** 
     336     * Method: delete 
     337     * Delete features from the database. 
     338     * 
     339     * Parameters: 
     340     * features - {Array({<OpenLayers.Feature.Vector>})} or 
     341     *            {<OpenLayers.Feature.Vector>} 
     342     * options - {Object} Optional object for configuring the request, it 
     343     *      may include a dontDelete property that indicates whether a 
     344     *      feature that wasn't created offline must actually be deleted 
     345     *      from the database or just be updated (with its new state). 
     346     *       This object is modified and should not be reused. 
     347     * 
     348     * Returns: 
     349     *  {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response> 
     350     *          object. 
     351     */ 
     352    "delete": function(features, options) { 
     353        if (!(features instanceof Array)) { 
     354            features = [features]; 
     355        } 
     356 
     357        options = OpenLayers.Util.applyDefaults(options, this.options); 
     358 
     359        var i, len, feature; 
     360        for (i = 0, len = features.length; i < len; i++) { 
     361            feature = features[i]; 
     362 
     363            // if the dontDelete flag is set in the options and if the feature 
     364            // wasn't created offline then don't delete it in the database 
     365            var doDelete = (typeof feature.fid == 'string' && 
     366                            !!(feature.fid.match(this.fidRegExp))); 
     367            if (options.dontDelete && !doDelete) { 
     368                var toDelete = feature.clone(); 
     369                toDelete.fid = feature.fid; 
     370                if (toDelete.geometry) { 
     371                    toDelete.geometry.destroy(); 
     372                    toDelete.geometry = null; 
     373                } 
     374                toDelete.state = feature.state; 
     375                 
     376                this.update(toDelete); 
     377            } else { 
     378                this.db.execute( 
     379                    "DELETE FROM " + this.tableName + 
     380                    " WHERE fid = ?", [feature.fid]); 
     381            } 
     382        } 
     383 
     384        var resp = new OpenLayers.Protocol.Response({ 
     385            code: OpenLayers.Protocol.Response.SUCCESS, 
     386            requestType: "delete", 
     387            reqFeatures: features 
     388        }); 
     389 
     390        if (options && options.callback) { 
     391            options.callback.call(options.scope, resp); 
     392        } 
     393 
     394        return resp; 
     395    }, 
     396 
     397    /** 
     398     * Method: commit 
     399     * Go over the features and for each take action 
     400     * based on the feature state. Possible actions are create, 
     401     * update and delete. 
     402     * 
     403     * Parameters: 
     404     * features - {Array({<OpenLayers.Feature.Vector>})} 
     405     * options - {Object} Object whose possible keys are "create", "update", 
     406     *      "delete", "callback" and "scope", the values referenced by the 
     407     *      first three are objects as passed to the "create", "update", and 
     408     *      "delete" methods, the value referenced by the "callback" key is 
     409     *      a function which is called when the commit operation is complete 
     410     *      using the scope referenced by the "scope" key. 
     411     * 
     412     * Returns: 
     413     * {Array({<OpenLayers.Protocol.Response>})} An array of 
     414     *       <OpenLayers.Protocol.Response> objects, one per request made 
     415     *       to the database. 
     416     */ 
     417    commit: function(features, options) { 
     418        var opt, resp = [], nRequests = 0, nResponses = 0; 
     419 
     420        function callback(resp) { 
     421            if (++nResponses < nRequests) { 
     422                resp.last = false; 
     423            } 
     424            this.callUserCallback(options, resp); 
     425        } 
     426 
     427        var feature, toCreate = [], toUpdate = [], toDelete = []; 
     428        for (var i = features.length - 1; i >= 0; i--) { 
     429            feature = features[i]; 
     430            switch (feature.state) { 
     431            case OpenLayers.State.INSERT: 
     432                toCreate.push(feature); 
     433                break; 
     434            case OpenLayers.State.UPDATE: 
     435                toUpdate.push(feature); 
     436                break; 
     437            case OpenLayers.State.DELETE: 
     438                toDelete.push(feature); 
     439                break; 
     440            } 
     441        } 
     442        if (toCreate.length > 0) { 
     443            nRequests++; 
     444            opt = OpenLayers.Util.applyDefaults( 
     445                {"callback": callback, "scope": this}, 
     446                options.create 
     447            ); 
     448            resp.push(this.create(toCreate, opt)); 
     449        } 
     450        if (toUpdate.length > 0) { 
     451            nRequests++; 
     452            opt = OpenLayers.Util.applyDefaults( 
     453                {"callback": callback, "scope": this}, 
     454                options.update 
     455            ); 
     456            resp.push(this.update(toUpdate, opt)); 
     457        } 
     458        if (toDelete.length > 0) { 
     459            nRequests++; 
     460            opt = OpenLayers.Util.applyDefaults( 
     461                {"callback": callback, "scope": this}, 
     462                options["delete"] 
     463            ); 
     464            resp.push(this["delete"](toDelete, opt)); 
     465        } 
     466 
     467        return resp; 
     468    }, 
     469 
     470    /** 
     471     * Method: clear 
     472     * Removes all rows of the table. 
     473     */ 
     474    clear: function() { 
     475        this.db.execute("DELETE FROM " + this.tableName); 
     476    }, 
     477 
     478    /** 
     479     * Method: callUserCallback 
     480     * This method is called from within commit each time a request is made 
     481     * to the database, it is responsible for calling the user-supplied 
     482     * callbacks. 
     483     * 
     484     * Parameters: 
     485     * options - {Object} The map of options passed to the commit call. 
     486     * resp - {<OpenLayers.Protocol.Response>} 
     487     */ 
     488    callUserCallback: function(options, resp) { 
     489        var opt = options[resp.requestType]; 
     490        if (opt && opt.callback) { 
     491            opt.callback.call(opt.scope, resp); 
     492        } 
     493        if (resp.last && options.callback) { 
     494            options.callback.call(options.scope); 
     495        } 
     496    }, 
     497 
     498    CLASS_NAME: "OpenLayers.Protocol.SQL.Gears" 
     499}); 
  • lib/OpenLayers/Protocol/SQL.js

    old new  
     1/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD 
     2 * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the 
     3 * full text of the license. */ 
     4 
     5/** 
     6 * @requires OpenLayers/Protocol.js 
     7 */ 
     8 
     9/** 
     10 * Class: OpenLayers.Protocol.SQL 
     11 * Abstract SQL protocol class.  Not to be instantiated directly.  Use 
     12 *     one of the SQL protocol subclasses instead. 
     13 * 
     14 * Inherits from: 
     15 *  - <OpenLayers.Protocol> 
     16 */ 
     17OpenLayers.Protocol.SQL = OpenLayers.Class(OpenLayers.Protocol, { 
     18 
     19    /** 
     20     * APIProperty: databaseName 
     21     * {String} 
     22     */ 
     23    databaseName: 'ol', 
     24 
     25    /** 
     26     * APIProperty: tableName 
     27     * Name of the database table into which Features should be saved. 
     28     */ 
     29    tableName: "ol_vector_features", 
     30 
     31    /** 
     32     * Constructor: OpenLayers.Protocol.SQL 
     33     */ 
     34    initialize: function(options) { 
     35        OpenLayers.Protocol.prototype.initialize.apply(this, [options]); 
     36    }, 
     37 
     38    /** 
     39     * APIMethod: destroy 
     40     * Clean up the protocol. 
     41     */ 
     42    destroy: function() { 
     43        OpenLayers.Protocol.prototype.destroy.apply(this); 
     44    }, 
     45 
     46    /** 
     47     * APIMethod: supported 
     48     * This should be overridden by specific subclasses 
     49     * 
     50     * Returns: 
     51     * {Boolean} Whether or not the browser supports the SQL backend 
     52     */ 
     53    supported: function() { 
     54        return false; 
     55    }, 
     56 
     57    CLASS_NAME: "OpenLayers.Protocol.SQL" 
     58}); 
     59 
     60 
     61/** 
     62 * APIFunction: factory. 
     63 * Alternative constructor 
     64 */ 
     65OpenLayers.Protocol.SQL.factory = function(options) { 
     66    // Available SQL backends. 
     67    var sqls = ["Gears"]; 
     68 
     69    for (var i = 0; i < sqls.length; i++) { 
     70        var sql = OpenLayers.Protocol.SQL[sqls[i]]; 
     71        if (sql && sql.prototype.supported()) { 
     72            return new sql(options); 
     73        } 
     74        OpenLayers.Console.userError("No SQL backend supported ..."); 
     75    } 
     76} 
  • lib/Gears/gears_init.js

    old new  
     1/* 
     2 * Copyright 2007, Google Inc. 
     3 * 
     4 * Redistribution and use in source and binary forms, with or without 
     5 * modification, are permitted provided that the following conditions are met: 
     6 * 
     7 *  1. Redistributions of source code must retain the above copyright notice, 
     8 *     this list of conditions and the following disclaimer. 
     9 *  2. Redistributions in binary form must reproduce the above copyright notice, 
     10 *     this list of conditions and the following disclaimer in the documentation 
     11 *     and/or other materials provided with the distribution. 
     12 *  3. Neither the name of Google Inc. nor the names of its contributors may be 
     13 *     used to endorse or promote products derived from this software without 
     14 *     specific prior written permission. 
     15 * 
     16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
     17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
     18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 
     19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
     20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
     21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
     22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
     23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
     24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
     25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
     26 * 
     27 * Sets up google.gears.*, which is *the only* supported way to access Gears. 
     28 * 
     29 * Circumvent this file at your own risk! 
     30 * 
     31 * In the future, Gears may automatically define google.gears.* without this 
     32 * file. Gears may use these objects to transparently fix bugs and compatibility 
     33 * issues. Applications that use the code below will continue to work seamlessly 
     34 * when that happens. 
     35 */ 
     36 
     37(function() { 
     38  // We are already defined. Hooray! 
     39  if (window.google && google.gears) { 
     40    return; 
     41  } 
     42 
     43  var factory = null; 
     44 
     45  // Firefox 
     46  if (typeof GearsFactory != 'undefined') { 
     47    factory = new GearsFactory(); 
     48  } else { 
     49    // IE 
     50    try { 
     51      factory = new ActiveXObject('Gears.Factory'); 
     52      // privateSetGlobalObject is only required and supported on WinCE. 
     53      if (factory.getBuildInfo().indexOf('ie_mobile') != -1) { 
     54        factory.privateSetGlobalObject(this); 
     55      } 
     56    } catch (e) { 
     57      // Safari 
     58      if ((typeof navigator.mimeTypes != 'undefined') 
     59           && navigator.mimeTypes["application/x-googlegears"]) { 
     60        factory = document.createElement("object"); 
     61        factory.style.display = "none"; 
     62        factory.width = 0; 
     63        factory.height = 0; 
     64        factory.type = "application/x-googlegears"; 
     65        document.documentElement.appendChild(factory); 
     66      } 
     67    } 
     68  } 
     69 
     70  // *Do not* define any objects if Gears is not installed. This mimics the 
     71  // behavior of Gears defining the objects in the future. 
     72  if (!factory) { 
     73    return; 
     74  } 
     75 
     76  // Now set up the objects, being careful not to overwrite anything. 
     77  // 
     78  // Note: In Internet Explorer for Windows Mobile, you can't add properties to 
     79  // the window object. However, global objects are automatically added as 
     80  // properties of the window object in all browsers. 
     81  if (!window.google) { 
     82    google = {}; 
     83  } 
     84 
     85  if (!google.gears) { 
     86    google.gears = {factory: factory}; 
     87  } 
     88})(); 
  • lib/OpenLayers.js

    old new  
    8383            "OpenLayers/Tween.js", 
    8484            "Rico/Corner.js", 
    8585            "Rico/Color.js", 
     86            "Gears/gears_init.js", 
    8687            "OpenLayers/Ajax.js", 
    8788            "OpenLayers/Request.js", 
    8889            "OpenLayers/Request/XMLHttpRequest.js", 
     
    184185            "OpenLayers/Strategy.js", 
    185186            "OpenLayers/Strategy/Fixed.js", 
    186187            "OpenLayers/Protocol.js", 
     188            "OpenLayers/Protocol/SQL.js", 
     189            "OpenLayers/Protocol/SQL/Gears.js", 
    187190            "OpenLayers/Layer/PointTrack.js", 
    188191            "OpenLayers/Layer/GML.js", 
    189192            "OpenLayers/Style.js", 
  • examples/protocol-gears.html

    old new  
     1<html xmlns="http://www.w3.org/1999/xhtml"> 
     2  <head> 
     3    <link rel="stylesheet" href="../theme/default/style.css" type="text/css" /> 
     4    <link rel="stylesheet" href="style.css" type="text/css" /> 
     5    <style type="text/css"> 
     6        .float-left { 
     7            float: left; 
     8        } 
     9        .clear-left { 
     10            clear: left; 
     11        } 
     12    </style> 
     13    <script src="../lib/OpenLayers.js"></script> 
     14    <script type="text/javascript"> 
     15        var map, vector, protocol, modify; 
     16 
     17        function init() { 
     18            // create Gears protocol 
     19            protocol = new OpenLayers.Protocol.SQL.Gears({ 
     20                databaseName: "db_name", 
     21                tableName: "table_name", 
     22                saveFeatureState: false 
     23            }); 
     24 
     25            if (!GearsIsSupported()) { 
     26                return; 
     27            } 
     28 
     29            map = new OpenLayers.Map("map"); 
     30 
     31            // create base layer 
     32            var layer = new OpenLayers.Layer.WMS("OpenLayers WMS", 
     33                "http://labs.metacarta.com/wms/vmap0", 
     34                {"layers": "basic"} 
     35            ); 
     36            map.addLayer(layer); 
     37 
     38            // create vector layer 
     39            vector = new OpenLayers.Layer.Vector("Vector", { 
     40                protocol: protocol, 
     41                strategies : [new OpenLayers.Strategy.Fixed()], 
     42                eventListeners: { 
     43                    featuremodified: function(obj) { 
     44                        if (obj.feature.state != OpenLayers.State.INSERT && 
     45                            obj.feature.state != OpenLayers.State.DELETE) { 
     46 
     47                            obj.feature.state = OpenLayers.State.UPDATE; 
     48                        } 
     49                        displayStatus(); 
     50                    } 
     51                } 
     52            }); 
     53            map.addLayer(vector); 
     54 
     55            // create modify feature control 
     56            modify = new OpenLayers.Control.ModifyFeature(vector); 
     57 
     58            // create editing panel 
     59            var panel = new OpenLayers.Control.Panel({ 
     60                displayClass: "olControlEditingToolbar" 
     61            }); 
     62 
     63            var navigation = new OpenLayers.Control.Navigation({ 
     64                eventListeners: { 
     65                    activate: function(obj) { 
     66                        modify.activate(); 
     67                    }, 
     68                    deactivate: function(obj) { 
     69                        modify.deactivate(); 
     70                    } 
     71                } 
     72            }); 
     73 
     74            var editing = new OpenLayers.Control.DrawFeature( 
     75                vector, OpenLayers.Handler.Polygon, { 
     76                displayClass: "olControlDrawFeaturePolygon", 
     77                eventListeners: { 
     78                    featureadded: function(obj) { 
     79                        obj.feature.state = OpenLayers.State.INSERT; 
     80                        displayStatus(); 
     81                    } 
     82                } 
     83            }); 
     84            panel.addControls([navigation, editing]); 
     85            panel.defaultControl = navigation; 
     86 
     87            // add controls to the map 
     88            map.addControl(modify); 
     89            map.addControl(panel); 
     90 
     91            // center the map 
     92            map.setCenter(new OpenLayers.LonLat(5, 40), 5); 
     93        } 
     94 
     95        function displayResult(txt) { 
     96            if (window.resultDomElement === undefined) { 
     97                window.resultDomElement = OpenLayers.Util.getElement("last-result"); 
     98            } 
     99            resultDomElement.innerHTML = txt; 
     100            displayStatus(); 
     101        } 
     102 
     103        function displayStatus() { 
     104            if (window.statusDomElement === undefined) { 
     105                window.statusDomElement = OpenLayers.Util.getElement("status"); 
     106            } 
     107 
     108            var createCnt = 0; 
     109            var updateCnt = 0; 
     110            var deleteCnt = 0; 
     111            var i, len, state; 
     112            for (i = 0, len = vector.features.length; i < len; i++) { 
     113                state = vector.features[i].state; 
     114                if (state == OpenLayers.State.INSERT) { 
     115                    createCnt++; 
     116                } else if (state == OpenLayers.State.UPDATE) { 
     117                    updateCnt++; 
     118                } else if (state == OpenLayers.State.DELETE) { 
     119                    deleteCnt++; 
     120                } 
     121            } 
     122            statusDomElement.innerHTML = createCnt + " features to create, " + 
     123                                         updateCnt + " features to update, " + 
     124                                         deleteCnt + " features to delete"; 
     125        } 
     126 
     127        function GearsIsSupported() { 
     128            if (!protocol.supported()) { 
     129                OpenLayers.Console.userError("You must install Gears prior to using this example"); 
     130                return false; 
     131            } 
     132            return true; 
     133        } 
     134 
     135        function featuresWithState(state) { 
     136            var list = []; 
     137            var i, len, feature; 
     138            for (i = 0, len = vector.features.length; i < len; i++) { 
     139                feature = vector.features[i]; 
     140                if (feature.state == state) { 
     141                    list.push(feature); 
     142                } 
     143            } 
     144            return list; 
     145        } 
     146 
     147        function _sync() { 
     148            if (!GearsIsSupported()) { 
     149                return; 
     150            } 
     151            var resp = protocol.read(); 
     152            if (!resp.success()) { 
     153                OpenLayers.Console.error("reading from Gears DB failed"); 
     154                return; 
     155            } 
     156            vector.destroyFeatures(); 
     157            if (!resp.features || resp.features.length <= 0) { 
     158                displayResult("No features to read"); 
     159                return; 
     160            } 
     161            vector.addFeatures(resp.features); 
     162            displayResult("features successfully read"); 
     163        } 
     164 
     165        function _commit() { 
     166            if (!GearsIsSupported()) { 
     167                return; 
     168            } 
     169            var error = false; 
     170            function callback(resp) { 
     171                if (error) { 
     172                    return; 
     173                } 
     174                if (!resp.success()) { 
     175                    OpenLayers.Console.error("Commiting to Gears DB failed"); 
     176                    error = true; 
     177                    return; 
     178                } 
     179                modify.selectControl.unselectAll() 
     180 
     181                if (resp.reqFeatures) { 
     182                    vector.destroyFeatures(resp.reqFeatures); 
     183                } 
     184                if (resp.features) { 
     185                    vector.addFeatures(resp.features); 
     186                } 
     187            } 
     188            if (vector.features.length > 0) { 
     189                protocol.commit(vector.features, { 
     190                    "create": { 
     191                        callback: callback 
     192                    }, 
     193                    "update": { 
     194                        callback: callback 
     195                    }, 
     196                    "delete": { 
     197                        callback: callback 
     198                    } 
     199                }); 
     200                if (!error) { 
     201                    displayResult("features successfully committed"); 
     202                } 
     203            } else { 
     204                displayResult("no features to commit"); 
     205            } 
     206        } 
     207 
     208        function _delete() { 
     209            if (!GearsIsSupported()) { 
     210                return; 
     211            } 
     212            var feature = vector.selectedFeatures[0]; 
     213            if (feature) { 
     214                modify.selectControl.unselectAll() 
     215                feature.state = OpenLayers.State.DELETE; 
     216                displayStatus(); 
     217            } 
     218        } 
     219    </script> 
     220  </head> 
     221  <body onload="init()"> 
     222    <h1 id="title">Gears Protocol Example</h1> 
     223 
     224    <div id="tags"> 
     225    </div> 
     226    <p id="shortdesc"> 
     227        Shows the usage of the Gears protocol. 
     228    </p> 
     229 
     230    <div class="float-left"> 
     231      <div id="map" class="smallmap"></div> 
     232    </div> 
     233 
     234    <div> 
     235      <a href="javascript:_sync()">Sync</a> 
     236      <p>The Sync link destroys the features currently in the layer, reads 
     237         features from the Gears database, and adds them to the layer. 
     238         Uncommitted features will be lost.</p> 
     239 
     240      <a href="javascript:_commit()">Commit</a> 
     241      <p>The Commit link commits to the Gears database the features that are 
     242         marked as INSERT, UPDATE or DELETE.</p> 
     243 
     244      <a href="javascript:_delete()">Delete</a> 
     245      <p>The Delete link marks the selected feature as DELETE. To select a feature 
     246         click choose the navigation control in the editing toolbar.</p> 
     247    </div> 
     248 
     249    <div style="margin-top: 30px"> 
     250      <p>Status: <span id="status"></span></p> 
     251      <p>Result: <span id="last-result"></span></p> 
     252    </div> 
     253 
     254    <div class="clear-left" id="docs"> 
     255      <p>This example demonstrates the usage of OpenLayers Gears protocol to 
     256         read/create/update/delete features from/to the Gears database. 
     257         <a href="http://gears.google.com/">Gears</a> must obviously be installed 
     258         in your browser for this example to work.</p> 
     259    </div> 
     260  </body> 
     261</html>