Skip to content

Commit

Permalink
WIP on refactored configuration handling: working on addding support …
Browse files Browse the repository at this point in the history
…for recursive inclusion, and better logic for merging included configurations, references #121
  • Loading branch information
rbuels committed Aug 3, 2012
1 parent 10e2140 commit 4f9ef04
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 125 deletions.
111 changes: 4 additions & 107 deletions src/JBrowse/Browser.js
Expand Up @@ -65,8 +65,7 @@ var Browser = function(params) {

// schedule the config load, the first step in the initialization
// process, to happen when the page is done loading
var browser = this;
dojo.addOnLoad( function() { browser.loadConfig(); } );
dojo.addOnLoad( dojo.hitch( this,'loadConfig' ) );

dojo.connect( this, 'onConfigLoaded', Util.debugHandler( this, 'loadRefSeqs' ));
dojo.connect( this, 'onConfigLoaded', Util.debugHandler( this, 'loadNames' ));
Expand Down Expand Up @@ -432,88 +431,12 @@ Browser.prototype.addRecentlyUsedTracks = function( trackLabels ) {
* @returns nothing meaningful
*/
Browser.prototype.loadConfig = function () {
var that = this;

// coerce include to an array
if( typeof this.config.include != 'object' || !this.config.include.length )
this.config.include = [ this.config.include ];

// coerce bare strings in the configs to URLs
for (var i = 0; i < this.config.include.length; i++) {
if( typeof this.config.include[i] == 'string' )
this.config.include[i] = { url: this.config.include[i] };
}

// fetch and parse all the configuration data
var configs_remaining = this.config.include.length;
dojo.forEach( this.config.include, function(config) {
// include array might have undefined elements in it if
// somebody left a trailing comma in and we are running under
// IE
if( !config )
return;

// set defaults for format and version
if( ! ('format' in config) ) {
config.format = 'JB_json';
}
if( config.format == 'JB_json' && ! ('version' in config) ) {
config.version = 1;
}

// instantiate the adaptor and load the config
this.getConfigAdaptor( config, dojo.hitch(this, function(adaptor) {
if( !adaptor ) {
this.fatalError( "Could not load config "+config.url+", no configuration adaptor found for config format "+config.format+' version '+config.version );
return;
}

adaptor.load({
config: config,
context: this,
onSuccess: function( config_data, request_info ) {
config.data = config_data;
config.loaded = true;
if( ! --configs_remaining )
this.onConfigLoaded();
//if you need a backtrace: window.setTimeout( function() { that.onConfigLoaded(); }, 1 );
},
onFailure: function( error ) {
config.loaded = false;
this.fatalError( error );
if( ! --configs_remaining )
this.onConfigLoaded();
//if you need a backtrace: window.setTimeout( function() { that.onConfigLoaded(); }, 1 );
}
var c = new ConfigManager();
c.load( this.config, function( finishedConfig ) {
this.config = dojo.clone( finishedConfig );
});
}));
}, this);
};

Browser.prototype.onConfigLoaded = function() {

var initial_config = this.config;
this.config = {};

// load all the configuration data in order
dojo.forEach( initial_config.include, function( config ) {
if( config.loaded && config.data )
this.addConfigData( config.data );
}, this );

// load the initial config (i.e. constructor params) last so that
// it overrides the other config
this.addConfigData( initial_config );

this.validateConfig();

// index the track configurations by name
this.trackConfigsByName = {};
dojo.forEach( this.config.tracks || [], function(conf){
this.trackConfigsByName[conf.label] = conf;
},this);

};

/**
* Examine the loaded and merged configuration for errors. Throws
Expand All @@ -532,23 +455,6 @@ Browser.prototype.validateConfig = function() {
throw "Errors in configuration, aborting.";
};

/**
* Instantiate the right config adaptor for a given configuration source.
* @param {Object} config the configuraiton
* @param {Function} callback called with the new config object
* @returns {Object} the right configuration adaptor to use, or
* undefined if one could not be found
*/

Browser.prototype.getConfigAdaptor = function( config_def, callback ) {
var adaptor_name = "JBrowse/ConfigAdaptor/" + config_def.format;
if( 'version' in config_def )
adaptor_name += '_v'+config_def.version;
adaptor_name.replace( /\W/g,'' );
return require([adaptor_name], function(adaptor_class) {
callback( new adaptor_class( config_def ) );
});
};

/**
* Add a function to be executed once JBrowse is initialized
Expand All @@ -561,15 +467,6 @@ Browser.prototype.addDeferred = function(f) {
this.deferredFunctions.push(f);
};

/**
* Merge in some additional configuration data. Properties in the
* passed configuration will override those properties in the existing
* configuration.
*/
Browser.prototype.addConfigData = function( /**Object*/ config_data ) {
Util.deepUpdate( this.config, config_data );
};

/**
* @param refSeqs {Array} array of refseq records to add to the browser
*/
Expand Down
3 changes: 1 addition & 2 deletions src/JBrowse/ConfigAdaptor/JB_json_v0.js
Expand Up @@ -51,8 +51,7 @@ return declare('JBrowse.ConfigAdaptor.JB_json_v0',JB_json_v1,
*/
parse_conf: function( conf_text ) {
conf_text.replace( /^[^\{]+/, '' );
var conf;
return eval( 'conf = ' + conf_text );
return this.inherited( [conf_text] );
}
});
});
Expand Down
37 changes: 21 additions & 16 deletions src/JBrowse/ConfigAdaptor/JB_json_v1.js
Expand Up @@ -25,20 +25,26 @@ return declare('JBrowse.ConfigAdaptor.JB_json_v1',null,
*/
load: function( /**Object*/ args ) {
var that = this;
dojo.xhrGet({
url: args.config.url,
handleAs: 'text',
load: function( o ) {
o = that.parse_conf( o, args );
o = that.regularize_conf( o, args );
args.onSuccess.call( args.context || this, o );
},
error: function( i ) {
console.error( ''+i );
if( args.onFailure )
args.onFailure.call( args.context || this, i);
}
});
if( args.config.url ) {
dojo.xhrGet({
url: args.config.url,
handleAs: 'text',
load: function( o ) {
o = that.parse_conf( o, args );
o = that.regularize_conf( o, args );
args.onSuccess.call( args.context || this, o );
},
error: function( i ) {
console.error( ''+i );
if( args.onFailure )
args.onFailure.call( args.context || this, i);
}
});
}
else if( args.config.data ) {
var conf = this.regularize_conf( args.config.data, args );
args.onSuccess.call( args.context || this, conf );
}
},

/**
Expand All @@ -49,8 +55,7 @@ return declare('JBrowse.ConfigAdaptor.JB_json_v1',null,
* @returns {Object} the parsed JSON
*/
parse_conf: function( conf_text, load_args ) {
var conf;
return eval( 'conf = ' + conf_text );
return dojo.fromJson( conf_text );
},

/**
Expand Down
158 changes: 158 additions & 0 deletions src/JBrowse/ConfigManager.js
@@ -0,0 +1,158 @@

//////////////////////////////

define(
[
'dojo/_base/declare'
],
function( declare ) { return declare(null,

/**
* @lends JBrowse.ConfigManager.prototype
*/
{

/**
* @constructs
*/
constructor: function( args ) {
this.browser = args.browser;
},

load: function( inputConfig, callback ) {

},

/**
* Instantiate the right config adaptor for a given configuration source.
* @param {Object} config the configuraiton
* @param {Function} callback called with the new config object
* @returns {Object} the right configuration adaptor to use, or
* undefined if one could not be found
*/

_getConfigAdaptor: function( config_def, callback ) {
var adaptor_name = "JBrowse/ConfigAdaptor/" + config_def.format;
if( 'version' in config_def )
adaptor_name += '_v'+config_def.version;
adaptor_name.replace( /\W/g,'' );
return require([adaptor_name], function(adaptor_class) {
callback( new adaptor_class( config_def ) );
});
},

_loadIncludes: function( inputConfig, callback ) {
var config = dojo.clone( inputConfig );

// coerce include to an array
if( typeof config.include != 'object' || !config.include.length )
config.include = [ config.include ];

// coerce bare strings in the includes to URLs
for (var i = 0; i < config.include.length; i++) {
if( typeof config.include[i] == 'string' )
config.include[i] = { url: config.include[i] };
}

// fetch and parse all the configuration data
var configs_remaining = config.include.length;
var included_configs = dojo.map( config.include, function(config) {
var loadingResult = {};

// include array might have undefined elements in it if
// somebody left a trailing comma in and we are running under
// IE
if( !config )
return loadingResult;

// set defaults for format and version
if( ! ('format' in config) ) {
config.format = 'JB_json';
}
if( config.format == 'JB_json' && ! ('version' in config) ) {
config.version = 1;
}

// instantiate the adaptor and load the config
this.getConfigAdaptor( config, dojo.hitch(this, function(adaptor) {
if( !adaptor ) {
loadingResult.error = "Could not load config "+config.url+", no configuration adaptor found for config format "+config.format+' version '+config.version;
return;
}

adaptor.load({
config: config,
context: this,
onSuccess: function( config_data ) {
loadingResult.config = config_data;
if( ! --configs_remaining )
mergeConfigs();
//if you need a backtrace: window.setTimeout( function() { that.onConfigLoaded(); }, 1 );
},
onFailure: function( error ) {
loadingResult.error = error;
if( ! --configs_remaining )
mergeConfigs();
//if you need a backtrace: window.setTimeout( function() { that.onConfigLoaded(); }, 1 );
}
});
}));
return loadingResult;
}, this);

},

/**
* Merge in some additional configuration data. Properties in the
* passed configuration will override those properties in the existing
* configuration.
*/
addConfigData: function( /**Object*/ config_data ) {
Util.deepUpdate( this.config, config_data );
},

/**
* Examine the loaded and merged configuration for errors. Throws
* exceptions if it finds anything amiss.
* @returns nothing meaningful
*/
validateConfig: function() {
var c = this.config;
if( ! c.tracks ) {
this.fatalError( 'No tracks defined in configuration' );
}
if( ! c.baseUrl ) {
this.fatalError( 'Must provide a <code>baseUrl</code> in configuration' );
}
if( this.hasFatalErrors )
throw "Errors in configuration, aborting.";
},

onConfigLoaded: function() {

var initial_config = this.config;
this.config = {};

// load all the configuration data in order
dojo.forEach( initial_config.include, function( config ) {
if( config.loaded && config.data )
this.addConfigData( config.data );
}, this );

// load the initial config (i.e. constructor params) last so that
// it overrides the other config
this.addConfigData( initial_config );

this.validateConfig();

// index the track configurations by name
this.trackConfigsByName = {};
dojo.forEach( this.config.tracks || [], function(conf){
this.trackConfigsByName[conf.label] = conf;
},this);

}

});
});

0 comments on commit 4f9ef04

Please sign in to comment.