1
|
/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
|
2
|
* full list of contributors). Published under the 2-clause BSD license.
|
3
|
* See license.txt in the OpenLayers distribution or repository for the
|
4
|
* full text of the license. */
|
5
|
|
6
|
/**
|
7
|
* @requires OpenLayers/Protocol.js
|
8
|
* @requires OpenLayers/Feature/Vector.js
|
9
|
* @requires OpenLayers/Format/GeoJSON.js
|
10
|
*/
|
11
|
|
12
|
/**
|
13
|
* if application uses the query string, for example, for BBOX parameters,
|
14
|
* OpenLayers/Format/QueryStringFilter.js should be included in the build config file
|
15
|
*/
|
16
|
|
17
|
/**
|
18
|
* Class: OpenLayers.Protocol.Script
|
19
|
* A basic Script protocol for vector layers. Create a new instance with the
|
20
|
* <OpenLayers.Protocol.Script> constructor. A script protocol is used to
|
21
|
* get around the same origin policy. It works with services that return
|
22
|
* JSONP - that is, JSON wrapped in a client-specified callback. The
|
23
|
* protocol handles fetching and parsing of feature data and sends parsed
|
24
|
* features to the <callback> configured with the protocol. The protocol
|
25
|
* expects features serialized as GeoJSON by default, but can be configured
|
26
|
* to work with other formats by setting the <format> property.
|
27
|
*
|
28
|
* Inherits from:
|
29
|
* - <OpenLayers.Protocol>
|
30
|
*/
|
31
|
OpenLayers.Protocol.Script = OpenLayers.Class(OpenLayers.Protocol, {
|
32
|
|
33
|
/**
|
34
|
* APIProperty: url
|
35
|
* {String} Service URL. The service is expected to return serialized
|
36
|
* features wrapped in a named callback (where the callback name is
|
37
|
* generated by this protocol).
|
38
|
* Read-only, set through the options passed to the constructor.
|
39
|
*/
|
40
|
url: null,
|
41
|
|
42
|
/**
|
43
|
* APIProperty: params
|
44
|
* {Object} Query string parameters to be appended to the URL.
|
45
|
* Read-only, set through the options passed to the constructor.
|
46
|
* Example: {maxFeatures: 50}
|
47
|
*/
|
48
|
params: null,
|
49
|
|
50
|
/**
|
51
|
* APIProperty: callback
|
52
|
* {Object} Function to be called when the <read> operation completes.
|
53
|
*/
|
54
|
callback: null,
|
55
|
|
56
|
/**
|
57
|
* APIProperty: callbackTemplate
|
58
|
* {String} Template for creating a unique callback function name
|
59
|
* for the registry. Should include ${id}. The ${id} variable will be
|
60
|
* replaced with a string identifier prefixed with a "c" (e.g. c1, c2).
|
61
|
* Default is "OpenLayers.Protocol.Script.registry.${id}".
|
62
|
*/
|
63
|
callbackTemplate: "OpenLayers.Protocol.Script.registry.${id}",
|
64
|
|
65
|
/**
|
66
|
* APIProperty: callbackKey
|
67
|
* {String} The name of the query string parameter that the service
|
68
|
* recognizes as the callback identifier. Default is "callback".
|
69
|
* This key is used to generate the URL for the script. For example
|
70
|
* setting <callbackKey> to "myCallback" would result in a URL like
|
71
|
* http://example.com/?myCallback=...
|
72
|
*/
|
73
|
callbackKey: "callback",
|
74
|
|
75
|
/**
|
76
|
* APIProperty: callbackPrefix
|
77
|
* {String} Where a service requires that the callback query string
|
78
|
* parameter value is prefixed by some string, this value may be set.
|
79
|
* For example, setting <callbackPrefix> to "foo:" would result in a
|
80
|
* URL like http://example.com/?callback=foo:... Default is "".
|
81
|
*/
|
82
|
callbackPrefix: "",
|
83
|
|
84
|
/**
|
85
|
* APIProperty: scope
|
86
|
* {Object} Optional ``this`` object for the callback. Read-only, set
|
87
|
* through the options passed to the constructor.
|
88
|
*/
|
89
|
scope: null,
|
90
|
|
91
|
/**
|
92
|
* APIProperty: format
|
93
|
* {<OpenLayers.Format>} Format for parsing features. Default is an
|
94
|
* <OpenLayers.Format.GeoJSON> format. If an alternative is provided,
|
95
|
* the format's read method must take an object and return an array
|
96
|
* of features.
|
97
|
*/
|
98
|
format: null,
|
99
|
|
100
|
/**
|
101
|
* Property: pendingRequests
|
102
|
* {Object} References all pending requests. Property names are script
|
103
|
* identifiers and property values are script elements.
|
104
|
*/
|
105
|
pendingRequests: null,
|
106
|
|
107
|
/**
|
108
|
* APIProperty: srsInBBOX
|
109
|
* {Boolean} Include the SRS identifier in BBOX query string parameter.
|
110
|
* Setting this property has no effect if a custom filterToParams method
|
111
|
* is provided. Default is false. If true and the layer has a
|
112
|
* projection object set, any BBOX filter will be serialized with a
|
113
|
* fifth item identifying the projection.
|
114
|
* E.g. bbox=-1000,-1000,1000,1000,EPSG:900913
|
115
|
*/
|
116
|
srsInBBOX: false,
|
117
|
|
118
|
/**
|
119
|
* Constructor: OpenLayers.Protocol.Script
|
120
|
* A class for giving layers generic Script protocol.
|
121
|
*
|
122
|
* Parameters:
|
123
|
* options - {Object} Optional object whose properties will be set on the
|
124
|
* instance.
|
125
|
*
|
126
|
* Valid options include:
|
127
|
* url - {String}
|
128
|
* params - {Object}
|
129
|
* callback - {Function}
|
130
|
* scope - {Object}
|
131
|
*/
|
132
|
initialize: function(options) {
|
133
|
options = options || {};
|
134
|
this.params = {};
|
135
|
this.pendingRequests = {};
|
136
|
OpenLayers.Protocol.prototype.initialize.apply(this, arguments);
|
137
|
if (!this.format) {
|
138
|
this.format = new OpenLayers.Format.GeoJSON();
|
139
|
}
|
140
|
|
141
|
if (!this.filterToParams && OpenLayers.Format.QueryStringFilter) {
|
142
|
var format = new OpenLayers.Format.QueryStringFilter({
|
143
|
srsInBBOX: this.srsInBBOX
|
144
|
});
|
145
|
this.filterToParams = function(filter, params) {
|
146
|
return format.write(filter, params);
|
147
|
};
|
148
|
}
|
149
|
},
|
150
|
|
151
|
/**
|
152
|
* APIMethod: read
|
153
|
* Construct a request for reading new features.
|
154
|
*
|
155
|
* Parameters:
|
156
|
* options - {Object} Optional object for configuring the request.
|
157
|
* This object is modified and should not be reused.
|
158
|
*
|
159
|
* Valid options:
|
160
|
* url - {String} Url for the request.
|
161
|
* params - {Object} Parameters to get serialized as a query string.
|
162
|
* filter - {<OpenLayers.Filter>} Filter to get serialized as a
|
163
|
* query string.
|
164
|
*
|
165
|
* Returns:
|
166
|
* {<OpenLayers.Protocol.Response>} A response object, whose "priv" property
|
167
|
* references the injected script. This object is also passed to the
|
168
|
* callback function when the request completes, its "features" property
|
169
|
* is then populated with the features received from the server.
|
170
|
*/
|
171
|
read: function(options) {
|
172
|
OpenLayers.Protocol.prototype.read.apply(this, arguments);
|
173
|
options = OpenLayers.Util.applyDefaults(options, this.options);
|
174
|
options.params = OpenLayers.Util.applyDefaults(
|
175
|
options.params, this.options.params
|
176
|
);
|
177
|
if (options.filter && this.filterToParams) {
|
178
|
options.params = this.filterToParams(
|
179
|
options.filter, options.params
|
180
|
);
|
181
|
}
|
182
|
var response = new OpenLayers.Protocol.Response({requestType: "read"});
|
183
|
var request = this.createRequest(
|
184
|
options.url,
|
185
|
options.params,
|
186
|
OpenLayers.Function.bind(function(data) {
|
187
|
response.data = data;
|
188
|
this.handleRead(response, options);
|
189
|
}, this)
|
190
|
);
|
191
|
response.priv = request;
|
192
|
return response;
|
193
|
},
|
194
|
|
195
|
/**
|
196
|
* APIMethod: filterToParams
|
197
|
* Optional method to translate an <OpenLayers.Filter> object into an object
|
198
|
* that can be serialized as request query string provided. If a custom
|
199
|
* method is not provided, any filter will not be serialized.
|
200
|
*
|
201
|
* Parameters:
|
202
|
* filter - {<OpenLayers.Filter>} filter to convert.
|
203
|
* params - {Object} The parameters object.
|
204
|
*
|
205
|
* Returns:
|
206
|
* {Object} The resulting parameters object.
|
207
|
*/
|
208
|
|
209
|
/**
|
210
|
* Method: createRequest
|
211
|
* Issues a request for features by creating injecting a script in the
|
212
|
* document head.
|
213
|
*
|
214
|
* Parameters:
|
215
|
* url - {String} Service URL.
|
216
|
* params - {Object} Query string parameters.
|
217
|
* callback - {Function} Callback to be called with resulting data.
|
218
|
*
|
219
|
* Returns:
|
220
|
* {HTMLScriptElement} The script pending execution.
|
221
|
*/
|
222
|
createRequest: function(url, params, callback) {
|
223
|
var id = OpenLayers.Protocol.Script.register(callback);
|
224
|
var name = OpenLayers.String.format(this.callbackTemplate, {id: id});
|
225
|
params = OpenLayers.Util.extend({}, params);
|
226
|
params[this.callbackKey] = this.callbackPrefix + name;
|
227
|
url = OpenLayers.Util.urlAppend(
|
228
|
url, OpenLayers.Util.getParameterString(params)
|
229
|
);
|
230
|
var script = document.createElement("script");
|
231
|
script.type = "text/javascript";
|
232
|
script.src = url;
|
233
|
script.id = "OpenLayers_Protocol_Script_" + id;
|
234
|
this.pendingRequests[script.id] = script;
|
235
|
var head = document.getElementsByTagName("head")[0];
|
236
|
head.appendChild(script);
|
237
|
return script;
|
238
|
},
|
239
|
|
240
|
/**
|
241
|
* Method: destroyRequest
|
242
|
* Remove a script node associated with a response from the document. Also
|
243
|
* unregisters the callback and removes the script from the
|
244
|
* <pendingRequests> object.
|
245
|
*
|
246
|
* Parameters:
|
247
|
* script - {HTMLScriptElement}
|
248
|
*/
|
249
|
destroyRequest: function(script) {
|
250
|
OpenLayers.Protocol.Script.unregister(script.id.split("_").pop());
|
251
|
delete this.pendingRequests[script.id];
|
252
|
if (script.parentNode) {
|
253
|
script.parentNode.removeChild(script);
|
254
|
}
|
255
|
},
|
256
|
|
257
|
/**
|
258
|
* Method: handleRead
|
259
|
* Individual callbacks are created for read, create and update, should
|
260
|
* a subclass need to override each one separately.
|
261
|
*
|
262
|
* Parameters:
|
263
|
* response - {<OpenLayers.Protocol.Response>} The response object to pass to
|
264
|
* the user callback.
|
265
|
* options - {Object} The user options passed to the read call.
|
266
|
*/
|
267
|
handleRead: function(response, options) {
|
268
|
this.handleResponse(response, options);
|
269
|
},
|
270
|
|
271
|
/**
|
272
|
* Method: handleResponse
|
273
|
* Called by CRUD specific handlers.
|
274
|
*
|
275
|
* Parameters:
|
276
|
* response - {<OpenLayers.Protocol.Response>} The response object to pass to
|
277
|
* any user callback.
|
278
|
* options - {Object} The user options passed to the create, read, update,
|
279
|
* or delete call.
|
280
|
*/
|
281
|
handleResponse: function(response, options) {
|
282
|
if (options.callback) {
|
283
|
if (response.data) {
|
284
|
response.features = this.parseFeatures(response.data);
|
285
|
response.code = OpenLayers.Protocol.Response.SUCCESS;
|
286
|
} else {
|
287
|
response.code = OpenLayers.Protocol.Response.FAILURE;
|
288
|
}
|
289
|
this.destroyRequest(response.priv);
|
290
|
options.callback.call(options.scope, response);
|
291
|
}
|
292
|
},
|
293
|
|
294
|
/**
|
295
|
* Method: parseFeatures
|
296
|
* Read Script response body and return features.
|
297
|
*
|
298
|
* Parameters:
|
299
|
* data - {Object} The data sent to the callback function by the server.
|
300
|
*
|
301
|
* Returns:
|
302
|
* {Array({<OpenLayers.Feature.Vector>})} or
|
303
|
* {<OpenLayers.Feature.Vector>} Array of features or a single feature.
|
304
|
*/
|
305
|
parseFeatures: function(data) {
|
306
|
return this.format.read(data);
|
307
|
},
|
308
|
|
309
|
/**
|
310
|
* APIMethod: abort
|
311
|
* Abort an ongoing request. If no response is provided, all pending
|
312
|
* requests will be aborted.
|
313
|
*
|
314
|
* Parameters:
|
315
|
* response - {<OpenLayers.Protocol.Response>} The response object returned
|
316
|
* from a <read> request.
|
317
|
*/
|
318
|
abort: function(response) {
|
319
|
if (response) {
|
320
|
this.destroyRequest(response.priv);
|
321
|
} else {
|
322
|
for (var key in this.pendingRequests) {
|
323
|
this.destroyRequest(this.pendingRequests[key]);
|
324
|
}
|
325
|
}
|
326
|
},
|
327
|
|
328
|
/**
|
329
|
* APIMethod: destroy
|
330
|
* Clean up the protocol.
|
331
|
*/
|
332
|
destroy: function() {
|
333
|
this.abort();
|
334
|
delete this.params;
|
335
|
delete this.format;
|
336
|
OpenLayers.Protocol.prototype.destroy.apply(this);
|
337
|
},
|
338
|
|
339
|
CLASS_NAME: "OpenLayers.Protocol.Script"
|
340
|
});
|
341
|
|
342
|
(function() {
|
343
|
var o = OpenLayers.Protocol.Script;
|
344
|
var counter = 0;
|
345
|
o.registry = {};
|
346
|
|
347
|
/**
|
348
|
* Function: OpenLayers.Protocol.Script.register
|
349
|
* Register a callback for a newly created script.
|
350
|
*
|
351
|
* Parameters:
|
352
|
* callback - {Function} The callback to be executed when the newly added
|
353
|
* script loads. This callback will be called with a single argument
|
354
|
* that is the JSON returned by the service.
|
355
|
*
|
356
|
* Returns:
|
357
|
* {Number} An identifier for retrieving the registered callback.
|
358
|
*/
|
359
|
o.register = function(callback) {
|
360
|
var id = "c"+(++counter);
|
361
|
o.registry[id] = function() {
|
362
|
callback.apply(this, arguments);
|
363
|
};
|
364
|
return id;
|
365
|
};
|
366
|
|
367
|
/**
|
368
|
* Function: OpenLayers.Protocol.Script.unregister
|
369
|
* Unregister a callback previously registered with the register function.
|
370
|
*
|
371
|
* Parameters:
|
372
|
* id - {Number} The identifer returned by the register function.
|
373
|
*/
|
374
|
o.unregister = function(id) {
|
375
|
delete o.registry[id];
|
376
|
};
|
377
|
})();
|