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/SingleFile.js
|
8
|
*/
|
9
|
|
10
|
/**
|
11
|
* Header: OpenLayers Base Types
|
12
|
* OpenLayers custom string, number and function functions are described here.
|
13
|
*/
|
14
|
|
15
|
/**
|
16
|
* Namespace: OpenLayers.String
|
17
|
* Contains convenience functions for string manipulation.
|
18
|
*/
|
19
|
OpenLayers.String = {
|
20
|
|
21
|
/**
|
22
|
* APIFunction: startsWith
|
23
|
* Test whether a string starts with another string.
|
24
|
*
|
25
|
* Parameters:
|
26
|
* str - {String} The string to test.
|
27
|
* sub - {String} The substring to look for.
|
28
|
*
|
29
|
* Returns:
|
30
|
* {Boolean} The first string starts with the second.
|
31
|
*/
|
32
|
startsWith: function(str, sub) {
|
33
|
return (str.indexOf(sub) == 0);
|
34
|
},
|
35
|
|
36
|
/**
|
37
|
* APIFunction: contains
|
38
|
* Test whether a string contains another string.
|
39
|
*
|
40
|
* Parameters:
|
41
|
* str - {String} The string to test.
|
42
|
* sub - {String} The substring to look for.
|
43
|
*
|
44
|
* Returns:
|
45
|
* {Boolean} The first string contains the second.
|
46
|
*/
|
47
|
contains: function(str, sub) {
|
48
|
return (str.indexOf(sub) != -1);
|
49
|
},
|
50
|
|
51
|
/**
|
52
|
* APIFunction: trim
|
53
|
* Removes leading and trailing whitespace characters from a string.
|
54
|
*
|
55
|
* Parameters:
|
56
|
* str - {String} The (potentially) space padded string. This string is not
|
57
|
* modified.
|
58
|
*
|
59
|
* Returns:
|
60
|
* {String} A trimmed version of the string with all leading and
|
61
|
* trailing spaces removed.
|
62
|
*/
|
63
|
trim: function(str) {
|
64
|
return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
|
65
|
},
|
66
|
|
67
|
/**
|
68
|
* APIFunction: camelize
|
69
|
* Camel-case a hyphenated string.
|
70
|
* Ex. "chicken-head" becomes "chickenHead", and
|
71
|
* "-chicken-head" becomes "ChickenHead".
|
72
|
*
|
73
|
* Parameters:
|
74
|
* str - {String} The string to be camelized. The original is not modified.
|
75
|
*
|
76
|
* Returns:
|
77
|
* {String} The string, camelized
|
78
|
*/
|
79
|
camelize: function(str) {
|
80
|
var oStringList = str.split('-');
|
81
|
var camelizedString = oStringList[0];
|
82
|
for (var i=1, len=oStringList.length; i<len; i++) {
|
83
|
var s = oStringList[i];
|
84
|
camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
|
85
|
}
|
86
|
return camelizedString;
|
87
|
},
|
88
|
|
89
|
/**
|
90
|
* APIFunction: format
|
91
|
* Given a string with tokens in the form ${token}, return a string
|
92
|
* with tokens replaced with properties from the given context
|
93
|
* object. Represent a literal "${" by doubling it, e.g. "${${".
|
94
|
*
|
95
|
* Parameters:
|
96
|
* template - {String} A string with tokens to be replaced. A template
|
97
|
* has the form "literal ${token}" where the token will be replaced
|
98
|
* by the value of context["token"].
|
99
|
* context - {Object} An optional object with properties corresponding
|
100
|
* to the tokens in the format string. If no context is sent, the
|
101
|
* window object will be used.
|
102
|
* args - {Array} Optional arguments to pass to any functions found in
|
103
|
* the context. If a context property is a function, the token
|
104
|
* will be replaced by the return from the function called with
|
105
|
* these arguments.
|
106
|
*
|
107
|
* Returns:
|
108
|
* {String} A string with tokens replaced from the context object.
|
109
|
*/
|
110
|
format: function(template, context, args) {
|
111
|
if(!context) {
|
112
|
context = window;
|
113
|
}
|
114
|
|
115
|
// Example matching:
|
116
|
// str = ${foo.bar}
|
117
|
// match = foo.bar
|
118
|
var replacer = function(str, match) {
|
119
|
var replacement;
|
120
|
|
121
|
// Loop through all subs. Example: ${a.b.c}
|
122
|
// 0 -> replacement = context[a];
|
123
|
// 1 -> replacement = context[a][b];
|
124
|
// 2 -> replacement = context[a][b][c];
|
125
|
var subs = match.split(/\.+/);
|
126
|
for (var i=0; i< subs.length; i++) {
|
127
|
if (i == 0) {
|
128
|
replacement = context;
|
129
|
}
|
130
|
if (replacement === undefined) {
|
131
|
break;
|
132
|
}
|
133
|
replacement = replacement[subs[i]];
|
134
|
}
|
135
|
|
136
|
if(typeof replacement == "function") {
|
137
|
replacement = args ?
|
138
|
replacement.apply(null, args) :
|
139
|
replacement();
|
140
|
}
|
141
|
|
142
|
// If replacement is undefined, return the string 'undefined'.
|
143
|
// This is a workaround for a bugs in browsers not properly
|
144
|
// dealing with non-participating groups in regular expressions:
|
145
|
// http://blog.stevenlevithan.com/archives/npcg-javascript
|
146
|
if (typeof replacement == 'undefined') {
|
147
|
return 'undefined';
|
148
|
} else {
|
149
|
return replacement;
|
150
|
}
|
151
|
};
|
152
|
|
153
|
return template.replace(OpenLayers.String.tokenRegEx, replacer);
|
154
|
},
|
155
|
|
156
|
/**
|
157
|
* Property: tokenRegEx
|
158
|
* Used to find tokens in a string.
|
159
|
* Examples: ${a}, ${a.b.c}, ${a-b}, ${5}
|
160
|
*/
|
161
|
tokenRegEx: /\$\{([\w.]+?)\}/g,
|
162
|
|
163
|
/**
|
164
|
* Property: numberRegEx
|
165
|
* Used to test strings as numbers.
|
166
|
*/
|
167
|
numberRegEx: /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/,
|
168
|
|
169
|
/**
|
170
|
* APIFunction: isNumeric
|
171
|
* Determine whether a string contains only a numeric value.
|
172
|
*
|
173
|
* Examples:
|
174
|
* (code)
|
175
|
* OpenLayers.String.isNumeric("6.02e23") // true
|
176
|
* OpenLayers.String.isNumeric("12 dozen") // false
|
177
|
* OpenLayers.String.isNumeric("4") // true
|
178
|
* OpenLayers.String.isNumeric(" 4 ") // false
|
179
|
* (end)
|
180
|
*
|
181
|
* Returns:
|
182
|
* {Boolean} String contains only a number.
|
183
|
*/
|
184
|
isNumeric: function(value) {
|
185
|
return OpenLayers.String.numberRegEx.test(value);
|
186
|
},
|
187
|
|
188
|
/**
|
189
|
* APIFunction: numericIf
|
190
|
* Converts a string that appears to be a numeric value into a number.
|
191
|
*
|
192
|
* Parameters:
|
193
|
* value - {String}
|
194
|
* trimWhitespace - {Boolean}
|
195
|
*
|
196
|
* Returns:
|
197
|
* {Number|String} a Number if the passed value is a number, a String
|
198
|
* otherwise.
|
199
|
*/
|
200
|
numericIf: function(value, trimWhitespace) {
|
201
|
var originalValue = value;
|
202
|
if (trimWhitespace === true && value != null && value.replace) {
|
203
|
value = value.replace(/^\s*|\s*$/g, "");
|
204
|
}
|
205
|
return OpenLayers.String.isNumeric(value) ? parseFloat(value) : originalValue;
|
206
|
}
|
207
|
|
208
|
};
|
209
|
|
210
|
/**
|
211
|
* Namespace: OpenLayers.Number
|
212
|
* Contains convenience functions for manipulating numbers.
|
213
|
*/
|
214
|
OpenLayers.Number = {
|
215
|
|
216
|
/**
|
217
|
* Property: decimalSeparator
|
218
|
* Decimal separator to use when formatting numbers.
|
219
|
*/
|
220
|
decimalSeparator: ".",
|
221
|
|
222
|
/**
|
223
|
* Property: thousandsSeparator
|
224
|
* Thousands separator to use when formatting numbers.
|
225
|
*/
|
226
|
thousandsSeparator: ",",
|
227
|
|
228
|
/**
|
229
|
* APIFunction: limitSigDigs
|
230
|
* Limit the number of significant digits on a float.
|
231
|
*
|
232
|
* Parameters:
|
233
|
* num - {Float}
|
234
|
* sig - {Integer}
|
235
|
*
|
236
|
* Returns:
|
237
|
* {Float} The number, rounded to the specified number of significant
|
238
|
* digits.
|
239
|
*/
|
240
|
limitSigDigs: function(num, sig) {
|
241
|
var fig = 0;
|
242
|
if (sig > 0) {
|
243
|
fig = parseFloat(num.toPrecision(sig));
|
244
|
}
|
245
|
return fig;
|
246
|
},
|
247
|
|
248
|
/**
|
249
|
* APIFunction: format
|
250
|
* Formats a number for output.
|
251
|
*
|
252
|
* Parameters:
|
253
|
* num - {Float}
|
254
|
* dec - {Integer} Number of decimal places to round to.
|
255
|
* Defaults to 0. Set to null to leave decimal places unchanged.
|
256
|
* tsep - {String} Thousands separator.
|
257
|
* Default is ",".
|
258
|
* dsep - {String} Decimal separator.
|
259
|
* Default is ".".
|
260
|
*
|
261
|
* Returns:
|
262
|
* {String} A string representing the formatted number.
|
263
|
*/
|
264
|
format: function(num, dec, tsep, dsep) {
|
265
|
dec = (typeof dec != "undefined") ? dec : 0;
|
266
|
tsep = (typeof tsep != "undefined") ? tsep :
|
267
|
OpenLayers.Number.thousandsSeparator;
|
268
|
dsep = (typeof dsep != "undefined") ? dsep :
|
269
|
OpenLayers.Number.decimalSeparator;
|
270
|
|
271
|
if (dec != null) {
|
272
|
num = parseFloat(num.toFixed(dec));
|
273
|
}
|
274
|
|
275
|
var parts = num.toString().split(".");
|
276
|
if (parts.length == 1 && dec == null) {
|
277
|
// integer where we do not want to touch the decimals
|
278
|
dec = 0;
|
279
|
}
|
280
|
|
281
|
var integer = parts[0];
|
282
|
if (tsep) {
|
283
|
var thousands = /(-?[0-9]+)([0-9]{3})/;
|
284
|
while(thousands.test(integer)) {
|
285
|
integer = integer.replace(thousands, "$1" + tsep + "$2");
|
286
|
}
|
287
|
}
|
288
|
|
289
|
var str;
|
290
|
if (dec == 0) {
|
291
|
str = integer;
|
292
|
} else {
|
293
|
var rem = parts.length > 1 ? parts[1] : "0";
|
294
|
if (dec != null) {
|
295
|
rem = rem + new Array(dec - rem.length + 1).join("0");
|
296
|
}
|
297
|
str = integer + dsep + rem;
|
298
|
}
|
299
|
return str;
|
300
|
},
|
301
|
|
302
|
/**
|
303
|
* Method: zeroPad
|
304
|
* Create a zero padded string optionally with a radix for casting numbers.
|
305
|
*
|
306
|
* Parameters:
|
307
|
* num - {Number} The number to be zero padded.
|
308
|
* len - {Number} The length of the string to be returned.
|
309
|
* radix - {Number} An integer between 2 and 36 specifying the base to use
|
310
|
* for representing numeric values.
|
311
|
*/
|
312
|
zeroPad: function(num, len, radix) {
|
313
|
var str = num.toString(radix || 10);
|
314
|
while (str.length < len) {
|
315
|
str = "0" + str;
|
316
|
}
|
317
|
return str;
|
318
|
}
|
319
|
};
|
320
|
|
321
|
/**
|
322
|
* Namespace: OpenLayers.Function
|
323
|
* Contains convenience functions for function manipulation.
|
324
|
*/
|
325
|
OpenLayers.Function = {
|
326
|
/**
|
327
|
* APIFunction: bind
|
328
|
* Bind a function to an object. Method to easily create closures with
|
329
|
* 'this' altered.
|
330
|
*
|
331
|
* Parameters:
|
332
|
* func - {Function} Input function.
|
333
|
* object - {Object} The object to bind to the input function (as this).
|
334
|
*
|
335
|
* Returns:
|
336
|
* {Function} A closure with 'this' set to the passed in object.
|
337
|
*/
|
338
|
bind: function(func, object) {
|
339
|
// create a reference to all arguments past the second one
|
340
|
var args = Array.prototype.slice.apply(arguments, [2]);
|
341
|
return function() {
|
342
|
// Push on any additional arguments from the actual function call.
|
343
|
// These will come after those sent to the bind call.
|
344
|
var newArgs = args.concat(
|
345
|
Array.prototype.slice.apply(arguments, [0])
|
346
|
);
|
347
|
return func.apply(object, newArgs);
|
348
|
};
|
349
|
},
|
350
|
|
351
|
/**
|
352
|
* APIFunction: bindAsEventListener
|
353
|
* Bind a function to an object, and configure it to receive the event
|
354
|
* object as first parameter when called.
|
355
|
*
|
356
|
* Parameters:
|
357
|
* func - {Function} Input function to serve as an event listener.
|
358
|
* object - {Object} A reference to this.
|
359
|
*
|
360
|
* Returns:
|
361
|
* {Function}
|
362
|
*/
|
363
|
bindAsEventListener: function(func, object) {
|
364
|
return function(event) {
|
365
|
return func.call(object, event || window.event);
|
366
|
};
|
367
|
},
|
368
|
|
369
|
/**
|
370
|
* APIFunction: False
|
371
|
* A simple function to that just does "return false". We use this to
|
372
|
* avoid attaching anonymous functions to DOM event handlers, which
|
373
|
* causes "issues" on IE<8.
|
374
|
*
|
375
|
* Usage:
|
376
|
* document.onclick = OpenLayers.Function.False;
|
377
|
*
|
378
|
* Returns:
|
379
|
* {Boolean}
|
380
|
*/
|
381
|
False : function() {
|
382
|
return false;
|
383
|
},
|
384
|
|
385
|
/**
|
386
|
* APIFunction: True
|
387
|
* A simple function to that just does "return true". We use this to
|
388
|
* avoid attaching anonymous functions to DOM event handlers, which
|
389
|
* causes "issues" on IE<8.
|
390
|
*
|
391
|
* Usage:
|
392
|
* document.onclick = OpenLayers.Function.True;
|
393
|
*
|
394
|
* Returns:
|
395
|
* {Boolean}
|
396
|
*/
|
397
|
True : function() {
|
398
|
return true;
|
399
|
},
|
400
|
|
401
|
/**
|
402
|
* APIFunction: Void
|
403
|
* A reusable function that returns ``undefined``.
|
404
|
*
|
405
|
* Returns:
|
406
|
* {undefined}
|
407
|
*/
|
408
|
Void: function() {}
|
409
|
|
410
|
};
|
411
|
|
412
|
/**
|
413
|
* Namespace: OpenLayers.Array
|
414
|
* Contains convenience functions for array manipulation.
|
415
|
*/
|
416
|
OpenLayers.Array = {
|
417
|
|
418
|
/**
|
419
|
* APIMethod: filter
|
420
|
* Filter an array. Provides the functionality of the
|
421
|
* Array.prototype.filter extension to the ECMA-262 standard. Where
|
422
|
* available, Array.prototype.filter will be used.
|
423
|
*
|
424
|
* Based on well known example from http://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Array/filter
|
425
|
*
|
426
|
* Parameters:
|
427
|
* array - {Array} The array to be filtered. This array is not mutated.
|
428
|
* Elements added to this array by the callback will not be visited.
|
429
|
* callback - {Function} A function that is called for each element in
|
430
|
* the array. If this function returns true, the element will be
|
431
|
* included in the return. The function will be called with three
|
432
|
* arguments: the element in the array, the index of that element, and
|
433
|
* the array itself. If the optional caller parameter is specified
|
434
|
* the callback will be called with this set to caller.
|
435
|
* caller - {Object} Optional object to be set as this when the callback
|
436
|
* is called.
|
437
|
*
|
438
|
* Returns:
|
439
|
* {Array} An array of elements from the passed in array for which the
|
440
|
* callback returns true.
|
441
|
*/
|
442
|
filter: function(array, callback, caller) {
|
443
|
var selected = [];
|
444
|
if (Array.prototype.filter) {
|
445
|
selected = array.filter(callback, caller);
|
446
|
} else {
|
447
|
var len = array.length;
|
448
|
if (typeof callback != "function") {
|
449
|
throw new TypeError();
|
450
|
}
|
451
|
for(var i=0; i<len; i++) {
|
452
|
if (i in array) {
|
453
|
var val = array[i];
|
454
|
if (callback.call(caller, val, i, array)) {
|
455
|
selected.push(val);
|
456
|
}
|
457
|
}
|
458
|
}
|
459
|
}
|
460
|
return selected;
|
461
|
}
|
462
|
|
463
|
};
|