mapstraction-rails 2.0.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. data/Gemfile +4 -0
  2. data/Gemfile.lock +14 -0
  3. data/LICENSE +22 -0
  4. data/README.md +32 -0
  5. data/Rakefile +2 -0
  6. data/lib/mapstraction/engine.rb +4 -0
  7. data/lib/mapstraction/version.rb +3 -0
  8. data/lib/mapstraction.rb +5 -0
  9. data/mapstraction/.gitignore +17 -0
  10. data/mapstraction.gemspec +17 -0
  11. data/vendor/.DS_Store +0 -0
  12. data/vendor/assets/.DS_Store +0 -0
  13. data/vendor/assets/javascripts/mxn-min.js +15 -0
  14. data/vendor/assets/javascripts/mxn.cartociudad.geocoder-min.js +15 -0
  15. data/vendor/assets/javascripts/mxn.cartociudad.geocoder.js +46 -0
  16. data/vendor/assets/javascripts/mxn.cloudmade.core-min.js +15 -0
  17. data/vendor/assets/javascripts/mxn.cloudmade.core.js +383 -0
  18. data/vendor/assets/javascripts/mxn.core-min.js +15 -0
  19. data/vendor/assets/javascripts/mxn.core.js +1892 -0
  20. data/vendor/assets/javascripts/mxn.geocoder-min.js +15 -0
  21. data/vendor/assets/javascripts/mxn.geocoder.js +74 -0
  22. data/vendor/assets/javascripts/mxn.geocommons.core-min.js +15 -0
  23. data/vendor/assets/javascripts/mxn.geocommons.core.js +343 -0
  24. data/vendor/assets/javascripts/mxn.google.core-min.js +15 -0
  25. data/vendor/assets/javascripts/mxn.google.core.js +536 -0
  26. data/vendor/assets/javascripts/mxn.google.geocoder-min.js +15 -0
  27. data/vendor/assets/javascripts/mxn.google.geocoder.js +87 -0
  28. data/vendor/assets/javascripts/mxn.googleearth.core-min.js +15 -0
  29. data/vendor/assets/javascripts/mxn.googleearth.core.js +350 -0
  30. data/vendor/assets/javascripts/mxn.googlev3.core-min.js +15 -0
  31. data/vendor/assets/javascripts/mxn.googlev3.core.js +630 -0
  32. data/vendor/assets/javascripts/mxn.googlev3.geocoder-min.js +15 -0
  33. data/vendor/assets/javascripts/mxn.googlev3.geocoder.js +101 -0
  34. data/vendor/assets/javascripts/mxn.js +581 -0
  35. data/vendor/assets/javascripts/mxn.leaflet.core-min.js +15 -0
  36. data/vendor/assets/javascripts/mxn.leaflet.core.js +398 -0
  37. data/vendor/assets/javascripts/mxn.mapquest.geocoder-min.js +15 -0
  38. data/vendor/assets/javascripts/mxn.mapquest.geocoder.js +63 -0
  39. data/vendor/assets/javascripts/mxn.microsoft.core-min.js +15 -0
  40. data/vendor/assets/javascripts/mxn.microsoft.core.js +429 -0
  41. data/vendor/assets/javascripts/mxn.microsoft7.core-min.js +15 -0
  42. data/vendor/assets/javascripts/mxn.microsoft7.core.js +458 -0
  43. data/vendor/assets/javascripts/mxn.microsoft7.geocoder-min.js +15 -0
  44. data/vendor/assets/javascripts/mxn.microsoft7.geocoder.js +66 -0
  45. data/vendor/assets/javascripts/mxn.multimap.core-min.js +15 -0
  46. data/vendor/assets/javascripts/mxn.multimap.core.js +473 -0
  47. data/vendor/assets/javascripts/mxn.openlayers.core-min.js +15 -0
  48. data/vendor/assets/javascripts/mxn.openlayers.core.js +630 -0
  49. data/vendor/assets/javascripts/mxn.openlayers.geocoder-min.js +15 -0
  50. data/vendor/assets/javascripts/mxn.openlayers.geocoder.js +106 -0
  51. data/vendor/assets/javascripts/mxn.openmq.core-min.js +15 -0
  52. data/vendor/assets/javascripts/mxn.openmq.core.js +364 -0
  53. data/vendor/assets/javascripts/mxn.openspace.core-min.js +15 -0
  54. data/vendor/assets/javascripts/mxn.openspace.core.js +460 -0
  55. data/vendor/assets/javascripts/mxn.ovi.core-min.js +15 -0
  56. data/vendor/assets/javascripts/mxn.ovi.core.js +508 -0
  57. data/vendor/assets/javascripts/mxn.ovi.geocoder-min.js +15 -0
  58. data/vendor/assets/javascripts/mxn.ovi.geocoder.js +129 -0
  59. data/vendor/assets/javascripts/mxn.yahoo.core-min.js +15 -0
  60. data/vendor/assets/javascripts/mxn.yahoo.core.js +406 -0
  61. data/vendor/assets/javascripts/mxn.yandex.core-min.js +15 -0
  62. data/vendor/assets/javascripts/mxn.yandex.core.js +527 -0
  63. data/vendor/assets/javascripts/mxn.yandex.geocoder-min.js +15 -0
  64. data/vendor/assets/javascripts/mxn.yandex.geocoder.js +66 -0
  65. metadata +110 -0
@@ -0,0 +1,101 @@
1
+ /*
2
+ MAPSTRACTION v2.0.18 http://www.mapstraction.com
3
+
4
+ Copyright (c) 2012 Tom Carden, Steve Coast, Mikel Maron, Andrew Turner, Henri Bergius, Rob Moran, Derek Fowler, Gary Gale
5
+ All rights reserved.
6
+
7
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
8
+
9
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
10
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
11
+ * Neither the name of the Mapstraction nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
12
+
13
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
+ */
15
+ mxn.register('googlev3', {
16
+
17
+ Geocoder: {
18
+
19
+ init: function() {
20
+ this.geocoders[this.api] = new google.maps.Geocoder();
21
+ },
22
+
23
+ geocode: function(query){
24
+ var me = this;
25
+ var geocode_request_object = {};
26
+ if (typeof(query) == 'object') {
27
+ // query is a LatLonPoint object (reverse geocode)
28
+ if (query.hasOwnProperty('lat') && query.hasOwnProperty('lon')) {
29
+ geocode_request_object.latLng = query.toProprietary(this.api);
30
+ }
31
+ // query is an address object
32
+ else{
33
+ geocode_request_object.address = [ query.street, query.locality, query.region, query.country ].join(', ');
34
+ }
35
+ }
36
+ // query is an address string
37
+ else {
38
+ geocode_request_object.address = query;
39
+ }
40
+ this.geocoders[this.api].geocode(geocode_request_object, function(results, status) {
41
+ me.geocode_callback(results, status);
42
+ });
43
+ },
44
+
45
+ geocode_callback: function(results, status){
46
+ var return_location = {};
47
+
48
+ if (status != google.maps.GeocoderStatus.OK) {
49
+ this.error_callback(status);
50
+ }
51
+ else {
52
+ return_location.street = '';
53
+ return_location.locality = '';
54
+ return_location.postcode = '';
55
+ return_location.region = '';
56
+ return_location.country = '';
57
+
58
+ var place = results[0];
59
+ var streetparts = [];
60
+
61
+ for (var i = 0; i < place.address_components.length; i++) {
62
+ var addressComponent = place.address_components[i];
63
+ for (var j = 0; j < addressComponent.types.length; j++) {
64
+ var componentType = addressComponent.types[j];
65
+ switch (componentType) {
66
+ case 'country':
67
+ return_location.country = addressComponent.long_name;
68
+ break;
69
+ case 'administrative_area_level_1':
70
+ return_location.region = addressComponent.long_name;
71
+ break;
72
+ case 'locality':
73
+ return_location.locality = addressComponent.long_name;
74
+ break;
75
+ case 'street_address':
76
+ return_location.street = addressComponent.long_name;
77
+ break;
78
+ case 'postal_code':
79
+ return_location.postcode = addressComponent.long_name;
80
+ break;
81
+ case 'street_number':
82
+ streetparts.unshift(addressComponent.long_name);
83
+ break;
84
+ case 'route':
85
+ streetparts.push(addressComponent.long_name);
86
+ break;
87
+ }
88
+ }
89
+ }
90
+
91
+ if (return_location.street === '' && streetparts.length > 0) {
92
+ return_location.street = streetparts.join(' ');
93
+ }
94
+
95
+ return_location.point = new mxn.LatLonPoint(place.geometry.location.lat(), place.geometry.location.lng());
96
+
97
+ this.callback(return_location);
98
+ }
99
+ }
100
+ }
101
+ });
@@ -0,0 +1,581 @@
1
+ /*
2
+ MAPSTRACTION v2.0.18 http://www.mapstraction.com
3
+
4
+ Copyright (c) 2012 Tom Carden, Steve Coast, Mikel Maron, Andrew Turner, Henri Bergius, Rob Moran, Derek Fowler, Gary Gale
5
+ All rights reserved.
6
+
7
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
8
+
9
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
10
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
11
+ * Neither the name of the Mapstraction nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
12
+
13
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
+ */
15
+ // Auto-load scripts
16
+ //
17
+ // specify which map providers to load by using
18
+ // <script src="mxn.js?(provider1,provider2,[module1,module2])" ...
19
+ // in your HTML
20
+ //
21
+ // for each provider mxn.provider.module.js and mxn.module.js will be loaded
22
+ // module 'core' is always loaded
23
+ //
24
+ // NOTE: if you call without providers
25
+ // <script src="mxn.js" ...
26
+ // no scripts will be loaded at all and it is then up to you to load the scripts independently
27
+ (function() {
28
+ var providers = null;
29
+ var modules = 'core';
30
+ var scriptBase;
31
+ var scripts = document.getElementsByTagName('script');
32
+
33
+ // Determine which scripts we need to load
34
+ for (var i = 0; i < scripts.length; i++) {
35
+ var match = scripts[i].src.replace(/%20/g , '').match(/^(.*?)mxn\.js(\?\(\[?(.*?)\]?\))?$/);
36
+ if (match !== null) {
37
+ scriptBase = match[1];
38
+ if (match[3]) {
39
+ var settings = match[3].split(',[');
40
+ providers = settings[0].replace(']' , '');
41
+ if (settings[1]) {
42
+ modules += ',' + settings[1];
43
+ }
44
+ }
45
+ break;
46
+ }
47
+ }
48
+
49
+ if (providers === null || providers == 'none') {
50
+ return; // Bail out if no auto-load has been found
51
+ }
52
+ providers = providers.replace(/ /g, '').split(',');
53
+ modules = modules.replace(/ /g, '').split(',');
54
+
55
+ // Actually load the scripts
56
+ var scriptTagStart = '<script type="text/javascript" src="' + scriptBase + 'mxn.';
57
+ var scriptTagEnd = '.js"></script>';
58
+ var scriptsAry = [];
59
+ for (i = 0; i < modules.length; i++) {
60
+ scriptsAry.push(scriptTagStart + modules[i] + scriptTagEnd);
61
+ for (var j = 0; j < providers.length; j++) {
62
+ scriptsAry.push(scriptTagStart + providers[j] + '.' + modules[i] + scriptTagEnd);
63
+ }
64
+ }
65
+ document.write(scriptsAry.join(''));
66
+ })();
67
+
68
+ (function(){
69
+
70
+ // holds all our implementing functions
71
+ var apis = {};
72
+
73
+ // Our special private methods
74
+ /**
75
+ * Calls the API specific implementation of a particular method.
76
+ * Deferrable: If the API implmentation includes a deferable hash such as { getCenter: true, setCenter: true},
77
+ * then the methods calls mentioned with in it will be queued until runDeferred is called.
78
+ *
79
+ * @private
80
+ */
81
+ var invoke = function(sApiId, sObjName, sFnName, oScope, args){
82
+ if(!hasImplementation(sApiId, sObjName, sFnName)) {
83
+ throw 'Method ' + sFnName + ' of object ' + sObjName + ' is not supported by API ' + sApiId + '. Are you missing a script tag?';
84
+ }
85
+ if(typeof(apis[sApiId][sObjName].deferrable) != 'undefined' && apis[sApiId][sObjName].deferrable[sFnName] === true) {
86
+ mxn.deferUntilLoaded.call(oScope, function() {return apis[sApiId][sObjName][sFnName].apply(oScope, args);} );
87
+ }
88
+ else {
89
+ return apis[sApiId][sObjName][sFnName].apply(oScope, args);
90
+ }
91
+ };
92
+
93
+ /**
94
+ * Determines whether the specified API provides an implementation for the
95
+ * specified object and function name.
96
+ * @private
97
+ */
98
+ var hasImplementation = function(sApiId, sObjName, sFnName){
99
+ if(typeof(apis[sApiId]) == 'undefined') {
100
+ throw 'API ' + sApiId + ' not loaded. Are you missing a script tag?';
101
+ }
102
+ if(typeof(apis[sApiId][sObjName]) == 'undefined') {
103
+ throw 'Object definition ' + sObjName + ' in API ' + sApiId + ' not loaded. Are you missing a script tag?';
104
+ }
105
+ return typeof(apis[sApiId][sObjName][sFnName]) == 'function';
106
+ };
107
+
108
+ /**
109
+ * @name mxn
110
+ * @namespace
111
+ */
112
+ var mxn = window.mxn = /** @lends mxn */ {
113
+
114
+ /**
115
+ * Registers a set of provider specific implementation functions.
116
+ * @function
117
+ * @param {String} sApiId The API ID to register implementing functions for.
118
+ * @param {Object} oApiImpl An object containing the API implementation.
119
+ */
120
+ register: function(sApiId, oApiImpl){
121
+ if(!apis.hasOwnProperty(sApiId)){
122
+ apis[sApiId] = {};
123
+ }
124
+ mxn.util.merge(apis[sApiId], oApiImpl);
125
+ },
126
+
127
+ /**
128
+ * Adds a list of named proxy methods to the prototype of a
129
+ * specified constructor function.
130
+ * @function
131
+ * @param {Function} func Constructor function to add methods to
132
+ * @param {Array} aryMethods Array of method names to create
133
+ * @param {Boolean} bWithApiArg Optional. Whether the proxy methods will use an API argument
134
+ */
135
+ addProxyMethods: function(func, aryMethods, bWithApiArg){
136
+ for(var i = 0; i < aryMethods.length; i++) {
137
+ var sMethodName = aryMethods[i];
138
+ if(bWithApiArg){
139
+ func.prototype[sMethodName] = new Function('return this.invoker.go(\'' + sMethodName + '\', arguments, { overrideApi: true } );');
140
+ }
141
+ else {
142
+ func.prototype[sMethodName] = new Function('return this.invoker.go(\'' + sMethodName + '\', arguments);');
143
+ }
144
+ }
145
+ },
146
+
147
+ checkLoad: function(funcDetails){
148
+ if(this.loaded[this.api] === false) {
149
+ var scope = this;
150
+ this.onload[this.api].push( function() { funcDetails.callee.apply(scope, funcDetails); } );
151
+ return true;
152
+ }
153
+ return false;
154
+ },
155
+
156
+ deferUntilLoaded: function(fnCall) {
157
+ if(this.loaded[this.api] === false) {
158
+ var scope = this;
159
+ this.onload[this.api].push( fnCall );
160
+ } else {
161
+ fnCall.call(this);
162
+ }
163
+ },
164
+
165
+ /**
166
+ * Bulk add some named events to an object.
167
+ * @function
168
+ * @param {Object} oEvtSrc The event source object.
169
+ * @param {String[]} aEvtNames Event names to add.
170
+ */
171
+ addEvents: function(oEvtSrc, aEvtNames){
172
+ for(var i = 0; i < aEvtNames.length; i++){
173
+ var sEvtName = aEvtNames[i];
174
+ if(sEvtName in oEvtSrc){
175
+ throw 'Event or method ' + sEvtName + ' already declared.';
176
+ }
177
+ oEvtSrc[sEvtName] = new mxn.Event(sEvtName, oEvtSrc);
178
+ }
179
+ }
180
+
181
+ };
182
+
183
+ /**
184
+ * Instantiates a new Event
185
+ * @constructor
186
+ * @param {String} sEvtName The name of the event.
187
+ * @param {Object} oEvtSource The source object of the event.
188
+ */
189
+ mxn.Event = function(sEvtName, oEvtSource){
190
+ var handlers = [];
191
+ if(!sEvtName){
192
+ throw 'Event name must be provided';
193
+ }
194
+ /**
195
+ * Add a handler to the Event.
196
+ * @param {Function} fn The handler function.
197
+ * @param {Object} ctx The context of the handler function.
198
+ */
199
+ this.addHandler = function(fn, ctx){
200
+ handlers.push({context: ctx, handler: fn});
201
+ };
202
+ /**
203
+ * Remove a handler from the Event.
204
+ * @param {Function} fn The handler function.
205
+ * @param {Object} ctx The context of the handler function.
206
+ */
207
+ this.removeHandler = function(fn, ctx){
208
+ for(var i = 0; i < handlers.length; i++){
209
+ if(handlers[i].handler == fn && handlers[i].context == ctx){
210
+ handlers.splice(i, 1);
211
+ }
212
+ }
213
+ };
214
+ /**
215
+ * Remove all handlers from the Event.
216
+ */
217
+ this.removeAllHandlers = function(){
218
+ handlers = [];
219
+ };
220
+ /**
221
+ * Fires the Event.
222
+ * @param {Object} oEvtArgs Event arguments object to be passed to the handlers.
223
+ */
224
+ this.fire = function(oEvtArgs){
225
+ var args = [sEvtName, oEvtSource, oEvtArgs];
226
+ for(var i = 0; i < handlers.length; i++){
227
+ handlers[i].handler.apply(handlers[i].context, args);
228
+ }
229
+ };
230
+ };
231
+
232
+ /**
233
+ * Creates a new Invoker, a class which helps with on-the-fly
234
+ * invocation of the correct API methods.
235
+ * @constructor
236
+ * @param {Object} aobj The core object whose methods will make cals to go()
237
+ * @param {String} asClassName The name of the Mapstraction class to be invoked, normally the same name as aobj's constructor function
238
+ * @param {Function} afnApiIdGetter The function on object aobj which will return the active API ID
239
+ */
240
+ mxn.Invoker = function(aobj, asClassName, afnApiIdGetter){
241
+ var obj = aobj;
242
+ var sClassName = asClassName;
243
+ var fnApiIdGetter = afnApiIdGetter;
244
+ var defOpts = {
245
+ overrideApi: false, // {Boolean} API ID is overridden by value in first argument
246
+ context: null, // {Object} Local vars can be passed from the body of the method to the API method within this object
247
+ fallback: null // {Function} If an API implementation doesn't exist this function is run instead
248
+ };
249
+
250
+ /**
251
+ * Invoke the API implementation of a specific method.
252
+ * @param {String} sMethodName The method name to invoke
253
+ * @param {Array} args Arguments to pass on
254
+ * @param {Object} oOptions Optional. Extra options for invocation
255
+ * @param {Boolean} oOptions.overrideApi When true the first argument is used as the API ID.
256
+ * @param {Object} oOptions.context A context object for passing extra information on to the provider implementation.
257
+ * @param {Function} oOptions.fallback A fallback function to run if the provider implementation is missing.
258
+ */
259
+ this.go = function(sMethodName, args, oOptions){
260
+
261
+ // make sure args is an array
262
+ args = typeof(args) != 'undefined' ? Array.prototype.slice.apply(args) : [];
263
+
264
+ if(typeof(oOptions) == 'undefined'){
265
+ oOptions = defOpts;
266
+ }
267
+
268
+ var sApiId;
269
+ if(oOptions.overrideApi){
270
+ sApiId = args.shift();
271
+ }
272
+ else {
273
+ sApiId = fnApiIdGetter.apply(obj);
274
+ }
275
+
276
+ if(typeof(sApiId) != 'string'){
277
+ throw 'API ID not available.';
278
+ }
279
+
280
+ if(typeof(oOptions.context) != 'undefined' && oOptions.context !== null){
281
+ args.push(oOptions.context);
282
+ }
283
+
284
+ if(typeof(oOptions.fallback) == 'function' && !hasImplementation(sApiId, sClassName, sMethodName)){
285
+ // we've got no implementation but have got a fallback function
286
+ return oOptions.fallback.apply(obj, args);
287
+ }
288
+ else {
289
+ return invoke(sApiId, sClassName, sMethodName, obj, args);
290
+ }
291
+
292
+ };
293
+
294
+ };
295
+
296
+ /**
297
+ * @namespace
298
+ */
299
+ mxn.util = {
300
+
301
+ /**
302
+ * Merges properties of one object into another recursively.
303
+ * @param {Object} oRecv The object receiveing properties
304
+ * @param {Object} oGive The object donating properties
305
+ */
306
+ merge: function(oRecv, oGive){
307
+ for (var sPropName in oGive){
308
+ if (oGive.hasOwnProperty(sPropName)) {
309
+ if(!oRecv.hasOwnProperty(sPropName) || typeof(oRecv[sPropName]) !== 'object' || typeof(oGive[sPropName]) !== 'object'){
310
+ oRecv[sPropName] = oGive[sPropName];
311
+ }
312
+ else {
313
+ mxn.util.merge(oRecv[sPropName], oGive[sPropName]);
314
+ }
315
+ }
316
+ }
317
+ },
318
+
319
+ /**
320
+ * $m, the dollar function, elegantising getElementById()
321
+ * @return An HTML element or array of HTML elements
322
+ */
323
+ $m: function() {
324
+ var elements = [];
325
+ for (var i = 0; i < arguments.length; i++) {
326
+ var element = arguments[i];
327
+ if (typeof(element) == 'string') {
328
+ element = document.getElementById(element);
329
+ }
330
+ if (arguments.length == 1) {
331
+ return element;
332
+ }
333
+ elements.push(element);
334
+ }
335
+ return elements;
336
+ },
337
+
338
+ /**
339
+ * loadScript is a JSON data fetcher
340
+ * @param {String} src URL to JSON file
341
+ * @param {Function} callback Callback function
342
+ */
343
+ loadScript: function(src, callback) {
344
+ var script = document.createElement('script');
345
+ script.type = 'text/javascript';
346
+ script.src = src;
347
+ if (callback) {
348
+ if(script.addEventListener){
349
+ script.addEventListener('load', callback, true);
350
+ }
351
+ else if(script.attachEvent){
352
+ var done = false;
353
+ script.attachEvent("onreadystatechange",function(){
354
+ if ( !done && document.readyState === "complete" ) {
355
+ done = true;
356
+ callback();
357
+ }
358
+ });
359
+ }
360
+ }
361
+ var h = document.getElementsByTagName('head')[0];
362
+ h.appendChild( script );
363
+ return;
364
+ },
365
+
366
+ /**
367
+ *
368
+ * @param {Object} point
369
+ * @param {Object} level
370
+ */
371
+ convertLatLonXY_Yahoo: function(point, level) { //Mercator
372
+ var size = 1 << (26 - level);
373
+ var pixel_per_degree = size / 360.0;
374
+ var pixel_per_radian = size / (2 * Math.PI);
375
+ var origin = new YCoordPoint(size / 2 , size / 2);
376
+ var answer = new YCoordPoint();
377
+ answer.x = Math.floor(origin.x + point.lon * pixel_per_degree);
378
+ var sin = Math.sin(point.lat * Math.PI / 180.0);
379
+ answer.y = Math.floor(origin.y + 0.5 * Math.log((1 + sin) / (1 - sin)) * -pixel_per_radian);
380
+ return answer;
381
+ },
382
+
383
+ /**
384
+ * Load a stylesheet from a remote file.
385
+ * @param {String} href URL to the CSS file
386
+ */
387
+ loadStyle: function(href) {
388
+ var link = document.createElement('link');
389
+ link.type = 'text/css';
390
+ link.rel = 'stylesheet';
391
+ link.href = href;
392
+ document.getElementsByTagName('head')[0].appendChild(link);
393
+ return;
394
+ },
395
+
396
+ /**
397
+ * getStyle provides cross-browser access to css
398
+ * @param {Object} el HTML Element
399
+ * @param {String} prop Style property name
400
+ */
401
+ getStyle: function(el, prop) {
402
+ var y;
403
+ if (el.currentStyle) {
404
+ y = el.currentStyle[prop];
405
+ }
406
+ else if (window.getComputedStyle) {
407
+ y = window.getComputedStyle( el, '').getPropertyValue(prop);
408
+ }
409
+ return y;
410
+ },
411
+
412
+ /**
413
+ * Convert longitude to metres
414
+ * http://www.uwgb.edu/dutchs/UsefulData/UTMFormulas.HTM
415
+ * "A degree of longitude at the equator is 111.2km... For other latitudes,
416
+ * multiply by cos(lat)"
417
+ * assumes the earth is a sphere but good enough for our purposes
418
+ * @param {Float} lon
419
+ * @param {Float} lat
420
+ */
421
+ lonToMetres: function(lon, lat) {
422
+ return lon * (111200 * Math.cos(lat * (Math.PI / 180)));
423
+ },
424
+
425
+ /**
426
+ * Convert metres to longitude
427
+ * @param {Object} m
428
+ * @param {Object} lat
429
+ */
430
+ metresToLon: function(m, lat) {
431
+ return m / (111200 * Math.cos(lat * (Math.PI / 180)));
432
+ },
433
+
434
+ /**
435
+ * Convert kilometres to miles
436
+ * @param {Float} km
437
+ * @returns {Float} miles
438
+ */
439
+ KMToMiles: function(km) {
440
+ return km / 1.609344;
441
+ },
442
+
443
+ /**
444
+ * Convert miles to kilometres
445
+ * @param {Float} miles
446
+ * @returns {Float} km
447
+ */
448
+ milesToKM: function(miles) {
449
+ return miles * 1.609344;
450
+ },
451
+
452
+ // stuff to convert google zoom levels to/from degrees
453
+ // assumes zoom 0 = 256 pixels = 360 degrees
454
+ // zoom 1 = 256 pixels = 180 degrees
455
+ // etc.
456
+
457
+ /**
458
+ *
459
+ * @param {Object} pixels
460
+ * @param {Object} zoom
461
+ */
462
+ getDegreesFromGoogleZoomLevel: function(pixels, zoom) {
463
+ return (360 * pixels) / (Math.pow(2, zoom + 8));
464
+ },
465
+
466
+ /**
467
+ *
468
+ * @param {Object} pixels
469
+ * @param {Object} degrees
470
+ */
471
+ getGoogleZoomLevelFromDegrees: function(pixels, degrees) {
472
+ return mxn.util.logN((360 * pixels) / degrees, 2) - 8;
473
+ },
474
+
475
+ /**
476
+ *
477
+ * @param {Object} number
478
+ * @param {Object} base
479
+ */
480
+ logN: function(number, base) {
481
+ return Math.log(number) / Math.log(base);
482
+ },
483
+
484
+ /**
485
+ * Returns array of loaded provider apis
486
+ * @returns {Array} providers
487
+ */
488
+ getAvailableProviders : function () {
489
+ var providers = [];
490
+ for (var propertyName in apis){
491
+ if (apis.hasOwnProperty(propertyName)) {
492
+ providers.push(propertyName);
493
+ }
494
+ }
495
+ return providers;
496
+ },
497
+
498
+ /**
499
+ * Formats a string, inserting values of subsequent parameters at specified
500
+ * locations. e.g. stringFormat('{0} {1}', 'hello', 'world');
501
+ */
502
+ stringFormat: function(strIn){
503
+ var replaceRegEx = /\{\d+\}/g;
504
+ var args = Array.prototype.slice.apply(arguments);
505
+ args.shift();
506
+ return strIn.replace(replaceRegEx, function(strVal){
507
+ var num = strVal.slice(1, -1);
508
+ return args[num];
509
+ });
510
+ },
511
+
512
+ /**
513
+ * Traverses an object graph using a series of map functions provided as arguments
514
+ * 2 to n. Map functions are only called if the working object is not undefined/null.
515
+ * For usage see mxn.google.geocoder.js.
516
+ */
517
+ traverse: function(start) {
518
+ var args = Array.prototype.slice.apply(arguments);
519
+ args.shift();
520
+ var working = start;
521
+ while(typeof(working) != 'undefined' && working !== null && args.length > 0){
522
+ var op = args.shift();
523
+ working = op(working);
524
+ }
525
+ }
526
+ };
527
+
528
+ /**
529
+ * Class for converting between HTML and RGB integer color formats.
530
+ * Accepts either a HTML color string argument or three integers for R, G and B.
531
+ * @constructor
532
+ */
533
+ mxn.util.Color = function() {
534
+ if(arguments.length == 3) {
535
+ this.red = arguments[0];
536
+ this.green = arguments[1];
537
+ this.blue = arguments[2];
538
+ }
539
+ else if(arguments.length == 1) {
540
+ this.setHexColor(arguments[0]);
541
+ }
542
+ };
543
+
544
+ mxn.util.Color.prototype.reHex = /^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
545
+
546
+ /**
547
+ * Set the color from the supplied HTML hex string.
548
+ * @param {String} strHexColor A HTML hex color string e.g. '#00FF88'.
549
+ */
550
+ mxn.util.Color.prototype.setHexColor = function(strHexColor) {
551
+ var match = strHexColor.match(this.reHex);
552
+ if(match) {
553
+ // grab the code - strips off the preceding # if there is one
554
+ strHexColor = match[1];
555
+ }
556
+ else {
557
+ throw 'Invalid HEX color format, expected #000, 000, #000000 or 000000';
558
+ }
559
+ // if a three character hex code was provided, double up the values
560
+ if(strHexColor.length == 3) {
561
+ strHexColor = strHexColor.replace(/\w/g, function(str){return str.concat(str);});
562
+ }
563
+ this.red = parseInt(strHexColor.substr(0,2), 16);
564
+ this.green = parseInt(strHexColor.substr(2,2), 16);
565
+ this.blue = parseInt(strHexColor.substr(4,2), 16);
566
+ };
567
+
568
+ /**
569
+ * Retrieve the color value as an HTML hex string.
570
+ * @returns {String} Format '#00FF88'.
571
+ */
572
+ mxn.util.Color.prototype.getHexColor = function() {
573
+ var rgb = this.blue | (this.green << 8) | (this.red << 16);
574
+ var hexString = rgb.toString(16).toUpperCase();
575
+ if(hexString.length < 6){
576
+ hexString = '0' + hexString;
577
+ }
578
+ return '#' + hexString;
579
+ };
580
+
581
+ })();