Adding HTTP protocol. Give a vector layer the HTTP protocol to create, read, update, and delete features via HTTP. This can be subclassed by protocols that extend HTTP. Thanks for the collaboration (and great tests) on this elemoine - good working with you guys. r=elemoine,me (closes #1652)
git-svn-id: http://svn.openlayers.org/trunk/openlayers@7940 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
49
examples/behavior-fixed-http-gml.html
Normal file
49
examples/behavior-fixed-http-gml.html
Normal file
@@ -0,0 +1,49 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>OpenLayers Vector Behavior Example</title>
|
||||
<link rel="stylesheet" href="../theme/default/style.css" type="text/css" />
|
||||
<link rel="stylesheet" href="style.css" type="text/css" />
|
||||
<script src="../lib/OpenLayers.js"></script>
|
||||
<script type="text/javascript">
|
||||
var map;
|
||||
|
||||
function init(){
|
||||
map = new OpenLayers.Map('map');
|
||||
var wms = new OpenLayers.Layer.WMS(
|
||||
"OpenLayers WMS", "http://labs.metacarta.com/wms/vmap0",
|
||||
{layers: 'basic'}
|
||||
);
|
||||
|
||||
var layer = new OpenLayers.Layer.Vector("GML", {
|
||||
strategies: [new OpenLayers.Strategy.Fixed()],
|
||||
protocol: new OpenLayers.Protocol.HTTP({
|
||||
url: "gml/polygon.xml",
|
||||
format: new OpenLayers.Format.GML()
|
||||
}),
|
||||
});
|
||||
|
||||
map.addLayers([wms, layer]);
|
||||
map.zoomToExtent(new OpenLayers.Bounds(
|
||||
-3.92, 44.34, 4.87, 49.55
|
||||
));
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="init()">
|
||||
<h1 id="title">Vector Behavior Example (Fixed/HTTP/GML)</h1>
|
||||
<p id="shortdesc">
|
||||
Vector layer with a Fixed strategy, HTTP protocol, and GML format.
|
||||
</p>
|
||||
<div id="map" class="smallmap"></div>
|
||||
<div id="docs">
|
||||
The vector layer shown uses the Fixed strategy, the HTTP protocol,
|
||||
and the GML format.
|
||||
The Fixed strategy is a simple strategy that fetches features once
|
||||
and never re-requests new data.
|
||||
The HTTP protocol makes requests using HTTP verbs. It should be
|
||||
constructed with a url that corresponds to a collection of features
|
||||
(a resource on some server).
|
||||
The GML format is used to serialize features.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -184,6 +184,7 @@
|
||||
"OpenLayers/Strategy.js",
|
||||
"OpenLayers/Strategy/Fixed.js",
|
||||
"OpenLayers/Protocol.js",
|
||||
"OpenLayers/Protocol/HTTP.js",
|
||||
"OpenLayers/Layer/PointTrack.js",
|
||||
"OpenLayers/Layer/GML.js",
|
||||
"OpenLayers/Style.js",
|
||||
|
||||
454
lib/OpenLayers/Protocol/HTTP.js
Normal file
454
lib/OpenLayers/Protocol/HTTP.js
Normal file
@@ -0,0 +1,454 @@
|
||||
/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
|
||||
* license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
|
||||
* full text of the license. */
|
||||
|
||||
/**
|
||||
* @requires OpenLayers/Protocol.js
|
||||
* @requires OpenLayers/Feature/Vector.js
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class: OpenLayers.Protocol.HTTP
|
||||
* A basic HTTP protocol for vector layers. Create a new instance with the
|
||||
* <OpenLayers.Protocol.HTTP> constructor.
|
||||
*
|
||||
* Inherits from:
|
||||
* - <OpenLayers.Protocol>
|
||||
*/
|
||||
OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, {
|
||||
|
||||
/**
|
||||
* Property: url
|
||||
* {String} - Service URL, read-only, set through the options
|
||||
* passed to constructor.
|
||||
*/
|
||||
url: null,
|
||||
|
||||
/**
|
||||
* Property: headers
|
||||
* {Object} - HTTP request headers, read-only, set through the options
|
||||
* passed to the constructor,
|
||||
* Example: {'Content-Type': 'plain/text'}
|
||||
*/
|
||||
headers: null,
|
||||
|
||||
/**
|
||||
* Property: params
|
||||
* {Object} - Parameters of GET requests, read-only, set through the options
|
||||
* passed to the constructor,
|
||||
* Example: {'bbox': '5,5,5,5'}
|
||||
*/
|
||||
params: null,
|
||||
|
||||
/**
|
||||
* Property: format
|
||||
* {<OpenLayers.Format>} Parser for reading and writing features.
|
||||
*/
|
||||
format: null,
|
||||
|
||||
/**
|
||||
* Property: callback
|
||||
* {Object} - Function to be called when the <read>, <create>,
|
||||
* <update>, <delete> or <commit> operation completes, read-only,
|
||||
* set through the options passed to the constructor.
|
||||
*/
|
||||
callback: null,
|
||||
|
||||
/**
|
||||
* Property: scope
|
||||
* {Object} - Callback execution scope, read-only, set through the
|
||||
* options passed to the constructor.
|
||||
*/
|
||||
scope: null,
|
||||
|
||||
/**
|
||||
* Constructor: OpenLayers.Protocol.HTTP
|
||||
* A class for giving layers generic HTTP protocol.
|
||||
*
|
||||
* Parameters:
|
||||
* options - {Object} Optional object whose properties will be set on the
|
||||
* instance.
|
||||
*
|
||||
* Valid options include:
|
||||
* url - {String}
|
||||
* headers - {Object}
|
||||
* params - {Object}
|
||||
* format - {<OpenLayers.Format>}
|
||||
* callback - {Function}
|
||||
* scope - {Object}
|
||||
*/
|
||||
initialize: function(options) {
|
||||
this.params = {};
|
||||
this.headers = {};
|
||||
OpenLayers.Protocol.prototype.initialize.apply(this, arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: destroy
|
||||
* Clean up the protocol.
|
||||
*/
|
||||
destroy: function() {
|
||||
this.params = null;
|
||||
this.headers = null;
|
||||
OpenLayers.Protocol.prototype.destroy.apply(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: createCallback
|
||||
* Returns a function that applies the given public method with resp and
|
||||
* options arguments.
|
||||
*
|
||||
* Parameters:
|
||||
* method - {Function} The method to be applied by the callback.
|
||||
* response - {<OpenLayers.Protocol.Response>} The protocol response object.
|
||||
* options - {Object} Options sent to the protocol method (read, create,
|
||||
* update, or delete).
|
||||
*/
|
||||
createCallback: function(method, response, options) {
|
||||
return OpenLayers.Function.bind(function() {
|
||||
method.apply(this, [response, options]);
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: read
|
||||
* Construct a request for reading new features.
|
||||
*
|
||||
* Parameters:
|
||||
* options - {Object} Optional object for configuring the request.
|
||||
* This object is modified and should not be reused.
|
||||
*
|
||||
* Returns:
|
||||
* {<OpenLayers.Protocol.Response>} A response object, whose "priv" property
|
||||
* references the HTTP request, this object is also passed to the
|
||||
* callback function when the request completes, its "features" property
|
||||
* is then populated with the the features received from the server.
|
||||
*/
|
||||
read: function(options) {
|
||||
options = OpenLayers.Util.applyDefaults(options, this.options);
|
||||
var resp = new OpenLayers.Protocol.Response({requestType: "read"});
|
||||
|
||||
resp.priv = OpenLayers.Request.GET({
|
||||
url: options.url,
|
||||
callback: this.createCallback(this.handleRead, resp, options),
|
||||
params: options.params,
|
||||
headers: options.headers
|
||||
});
|
||||
|
||||
return resp;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: handleRead
|
||||
* Individual callbacks are created for read, create and update, should
|
||||
* a subclass need to override each one separately.
|
||||
*
|
||||
* Parameters:
|
||||
* resp - {<OpenLayers.Protocol.Response>} The response object to pass to
|
||||
* the user callback.
|
||||
* options - {Object} The user options passed to the read call.
|
||||
*/
|
||||
handleRead: function(resp, options) {
|
||||
this.handleResponse(resp, options);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: create
|
||||
* Construct a request for writing newly created features.
|
||||
*
|
||||
* Parameters:
|
||||
* features - {Array({<OpenLayers.Feature.Vector>})} or
|
||||
* {<OpenLayers.Feature.Vector>}
|
||||
* options - {Object} Optional object for configuring the request.
|
||||
* This object is modified and should not be reused.
|
||||
*
|
||||
* Returns:
|
||||
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
|
||||
* object, whose "priv" property references the HTTP request, this
|
||||
* object is also passed to the callback function when the request
|
||||
* completes, its "features" property is then populated with the
|
||||
* the features received from the server.
|
||||
*/
|
||||
create: function(features, options) {
|
||||
options = OpenLayers.Util.applyDefaults(options, this.options);
|
||||
|
||||
var resp = new OpenLayers.Protocol.Response({
|
||||
reqFeatures: features,
|
||||
requestType: "create"
|
||||
});
|
||||
|
||||
resp.priv = OpenLayers.Request.POST({
|
||||
url: options.url,
|
||||
callback: this.createCallback(this.handleCreate, resp, options),
|
||||
headers: options.headers,
|
||||
data: this.format.write(features)
|
||||
});
|
||||
|
||||
return resp;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: handleCreate
|
||||
* Called the the request issued by <create> is complete. May be overridden
|
||||
* by subclasses.
|
||||
*
|
||||
* Parameters:
|
||||
* resp - {<OpenLayers.Protocol.Response>} The response object to pass to
|
||||
* any user callback.
|
||||
* options - {Object} The user options passed to the create call.
|
||||
*/
|
||||
handleCreate: function(resp, options) {
|
||||
this.handleResponse(resp, options);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: update
|
||||
* Construct a request updating modified feature.
|
||||
*
|
||||
* Parameters:
|
||||
* feature - {<OpenLayers.Feature.Vector>}
|
||||
* options - {Object} Optional object for configuring the request.
|
||||
* This object is modified and should not be reused.
|
||||
*
|
||||
* Returns:
|
||||
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
|
||||
* object, whose "priv" property references the HTTP request, this
|
||||
* object is also passed to the callback function when the request
|
||||
* completes, its "features" property is then populated with the
|
||||
* the feature received from the server.
|
||||
*/
|
||||
update: function(feature, options) {
|
||||
var url = options.url || feature.url || this.options.url;
|
||||
options = OpenLayers.Util.applyDefaults(options, this.options);
|
||||
|
||||
var resp = new OpenLayers.Protocol.Response({
|
||||
reqFeatures: feature,
|
||||
requestType: "update"
|
||||
});
|
||||
|
||||
resp.priv = OpenLayers.Request.PUT({
|
||||
url: url,
|
||||
callback: this.createCallback(this.handleUpdate, resp, options),
|
||||
headers: options.headers,
|
||||
data: this.format.write(feature)
|
||||
});
|
||||
|
||||
return resp;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: handleUpdate
|
||||
* Called the the request issued by <update> is complete. May be overridden
|
||||
* by subclasses.
|
||||
*
|
||||
* Parameters:
|
||||
* resp - {<OpenLayers.Protocol.Response>} The response object to pass to
|
||||
* any user callback.
|
||||
* options - {Object} The user options passed to the update call.
|
||||
*/
|
||||
handleUpdate: function(resp, options) {
|
||||
this.handleResponse(resp, options);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: delete
|
||||
* Construct a request deleting a removed feature.
|
||||
*
|
||||
* Parameters:
|
||||
* feature - {<OpenLayers.Feature.Vector>}
|
||||
* options - {Object} Optional object for configuring the request.
|
||||
* This object is modified and should not be reused.
|
||||
*
|
||||
* Returns:
|
||||
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
|
||||
* object, whose "priv" property references the HTTP request, this
|
||||
* object is also passed to the callback function when the request
|
||||
* completes.
|
||||
*/
|
||||
"delete": function(feature, options) {
|
||||
var url = options.url || feature.url || this.options.url;
|
||||
options = OpenLayers.Util.applyDefaults(options, this.options);
|
||||
|
||||
var resp = new OpenLayers.Protocol.Response({
|
||||
reqFeatures: feature,
|
||||
requestType: "delete"
|
||||
});
|
||||
|
||||
resp.priv = OpenLayers.Request.DELETE({
|
||||
url: url,
|
||||
callback: this.createCallback(this.handleDelete, resp, options),
|
||||
headers: options.headers
|
||||
});
|
||||
|
||||
return resp;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: handleDelete
|
||||
* Called the the request issued by <delete> is complete. May be overridden
|
||||
* by subclasses.
|
||||
*
|
||||
* Parameters:
|
||||
* resp - {<OpenLayers.Protocol.Response>} The response object to pass to
|
||||
* any user callback.
|
||||
* options - {Object} The user options passed to the delete call.
|
||||
*/
|
||||
handleDelete: function(resp, options) {
|
||||
this.handleResponse(resp, options);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: handleResponse
|
||||
* Called by CRUD specific handlers.
|
||||
*
|
||||
* Parameters:
|
||||
* resp - {<OpenLayers.Protocol.Response>} The response object to pass to
|
||||
* any user callback.
|
||||
* options - {Object} The user options passed to the create, read, update,
|
||||
* or delete call.
|
||||
*/
|
||||
handleResponse: function(resp, options) {
|
||||
var request = resp.priv;
|
||||
if(options.callback) {
|
||||
if(request.status >= 200 && request.status < 300) {
|
||||
// success
|
||||
if(resp.requestType != "delete") {
|
||||
resp.features = this.parseFeatures(request);
|
||||
}
|
||||
resp.code = OpenLayers.Protocol.Response.SUCCESS;
|
||||
} else {
|
||||
// failure
|
||||
resp.code = OpenLayers.Protocol.Response.FAILURE;
|
||||
}
|
||||
options.callback.call(options.scope, resp);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: parseFeatures
|
||||
* Read HTTP response body and return features.
|
||||
*
|
||||
* Parameters:
|
||||
* request - {XMLHttpRequest} The request object
|
||||
*
|
||||
* Returns:
|
||||
* {Array({<OpenLayers.Feature.Vector>})} or
|
||||
* {<OpenLayers.Feature.Vector>} Array of features or a single feature.
|
||||
*/
|
||||
parseFeatures: function(request) {
|
||||
var doc = request.responseXML;
|
||||
if (!doc || !doc.documentElement) {
|
||||
doc = request.responseText;
|
||||
}
|
||||
if (!doc || doc.length <= 0) {
|
||||
return null;
|
||||
}
|
||||
return this.format.read(doc);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: commit
|
||||
* Iterate over each feature and take action based on the feature state.
|
||||
* Possible actions are create, update and delete.
|
||||
*
|
||||
* Parameters:
|
||||
* features - {Array({<OpenLayers.Feature.Vector>})}
|
||||
* options - {Object} Optional object for setting up intermediate commit
|
||||
* callbacks.
|
||||
*
|
||||
* Valid options:
|
||||
* create - {Object} Optional object to be passed to the <create> method.
|
||||
* update - {Object} Optional object to be passed to the <update> method.
|
||||
* delete - {Object} Optional object to be passed to the <delete> method.
|
||||
* callback - {Function} Optional function to be called when the commit
|
||||
* is complete.
|
||||
* scope - {Object} Optional object to be set as the scope of the callback.
|
||||
*
|
||||
* Returns:
|
||||
* {Array(<OpenLayers.Protocol.Response>)} An array of response objects,
|
||||
* one per request made to the server, each object's "priv" property
|
||||
* references the corresponding HTTP request.
|
||||
*/
|
||||
commit: function(features, options) {
|
||||
options = OpenLayers.Util.applyDefaults(options, this.options);
|
||||
var resp = [], nResponses = 0;
|
||||
|
||||
// Divide up features before issuing any requests. This properly
|
||||
// counts requests in the event that any responses come in before
|
||||
// all requests have been issued.
|
||||
var types = {};
|
||||
types[OpenLayers.State.INSERT] = [];
|
||||
types[OpenLayers.State.UPDATE] = [];
|
||||
types[OpenLayers.State.DELETE] = [];
|
||||
var feature, list;
|
||||
for(var i=0, len=features.length; i<len; ++i) {
|
||||
feature = features[i];
|
||||
list = types[feature.state];
|
||||
if(list) {
|
||||
list.push(feature);
|
||||
}
|
||||
}
|
||||
// tally up number of requests
|
||||
var nRequests = (types[OpenLayers.State.INSERT].length > 0 ? 1 : 0) +
|
||||
types[OpenLayers.State.UPDATE].length +
|
||||
types[OpenLayers.State.DELETE].length;
|
||||
|
||||
function callback(response) {
|
||||
nResponses++;
|
||||
response.last = (nResponses >= nRequests);
|
||||
this.callUserCallback(response, options);
|
||||
}
|
||||
|
||||
// start issuing requests
|
||||
var queue = types[OpenLayers.State.INSERT];
|
||||
if(queue.length > 0) {
|
||||
resp.push(this.create(
|
||||
queue, OpenLayers.Util.applyDefaults(
|
||||
{callback: callback, scope: this},
|
||||
options.create || {} // remove || when #1716 is resolved
|
||||
)
|
||||
));
|
||||
}
|
||||
queue = types[OpenLayers.State.UPDATE];
|
||||
for(var i=queue.length-1; i>=0; --i) {
|
||||
resp.push(this.update(
|
||||
queue[i], OpenLayers.Util.applyDefaults(
|
||||
{callback: callback, scope: this},
|
||||
options.update || {} // remove || when #1716 is resolved
|
||||
))
|
||||
);
|
||||
}
|
||||
queue = types[OpenLayers.State.DELETE];
|
||||
for(var i=queue.length-1; i>=0; --i) {
|
||||
resp.push(this["delete"](
|
||||
queue[i], OpenLayers.Util.applyDefaults(
|
||||
{callback: callback, scope: this},
|
||||
options["delete"] || {} // remove || when #1716 is resolved
|
||||
))
|
||||
);
|
||||
}
|
||||
return resp;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: callUserCallback
|
||||
* This method is used from within the commit method each time an
|
||||
* an HTTP response is received from the server, it is responsible
|
||||
* for calling the user-supplied callbacks.
|
||||
*
|
||||
* Parameters:
|
||||
* resp - {<OpenLayers.Protocol.Response>}
|
||||
* options - {Object} The map of options passed to the commit call.
|
||||
*/
|
||||
callUserCallback: function(resp, options) {
|
||||
var opt = options[resp.requestType];
|
||||
if(opt && opt.callback) {
|
||||
opt.callback.call(opt.scope, resp);
|
||||
}
|
||||
if(resp.last && options.callback) {
|
||||
options.callback.call(options.scope);
|
||||
}
|
||||
},
|
||||
|
||||
CLASS_NAME: "OpenLayers.Protocol.HTTP"
|
||||
});
|
||||
669
tests/Protocol/HTTP.html
Normal file
669
tests/Protocol/HTTP.html
Normal file
@@ -0,0 +1,669 @@
|
||||
<html>
|
||||
<head>
|
||||
<script src="../../lib/OpenLayers.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
function test_constructor(t) {
|
||||
t.plan(8);
|
||||
var a = new OpenLayers.Protocol.HTTP({
|
||||
url: "foo"
|
||||
});
|
||||
|
||||
// 4 tests
|
||||
t.eq(a.url, "foo", "constructor sets url");
|
||||
t.eq(a.options.url, a.url, "constructor copies url to options.url");
|
||||
t.eq(a.params, {}, "constructor sets params");
|
||||
t.eq(a.options.params, undefined, "constructor do not copy params to options.params");
|
||||
|
||||
var params = {hello: "world"};
|
||||
var b = new OpenLayers.Protocol.HTTP({
|
||||
url: "bar",
|
||||
params: params
|
||||
});
|
||||
|
||||
// 4 tests
|
||||
t.eq(b.url, "bar", "constructor sets url");
|
||||
t.eq(b.options.url, b.url, "constructor copies url to options.url");
|
||||
t.eq(b.params, params, "constructor sets params");
|
||||
t.eq(b.options.params, b.params, "constructor copies params to options.params");
|
||||
}
|
||||
|
||||
function test_destroy(t) {
|
||||
t.plan(3);
|
||||
var protocol = new OpenLayers.Protocol.HTTP({
|
||||
url: "bar",
|
||||
params: {hello: "world"}
|
||||
});
|
||||
protocol.destroy();
|
||||
t.eq(protocol.options, null, "destroy nullifies options");
|
||||
t.eq(protocol.params, null, "destroy nullifies params");
|
||||
t.eq(protocol.headers, null, "destroy nullifies headers");
|
||||
}
|
||||
|
||||
function test_read(t) {
|
||||
t.plan(10);
|
||||
var protocol = new OpenLayers.Protocol.HTTP({
|
||||
'url': 'foo_url',
|
||||
'params': {'k': 'foo_param'}
|
||||
});
|
||||
|
||||
// fake XHR request object
|
||||
var request = {'status': 200};
|
||||
|
||||
// options to pass to read
|
||||
var readOptions = {
|
||||
'url': 'bar_url',
|
||||
'params': {'k': 'bar_param'},
|
||||
'headers': {'k': 'bar_header'},
|
||||
'scope': {'hello': 'world'},
|
||||
'callback': function() {}
|
||||
};
|
||||
|
||||
var response;
|
||||
|
||||
protocol.handleResponse = function(resp, opt) {
|
||||
// 4 tests
|
||||
var req = resp.priv;
|
||||
t.ok(this == protocol,
|
||||
'handleResponse called with correct scope');
|
||||
t.ok(opt == readOptions,
|
||||
'handleResponse called with correct options');
|
||||
t.eq(resp.CLASS_NAME, 'OpenLayers.Protocol.Response',
|
||||
'handleResponse called with a Response object');
|
||||
t.eq(req, request,
|
||||
'handleResponse called with correct request');
|
||||
|
||||
response = resp;
|
||||
};
|
||||
|
||||
var _get = OpenLayers.Request.GET;
|
||||
|
||||
OpenLayers.Request.GET = function(options) {
|
||||
// 5 tests
|
||||
t.eq(options.url, readOptions.url,
|
||||
'GET called with correct url in options');
|
||||
t.eq(options.params['k'], readOptions.params['k'],
|
||||
'GET called with correct params in options');
|
||||
t.eq(options.headers['k'], readOptions.headers['k'],
|
||||
'GET called with correct headers in options');
|
||||
t.eq(options.scope, undefined,
|
||||
'GET called with correct scope in options');
|
||||
t.ok(typeof options.callback == 'function',
|
||||
'GET called with a callback in options');
|
||||
t.delay_call(0.1, function() {
|
||||
options.callback(request);
|
||||
t.ok(resp == response,
|
||||
'read returns the expected response object');
|
||||
// cleanup
|
||||
protocol.destroy();
|
||||
OpenLayers.Request.GET = _get;
|
||||
});
|
||||
return request;
|
||||
};
|
||||
|
||||
var resp = protocol.read(readOptions);
|
||||
}
|
||||
|
||||
function test_parseFeatures(t) {
|
||||
t.plan(5);
|
||||
|
||||
var protocol = new OpenLayers.Protocol.HTTP();
|
||||
|
||||
// test responseXML - 2 tests
|
||||
var request = {
|
||||
'responseXML': {
|
||||
'documentElement': 'xml'
|
||||
}
|
||||
};
|
||||
protocol.format = {
|
||||
'read': function(doc) {
|
||||
t.eq(doc.documentElement, 'xml',
|
||||
'format.read called with correct doc');
|
||||
return doc.documentElement;
|
||||
}
|
||||
};
|
||||
var ret = protocol.parseFeatures(request);
|
||||
t.eq(ret, 'xml', 'parseFeatures returns expected value');
|
||||
|
||||
// test responseText - 2 tests
|
||||
var request = {
|
||||
'responseText': 'text'
|
||||
};
|
||||
protocol.format = {
|
||||
'read': function(doc) {
|
||||
t.eq(doc, 'text',
|
||||
'format.read called with correct doc');
|
||||
return doc;
|
||||
}
|
||||
};
|
||||
var ret = protocol.parseFeatures(request);
|
||||
t.eq(ret, 'text', 'parseFeatures returns expected value');
|
||||
|
||||
// test empty responseText - 1 test
|
||||
var request = {
|
||||
'responseText': ''
|
||||
};
|
||||
protocol.format = {
|
||||
'read': function(doc) {
|
||||
t.fail('format.read should not be called');
|
||||
}
|
||||
};
|
||||
var ret = protocol.parseFeatures(request);
|
||||
t.eq(ret, null, 'parseFeatures returns expected value');
|
||||
}
|
||||
|
||||
function test_create(t) {
|
||||
t.plan(10);
|
||||
var protocol = new OpenLayers.Protocol.HTTP({
|
||||
'url': 'foo_url',
|
||||
'format': {'write': function() {}}
|
||||
});
|
||||
|
||||
// fake XHR request object
|
||||
var request = {'status': 200};
|
||||
|
||||
// features to pass to create
|
||||
var features = ['feature'];
|
||||
|
||||
// options to pass to create
|
||||
var createOptions = {
|
||||
'url': 'bar_url',
|
||||
'headers': {'k': 'bar_header'},
|
||||
'scope': {'hello': 'world'},
|
||||
'callback': function() {}
|
||||
};
|
||||
|
||||
var response;
|
||||
|
||||
protocol.handleCreate = function(resp, opt) {
|
||||
// 5 tests
|
||||
var req = resp.priv;
|
||||
t.ok(this == protocol,
|
||||
'handleCreate called with correct scope');
|
||||
t.ok(opt == createOptions,
|
||||
'handleCreate called with correct options');
|
||||
t.eq(resp.CLASS_NAME, 'OpenLayers.Protocol.Response',
|
||||
'handleCreate called with a Response object');
|
||||
t.ok(resp.reqFeatures == features,
|
||||
'handleCreate called with correct requested features in response');
|
||||
t.eq(req, request,
|
||||
'handleCreate called with correct request');
|
||||
|
||||
response = resp;
|
||||
};
|
||||
|
||||
var _post = OpenLayers.Request.POST;
|
||||
|
||||
OpenLayers.Request.POST = function(options) {
|
||||
// 4 tests
|
||||
t.eq(options.url, createOptions.url,
|
||||
'POST called with correct url in options');
|
||||
t.eq(options.headers['k'], createOptions.headers['k'],
|
||||
'POST called with correct headers in options');
|
||||
t.eq(options.scope, undefined,
|
||||
'POST called with correct scope in options');
|
||||
t.ok(typeof options.callback == 'function',
|
||||
'POST called with a callback in options');
|
||||
// call callback - delayed because this function has to return first
|
||||
t.delay_call(0.1, function() {
|
||||
options.callback(request);
|
||||
t.ok(resp == response,
|
||||
'create returns the expected response object');
|
||||
// cleanup
|
||||
protocol.destroy();
|
||||
OpenLayers.Request.POST = _post;
|
||||
});
|
||||
return request;
|
||||
};
|
||||
|
||||
var resp = protocol.create(features, createOptions);
|
||||
}
|
||||
|
||||
function test_update(t) {
|
||||
t.plan(10);
|
||||
var protocol = new OpenLayers.Protocol.HTTP({
|
||||
'url': 'foo_url',
|
||||
'format': {'write': function() {}}
|
||||
});
|
||||
|
||||
// fake XHR request object
|
||||
var request = {'status': 200};
|
||||
|
||||
// feature to pass to update
|
||||
var feature = {'feature':'feature'};
|
||||
|
||||
// options to pass to update
|
||||
var updateOptions = {
|
||||
'url': 'bar_url',
|
||||
'headers': {'k': 'bar_header'},
|
||||
'scope': {'hello': 'world'},
|
||||
'callback': function() {}
|
||||
};
|
||||
|
||||
var response;
|
||||
|
||||
protocol.handleUpdate = function(resp, opt) {
|
||||
var req = resp.priv;
|
||||
// 5 tests
|
||||
t.ok(this == protocol,
|
||||
'handleUpdate called with correct scope');
|
||||
t.ok(opt == updateOptions,
|
||||
'handleUpdate called with correct options');
|
||||
t.eq(resp.CLASS_NAME, 'OpenLayers.Protocol.Response',
|
||||
'handleUpdate called with a Response object');
|
||||
t.ok(resp.reqFeatures == feature,
|
||||
'handleUpdate called with correct requested feature in response');
|
||||
t.eq(req, request,
|
||||
'handleUpdate called with correct request');
|
||||
|
||||
response = resp;
|
||||
};
|
||||
|
||||
var _put = OpenLayers.Request.PUT;
|
||||
|
||||
OpenLayers.Request.PUT = function(options) {
|
||||
// 4 tests
|
||||
t.eq(options.url, updateOptions.url,
|
||||
'PUT called with correct url in options');
|
||||
t.eq(options.headers['k'], updateOptions.headers['k'],
|
||||
'PUT called with correct headers in options');
|
||||
t.eq(options.scope, undefined,
|
||||
'PUT called with correct scope in options');
|
||||
t.ok(typeof options.callback == 'function',
|
||||
'PUT called with a callback in options');
|
||||
// call callback - delayed because this function has to return first
|
||||
t.delay_call(0.1, function() {
|
||||
options.callback(request);
|
||||
t.ok(resp == response,
|
||||
'update returns the expected response object');
|
||||
// cleanup
|
||||
protocol.destroy();
|
||||
OpenLayers.Request.PUT = _put;
|
||||
});
|
||||
return request;
|
||||
};
|
||||
|
||||
var resp = protocol.update(feature, updateOptions);
|
||||
|
||||
}
|
||||
function test_handleResponse(t) {
|
||||
t.plan(6);
|
||||
|
||||
var protocol = new OpenLayers.Protocol.HTTP();
|
||||
|
||||
var options, response, request, features;
|
||||
|
||||
// test options - 2 tests
|
||||
var scope = {'fake': 'scope'};
|
||||
options = {
|
||||
'scope': scope,
|
||||
'callback': function(resp) {
|
||||
t.ok(this == scope,
|
||||
'[no status] callback called with correct scope');
|
||||
t.ok(resp == response,
|
||||
'[no status] callback called with correct response');
|
||||
}
|
||||
};
|
||||
response = {priv: {}};
|
||||
protocol.handleResponse(response, options);
|
||||
|
||||
// test failure condition - 1 test
|
||||
options = {
|
||||
'callback': function(resp) {
|
||||
t.eq(resp.code, OpenLayers.Protocol.Response.FAILURE,
|
||||
'[status 400] callback called with correct response code');
|
||||
}
|
||||
};
|
||||
response = {priv: {status: 400}};
|
||||
protocol.handleResponse(response, options);
|
||||
|
||||
// test success condition - 3 tests
|
||||
features = {'fake': 'features'};
|
||||
options = {
|
||||
'callback': function(resp) {
|
||||
t.eq(resp.code, OpenLayers.Protocol.Response.SUCCESS,
|
||||
'[status 200] callback called with correct response code');
|
||||
t.eq(resp.features, features,
|
||||
'[status 200] callback called with correct features in response');
|
||||
}
|
||||
};
|
||||
response = {priv: {status: 200}};
|
||||
protocol.parseFeatures = function(request) {
|
||||
t.ok(request == response.priv,
|
||||
'[status 200] parseFeatures called with correct request');
|
||||
return features;
|
||||
}
|
||||
protocol.handleResponse(response, options);
|
||||
|
||||
// cleanup
|
||||
protocol.destroy();
|
||||
}
|
||||
|
||||
function test_delete(t) {
|
||||
t.plan(10);
|
||||
var protocol = new OpenLayers.Protocol.HTTP({
|
||||
'url': 'foo_url'
|
||||
});
|
||||
|
||||
// fake XHR request object
|
||||
var request = {'status': 200};
|
||||
|
||||
// feature to pass to delete
|
||||
var feature = {'url': 'bar_url'};
|
||||
|
||||
// options to pass to delete
|
||||
var deleteOptions = {
|
||||
'url': 'bar_url',
|
||||
'headers': {'k': 'bar_header'},
|
||||
'scope': {'hello': 'world'},
|
||||
'callback': function() {}
|
||||
};
|
||||
|
||||
var response;
|
||||
|
||||
protocol.handleDelete = function(resp, opt) {
|
||||
// 5 tests
|
||||
var req = resp.priv;
|
||||
t.ok(this == protocol,
|
||||
'handleDelete called with correct scope');
|
||||
t.ok(opt == deleteOptions,
|
||||
'handleDelete called with correct options');
|
||||
t.eq(resp.CLASS_NAME, 'OpenLayers.Protocol.Response',
|
||||
'handleDelete called with a Response object');
|
||||
t.ok(resp.reqFeatures == feature,
|
||||
'handleDelete called with correct requested feature in response');
|
||||
t.eq(req, request,
|
||||
'handleDelete called with correct request');
|
||||
|
||||
response = resp;
|
||||
};
|
||||
|
||||
var _delete = OpenLayers.Request.DELETE;
|
||||
|
||||
OpenLayers.Request.DELETE = function(options) {
|
||||
// 4 tests
|
||||
t.eq(options.url, deleteOptions.url,
|
||||
'DELETE called with correct url in options');
|
||||
t.eq(options.headers['k'], deleteOptions.headers['k'],
|
||||
'DELETE called with correct headers in options');
|
||||
t.eq(options.scope, undefined,
|
||||
'DELETE called with correct scope in options');
|
||||
t.ok(typeof options.callback == 'function',
|
||||
'DELETE called with a callback in options');
|
||||
// call callback - delayed because this function has to return first
|
||||
t.delay_call(0.1, function() {
|
||||
options.callback(request);
|
||||
t.ok(resp == response,
|
||||
'read returns the expected response object');
|
||||
// cleanup
|
||||
protocol.destroy();
|
||||
OpenLayers.Request.DELETE = _delete;
|
||||
});
|
||||
return request;
|
||||
};
|
||||
|
||||
var resp = protocol['delete'](feature, deleteOptions);
|
||||
|
||||
}
|
||||
|
||||
function test_handleDelete(t) {
|
||||
t.plan(4);
|
||||
|
||||
var protocol = new OpenLayers.Protocol.HTTP();
|
||||
|
||||
var options, response, request, features;
|
||||
|
||||
// test options - 2 tests
|
||||
var scope = {'fake': 'scope'};
|
||||
options = {
|
||||
'scope': scope,
|
||||
'callback': function(resp) {
|
||||
t.ok(this == scope,
|
||||
'callback called with correct scope');
|
||||
t.ok(resp == response,
|
||||
'callback called with correct response');
|
||||
}
|
||||
};
|
||||
response = {priv: {}};
|
||||
protocol.handleDelete(response, options);
|
||||
|
||||
// test failure condition - 1 test
|
||||
options = {
|
||||
'callback': function(resp) {
|
||||
t.eq(resp.code, OpenLayers.Protocol.Response.FAILURE,
|
||||
'callback called with correct response code');
|
||||
}
|
||||
};
|
||||
response = {priv: {status: 400}};
|
||||
protocol.handleDelete(response, options);
|
||||
|
||||
// test success condition - 1 test
|
||||
options = {
|
||||
'callback': function(resp) {
|
||||
t.eq(resp.code, OpenLayers.Protocol.Response.SUCCESS,
|
||||
'callback called with correct response code');
|
||||
}
|
||||
};
|
||||
response = {priv: {status: 200}};
|
||||
protocol.handleDelete(response, options);
|
||||
|
||||
// cleanup
|
||||
protocol.destroy();
|
||||
}
|
||||
|
||||
function test_commit(t) {
|
||||
t.plan(17);
|
||||
|
||||
var protocol = new OpenLayers.Protocol.HTTP();
|
||||
|
||||
// 6 features
|
||||
var features = [
|
||||
{'state': OpenLayers.State.INSERT},
|
||||
{'state': OpenLayers.State.INSERT},
|
||||
{'state': OpenLayers.State.UPDATE},
|
||||
{'state': OpenLayers.State.UPDATE},
|
||||
{'state': OpenLayers.State.DELETE},
|
||||
{'state': OpenLayers.State.DELETE}
|
||||
];
|
||||
|
||||
var options = {
|
||||
'create': {
|
||||
'callback': function(resp) {
|
||||
}
|
||||
},
|
||||
'update': {
|
||||
'callback': function(resp) {
|
||||
}
|
||||
},
|
||||
'delete': {
|
||||
'callback': function(resp) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var respCreate = new OpenLayers.Protocol.Response();
|
||||
var respUpdate = new OpenLayers.Protocol.Response();
|
||||
var respDelete = new OpenLayers.Protocol.Response();
|
||||
|
||||
// 2 tests
|
||||
protocol['create'] = function(feature, options) {
|
||||
t.ok(options.scope == protocol,
|
||||
'create called with correct scope');
|
||||
t.ok(typeof options.callback == 'function',
|
||||
'create called with a callback in options');
|
||||
options.callback.call(options.scope, respCreate);
|
||||
return respCreate;
|
||||
};
|
||||
// 4 tests
|
||||
protocol['update'] = function(feature, options) {
|
||||
t.ok(options.scope == protocol,
|
||||
'update called with correct scope');
|
||||
t.ok(typeof options.callback == 'function',
|
||||
'update called with a callback in options');
|
||||
options.callback.call(options.scope, respUpdate);
|
||||
return respUpdate;
|
||||
};
|
||||
// 4 tests
|
||||
protocol['delete'] = function(feature, options) {
|
||||
t.ok(options.scope == protocol,
|
||||
'delete called with correct scope');
|
||||
t.ok(typeof options.callback == 'function',
|
||||
'delete called with a callback in options');
|
||||
options.callback.call(options.scope, respDelete);
|
||||
return respDelete;
|
||||
};
|
||||
|
||||
var count = 0;
|
||||
|
||||
// 5 tests
|
||||
protocol.callUserCallback = function(resp, opt) {
|
||||
t.ok(opt == options,
|
||||
'callUserCallback called with correction options map');
|
||||
count++;
|
||||
};
|
||||
|
||||
var resp = protocol.commit(features, options);
|
||||
|
||||
// 2 tests
|
||||
t.eq(count, 5, 'callUserCallback called for each request');
|
||||
t.eq(resp.length, 5, 'commit returns array with correct length');
|
||||
|
||||
// cleanup
|
||||
protocol.destroy();
|
||||
}
|
||||
|
||||
function test_callUserCallback(t) {
|
||||
t.plan(6);
|
||||
|
||||
var protocol = new OpenLayers.Protocol.HTTP();
|
||||
|
||||
var options, resp;
|
||||
var scope = {'fake': 'scope'};
|
||||
|
||||
// test commit callback
|
||||
// 1 tests
|
||||
options = {
|
||||
'callback': function() {
|
||||
t.ok(this == scope, 'callback called with correct scope');
|
||||
},
|
||||
'scope': scope
|
||||
};
|
||||
resp = {'requestType': 'create', 'last': true};
|
||||
protocol.callUserCallback(resp, options);
|
||||
// 0 test
|
||||
resp = {'requestType': 'create', 'last': false};
|
||||
protocol.callUserCallback(resp, options);
|
||||
|
||||
// test create callback
|
||||
// 2 tests
|
||||
options = {
|
||||
'create': {
|
||||
'callback': function(r) {
|
||||
t.ok(this == scope, 'callback called with correct scope');
|
||||
t.ok(r == resp, 'callback called with correct response');
|
||||
},
|
||||
'scope': scope
|
||||
}
|
||||
};
|
||||
resp = {'requestType': 'create'};
|
||||
protocol.callUserCallback(resp, options);
|
||||
|
||||
// test with both callbacks set
|
||||
// 3 tests
|
||||
options = {
|
||||
'create': {
|
||||
'callback': function(r) {
|
||||
t.ok(this == scope, 'callback called with correct scope');
|
||||
t.ok(r == resp, 'callback called with correct response');
|
||||
},
|
||||
'scope': scope
|
||||
},
|
||||
'callback': function() {
|
||||
t.ok(this == scope, 'callback called with correct scope');
|
||||
},
|
||||
'scope': scope
|
||||
};
|
||||
resp = {'requestType': 'create', 'last': true};
|
||||
protocol.callUserCallback(resp, options);
|
||||
|
||||
// no callback set
|
||||
// 0 test
|
||||
options = {
|
||||
'delete': {
|
||||
'callback': function(resp) {
|
||||
t.fail('callback should not get called');
|
||||
}
|
||||
}
|
||||
};
|
||||
resp = {'requestType': 'create'};
|
||||
protocol.callUserCallback(resp, options);
|
||||
|
||||
// cleanup
|
||||
protocol.destroy();
|
||||
}
|
||||
|
||||
function test_options(t) {
|
||||
t.plan(7);
|
||||
|
||||
var _R = OpenLayers.Protocol.Response;
|
||||
OpenLayers.Protocol.Response = function() {
|
||||
this.priv = {status: 200};
|
||||
};
|
||||
|
||||
// test that read with no options uses protocol options - 5 tests
|
||||
var url = "foo";
|
||||
var headers = {};
|
||||
var params = {};
|
||||
var scope = {};
|
||||
var protocol = new OpenLayers.Protocol.HTTP({
|
||||
format: new OpenLayers.Format({read: function(){}, write: function(){}}),
|
||||
url: url,
|
||||
headers: headers,
|
||||
params: params,
|
||||
callback: function() {
|
||||
t.ok(true, "[read] Correct callback.");
|
||||
t.eq(this, scope, "[read] Correct scope.");
|
||||
},
|
||||
scope: scope
|
||||
});
|
||||
var _issue = OpenLayers.Request.issue;
|
||||
OpenLayers.Request.issue = function(config) {
|
||||
t.eq(config.url, url, "[" + config.method + "] Correct url.");
|
||||
t.eq(config.headers, headers, "[" + config.method + "] Correct headers.");
|
||||
t.eq(config.params, params, "[" + config.method + "] Correct params.");
|
||||
config.callback.call(config.scope);
|
||||
};
|
||||
protocol.read();
|
||||
OpenLayers.Request.issue = _issue;
|
||||
|
||||
// test that commit with no options uses protocol options - 2 tests
|
||||
_issue = OpenLayers.Request.issue;
|
||||
OpenLayers.Request.issue = function(config) {
|
||||
config.callback.call(config.scope);
|
||||
};
|
||||
var called = 0;
|
||||
protocol.options.callback = function() {
|
||||
called++;
|
||||
t.eq(this, scope, "[commit] Correct scope.");
|
||||
};
|
||||
protocol.commit([
|
||||
{state: OpenLayers.State.INSERT},
|
||||
{state: OpenLayers.State.INSERT},
|
||||
{state: OpenLayers.State.UPDATE},
|
||||
{state: OpenLayers.State.UPDATE},
|
||||
{state: OpenLayers.State.DELETE},
|
||||
{state: OpenLayers.State.DELETE}
|
||||
]);
|
||||
t.eq(called, 1, "[commit] Callback called once.");
|
||||
|
||||
// cleanup
|
||||
protocol.destroy();
|
||||
OpenLayers.Protocol.Response = _R;
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -113,6 +113,7 @@
|
||||
<li>Popup/FramedCloud.html</li>
|
||||
<li>Projection.html</li>
|
||||
<li>Protocol.html</li>
|
||||
<li>Protocol/HTTP.html</li>
|
||||
<li>Renderer.html</li>
|
||||
<li>Renderer/Canvas.html</li>
|
||||
<li>Renderer/Elements.html</li>
|
||||
|
||||
Reference in New Issue
Block a user