207 lines
9.5 KiB
JavaScript
207 lines
9.5 KiB
JavaScript
class ChopChopImporter extends AbstractImporter {
|
|
|
|
#id = null;
|
|
#runinfo = null;
|
|
#query = null;
|
|
#cut = null;
|
|
#vis = null;
|
|
|
|
constructor(){
|
|
super(new ChopChopHelper())
|
|
}
|
|
|
|
render(){
|
|
this.getRootDoc().innerHTML = `
|
|
<link href="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js rel="stylesheet" crossorigin="anonymous">
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5>Import from <a href="https://chopchop.cbu.uib.no" target="_new">CHOPCHOP</a></h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<label for="basic-url" class="form-label">Enter your CHOPCHOP job URL</label>
|
|
<div class="input-group mb-3">
|
|
<span class="input-group-text">https://chopchop.cbu.uib.no/results/</span>
|
|
<input value="" type="text" class="form-control" id="chopchop_job_id" placeholder="CHOPCHOP job id (e.g.: 1684831154920.0437)" data-bs-toggle="tooltip" title="You can drag-and-drop or copy-and-paste CHOPCHOP address or directly write"/>
|
|
<button class="btn btn-outline-primary" type="button" id="chopchop_import_button">Import</button>
|
|
</div>
|
|
<label for="basic-url" class="form-label">Or import a Chopchop TSV exported file or from a D4Science Workspace file share long URL (e.g. https://data.d4science.net/shub/E_TnRRST...)</label>
|
|
<div class="input-group mb-3">
|
|
<div><input class="btn btn-outline-primary" type="file" accept=".tsv" id="chopchop_file"><input class="btn btn-outline-primary" type="url" placeholder="https://data.d4science.net/shub/E_TnRRST..." pattern="https://data.d4science.net/shub/.*" size="34" id="chopchop_url"></div>
|
|
<select class="form-select" id="chopchop_file_genome">
|
|
<option value="">-- Select the Genome --</option>
|
|
<option value="danRer10">Danio rerio (danRer10)</option>
|
|
<option value="danRer11">Danio rerio (danRer11)</option>
|
|
<option value="hg19">Homo sapiens (hg19)</option>
|
|
<option value="hg38">Homo sapiens (hg38)</option>
|
|
<option value="mm10">Mus musculus (mm10)</option>
|
|
<option value="mm39">Mus musculus (mm39)</option>
|
|
</select>
|
|
<select class="form-select" id="chopchop_file_pam"/>
|
|
<option value="">-- Select the PAM --</option>
|
|
<option value="NGG">NGG</option>
|
|
<option value="NAG">NAG</option>
|
|
<option value="NGA">NGA</option>
|
|
<option value="NRG">NRG (R = A or G)</option>
|
|
</select>
|
|
<button class="btn btn-outline-primary" type="button" id="chopchop_file_import_button">Import</button>
|
|
</div>
|
|
</div>
|
|
<div class="card-footer">
|
|
<a name="trigger" class="d-none" href="#"><a/>
|
|
</div>
|
|
</div>
|
|
`
|
|
this.getRootDoc().querySelector("#chopchop_job_id").addEventListener("paste", ev=> {
|
|
const contents = ev.clipboardData.getData('text');
|
|
if (contents.indexOf('/results/') > 0) {
|
|
ev.preventDefault();
|
|
this.getRootDoc().querySelector("#chopchop_job_id").value = contents.substring(contents.indexOf("/results/") + 9, contents.indexOf("/details/") != -1 ? contents.indexOf("/details/") + 1 : contents.length);
|
|
}
|
|
});
|
|
this.getRootDoc().querySelector("#chopchop_job_id").addEventListener("drop", ev=> {
|
|
const uri = ev.dataTransfer.getData("text/uri-list");
|
|
if (uri.indexOf('/results/') > 0) {
|
|
ev.preventDefault();
|
|
ev.stopPropagation();
|
|
this.getRootDoc().querySelector("#chopchop_job_id").value = uri.substring(uri.indexOf("/results/") + 9, uri.indexOf("/details/") != -1 ? uri.indexOf("/details/") + 1 : uri.length);
|
|
}
|
|
});
|
|
this.getRootDoc().querySelector("#chopchop_import_button").addEventListener("click", ev=> {
|
|
this.#id = this.getRootDoc().querySelector("#chopchop_job_id").value
|
|
if (this.#id == null || this.#id == '') {
|
|
alert("Please, enter the CHOPCHOP job id to import");
|
|
return;
|
|
}
|
|
if (this.#id.endsWith('/')) {
|
|
this.#id = this.#id.substring(0, this.#id.length - 1)
|
|
}
|
|
this.import()
|
|
})
|
|
this.getRootDoc().querySelector("#chopchop_file_import_button").addEventListener("click", ev=> {
|
|
const tsvFile = this.getRootDoc().querySelector("#chopchop_file").files[0];
|
|
const tsvURL = this.getRootDoc().querySelector("#chopchop_url").value;
|
|
if ((tsvFile == null || tsvFile == '') && (tsvURL == null || tsvURL == '')) {
|
|
alert("Please, select/enter the CHOPCHOP's TSV file/URL to import first");
|
|
return;
|
|
}
|
|
const genome = this.getGenomeFromInput()
|
|
if (genome == null || genome == '') {
|
|
alert("Please, select the Genome first");
|
|
return;
|
|
}
|
|
const pam = this.getPAMFromInput();
|
|
if (pam == null || pam == '') {
|
|
alert("Please, select the PAM first");
|
|
return;
|
|
}
|
|
if (tsvFile != null && tsvFile != '') {
|
|
this.importTSVExport(tsvFile, genome, pam);
|
|
} else {
|
|
this.importTSVURL(tsvURL, genome, pam);
|
|
}
|
|
})
|
|
|
|
this.getRootDoc().querySelector("a[name=trigger]").addEventListener("click", ev=> {
|
|
ev.preventDefault()
|
|
ev.stopPropagation()
|
|
|
|
if(this.getDatadisplay()){
|
|
this.getDatadisplay().show(this)
|
|
}
|
|
})
|
|
}
|
|
|
|
getGenomeFromInput() {
|
|
return this.getRootDoc().querySelector("#chopchop_file_genome").value;
|
|
}
|
|
|
|
getPAMFromInput() {
|
|
return this.getRootDoc().querySelector("#chopchop_file_pam").value;
|
|
}
|
|
|
|
import() {
|
|
this.downloadData()
|
|
.then(v=>{
|
|
const runinfo = v[0].split("\t")
|
|
this.#runinfo = {
|
|
targets : runinfo[0],
|
|
genome : runinfo[1],
|
|
mode : runinfo[2],
|
|
uniqueMethod_cong : runinfo[3],
|
|
quideSize : runinfo[4]
|
|
}
|
|
this.#query = JSON.parse(v[1])
|
|
this.parseTSV(v[2])
|
|
this.#cut = JSON.parse(v[3])
|
|
this.#vis = JSON.parse(v[4])
|
|
|
|
this.setIndexer(new iGeneIndexer(this.getTableLines(), this.getGenomeFromRunInfo(), this.getPAMFromRunInfo(), this.getHelper()));
|
|
this.enableData();
|
|
}).catch(err=>console.error(err))
|
|
}
|
|
|
|
downloadData() {
|
|
const base = "http://chopchop.cbu.uib.no/results/" + this.#id + "/";
|
|
const urls = [base + "run.info", base + "query.json", base + "results.tsv", base + "cutcoords.json", base + "viscoords.json"];
|
|
const fetches = urls.map(u => {
|
|
return iGeneIndexer.fetchViaCORSProxy(u).then(r => { if(r.status !== 200) throw "Error fetching CHOPCHOP job via CORS proxy..."; else return r.text() });
|
|
})
|
|
return Promise.all(fetches);
|
|
}
|
|
|
|
enableData(){
|
|
const a = this.getRootDoc().querySelector("a[name=trigger]")
|
|
if (this.#query != null) {
|
|
a.textContent = `
|
|
Show ${this.getTableLines().length} matches on genome ${this.getGenomeFromRunInfo()} ${this.getShortInput()} for ${this.#query.forSelect}
|
|
`
|
|
} else {
|
|
a.textContent = `
|
|
Show ${this.getTableLines().length} matches from imported TSV data
|
|
`
|
|
}
|
|
a.classList.remove("d-none")
|
|
}
|
|
|
|
#API
|
|
getGenomeFromRunInfo() {
|
|
return this.#runinfo.genome;
|
|
}
|
|
|
|
getPAMFromRunInfo() {
|
|
let pam = 'NGG' // PAM is initialized with default value of the Cas9 sequence, then is copied from result's '-M' query parameter, if defined
|
|
this.#query.opts.forEach((element, index) => {
|
|
if (element == '-M') {
|
|
pam = this.#query.opts[index +1];
|
|
}
|
|
});
|
|
return pam;
|
|
}
|
|
|
|
getShortInput(){
|
|
if (this.#runinfo != null) {
|
|
var input = ""
|
|
if(this.#query.geneInput === ""){
|
|
input = "fasta " + this.#query.fastaInput.length > 10 ? this.#query.fastaInput.substring(0,10) + "..." : this.#query.fastaInput
|
|
}else{
|
|
input = "gene " + this.#query.geneInput
|
|
}
|
|
return input
|
|
} else {
|
|
return "[No info]"
|
|
}
|
|
}
|
|
|
|
getHeader(){
|
|
if (this.#runinfo != null) {
|
|
return `Imported from CHOPCHOP job ${this.#id}: ${this.getGenomeFromRunInfo()} ${this.getShortInput()}`;
|
|
} else {
|
|
return `Imported from CHOPCHOP TSV export: ${this.getGenomeFromInput()} - ${this.getPAMFromInput()}`;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
window.customElements.define('igene-chopchop-importer', ChopChopImporter);
|