mirror of
https://github.com/peeringdb/peeringdb.git
synced 2024-05-11 05:55:09 +00:00
* stub in poetry for pipenv * re-add tester image * add pre-commit / formatting * fix ghactions * revert test data whitespace, exclude tests/data * revert ws * decruft, rm tox/pipenv * install dev packages for base image * add lgtm config to force to py3
697 lines
16 KiB
JavaScript
697 lines
16 KiB
JavaScript
(function() {
|
|
|
|
/**
|
|
* create root namespace for all twentyc definitions
|
|
* @module twentyc
|
|
*/
|
|
|
|
twentyc = {};
|
|
|
|
/**
|
|
* class helper functions
|
|
* @module twentyc
|
|
* @class cls
|
|
* @static
|
|
*/
|
|
|
|
/// Contains 7 sentences fo devs, no need for translation
|
|
|
|
twentyc.cls = {
|
|
|
|
/**
|
|
* converts a string into a standardized class name, replacing
|
|
* invalid characters with valid ones.
|
|
*
|
|
* twentyc.cls.make_name("class-a"); // classA
|
|
* twentyc.cls.make_name("class a b"); // classAB
|
|
* twentyc.cls.make_name("Class-A_B"); // ClassA_B
|
|
*
|
|
* @method make_name
|
|
* @param {String} name base name
|
|
* @returns {String} class_name changed name
|
|
*/
|
|
|
|
make_name : function(name) {
|
|
var i, names = name.split(/[-\s]/);
|
|
for(i = 0; i < names.length; i++) {
|
|
if(i > 0)
|
|
names[i] = names[i].charAt(0).toUpperCase() + names[i].slice(1);
|
|
}
|
|
return names.join("");
|
|
},
|
|
|
|
/**
|
|
* create a new class - if you wish to extend a class take a look at
|
|
* {{#crossLink "cls/extend:method"}}twentyc.cls.extend{{/crossLink}}
|
|
* instead
|
|
*
|
|
* you may define a constructor in the definition by using the class
|
|
* name you provide at __name__
|
|
*
|
|
* Note that if the name you provide is not a valid variable name
|
|
* it will be passed through twentyc.cls.make_name to make it valid
|
|
*
|
|
* ##examples
|
|
*
|
|
* * define and instantiate a class: examples/cls.define.js
|
|
*
|
|
* @method define
|
|
* @param {String} name name or unique identifier of the new class
|
|
* @param {Object} definition object literal of properties and functions that you wish define or redefine
|
|
* @returns {Function} dest constructor of new class
|
|
*/
|
|
|
|
define : function(name, definition) {
|
|
|
|
var k;
|
|
|
|
name = twentyc.cls.make_name(name);
|
|
|
|
if(typeof(definition[name]) == "function") {
|
|
// a constructor has been provided
|
|
var ctor = definition[name]
|
|
delete definition[name]
|
|
} else {
|
|
// no constructor provided, substitute empty constructor
|
|
var ctor = function(){};
|
|
}
|
|
|
|
// cycle through definition and copy to class prototype
|
|
for(k in definition) {
|
|
ctor.prototype[k] = definition[k]
|
|
}
|
|
|
|
// create meta information
|
|
ctor.prototype._meta = {
|
|
"name" : name
|
|
}
|
|
|
|
return ctor
|
|
|
|
},
|
|
|
|
/**
|
|
* extend an existing class with new properties and functions
|
|
*
|
|
* if a function is defined that already exists on the parent class
|
|
* this function will be overwritten and a reference to the original
|
|
* function will be provided at parentClassName_functionName
|
|
*
|
|
* you may define a constructor in the definition by using the class
|
|
* name you provide at __name__
|
|
*
|
|
* Note that if the name you provide is not a valid variable name
|
|
* it will be passed through twentyc.cls.make_name to make it valid
|
|
*
|
|
* ##examples
|
|
*
|
|
* * extend and instantiate a class: examples/cls.extend.js
|
|
* * handling method override: examples/cls.extend.method-override.js
|
|
*
|
|
* @method extend
|
|
* @param {String} name name or unqiue identifier of the new class
|
|
* @param {Object} definition object literal of properties and functions that you wish define or redefine
|
|
* @param {Function} [parent] constructor of class
|
|
* that you wish to extend, if omitted an empty function will be substituted
|
|
* @returns {Function} dest constructor of new class
|
|
*/
|
|
|
|
extend : function(name, definition, parent) {
|
|
|
|
var k;
|
|
name = twentyc.cls.make_name(name);
|
|
|
|
if(typeof(definition[name]) == "function") {
|
|
// a constructor has been provided
|
|
var ctor = definition[name]
|
|
delete definition[name]
|
|
} else {
|
|
// no constructor provided, substitute empty constructor
|
|
var ctor = function(){
|
|
parent.apply(this, arguments)
|
|
};
|
|
}
|
|
|
|
// cycle through parent prototype and copy to class prototype
|
|
for(k in parent.prototype) {
|
|
ctor.prototype[k] = parent.prototype[k]
|
|
}
|
|
|
|
// cycle through definition and copy to class prototype
|
|
for(k in definition) {
|
|
if(typeof(ctor.prototype[k]) == "function") {
|
|
// function was already defined by parent, store backref
|
|
ctor.prototype[parent.prototype._meta.name+"_"+k] = parent.prototype[k];
|
|
}
|
|
ctor.prototype[k] = definition[k]
|
|
}
|
|
|
|
// reference parent constructor
|
|
ctor.prototype[parent.prototype._meta.name] = parent
|
|
|
|
// create meta information
|
|
ctor.prototype._meta = {
|
|
"name" : name,
|
|
"parent" : parent
|
|
}
|
|
|
|
return ctor
|
|
|
|
|
|
},
|
|
|
|
/**
|
|
* overrides a method on the provided class
|
|
*
|
|
* @method override
|
|
* @param {Function} destClass A class created via __twentyc.cls.define__ or __twentyc.cls.extend__
|
|
* @param {String} methodName name of method that you wish to override
|
|
* @param {Function} method new method
|
|
*/
|
|
|
|
override : function(destClass, methodName, method) {
|
|
|
|
// create reference to old method
|
|
if(destClass.prototype[methodName])
|
|
destClass.prototype[destClass.prototype._meta.name+"_"+methodName] = destClass.prototype[methodName];
|
|
|
|
// override
|
|
destClass.prototype[methodName] = method;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* class registry object - allows you to quickly define and extend
|
|
* similar classes
|
|
*
|
|
* @module twentyc
|
|
* @namespace twentyc.cls
|
|
* @class Registry
|
|
* @constructor
|
|
*/
|
|
|
|
twentyc.cls.Registry = twentyc.cls.define(
|
|
"Registry",
|
|
{
|
|
|
|
Registry : function() {
|
|
|
|
/**
|
|
* holds the classes defined in this registry
|
|
* @property _classes
|
|
* @type Object
|
|
* @private
|
|
*/
|
|
|
|
this._classes = {}
|
|
|
|
},
|
|
|
|
/**
|
|
* register a new class - look at twentyc.cls.define and twentyc.cls.extend for param
|
|
* explanation
|
|
* @method register
|
|
* @param {String} name class name
|
|
* @param {Object} definition class definition
|
|
* @param {String} extend if passed, extend this class from this class (needs to exist in the Registry)
|
|
* @returns {Function} class ctor of the newly created class
|
|
*/
|
|
|
|
register : function(name, definition, extend) {
|
|
if(this._classes[name] != undefined) {
|
|
throw("Class with name '"+name+"' already exists - name must be unique in the Registry");
|
|
}
|
|
if(extend && typeof this._classes[extend] != "function") {
|
|
throw("Trying to extend from class unknown to this Registry: "+extend);
|
|
}
|
|
if(extend)
|
|
this._classes[name] = twentyc.cls.extend(name, definition, this._classes[extend]);
|
|
else
|
|
this._classes[name] = twentyc.cls.define(name, definition);
|
|
return this._classes[name];
|
|
},
|
|
|
|
/**
|
|
* get a registered class constructor
|
|
* @method get
|
|
* @param {String} name class name
|
|
* @returns {Function} class ctor of registered class
|
|
*/
|
|
|
|
get : function(name) {
|
|
if(typeof this._classes[name] != "function")
|
|
throw("Trying to retrieve class unknown to this Registry: "+name);
|
|
return this._classes[name];
|
|
},
|
|
|
|
/**
|
|
* See if a class constructor for the specified name exists
|
|
* @method has
|
|
* @param {String} name class name
|
|
* @returns {Boolean} exists
|
|
*/
|
|
|
|
has : function(name) {
|
|
return (typeof this._classes[name] == "function")
|
|
}
|
|
}
|
|
);
|
|
|
|
/**
|
|
* utility functions
|
|
* @module twentyc
|
|
* @class util
|
|
* @static
|
|
*/
|
|
|
|
twentyc.util = {
|
|
|
|
/**
|
|
* retrieve value from object literal - allows you to pass null or undefined
|
|
* as the object and will return null if you do
|
|
*
|
|
* @method get
|
|
* @param {Object} obj
|
|
* @param {String) key
|
|
* @param {Mixed} [default] return this if obj is null or key does not exist
|
|
* @returns {Mixed} value
|
|
*/
|
|
|
|
get : function(obj, key, dflt) {
|
|
if(!obj || obj[key] == undefined)
|
|
return dflt;
|
|
return obj[key]
|
|
},
|
|
|
|
/**
|
|
* requires a namespace exist, any keys that do not exist will
|
|
* be created as object literals
|
|
*
|
|
* @method require_namespace
|
|
* @param {String} namespace "." separated namespace
|
|
*/
|
|
|
|
require_namespace : function(namespace) {
|
|
var tokens = namespace.split("."),
|
|
i,
|
|
t,
|
|
container=window;
|
|
|
|
for(i = 0; i < tokens.length; i++) {
|
|
t = tokens[i];
|
|
if(typeof container[t] == "undefined") {
|
|
container[t] = {}
|
|
}
|
|
container = container[t];
|
|
}
|
|
return container;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* data retrieval, storage and management
|
|
*
|
|
* assures that data is only retrieved once even when multiple sources
|
|
* are requesting it.
|
|
*
|
|
* data is cached locally for quick retrieval afterwards
|
|
*
|
|
* @module twentyc
|
|
* @class data
|
|
* @static
|
|
*/
|
|
|
|
twentyc.data = {
|
|
|
|
/**
|
|
* fires everytime a dataset is retrieved from the server - __*__ is
|
|
* substituted with the data id
|
|
*
|
|
* all handlers bound to this event will be removed after its been
|
|
* triggered - in order to permanently subscribe a load event
|
|
* subscribe to "load"
|
|
*
|
|
* @event load-*
|
|
* @param {String} id data id
|
|
* @param {Object} data object literal of retrieved data
|
|
*/
|
|
|
|
/**
|
|
* fires everytime a dataset is retrieved from the server
|
|
*
|
|
* @event load
|
|
* @param {String} id data id
|
|
* @param {Object} data object literal of retrieved data
|
|
*/
|
|
|
|
/**
|
|
* fires when all loads are finished
|
|
*
|
|
* @event done
|
|
*/
|
|
|
|
/**
|
|
* keeps track of current loading status
|
|
* @property _loading
|
|
* @type Object
|
|
* @private
|
|
*/
|
|
|
|
_loading : {},
|
|
|
|
/**
|
|
* _data storage, keyed by data id
|
|
* @property data
|
|
* @type Object
|
|
* @private
|
|
*/
|
|
|
|
_data : {},
|
|
|
|
/**
|
|
* attempts to retrieve and return a data set
|
|
*
|
|
* ##example(s)
|
|
*
|
|
* examples/data.load.js
|
|
*
|
|
* @method get
|
|
* @param {String} id data id
|
|
* @returns {Object} data
|
|
*/
|
|
|
|
get : function(id) {
|
|
return tc.u.get(this._data, id, {})
|
|
},
|
|
|
|
/**
|
|
* retrieve data from server. at this point this expects a json
|
|
* string response, with the actual data keyed at the id you provided
|
|
*
|
|
* ##example(s)
|
|
*
|
|
* examples/data.load.js
|
|
*
|
|
* @method load
|
|
* @param {String} id data identification key
|
|
* @param {Object} [config] object literal holding options
|
|
* @param {Function} [config.callback] called when data is available
|
|
* @param {Boolean} [config.reload] if true data will be re-fetched even if already loaded
|
|
*/
|
|
|
|
load : function(id, config) {
|
|
|
|
var callback = tc.u.get(config, "callback");
|
|
|
|
// check if data is already loaded
|
|
if(this._data[id] && !tc.u.get(config, "reload")) {
|
|
var payload = {id:id, data:this._data[id]}
|
|
$(this).trigger("load-"+id, payload);
|
|
if(callback)
|
|
callback(payload)
|
|
return;
|
|
}
|
|
|
|
// attach callback to load event
|
|
if(callback) {
|
|
$(this).on("load-"+id, function(ev, payload) { callback(payload) });
|
|
}
|
|
|
|
// check if data is currently being loaded
|
|
if(this._loading[id]) {
|
|
return;
|
|
}
|
|
|
|
// data is not loaded AND not currently loading, attempt to load data
|
|
|
|
// in order to load data we need to find a suitable loader for it
|
|
|
|
var loader = this.loaders.loader(id, config);
|
|
this._loading[id] = new Date().getTime()
|
|
loader.load(
|
|
{
|
|
success : function(data) {
|
|
twentyc.data._data[id] = data
|
|
twentyc.data._loading[id] = false;
|
|
$(twentyc.data).trigger("load", { id:id, data:data} );
|
|
$(twentyc.data).trigger("load-"+id, { id:id, data:data });
|
|
$(twentyc.data).off("load-"+id);
|
|
twentyc.data.done();
|
|
}
|
|
}
|
|
);
|
|
},
|
|
|
|
done : function(callback) {
|
|
var i;
|
|
if(callback) {
|
|
$(this).on("done", callback);
|
|
$(this).on("done", function() { $(twentyc.data).off("done", callback); });
|
|
}
|
|
for(i in this._loading) {
|
|
if(twentyc.data._loading[i]) {
|
|
return;
|
|
}
|
|
}
|
|
$(this).trigger("done", {});
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* create and manage data loaders
|
|
* @module twentyc
|
|
* @namesapce twentyc.data
|
|
* @class loaders
|
|
* @extends twentyc.cls.Registry
|
|
* @static
|
|
*/
|
|
|
|
twentyc.data.LoaderRegistry = twentyc.cls.extend(
|
|
"LoaderRegistry",
|
|
{
|
|
LoaderRegistry : function() {
|
|
this.Registry();
|
|
|
|
/**
|
|
* holds data id -> loader assignments, keyed by data id
|
|
* @property _loaders
|
|
* @type Object
|
|
* @private
|
|
*/
|
|
|
|
this._loaders = {};
|
|
},
|
|
|
|
/**
|
|
* assign loader to data id
|
|
* @method assign
|
|
* @param {String} id data id
|
|
* @param {String} loaderName name that you registered the loader under
|
|
*/
|
|
|
|
assign : function(id, loaderName) {
|
|
|
|
// this will error if loaderName is not registered
|
|
var loader = this.get(loaderName);
|
|
|
|
// link loader
|
|
this._loaders[id] = loaderName;
|
|
|
|
},
|
|
|
|
/**
|
|
* get loader linked to data id via __link__
|
|
* @method loader
|
|
* @param {String} id data_id
|
|
* @returns {Object} loader instance of loader
|
|
*/
|
|
|
|
loader : function(id, config) {
|
|
if(!this._loaders[id])
|
|
throw("Could not find suitable loader for data id "+id+", are you certain it's assigned?");
|
|
|
|
var loader = this.get(this._loaders[id]);
|
|
return new loader(id, config || {});
|
|
}
|
|
|
|
},
|
|
twentyc.cls.Registry
|
|
);
|
|
twentyc.data.loaders = new twentyc.data.LoaderRegistry();
|
|
|
|
/**
|
|
* any new loader you register should at the very least
|
|
* extend this loader
|
|
*
|
|
* @class Base
|
|
* @module twentyc
|
|
* @namespace twentyc.data.loaders.get
|
|
* @constructor
|
|
* @param {String} id data id
|
|
* @param {Object} [config] object literal holding config attributes
|
|
*/
|
|
twentyc.data.loaders.register(
|
|
"Base",
|
|
{
|
|
Base : function(id, config) {
|
|
this.dataId = id;
|
|
this.config = config || {};
|
|
},
|
|
retrieve : function(data) {
|
|
var set = tc.u.get(data, this.dataId)
|
|
if(typeof set == undefined)
|
|
return {};
|
|
return set;
|
|
},
|
|
load : function() {
|
|
throw("The load() function needs to be overwritten to do something")
|
|
}
|
|
}
|
|
);
|
|
|
|
|
|
/**
|
|
* you may use this loader as a base class for any xhr data retrieval
|
|
* loaders you define. during the ctor you will need to set the url
|
|
* attribute on this.config
|
|
*
|
|
* @class XHRGet
|
|
* @module twentyc
|
|
* @namespace twentyc.data.loaders._classes
|
|
* @constructor
|
|
* @param {String} id data id
|
|
* @param {Object} [config] object literal holding config attributes
|
|
* @param {String} [config.url] url of the request
|
|
* @param {Object} [config.data] parameters to send
|
|
*/
|
|
|
|
twentyc.data.loaders.register(
|
|
"XHRGet",
|
|
{
|
|
load : function(callbacks) {
|
|
var url = tc.u.get(this.config, "url");
|
|
var loader = this;
|
|
if(url == undefined)
|
|
throw("XHRGet loader needs url, "+this._meta.name);
|
|
$.ajax(
|
|
{
|
|
url : url,
|
|
data : this.config.data,
|
|
success : function(data) {
|
|
if(typeof callbacks.success == "function")
|
|
callbacks.success(loader.retrieve(data));
|
|
}
|
|
}
|
|
).fail(function(response) {
|
|
if(callbacks.error)
|
|
callbacks.error(response);
|
|
});
|
|
}
|
|
},
|
|
"Base"
|
|
);
|
|
|
|
/**
|
|
* Timeout that will reset itself when invoked again before
|
|
* execution
|
|
*
|
|
* @class SmartTimeout
|
|
* @namespace twentyc.util
|
|
* @constructor
|
|
* @param {Function} callback
|
|
* @param {Number} interval trigger in N ms
|
|
*/
|
|
|
|
twentyc.util.SmartTimeout = twentyc.cls.define(
|
|
"SmartTimeout",
|
|
{
|
|
SmartTimeout : function(callback, interval) {
|
|
this.set(callback, interval);
|
|
},
|
|
|
|
/**
|
|
* Reset / start the timeout
|
|
* @method set
|
|
* @param {Function} callback
|
|
* @param {Number} interval trigger in N ms
|
|
*/
|
|
|
|
set : function(callback, interval) {
|
|
this.cancel();
|
|
this._timeout = setTimeout(callback, interval);
|
|
},
|
|
|
|
/**
|
|
* Cancel timeout
|
|
* @method cancel
|
|
*/
|
|
|
|
cancel : function() {
|
|
if(this._timeout) {
|
|
clearTimeout(this._timeout);
|
|
this._timeout = null;
|
|
}
|
|
}
|
|
}
|
|
);
|
|
|
|
/**
|
|
* jQuery helper functions
|
|
*
|
|
* @class jq
|
|
* @static
|
|
* @namespace twentyc
|
|
*/
|
|
|
|
twentyc.jq = {
|
|
|
|
/**
|
|
* define a jquery plugin
|
|
*
|
|
* @method plugin
|
|
* @param {String} name plugin name as it will be used to access the plugin
|
|
* on the jquery resultset
|
|
* @param {Object} definition object literal defining methods of the plugin
|
|
* @param {Object} config object literal with default plugin config
|
|
*/
|
|
|
|
plugin : function(name, definition, config) {
|
|
|
|
if(!definition.init) {
|
|
throw("Plugin definition for jQuery."+name+" missing init method");
|
|
}
|
|
|
|
jQuery.fn[name] = function(arg) {
|
|
|
|
if(definition[arg]) {
|
|
return definition[arg].apply(this, Array.prototype.slice.call(arguments, 1));
|
|
} else if(typeof arg === "object" || !arg) {
|
|
var opt = jQuery.extend(config || {}, arg);
|
|
return definition.init.call(this, opt);
|
|
} else {
|
|
throw("Method "+arg+" does not exist on jQuery."+name);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* shortcuts
|
|
*/
|
|
|
|
tc = {
|
|
u : twentyc.util,
|
|
def : twentyc.cls.define,
|
|
ext : twentyc.cls.extend
|
|
}
|
|
|
|
})();
|