@gmod/jbrowse
Version:
JBrowse - client-side genome browser
138 lines (114 loc) • 4.14 kB
JavaScript
/**
* A JBrowse component keeps a reference to the main browser object, and is configurable.
*/
define([
'dojo/_base/declare',
'dojo/_base/lang',
'JBrowse/Util'
],
function(
declare,
lang,
Util
) {
return declare( null, {
constructor: function( args ) {
args = args || {};
// merge our config with the config defaults
this._finalizeConfig( args.config );
this.browser = args.browser;
if( ! this.browser )
throw "a reference to the main browser is required by this constructor";
this.compiledConfig = {};
},
_finalizeConfig: function( config ) {
this.config = this._mergeConfigs( dojo.clone( this._defaultConfig() ), config || {} );
},
_defaultConfig: function() {
return {
baseUrl: '/'
};
},
resolveUrl: function( url, args ) {
args = args || {};
return Util.resolveUrl(
this.getConf('baseUrl',[]),
this.fillTemplate( url, args )
);
},
_mergeConfigs: function(a, b) {
if( b === null )
return null;
if( a === null )
a = {};
for (var prop in b) {
if ((prop in a)
&& ("object" == typeof b[prop])
&& ("object" == typeof a[prop]) ) {
a[prop] = this._mergeConfigs( a[prop], b[prop] );
} else if( typeof a[prop] == 'undefined' || typeof b[prop] != 'undefined' ){
a[prop] = b[prop];
}
}
return a;
},
_compileConfigurationPath: function( path ) {
var confVal = this.config;
if( typeof path == 'string' )
path = path.split('.');
while( path.length && confVal )
confVal = confVal[ path.shift() ];
if( path.length )
return function() { return null; };
return typeof confVal == 'function'
? confVal
: function() { return confVal; };
},
/**
* Given a dot-separated string configuration path into the config
* (e.g. "style.bg_color"), get the value of the configuration.
*
* If args are given, evaluate the configuration using them.
* Otherwise, return a function that returns the value of the
* configuration when called.
*/
getConf: function( path, args ) {
var func = this.compiledConfig[path];
if( ! func ) {
func = this.compiledConfig[path] = this._compileConfigurationPath( path );
}
return args ? func.apply( this, args ) : func.call( this );
},
/**
* Given a string with templating strings like {refseq}, fill them
* in using the given values.
*
* With no additional values given, knows how to interpolate
* {refseq}, {refSeq}, {refSeqNum}, and {refSeqNumNoLeadingZeroes}.
*
* @param {String} str string to interpolate values into
* @param {Object} values optional object with additional values that can be interpolated
* @returns new string with interpolations
*/
fillTemplate: function( str, values ) {
// skip if it's not a string or the string has no interpolations
if( typeof str != 'string' || str.indexOf('{') == -1 )
return str;
// fill in a bunch of args for this.refSeq or this.ref
var templateFillArgs = {
'refseq': (this.refSeq||{}).name || (this.ref||{}).name || this.ref || ''
};
templateFillArgs.refSeq = templateFillArgs.refseq;
if( templateFillArgs.refSeq ) {
templateFillArgs.refSeqNum = ( /\d+/.exec( templateFillArgs.refSeq ) || [] )[0] || '';
}
// make refseqNumNoLeadingZeroes
if( templateFillArgs.refSeqNum ) {
templateFillArgs.refSeqNumNoLeadingZeroes = ( /^0*(\d+)/.exec( templateFillArgs.refSeqNum ) || [] )[1] || '';
}
if( values )
lang.mixin( templateFillArgs, values );
return Util.fillTemplate( str, templateFillArgs );
}
});
});