sequenceserver 3.1.2 → 3.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/sequenceserver/blast/tasks.rb +1 -1
- data/lib/sequenceserver/routes.rb +1 -1
- data/lib/sequenceserver/version.rb +1 -1
- data/lib/sequenceserver.rb +1 -1
- data/public/css/app.min.css +1 -1
- data/public/css/sequenceserver.css +0 -18
- data/public/css/sequenceserver.min.css +2 -2
- data/public/js/alignment_exporter.js +16 -28
- data/public/js/cloud_share_modal.js +42 -42
- data/public/js/form.js +12 -10
- data/public/js/grapher.js +4 -4
- data/public/js/hit.js +3 -3
- data/public/js/hits.js +276 -0
- data/public/js/jquery_world.js +1 -1
- data/public/js/mailto.js +1 -3
- data/public/js/null_plugins/report_plugins.js +1 -0
- data/public/js/options.js +2 -6
- data/public/js/query.js +1 -1
- data/public/js/report.js +68 -252
- data/public/js/report_root.js +7 -5
- data/public/js/search.js +28 -11
- data/public/js/sequence.js +158 -158
- data/public/js/sequence_modal.js +28 -36
- data/public/js/sidebar.js +7 -6
- data/public/js/tests/alignment_exporter.spec.js +38 -0
- data/public/js/tests/cloud_share_modal.spec.js +75 -0
- data/public/js/tests/report.spec.js +37 -15
- data/public/packages/jquery-ui@1.13.3.js +19070 -0
- data/public/sequenceserver-report.min.js +3 -2481
- data/public/sequenceserver-report.min.js.LICENSE.txt +300 -0
- data/public/sequenceserver-report.min.js.map +1 -0
- data/public/sequenceserver-search.min.js +3 -2382
- data/public/sequenceserver-search.min.js.LICENSE.txt +292 -0
- data/public/sequenceserver-search.min.js.map +1 -0
- data/views/layout.erb +3 -7
- data/views/search.erb +1 -1
- data/views/search_layout.erb +1 -1
- metadata +11 -5
- data/public/config.js +0 -147
- data/public/packages/jquery-ui@1.11.4.js +0 -16624
    
        data/public/js/report.js
    CHANGED
    
    | @@ -3,10 +3,8 @@ import React, { Component } from 'react'; | |
| 3 3 | 
             
            import _ from 'underscore';
         | 
| 4 4 |  | 
| 5 5 | 
             
            import Sidebar from './sidebar';
         | 
| 6 | 
            +
            import Hits from './hits';
         | 
| 6 7 | 
             
            import Circos from './circos';
         | 
| 7 | 
            -
            import { ReportQuery } from './query';
         | 
| 8 | 
            -
            import Hit from './hit';
         | 
| 9 | 
            -
            import HSP from './hsp';
         | 
| 10 8 | 
             
            import AlignmentExporter from './alignment_exporter';
         | 
| 11 9 | 
             
            import ReportPlugins from 'report_plugins';
         | 
| 12 10 |  | 
| @@ -21,11 +19,6 @@ class Report extends Component { | |
| 21 19 | 
             
                    super(props);
         | 
| 22 20 | 
             
                    // Properties below are internal state used to render results in small
         | 
| 23 21 | 
             
                    // slices (see updateState).
         | 
| 24 | 
            -
                    this.numUpdates = 0;
         | 
| 25 | 
            -
                    this.nextQuery = 0;
         | 
| 26 | 
            -
                    this.nextHit = 0;
         | 
| 27 | 
            -
                    this.nextHSP = 0;
         | 
| 28 | 
            -
                    this.maxHSPs = 3; // max HSPs to render in a cycle
         | 
| 29 22 | 
             
                    this.state = {
         | 
| 30 23 | 
             
                        user_warning: null,
         | 
| 31 24 | 
             
                        download_links: [],
         | 
| @@ -34,8 +27,8 @@ class Report extends Component { | |
| 34 27 | 
             
                        program: '',
         | 
| 35 28 | 
             
                        program_version: '',
         | 
| 36 29 | 
             
                        submitted_at: '',
         | 
| 37 | 
            -
                        queries: [],
         | 
| 38 30 | 
             
                        results: [],
         | 
| 31 | 
            +
                        queries: [],
         | 
| 39 32 | 
             
                        querydb: [],
         | 
| 40 33 | 
             
                        params: [],
         | 
| 41 34 | 
             
                        stats: [],
         | 
| @@ -43,7 +36,6 @@ class Report extends Component { | |
| 43 36 | 
             
                        allQueriesLoaded: false,
         | 
| 44 37 | 
             
                        cloud_sharing_enabled: false,
         | 
| 45 38 | 
             
                    };
         | 
| 46 | 
            -
                    this.prepareAlignmentOfSelectedHits = this.prepareAlignmentOfSelectedHits.bind(this);
         | 
| 47 39 | 
             
                    this.prepareAlignmentOfAllHits = this.prepareAlignmentOfAllHits.bind(this);
         | 
| 48 40 | 
             
                    this.setStateFromJSON = this.setStateFromJSON.bind(this);
         | 
| 49 41 | 
             
                    this.plugins = new ReportPlugins(this);
         | 
| @@ -58,31 +50,66 @@ class Report extends Component { | |
| 58 50 | 
             
                }
         | 
| 59 51 |  | 
| 60 52 | 
             
                pollPeriodically(path, callback, errCallback) {
         | 
| 61 | 
            -
             | 
| 53 | 
            +
                var intervals = [200, 400, 800, 1200, 2000, 3000, 5000];
         | 
| 62 54 | 
             
                    function poll() {
         | 
| 63 | 
            -
                         | 
| 64 | 
            -
                             | 
| 65 | 
            -
             | 
| 66 | 
            -
                                 | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 55 | 
            +
                        fetch(path)
         | 
| 56 | 
            +
                            .then(response => {
         | 
| 57 | 
            +
                                // Handle HTTP status codes
         | 
| 58 | 
            +
                                if (!response.ok) throw response;
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                                return response.text().then(data => {
         | 
| 61 | 
            +
                                    if (data) {
         | 
| 62 | 
            +
                                        data = parseJSON(data);
         | 
| 63 | 
            +
                                    };
         | 
| 64 | 
            +
                                    return { status: response.status, data }
         | 
| 65 | 
            +
                                });
         | 
| 66 | 
            +
                            })
         | 
| 67 | 
            +
                            .then(({ status, data }) => {
         | 
| 68 | 
            +
                                switch (status) {
         | 
| 69 | 
            +
                                    case 202:
         | 
| 70 | 
            +
                                        var interval;
         | 
| 71 | 
            +
                                        if (intervals.length === 1) {
         | 
| 72 | 
            +
                                            interval = intervals[0];
         | 
| 73 | 
            +
                                        } else {
         | 
| 74 | 
            +
                                            interval = intervals.shift();
         | 
| 75 | 
            +
                                        }
         | 
| 76 | 
            +
                                        setTimeout(poll, interval);
         | 
| 77 | 
            +
                                        break;
         | 
| 78 | 
            +
                                    case 200:
         | 
| 79 | 
            +
                                        callback(data);
         | 
| 80 | 
            +
                                        break;
         | 
| 81 | 
            +
                                }
         | 
| 82 | 
            +
                            })
         | 
| 83 | 
            +
                            .catch(error => {
         | 
| 84 | 
            +
                                if (error.text) {
         | 
| 85 | 
            +
                                    error.text().then(errData => {
         | 
| 86 | 
            +
                                        errData = parseJSON(errData);
         | 
| 87 | 
            +
                                        switch (error.status) {
         | 
| 88 | 
            +
                                            case 400:
         | 
| 89 | 
            +
                                            case 422:
         | 
| 90 | 
            +
                                            case 500:
         | 
| 91 | 
            +
                                                errCallback(errData);
         | 
| 92 | 
            +
                                                break;
         | 
| 93 | 
            +
                                            default:
         | 
| 94 | 
            +
                                                console.error("Unhandled error:", error.status);
         | 
| 95 | 
            +
                                        }
         | 
| 96 | 
            +
                                    });
         | 
| 69 97 | 
             
                                } else {
         | 
| 70 | 
            -
                                     | 
| 98 | 
            +
                                    console.error("Network error:", error);
         | 
| 71 99 | 
             
                                }
         | 
| 72 | 
            -
             | 
| 73 | 
            -
                                break;
         | 
| 74 | 
            -
                            case 200:
         | 
| 75 | 
            -
                                callback(jqXHR.responseJSON);
         | 
| 76 | 
            -
                                break;
         | 
| 77 | 
            -
                            case 400:
         | 
| 78 | 
            -
                            case 422:
         | 
| 79 | 
            -
                            case 500:
         | 
| 80 | 
            -
                                errCallback(jqXHR.responseJSON);
         | 
| 81 | 
            -
                                break;
         | 
| 82 | 
            -
                            }
         | 
| 83 | 
            -
                        });
         | 
| 100 | 
            +
                            });
         | 
| 84 101 | 
             
                    }
         | 
| 85 102 |  | 
| 103 | 
            +
                    function parseJSON(str) {
         | 
| 104 | 
            +
                        let parsedJson = str;
         | 
| 105 | 
            +
                        try {
         | 
| 106 | 
            +
                            parsedJson = JSON.parse(str);
         | 
| 107 | 
            +
                        } catch (e) {
         | 
| 108 | 
            +
                            console.error("Error parsing JSON:", e);
         | 
| 109 | 
            +
                        }
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                        return parsedJson;
         | 
| 112 | 
            +
                    }
         | 
| 86 113 | 
             
                    poll();
         | 
| 87 114 | 
             
                }
         | 
| 88 115 |  | 
| @@ -113,139 +140,6 @@ class Report extends Component { | |
| 113 140 | 
             
                    this.toggleTable();
         | 
| 114 141 | 
             
                }
         | 
| 115 142 |  | 
| 116 | 
            -
                /**
         | 
| 117 | 
            -
               * Called for the first time after as BLAST results have been retrieved from
         | 
| 118 | 
            -
               * the server and added to this.state by fetchResults. Only summary overview
         | 
| 119 | 
            -
               * and circos would have been rendered at this point. At this stage we kick
         | 
| 120 | 
            -
               * start iteratively adding 1 HSP to the page every 25 milli-seconds.
         | 
| 121 | 
            -
               */
         | 
| 122 | 
            -
                componentDidUpdate(prevProps, prevState) {
         | 
| 123 | 
            -
                    // Log to console how long the last update take?
         | 
| 124 | 
            -
                    // console.log((Date.now() - this.lastTimeStamp) / 1000);
         | 
| 125 | 
            -
             | 
| 126 | 
            -
                    // Lock sidebar in its position on the first update.
         | 
| 127 | 
            -
                    if (this.nextQuery == 0 && this.nextHit == 0 && this.nextHSP == 0) {
         | 
| 128 | 
            -
                        this.affixSidebar();
         | 
| 129 | 
            -
                    }
         | 
| 130 | 
            -
             | 
| 131 | 
            -
                    // Queue next update if we have not rendered all results yet.
         | 
| 132 | 
            -
                    if (this.nextQuery < this.state.queries.length) {
         | 
| 133 | 
            -
                        // setTimeout is used to clear call stack and space out
         | 
| 134 | 
            -
                        // the updates giving the browser a chance to respond
         | 
| 135 | 
            -
                        // to user interactions.
         | 
| 136 | 
            -
                        setTimeout(() => this.updateState(), 25);
         | 
| 137 | 
            -
                    } else {
         | 
| 138 | 
            -
                        this.componentFinishedUpdating();
         | 
| 139 | 
            -
                    }
         | 
| 140 | 
            -
             | 
| 141 | 
            -
                    this.plugins.componentDidUpdate(prevProps, prevState);
         | 
| 142 | 
            -
                }
         | 
| 143 | 
            -
             | 
| 144 | 
            -
                /**
         | 
| 145 | 
            -
               * Push next slice of results to React for rendering.
         | 
| 146 | 
            -
               */
         | 
| 147 | 
            -
                updateState() {
         | 
| 148 | 
            -
                    var results = [];
         | 
| 149 | 
            -
                    var numHSPsProcessed = 0;
         | 
| 150 | 
            -
                    while (this.nextQuery < this.state.queries.length) {
         | 
| 151 | 
            -
                        var query = this.state.queries[this.nextQuery];
         | 
| 152 | 
            -
             | 
| 153 | 
            -
                        // We may see a query multiple times during rendering because only
         | 
| 154 | 
            -
                        // 3 hsps are rendered in each cycle, but we want to create the
         | 
| 155 | 
            -
                        // corresponding Query component only the first time we see it.
         | 
| 156 | 
            -
                        if (this.nextHit == 0 && this.nextHSP == 0) {
         | 
| 157 | 
            -
                            results.push(
         | 
| 158 | 
            -
                                <ReportQuery
         | 
| 159 | 
            -
                                    key={'Query_' + query.id}
         | 
| 160 | 
            -
                                    query={query}
         | 
| 161 | 
            -
                                    program={this.state.program}
         | 
| 162 | 
            -
                                    querydb={this.state.querydb}
         | 
| 163 | 
            -
                                    showQueryCrumbs={this.state.queries.length > 1}
         | 
| 164 | 
            -
                                    non_parse_seqids={this.state.non_parse_seqids}
         | 
| 165 | 
            -
                                    imported_xml={this.state.imported_xml}
         | 
| 166 | 
            -
                                    veryBig={this.state.veryBig}
         | 
| 167 | 
            -
                                />
         | 
| 168 | 
            -
                            );
         | 
| 169 | 
            -
             | 
| 170 | 
            -
                            results.push(...this.plugins.queryResults(query));
         | 
| 171 | 
            -
                        }
         | 
| 172 | 
            -
             | 
| 173 | 
            -
                        while (this.nextHit < query.hits.length) {
         | 
| 174 | 
            -
                            var hit = query.hits[this.nextHit];
         | 
| 175 | 
            -
                            // We may see a hit multiple times during rendering because only
         | 
| 176 | 
            -
                            // 10 hsps are rendered in each cycle, but we want to create the
         | 
| 177 | 
            -
                            // corresponding Hit component only the first time we see it.
         | 
| 178 | 
            -
                            if (this.nextHSP == 0) {
         | 
| 179 | 
            -
                                results.push(
         | 
| 180 | 
            -
                                    <Hit
         | 
| 181 | 
            -
                                        key={'Query_' + query.number + '_Hit_' + hit.number}
         | 
| 182 | 
            -
                                        query={query}
         | 
| 183 | 
            -
                                        hit={hit}
         | 
| 184 | 
            -
                                        algorithm={this.state.program}
         | 
| 185 | 
            -
                                        querydb={this.state.querydb}
         | 
| 186 | 
            -
                                        selectHit={this.selectHit}
         | 
| 187 | 
            -
                                        imported_xml={this.state.imported_xml}
         | 
| 188 | 
            -
                                        non_parse_seqids={this.state.non_parse_seqids}
         | 
| 189 | 
            -
                                        showQueryCrumbs={this.state.queries.length > 1}
         | 
| 190 | 
            -
                                        showHitCrumbs={query.hits.length > 1}
         | 
| 191 | 
            -
                                        veryBig={this.state.veryBig}
         | 
| 192 | 
            -
                                        onChange={this.prepareAlignmentOfSelectedHits}
         | 
| 193 | 
            -
                                        {...this.props}
         | 
| 194 | 
            -
                                    />
         | 
| 195 | 
            -
                                );
         | 
| 196 | 
            -
                            }
         | 
| 197 | 
            -
             | 
| 198 | 
            -
                            while (this.nextHSP < hit.hsps.length) {
         | 
| 199 | 
            -
                                // Get nextHSP and increment the counter.
         | 
| 200 | 
            -
                                var hsp = hit.hsps[this.nextHSP++];
         | 
| 201 | 
            -
                                results.push(
         | 
| 202 | 
            -
                                    <HSP
         | 
| 203 | 
            -
                                        key={
         | 
| 204 | 
            -
                                            'Query_' +
         | 
| 205 | 
            -
                                            query.number +
         | 
| 206 | 
            -
                                            '_Hit_' +
         | 
| 207 | 
            -
                                            hit.number +
         | 
| 208 | 
            -
                                            '_HSP_' +
         | 
| 209 | 
            -
                                            hsp.number
         | 
| 210 | 
            -
                                        }
         | 
| 211 | 
            -
                                        query={query}
         | 
| 212 | 
            -
                                        hit={hit}
         | 
| 213 | 
            -
                                        hsp={hsp}
         | 
| 214 | 
            -
                                        algorithm={this.state.program}
         | 
| 215 | 
            -
                                        showHSPNumbers={hit.hsps.length > 1}
         | 
| 216 | 
            -
                                        {...this.props}
         | 
| 217 | 
            -
                                    />
         | 
| 218 | 
            -
                                );
         | 
| 219 | 
            -
                                numHSPsProcessed++;
         | 
| 220 | 
            -
                                if (numHSPsProcessed == this.maxHSPs) break;
         | 
| 221 | 
            -
                            }
         | 
| 222 | 
            -
                            // Are we here because we have iterated over all hsps of a hit,
         | 
| 223 | 
            -
                            // or because of the break clause in the inner loop?
         | 
| 224 | 
            -
                            if (this.nextHSP == hit.hsps.length) {
         | 
| 225 | 
            -
                                this.nextHit = this.nextHit + 1;
         | 
| 226 | 
            -
                                this.nextHSP = 0;
         | 
| 227 | 
            -
                            }
         | 
| 228 | 
            -
                            if (numHSPsProcessed == this.maxHSPs) break;
         | 
| 229 | 
            -
                        }
         | 
| 230 | 
            -
             | 
| 231 | 
            -
                        // Are we here because we have iterated over all hits of a query,
         | 
| 232 | 
            -
                        // or because of the break clause in the inner loop?
         | 
| 233 | 
            -
                        if (this.nextHit == query.hits.length) {
         | 
| 234 | 
            -
                            this.nextQuery = this.nextQuery + 1;
         | 
| 235 | 
            -
                            this.nextHit = 0;
         | 
| 236 | 
            -
                        }
         | 
| 237 | 
            -
                        if (numHSPsProcessed == this.maxHSPs) break;
         | 
| 238 | 
            -
                    }
         | 
| 239 | 
            -
             | 
| 240 | 
            -
                    // Push the components to react for rendering.
         | 
| 241 | 
            -
                    this.numUpdates++;
         | 
| 242 | 
            -
                    this.lastTimeStamp = Date.now();
         | 
| 243 | 
            -
                    this.setState({
         | 
| 244 | 
            -
                        results: this.state.results.concat(results),
         | 
| 245 | 
            -
                        veryBig: this.numUpdates >= 250,
         | 
| 246 | 
            -
                    });
         | 
| 247 | 
            -
                }
         | 
| 248 | 
            -
             | 
| 249 143 | 
             
                /**
         | 
| 250 144 | 
             
               * Called after all results have been rendered.
         | 
| 251 145 | 
             
               */
         | 
| @@ -282,6 +176,7 @@ class Report extends Component { | |
| 282 176 | 
             
                    );
         | 
| 283 177 | 
             
                }
         | 
| 284 178 |  | 
| 179 | 
            +
                /* eslint-disable */
         | 
| 285 180 | 
             
                /**
         | 
| 286 181 | 
             
               * Return results JSX.
         | 
| 287 182 | 
             
               */
         | 
| @@ -300,12 +195,20 @@ class Report extends Component { | |
| 300 195 | 
             
                            <div className="col-md-9">
         | 
| 301 196 | 
             
                                {this.overviewJSX()}
         | 
| 302 197 | 
             
                                {this.circosJSX()}
         | 
| 303 | 
            -
                                {this.plugins.generateStats()}
         | 
| 198 | 
            +
                                {this.plugins.generateStats(this.state.queries)}
         | 
| 304 199 | 
             
                                {this.state.results}
         | 
| 200 | 
            +
                                <Hits
         | 
| 201 | 
            +
                                    state={this.state}
         | 
| 202 | 
            +
                                    componentFinishedUpdating={(_) => this.componentFinishedUpdating(_)}
         | 
| 203 | 
            +
                                    populate_hsp_array={this.populate_hsp_array.bind(this)}
         | 
| 204 | 
            +
                                    plugins={this.plugins}
         | 
| 205 | 
            +
                                    {...this.props}
         | 
| 206 | 
            +
                                />
         | 
| 305 207 | 
             
                            </div>
         | 
| 306 208 | 
             
                        </div>
         | 
| 307 209 | 
             
                    );
         | 
| 308 210 | 
             
                }
         | 
| 211 | 
            +
                /* eslint-enable */
         | 
| 309 212 |  | 
| 310 213 |  | 
| 311 214 | 
             
                warningJSX() {
         | 
| @@ -477,20 +380,7 @@ class Report extends Component { | |
| 477 380 | 
             
                    );
         | 
| 478 381 | 
             
                }
         | 
| 479 382 |  | 
| 480 | 
            -
             | 
| 481 | 
            -
               * Affixes the sidebar.
         | 
| 482 | 
            -
               */
         | 
| 483 | 
            -
                affixSidebar() {
         | 
| 484 | 
            -
                    var $sidebar = $('.sidebar');
         | 
| 485 | 
            -
                    var sidebarOffset = $sidebar.offset();
         | 
| 486 | 
            -
                    if (sidebarOffset) {
         | 
| 487 | 
            -
                        $sidebar.affix({
         | 
| 488 | 
            -
                            offset: {
         | 
| 489 | 
            -
                                top: sidebarOffset.top,
         | 
| 490 | 
            -
                            },
         | 
| 491 | 
            -
                        });
         | 
| 492 | 
            -
                    }
         | 
| 493 | 
            -
                }
         | 
| 383 | 
            +
             | 
| 494 384 |  | 
| 495 385 | 
             
                /**
         | 
| 496 386 | 
             
               * For the query in viewport, highlights corresponding entry in the index.
         | 
| @@ -499,84 +389,10 @@ class Report extends Component { | |
| 499 389 | 
             
                    $('body').scrollspy({ target: '.sidebar' });
         | 
| 500 390 | 
             
                }
         | 
| 501 391 |  | 
| 502 | 
            -
                /**
         | 
| 503 | 
            -
               * Event-handler when hit is selected
         | 
| 504 | 
            -
               * Adds glow to hit component.
         | 
| 505 | 
            -
               * Updates number of Fasta that can be downloaded
         | 
| 506 | 
            -
               */
         | 
| 507 | 
            -
                selectHit(id) {
         | 
| 508 | 
            -
                    var checkbox = $('#' + id);
         | 
| 509 | 
            -
                    var num_checked = $('.hit-links :checkbox:checked').length;
         | 
| 510 | 
            -
             | 
| 511 | 
            -
                    if (!checkbox || !checkbox.val()) {
         | 
| 512 | 
            -
                        return;
         | 
| 513 | 
            -
                    }
         | 
| 514 | 
            -
             | 
| 515 | 
            -
                    var $hit = $(checkbox.data('target'));
         | 
| 516 | 
            -
             | 
| 517 | 
            -
                    // Highlight selected hit and enable 'Download FASTA/Alignment of
         | 
| 518 | 
            -
                    // selected' links.
         | 
| 519 | 
            -
                    if (checkbox.is(':checked')) {
         | 
| 520 | 
            -
                        $hit.addClass('glow');
         | 
| 521 | 
            -
                        $hit.next('.hsp').addClass('glow');
         | 
| 522 | 
            -
                        $('.download-fasta-of-selected').enable();
         | 
| 523 | 
            -
                        $('.download-alignment-of-selected').enable();
         | 
| 524 | 
            -
                    } else {
         | 
| 525 | 
            -
                        $hit.removeClass('glow');
         | 
| 526 | 
            -
                        $hit.next('.hsp').removeClass('glow');
         | 
| 527 | 
            -
                        $('.download-fasta-of-selected').attr('href', '#').removeAttr('download');
         | 
| 528 | 
            -
                    }
         | 
| 529 | 
            -
             | 
| 530 | 
            -
                    var $a = $('.download-fasta-of-selected');
         | 
| 531 | 
            -
                    var $b = $('.download-alignment-of-selected');
         | 
| 532 | 
            -
             | 
| 533 | 
            -
                    if (num_checked >= 1) {
         | 
| 534 | 
            -
                        $a.find('.text-bold').html(num_checked);
         | 
| 535 | 
            -
                        $b.find('.text-bold').html(num_checked);
         | 
| 536 | 
            -
                    }
         | 
| 537 | 
            -
             | 
| 538 | 
            -
                    if (num_checked == 0) {
         | 
| 539 | 
            -
                        $a.addClass('disabled').find('.text-bold').html('');
         | 
| 540 | 
            -
                        $b.addClass('disabled').find('.text-bold').html('');
         | 
| 541 | 
            -
                    }
         | 
| 542 | 
            -
                }
         | 
| 543 392 | 
             
                populate_hsp_array(hit, query_id){
         | 
| 544 393 | 
             
                    return hit.hsps.map(hsp => Object.assign(hsp, {hit_id: hit.id, query_id}));
         | 
| 545 394 | 
             
                }
         | 
| 546 395 |  | 
| 547 | 
            -
                prepareAlignmentOfSelectedHits() {
         | 
| 548 | 
            -
                    var sequence_ids = $('.hit-links :checkbox:checked').map(function () {
         | 
| 549 | 
            -
                        return this.value;
         | 
| 550 | 
            -
                    }).get();
         | 
| 551 | 
            -
             | 
| 552 | 
            -
                    if(!sequence_ids.length){
         | 
| 553 | 
            -
                        // remove attributes from link if sequence_ids array is empty
         | 
| 554 | 
            -
                        $('.download-alignment-of-selected').attr('href', '#').removeAttr('download');
         | 
| 555 | 
            -
                        return;
         | 
| 556 | 
            -
             | 
| 557 | 
            -
                    }
         | 
| 558 | 
            -
                    if(this.state.alignment_blob_url){
         | 
| 559 | 
            -
                        // always revoke existing url if any because this method will always create a new url
         | 
| 560 | 
            -
                        window.URL.revokeObjectURL(this.state.alignment_blob_url);
         | 
| 561 | 
            -
                    }
         | 
| 562 | 
            -
                    var hsps_arr = [];
         | 
| 563 | 
            -
                    var aln_exporter = new AlignmentExporter();
         | 
| 564 | 
            -
                    const self = this;
         | 
| 565 | 
            -
                    _.each(this.state.queries, _.bind(function (query) {
         | 
| 566 | 
            -
                        _.each(query.hits, function (hit) {
         | 
| 567 | 
            -
                            if (_.indexOf(sequence_ids, hit.id) != -1) {
         | 
| 568 | 
            -
                                hsps_arr = hsps_arr.concat(self.populate_hsp_array(hit, query.id));
         | 
| 569 | 
            -
                            }
         | 
| 570 | 
            -
                        });
         | 
| 571 | 
            -
                    }, this));
         | 
| 572 | 
            -
                    const filename = 'alignment-' + sequence_ids.length + '_hits.txt';
         | 
| 573 | 
            -
                    const blob_url = aln_exporter.prepare_alignments_for_export(hsps_arr, filename);
         | 
| 574 | 
            -
                    // set required download attributes for link
         | 
| 575 | 
            -
                    $('.download-alignment-of-selected').attr('href', blob_url).attr('download', filename);
         | 
| 576 | 
            -
                    // track new url for future removal
         | 
| 577 | 
            -
                    this.setState({alignment_blob_url: blob_url});
         | 
| 578 | 
            -
                }
         | 
| 579 | 
            -
             | 
| 580 396 | 
             
                prepareAlignmentOfAllHits() {
         | 
| 581 397 | 
             
                    // Get number of hits and array of all hsps.
         | 
| 582 398 | 
             
                    var num_hits = 0;
         | 
    
        data/public/js/report_root.js
    CHANGED
    
    | @@ -17,6 +17,8 @@ class Page extends Component { | |
| 17 17 | 
             
                    this.showErrorModal = this.showErrorModal.bind(this);
         | 
| 18 18 | 
             
                    this.getCharacterWidth = this.getCharacterWidth.bind(this);
         | 
| 19 19 | 
             
                    this.hspChars = createRef();
         | 
| 20 | 
            +
                    this.sequenceModal = createRef();
         | 
| 21 | 
            +
                    this.errorModal = createRef();
         | 
| 20 22 | 
             
                }
         | 
| 21 23 | 
             
                componentDidMount() {
         | 
| 22 24 | 
             
                    var job_id = location.pathname.split('/').pop();
         | 
| @@ -24,11 +26,11 @@ class Page extends Component { | |
| 24 26 | 
             
                }
         | 
| 25 27 |  | 
| 26 28 | 
             
                showSequenceModal(url) {
         | 
| 27 | 
            -
                    this. | 
| 29 | 
            +
                    this.sequenceModal.current.show(url);
         | 
| 28 30 | 
             
                }
         | 
| 29 31 |  | 
| 30 32 | 
             
                showErrorModal(errorData, beforeShow) {
         | 
| 31 | 
            -
                    this. | 
| 33 | 
            +
                    this.errorModal.current.show(errorData, beforeShow);
         | 
| 32 34 | 
             
                }
         | 
| 33 35 |  | 
| 34 36 | 
             
                getCharacterWidth() {
         | 
| @@ -60,11 +62,11 @@ class Page extends Component { | |
| 60 62 | 
             
                            <canvas id="png-exporter" hidden></canvas>
         | 
| 61 63 |  | 
| 62 64 | 
             
                            <SequenceModal
         | 
| 63 | 
            -
                                ref= | 
| 65 | 
            +
                                ref={this.sequenceModal}
         | 
| 64 66 | 
             
                                showErrorModal={(...args) => this.showErrorModal(...args)}
         | 
| 65 67 | 
             
                            />
         | 
| 66 68 |  | 
| 67 | 
            -
                            <ErrorModal ref= | 
| 69 | 
            +
                            <ErrorModal ref={this.errorModal} />
         | 
| 68 70 | 
             
                        </div>
         | 
| 69 71 | 
             
                    );
         | 
| 70 72 | 
             
                }
         | 
| @@ -72,4 +74,4 @@ class Page extends Component { | |
| 72 74 |  | 
| 73 75 |  | 
| 74 76 | 
             
            const root = createRoot(document.getElementById('view'));
         | 
| 75 | 
            -
            root.render(<Page />);
         | 
| 77 | 
            +
            root.render(<Page />);
         | 
    
        data/public/js/search.js
    CHANGED
    
    | @@ -1,32 +1,49 @@ | |
| 1 | 
            -
            import  | 
| 2 | 
            -
            import React, { Component } from  | 
| 3 | 
            -
            import { createRoot } from  | 
| 4 | 
            -
            import { DnD } from  | 
| 5 | 
            -
            import { Form } from  | 
| 6 | 
            -
            import { SearchHeaderPlugin } from  | 
| 1 | 
            +
            import './jquery_world';
         | 
| 2 | 
            +
            import React, { Component } from 'react';
         | 
| 3 | 
            +
            import { createRoot } from 'react-dom/client';
         | 
| 4 | 
            +
            import { DnD } from './dnd';
         | 
| 5 | 
            +
            import { Form } from './form';
         | 
| 6 | 
            +
            import { SearchHeaderPlugin } from 'search_header_plugin';
         | 
| 7 7 |  | 
| 8 8 | 
             
            /**
         | 
| 9 9 | 
             
             * Clear sessionStorage on reload.
         | 
| 10 10 | 
             
             */
         | 
| 11 | 
            -
             | 
| 11 | 
            +
            const navigationEntry = performance.getEntriesByType('navigation')[0];
         | 
| 12 | 
            +
            if (navigationEntry && navigationEntry.type === 'reload') {
         | 
| 12 13 | 
             
              sessionStorage.clear();
         | 
| 13 14 | 
             
              history.replaceState(null, "", location.href.split("?")[0]);
         | 
| 14 15 | 
             
            }
         | 
| 15 16 |  | 
| 16 17 | 
             
            class Page extends Component {
         | 
| 18 | 
            +
              constructor(props) {
         | 
| 19 | 
            +
                super(props);
         | 
| 20 | 
            +
                this.dnd = React.createRef();
         | 
| 21 | 
            +
                this.form = React.createRef();
         | 
| 22 | 
            +
              }
         | 
| 23 | 
            +
             | 
| 17 24 | 
             
              componentDidMount() {
         | 
| 18 | 
            -
                this. | 
| 25 | 
            +
                this.dnd.current.setState({ query: this.form.current.query.current })
         | 
| 19 26 | 
             
              }
         | 
| 27 | 
            +
             | 
| 20 28 | 
             
              render() {
         | 
| 21 29 | 
             
                return (
         | 
| 22 30 | 
             
                  <div>
         | 
| 23 31 | 
             
                    <SearchHeaderPlugin />
         | 
| 24 | 
            -
                    <DnD ref= | 
| 25 | 
            -
                    <Form ref= | 
| 32 | 
            +
                    <DnD ref={this.dnd} />
         | 
| 33 | 
            +
                    <Form ref={this.form} />
         | 
| 26 34 | 
             
                  </div>
         | 
| 27 35 | 
             
                );
         | 
| 28 36 | 
             
              }
         | 
| 29 37 | 
             
            }
         | 
| 30 38 |  | 
| 31 | 
            -
            const root = createRoot(document.getElementById( | 
| 39 | 
            +
            const root = createRoot(document.getElementById('view'));
         | 
| 32 40 | 
             
            root.render(<Page />);
         | 
| 41 | 
            +
             | 
| 42 | 
            +
            document.addEventListener('DOMContentLoaded', () => {
         | 
| 43 | 
            +
                const closeButton = document.querySelector('.js--close-help');
         | 
| 44 | 
            +
                if (closeButton) {
         | 
| 45 | 
            +
                    closeButton.addEventListener('click', function() {
         | 
| 46 | 
            +
                        document.querySelector('[data-help-modal]').classList.add('hidden');
         | 
| 47 | 
            +
                    });
         | 
| 48 | 
            +
                }
         | 
| 49 | 
            +
            });
         |