OpenLayers OpenLayers

Ticket #1652: patch-1652-r7754-A1.diff

File patch-1652-r7754-A1.diff, 36.6 kB (added by fredj, 4 months ago)

Sync patch with trunk, fix coding style (no functional change)

  • tests/Protocol/HTTP.html

    old new  
     1<html> 
     2<head> 
     3  <script src="../../lib/OpenLayers.js"></script> 
     4  <script type="text/javascript"> 
     5 
     6    function test_Protocol_HTTP_constructor(t) { 
     7        t.plan(8); 
     8        var a = new OpenLayers.Protocol.HTTP({ 
     9            url: "foo" 
     10        }); 
     11 
     12        // 4 tests 
     13        t.eq(a.url, "foo", "constructor sets url"); 
     14        t.eq(a.options.url, a.url, "constructor copies url to options.url"); 
     15        t.eq(a.params, {}, "constructor sets params"); 
     16        t.eq(a.options.params, undefined, "constructor do not copy params to options.params"); 
     17 
     18        var params = {hello: "world"}; 
     19        var b = new OpenLayers.Protocol.HTTP({ 
     20            url: "bar", 
     21            params: params 
     22        }); 
     23 
     24        // 4 tests 
     25        t.eq(b.url, "bar", "constructor sets url"); 
     26        t.eq(b.options.url, b.url, "constructor copies url to options.url"); 
     27        t.eq(b.params, params, "constructor sets params"); 
     28        t.eq(b.options.params, b.params, "constructor copies params to options.params"); 
     29    } 
     30 
     31    function test_Protocol_HTTP_destroy(t) { 
     32        t.plan(3); 
     33        var protocol = new OpenLayers.Protocol.HTTP({ 
     34            url: "bar", 
     35            params: {hello: "world"} 
     36        }); 
     37        protocol.destroy(); 
     38        t.eq(protocol.options, null, "destroy nullifies options"); 
     39        t.eq(protocol.params, null, "destroy nullifies params"); 
     40        t.eq(protocol.headers, null, "destroy nullifies headers"); 
     41    } 
     42 
     43    function test_Protocol_HTTP_read(t) { 
     44        t.plan(10); 
     45        var protocol = new OpenLayers.Protocol.HTTP({ 
     46            'url': 'foo_url', 
     47            'params': {'k': 'foo_param'} 
     48        }); 
     49 
     50        // fake XHR request object 
     51        var request = {'status': 200}; 
     52 
     53        // options to pass to read 
     54        var readOptions = { 
     55            'url': 'bar_url', 
     56            'params': {'k': 'bar_param'}, 
     57            'headers': {'k': 'bar_header'}, 
     58            'scope': {'hello': 'world'}, 
     59            'callback': function() {} 
     60        }; 
     61 
     62        var response; 
     63 
     64        protocol.callbackReadCreateUpdate = function(opt, resp, req) { 
     65            // 4 tests 
     66            t.ok(this == protocol, 
     67                'callbackReadCreateUpdate called with correct scope'); 
     68            t.ok(opt == readOptions, 
     69                'callbackReadCreateUpdate called with correct options'); 
     70            t.eq(resp.CLASS_NAME, 'OpenLayers.Protocol.Response', 
     71                'callbackReadCreateUpdate called with a Response object'); 
     72            t.eq(req, request, 
     73                'callbackReadCreateUpdate called with correct request'); 
     74 
     75            response = resp; 
     76        }; 
     77 
     78        var _get = OpenLayers.Request.GET; 
     79 
     80        OpenLayers.Request.GET = function(options) { 
     81            // 5 tests 
     82            t.eq(options.url, readOptions.url, 
     83                'GET called with correct url in options'); 
     84            t.eq(options.params['k'], readOptions.params['k'], 
     85                'GET called with correct params in options'); 
     86            t.eq(options.headers['k'], readOptions.headers['k'], 
     87                'GET called with correct headers in options'); 
     88            t.eq(options.scope, undefined, 
     89                'GET called with correct scope in options'); 
     90            t.ok(typeof options.callback == 'function', 
     91                'GET called with a callback in options'); 
     92            options.callback(request); 
     93        }; 
     94 
     95        var resp = protocol.read(readOptions); 
     96        t.ok(resp == response, 
     97            'read returns the expected response object'); 
     98 
     99        // cleanup 
     100        protocol.destroy(); 
     101        OpenLayers.Request.GET = _get; 
     102    } 
     103 
     104    function test_Protocol_HTTP_readResponse(t) { 
     105        t.plan(5); 
     106 
     107        var protocol = new OpenLayers.Protocol.HTTP(); 
     108 
     109        // test responseXML - 2 tests 
     110        var request = { 
     111            'responseXML': { 
     112                'documentElement': 'xml' 
     113            } 
     114        }; 
     115        protocol.format = { 
     116            'read': function(doc) { 
     117                t.eq(doc.documentElement, 'xml', 
     118                    'format.read called with correct doc'); 
     119                return doc.documentElement; 
     120            } 
     121        }; 
     122        var ret = protocol.readResponse(request); 
     123        t.eq(ret, 'xml', 'readResponse returns expected value'); 
     124 
     125        // test responseText - 2 tests 
     126        var request = { 
     127            'responseText': 'text' 
     128        }; 
     129        protocol.format = { 
     130            'read': function(doc) { 
     131                t.eq(doc, 'text', 
     132                    'format.read called with correct doc'); 
     133                return doc; 
     134            } 
     135        }; 
     136        var ret = protocol.readResponse(request); 
     137        t.eq(ret, 'text', 'readResponse returns expected value'); 
     138 
     139        // test empty responseText - 1 test 
     140        var request = { 
     141            'responseText': '' 
     142        }; 
     143        protocol.format = { 
     144            'read': function(doc) { 
     145                t.fail('format.read should not be called'); 
     146            } 
     147        }; 
     148        var ret = protocol.readResponse(request); 
     149        t.eq(ret, null, 'readResponse returns expected value'); 
     150    } 
     151 
     152    function test_Protocol_HTTP_create(t) { 
     153        t.plan(10); 
     154        var protocol = new OpenLayers.Protocol.HTTP({ 
     155            'url': 'foo_url', 
     156            'format': {'write': function() {}} 
     157        }); 
     158 
     159        // fake XHR request object 
     160        var request = {'status': 200}; 
     161 
     162        // features to pass to create 
     163        var features = ['feature']; 
     164 
     165        // options to pass to create 
     166        var createOptions = { 
     167            'url': 'bar_url', 
     168            'headers': {'k': 'bar_header'}, 
     169            'scope': {'hello': 'world'}, 
     170            'callback': function() {} 
     171        }; 
     172 
     173        var response; 
     174 
     175        protocol.callbackCreate = function(opt, resp, req) { 
     176            // 5 tests 
     177            t.ok(this == protocol, 
     178                'callbackCreate called with correct scope'); 
     179            t.ok(opt == createOptions, 
     180                'callbackCreate called with correct options'); 
     181            t.eq(resp.CLASS_NAME, 'OpenLayers.Protocol.Response', 
     182                'callbackCreate called with a Response object'); 
     183            t.ok(resp.reqFeatures == features, 
     184                'callbackCreate called with correct requested features in response'); 
     185            t.eq(req, request, 
     186                'callbackCreate called with correct request'); 
     187 
     188            response = resp; 
     189        }; 
     190 
     191        var _post = OpenLayers.Request.POST; 
     192 
     193        OpenLayers.Request.POST = function(options) { 
     194            // 4 tests 
     195            t.eq(options.url, createOptions.url, 
     196                'POST called with correct url in options'); 
     197            t.eq(options.headers['k'], createOptions.headers['k'], 
     198                'POST called with correct headers in options'); 
     199            t.eq(options.scope, undefined, 
     200                'POST called with correct scope in options'); 
     201            t.ok(typeof options.callback == 'function', 
     202                'POST called with a callback in options'); 
     203            // call callback 
     204            options.callback(request); 
     205        }; 
     206 
     207        var resp = protocol.create(features, createOptions); 
     208        t.ok(resp == response, 
     209            'read returns the expected response object'); 
     210 
     211        // cleanup 
     212        protocol.destroy(); 
     213        OpenLayers.Request.POST = _post; 
     214    } 
     215 
     216    function test_Protocol_HTTP_update(t) { 
     217        t.plan(10); 
     218        var protocol = new OpenLayers.Protocol.HTTP({ 
     219            'url': 'foo_url', 
     220            'format': {'write': function() {}} 
     221        }); 
     222 
     223        // fake XHR request object 
     224        var request = {'status': 200}; 
     225 
     226        // feature to pass to update 
     227        var feature = {'feature':'feature'}; 
     228 
     229        // options to pass to update 
     230        var updateOptions = { 
     231            'url': 'bar_url', 
     232            'headers': {'k': 'bar_header'}, 
     233            'scope': {'hello': 'world'}, 
     234            'callback': function() {} 
     235        }; 
     236 
     237        var response; 
     238 
     239        protocol.callbackUpdate = function(opt, resp, req) { 
     240            // 5 tests 
     241            t.ok(this == protocol, 
     242                'callbackUpdate called with correct scope'); 
     243            t.ok(opt == updateOptions, 
     244                'callbackUpdate called with correct options'); 
     245            t.eq(resp.CLASS_NAME, 'OpenLayers.Protocol.Response', 
     246                'callbackUpdate called with a Response object'); 
     247            t.ok(resp.reqFeatures == feature, 
     248                'callbackUpdate called with correct requested feature in response'); 
     249            t.eq(req, request, 
     250                'callbackUpdate called with correct request'); 
     251 
     252            response = resp; 
     253        }; 
     254 
     255        var _put = OpenLayers.Request.PUT; 
     256 
     257        OpenLayers.Request.PUT = function(options) { 
     258            // 4 tests 
     259            t.eq(options.url, updateOptions.url, 
     260                'PUT called with correct url in options'); 
     261            t.eq(options.headers['k'], updateOptions.headers['k'], 
     262                'PUT called with correct headers in options'); 
     263            t.eq(options.scope, undefined, 
     264                'PUT called with correct scope in options'); 
     265            t.ok(typeof options.callback == 'function', 
     266                'PUT called with a callback in options'); 
     267            // call callback 
     268            options.callback(request); 
     269        }; 
     270 
     271        var resp = protocol.update(feature, updateOptions); 
     272        t.ok(resp == response, 
     273            'read returns the expected response object'); 
     274 
     275        // cleanup 
     276        protocol.destroy(); 
     277        OpenLayers.Request.PUT = _put; 
     278    } 
     279    function test_Protocol_HTTP_callbackReadCreateUpdate(t) { 
     280        t.plan(6); 
     281 
     282        var protocol = new OpenLayers.Protocol.HTTP(); 
     283 
     284        var options, response, request, features; 
     285 
     286        // test options - 2 tests 
     287        var scope = {'fake': 'scope'}; 
     288        options = { 
     289            'scope': scope, 
     290            'callback': function(resp) { 
     291                t.ok(this == scope, 
     292                    'callback called with correct scope'); 
     293                t.ok(resp == response, 
     294                    'callback called with correct response'); 
     295            } 
     296        }; 
     297        response = {'fake': 'reponse'}; 
     298        request = {'fake': 'request'}; 
     299        protocol.callbackReadCreateUpdate(options, response, request); 
     300         
     301        // test failure condition - 1 test 
     302        options = { 
     303            'callback': function(resp) { 
     304                t.eq(resp.code, OpenLayers.Protocol.Response.FAILURE, 
     305                    'callback called with correct response code'); 
     306            } 
     307        }; 
     308        response = {'fake': 'reponse'}; 
     309        request = {'status': 400}; 
     310        protocol.callbackReadCreateUpdate(options, response, request); 
     311 
     312        // test success condition - 3 tests 
     313        features = {'fake': 'features'}; 
     314        options = { 
     315            'callback': function(resp) { 
     316                t.eq(resp.code, OpenLayers.Protocol.Response.SUCCESS, 
     317                    'callback called with correct response code'); 
     318                t.ok(resp.features, features, 
     319                    'callback called with correct features in response'); 
     320            } 
     321        }; 
     322        response = {'fake': 'reponse'}; 
     323        request = {'status': 200}; 
     324        protocol.readResponse = function(req) { 
     325            t.ok(req == req, 
     326                'readResponse called with correct request'); 
     327            return features; 
     328        } 
     329        protocol.callbackReadCreateUpdate(options, response, request); 
     330 
     331        // cleanup 
     332        protocol.destroy(); 
     333    } 
     334 
     335    function test_Protocol_HTTP_delete(t) { 
     336        t.plan(10); 
     337        var protocol = new OpenLayers.Protocol.HTTP({ 
     338            'url': 'foo_url' 
     339        }); 
     340 
     341        // fake XHR request object 
     342        var request = {'status': 200}; 
     343 
     344        // feature to pass to delete 
     345        var feature = {'url': 'bar_url'}; 
     346 
     347        // options to pass to delete 
     348        var deleteOptions = { 
     349            'url': 'bar_url', 
     350            'headers': {'k': 'bar_header'}, 
     351            'scope': {'hello': 'world'}, 
     352            'callback': function() {} 
     353        }; 
     354 
     355        var response; 
     356 
     357        protocol.callbackDelete = function(opt, resp, req) { 
     358            // 5 tests 
     359            t.ok(this == protocol, 
     360                'callbackDelete called with correct scope'); 
     361            t.ok(opt == deleteOptions, 
     362                'callbackDelete called with correct options'); 
     363            t.eq(resp.CLASS_NAME, 'OpenLayers.Protocol.Response', 
     364                'callbackDelete called with a Response object'); 
     365            t.ok(resp.reqFeatures == feature, 
     366                'callbackDelete called with correct requested feature in response'); 
     367            t.eq(req, request, 
     368                'callbackDelete called with correct request'); 
     369 
     370            response = resp; 
     371        }; 
     372 
     373        var _delete = OpenLayers.Request.DELETE; 
     374 
     375        OpenLayers.Request.DELETE = function(options) { 
     376            // 4 tests 
     377            t.eq(options.url, deleteOptions.url, 
     378                'DELETE called with correct url in options'); 
     379            t.eq(options.headers['k'], deleteOptions.headers['k'], 
     380                'DELETE called with correct headers in options'); 
     381            t.eq(options.scope, undefined, 
     382                'DELETE called with correct scope in options'); 
     383            t.ok(typeof options.callback == 'function', 
     384                'DELETE called with a callback in options'); 
     385            // call callback 
     386            options.callback(request); 
     387        }; 
     388 
     389        var resp = protocol['delete'](feature, deleteOptions); 
     390        t.ok(resp == response, 
     391            'read returns the expected response object'); 
     392 
     393        // cleanup 
     394        protocol.destroy(); 
     395        OpenLayers.Request.DELETE = _delete; 
     396    } 
     397 
     398    function test_Protocol_HTTP_callbackDelete(t) { 
     399        t.plan(4); 
     400 
     401        var protocol = new OpenLayers.Protocol.HTTP(); 
     402 
     403        var options, response, request, features; 
     404 
     405        // test options - 2 tests 
     406        var scope = {'fake': 'scope'}; 
     407        options = { 
     408            'scope': scope, 
     409            'callback': function(resp) { 
     410                t.ok(this == scope, 
     411                    'callback called with correct scope'); 
     412                t.ok(resp == response, 
     413                    'callback called with correct response'); 
     414            } 
     415        }; 
     416        response = {'fake': 'reponse'}; 
     417        request = {'fake': 'request'}; 
     418        protocol.callbackDelete(options, response, request); 
     419         
     420        // test failure condition - 1 test 
     421        options = { 
     422            'callback': function(resp) { 
     423                t.eq(resp.code, OpenLayers.Protocol.Response.FAILURE, 
     424                    'callback called with correct response code'); 
     425            } 
     426        }; 
     427        response = {'fake': 'reponse'}; 
     428        request = {'status': 400}; 
     429        protocol.callbackDelete(options, response, request); 
     430 
     431        // test success condition - 1 test 
     432        options = { 
     433            'callback': function(resp) { 
     434                t.eq(resp.code, OpenLayers.Protocol.Response.SUCCESS, 
     435                    'callback called with correct response code'); 
     436            } 
     437        }; 
     438        response = {'fake': 'reponse'}; 
     439        request = {'status': 200}; 
     440        protocol.callbackDelete(options, response, request); 
     441 
     442        // cleanup 
     443        protocol.destroy(); 
     444    } 
     445 
     446    function test_Protocol_HTTP_commit(t) { 
     447        t.plan(17); 
     448 
     449        var protocol = new OpenLayers.Protocol.HTTP(); 
     450 
     451        // 6 features 
     452        var features = [ 
     453            {'state': OpenLayers.State.INSERT}, 
     454            {'state': OpenLayers.State.INSERT}, 
     455            {'state': OpenLayers.State.UPDATE}, 
     456            {'state': OpenLayers.State.UPDATE}, 
     457            {'state': OpenLayers.State.DELETE}, 
     458            {'state': OpenLayers.State.DELETE} 
     459        ]; 
     460 
     461        var options = { 
     462            'create': { 
     463                'callback': function(resp) { 
     464                } 
     465            }, 
     466            'update': { 
     467                'callback': function(resp) { 
     468                } 
     469            }, 
     470            'delete': { 
     471                'callback': function(resp) { 
     472                } 
     473            } 
     474        }; 
     475 
     476        var respCreate = new OpenLayers.Protocol.Response(); 
     477        var respUpdate = new OpenLayers.Protocol.Response(); 
     478        var respDelete = new OpenLayers.Protocol.Response(); 
     479 
     480        // 2 tests 
     481        protocol['create'] = function(feature, options) { 
     482            t.ok(options.scope == protocol, 
     483                'create called with correct scope'); 
     484            t.ok(typeof options.callback == 'function', 
     485                'create called with a callback in options'); 
     486            options.callback.call(options.scope, respCreate); 
     487            return respCreate; 
     488        }; 
     489        // 4 tests 
     490        protocol['update'] = function(feature, options) { 
     491            t.ok(options.scope == protocol, 
     492                'update called with correct scope'); 
     493            t.ok(typeof options.callback == 'function', 
     494                'update called with a callback in options'); 
     495            options.callback.call(options.scope, respUpdate); 
     496            return respUpdate; 
     497        }; 
     498        // 4 tests 
     499        protocol['delete'] = function(feature, options) { 
     500            t.ok(options.scope == protocol, 
     501                'delete called with correct scope'); 
     502            t.ok(typeof options.callback == 'function', 
     503                'delete called with a callback in options'); 
     504            options.callback.call(options.scope, respDelete); 
     505            return respDelete; 
     506        }; 
     507 
     508        var count = 0; 
     509 
     510        // 5 tests 
     511        protocol.callUserCallback = function(opt, resp) { 
     512            t.ok(opt == options, 
     513                'callUserCallback called with correction options map'); 
     514            count++; 
     515        }; 
     516 
     517        var resp = protocol.commit(features, options); 
     518 
     519        // 2 tests 
     520        t.eq(count, 5, 'callUserCallback called for each request'); 
     521        t.eq(resp.length, 5, 'commit returns array with correct length'); 
     522 
     523        // cleanup 
     524        protocol.destroy(); 
     525    } 
     526 
     527    function test_Protocol_HTTP_callUserCallback(t) { 
     528        t.plan(6); 
     529 
     530        var protocol = new OpenLayers.Protocol.HTTP(); 
     531 
     532        var options, resp; 
     533        var scope = {'fake': 'scope'}; 
     534 
     535        // test commit callback 
     536        // 1 tests 
     537        options = { 
     538            'callback': function() { 
     539                t.ok(this == scope, 'callback called with correct scope'); 
     540            }, 
     541            'scope': scope 
     542        }; 
     543        resp = {'requestType': 'create', 'last': true}; 
     544        protocol.callUserCallback(options, resp); 
     545        // 0 test 
     546        resp = {'requestType': 'create', 'last': false}; 
     547        protocol.callUserCallback(options, resp); 
     548 
     549        // test create callback 
     550        // 2 tests 
     551        options = { 
     552            'create': { 
     553                'callback': function(r) { 
     554                    t.ok(this == scope, 'callback called with correct scope'); 
     555                    t.ok(r == resp, 'callback called with correct response'); 
     556                }, 
     557                'scope': scope 
     558            } 
     559        }; 
     560        resp = {'requestType': 'create'}; 
     561        protocol.callUserCallback(options, resp); 
     562 
     563        // test with both callbacks set 
     564        // 3 tests 
     565        options = { 
     566            'create': { 
     567                'callback': function(r) { 
     568                    t.ok(this == scope, 'callback called with correct scope'); 
     569                    t.ok(r == resp, 'callback called with correct response'); 
     570                }, 
     571                'scope': scope 
     572            }, 
     573            'callback': function() { 
     574                t.ok(this == scope, 'callback called with correct scope'); 
     575            }, 
     576            'scope': scope 
     577        }; 
     578        resp = {'requestType': 'create', 'last': true}; 
     579        protocol.callUserCallback(options, resp); 
     580 
     581        // no callback set 
     582        // 0 test 
     583        options = { 
     584            'delete': { 
     585                'callback': function(resp) { 
     586                    t.fail('callback should not get called'); 
     587                } 
     588            } 
     589        }; 
     590        resp = {'requestType': 'create'}; 
     591        protocol.callUserCallback(options, resp); 
     592 
     593        // cleanup 
     594        protocol.destroy(); 
     595    } 
     596  </script> 
     597</head> 
     598<body> 
     599<div id="map" style="width:512px; height:256px"> </div> 
     600</body> 
     601</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/HTTP.html</li> 
    116117    <li>Renderer.html</li> 
    117118    <li>Renderer/Canvas.html</li> 
    118119    <li>Renderer/Elements.html</li> 
  • lib/OpenLayers/Protocol/HTTP.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 * @requires OpenLayers/Feature/Vector.js 
     8 */ 
     9 
     10/** 
     11 * Class: OpenLayers.Protocol.HTTP 
     12 * A basic HTTP protocol for vector layers.  Create a new instance with the 
     13 *     <OpenLayers.Protocol.HTTP> constructor. 
     14 * 
     15 * Inherits from: 
     16 *  - <OpenLayers.Protocol> 
     17 */ 
     18OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, { 
     19 
     20    /** 
     21     * Property: url 
     22     * {String} - Service URL 
     23     */ 
     24    url: null, 
     25 
     26    /** 
     27     * Property: headers 
     28     * {Object} - HTTP request headers 
     29     *      Example: {'Content-Type': 'plain/text'} 
     30     */ 
     31    headers: null, 
     32 
     33    /** 
     34     * Property: params 
     35     * {Object} - Parameters of GET requests 
     36     *      Example: {'bbox': '5,5,5,5'} 
     37     */ 
     38    params: null, 
     39 
     40    /** 
     41     * Property: scope 
     42     * {Object} - Callback execution scope 
     43     */ 
     44    scope: null, 
     45 
     46    /** 
     47     * Property: options 
     48     * {Object} - Options object, properties are: 
     49     *      {String} url 
     50     *      {Object} headers 
     51     *      {Object} params 
     52     *      {Object} scope 
     53     */ 
     54    options: null, 
     55     
     56    /** 
     57     * Constructor: OpenLayers.Protocol.HTTP 
     58     * A class for giving layers generic HTTP protocol. 
     59     * 
     60     * Parameters: 
     61     * options - {Object} Optional object whose properties will be set on the 
     62     *     instance. 
     63     */ 
     64    initialize: function(options) { 
     65        this.params = {}; 
     66        this.headers = {}; 
     67        OpenLayers.Protocol.prototype.initialize.apply(this, arguments); 
     68    }, 
     69     
     70    /** 
     71     * APIMethod: destroy 
     72     * Clean up the protocol. 
     73     */ 
     74    destroy: function() { 
     75        this.params = null; 
     76        this.headers = null; 
     77        OpenLayers.Protocol.prototype.destroy.apply(this); 
     78    }, 
     79    
     80    /** 
     81     * Method: read 
     82     * Construct a request for reading new features. 
     83     * 
     84     * Parameters: 
     85     * options - {Object} Optional object for configuring the request. 
     86     *     This object is modified and should not be reused. 
     87     * 
     88     * Returns: 
     89     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response> 
     90     *      object, whose "priv" property references the HTTP request, this  
     91     *      object is also passed to the callback function when the request 
     92     *      completes, its "features" property is then populated with the 
     93     *      the features received from the server. 
     94     */ 
     95    "read": function(options) { 
     96        options = OpenLayers.Util.applyDefaults(options, this.options); 
     97 
     98        var resp = new OpenLayers.Protocol.Response({ 
     99            requestType: "read" 
     100        }); 
     101 
     102        // do the bind ourself, to be able to pass options and resp to 
     103        // the read callback 
     104        var callback = OpenLayers.Function.bind(this.callbackRead,  
     105                                                this,  
     106                                                options,  
     107                                                resp); 
     108 
     109        resp.priv = OpenLayers.Request.GET({ 
     110            url: options.url, 
     111            callback: callback, 
     112            params: options.params, 
     113            headers: options.headers 
     114        });         
     115 
     116        return resp; 
     117    }, 
     118 
     119    /** 
     120     * Method: callbackRead 
     121     * Individual callbacks are created for read, create and update, should 
     122     * a subclass need to override each one separately. 
     123     * 
     124     * Parameters: 
     125     * options - {Object} The user options passed to the read call. 
     126     * resp - {<OpenLayers.Protocol.Response>} The 
     127     *      <OpenLayers.Protocol.Response> object to pass to the user 
     128     *      callback. 
     129     * request - {Object} The request object returned by XHR. 
     130     */ 
     131    callbackRead: function(options, resp, request) { 
     132        this.callbackReadCreateUpdate(options, resp, request); 
     133    }, 
     134 
     135    /** 
     136     * Method: readResponse 
     137     * Read HTTP response body and return features 
     138     * 
     139     * Parameters: 
     140     * request - {Object} The request object 
     141     * 
     142     * Returns: 
     143     * {Array({<OpenLayers.Feature.Vector>})} or 
     144     * {<OpenLayers.Feature.Vector>} Array of features or a single feature. 
     145     */ 
     146    readResponse: function(request) { 
     147        var doc = request.responseXML; 
     148        if (!doc || !doc.documentElement) { 
     149            doc = request.responseText; 
     150        } 
     151        if (!doc || doc.length <= 0) { 
     152            return null; 
     153        } 
     154        return this.format.read(doc); 
     155    }, 
     156     
     157    /** 
     158     * Method: create 
     159     * Construct a request for writing newly created features. 
     160     * 
     161     * Parameters: 
     162     * features - {Array({<OpenLayers.Feature.Vector>})} or 
     163     *            {<OpenLayers.Feature.Vector>} 
     164     * options - {Object} Optional object for configuring the request. 
     165     *     This object is modified and should not be reused. 
     166     * 
     167     * Returns: 
     168     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response> 
     169     *      object, whose "priv" property references the HTTP request, this  
     170     *      object is also passed to the callback function when the request 
     171     *      completes, its "features" property is then populated with the 
     172     *      the features received from the server. 
     173     */ 
     174    "create": function(features, options) { 
     175        options = OpenLayers.Util.applyDefaults(options, this.options); 
     176 
     177        var resp = new OpenLayers.Protocol.Response({ 
     178            reqFeatures: features, 
     179            requestType: "create" 
     180        }); 
     181 
     182        // do the bind ourself, to be able to pass options to the 
     183        // read callback 
     184        var callback = OpenLayers.Function.bind(this.callbackCreate,  
     185                                                this,  
     186                                                options,  
     187                                                resp); 
     188 
     189        resp.priv = OpenLayers.Request.POST({ 
     190            url: options.url, 
     191            callback: callback, 
     192            headers: options.headers, 
     193            data: this.format.write(features) 
     194        }); 
     195 
     196        return resp; 
     197    }, 
     198 
     199    /** 
     200     * Method: callbackCreate 
     201     * Individual callbacks are created for read, create and update, should 
     202     * a subclass need to override each one separately. 
     203     * 
     204     * Parameters: 
     205     * options - {Object} The user options passed to the read call. 
     206     * resp - {<OpenLayers.Protocol.Response>} The 
     207     *      <OpenLayers.Protocol.Response> object to pass to the user 
     208     *      callback. 
     209     * request - {Object} The request object returned by XHR. 
     210     */ 
     211    callbackCreate: function(options, resp, request) { 
     212        this.callbackReadCreateUpdate(options, resp, request); 
     213    }, 
     214 
     215    /** 
     216     * Method: update 
     217     * Construct a request updating modified feature. 
     218     * 
     219     * Parameters: 
     220     * feature - {<OpenLayers.Feature.Vector>} 
     221     * options - {Object} Optional object for configuring the request. 
     222     *     This object is modified and should not be reused. 
     223     * 
     224     * Returns: 
     225     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response> 
     226     *      object, whose "priv" property references the HTTP request, this  
     227     *      object is also passed to the callback function when the request 
     228     *      completes, its "features" property is then populated with the 
     229     *      the feature received from the server. 
     230     */ 
     231    "update": function(feature, options) { 
     232        var url = options.url || feature.url || this.options.url; 
     233        options = OpenLayers.Util.applyDefaults(options, this.options); 
     234 
     235        var resp = new OpenLayers.Protocol.Response({ 
     236            reqFeatures: feature, 
     237            requestType: "update" 
     238        }); 
     239 
     240        // do the bind ourself, to be able to pass options to the 
     241        // read callback 
     242        var callback = OpenLayers.Function.bind(this.callbackUpdate,  
     243                                                this,  
     244                                                options,  
     245                                                resp); 
     246 
     247        resp.priv = OpenLayers.Request.PUT({ 
     248            url: url, 
     249            callback: callback, 
     250            headers: options.headers, 
     251            data: this.format.write(feature) 
     252        }); 
     253 
     254        return resp; 
     255    }, 
     256 
     257    /** 
     258     * Method: callbackUpdate 
     259     * Individual callbacks are created for read, create and update, should 
     260     * a subclass need to override each one separately. 
     261     * 
     262     * Parameters: 
     263     * options - {Object} The user options passed to the read call. 
     264     * resp - {<OpenLayers.Protocol.Response>} The 
     265     *      <OpenLayers.Protocol.Response> object to pass to the user 
     266     *      callback. 
     267     * request - {Object} The request object returned by XHR. 
     268     */ 
     269    callbackUpdate: function(options, resp, request) { 
     270        this.callbackReadCreateUpdate(options, resp, request); 
     271    }, 
     272 
     273    /** 
     274     * Method: callbackReadCreateUpdate 
     275     * 
     276     * Parameters: 
     277     * options - {Object} The user options passed to the read call. 
     278     * resp - {<OpenLayers.Protocol.Response>} The 
     279     *      <OpenLayers.Protocol.Response> object to pass to the user 
     280     *      callback. 
     281     * request - {Object} The request object returned by XHR. 
     282     */ 
     283    callbackReadCreateUpdate: function(options, resp, request) { 
     284        if (options.callback) { 
     285            if (request.status >= 200 && request.status < 300) { 
     286                // success 
     287                resp.features = this.readResponse(request); 
     288                resp.code = OpenLayers.Protocol.Response.SUCCESS; 
     289            } else { 
     290                // failure 
     291                resp.code = OpenLayers.Protocol.Response.FAILURE; 
     292            } 
     293            options.callback.call(options.scope, resp); 
     294        } 
     295    }, 
     296 
     297    /** 
     298     * Method: delete 
     299     * Construct a request deleting a removed feature. 
     300     * 
     301     * Parameters: 
     302     * feature - {<OpenLayers.Feature.Vector>} 
     303     * options - {Object} Optional object for configuring the request. 
     304     *     This object is modified and should not be reused. 
     305     * 
     306     * Returns: 
     307     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response> 
     308     *      object, whose "priv" property references the HTTP request, this  
     309     *      object is also passed to the callback function when the request 
     310     *      completes. 
     311     */ 
     312    "delete": function(feature, options) { 
     313        var url = options.url || feature.url; 
     314        options = OpenLayers.Util.applyDefaults(options, this.options); 
     315 
     316        var resp = new OpenLayers.Protocol.Response({ 
     317            reqFeatures: feature, 
     318            requestType: "delete" 
     319        }); 
     320 
     321        // do the bind ourself, to be able to pass options to the 
     322        // read callback 
     323        var callback = OpenLayers.Function.bind(this.callbackDelete,  
     324                                                this,  
     325                                                options,  
     326                                                resp); 
     327        
     328        resp.priv = OpenLayers.Request.DELETE({ 
     329            url: url, 
     330            callback: callback, 
     331            headers: options.headers 
     332        }); 
     333 
     334        return resp; 
     335    }, 
     336 
     337    /** 
     338     * Method: callbackDelete 
     339     * 
     340     * Parameters: 
     341     * options - {Object} The user options passed to the read call. 
     342     * resp - {<OpenLayers.Protocol.Response>} The 
     343     *      <OpenLayers.Protocol.Response> object to pass to the user 
     344     *      callback. 
     345     * request - {Object} The request object returned by XHR. 
     346     */ 
     347    callbackDelete: function(options, resp, request) { 
     348        if (options.callback) { 
     349            if (request.status >= 200 && request.status < 300) { 
     350                // success 
     351                resp.code = OpenLayers.Protocol.Response.SUCCESS; 
     352            } else { 
     353                // failure 
     354                resp.code = OpenLayers.Protocol.Response.FAILURE; 
     355            } 
     356            options.callback.call(options.scope, resp); 
     357        } 
     358    }, 
     359 
     360    /** 
     361     * Method: commit 
     362     * Go over the features and for each take action 
     363     * based on the feature state. Possible actions are create, 
     364     * update and delete. 
     365     * 
     366     * Parameters: 
     367     * features - {Array({<OpenLayers.Feature.Vector>})} 
     368     * options - {Object} Object whose possible keys are "create", "update", 
     369     *      "delete", "callback" and "scope", the values referenced by the 
     370     *      first three are objects as passed to the "create", "update", and 
     371     *      "delete" methods, the value referenced by the "callback" key is 
     372     *      a function which is called when the commit operation is complete 
     373     *      using the scope referenced by the "scope" key. 
     374     * 
     375     * Returns: 
     376     * {Array({<OpenLayers.Protocol.Response>})} An array of 
     377     *      <OpenLayers.Protocol.Response> objects, one per request made 
     378     *      to the server, each object's "priv" property references the 
     379     *      corresponding HTTP request. 
     380     */ 
     381    "commit": function(features, options) { 
     382        var opt, resp = [], nRequests = 0, nResponses = 0; 
     383 
     384        function callback(resp) { 
     385            if (++nResponses < nRequests) { 
     386                resp.last = false; 
     387            } 
     388            this.callUserCallback(options, resp); 
     389        } 
     390 
     </