"use strict"; if(!require) var require = function(path, module){return module}; /* * earth.core.object powers the OOP facilities of the library. * Thanks to John Resig and Dean Edwards for inspiration! */ var earth = { core:{ object : function () {} } }; earth.core.object.prototype.__id__ = 'earth.core.object'; /** * When extending: * STATICS * statics is a convenience property that injects specified object properties as the static properties of the object: * * var my_object = earth.core.object.extend({ * statics:{ * foo:5 * } * this.add = function(obj){ * this.cache.push(obj) * } * }); * my_instance = new my_object(); * * OR * * var my_object = earth.core.object.extend(new function(){ * this.statics = {}; * this.statics.foo = 5; * * this.add = function(obj){ * this.cache.push(obj); * }; * }); * * console.log(my_object.foo); -> 5 * console.log(my_instance.constructor.foo); -> 5 * * console.log(my_object.statics.foo -> TypeError * console.log(my_instance.foo) -> undefined * console.log(my_instance.statics.foo); -> TypeError * * OPTIONS * options is a special property that unlike other objects that you pass to extend will be merged with the parent one instead of overriding it completely, which makes managing configuration of objects and default values convenient: * * var Myobject = L.object.extend({ * options: { * myOption1: 'foo', * myOption2: 'bar' * } * }); * * var MyChildobject = Myobject.extend({ * options: { * myOption1: 'baz', * myOption3: 5 * } * }); * * var a = new MyChildobject(); * a.options.myOption1; // 'baz' * a.options.myOption2; // 'bar' * a.options.myOption3; // 5 */ earth.core.object.extend = function (skeleton, options) { if(skeleton instanceof Function) skeleton = new skeleton(this.prototype); var options = options?options:{}; options.sugar = (options.sugar!==false)?true:false; var base = this; var derived = null; if(options.sugar){ derived = function(){ if(this.__complex_member_variables__){ var l = this.__complex_member_variables__.length; for(var i = 0; i 0){ var __id__ = derived.prototype.hasOwnProperty('__id__')?derived.prototype.__id__:('Child of ' + derived.prototype.__id__); console.info(__id__ + ': implements complex objects as a member variables (' + complex_members.join(', ') + ').'); if(options.complex_member_variables===undefined){//i.e. if implementer is potentially not aware of consequences, warn with consequences console.warn(__id__ + ': Complex member cloning will be enforced. If you would like to avoid this behaviour, please initiate the member variable in the constructor (__init) or set complex_member_variable to false. The consequence of setting complex_members_variables to false is that complex members will be shared across all instances and modifying a complex member variable will result in the change being visible in all other instances.'); } //setting the complex member variable if complex member variables have not been explicitly set to false derived.prototype.__complex_member_variables__ = (true && (options.complex_member_variables!== false))?complex_members:false; } return derived; }; // method for adding properties to prototype earth.core.object.include = function(props){ if(!earth.core.mixin){console.error('Mixins (class earth.core.mixin) are not defined');return false;} if(!props){console.error('Trying to include non-existing object as a mixin');return false;} if(!props instanceof earth.core.mixin){console.warn('Trying to include a non Mixin object');} //include static properties for(var prop in props){ //we are not overwriting the extend method as mixins have a different extend method! if( prop != 'extend' && prop != 'superclass' && prop != 'prototype' && prop != 'add_init_hook' ){ if(this[prop]){ console.warn('Static method/property ' + prop + ' is shadowed/overwritten in ' + this.prototype.__id__ + ' by ' + props.prototype.__id__ + '. This might lead to unforseen behaviour. Inherit method is keeping the original to allow for local static extension/shadowing.'); }else{ this[prop] = props[prop]; } } } // include prototype methods var props = (props.prototype)?props.prototype:function(){}; //we wanna know what the leaf methods/properties are var this_props = Object.keys(this.prototype); //TODO: implement indexed array (k => v) to avoid naming conflicts between mixings. this way mixins can be ID'd/labeled and the respective function names prefixed while(props){ for(var prop in props){ switch(prop){ case '__init_hooks__': for(var hook in props[prop]){ this.add_init_hook(props[prop][hook]); } break; case 'options': this.prototype.options = earth.core.utils.extend(props[prop], this.prototype.options); break; case 'constructor': case '__init': case '__id__'://custom ID for each class/object //do nothing break; default: //if the prototype already has this method and since we're propagating upwards, we do not overwrite the respective property, otherwise we would be overwriting child methods/properties (shadowing) with parent methods/properties. if(this.prototype[prop]){ //we only log/warn in case it's not an inherited method, but an explicitly defined method/property -> otherwise we'll run in the risk of having many warnings up the inheritance chain of mixins. if(this_props.indexOf(prop)!= -1){ console.error('Instance method/property ' + prop + ' is shadowed/overwritten by mixin. This might lead to unforseen behaviour. Inherit method is using the local method/function to allow for local instance extension/shadowing.'); } }else{ this.prototype[prop] = props[prop]; } } } props = (props.prototype)?props.prototype:props.__proto__; } return true; }; // merge new default options to the object earth.core.object.merge_options = function(options){ this.prototype.options = earth.core.utils.extend(this.prototype.options, options); }; // add a constructor hook earth.core.object.add_init_hook = function (fn) { // (Function) || (String, args...) var args = Array.prototype.slice.call(arguments, 1); var init = typeof fn === 'function' ? fn : function () { this[fn].apply(this, args); }; this.prototype.__init_hooks__ = this.prototype.__init_hooks__ || []; this.prototype.__init_hooks__.push(init); }; earth.core.object.prototype.equals = function(obj){ return (obj === this); }; "use strict"; earth.core.utils = new (function(){ this.__id__ = 'earth.core.utils'; this.timeouts = []; this.intervals = []; this.set_timeout = function(id, f, timeout, immediate, callback){ if(this.timeouts[id]) clearTimeout(this.timeouts[id]); this.timeouts[id] = setTimeout(function(){ f(id); if(callback) callback(id, f); }, timeout); if(immediate) f(); }; this.clear_timeout = function(id){ if(this.timeouts[id]) clearTimeout(this.timeouts[id]); }; this.set_interval = function(id, f, interval, immediate, callback){ var count = 0; if(immediate){f(0); count++;} if(this.intervals[id]) clearInterval(this.intervals[id]); this.intervals[id] = setInterval(function(){ f(id, count++); if(callback) callback(id, count++, f); }, interval); }; this.clear_interval = function(id){ if(this.intervals[id]) clearInterval(this.intervals[id]); }; this.stop_propagation = function(e){ (e.originalEvent.stopPropagation) ? e.originalEvent.stopPropagation() : e.originalEvent.cancelBubble=true ; (e.originalEvent.preDefault) ? e.originalEvent.preDefault() : e.originalEvent.returnValue = false; }; /** * extend an object with properties of one or more other objects */ this.extend = function (dest) { var i, j, len, src; var complex = false; for (j = 1, len = arguments.length; j < len; j++) { src = arguments[j]; for (i in src) { dest[i] = src[i]; } } return dest; }; /** * create an object from a given prototypv */ this.create = (function () { function F() {}; return function (prototype) { F.prototype = prototype; return new F(); }; })(); this.merge_array = function(arr1, arr2){ return $.extend(true, {}, arr2, arr1); }; /** * bind a function to be called with a given context */ this.bind = function (fn, obj) { var slice = Array.prototype.slice; if (fn.bind) { return fn.bind.apply(fn, slice.call(arguments, 1)); } var args = slice.call(arguments, 2); return function () { return fn.apply(obj, args.length ? args.concat(slice.call(arguments)) : arguments); }; }; // round a given number to a given precision this.format_number = function (num, digits) { var pow = Math.pow(10, digits || 5); return Math.round(num * pow) / pow; }; // trim whitespace from both sides of a string this.trim = function (str) { return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, ''); }; // split a string into words this.split_words = function (str) { return this.trim(str).split(/\s+/); }; // set options to an object, inheriting parent's options as well this.set_options = function (obj, options) { if (!obj.hasOwnProperty('options')) { obj.options = obj.options ? earth.core.utils.create(obj.options) : {}; } for (var i in options) { obj.options[i] = options[i]; } return obj.options; }; // make an URL with GET parameters out of a set of properties/values this.get_url_parameter= function (obj, existing_url, uppercase) { var params = []; for (var i in obj) { params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i])); } return ((!existing_url || existing_url.indexOf('?') === -1) ? '?' : '&') + params.join('&'); }; this.is_array= Array.isArray || function (obj) { return (Object.prototype.toString.call(obj) === '[object Array]'); }; this.coordinate = function(coordinate){ return parseFloat(coordinate).toFixed(6); }; this.empty_image = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='; // do nothing (used as a noop throughout the code) this.false_function = function () { return false; }; this.parse_ids = function(ids, as_query_parameter){ as_query_parameter = (as_query_parameter)?true:false; switch(typeof ids){ case 'string': ids = ids.split('|'); break; case 'number': ids = [ids]; break; case 'undefined': case 'object': if(!(ids instanceof Array)){ ids = []; } break; default: ids = []; } var r = [],len,id; for(var i = 0,len=ids.length;ithis.length-1) i= this.length-1; for (i++; i-->0;) /* i++ because from-argument is sadly inclusive */ if (i in this && this[i]===find) return i; return -1; }; } if (!('forEach' in Array.prototype)) { Array.prototype.forEach= function(action, that /*opt*/) { for (var i= 0, n= this.length; i