web-components/i-gene/components/chopchop_importer.js

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);