Skip to content

Commit

Permalink
Fix alignments download bug on safari
Browse files Browse the repository at this point in the history
  • Loading branch information
Lazy-poet committed Jun 19, 2023
1 parent 793c2e2 commit 6409318
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 68 deletions.
24 changes: 16 additions & 8 deletions public/js/alignment_exporter.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import * as Exporter from './exporter';
import _ from 'underscore';
export default class AlignmentExporter {
constructor() {}
constructor() {
this.prepare_alignments_for_export = this.prepare_alignments_for_export.bind(this);
this.export_alignments = this.export_alignments.bind(this);
}

wrap_string(str, width) {
var idx = 0;
Expand Down Expand Up @@ -33,17 +36,22 @@ export default class AlignmentExporter {
return fasta;
}

export_alignments(hsps, filename_prefix) {
get_alignments_download_metadata(hsps, filename_prefix){
var fasta = this.generate_fasta(hsps);

var blob = new Blob([fasta], { type: 'text/fasta' });
// var filename_prefix = query_def + '_' + subject_def;
// var filename_prefix = query_id + '_' + subject_id;
var filename = Exporter.sanitize_filename(filename_prefix) + '.txt';
Exporter.download_blob(blob, filename);
return {filename, blob};
}

export_alignments_of_all(hsps, name) {


prepare_alignments_for_export(hsps, filename_prefix) {
const { filename, blob } = this.get_alignments_download_metadata(hsps, filename_prefix);
const blob_url = Exporter.generate_blob_url(blob, filename);
return blob_url;
}

export_alignments(hsps, filename_prefix) {
const { filename, blob } = this.get_alignments_download_metadata(hsps, filename_prefix);
Exporter.download_blob(blob, filename);
}
}
10 changes: 7 additions & 3 deletions public/js/exporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@ export function download_url(url, filename) {
}, 100);
}

export function generate_blob_url(blob) {
const url = window.URL.createObjectURL(blob);
return url;
}

export function download_blob(blob, filename) {
if (typeof window.navigator.msSaveOrOpenBlob !== 'undefined') {
window.navigator.msSaveOrOpenBlob(blob, filename);
return;
}else{
download_url(generate_blob_url(blob), filename);
}

download_url(window.URL.createObjectURL(blob), filename);
}

export function sanitize_filename(str) {
Expand Down
2 changes: 2 additions & 0 deletions public/js/hit.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export default class extends Component {
var aln_exporter = new AlignmentExporter();
aln_exporter.export_alignments(hsps, this.props.query.id + '_' + this.props.hit.id);
}

headerJSX() {
var meta = `length: ${this.hitLength().toLocaleString()}`;

Expand Down Expand Up @@ -147,6 +148,7 @@ export default class extends Component {
<input type="checkbox" id={this.domID() + '_checkbox'}
value={this.sequenceID()} onChange={function () {
this.props.selectHit(this.domID() + '_checkbox');
this.props.onChange();
}.bind(this)} data-target={'#' + this.domID()}
/> Select
</label>
Expand Down
79 changes: 78 additions & 1 deletion public/js/report.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Circos from './circos';
import { ReportQuery } from './query';
import Hit from './hit';
import HSP from './hsp';
import AlignmentExporter from './alignment_exporter';



Expand Down Expand Up @@ -37,8 +38,12 @@ class Report extends Component {
querydb: [],
params: [],
stats: [],
alignment_blob_url: '',
allQueriesLoaded: false
};
this.prepareAlignmentOfSelectedHits = this.prepareAlignmentOfSelectedHits.bind(this);
this.prepareAlignmentOfAllHits = this.prepareAlignmentOfAllHits.bind(this);
this.setStateFromJSON = this.setStateFromJSON.bind(this);
}
/**
* Fetch results.
Expand Down Expand Up @@ -79,7 +84,8 @@ class Report extends Component {
*/
setStateFromJSON(responseJSON) {
this.lastTimeStamp = Date.now();
this.setState(responseJSON);
// the callback prepares the download link for all alignments
this.setState(responseJSON, this.prepareAlignmentOfAllHits);
}
/**
* Called as soon as the page has loaded and the user sees the loading spinner.
Expand Down Expand Up @@ -165,6 +171,7 @@ class Report extends Component {
showQueryCrumbs={this.state.queries.length > 1}
showHitCrumbs={query.hits.length > 1}
veryBig={this.state.veryBig}
onChange={this.prepareAlignmentOfSelectedHits}
{...this.props}
/>
);
Expand Down Expand Up @@ -468,6 +475,76 @@ class Report extends Component {
}
}

prepareAlignmentOfSelectedHits() {
var sequence_ids = $('.hit-links :checkbox:checked').map(function () {
return this.value;
}).get();

if(!sequence_ids.length){
// remove attributes from link if sequence_ids array is empty
$('.download-alignment-of-selected')
.attr('href', '#')
.removeAttr('download');
return;

}
if(this.state.alignment_blob_url){
// always revoke existing url if any because this method will always create a new url
window.URL.revokeObjectURL(this.state.alignment_blob_url);
}
var hsps_arr = [];
var aln_exporter = new AlignmentExporter();
_.each(this.state.queries, _.bind(function (query) {
_.each(query.hits, function (hit) {
if (_.indexOf(sequence_ids, hit.id) != -1) {
_.each(hit.hsps, function (hsp) {
hsp.hit_id = hit.id;
hsp.query_id = query.id;
hsps_arr.push(hsp);
});
}
});
}, this));
const filename = 'alignment-' + sequence_ids.length + '_hits';
const blob_url = aln_exporter.prepare_alignments_for_export(hsps_arr, filename);
// set required download attributes for link
$('.download-alignment-of-selected')
.attr('href', blob_url)
.attr('download', filename);
// track new url for future removal
this.setState({alignment_blob_url: blob_url});
}


prepareAlignmentOfAllHits() {
// Get number of hits and array of all hsps.
var num_hits = 0;
var hsps_arr = [];
if(!this.state.queries.length){
return;
}
this.state.queries.forEach(
(query) => query.hits.forEach(
(hit) => {
num_hits++;
hit.hsps.forEach((hsp) => {
hsp.query_id = query.id;
hsp.hit_id = hit.id;
hsps_arr.push(hsp);
});
}
)
);

var aln_exporter = new AlignmentExporter();
var file_name = `alignment-${num_hits}_hits`;
const blob_url = aln_exporter.prepare_alignments_for_export(hsps_arr, file_name);
$('.download-alignment-of-all')
.attr('href', blob_url)
.attr('download', file_name);
return false;
}

render() {
return this.isResultAvailable() ? this.resultsJSX() : this.loadingJSX();
}
Expand Down
52 changes: 2 additions & 50 deletions public/js/sidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ export default class extends Component {
super(props);
this.downloadFastaOfAll = this.downloadFastaOfAll.bind(this);
this.downloadFastaOfSelected = this.downloadFastaOfSelected.bind(this);
this.downloadAlignmentOfAll = this.downloadAlignmentOfAll.bind(this);
this.downloadAlignmentOfSelected = this.downloadAlignmentOfSelected.bind(this);
this.topPanelJSX = this.topPanelJSX.bind(this);
this.summaryString = this.summaryString.bind(this);
this.indexJSX = this.indexJSX.bind(this);
Expand Down Expand Up @@ -178,50 +176,6 @@ export default class extends Component {
return false;
}

downloadAlignmentOfAll() {
// Get number of hits and array of all hsps.
var num_hits = 0;
var hsps_arr = [];
this.props.data.queries.forEach(
(query) => query.hits.forEach(
(hit) => {
num_hits++;
hit.hsps.forEach((hsp) => {
hsp.query_id = query.id;
hsp.hit_id = hit.id;
hsps_arr.push(hsp);
});
}
)
);

var aln_exporter = new AlignmentExporter();
var file_name = `alignment-${num_hits}_hits`;
aln_exporter.export_alignments(hsps_arr, file_name);
return false;
}

downloadAlignmentOfSelected() {
var sequence_ids = $('.hit-links :checkbox:checked').map(function () {
return this.value;
}).get();
var hsps_arr = [];
var aln_exporter = new AlignmentExporter();
console.log('check ' + sequence_ids.toString());
_.each(this.props.data.queries, _.bind(function (query) {
_.each(query.hits, function (hit) {
if (_.indexOf(sequence_ids, hit.id) != -1) {
_.each(hit.hsps, function (hsp) {
hsp.hit_id = hit.id;
hsp.query_id = query.id;
hsps_arr.push(hsp);
});
}
});
}, this));
aln_exporter.export_alignments(hsps_arr, 'alignment-' + sequence_ids.length + '_hits');
return false;
}



Expand Down Expand Up @@ -379,14 +333,12 @@ export default class extends Component {
</li>
}
<li>
<a href="#" className={`btn-link download-alignment-of-all ${!this.props.atLeastOneHit && 'disabled'}`}
onClick={this.downloadAlignmentOfAll}>
<a href="#" className={`btn-link download-alignment-of-all ${!this.props.atLeastOneHit && 'disabled'}`}>
Alignment of all hits
</a>
</li>
<li>
<a href="#" className="btn-link download-alignment-of-selected disabled"
onClick={this.downloadAlignmentOfSelected}>
<a href="#" className="btn-link download-alignment-of-selected disabled">
Alignment of <span className="text-bold"></span> selected hit(s)
</a>
</li>
Expand Down
Loading

0 comments on commit 6409318

Please sign in to comment.