diff --git a/README.md b/README.md index 4c6655f..6ee762c 100644 --- a/README.md +++ b/README.md @@ -709,10 +709,10 @@ There are few things that can be setup from outside: - **`algorithms`** (attr. `data-algorithms`): Whether to list available algorithms, rather than available models. Default: _false_. - **`maxStars`** (attr. `data-max-stars`): How many stars are considered maximum, when building the long version of ratings. Default: _10_. - **`shortStars`** (attr. `data-short-stars`): Whether to show show star rating notation, i.e. - one star and the number of stars next to it, opposed to the long (default) version - always showing the maximum number of stars, with given number of them - highlighted. Default is _false_. -- **`loadOnInit`** (attr. `data-load-on-init`): Whether to make an initial query even when _modelUri_ or _algorithmNeedle_ are not specified. Default is _false_. +- **`loadOnInit`** (attr. `data-load-on-init`): Whether to make an initial query even when _modelUri_ or _algorithmFilter_ are not specified. Default is _false_. - **`sDom`** (attr. `data-s-dom`): The redefinition of _sDom_ attribute for the table. Default _"\rt"_. - **`modelUri`** (attr. `data-model-uri`): The address to query for list of models. If none is passed, the standard `/model` is used. -- **`algorithmNeedle`** (attr. `data-algorithms-needle`): If algorithms listing mode is selected (`algorithms` = _true_) - this is the needle to be used when listing them. Default: _null_. +- **`algorithmFilter`** (attr. `data-algorithm-filter`): If algorithms listing mode is selected (`algorithms` = _true_) - this is the needle to be used when listing them. Default: _null_. - **`forceCreate`** (attr. `data-force-create`): When creating a model from an algorithm, the kit usually tries to obtain one from the server, and only if that fails it makes a _create model_ query, unless this option is specified, which instructs the kit to directly try to create a new one. Default _false_. diff --git a/scripts/toxcompound.js b/scripts/toxcompound.js index 90e0bf9..cf1477d 100644 --- a/scripts/toxcompound.js +++ b/scripts/toxcompound.js @@ -1034,7 +1034,7 @@ cls.prototype.init = function () { var feat = jT.$.extend({}, features[fId]); feat.value = entry.values[fId]; if (!!feat.title) { - if (ccLib.fireCallback(callback, null, feat, fId) !== false) { + if (ccLib.fireCallback(callback, null, feat, fId, data.length) !== false) { if (!feat.value) feat.value = '-'; data.push(feat); diff --git a/scripts/toxmodel.js b/scripts/toxmodel.js index cddcff7..5ceda65 100644 --- a/scripts/toxmodel.js +++ b/scripts/toxmodel.js @@ -17,7 +17,7 @@ var jToxModel = (function () { sDom: "rt", // merged to dataTable's settings, when created loadOnInit: false, // whether to make a (blank) request upon loading oLanguage: null, // merged to dataTable's settings, when created - /* algorithmNeedle */ + /* algorithmFilter */ /* modelUri */ configuration: { columns : { @@ -64,7 +64,7 @@ var jToxModel = (function () { } // finally, wait a bit for everyone to get initialized and make a call, if asked to - if (self.settings.modelUri != null || self.settings.algorithmNeedle != null || self.settings.loadOnInit) + if (self.settings.modelUri != null || self.settings.algorithmFilter != null || self.settings.loadOnInit) self.query(); }; @@ -222,7 +222,7 @@ var jToxModel = (function () { cls.prototype.query = function (uri) { if (this.settings.algorithms) - this.listAlgorithms(this.settings.algorithmNeedle = (uri || this.settings.algorithmNeedle)); + this.listAlgorithms(this.settings.algorithmFilter = (uri || this.settings.algorithmFilter)); else this.listModels(this.settings.modelUri = (uri || this.settings.modelUri)); }; diff --git a/toxmodel.html b/toxmodel.html index 156ca3d..124bb16 100644 --- a/toxmodel.html +++ b/toxmodel.html @@ -28,7 +28,7 @@ -
+
diff --git a/uses/ui-toxtree.css b/uses/ui-prediction.css similarity index 99% rename from uses/ui-toxtree.css rename to uses/ui-prediction.css index fdabef4..01e5ab8 100644 --- a/uses/ui-toxtree.css +++ b/uses/ui-prediction.css @@ -95,6 +95,7 @@ body>div.jtox-toolkit { #tt-models-panel .content .tt-explanation { margin: 5px; + padding: 5px; background: #fefefe; border: 1px solid #aaa; border-radius: 5px; diff --git a/uses/ui-toxtree.html b/uses/ui-prediction.html similarity index 88% rename from uses/ui-toxtree.html rename to uses/ui-prediction.html index 8a39e99..0594592 100644 --- a/uses/ui-toxtree.html +++ b/uses/ui-prediction.html @@ -8,7 +8,7 @@ - ToxTree web interface + Model Prediction @@ -18,7 +18,7 @@ - + @@ -32,12 +32,12 @@ - + -
+
@@ -59,9 +59,9 @@
Toxicity prediction modules (0/0)
-
+
-
+
-
-
-
-
-
+
+
diff --git a/uses/ui-toxtree.js b/uses/ui-prediction.js similarity index 75% rename from uses/ui-toxtree.js rename to uses/ui-prediction.js index 110705e..14c3733 100644 --- a/uses/ui-toxtree.js +++ b/uses/ui-prediction.js @@ -20,7 +20,7 @@ var tt = { ] }; -var config_toxtree = { +var config_model = { "baseFeatures": {}, // to be expanded upon algorithm loading "handlers": { "query": function (e, query) { @@ -42,7 +42,7 @@ var config_toxtree = { "http://www.opentox.org/api/1.1#EINECS", "http://www.opentox.org/api/1.1#IUCLID5_UUID" ], - "ToxTree": [] // to be expanded upon algorithm loading + "Models": [] // to be expanded upon algorithm loading } }; @@ -121,50 +121,36 @@ function runSelected() { } function formatAlgoName(val) { - return (val.indexOf('ToxTree: ') == 0) ? val = val.substr(9) : val; + return val.replace(/^\w+:\s+/, ""); } -function buildCategories(features, values) { - var cats = []; - var regex = /\^\^(\S+)Category/i; - var multi = false; - - for (var fId in values) { - if (features[fId].title.indexOf('#explanation') > -1 || features[fId].source.type.toLowerCase() != 'model') - continue; - var val = values[fId]; - var anot = features[fId].annotation; - if (anot.length > 0) { - if (cats.length > 0) - multi = true; - for (var i = 0;i < anot.length; ++i) { - cats.push({ - name: features[fId].title.replace(/\s/g, ' '), - title: anot[i].o.replace(/\s/g, ' '), - toxicity: anot[i].type.replace(regex, '$1').toLowerCase(), - active: anot[i].o == val - }); - } - } - else - cats.push({ - name: features[fId].title.replace(/\s/g, ' '), - title: val, - toxicity: 'unknown', - active: true - }); - }; - - if (multi) { - var old = cats; - cats = []; - $.map(old, function (o) { +function mergeCategories(features, indices) { + var cats = []; + for (var i = 0; i < indices.length; ++i) { + $.map(features[indices[i]].categories, function (o) { if (o.active) { o.title = o.name + ': ' + o.title; cats.push(o); } - }); + }); + } + + return cats; +} +function buildCategories(feature) { + anot = feature.annotation; + if (!anot || anot.length == 0) + return null; + var cats = [], + regex = /\^\^(\S+)Category/i; + for (var i = 0;i < anot.length; ++i) { + cats.push({ + name: feature.title.replace(/\s/g, ' '), + title: anot[i].o.replace(/\s/g, ' '), + toxicity: anot[i].type.replace(regex, '$1').toLowerCase(), + active: anot[i].o == feature.value + }); } return cats; @@ -204,8 +190,8 @@ function onAlgoLoaded(result) { }; $(this).data('algoId', data.id); - config_toxtree.groups.ToxTree.push(data.uri); - config_toxtree.baseFeatures[data.uri] = { + config_model.groups.Models.push(data.uri); + config_model.baseFeatures[data.uri] = { title: formatAlgoName(data.name), search: false, data: "index", @@ -244,7 +230,7 @@ function addFeatures(data, className) { enumFn = function () { $(this).addClass(className); }; $('.' + className, tt.featuresList).remove(); } - ccLib.populateData(tt.featuresList, '#tt-feature', data, enumFn); + ccLib.populateData(tt.featuresList, '#tt-feature', data.filter(function (e) { return e.explanation == null; }), enumFn); var sep = $('#tt-feature')[0].cloneNode(true); sep.removeAttribute('id'); $(sep).addClass('separator').empty(); @@ -307,51 +293,120 @@ function showCompound() { } function showPrediction(algoId) { - var map = tt.algoMap[algoId]; - var mapRes = map.results[tt.compoundIdx]; + var map = tt.algoMap[algoId], + mapRes = map.results[tt.compoundIdx]; // check if we have results for this guy at all... if (mapRes == null || mapRes.data == null) return; - addFeatures(mapRes.data, algoId); - var aEl = map.dom; - if (mapRes.explanation != null) - $('.tt-explanation', aEl).html(mapRes.explanation.replace(/(Yes|No)/g, '$1')); + var aEl = map.dom, + $expEl = $('.content', aEl).empty(); + + if (mapRes.submodels && mapRes.submodels.length) { + mapRes.submodels.forEach(function (el, subIdx) { + addFeatures(el.data, algoId + "-" + subIdx); + if (!el.explanation) { + el.explanation = ""; + el.data.forEach(function (feature) { + if (!feature.annotation || !feature.annotation.length) + el.explanation += feature.title + " : " + jT.ui.valueWithUnits(feature.value, feature.units) + "
"; + }); + } + + if (!!el.explanation) + $expEl.append('
' + el.explanation + '
'); + }); + } + else { // Singe model mode + addFeatures(mapRes.data, algoId); + if (mapRes.explanation != null) + $expEl.append('
' + mapRes.explanation + '
'); + } + $('.tt-classification', aEl).empty(); - - fillClassification($('.tt-classification', aEl)[0], mapRes.categories); $(aEl).removeClass('folded'); } +function splitFeatures(features) { + var lastURI = features[0].source.URI, + subs = [], + catFeatures = [], + descIndex = null; + + for (var e, i = 0;; ++i) { + if (i >= features.length || features[i].source.URI != lastURI) { + e = { data: features.splice(0, i) }; + if (catFeatures.length > 1) + e.categories = mergeCategories(e.data, catFeatures); + else if (catFeatures.length == 1) + e.categories = e.data[catFeatures[0]].categories; + + if (descIndex != null) + e.explanation = e.data[descIndex].explanation; + + subs.push(e); + + i = 0; + descIndex = null; + catFeatures = []; + } + + if (i >= features.length) + break; + else if (features[i].explanation != null) + descIndex = i; + else if (features[i].categories != null) + catFeatures.push(i); + lastURI = i < features.length ? features[i].source.URI : null; + } + + return subs; +} + function parsePrediction(result, algoId, index) { var map = tt.algoMap[algoId]; var cells = $('#tt-table table td.' + algoId); for (var i = 0, rl = result.dataEntry.length; i < rl; ++i) { - var idx = i + (index || 0); - var mapRes = map.results[idx]; - if (mapRes == null){ + var idx = i + (index || 0), + mapRes = map.results[idx], + catFeatures = []; + + if (mapRes == null) map.results[idx] = mapRes = {}; - } - mapRes.explanation = ''; - mapRes.data = jToxCompound.extractFeatures(result.dataEntry[i], result.feature, function (feature, fId) { - if (feature.title.indexOf("#explanation") > -1) { - mapRes.explanation = feature.value; + + mapRes.data = jToxCompound.extractFeatures(result.dataEntry[i], result.feature, function (feature, fId, fIdx) { + if (feature.source.type.toLowerCase() != 'model' || !feature.value) return false; + + if (feature.title.endsWith("#explanation")) + feature.explanation = feature.value.replace(/\W(Yes|No)\W/g, '$&'); + else { + feature.categories = buildCategories(feature); + if (feature.categories != null) + catFeatures.push(fIdx) } - else if (feature.source.type.toLowerCase() == 'model' && !!feature.value) - return true; - else - return false; + return true; }); - mapRes.categories = buildCategories(result.feature, result.dataEntry[i].values); + // Make the combined categories in any case for the table mode + if (catFeatures.length > 1) + mapRes.categories = mergeCategories(mapRes.data, catFeatures); + else if (catFeatures.length == 1) + mapRes.categories = mapRes.data[catFeatures[0]].categories; - if (mapRes.categories.length == 0 && index == null){ - runPredict ($('button', cells[idx]), algoId); + if (tt.modelKit.settings.multiModels && mapRes.data.length > 1) { + mapRes.data.sort(function (a, b) { return a.title < b.title ? -1 : (a.title > b.title ? 1 : 0); }); + mapRes.submodels = splitFeatures(mapRes.data); } + else // !multiModels + mapRes.explanation = mapRes.data.find(function (e) { return e.explanation != null; }).explanation; + + // Finally, fill the table cell. + if (mapRes.categories.length == 0 && index == null) + runPredict ($('button', cells[idx]), algoId); else { $('.tt-class', cells[idx]).remove(); $(cells[idx]).addClass('calculated'); diff --git a/www/jtoxkit-1.0.0.js b/www/jtoxkit-1.0.0.js index 97b8c73..87e68b1 100644 --- a/www/jtoxkit-1.0.0.js +++ b/www/jtoxkit-1.0.0.js @@ -2803,7 +2803,7 @@ cls.prototype.init = function () { var feat = jT.$.extend({}, features[fId]); feat.value = entry.values[fId]; if (!!feat.title) { - if (ccLib.fireCallback(callback, null, feat, fId) !== false) { + if (ccLib.fireCallback(callback, null, feat, fId, data.length) !== false) { if (!feat.value) feat.value = '-'; data.push(feat); @@ -3024,7 +3024,7 @@ var jToxModel = (function () { sDom: "rt", // merged to dataTable's settings, when created loadOnInit: false, // whether to make a (blank) request upon loading oLanguage: null, // merged to dataTable's settings, when created - /* algorithmNeedle */ + /* algorithmFilter */ /* modelUri */ configuration: { columns : { @@ -3071,7 +3071,7 @@ var jToxModel = (function () { } // finally, wait a bit for everyone to get initialized and make a call, if asked to - if (self.settings.modelUri != null || self.settings.algorithmNeedle != null || self.settings.loadOnInit) + if (self.settings.modelUri != null || self.settings.algorithmFilter != null || self.settings.loadOnInit) self.query(); }; @@ -3229,7 +3229,7 @@ var jToxModel = (function () { cls.prototype.query = function (uri) { if (this.settings.algorithms) - this.listAlgorithms(this.settings.algorithmNeedle = (uri || this.settings.algorithmNeedle)); + this.listAlgorithms(this.settings.algorithmFilter = (uri || this.settings.algorithmFilter)); else this.listModels(this.settings.modelUri = (uri || this.settings.modelUri)); }; diff --git a/www/jtoxkit-1.0.0.min.js b/www/jtoxkit-1.0.0.min.js index d6aca5c..f4f72b4 100644 --- a/www/jtoxkit-1.0.0.min.js +++ b/www/jtoxkit-1.0.0.min.js @@ -379,7 +379,7 @@ fnValue=defaultSettings.fnAccumulate;for(var fid in entry.values){var feature=fe continue;var newVal=entry.values[fid];if(!!feature.accumulate&&!!newVal&&!!feature.data){var fn=typeof feature.accumulate=='function'?feature.accumulate:fnValue;var accArr=feature.data;if(!jT.$.isArray(accArr)) accArr=[accArr];for(var v=0;v'+data+'; '+ (full.isSupevised?'Supervised; ':'')+ ''+full.implementationOf+'';}}}}}};var cls=function(root,settings){var self=this;self.rootElement=root;jT.$(root).addClass('jtox-toolkit');self.settings=jT.$.extend(true,{},defaultSettings,jT.settings,settings);self.models=null;if(!self.settings.noInterface){self.rootElement.appendChild(jT.getTemplate('#jtox-model'));self.init(settings);} -if(self.settings.modelUri!=null||self.settings.algorithmNeedle!=null||self.settings.loadOnInit) +if(self.settings.modelUri!=null||self.settings.algorithmFilter!=null||self.settings.loadOnInit) self.query();};cls.prototype.init=function(settings){var self=this;if(!self.settings.algorithms){self.settings.configuration.columns.model.Stars.mRender=function(data,type,full){return type!='display'?data:jT.ui.putStars(self,data,"Model star rating (worst) 1 - 10 (best)");};if(self.settings.shortStars) self.settings.configuration.columns.model.Stars.sWidth="40px";self.settings.configuration.columns.model.Algorithm.mRender=function(data,type,full){var name=data.URI.match(/https{0,1}:\/\/.*\/algorithm\/(\w+).*/)[1];if(type!='display') return name;var res=''+ @@ -448,7 +448,7 @@ createIt();else ccLib.fireCallback(callback,self,result,jhr)} else createIt();});};cls.prototype.query=function(uri){if(this.settings.algorithms) -this.listAlgorithms(this.settings.algorithmNeedle=(uri||this.settings.algorithmNeedle));else +this.listAlgorithms(this.settings.algorithmFilter=(uri||this.settings.algorithmFilter));else this.listModels(this.settings.modelUri=(uri||this.settings.modelUri));};cls.prototype.modifyUri=function(uri){jT.$('input[type="checkbox"]',this.rootElement).each(function(){if(this.checked) uri=ccLib.addParameter(uri,'feature_uris[]='+encodeURIComponent(this.value+'/predicted'));}) return uri;};return cls;})();var jToxSubstance=(function(){var defaultSettings={showControls:true,selectionHandler:null,embedComposition:null,noInterface:false,onDetails:null,onLoaded:null,oLanguage:{"sLoadingRecords":"No substances found.","sZeroRecords":"No substances found.","sEmptyTable":"No substances available.","sInfo":"Showing _TOTAL_ substance(s) (_START_ to _END_)"},pageStart:0,pageSize:10,configuration:{columns:{substance:{'Id':{sTitle:'Id',mData:'URI',sDefaultContent:"-",sWidth:"60px",mRender:function(data,type,full){return(type!='display')?full.index:' - '+full.index+' - ';}},'Substance Name':{sTitle:"Substance Name",mData:"name",mRender:function(data,type,full){if(data==null||data=='null')data='-';return(type!='display')?data:jT.ui.linkedData(''+data+'',"Click to view study details",data)}},'Substance UUID':{sTitle:"Substance UUID",mData:"i5uuid",mRender:function(data,type,full){if(data==null||data=='null')return'';return(type!='display')?data:jT.ui.shortenedData(''+data+'',"Press to copy the UUID in the clipboard",data)}},'Substance Type':{sTitle:"Substance Type",mData:"substanceType",sWidth:"15%",sDefaultContent:'-'},'Public name':{sTitle:"Public name",mData:"publicname",sDefaultContent:'-'},'Reference substance UUID':{sTitle:"Reference substance UUID",mData:"referenceSubstance",mRender:function(data,type,full){if(data.i5uuid==null||data.i5uuid=='null')return'';return(type!='display')?data.i5uuid:jT.ui.shortenedData(''+data.i5uuid+'',"Press to copy the UUID in the clipboard",data.i5uuid);}},'Owner':{sTitle:"Owner",mData:"ownerName",sDefaultContent:'-'},'Info':{sTitle:"Info",mData:"externalIdentifiers",mRender:function(data,type,full){return jToxSubstance.formatExtIdentifiers(data,type,full);}}}}}};var cls=function(root,settings){var self=this;self.rootElement=root;jT.$(root).addClass('jtox-toolkit');self.settings=jT.$.extend(true,{},defaultSettings,jT.settings,settings);self.pageStart=self.settings.pageStart;self.pageSize=self.settings.pageSize;if(!self.settings.noInterface){if(self.settings.embedComposition&&self.settings.onDetails==null){self.settings.onDetails=function(root,data,element){new jToxComposition(root,jT.$.extend({},self.settings,(typeof self.settings.embedComposition=='object'?self.settings.embedComposition:jT.blankSettings),{compositionUri:data.URI+'/composition'}));};} diff --git a/www/jtoxkit.js b/www/jtoxkit.js index 97b8c73..87e68b1 100644 --- a/www/jtoxkit.js +++ b/www/jtoxkit.js @@ -2803,7 +2803,7 @@ cls.prototype.init = function () { var feat = jT.$.extend({}, features[fId]); feat.value = entry.values[fId]; if (!!feat.title) { - if (ccLib.fireCallback(callback, null, feat, fId) !== false) { + if (ccLib.fireCallback(callback, null, feat, fId, data.length) !== false) { if (!feat.value) feat.value = '-'; data.push(feat); @@ -3024,7 +3024,7 @@ var jToxModel = (function () { sDom: "rt", // merged to dataTable's settings, when created loadOnInit: false, // whether to make a (blank) request upon loading oLanguage: null, // merged to dataTable's settings, when created - /* algorithmNeedle */ + /* algorithmFilter */ /* modelUri */ configuration: { columns : { @@ -3071,7 +3071,7 @@ var jToxModel = (function () { } // finally, wait a bit for everyone to get initialized and make a call, if asked to - if (self.settings.modelUri != null || self.settings.algorithmNeedle != null || self.settings.loadOnInit) + if (self.settings.modelUri != null || self.settings.algorithmFilter != null || self.settings.loadOnInit) self.query(); }; @@ -3229,7 +3229,7 @@ var jToxModel = (function () { cls.prototype.query = function (uri) { if (this.settings.algorithms) - this.listAlgorithms(this.settings.algorithmNeedle = (uri || this.settings.algorithmNeedle)); + this.listAlgorithms(this.settings.algorithmFilter = (uri || this.settings.algorithmFilter)); else this.listModels(this.settings.modelUri = (uri || this.settings.modelUri)); }; diff --git a/www/jtoxkit.min.js b/www/jtoxkit.min.js index d6aca5c..f4f72b4 100644 --- a/www/jtoxkit.min.js +++ b/www/jtoxkit.min.js @@ -379,7 +379,7 @@ fnValue=defaultSettings.fnAccumulate;for(var fid in entry.values){var feature=fe continue;var newVal=entry.values[fid];if(!!feature.accumulate&&!!newVal&&!!feature.data){var fn=typeof feature.accumulate=='function'?feature.accumulate:fnValue;var accArr=feature.data;if(!jT.$.isArray(accArr)) accArr=[accArr];for(var v=0;v'+data+'; '+ (full.isSupevised?'Supervised; ':'')+ ''+full.implementationOf+'';}}}}}};var cls=function(root,settings){var self=this;self.rootElement=root;jT.$(root).addClass('jtox-toolkit');self.settings=jT.$.extend(true,{},defaultSettings,jT.settings,settings);self.models=null;if(!self.settings.noInterface){self.rootElement.appendChild(jT.getTemplate('#jtox-model'));self.init(settings);} -if(self.settings.modelUri!=null||self.settings.algorithmNeedle!=null||self.settings.loadOnInit) +if(self.settings.modelUri!=null||self.settings.algorithmFilter!=null||self.settings.loadOnInit) self.query();};cls.prototype.init=function(settings){var self=this;if(!self.settings.algorithms){self.settings.configuration.columns.model.Stars.mRender=function(data,type,full){return type!='display'?data:jT.ui.putStars(self,data,"Model star rating (worst) 1 - 10 (best)");};if(self.settings.shortStars) self.settings.configuration.columns.model.Stars.sWidth="40px";self.settings.configuration.columns.model.Algorithm.mRender=function(data,type,full){var name=data.URI.match(/https{0,1}:\/\/.*\/algorithm\/(\w+).*/)[1];if(type!='display') return name;var res=''+ @@ -448,7 +448,7 @@ createIt();else ccLib.fireCallback(callback,self,result,jhr)} else createIt();});};cls.prototype.query=function(uri){if(this.settings.algorithms) -this.listAlgorithms(this.settings.algorithmNeedle=(uri||this.settings.algorithmNeedle));else +this.listAlgorithms(this.settings.algorithmFilter=(uri||this.settings.algorithmFilter));else this.listModels(this.settings.modelUri=(uri||this.settings.modelUri));};cls.prototype.modifyUri=function(uri){jT.$('input[type="checkbox"]',this.rootElement).each(function(){if(this.checked) uri=ccLib.addParameter(uri,'feature_uris[]='+encodeURIComponent(this.value+'/predicted'));}) return uri;};return cls;})();var jToxSubstance=(function(){var defaultSettings={showControls:true,selectionHandler:null,embedComposition:null,noInterface:false,onDetails:null,onLoaded:null,oLanguage:{"sLoadingRecords":"No substances found.","sZeroRecords":"No substances found.","sEmptyTable":"No substances available.","sInfo":"Showing _TOTAL_ substance(s) (_START_ to _END_)"},pageStart:0,pageSize:10,configuration:{columns:{substance:{'Id':{sTitle:'Id',mData:'URI',sDefaultContent:"-",sWidth:"60px",mRender:function(data,type,full){return(type!='display')?full.index:' - '+full.index+' - ';}},'Substance Name':{sTitle:"Substance Name",mData:"name",mRender:function(data,type,full){if(data==null||data=='null')data='-';return(type!='display')?data:jT.ui.linkedData(''+data+'',"Click to view study details",data)}},'Substance UUID':{sTitle:"Substance UUID",mData:"i5uuid",mRender:function(data,type,full){if(data==null||data=='null')return'';return(type!='display')?data:jT.ui.shortenedData(''+data+'',"Press to copy the UUID in the clipboard",data)}},'Substance Type':{sTitle:"Substance Type",mData:"substanceType",sWidth:"15%",sDefaultContent:'-'},'Public name':{sTitle:"Public name",mData:"publicname",sDefaultContent:'-'},'Reference substance UUID':{sTitle:"Reference substance UUID",mData:"referenceSubstance",mRender:function(data,type,full){if(data.i5uuid==null||data.i5uuid=='null')return'';return(type!='display')?data.i5uuid:jT.ui.shortenedData(''+data.i5uuid+'',"Press to copy the UUID in the clipboard",data.i5uuid);}},'Owner':{sTitle:"Owner",mData:"ownerName",sDefaultContent:'-'},'Info':{sTitle:"Info",mData:"externalIdentifiers",mRender:function(data,type,full){return jToxSubstance.formatExtIdentifiers(data,type,full);}}}}}};var cls=function(root,settings){var self=this;self.rootElement=root;jT.$(root).addClass('jtox-toolkit');self.settings=jT.$.extend(true,{},defaultSettings,jT.settings,settings);self.pageStart=self.settings.pageStart;self.pageSize=self.settings.pageSize;if(!self.settings.noInterface){if(self.settings.embedComposition&&self.settings.onDetails==null){self.settings.onDetails=function(root,data,element){new jToxComposition(root,jT.$.extend({},self.settings,(typeof self.settings.embedComposition=='object'?self.settings.embedComposition:jT.blankSettings),{compositionUri:data.URI+'/composition'}));};}