Adding a protocol for reading features cross-origin from services that support JSON with a callback. r=erilem (closes #2956)
git-svn-id: http://svn.openlayers.org/trunk/openlayers@11691 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
363
lib/OpenLayers/Protocol/Script.js
Normal file
363
lib/OpenLayers/Protocol/Script.js
Normal file
@@ -0,0 +1,363 @@
|
||||
/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
|
||||
* full list of contributors). Published under the Clear BSD license.
|
||||
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
|
||||
* full text of the license. */
|
||||
|
||||
/**
|
||||
* @requires OpenLayers/Protocol.js
|
||||
* @requires OpenLayers/Feature/Vector.js
|
||||
* @requires OpenLayers/Format/GeoJSON.js
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class: OpenLayers.Protocol.Script
|
||||
* A basic Script protocol for vector layers. Create a new instance with the
|
||||
* <OpenLayers.Protocol.Script> constructor. A script protocol is used to
|
||||
* get around the same origin policy. It works with services that return
|
||||
* JSONP - that is, JSON wrapped in a client-specified callback. The
|
||||
* protocol handles fetching and parsing of feature data and sends parsed
|
||||
* features to the <callback> configured with the protocol. The protocol
|
||||
* expects features serialized as GeoJSON by default, but can be configured
|
||||
* to work with other formats by setting the <format> property.
|
||||
*
|
||||
* Inherits from:
|
||||
* - <OpenLayers.Protocol>
|
||||
*/
|
||||
OpenLayers.Protocol.Script = OpenLayers.Class(OpenLayers.Protocol, {
|
||||
|
||||
/**
|
||||
* APIProperty: url
|
||||
* {String} Service URL. The service is expected to return serialized
|
||||
* features wrapped in a named callback (where the callback name is
|
||||
* generated by this protocol).
|
||||
* Read-only, set through the options passed to the constructor.
|
||||
*/
|
||||
url: null,
|
||||
|
||||
/**
|
||||
* APIProperty: params
|
||||
* {Object} Query string parameters to be appended to the URL.
|
||||
* Read-only, set through the options passed to the constructor.
|
||||
* Example: {maxFeatures: 50}
|
||||
*/
|
||||
params: null,
|
||||
|
||||
/**
|
||||
* APIProperty: callback
|
||||
* {Object} Function to be called when the <read> operation completes.
|
||||
*/
|
||||
callback: null,
|
||||
|
||||
/**
|
||||
* APIProperty: scope
|
||||
* {Object} Optional ``this`` object for the callback. Read-only, set
|
||||
* through the options passed to the constructor.
|
||||
*/
|
||||
scope: null,
|
||||
|
||||
/**
|
||||
* APIProperty: format
|
||||
* {<OpenLayers.Format>} Format for parsing features. Default is an
|
||||
* <OpenLayers.Format.GeoJSON> format. If an alternative is provided,
|
||||
* the format's read method must take an object and return an array
|
||||
* of features.
|
||||
*/
|
||||
format: null,
|
||||
|
||||
/**
|
||||
* APIProperty: callbackKey
|
||||
* {String} The name of the query string parameter that the service
|
||||
* recognizes as the callback identifier. Default is "callback".
|
||||
* This key is used to generate the URL for the script. For example
|
||||
* setting <callbackKey> to "myCallback" would result in a URL like
|
||||
* http://example.com/?myCallback=...
|
||||
*/
|
||||
callbackKey: "callback",
|
||||
|
||||
/**
|
||||
* APIProperty: callbackPrefix
|
||||
* {String} Where a service requires that the callback query string
|
||||
* parameter value is prefixed by some string, this value may be set.
|
||||
* For example, setting <callbackPrefix> to "foo:" would result in a
|
||||
* URL like http://example.com/?callback=foo:... Default is "".
|
||||
*/
|
||||
callbackPrefix: "",
|
||||
|
||||
/**
|
||||
* Property: pendingRequests
|
||||
* {Object} References all pending requests. Property names are script
|
||||
* identifiers and property values are script elements.
|
||||
*/
|
||||
pendingRequests: null,
|
||||
|
||||
/**
|
||||
* Constructor: OpenLayers.Protocol.Script
|
||||
* A class for giving layers generic Script protocol.
|
||||
*
|
||||
* Parameters:
|
||||
* options - {Object} Optional object whose properties will be set on the
|
||||
* instance.
|
||||
*
|
||||
* Valid options include:
|
||||
* url - {String}
|
||||
* params - {Object}
|
||||
* callback - {Function}
|
||||
* scope - {Object}
|
||||
*/
|
||||
initialize: function(options) {
|
||||
options = options || {};
|
||||
this.params = {};
|
||||
this.pendingRequests = {};
|
||||
OpenLayers.Protocol.prototype.initialize.apply(this, arguments);
|
||||
if (!this.format) {
|
||||
this.format = new OpenLayers.Format.GeoJSON();
|
||||
}
|
||||
|
||||
if (!this.filterToParams && OpenLayers.Protocol.simpleFilterSerializer) {
|
||||
this.filterToParams = OpenLayers.Function.bind(
|
||||
OpenLayers.Protocol.simpleFilterSerializer, this
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: 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.
|
||||
*
|
||||
* Valid options:
|
||||
* url - {String} Url for the request.
|
||||
* params - {Object} Parameters to get serialized as a query string.
|
||||
* filter - {<OpenLayers.Filter>} Filter to get serialized as a
|
||||
* query string.
|
||||
*
|
||||
* Returns:
|
||||
* {<OpenLayers.Protocol.Response>} A response object, whose "priv" property
|
||||
* references the injected script. This object is also passed to the
|
||||
* callback function when the request completes, its "features" property
|
||||
* is then populated with the features received from the server.
|
||||
*/
|
||||
read: function(options) {
|
||||
OpenLayers.Protocol.prototype.read.apply(this, arguments);
|
||||
options = OpenLayers.Util.applyDefaults(options, this.options);
|
||||
options.params = OpenLayers.Util.applyDefaults(
|
||||
options.params, this.options.params
|
||||
);
|
||||
if (options.filter && this.filterToParams) {
|
||||
options.params = this.filterToParams(
|
||||
options.filter, options.params
|
||||
);
|
||||
}
|
||||
var response = new OpenLayers.Protocol.Response({requestType: "read"});
|
||||
var request = this.createRequest(
|
||||
options.url,
|
||||
options.params,
|
||||
OpenLayers.Function.bind(function(data) {
|
||||
response.data = data;
|
||||
this.handleRead(response, options);
|
||||
}, this)
|
||||
);
|
||||
response.priv = request;
|
||||
return response;
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: filterToParams
|
||||
* Optional method to translate an <OpenLayers.Filter> object into an object
|
||||
* that can be serialized as request query string provided. If a custom
|
||||
* method is not provided, any filter will not be serialized.
|
||||
*
|
||||
* Parameters:
|
||||
* filter - {<OpenLayers.Filter>} filter to convert.
|
||||
* params - {Object} The parameters object.
|
||||
*
|
||||
* Returns:
|
||||
* {Object} The resulting parameters object.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Method: createRequest
|
||||
* Issues a request for features by creating injecting a script in the
|
||||
* document head.
|
||||
*
|
||||
* Parameters:
|
||||
* url - {String} Service URL.
|
||||
* params - {Object} Query string parameters.
|
||||
* callback - {Function} Callback to be called with resulting data.
|
||||
*
|
||||
* Returns:
|
||||
* {HTMLScriptElement} The script pending execution.
|
||||
*/
|
||||
createRequest: function(url, params, callback) {
|
||||
var id = OpenLayers.Protocol.Script.register(callback);
|
||||
var name = "OpenLayers.Protocol.Script.getCallback(" + id + ")";
|
||||
params = OpenLayers.Util.extend({}, params);
|
||||
params[this.callbackKey] = this.callbackPrefix + name;
|
||||
url = OpenLayers.Util.urlAppend(
|
||||
url, OpenLayers.Util.getParameterString(params)
|
||||
);
|
||||
var script = document.createElement("script");
|
||||
script.type = "text/javascript";
|
||||
script.src = url;
|
||||
script.id = "OpenLayers_Protocol_Script_" + id;
|
||||
this.pendingRequests[script.id] = script;
|
||||
var head = document.getElementsByTagName("head")[0];
|
||||
head.appendChild(script);
|
||||
return script;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: destroyRequest
|
||||
* Remove a script node associated with a response from the document. Also
|
||||
* unregisters the callback and removes the script from the
|
||||
* <pendingRequests> object.
|
||||
*
|
||||
* Parameters:
|
||||
* script - {HTMLScriptElement}
|
||||
*/
|
||||
destroyRequest: function(script) {
|
||||
OpenLayers.Protocol.Script.unregister(script.id.split("_").pop());
|
||||
delete this.pendingRequests[script.id];
|
||||
if (script.parentNode) {
|
||||
script.parentNode.removeChild(script);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: handleRead
|
||||
* Individual callbacks are created for read, create and update, should
|
||||
* a subclass need to override each one separately.
|
||||
*
|
||||
* Parameters:
|
||||
* response - {<OpenLayers.Protocol.Response>} The response object to pass to
|
||||
* the user callback.
|
||||
* options - {Object} The user options passed to the read call.
|
||||
*/
|
||||
handleRead: function(response, options) {
|
||||
this.handleResponse(response, options);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: handleResponse
|
||||
* Called by CRUD specific handlers.
|
||||
*
|
||||
* Parameters:
|
||||
* response - {<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(response, options) {
|
||||
if (options.callback) {
|
||||
if (response.data) {
|
||||
response.features = this.parseFeatures(response.data);
|
||||
response.code = OpenLayers.Protocol.Response.SUCCESS;
|
||||
} else {
|
||||
response.code = OpenLayers.Protocol.Response.FAILURE;
|
||||
}
|
||||
this.destroyRequest(response.priv);
|
||||
options.callback.call(options.scope, response);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: parseFeatures
|
||||
* Read Script response body and return features.
|
||||
*
|
||||
* Parameters:
|
||||
* data - {Object} The data sent to the callback function by the server.
|
||||
*
|
||||
* Returns:
|
||||
* {Array({<OpenLayers.Feature.Vector>})} or
|
||||
* {<OpenLayers.Feature.Vector>} Array of features or a single feature.
|
||||
*/
|
||||
parseFeatures: function(data) {
|
||||
return this.format.read(data);
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: abort
|
||||
* Abort an ongoing request. If no response is provided, all pending
|
||||
* requests will be aborted.
|
||||
*
|
||||
* Parameters:
|
||||
* response - {<OpenLayers.Protocol.Response>} The response object returned
|
||||
* from a <read> request.
|
||||
*/
|
||||
abort: function(response) {
|
||||
if (response) {
|
||||
this.destroyRequest(response.priv);
|
||||
} else {
|
||||
for (var key in this.pendingRequests) {
|
||||
this.destroyRequest(this.pendingRequests[key]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: destroy
|
||||
* Clean up the protocol.
|
||||
*/
|
||||
destroy: function() {
|
||||
this.abort();
|
||||
delete this.params;
|
||||
delete this.format;
|
||||
OpenLayers.Protocol.prototype.destroy.apply(this);
|
||||
},
|
||||
|
||||
CLASS_NAME: "OpenLayers.Protocol.Script"
|
||||
});
|
||||
|
||||
(function() {
|
||||
var o = OpenLayers.Protocol.Script;
|
||||
var counter = 0;
|
||||
var registry = {};
|
||||
|
||||
/**
|
||||
* Function: OpenLayers.Protocol.Script.register
|
||||
* Register a callback for a newly created script.
|
||||
*
|
||||
* Parameters:
|
||||
* callback: {Function} The callback to be executed when the newly added
|
||||
* script loads. This callback will be called with a single argument
|
||||
* that is the JSON returned by the service.
|
||||
*
|
||||
* Returns:
|
||||
* {Number} An identifier for retreiving the registered callback.
|
||||
*/
|
||||
o.register = function(callback) {
|
||||
var id = ++counter;
|
||||
registry[id] = callback;
|
||||
return id;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: OpenLayers.Protocol.Script.unregister
|
||||
* Unregister a callback previously registered with the register function.
|
||||
*
|
||||
* Parameters:
|
||||
* id: {Number} The identifer returned by the register function.
|
||||
*/
|
||||
o.unregister = function(id) {
|
||||
delete registry[id];
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: OpenLayers.Protocol.Script.getCallback
|
||||
* Retreive and unregister a callback. A call to this function is the "P"
|
||||
* in JSONP. For example, a script may be added with a src attribute
|
||||
* http://example.com/features.json?callback=OpenLayers.Protocol.Script.getCallback(1)
|
||||
*
|
||||
* Parameters:
|
||||
* id: {Number} The identifer returned by the register function.
|
||||
*/
|
||||
o.getCallback = function(id) {
|
||||
var callback = registry[id];
|
||||
o.unregister(id);
|
||||
return callback;
|
||||
};
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user