[76] | 1 | /* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for |
---|
| 2 | * full list of contributors). Published under the Clear BSD license. |
---|
| 3 | * See http://svn.openlayers.org/trunk/openlayers/license.txt for the |
---|
| 4 | * full text of the license. */ |
---|
| 5 | |
---|
| 6 | /** |
---|
| 7 | * @requires OpenLayers/BaseTypes/Class.js |
---|
| 8 | * @requires OpenLayers/BaseTypes/LonLat.js |
---|
| 9 | * @requires OpenLayers/BaseTypes/Size.js |
---|
| 10 | * @requires OpenLayers/BaseTypes/Pixel.js |
---|
| 11 | * @requires OpenLayers/BaseTypes/Bounds.js |
---|
| 12 | * @requires OpenLayers/BaseTypes/Element.js |
---|
| 13 | * @requires OpenLayers/Lang/en.js |
---|
| 14 | * @requires OpenLayers/Console.js |
---|
| 15 | */ |
---|
| 16 | |
---|
| 17 | /** |
---|
| 18 | * Header: OpenLayers Base Types |
---|
| 19 | * OpenLayers custom string, number and function functions are described here. |
---|
| 20 | */ |
---|
| 21 | |
---|
| 22 | /** |
---|
| 23 | * Namespace: OpenLayers.String |
---|
| 24 | * Contains convenience functions for string manipulation. |
---|
| 25 | */ |
---|
| 26 | OpenLayers.String = { |
---|
| 27 | |
---|
| 28 | /** |
---|
| 29 | * APIFunction: startsWith |
---|
| 30 | * Test whether a string starts with another string. |
---|
| 31 | * |
---|
| 32 | * Parameters: |
---|
| 33 | * str - {String} The string to test. |
---|
| 34 | * sub - {Sring} The substring to look for. |
---|
| 35 | * |
---|
| 36 | * Returns: |
---|
| 37 | * {Boolean} The first string starts with the second. |
---|
| 38 | */ |
---|
| 39 | startsWith: function(str, sub) { |
---|
| 40 | return (str.indexOf(sub) == 0); |
---|
| 41 | }, |
---|
| 42 | |
---|
| 43 | /** |
---|
| 44 | * APIFunction: contains |
---|
| 45 | * Test whether a string contains another string. |
---|
| 46 | * |
---|
| 47 | * Parameters: |
---|
| 48 | * str - {String} The string to test. |
---|
| 49 | * sub - {String} The substring to look for. |
---|
| 50 | * |
---|
| 51 | * Returns: |
---|
| 52 | * {Boolean} The first string contains the second. |
---|
| 53 | */ |
---|
| 54 | contains: function(str, sub) { |
---|
| 55 | return (str.indexOf(sub) != -1); |
---|
| 56 | }, |
---|
| 57 | |
---|
| 58 | /** |
---|
| 59 | * APIFunction: trim |
---|
| 60 | * Removes leading and trailing whitespace characters from a string. |
---|
| 61 | * |
---|
| 62 | * Parameters: |
---|
| 63 | * str - {String} The (potentially) space padded string. This string is not |
---|
| 64 | * modified. |
---|
| 65 | * |
---|
| 66 | * Returns: |
---|
| 67 | * {String} A trimmed version of the string with all leading and |
---|
| 68 | * trailing spaces removed. |
---|
| 69 | */ |
---|
| 70 | trim: function(str) { |
---|
| 71 | return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); |
---|
| 72 | }, |
---|
| 73 | |
---|
| 74 | /** |
---|
| 75 | * APIFunction: camelize |
---|
| 76 | * Camel-case a hyphenated string. |
---|
| 77 | * Ex. "chicken-head" becomes "chickenHead", and |
---|
| 78 | * "-chicken-head" becomes "ChickenHead". |
---|
| 79 | * |
---|
| 80 | * Parameters: |
---|
| 81 | * str - {String} The string to be camelized. The original is not modified. |
---|
| 82 | * |
---|
| 83 | * Returns: |
---|
| 84 | * {String} The string, camelized |
---|
| 85 | */ |
---|
| 86 | camelize: function(str) { |
---|
| 87 | var oStringList = str.split('-'); |
---|
| 88 | var camelizedString = oStringList[0]; |
---|
| 89 | for (var i=1, len=oStringList.length; i<len; i++) { |
---|
| 90 | var s = oStringList[i]; |
---|
| 91 | camelizedString += s.charAt(0).toUpperCase() + s.substring(1); |
---|
| 92 | } |
---|
| 93 | return camelizedString; |
---|
| 94 | }, |
---|
| 95 | |
---|
| 96 | /** |
---|
| 97 | * APIFunction: format |
---|
| 98 | * Given a string with tokens in the form ${token}, return a string |
---|
| 99 | * with tokens replaced with properties from the given context |
---|
| 100 | * object. Represent a literal "${" by doubling it, e.g. "${${". |
---|
| 101 | * |
---|
| 102 | * Parameters: |
---|
| 103 | * template - {String} A string with tokens to be replaced. A template |
---|
| 104 | * has the form "literal ${token}" where the token will be replaced |
---|
| 105 | * by the value of context["token"]. |
---|
| 106 | * context - {Object} An optional object with properties corresponding |
---|
| 107 | * to the tokens in the format string. If no context is sent, the |
---|
| 108 | * window object will be used. |
---|
| 109 | * args - {Array} Optional arguments to pass to any functions found in |
---|
| 110 | * the context. If a context property is a function, the token |
---|
| 111 | * will be replaced by the return from the function called with |
---|
| 112 | * these arguments. |
---|
| 113 | * |
---|
| 114 | * Returns: |
---|
| 115 | * {String} A string with tokens replaced from the context object. |
---|
| 116 | */ |
---|
| 117 | format: function(template, context, args) { |
---|
| 118 | if(!context) { |
---|
| 119 | context = window; |
---|
| 120 | } |
---|
| 121 | |
---|
| 122 | // Example matching: |
---|
| 123 | // str = ${foo.bar} |
---|
| 124 | // match = foo.bar |
---|
| 125 | var replacer = function(str, match) { |
---|
| 126 | var replacement; |
---|
| 127 | |
---|
| 128 | // Loop through all subs. Example: ${a.b.c} |
---|
| 129 | // 0 -> replacement = context[a]; |
---|
| 130 | // 1 -> replacement = context[a][b]; |
---|
| 131 | // 2 -> replacement = context[a][b][c]; |
---|
| 132 | var subs = match.split(/\.+/); |
---|
| 133 | for (var i=0; i< subs.length; i++) { |
---|
| 134 | if (i == 0) { |
---|
| 135 | replacement = context; |
---|
| 136 | } |
---|
| 137 | |
---|
| 138 | replacement = replacement[subs[i]]; |
---|
| 139 | } |
---|
| 140 | |
---|
| 141 | if(typeof replacement == "function") { |
---|
| 142 | replacement = args ? |
---|
| 143 | replacement.apply(null, args) : |
---|
| 144 | replacement(); |
---|
| 145 | } |
---|
| 146 | |
---|
| 147 | // If replacement is undefined, return the string 'undefined'. |
---|
| 148 | // This is a workaround for a bugs in browsers not properly |
---|
| 149 | // dealing with non-participating groups in regular expressions: |
---|
| 150 | // http://blog.stevenlevithan.com/archives/npcg-javascript |
---|
| 151 | if (typeof replacement == 'undefined') { |
---|
| 152 | return 'undefined'; |
---|
| 153 | } else { |
---|
| 154 | return replacement; |
---|
| 155 | } |
---|
| 156 | }; |
---|
| 157 | |
---|
| 158 | return template.replace(OpenLayers.String.tokenRegEx, replacer); |
---|
| 159 | }, |
---|
| 160 | |
---|
| 161 | /** |
---|
| 162 | * Property: OpenLayers.String.tokenRegEx |
---|
| 163 | * Used to find tokens in a string. |
---|
| 164 | * Examples: ${a}, ${a.b.c}, ${a-b}, ${5} |
---|
| 165 | */ |
---|
| 166 | tokenRegEx: /\$\{([\w.]+?)\}/g, |
---|
| 167 | |
---|
| 168 | /** |
---|
| 169 | * Property: OpenLayers.String.numberRegEx |
---|
| 170 | * Used to test strings as numbers. |
---|
| 171 | */ |
---|
| 172 | numberRegEx: /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/, |
---|
| 173 | |
---|
| 174 | /** |
---|
| 175 | * APIFunction: OpenLayers.String.isNumeric |
---|
| 176 | * Determine whether a string contains only a numeric value. |
---|
| 177 | * |
---|
| 178 | * Examples: |
---|
| 179 | * (code) |
---|
| 180 | * OpenLayers.String.isNumeric("6.02e23") // true |
---|
| 181 | * OpenLayers.String.isNumeric("12 dozen") // false |
---|
| 182 | * OpenLayers.String.isNumeric("4") // true |
---|
| 183 | * OpenLayers.String.isNumeric(" 4 ") // false |
---|
| 184 | * (end) |
---|
| 185 | * |
---|
| 186 | * Returns: |
---|
| 187 | * {Boolean} String contains only a number. |
---|
| 188 | */ |
---|
| 189 | isNumeric: function(value) { |
---|
| 190 | return OpenLayers.String.numberRegEx.test(value); |
---|
| 191 | }, |
---|
| 192 | |
---|
| 193 | /** |
---|
| 194 | * APIFunction: numericIf |
---|
| 195 | * Converts a string that appears to be a numeric value into a number. |
---|
| 196 | * |
---|
| 197 | * Returns |
---|
| 198 | * {Number|String} a Number if the passed value is a number, a String |
---|
| 199 | * otherwise. |
---|
| 200 | */ |
---|
| 201 | numericIf: function(value) { |
---|
| 202 | return OpenLayers.String.isNumeric(value) ? parseFloat(value) : value; |
---|
| 203 | } |
---|
| 204 | |
---|
| 205 | }; |
---|
| 206 | |
---|
| 207 | if (!String.prototype.startsWith) { |
---|
| 208 | /** |
---|
| 209 | * APIMethod: String.startsWith |
---|
| 210 | * *Deprecated*. Whether or not a string starts with another string. |
---|
| 211 | * |
---|
| 212 | * Parameters: |
---|
| 213 | * sStart - {Sring} The string we're testing for. |
---|
| 214 | * |
---|
| 215 | * Returns: |
---|
| 216 | * {Boolean} Whether or not this string starts with the string passed in. |
---|
| 217 | */ |
---|
| 218 | String.prototype.startsWith = function(sStart) { |
---|
| 219 | OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated", |
---|
| 220 | {'newMethod':'OpenLayers.String.startsWith'})); |
---|
| 221 | return OpenLayers.String.startsWith(this, sStart); |
---|
| 222 | }; |
---|
| 223 | } |
---|
| 224 | |
---|
| 225 | if (!String.prototype.contains) { |
---|
| 226 | /** |
---|
| 227 | * APIMethod: String.contains |
---|
| 228 | * *Deprecated*. Whether or not a string contains another string. |
---|
| 229 | * |
---|
| 230 | * Parameters: |
---|
| 231 | * str - {String} The string that we're testing for. |
---|
| 232 | * |
---|
| 233 | * Returns: |
---|
| 234 | * {Boolean} Whether or not this string contains with the string passed in. |
---|
| 235 | */ |
---|
| 236 | String.prototype.contains = function(str) { |
---|
| 237 | OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated", |
---|
| 238 | {'newMethod':'OpenLayers.String.contains'})); |
---|
| 239 | return OpenLayers.String.contains(this, str); |
---|
| 240 | }; |
---|
| 241 | } |
---|
| 242 | |
---|
| 243 | if (!String.prototype.trim) { |
---|
| 244 | /** |
---|
| 245 | * APIMethod: String.trim |
---|
| 246 | * *Deprecated*. Removes leading and trailing whitespace characters from a string. |
---|
| 247 | * |
---|
| 248 | * Returns: |
---|
| 249 | * {String} A trimmed version of the string - all leading and |
---|
| 250 | * trailing spaces removed |
---|
| 251 | */ |
---|
| 252 | String.prototype.trim = function() { |
---|
| 253 | OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated", |
---|
| 254 | {'newMethod':'OpenLayers.String.trim'})); |
---|
| 255 | return OpenLayers.String.trim(this); |
---|
| 256 | }; |
---|
| 257 | } |
---|
| 258 | |
---|
| 259 | if (!String.prototype.camelize) { |
---|
| 260 | /** |
---|
| 261 | * APIMethod: String.camelize |
---|
| 262 | * *Deprecated*. Camel-case a hyphenated string. |
---|
| 263 | * Ex. "chicken-head" becomes "chickenHead", and |
---|
| 264 | * "-chicken-head" becomes "ChickenHead". |
---|
| 265 | * |
---|
| 266 | * Returns: |
---|
| 267 | * {String} The string, camelized |
---|
| 268 | */ |
---|
| 269 | String.prototype.camelize = function() { |
---|
| 270 | OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated", |
---|
| 271 | {'newMethod':'OpenLayers.String.camelize'})); |
---|
| 272 | return OpenLayers.String.camelize(this); |
---|
| 273 | }; |
---|
| 274 | } |
---|
| 275 | |
---|
| 276 | /** |
---|
| 277 | * Namespace: OpenLayers.Number |
---|
| 278 | * Contains convenience functions for manipulating numbers. |
---|
| 279 | */ |
---|
| 280 | OpenLayers.Number = { |
---|
| 281 | |
---|
| 282 | /** |
---|
| 283 | * Property: decimalSeparator |
---|
| 284 | * Decimal separator to use when formatting numbers. |
---|
| 285 | */ |
---|
| 286 | decimalSeparator: ".", |
---|
| 287 | |
---|
| 288 | /** |
---|
| 289 | * Property: thousandsSeparator |
---|
| 290 | * Thousands separator to use when formatting numbers. |
---|
| 291 | */ |
---|
| 292 | thousandsSeparator: ",", |
---|
| 293 | |
---|
| 294 | /** |
---|
| 295 | * APIFunction: limitSigDigs |
---|
| 296 | * Limit the number of significant digits on a float. |
---|
| 297 | * |
---|
| 298 | * Parameters: |
---|
| 299 | * num - {Float} |
---|
| 300 | * sig - {Integer} |
---|
| 301 | * |
---|
| 302 | * Returns: |
---|
| 303 | * {Float} The number, rounded to the specified number of significant |
---|
| 304 | * digits. |
---|
| 305 | */ |
---|
| 306 | limitSigDigs: function(num, sig) { |
---|
| 307 | var fig = 0; |
---|
| 308 | if (sig > 0) { |
---|
| 309 | fig = parseFloat(num.toPrecision(sig)); |
---|
| 310 | } |
---|
| 311 | return fig; |
---|
| 312 | }, |
---|
| 313 | |
---|
| 314 | /** |
---|
| 315 | * APIFunction: format |
---|
| 316 | * Formats a number for output. |
---|
| 317 | * |
---|
| 318 | * Parameters: |
---|
| 319 | * num - {Float} |
---|
| 320 | * dec - {Integer} Number of decimal places to round to. |
---|
| 321 | * Defaults to 0. Set to null to leave decimal places unchanged. |
---|
| 322 | * tsep - {String} Thousands separator. |
---|
| 323 | * Default is ",". |
---|
| 324 | * dsep - {String} Decimal separator. |
---|
| 325 | * Default is ".". |
---|
| 326 | * |
---|
| 327 | * Returns: |
---|
| 328 | * {String} A string representing the formatted number. |
---|
| 329 | */ |
---|
| 330 | format: function(num, dec, tsep, dsep) { |
---|
| 331 | dec = (typeof dec != "undefined") ? dec : 0; |
---|
| 332 | tsep = (typeof tsep != "undefined") ? tsep : |
---|
| 333 | OpenLayers.Number.thousandsSeparator; |
---|
| 334 | dsep = (typeof dsep != "undefined") ? dsep : |
---|
| 335 | OpenLayers.Number.decimalSeparator; |
---|
| 336 | |
---|
| 337 | if (dec != null) { |
---|
| 338 | num = parseFloat(num.toFixed(dec)); |
---|
| 339 | } |
---|
| 340 | |
---|
| 341 | var parts = num.toString().split("."); |
---|
| 342 | if (parts.length == 1 && dec == null) { |
---|
| 343 | // integer where we do not want to touch the decimals |
---|
| 344 | dec = 0; |
---|
| 345 | } |
---|
| 346 | |
---|
| 347 | var integer = parts[0]; |
---|
| 348 | if (tsep) { |
---|
| 349 | var thousands = /(-?[0-9]+)([0-9]{3})/; |
---|
| 350 | while(thousands.test(integer)) { |
---|
| 351 | integer = integer.replace(thousands, "$1" + tsep + "$2"); |
---|
| 352 | } |
---|
| 353 | } |
---|
| 354 | |
---|
| 355 | var str; |
---|
| 356 | if (dec == 0) { |
---|
| 357 | str = integer; |
---|
| 358 | } else { |
---|
| 359 | var rem = parts.length > 1 ? parts[1] : "0"; |
---|
| 360 | if (dec != null) { |
---|
| 361 | rem = rem + new Array(dec - rem.length + 1).join("0"); |
---|
| 362 | } |
---|
| 363 | str = integer + dsep + rem; |
---|
| 364 | } |
---|
| 365 | return str; |
---|
| 366 | } |
---|
| 367 | }; |
---|
| 368 | |
---|
| 369 | if (!Number.prototype.limitSigDigs) { |
---|
| 370 | /** |
---|
| 371 | * APIMethod: Number.limitSigDigs |
---|
| 372 | * *Deprecated*. Limit the number of significant digits on an integer. Does *not* |
---|
| 373 | * work with floats! |
---|
| 374 | * |
---|
| 375 | * Parameters: |
---|
| 376 | * sig - {Integer} |
---|
| 377 | * |
---|
| 378 | * Returns: |
---|
| 379 | * {Integer} The number, rounded to the specified number of significant digits. |
---|
| 380 | * If null, 0, or negative value passed in, returns 0 |
---|
| 381 | */ |
---|
| 382 | Number.prototype.limitSigDigs = function(sig) { |
---|
| 383 | OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated", |
---|
| 384 | {'newMethod':'OpenLayers.Number.limitSigDigs'})); |
---|
| 385 | return OpenLayers.Number.limitSigDigs(this, sig); |
---|
| 386 | }; |
---|
| 387 | } |
---|
| 388 | |
---|
| 389 | /** |
---|
| 390 | * Namespace: OpenLayers.Function |
---|
| 391 | * Contains convenience functions for function manipulation. |
---|
| 392 | */ |
---|
| 393 | OpenLayers.Function = { |
---|
| 394 | /** |
---|
| 395 | * APIFunction: bind |
---|
| 396 | * Bind a function to an object. Method to easily create closures with |
---|
| 397 | * 'this' altered. |
---|
| 398 | * |
---|
| 399 | * Parameters: |
---|
| 400 | * func - {Function} Input function. |
---|
| 401 | * object - {Object} The object to bind to the input function (as this). |
---|
| 402 | * |
---|
| 403 | * Returns: |
---|
| 404 | * {Function} A closure with 'this' set to the passed in object. |
---|
| 405 | */ |
---|
| 406 | bind: function(func, object) { |
---|
| 407 | // create a reference to all arguments past the second one |
---|
| 408 | var args = Array.prototype.slice.apply(arguments, [2]); |
---|
| 409 | return function() { |
---|
| 410 | // Push on any additional arguments from the actual function call. |
---|
| 411 | // These will come after those sent to the bind call. |
---|
| 412 | var newArgs = args.concat( |
---|
| 413 | Array.prototype.slice.apply(arguments, [0]) |
---|
| 414 | ); |
---|
| 415 | return func.apply(object, newArgs); |
---|
| 416 | }; |
---|
| 417 | }, |
---|
| 418 | |
---|
| 419 | /** |
---|
| 420 | * APIFunction: bindAsEventListener |
---|
| 421 | * Bind a function to an object, and configure it to receive the event |
---|
| 422 | * object as first parameter when called. |
---|
| 423 | * |
---|
| 424 | * Parameters: |
---|
| 425 | * func - {Function} Input function to serve as an event listener. |
---|
| 426 | * object - {Object} A reference to this. |
---|
| 427 | * |
---|
| 428 | * Returns: |
---|
| 429 | * {Function} |
---|
| 430 | */ |
---|
| 431 | bindAsEventListener: function(func, object) { |
---|
| 432 | return function(event) { |
---|
| 433 | return func.call(object, event || window.event); |
---|
| 434 | }; |
---|
| 435 | }, |
---|
| 436 | |
---|
| 437 | /** |
---|
| 438 | * APIFunction: False |
---|
| 439 | * A simple function to that just does "return false". We use this to |
---|
| 440 | * avoid attaching anonymous functions to DOM event handlers, which |
---|
| 441 | * causes "issues" on IE<8. |
---|
| 442 | * |
---|
| 443 | * Usage: |
---|
| 444 | * document.onclick = OpenLayers.Function.False; |
---|
| 445 | * |
---|
| 446 | * Returns: |
---|
| 447 | * {Boolean} |
---|
| 448 | */ |
---|
| 449 | False : function() { |
---|
| 450 | return false; |
---|
| 451 | }, |
---|
| 452 | |
---|
| 453 | /** |
---|
| 454 | * APIFunction: True |
---|
| 455 | * A simple function to that just does "return true". We use this to |
---|
| 456 | * avoid attaching anonymous functions to DOM event handlers, which |
---|
| 457 | * causes "issues" on IE<8. |
---|
| 458 | * |
---|
| 459 | * Usage: |
---|
| 460 | * document.onclick = OpenLayers.Function.True; |
---|
| 461 | * |
---|
| 462 | * Returns: |
---|
| 463 | * {Boolean} |
---|
| 464 | */ |
---|
| 465 | True : function() { |
---|
| 466 | return true; |
---|
| 467 | } |
---|
| 468 | }; |
---|
| 469 | |
---|
| 470 | if (!Function.prototype.bind) { |
---|
| 471 | /** |
---|
| 472 | * APIMethod: Function.bind |
---|
| 473 | * *Deprecated*. Bind a function to an object. |
---|
| 474 | * Method to easily create closures with 'this' altered. |
---|
| 475 | * |
---|
| 476 | * Parameters: |
---|
| 477 | * object - {Object} the this parameter |
---|
| 478 | * |
---|
| 479 | * Returns: |
---|
| 480 | * {Function} A closure with 'this' altered to the first |
---|
| 481 | * argument. |
---|
| 482 | */ |
---|
| 483 | Function.prototype.bind = function() { |
---|
| 484 | OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated", |
---|
| 485 | {'newMethod':'OpenLayers.Function.bind'})); |
---|
| 486 | // new function takes the same arguments with this function up front |
---|
| 487 | Array.prototype.unshift.apply(arguments, [this]); |
---|
| 488 | return OpenLayers.Function.bind.apply(null, arguments); |
---|
| 489 | }; |
---|
| 490 | } |
---|
| 491 | |
---|
| 492 | if (!Function.prototype.bindAsEventListener) { |
---|
| 493 | /** |
---|
| 494 | * APIMethod: Function.bindAsEventListener |
---|
| 495 | * *Deprecated*. Bind a function to an object, and configure it to receive the |
---|
| 496 | * event object as first parameter when called. |
---|
| 497 | * |
---|
| 498 | * Parameters: |
---|
| 499 | * object - {Object} A reference to this. |
---|
| 500 | * |
---|
| 501 | * Returns: |
---|
| 502 | * {Function} |
---|
| 503 | */ |
---|
| 504 | Function.prototype.bindAsEventListener = function(object) { |
---|
| 505 | OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated", |
---|
| 506 | {'newMethod':'OpenLayers.Function.bindAsEventListener'})); |
---|
| 507 | return OpenLayers.Function.bindAsEventListener(this, object); |
---|
| 508 | }; |
---|
| 509 | } |
---|
| 510 | |
---|
| 511 | /** |
---|
| 512 | * Namespace: OpenLayers.Array |
---|
| 513 | * Contains convenience functions for array manipulation. |
---|
| 514 | */ |
---|
| 515 | OpenLayers.Array = { |
---|
| 516 | |
---|
| 517 | /** |
---|
| 518 | * APIMethod: filter |
---|
| 519 | * Filter an array. Provides the functionality of the |
---|
| 520 | * Array.prototype.filter extension to the ECMA-262 standard. Where |
---|
| 521 | * available, Array.prototype.filter will be used. |
---|
| 522 | * |
---|
| 523 | * Based on well known example from http://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Array/filter |
---|
| 524 | * |
---|
| 525 | * Parameters: |
---|
| 526 | * array - {Array} The array to be filtered. This array is not mutated. |
---|
| 527 | * Elements added to this array by the callback will not be visited. |
---|
| 528 | * callback - {Function} A function that is called for each element in |
---|
| 529 | * the array. If this function returns true, the element will be |
---|
| 530 | * included in the return. The function will be called with three |
---|
| 531 | * arguments: the element in the array, the index of that element, and |
---|
| 532 | * the array itself. If the optional caller parameter is specified |
---|
| 533 | * the callback will be called with this set to caller. |
---|
| 534 | * caller - {Object} Optional object to be set as this when the callback |
---|
| 535 | * is called. |
---|
| 536 | * |
---|
| 537 | * Returns: |
---|
| 538 | * {Array} An array of elements from the passed in array for which the |
---|
| 539 | * callback returns true. |
---|
| 540 | */ |
---|
| 541 | filter: function(array, callback, caller) { |
---|
| 542 | var selected = []; |
---|
| 543 | if (Array.prototype.filter) { |
---|
| 544 | selected = array.filter(callback, caller); |
---|
| 545 | } else { |
---|
| 546 | var len = array.length; |
---|
| 547 | if (typeof callback != "function") { |
---|
| 548 | throw new TypeError(); |
---|
| 549 | } |
---|
| 550 | for(var i=0; i<len; i++) { |
---|
| 551 | if (i in array) { |
---|
| 552 | var val = array[i]; |
---|
| 553 | if (callback.call(caller, val, i, array)) { |
---|
| 554 | selected.push(val); |
---|
| 555 | } |
---|
| 556 | } |
---|
| 557 | } |
---|
| 558 | } |
---|
| 559 | return selected; |
---|
| 560 | } |
---|
| 561 | |
---|
| 562 | }; |
---|
| 563 | |
---|
| 564 | /** |
---|
| 565 | * Namespace: OpenLayers.Date |
---|
| 566 | * Contains implementations of Date.parse and date.toISOString that match the |
---|
| 567 | * ECMAScript 5 specification for parsing RFC 3339 dates. |
---|
| 568 | * http://tools.ietf.org/html/rfc3339 |
---|
| 569 | */ |
---|
| 570 | OpenLayers.Date = { |
---|
| 571 | |
---|
| 572 | /** |
---|
| 573 | * APIMethod: toISOString |
---|
| 574 | * Generates a string representing a date. The format of the string follows |
---|
| 575 | * the profile of ISO 8601 for date and time on the Internet (see |
---|
| 576 | * http://tools.ietf.org/html/rfc3339). If the toISOString method is |
---|
| 577 | * available on the Date prototype, that is used. The toISOString |
---|
| 578 | * method for Date instances is defined in ECMA-262. |
---|
| 579 | * |
---|
| 580 | * Parameters: |
---|
| 581 | * date - {Date} A date object. |
---|
| 582 | * |
---|
| 583 | * Returns: |
---|
| 584 | * {String} A string representing the date (e.g. |
---|
| 585 | * "2010-08-07T16:58:23.123Z"). If the date does not have a valid time |
---|
| 586 | * (i.e. isNaN(date.getTime())) this method returns the string "Invalid |
---|
| 587 | * Date". The ECMA standard says the toISOString method should throw |
---|
| 588 | * RangeError in this case, but Firefox returns a string instead. For |
---|
| 589 | * best results, use isNaN(date.getTime()) to determine date validity |
---|
| 590 | * before generating date strings. |
---|
| 591 | */ |
---|
| 592 | toISOString: (function() { |
---|
| 593 | if ("toISOString" in Date.prototype) { |
---|
| 594 | return function(date) { |
---|
| 595 | return date.toISOString(); |
---|
| 596 | } |
---|
| 597 | } else { |
---|
| 598 | function pad(num, len) { |
---|
| 599 | var str = num + ""; |
---|
| 600 | while (str.length < len) { |
---|
| 601 | str = "0" + str; |
---|
| 602 | } |
---|
| 603 | return str; |
---|
| 604 | } |
---|
| 605 | return function(date) { |
---|
| 606 | var str; |
---|
| 607 | if (isNaN(date.getTime())) { |
---|
| 608 | // ECMA-262 says throw RangeError, Firefox returns |
---|
| 609 | // "Invalid Date" |
---|
| 610 | str = "Invalid Date"; |
---|
| 611 | } else { |
---|
| 612 | str = |
---|
| 613 | date.getUTCFullYear() + "-" + |
---|
| 614 | pad(date.getUTCMonth() + 1, 2) + "-" + |
---|
| 615 | pad(date.getUTCDate(), 2) + "T" + |
---|
| 616 | pad(date.getUTCHours(), 2) + ":" + |
---|
| 617 | pad(date.getUTCMinutes(), 2) + ":" + |
---|
| 618 | pad(date.getUTCSeconds(), 2) + "." + |
---|
| 619 | pad(date.getUTCMilliseconds(), 3) + "Z"; |
---|
| 620 | } |
---|
| 621 | return str; |
---|
| 622 | } |
---|
| 623 | } |
---|
| 624 | |
---|
| 625 | })(), |
---|
| 626 | |
---|
| 627 | /** |
---|
| 628 | * APIMethod: parse |
---|
| 629 | * Generate a date object from a string. The format for the string follows |
---|
| 630 | * the profile of ISO 8601 for date and time on the Internet (see |
---|
| 631 | * http://tools.ietf.org/html/rfc3339). If the parse method on |
---|
| 632 | * the Date constructor returns a valid date for the given string, |
---|
| 633 | * that method is used. |
---|
| 634 | * |
---|
| 635 | * Parameters: |
---|
| 636 | * str - {String} A string representing the date (e.g. |
---|
| 637 | * "2010", "2010-08", "2010-08-07", "2010-08-07T16:58:23.123Z", |
---|
| 638 | * "2010-08-07T11:58:23.123-06"). |
---|
| 639 | * |
---|
| 640 | * Returns: |
---|
| 641 | * {Date} A date object. If the string could not be parsed, an invalid |
---|
| 642 | * date is returned (i.e. isNaN(date.getTime())). |
---|
| 643 | */ |
---|
| 644 | parse: function(str) { |
---|
| 645 | var date; |
---|
| 646 | // first check if the native parse method can parse it |
---|
| 647 | var elapsed = Date.parse(str); |
---|
| 648 | if (!isNaN(elapsed)) { |
---|
| 649 | date = new Date(elapsed); |
---|
| 650 | } else { |
---|
| 651 | var match = str.match(/^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:T(\d{1,2}):(\d{2}):(\d{2}(?:\.\d+)?)(Z|(?:[+-]\d{1,2}(?::(\d{2}))?)))?$/); |
---|
| 652 | var date; |
---|
| 653 | if (match && (match[1] || match[7])) { // must have at least year or time |
---|
| 654 | var year = parseInt(match[1], 10) || 0; |
---|
| 655 | var month = (parseInt(match[2], 10) - 1) || 0; |
---|
| 656 | var day = parseInt(match[3], 10) || 1; |
---|
| 657 | date = new Date(Date.UTC(year, month, day)); |
---|
| 658 | // optional time |
---|
| 659 | var type = match[7]; |
---|
| 660 | if (type) { |
---|
| 661 | var hours = parseInt(match[4], 10); |
---|
| 662 | var minutes = parseInt(match[5], 10); |
---|
| 663 | var secFrac = parseFloat(match[6]); |
---|
| 664 | var seconds = secFrac | 0; |
---|
| 665 | var milliseconds = Math.round(1000 * (secFrac - seconds)); |
---|
| 666 | date.setUTCHours(hours, minutes, seconds, milliseconds); |
---|
| 667 | // check offset |
---|
| 668 | if (type !== "Z") { |
---|
| 669 | var hoursOffset = parseInt(type, 10); |
---|
| 670 | var minutesOffset = parseInt(match[8]) || 0; |
---|
| 671 | var offset = -1000 * (60 * (hoursOffset * 60) + minutesOffset * 60); |
---|
| 672 | date = new Date(date.getTime() + offset); |
---|
| 673 | } |
---|
| 674 | } |
---|
| 675 | } else { |
---|
| 676 | date = new Date("invalid"); |
---|
| 677 | } |
---|
| 678 | } |
---|
| 679 | return date; |
---|
| 680 | } |
---|
| 681 | |
---|
| 682 | }; |
---|