OpenLayers OpenLayers

Changeset 7937

Show
Ignore:
Timestamp:
09/03/08 02:14:23 (3 months ago)
Author:
elemoine
Message:

apply new patch attached to #1652 (Tim's patch)

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • sandbox/camptocamp/unhcr/lib/OpenLayers/Protocol/HTTP.js

    r7861 r7937  
    2727     * Property: headers 
    2828     * {Object} - HTTP request headers 
    29      *      Example: {'Content-Type': 'plain/text'} 
     29     *     Example: {'Content-Type': 'plain/text'} 
    3030     */ 
    3131    headers: null, 
     
    3434     * Property: params 
    3535     * {Object} - Parameters of GET requests 
    36      *      Example: {'bbox': '5,5,5,5'} 
     36     *     Example: {'bbox': '5,5,5,5'} 
    3737     */ 
    3838    params: null, 
     39     
     40    /** 
     41     * Property: format 
     42     * {<OpenLayers.Format>} Parser for reading and writing features. 
     43     */ 
     44    format: null, 
     45 
     46    /** 
     47     * Property: callback 
     48     * {Object} - Function to be called when  
     49     */ 
     50    callback: null, 
    3951 
    4052    /** 
    4153     * Property: scope 
    42      * {Object} - Callback execution scope 
     54     * {Object} - Callback execution scope. 
    4355     */ 
    4456    scope: null, 
     
    4658    /** 
    4759     * Property: options 
    48      * {Object} - Options object, properties are: 
    49      *      {String} url 
    50      *      {Object} headers 
    51      *      {Object} params 
    52      *      {Object} scope 
     60     * {Object} - Optional properties to be set on the protocol. 
    5361     */ 
    5462    options: null, 
     
    6169     * options - {Object} Optional object whose properties will be set on the 
    6270     *     instance. 
     71     * 
     72     * Valid options include: 
     73     * url - {String} 
     74     * headers - {Object}  
     75     * params - {Object} 
     76     * format - {<OpenLayers.Format>} 
     77     * callback - {Function} 
     78     * scope - {Object} 
    6379     */ 
    6480    initialize: function(options) { 
     
    7995    
    8096    /** 
     97     * Method: createCallback 
     98     * Returns a function that applies the given public method with resp and 
     99     *     options arguments. 
     100     * 
     101     * Parameters: 
     102     * method - {Function} The method to be applied by the callback. 
     103     * response - {<OpenLayers.Protocol.Response>} The protocol response object. 
     104     * options - {Object} Options sent to the protocol method (read, create, 
     105     *     update, or delete). 
     106     */ 
     107    createCallback: function(method, response, options) { 
     108        return OpenLayers.Function.bind(function() { 
     109            method.apply(this, [response, options]); 
     110        }, this); 
     111    }, 
     112 
     113    /** 
    81114     * Method: read 
    82115     * Construct a request for reading new features. 
     
    87120     * 
    88121     * 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) { 
     122     * {<OpenLayers.Protocol.Response>} A response object, whose "priv" property 
     123     *     references the HTTP request, this object is also passed to the 
     124     *     callback function when the request completes, its "features" property 
     125     *     is then populated with the the features received from the server. 
     126     */ 
     127    read: function(options) { 
    96128        options = OpenLayers.Util.applyDefaults(options, this.options); 
    97  
    98         var resp = new OpenLayers.Protocol.Response({ 
    99             "requestType": "read"}); 
    100  
    101         // do the bind ourself, to be able to pass options and resp to 
    102         // the read callback 
    103         var callback = OpenLayers.Function.bind( 
    104             this.callbackRead, this, options, resp); 
     129        var resp = new OpenLayers.Protocol.Response({requestType: "read"}); 
    105130 
    106131        resp.priv = OpenLayers.Request.GET({ 
    107132            url: options.url, 
    108             callback: callback
     133            callback: this.createCallback(this.handleRead, resp, options)
    109134            params: options.params, 
    110135            headers: options.headers 
     
    115140 
    116141    /** 
    117      * Method: callbackRead 
     142     * Method: handleRead 
    118143     * Individual callbacks are created for read, create and update, should 
    119      * a subclass need to override each one separately. 
    120      * 
    121      * Parameters: 
     144     *     a subclass need to override each one separately. 
     145     * 
     146     * Parameters: 
     147     * resp - {<OpenLayers.Protocol.Response>} The response object to pass to 
     148     *     the user callback. 
    122149     * options - {Object} The user options passed to the read call. 
    123      * resp - {<OpenLayers.Protocol.Response>} The 
    124      *      <OpenLayers.Protocol.Response> object to pass to the user 
    125      *      callback. 
    126      * request - {Object} The request object returned by XHR. 
    127      */ 
    128     callbackRead: function(options, resp, request) { 
    129         this.callbackReadCreateUpdate(options, resp, request); 
    130     }, 
    131  
    132     /** 
    133      * Method: readResponse 
    134      * Read HTTP response body and return features 
    135      * 
    136      * Parameters: 
    137      * request - {Object} The request object 
    138      * 
    139      * Returns: 
    140      * {Array({<OpenLayers.Feature.Vector>})} or 
    141      * {<OpenLayers.Feature.Vector>} Array of features or a single feature. 
    142      */ 
    143     readResponse: function(request) { 
    144         var doc = request.responseXML; 
    145         if (!doc || !doc.documentElement) { 
    146             doc = request.responseText; 
    147         } 
    148         if (!doc || doc.length <= 0) { 
    149             return null; 
    150         } 
    151         return this.format.read(doc); 
     150     */ 
     151    handleRead: function(resp, options) { 
     152        this.handleResponse(resp, options); 
    152153    }, 
    153154     
     
    158159     * Parameters: 
    159160     * features - {Array({<OpenLayers.Feature.Vector>})} or 
    160      *            {<OpenLayers.Feature.Vector>} 
     161     *     {<OpenLayers.Feature.Vector>} 
    161162     * options - {Object} Optional object for configuring the request. 
    162163     *     This object is modified and should not be reused. 
     
    164165     * Returns: 
    165166     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response> 
    166      *      object, whose "priv" property references the HTTP request, this  
    167      *      object is also passed to the callback function when the request 
    168      *      completes, its "features" property is then populated with the 
    169      *      the features received from the server. 
    170      */ 
    171     "create": function(features, options) { 
     167     *     object, whose "priv" property references the HTTP request, this  
     168     *     object is also passed to the callback function when the request 
     169     *     completes, its "features" property is then populated with the 
     170     *     the features received from the server. 
     171     */ 
     172    create: function(features, options) { 
    172173        options = OpenLayers.Util.applyDefaults(options, this.options); 
    173174 
    174175        var resp = new OpenLayers.Protocol.Response({ 
    175             "reqFeatures": features, 
    176             "requestType": "create" 
    177         }); 
    178  
    179         // do the bind ourself, to be able to pass options to the 
    180         // read callback 
    181         var callback = OpenLayers.Function.bind( 
    182             this.callbackCreate, this, options, resp); 
     176            reqFeatures: features, 
     177            requestType: "create" 
     178        }); 
    183179 
    184180        resp.priv = OpenLayers.Request.POST({ 
    185181            url: options.url, 
    186             callback: callback
     182            callback: this.createCallback(this.handleCreate, resp, options)
    187183            headers: options.headers, 
    188184            data: this.format.write(features) 
     
    193189 
    194190    /** 
    195      * Method: callbackCreate 
    196      * Individual callbacks are created for read, create and update, should 
    197      * a subclass need to override each one separately. 
    198      * 
    199      * Parameters: 
    200      * options - {Object} The user options passed to the read call. 
    201      * resp - {<OpenLayers.Protocol.Response>} The 
    202      *      <OpenLayers.Protocol.Response> object to pass to the user 
    203      *      callback. 
    204      * request - {Object} The request object returned by XHR. 
    205      */ 
    206     callbackCreate: function(options, resp, request) { 
    207         this.callbackReadCreateUpdate(options, resp, request); 
     191     * Method: handleCreate 
     192     * Called the the request issued by <create> is complete.  May be overridden 
     193     *     by subclasses. 
     194     * 
     195     * Parameters: 
     196     * resp - {<OpenLayers.Protocol.Response>} The response object to pass to 
     197     *     any user callback. 
     198     * options - {Object} The user options passed to the create call. 
     199     */ 
     200    handleCreate: function(resp, options) { 
     201        this.handleResponse(resp, options); 
    208202    }, 
    209203 
     
    219213     * Returns: 
    220214     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response> 
    221      *      object, whose "priv" property references the HTTP request, this  
    222      *      object is also passed to the callback function when the request 
    223      *      completes, its "features" property is then populated with the 
    224      *      the feature received from the server. 
    225      */ 
    226     "update": function(feature, options) { 
     215     *     object, whose "priv" property references the HTTP request, this  
     216     *     object is also passed to the callback function when the request 
     217     *     completes, its "features" property is then populated with the 
     218     *     the feature received from the server. 
     219     */ 
     220    update: function(feature, options) { 
    227221        var url = options.url || feature.url || this.options.url; 
    228222        options = OpenLayers.Util.applyDefaults(options, this.options); 
    229223 
    230224        var resp = new OpenLayers.Protocol.Response({ 
    231             "reqFeatures": feature, 
    232             "requestType": "update" 
    233         }); 
    234  
    235         // do the bind ourself, to be able to pass options to the 
    236         // read callback 
    237         var callback = OpenLayers.Function.bind( 
    238             this.callbackUpdate, this, options, resp); 
     225            reqFeatures: feature, 
     226            requestType: "update" 
     227        }); 
    239228 
    240229        resp.priv = OpenLayers.Request.PUT({ 
    241230            url: url, 
    242             callback: callback
     231            callback: this.createCallback(this.handleUpdate, resp, options)
    243232            headers: options.headers, 
    244233            data: this.format.write(feature) 
     
    249238 
    250239    /** 
    251      * Method: callbackUpdate 
    252      * Individual callbacks are created for read, create and update, should 
    253      * a subclass need to override each one separately. 
    254      * 
    255      * Parameters: 
    256      * options - {Object} The user options passed to the read call. 
    257      * resp - {<OpenLayers.Protocol.Response>} The 
    258      *      <OpenLayers.Protocol.Response> object to pass to the user 
    259      *      callback. 
    260      * request - {Object} The request object returned by XHR. 
    261      */ 
    262     callbackUpdate: function(options, resp, request) { 
    263         this.callbackReadCreateUpdate(options, resp, request); 
    264     }, 
    265  
    266     /** 
    267      * Method: callbackReadCreateUpdate 
    268      * 
    269      * Parameters: 
    270      * options - {Object} The user options passed to the read call. 
    271      * resp - {<OpenLayers.Protocol.Response>} The 
    272      *      <OpenLayers.Protocol.Response> object to pass to the user 
    273      *      callback. 
    274      * request - {Object} The request object returned by XHR. 
    275      */ 
    276     callbackReadCreateUpdate: function(options, resp, request) { 
     240     * Method: handleUpdate 
     241     * Called the the request issued by <update> is complete.  May be overridden 
     242     *     by subclasses. 
     243     * 
     244     * Parameters: 
     245     * resp - {<OpenLayers.Protocol.Response>} The response object to pass to 
     246     *     any user callback. 
     247     * options - {Object} The user options passed to the update call. 
     248     */ 
     249    handleUpdate: function(resp, options) { 
     250        this.handleResponse(resp, options); 
     251    }, 
     252 
     253    /** 
     254     * Method: delete 
     255     * Construct a request deleting a removed feature. 
     256     * 
     257     * Parameters: 
     258     * feature - {<OpenLayers.Feature.Vector>} 
     259     * options - {Object} Optional object for configuring the request. 
     260     *     This object is modified and should not be reused. 
     261     * 
     262     * Returns: 
     263     * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response> 
     264     *     object, whose "priv" property references the HTTP request, this  
     265     *     object is also passed to the callback function when the request 
     266     *     completes. 
     267     */ 
     268    "delete": function(feature, options) { 
     269        var url = options.url || feature.url || this.options.url; 
     270        options = OpenLayers.Util.applyDefaults(options, this.options); 
     271 
     272        var resp = new OpenLayers.Protocol.Response({ 
     273            reqFeatures: feature, 
     274            requestType: "delete" 
     275        }); 
     276 
     277        resp.priv = OpenLayers.Request.DELETE({ 
     278            url: url, 
     279            callback: this.createCallback(this.handleDelete, resp, options), 
     280            headers: options.headers 
     281        }); 
     282 
     283        return resp; 
     284    }, 
     285 
     286    /** 
     287     * Method: handleDelete 
     288     * Called the the request issued by <delete> is complete.  May be overridden 
     289     *     by subclasses. 
     290     * 
     291     * Parameters: 
     292     * resp - {<OpenLayers.Protocol.Response>} The response object to pass to 
     293     *     any user callback. 
     294     * options - {Object} The user options passed to the delete call. 
     295     */ 
     296    handleDelete: function(resp, options) { 
     297        this.handleResponse(resp, options); 
     298    }, 
     299 
     300    /** 
     301     * Method: handleResponse 
     302     * Called by CRUD specific handlers. 
     303     * 
     304     * Parameters: 
     305     * resp - {<OpenLayers.Protocol.Response>} The response object to pass to 
     306     *     any user callback. 
     307     * options - {Object} The user options passed to the create, read, update, 
     308     *     or delete call. 
     309     */ 
     310    handleResponse: function(resp, options) { 
     311        var request = resp.priv; 
    277312        if(options.callback) { 
    278313            if(request.status >= 200 && request.status < 300) { 
    279314                // success 
    280                 resp.features = this.readResponse(request); 
     315                if(resp.requestType != "delete") { 
     316                    resp.features = this.parseFeatures(request); 
     317                } 
    281318                resp.code = OpenLayers.Protocol.Response.SUCCESS; 
    282319            } else { 
     
    289326 
    290327    /** 
    291      * Method: delete 
    292      * Construct a request deleting a removed feature. 
    293      * 
    294      * Parameters: 
    295      * feature - {<OpenLayers.Feature.Vector>} 
    296      * options - {Object} Optional object for configuring the request. 
    297      *     This object is modified and should not be reused. 
    298      * 
    299      * Returns: 
    300      * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response> 
    301      *      object, whose "priv" property references the HTTP request, this  
    302      *      object is also passed to the callback function when the request 
    303      *      completes. 
    304      */ 
    305     "delete": function(feature, options) { 
    306         var url = options.url || feature.url; 
     328     * Method: parseFeatures 
     329     * Read HTTP response body and return features. 
     330     * 
     331     * Parameters: 
     332     * request - {XMLHttpRequest} The request object 
     333     * 
     334     * Returns: 
     335     * {Array({<OpenLayers.Feature.Vector>})} or 
     336     *     {<OpenLayers.Feature.Vector>} Array of features or a single feature. 
     337     */ 
     338    parseFeatures: function(request) { 
     339        var doc = request.responseXML; 
     340        if (!doc || !doc.documentElement) { 
     341            doc = request.responseText; 
     342        } 
     343        if (!doc || doc.length <= 0) { 
     344            return null; 
     345        } 
     346        return this.format.read(doc); 
     347    }, 
     348 
     349    /** 
     350     * Method: commit 
     351     * Iterate over each feature and take action based on the feature state. 
     352     *     Possible actions are create, update and delete. 
     353     * 
     354     * Parameters: 
     355     * features - {Array({<OpenLayers.Feature.Vector>})} 
     356     * options - {Object} Optional object for setting up intermediate commit 
     357     *     callbacks. 
     358     * 
     359     * Valid options: 
     360     * create - {Object} Optional object to be passed to the <create> method. 
     361     * update - {Object} Optional object to be passed to the <update> method. 
     362     * delete - {Object} Optional object to be passed to the <delete> method. 
     363     * callback - {Function} Optional function to be called when the commit 
     364     *     is complete. 
     365     * scope - {Object} Optional object to be set as the scope of the callback. 
     366     * 
     367     * Returns: 
     368     * {Array(<OpenLayers.Protocol.Response>)} An array of response objects, 
     369     *     one per request made to the server, each object's "priv" property 
     370     *     references the corresponding HTTP request. 
     371     */ 
     372    commit: function(features, options) { 
    307373        options = OpenLayers.Util.applyDefaults(options, this.options); 
    308  
    309         var resp = new OpenLayers.Protocol.Response({ 
    310             "reqFeatures": feature, 
    311             "requestType": "delete" 
    312         }); 
    313  
    314         // do the bind ourself, to be able to pass options to the 
    315         // read callback 
    316         var callback = OpenLayers.Function.bind( 
    317             this.callbackDelete, this, options, resp); 
    318         
    319         resp.priv = OpenLayers.Request.DELETE({ 
    320             url: url, 
    321             callback: callback, 
    322             headers: options.headers 
    323         }); 
    324  
    325         return resp; 
    326     }, 
    327  
    328     /** 
    329      * Method: callbackDelete 
    330      * 
    331      * Parameters: 
    332      * options - {Object} The user options passed to the read call. 
    333      * resp - {<OpenLayers.Protocol.Response>} The 
    334      *      <OpenLayers.Protocol.Response> object to pass to the user 
    335      *      callback. 
    336      * request - {Object} The request object returned by XHR. 
    337      */ 
    338     callbackDelete: function(options, resp, request) { 
    339         if(options.callback) { 
    340             if(request.status >= 200 && request.status < 300) { 
    341                 // success 
    342                 resp.code = OpenLayers.Protocol.Response.SUCCESS; 
    343             } else { 
    344                 // failure 
    345                 resp.code = OpenLayers.Protocol.Response.FAILURE; 
     374        var resp = [], nResponses = 0; 
     375         
     376        // Divide up features before issuing any requests.  This properly 
     377        // counts requests in the event that any responses come in before 
     378        // all requests have been issued. 
     379        var types = {}; 
     380        types[OpenLayers.State.INSERT] = []; 
     381        types[OpenLayers.State.UPDATE] = []; 
     382        types[OpenLayers.State.DELETE] = []; 
     383        var feature, list; 
     384        for(var i=0, len=features.length; i<len; ++i) { 
     385            feature = features[i]; 
     386            list = types[feature.state]; 
     387            if(list) { 
     388                list.push(feature); 
    346389            } 
    347             options.callback.call(options.scope, resp); 
    348         } 
    349     }, 
    350  
    351     /** 
    352      * Method: commit 
    353      * Go over the features and for each take action 
    354      * based on the feature state. Possible actions are create, 
    355      * update and delete. 
    356      * 
    357      * Parameters: 
    358      * features - {Array({<OpenLayers.Feature.Vector>})} 
    359      * options - {Object} Object whose possible keys are "create", "update", 
    360      *      "delete", "callback" and "scope", the values referenced by the 
    361      *      first three are objects as passed to the "create", "update", and 
    362      *      "delete" methods, the value referenced by the "callback" key is 
    363      *      a function which is called when the commit operation is complete 
    364      *      using the scope referenced by the "scope" key. 
    365      * 
    366      * Returns: 
    367      * {Array({<OpenLayers.Protocol.Response>})} An array of 
    368      *      <OpenLayers.Protocol.Response> objects, one per request made 
    369      *      to the server, each object's "priv" property references the 
    370      *      corresponding HTTP request. 
    371      */ 
    372     "commit": function(features, options) { 
    373         var opt, resp = [], nRequests = 0, nResponses = 0; 
    374  
    375         function callback(resp) { 
    376             if (++nResponses < nRequests) { 
    377                 resp.last = false; 
    378             } 
    379             this.callUserCallback(options, resp); 
    380         } 
    381  
    382         var feature, toCreate = []; 
    383         for (var i = features.length - 1; i >= 0; i--) { 
    384             feature = features[i]; 
    385             switch (feature.state) { 
    386             case OpenLayers.State.INSERT: 
    387                 toCreate.push(feature); 
    388                 break; 
    389             case OpenLayers.State.UPDATE: 
    390                 nRequests++; 
    391                 opt = OpenLayers.Util.applyDefaults( 
    392                     {"callback": callback, "scope": this}, 
    393                     options.update 
    394                 ); 
    395                 resp.push(this.update(feature, opt)); 
    396                 break; 
    397             case OpenLayers.State.DELETE: 
    398                 nRequests++; 
    399                 opt = OpenLayers.Util.applyDefaults( 
    400                     {"callback": callback, "scope": this}, 
    401                     options["delete"] 
    402                 ); 
    403                 resp.push(this["delete"](feature, opt)); 
    404                 break; 
    405             } 
    406         } 
    407         if (toCreate.length > 0) { 
    408             nRequests++; 
    409             opt = OpenLayers.Util.applyDefaults( 
    410                 {"callback": callback, "scope": this}, 
    411                 options.create 
     390        } 
     391        // tally up number of requests 
     392        var nRequests = (types[OpenLayers.State.INSERT].length > 0 ? 1 : 0) + 
     393            types[OpenLayers.State.UPDATE].length + 
     394            types[OpenLayers.State.DELETE].length; 
     395         
     396        function callback(response) { 
     397            nResponses++; 
     398            response.last = (nResponses >= nRequests); 
     399            this.callUserCallback(response, options); 
     400        } 
     401         
     402        // start issuing requests 
     403        var queue = types[OpenLayers.State.INSERT]; 
     404        if(queue.length > 0) { 
     405            resp.push(this.create( 
     406                queue, OpenLayers.Util.applyDefaults( 
     407                    {callback: callback, scope: this}, 
     408                    options.create || {} // remove || when #1716 is resolved 
     409                ) 
     410            )); 
     411        } 
     412        queue = types[OpenLayers.State.UPDATE]; 
     413        for(var i=queue.length-1; i>=0; --i) { 
     414            resp.push(this.update( 
     415                queue[i], OpenLayers.Util.applyDefaults( 
     416                    {callback: callback, scope: this},  
     417                    options.update || {} // remove || when #1716 is resolved 
     418                )) 
    412419            ); 
    413             resp.push(this.create(toCreate, opt)); 
     420        } 
     421        queue = types[OpenLayers.State.DELETE]; 
     422        for(var i=queue.length-1; i>=0; --i) { 
     423            resp.push(this["delete"]( 
     424                queue[i], OpenLayers.Util.applyDefaults( 
     425                    {callback: callback, scope: this}, 
     426                    options["delete"] || {} // remove || when #1716 is resolved 
     427                )) 
     428            ); 
    414429        } 
    415430        return resp; 
     
    419434     * Method: callUserCallback 
    420435     * This method is used from within the commit method each time an 
    421      * an HTTP response is received from the server, it is responsible 
    422      * for calling the user-supplied callbacks. 
    423      * 
    424      * Parameters: 
     436     *     an HTTP response is received from the server, it is responsible 
     437     *     for calling the user-supplied callbacks. 
     438     * 
     439     * Parameters: 
     440     * resp - {<OpenLayers.Protocol.Response>} 
    425441     * options - {Object} The map of options passed to the commit call. 
    426      * resp - {<OpenLayers.Protocol.Response>} 
    427      */ 
    428     callUserCallback: function(options, resp) { 
     442     */ 
     443    callUserCallback: function(resp, options) { 
    429444        var opt = options[resp.requestType]; 
    430         if (opt && opt.callback) { 
     445        if(opt && opt.callback) { 
    431446            opt.callback.call(opt.scope, resp); 
    432447        } 
    433         if (resp.last && options.callback) { 
     448        if(resp.last && options.callback) { 
    434449            options.callback.call(options.scope); 
    435450        } 
  • sandbox/camptocamp/unhcr/tests/Protocol/HTTP.html

    r7861 r7937  
    44  <script type="text/javascript"> 
    55 
    6     function test_Protocol_HTTP_constructor(t) { 
     6    function test_constructor(t) { 
    77        t.plan(8); 
    88        var a = new OpenLayers.Protocol.HTTP({ 
     
    2929    } 
    3030 
    31     function test_Protocol_HTTP_destroy(t) { 
     31    function test_destroy(t) { 
    3232        t.plan(3); 
    3333        var protocol = new OpenLayers.Protocol.HTTP({ 
     
    4141    } 
    4242 
    43     function test_Protocol_HTTP_read(t) { 
     43    function test_read(t) { 
    4444        t.plan(10); 
    4545        var protocol = new OpenLayers.Protocol.HTTP({ 
     
    6262        var response; 
    6363 
    64         protocol.callbackReadCreateUpdate = function(opt, resp, req) { 
     64        protocol.handleResponse = function(resp, opt) { 
    6565            // 4 tests 
     66            var req = resp.priv; 
    6667            t.ok(this == protocol, 
    67                 'callbackReadCreateUpdate called with correct scope'); 
     68                'handleResponse called with correct scope'); 
    6869            t.ok(opt == readOptions, 
    69                 'callbackReadCreateUpdate called with correct options'); 
     70                'handleResponse called with correct options'); 
    7071            t.eq(resp.CLASS_NAME, 'OpenLayers.Protocol.Response', 
    71                 'callbackReadCreateUpdate called with a Response object'); 
     72                'handleResponse called with a Response object'); 
    7273            t.eq(req, request, 
    73                 'callbackReadCreateUpdate called with correct request'); 
     74                'handleResponse called with correct request'); 
    7475 
    7576            response = resp; 
     
    9091            t.ok(typeof options.callback == 'function', 
    9192                'GET called with a callback in options'); 
    92             options.callback(request); 
     93            t.delay_call(0.1, function() { 
     94                options.callback(request); 
     95                t.ok(resp == response, 
     96                    'read returns the expected response object');         
     97                // cleanup 
     98                protocol.destroy(); 
     99                OpenLayers.Request.GET = _get; 
     100            }); 
     101            return request; 
    93102        }; 
    94103 
    95104        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    } 
     106 
     107    function test_parseFeatures(t) { 
    105108        t.plan(5); 
    106109 
     
    120123            } 
    121124        }; 
    122         var ret = protocol.readResponse(request); 
    123         t.eq(ret, 'xml', 'readResponse returns expected value'); 
     125        var ret = protocol.parseFeatures(request); 
     126        t.eq(ret, 'xml', 'parseFeatures returns expected value'); 
    124127 
    125128        // test responseText - 2 tests 
     
    134137            } 
    135138        }; 
    136         var ret = protocol.readResponse(request); 
    137         t.eq(ret, 'text', 'readResponse returns expected value'); 
     139        var ret = protocol.parseFeatures(request); 
     140        t.eq(ret, 'text', 'parseFeatures returns expected value'); 
    138141 
    139142        // test empty responseText - 1 test 
     
    146149            } 
    147150        }; 
    148         var ret = protocol.readResponse(request); 
    149         t.eq(ret, null, 'readResponse returns expected value'); 
    150     } 
    151  
    152     function test_Protocol_HTTP_create(t) { 
     151        var ret = protocol.parseFeatures(request); 
     152        t.eq(ret, null, 'parseFeatures returns expected value'); 
     153    } 
     154 
     155    function test_create(t) { 
    153156        t.plan(10); 
    154157        var protocol = new OpenLayers.Protocol.HTTP({ 
     
    173176        var response; 
    174177 
    175         protocol.callbackCreate = function(opt, resp, req) { 
     178        protocol.handleCreate = function(resp, opt) { 
    176179            // 5 tests 
     180            var req = resp.priv; 
    177181            t.ok(this == protocol, 
    178                 'callbackCreate called with correct scope'); 
     182                'handleCreate called with correct scope'); 
    179183            t.ok(opt == createOptions, 
    180                 'callbackCreate called with correct options'); 
     184                'handleCreate called with correct options'); 
    181185            t.eq(resp.CLASS_NAME, 'OpenLayers.Protocol.Response', 
    182                 'callbackCreate called with a Response object'); 
     186                'handleCreate called with a Response object'); 
    183187            t.ok(resp.reqFeatures == features, 
    184                 'callbackCreate called with correct requested features in response'); 
     188                'handleCreate called with correct requested features in response'); 
    185189            t.eq(req, request, 
    186                 'callbackCreate called with correct request'); 
     190                'handleCreate called with correct request'); 
    187191 
    188192            response = resp; 
     
    201205            t.ok(typeof options.callback == 'function', 
    202206                'POST called with a callback in options'); 
    203             // call callback 
    204             options.callback(request); 
     207            // call callback - delayed because this function has to return first 
     208            t.delay_call(0.1, function() { 
     209                options.callback(request); 
     210                t.ok(resp == response, 
     211                    'create returns the expected response object'); 
     212                // cleanup 
     213                protocol.destroy(); 
     214                OpenLayers.Request.POST = _post; 
     215            }); 
     216            return request; 
    205217        }; 
    206218 
    207219        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) { 
     220    } 
     221 
     222    function test_update(t) { 
    217223        t.plan(10); 
    218224        var protocol = new OpenLayers.Protocol.HTTP({ 
     
    237243        var response; 
    238244 
    239         protocol.callbackUpdate = function(opt, resp, req) { 
     245        protocol.handleUpdate = function(resp, opt) { 
     246            var req = resp.priv; 
    240247            // 5 tests 
    241248            t.ok(this == protocol, 
    242                 'callbackUpdate called with correct scope'); 
     249                'handleUpdate called with correct scope'); 
    243250            t.ok(opt == updateOptions, 
    244                 'callbackUpdate called with correct options'); 
     251                'handleUpdate called with correct options'); 
    245252            t.eq(resp.CLASS_NAME, 'OpenLayers.Protocol.Response', 
    246                 'callbackUpdate called with a Response object'); 
     253                'handleUpdate called with a Response object'); 
    247254            t.ok(resp.reqFeatures == feature, 
    248                 'callbackUpdate called with correct requested feature in response'); 
     255                'handleUpdate called with correct requested feature in response'); 
    249256            t.eq(req, request, 
    250                 'callbackUpdate called with correct request'); 
     257                'handleUpdate called with correct request'); 
    251258 
    252259            response = resp; 
     
    265272            t.ok(typeof options.callback == 'function', 
    266273                'PUT called with a callback in options'); 
    267             // call callback 
    268             options.callback(request); 
     274            // call callback - delayed because this function has to return first 
     275            t.delay_call(0.1, function() { 
     276                options.callback(request); 
     277                t.ok(resp == response, 
     278                    'update returns the expected response object'); 
     279                // cleanup 
     280                protocol.destroy(); 
     281                OpenLayers.Request.PUT = _put; 
     282            }); 
     283            return request; 
    269284        }; 
    270285 
    271286        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) { 
     287 
     288    } 
     289    function test_handleResponse(t) { 
    280290        t.plan(6); 
    281291 
     
    290300            'callback': function(resp) { 
    291301                t.ok(this == scope, 
    292                     'callback called with correct scope'); 
     302                    '[no status] callback called with correct scope'); 
    293303                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); 
     304                    '[no status] callback called with correct response'); 
     305            } 
     306        }; 
     307        response = {priv: {}}; 
     308        protocol.handleResponse(response, options); 
    300309         
    301310        // test failure condition - 1 test 
     
    303312            'callback': function(resp) { 
    304313                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); 
     314                    '[status 400] callback called with correct response code'); 
     315            } 
     316        }; 
     317        response = {priv: {status: 400}}; 
     318        protocol.handleResponse(response, options); 
    311319 
    312320        // test success condition - 3 tests 
     
    315323            'callback': function(resp) { 
    316324                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'); 
     325                    '[status 200] callback called with correct response code'); 
     326                t.eq(resp.features, features, 
     327                    '[status 200] callback called with correct features in response'); 
     328            } 
     329        }; 
     330        response = {priv: {status: 200}}; 
     331        protocol.parseFeatures = function(request) { 
     332            t.ok(request == response.priv, 
     333                '[status 200] parseFeatures called with correct request'); 
    327334            return features; 
    328335        } 
    329         protocol.callbackReadCreateUpdate(options, response, request); 
     336        protocol.handleResponse(response, options); 
    330337 
    331338        // cleanup 
     
    333340    } 
    334341 
    335     function test_Protocol_HTTP_delete(t) { 
     342    function test_delete(t) { 
    336343        t.plan(10); 
    337344        var protocol = new OpenLayers.Protocol.HTTP({ 
     
    355362        var response; 
    356363 
    357         protocol.callbackDelete = function(opt, resp, req) { 
     364        protocol.handleDelete = function(resp, opt) { 
    358365            // 5 tests 
     366            var req = resp.priv; 
    359367            t.ok(this == protocol, 
    360                 'callbackDelete called with correct scope'); 
     368                'handleDelete called with correct scope'); 
    361369            t.ok(opt == deleteOptions, 
    362                 'callbackDelete called with correct options'); 
     370                'handleDelete called with correct options'); 
    363371            t.eq(resp.CLASS_NAME, 'OpenLayers.Protocol.Response', 
    364                 'callbackDelete called with a Response object'); 
     372                'handleDelete called with a Response object'); 
    365373            t.ok(resp.reqFeatures == feature, 
    366                 'callbackDelete called with correct requested feature in response'); 
     374                'handleDelete called with correct requested feature in response'); 
    367375            t.eq(req, request, 
    368                 'callbackDelete called with correct request'); 
     376                'handleDelete called with correct request'); 
    369377 
    370378            response = resp; 
     
    383391            t.ok(typeof options.callback == 'function', 
    384392                'DELETE called with a callback in options'); 
    385             // call callback 
    386             options.callback(request); 
     393            // call callback - delayed because this function has to return first 
     394            t.delay_call(0.1, function() { 
     395                options.callback(request); 
     396                t.ok(resp == response, 
     397                    'read returns the expected re