igv 3.5.2 → 3.5.4
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.
- package/README.md +10 -10
- package/dist/igv.esm.js +414 -444
- package/dist/igv.esm.min.js +9 -9
- package/dist/igv.esm.min.js.map +1 -1
- package/dist/igv.js +414 -444
- package/dist/igv.min.js +9 -9
- package/dist/igv.min.js.map +1 -1
- package/package.json +2 -2
package/dist/igv.js
CHANGED
|
@@ -392,12 +392,12 @@
|
|
|
392
392
|
decsep = '.';
|
|
393
393
|
|
|
394
394
|
return dec[0].split('').reverse().reduce(function (prev, now, i) {
|
|
395
|
-
return i % 3 === 0 ? prev + sep + now : prev + now
|
|
396
|
-
}).split('').reverse().join('') + (dec[1] ? decsep + dec[1] : '')
|
|
395
|
+
return i % 3 === 0 ? prev + sep + now : prev + now
|
|
396
|
+
}).split('').reverse().join('') + (dec[1] ? decsep + dec[1] : '')
|
|
397
397
|
}
|
|
398
398
|
|
|
399
399
|
const splitLines$3 = function (string) {
|
|
400
|
-
return string.split(/\n|\r\n|\r/g)
|
|
400
|
+
return string.split(/\n|\r\n|\r/g)
|
|
401
401
|
};
|
|
402
402
|
|
|
403
403
|
|
|
@@ -425,24 +425,24 @@
|
|
|
425
425
|
}
|
|
426
426
|
}
|
|
427
427
|
}
|
|
428
|
-
return tokens
|
|
428
|
+
return tokens
|
|
429
429
|
}
|
|
430
430
|
|
|
431
431
|
function stripQuotes$2(str) {
|
|
432
|
-
if(str === undefined) {
|
|
433
|
-
return str
|
|
432
|
+
if (str === undefined) {
|
|
433
|
+
return str
|
|
434
434
|
}
|
|
435
|
-
if(str.startsWith("'") || str.startsWith('"')) {
|
|
435
|
+
if (str.startsWith("'") || str.startsWith('"')) {
|
|
436
436
|
str = str.substring(1);
|
|
437
437
|
}
|
|
438
438
|
if (str.endsWith("'") || str.endsWith('"')) {
|
|
439
439
|
str = str.substring(0, str.length - 1);
|
|
440
440
|
}
|
|
441
|
-
return str
|
|
441
|
+
return str
|
|
442
442
|
}
|
|
443
443
|
|
|
444
444
|
function capitalize(str) {
|
|
445
|
-
return str.length > 0 ? str.charAt(0).toUpperCase() + str.slice(1) : str
|
|
445
|
+
return str.length > 0 ? str.charAt(0).toUpperCase() + str.slice(1) : str
|
|
446
446
|
}
|
|
447
447
|
|
|
448
448
|
|
|
@@ -466,7 +466,7 @@
|
|
|
466
466
|
range.end = range.start + 1;
|
|
467
467
|
}
|
|
468
468
|
|
|
469
|
-
return range
|
|
469
|
+
return range
|
|
470
470
|
}
|
|
471
471
|
|
|
472
472
|
/**
|
|
@@ -475,7 +475,7 @@
|
|
|
475
475
|
* @param urlOrFile
|
|
476
476
|
*/
|
|
477
477
|
|
|
478
|
-
function getFilename$
|
|
478
|
+
function getFilename$1(urlOrFile) {
|
|
479
479
|
|
|
480
480
|
if (urlOrFile.name !== undefined) {
|
|
481
481
|
return urlOrFile.name
|
|
@@ -502,8 +502,8 @@
|
|
|
502
502
|
* @param object
|
|
503
503
|
*/
|
|
504
504
|
function isFile(object) {
|
|
505
|
-
if(!object) {
|
|
506
|
-
return false
|
|
505
|
+
if (!object) {
|
|
506
|
+
return false
|
|
507
507
|
}
|
|
508
508
|
return typeof object !== 'function' &&
|
|
509
509
|
(object instanceof File ||
|
|
@@ -523,7 +523,7 @@
|
|
|
523
523
|
|
|
524
524
|
if (typeof process === 'object' && typeof window === 'undefined') {
|
|
525
525
|
global.atob = function (str) {
|
|
526
|
-
return Buffer.from(str, 'base64').toString('binary')
|
|
526
|
+
return Buffer.from(str, 'base64').toString('binary')
|
|
527
527
|
};
|
|
528
528
|
}
|
|
529
529
|
|
|
@@ -542,7 +542,7 @@
|
|
|
542
542
|
if ($1) uri[o.q.name][$1] = $2;
|
|
543
543
|
});
|
|
544
544
|
|
|
545
|
-
return uri
|
|
545
|
+
return uri
|
|
546
546
|
}
|
|
547
547
|
|
|
548
548
|
const options = {
|
|
@@ -565,7 +565,7 @@
|
|
|
565
565
|
* @returns {Promise<*>}
|
|
566
566
|
*/
|
|
567
567
|
async function resolveURL(url) {
|
|
568
|
-
return (typeof url === 'function')
|
|
568
|
+
return (typeof url === 'function') ? url() : url
|
|
569
569
|
}
|
|
570
570
|
|
|
571
571
|
/*! pako 2.1.0 https://github.com/nodeca/pako @license (MIT AND Zlib) */
|
|
@@ -7427,7 +7427,7 @@
|
|
|
7427
7427
|
|
|
7428
7428
|
function isgzipped(data) {
|
|
7429
7429
|
const b = ArrayBuffer.isView(data) ? data : new Uint8Array(data);
|
|
7430
|
-
return b[0] ===31 && b[1] === 139
|
|
7430
|
+
return b[0] === 31 && b[1] === 139
|
|
7431
7431
|
}
|
|
7432
7432
|
|
|
7433
7433
|
/**
|
|
@@ -7437,9 +7437,9 @@
|
|
|
7437
7437
|
const ba = ArrayBuffer.isView(data) ? data : new Uint8Array(data);
|
|
7438
7438
|
const b = ba[3] & FEXTRA$1;
|
|
7439
7439
|
if (b !== 0 && ba[12] === 66 && ba[13] === 67) {
|
|
7440
|
-
return unbgzf(ba.buffer)
|
|
7440
|
+
return unbgzf(ba.buffer)
|
|
7441
7441
|
} else {
|
|
7442
|
-
return ungzip_1$1(ba)
|
|
7442
|
+
return ungzip_1$1(ba)
|
|
7443
7443
|
}
|
|
7444
7444
|
}
|
|
7445
7445
|
|
|
@@ -7465,7 +7465,7 @@
|
|
|
7465
7465
|
const start = 12 + xlen + ptr; // Start of CDATA
|
|
7466
7466
|
const bytesLeft = data.byteLength - start;
|
|
7467
7467
|
const cDataSize = bsize - xlen - 19;
|
|
7468
|
-
if (bytesLeft < cDataSize || cDataSize <= 0) break
|
|
7468
|
+
if (bytesLeft < cDataSize || cDataSize <= 0) break
|
|
7469
7469
|
|
|
7470
7470
|
const a = new Uint8Array(data, start, cDataSize);
|
|
7471
7471
|
const unc = inflateRaw_1(a);
|
|
@@ -7478,13 +7478,13 @@
|
|
|
7478
7478
|
oBlockList.push(unc);
|
|
7479
7479
|
} catch (e) {
|
|
7480
7480
|
console.error(e);
|
|
7481
|
-
break
|
|
7481
|
+
break
|
|
7482
7482
|
}
|
|
7483
7483
|
}
|
|
7484
7484
|
|
|
7485
7485
|
// Concatenate decompressed blocks
|
|
7486
7486
|
if (oBlockList.length === 1) {
|
|
7487
|
-
return oBlockList[0]
|
|
7487
|
+
return oBlockList[0]
|
|
7488
7488
|
} else {
|
|
7489
7489
|
const out = new Uint8Array(totalSize);
|
|
7490
7490
|
let cursor = 0;
|
|
@@ -7493,14 +7493,14 @@
|
|
|
7493
7493
|
arrayCopy(b, 0, out, cursor, b.length);
|
|
7494
7494
|
cursor += b.length;
|
|
7495
7495
|
}
|
|
7496
|
-
return out
|
|
7496
|
+
return out
|
|
7497
7497
|
}
|
|
7498
7498
|
}
|
|
7499
7499
|
|
|
7500
7500
|
function bgzBlockSize$1(data) {
|
|
7501
7501
|
const ba = ArrayBuffer.isView(data) ? data : new Uint8Array(data);
|
|
7502
7502
|
const bsize = (ba[17] << 8 | ba[16]) + 1;
|
|
7503
|
-
return bsize
|
|
7503
|
+
return bsize
|
|
7504
7504
|
}
|
|
7505
7505
|
|
|
7506
7506
|
// From Thomas Down's zlib implementation
|
|
@@ -7510,12 +7510,12 @@
|
|
|
7510
7510
|
|
|
7511
7511
|
function arrayCopy(src, srcOffset, dest, destOffset, count) {
|
|
7512
7512
|
if (count === 0) {
|
|
7513
|
-
return
|
|
7513
|
+
return
|
|
7514
7514
|
}
|
|
7515
7515
|
if (!src) {
|
|
7516
|
-
throw "Undef src"
|
|
7516
|
+
throw "Undef src"
|
|
7517
7517
|
} else if (!dest) {
|
|
7518
|
-
throw "Undef dest"
|
|
7518
|
+
throw "Undef dest"
|
|
7519
7519
|
}
|
|
7520
7520
|
if (srcOffset === 0 && count === src.length) {
|
|
7521
7521
|
arrayCopy_fast(src, dest, destOffset);
|
|
@@ -7552,7 +7552,7 @@
|
|
|
7552
7552
|
const compressedBytes = new deflateRaw_1(bytes); // UInt8Arry
|
|
7553
7553
|
const compressedString = String.fromCharCode.apply(null, compressedBytes); // Convert to string
|
|
7554
7554
|
let enc = btoa(compressedString);
|
|
7555
|
-
return enc.replace(/\+/g, '.').replace(/\//g, '_').replace(/=/g, '-')
|
|
7555
|
+
return enc.replace(/\+/g, '.').replace(/\//g, '_').replace(/=/g, '-') // URL safe
|
|
7556
7556
|
}
|
|
7557
7557
|
|
|
7558
7558
|
/**
|
|
@@ -7577,7 +7577,7 @@
|
|
|
7577
7577
|
for (let b of bytes) {
|
|
7578
7578
|
str += String.fromCharCode(b);
|
|
7579
7579
|
}
|
|
7580
|
-
return str
|
|
7580
|
+
return str
|
|
7581
7581
|
}
|
|
7582
7582
|
|
|
7583
7583
|
|
|
@@ -7607,7 +7607,7 @@
|
|
|
7607
7607
|
}
|
|
7608
7608
|
return plain
|
|
7609
7609
|
} else {
|
|
7610
|
-
return decodeURIComponent(dataString)
|
|
7610
|
+
return decodeURIComponent(dataString) // URL encoded string -- not currently used or tested
|
|
7611
7611
|
}
|
|
7612
7612
|
}
|
|
7613
7613
|
|
|
@@ -7639,7 +7639,7 @@
|
|
|
7639
7639
|
const IGVMath = {
|
|
7640
7640
|
|
|
7641
7641
|
lerp: (v0, v1, t) => {
|
|
7642
|
-
return (1 - t) * v0 + t * v1
|
|
7642
|
+
return (1 - t) * v0 + t * v1
|
|
7643
7643
|
},
|
|
7644
7644
|
|
|
7645
7645
|
mean: function (array) {
|
|
@@ -7652,7 +7652,7 @@
|
|
|
7652
7652
|
n++;
|
|
7653
7653
|
}
|
|
7654
7654
|
}
|
|
7655
|
-
return n > 0 ? t / n : 0
|
|
7655
|
+
return n > 0 ? t / n : 0
|
|
7656
7656
|
},
|
|
7657
7657
|
|
|
7658
7658
|
meanAndStdev: function (array) {
|
|
@@ -7669,7 +7669,7 @@
|
|
|
7669
7669
|
n++;
|
|
7670
7670
|
}
|
|
7671
7671
|
}
|
|
7672
|
-
return n > 0 ? {mean: t / n, stdev: Math.sqrt(t2 - t * t / n)} : {mean: 0, stdev: 0}
|
|
7672
|
+
return n > 0 ? {mean: t / n, stdev: Math.sqrt(t2 - t * t / n)} : {mean: 0, stdev: 0}
|
|
7673
7673
|
},
|
|
7674
7674
|
|
|
7675
7675
|
median: function (numbers) {
|
|
@@ -7687,33 +7687,33 @@
|
|
|
7687
7687
|
median = numbers[(numsLen - 1) / 2];
|
|
7688
7688
|
}
|
|
7689
7689
|
|
|
7690
|
-
return median
|
|
7690
|
+
return median
|
|
7691
7691
|
},
|
|
7692
7692
|
|
|
7693
7693
|
// Fast percentile function for "p" near edges. This needs profiled for p in middle (e.g. median)
|
|
7694
7694
|
percentile: function (array, p) {
|
|
7695
7695
|
|
|
7696
|
-
if (array.length === 0) return undefined
|
|
7696
|
+
if (array.length === 0) return undefined
|
|
7697
7697
|
|
|
7698
7698
|
var k = Math.floor(array.length * ((100 - p) / 100));
|
|
7699
7699
|
if (k === 0) {
|
|
7700
7700
|
array.sort(function (a, b) {
|
|
7701
7701
|
return b - a
|
|
7702
7702
|
});
|
|
7703
|
-
return array[k]
|
|
7703
|
+
return array[k]
|
|
7704
7704
|
} else {
|
|
7705
|
-
return selectElement(array, k)
|
|
7705
|
+
return selectElement(array, k)
|
|
7706
7706
|
}
|
|
7707
7707
|
|
|
7708
7708
|
},
|
|
7709
7709
|
|
|
7710
7710
|
|
|
7711
7711
|
clamp: function (value, min, max) {
|
|
7712
|
-
return Math.min(Math.max(value, min), max)
|
|
7712
|
+
return Math.min(Math.max(value, min), max)
|
|
7713
7713
|
},
|
|
7714
7714
|
|
|
7715
7715
|
log2: function (x) {
|
|
7716
|
-
return Math.log(x) / Math.LN2
|
|
7716
|
+
return Math.log(x) / Math.LN2
|
|
7717
7717
|
}
|
|
7718
7718
|
|
|
7719
7719
|
};
|
|
@@ -7739,7 +7739,7 @@
|
|
|
7739
7739
|
}
|
|
7740
7740
|
}
|
|
7741
7741
|
|
|
7742
|
-
return heap.content[0]
|
|
7742
|
+
return heap.content[0]
|
|
7743
7743
|
}
|
|
7744
7744
|
|
|
7745
7745
|
|
|
@@ -7766,7 +7766,7 @@
|
|
|
7766
7766
|
this.content[0] = end;
|
|
7767
7767
|
this.sinkDown(0);
|
|
7768
7768
|
}
|
|
7769
|
-
return result
|
|
7769
|
+
return result
|
|
7770
7770
|
},
|
|
7771
7771
|
|
|
7772
7772
|
remove: function (node) {
|
|
@@ -7774,24 +7774,24 @@
|
|
|
7774
7774
|
// To remove a value, we must search through the array to find
|
|
7775
7775
|
// it.
|
|
7776
7776
|
for (var i = 0; i < length; i++) {
|
|
7777
|
-
if (this.content[i] !== node) continue
|
|
7777
|
+
if (this.content[i] !== node) continue
|
|
7778
7778
|
// When it is found, the process seen in 'pop' is repeated
|
|
7779
7779
|
// to fill up the hole.
|
|
7780
7780
|
var end = this.content.pop();
|
|
7781
7781
|
// If the element we popped was the one we needed to remove,
|
|
7782
7782
|
// we're done.
|
|
7783
|
-
if (i === length - 1) break
|
|
7783
|
+
if (i === length - 1) break
|
|
7784
7784
|
// Otherwise, we replace the removed element with the popped
|
|
7785
7785
|
// one, and allow it to float up or sink down as appropriate.
|
|
7786
7786
|
this.content[i] = end;
|
|
7787
7787
|
this.bubbleUp(i);
|
|
7788
7788
|
this.sinkDown(i);
|
|
7789
|
-
break
|
|
7789
|
+
break
|
|
7790
7790
|
}
|
|
7791
7791
|
},
|
|
7792
7792
|
|
|
7793
7793
|
size: function () {
|
|
7794
|
-
return this.content.length
|
|
7794
|
+
return this.content.length
|
|
7795
7795
|
},
|
|
7796
7796
|
|
|
7797
7797
|
bubbleUp: function (n) {
|
|
@@ -7805,7 +7805,7 @@
|
|
|
7805
7805
|
// If the parent has a lesser score, things are in order and we
|
|
7806
7806
|
// are done.
|
|
7807
7807
|
if (score >= parent)
|
|
7808
|
-
break
|
|
7808
|
+
break
|
|
7809
7809
|
|
|
7810
7810
|
// Otherwise, swap the parent with the current element and
|
|
7811
7811
|
// continue.
|
|
@@ -7845,7 +7845,7 @@
|
|
|
7845
7845
|
}
|
|
7846
7846
|
|
|
7847
7847
|
// No need to swap further, we are done.
|
|
7848
|
-
if (swap == null) break
|
|
7848
|
+
if (swap == null) break
|
|
7849
7849
|
|
|
7850
7850
|
// Otherwise, swap and continue.
|
|
7851
7851
|
this.content[n] = this.content[swap];
|
|
@@ -8439,145 +8439,78 @@
|
|
|
8439
8439
|
}
|
|
8440
8440
|
|
|
8441
8441
|
function isGoogleURL(url) {
|
|
8442
|
-
|
|
8443
|
-
|
|
8444
|
-
|
|
8445
|
-
|
|
8446
|
-
|
|
8447
|
-
|
|
8448
|
-
|
|
8449
|
-
|
|
8450
|
-
|
|
8451
|
-
|
|
8452
|
-
|
|
8453
|
-
|
|
8454
|
-
|
|
8455
|
-
|
|
8456
|
-
|
|
8457
|
-
|
|
8458
|
-
|
|
8459
|
-
|
|
8460
|
-
|
|
8461
|
-
|
|
8462
|
-
|
|
8463
|
-
|
|
8464
|
-
|
|
8465
|
-
|
|
8466
|
-
|
|
8467
|
-
|
|
8468
|
-
|
|
8469
|
-
const qIdx = gsUrl.indexOf('?');
|
|
8470
|
-
const paramString = (qIdx > 0) ? gsUrl.substring(qIdx) + "&alt=media" : "?alt=media";
|
|
8471
|
-
|
|
8472
|
-
return `https://storage.googleapis.com/storage/v1/b/${bucket}/o/${object}${paramString}`
|
|
8473
|
-
}
|
|
8474
|
-
|
|
8475
|
-
/**
|
|
8476
|
-
* Parse a google bucket and object name from a google storage URL. Known forms include
|
|
8477
|
-
*
|
|
8478
|
-
* gs://BUCKET_NAME/OBJECT_NAME
|
|
8479
|
-
* https://storage.googleapis.com/BUCKET_NAME/OBJECT_NAME
|
|
8480
|
-
* https://storage.googleapis.com/storage/v1/b/BUCKET_NAME/o/OBJECT_NAME
|
|
8481
|
-
* https://www.googleapis.com/storage/v1/b/BUCKET_NAME/o/OBJECT_NAME"
|
|
8482
|
-
* https://storage.googleapis.com/download/storage/v1/b/BUCKET_NAME/o/OBJECT_NAME
|
|
8483
|
-
*
|
|
8484
|
-
* @param url
|
|
8485
|
-
*/
|
|
8486
|
-
function parseBucketName(url) {
|
|
8487
|
-
|
|
8488
|
-
let bucket;
|
|
8489
|
-
let object;
|
|
8490
|
-
|
|
8491
|
-
if (url.startsWith("gs://")) {
|
|
8492
|
-
const i = url.indexOf('/', 5);
|
|
8493
|
-
if (i >= 0) {
|
|
8494
|
-
bucket = url.substring(5, i);
|
|
8495
|
-
const qIdx = url.indexOf('?');
|
|
8496
|
-
object = (qIdx < 0) ? url.substring(i + 1) : url.substring(i + 1, qIdx);
|
|
8497
|
-
}
|
|
8498
|
-
|
|
8499
|
-
} else if (url.startsWith("https://storage.googleapis.com") || url.startsWith("https://storage.cloud.google.com")) {
|
|
8500
|
-
const bucketIdx = url.indexOf("/v1/b/", 8);
|
|
8501
|
-
if (bucketIdx > 0) {
|
|
8502
|
-
const objIdx = url.indexOf("/o/", bucketIdx);
|
|
8503
|
-
if (objIdx > 0) {
|
|
8504
|
-
const queryIdx = url.indexOf("?", objIdx);
|
|
8505
|
-
bucket = url.substring(bucketIdx + 6, objIdx);
|
|
8506
|
-
object = queryIdx > 0 ? url.substring(objIdx + 3, queryIdx) : url.substring(objIdx + 3);
|
|
8507
|
-
}
|
|
8508
|
-
|
|
8509
|
-
} else {
|
|
8510
|
-
const idx1 = url.indexOf("/", 8);
|
|
8511
|
-
const idx2 = url.indexOf("/", idx1+1);
|
|
8512
|
-
const idx3 = url.indexOf("?", idx2);
|
|
8513
|
-
if (idx2 > 0) {
|
|
8514
|
-
bucket = url.substring(idx1+1, idx2);
|
|
8515
|
-
object = idx3 < 0 ? url.substring(idx2+1) : url.substring(idx2+1, idx3);
|
|
8516
|
-
}
|
|
8517
|
-
}
|
|
8518
|
-
|
|
8519
|
-
} else if (url.startsWith("https://www.googleapis.com/storage/v1/b")) {
|
|
8520
|
-
const bucketIdx = url.indexOf("/v1/b/", 8);
|
|
8521
|
-
const objIdx = url.indexOf("/o/", bucketIdx);
|
|
8522
|
-
if (objIdx > 0) {
|
|
8523
|
-
const queryIdx = url.indexOf("?", objIdx);
|
|
8524
|
-
bucket = url.substring(bucketIdx + 6, objIdx);
|
|
8525
|
-
object = queryIdx > 0 ? url.substring(objIdx + 3, queryIdx) : url.substring(objIdx + 3);
|
|
8526
|
-
}
|
|
8527
|
-
}
|
|
8442
|
+
return (url.includes("googleapis") && !url.includes("urlshortener")) ||
|
|
8443
|
+
isGoogleStorageURL(url) ||
|
|
8444
|
+
isGoogleDriveURL(url);
|
|
8445
|
+
}
|
|
8446
|
+
|
|
8447
|
+
function isGoogleStorageURL(url) {
|
|
8448
|
+
return url.startsWith("gs://") ||
|
|
8449
|
+
url.startsWith("https://www.googleapis.com/storage") ||
|
|
8450
|
+
url.startsWith("https://storage.cloud.google.com") ||
|
|
8451
|
+
url.startsWith("https://storage.googleapis.com");
|
|
8452
|
+
}
|
|
8453
|
+
|
|
8454
|
+
function isGoogleDriveURL(url) {
|
|
8455
|
+
return url.startsWith("https://www.googleapis.com/drive/v3/files");
|
|
8456
|
+
}
|
|
8457
|
+
|
|
8458
|
+
/**
|
|
8459
|
+
* Translate gs:// urls to https
|
|
8460
|
+
* See https://cloud.google.com/storage/docs/json_api/v1
|
|
8461
|
+
* @param gsUrl
|
|
8462
|
+
* @returns {string|*}
|
|
8463
|
+
*/
|
|
8464
|
+
function translateGoogleCloudURL(gsUrl) {
|
|
8465
|
+
try {
|
|
8466
|
+
let {bucket, object} = parseBucketName(gsUrl);
|
|
8467
|
+
object = encode(object);
|
|
8528
8468
|
|
|
8529
|
-
|
|
8530
|
-
|
|
8531
|
-
bucket, object
|
|
8532
|
-
}
|
|
8533
|
-
} else {
|
|
8534
|
-
throw Error(`Unrecognized Google Storage URI: ${url}`)
|
|
8535
|
-
}
|
|
8469
|
+
const qIdx = gsUrl.indexOf('?');
|
|
8470
|
+
let paramString = (qIdx > 0) ? gsUrl.substring(qIdx) : "";
|
|
8536
8471
|
|
|
8537
|
-
|
|
8472
|
+
if (!paramString.includes("alt=media")) {
|
|
8473
|
+
paramString = paramString ? `${paramString}&alt=media` : "?alt=media";
|
|
8474
|
+
}
|
|
8538
8475
|
|
|
8539
|
-
|
|
8540
|
-
|
|
8541
|
-
|
|
8542
|
-
|
|
8543
|
-
|
|
8544
|
-
*/
|
|
8476
|
+
return `https://storage.googleapis.com/storage/v1/b/${bucket}/o/${object}${paramString}`;
|
|
8477
|
+
} catch (error) {
|
|
8478
|
+
throw new Error(`Failed to translate Google Cloud URL: ${error.message}`);
|
|
8479
|
+
}
|
|
8480
|
+
}
|
|
8545
8481
|
|
|
8546
|
-
|
|
8482
|
+
/**
|
|
8483
|
+
* Parse a google bucket and object name from a google storage URL.
|
|
8484
|
+
* @param url
|
|
8485
|
+
*/
|
|
8486
|
+
function parseBucketName(url) {
|
|
8487
|
+
const regex = /gs:\/\/([a-zA-Z0-9._-]+)\/([^?]+)|https?:\/\/(?:storage\.googleapis\.com|storage\.cloud\.google\.com|www\.googleapis\.com)\/(?:storage\/v1\/b\/)?([a-zA-Z0-9._-]+)\/(?:o\/)?([^?]+)/;
|
|
8488
|
+
const match = url.match(regex);
|
|
8489
|
+
|
|
8490
|
+
if (match) {
|
|
8491
|
+
const bucket = match[1] || match[3];
|
|
8492
|
+
const object = match[2] || match[4];
|
|
8493
|
+
if (bucket && object) {
|
|
8494
|
+
return { bucket, object };
|
|
8495
|
+
}
|
|
8496
|
+
}
|
|
8497
|
+
throw new Error(`Unrecognized Google Storage URI: ${url}`);
|
|
8498
|
+
}
|
|
8547
8499
|
|
|
8548
|
-
|
|
8549
|
-
|
|
8550
|
-
|
|
8551
|
-
|
|
8552
|
-
|
|
8553
|
-
|
|
8554
|
-
|
|
8555
|
-
});
|
|
8556
|
-
return result;
|
|
8557
|
-
}
|
|
8500
|
+
/**
|
|
8501
|
+
* Percent a GCS object name. See https://cloud.google.com/storage/docs/request-endpoints
|
|
8502
|
+
* @param objectName
|
|
8503
|
+
*/
|
|
8504
|
+
function encode(objectName) {
|
|
8505
|
+
return objectName.split('').map(letter => encodings$1.get(letter) || letter).join('');
|
|
8506
|
+
}
|
|
8558
8507
|
|
|
8559
|
-
|
|
8560
|
-
|
|
8561
|
-
|
|
8562
|
-
|
|
8563
|
-
|
|
8564
|
-
|
|
8565
|
-
encodings$1.set("&", "%26");
|
|
8566
|
-
encodings$1.set("'", "%27");
|
|
8567
|
-
encodings$1.set("(", "%28");
|
|
8568
|
-
encodings$1.set(")", "%29");
|
|
8569
|
-
encodings$1.set("*", "%2A");
|
|
8570
|
-
encodings$1.set("+", "%2B");
|
|
8571
|
-
encodings$1.set(",", "%2C");
|
|
8572
|
-
encodings$1.set("/", "%2F");
|
|
8573
|
-
encodings$1.set(":", "%3A");
|
|
8574
|
-
encodings$1.set(";", "%3B");
|
|
8575
|
-
encodings$1.set("=", "%3D");
|
|
8576
|
-
encodings$1.set("?", "%3F");
|
|
8577
|
-
encodings$1.set("@", "%40");
|
|
8578
|
-
encodings$1.set("[", "%5B");
|
|
8579
|
-
encodings$1.set("]", "%5D");
|
|
8580
|
-
encodings$1.set(" ", "%20");
|
|
8508
|
+
const encodings$1 = new Map([
|
|
8509
|
+
["!", "%21"], ["#", "%23"], ["$", "%24"], ["%", "%25"], ["&", "%26"],
|
|
8510
|
+
["'", "%27"], ["(", "%28"], [")", "%29"], ["*", "%2A"], ["+", "%2B"],
|
|
8511
|
+
[",", "%2C"], ["/", "%2F"], [":", "%3A"], [";", "%3B"], ["=", "%3D"],
|
|
8512
|
+
["?", "%3F"], ["@", "%40"], ["[", "%5B"], ["]", "%5D"], [" ", "%20"]
|
|
8513
|
+
]);
|
|
8581
8514
|
|
|
8582
8515
|
// Convenience functions for the gapi oAuth library.
|
|
8583
8516
|
|
|
@@ -8608,7 +8541,8 @@
|
|
|
8608
8541
|
// Attach an object to keep igv state
|
|
8609
8542
|
google.igv = {
|
|
8610
8543
|
tokenClient: tokenClient,
|
|
8611
|
-
apiKey: config.apiKey
|
|
8544
|
+
apiKey: config.apiKey,
|
|
8545
|
+
appId: config.appId
|
|
8612
8546
|
};
|
|
8613
8547
|
}
|
|
8614
8548
|
|
|
@@ -8628,8 +8562,6 @@
|
|
|
8628
8562
|
undefined
|
|
8629
8563
|
}
|
|
8630
8564
|
|
|
8631
|
-
|
|
8632
|
-
let promise;
|
|
8633
8565
|
/**
|
|
8634
8566
|
* Return a promise for an access token for the given scope. If the user hasn't authorized the scope request it
|
|
8635
8567
|
*
|
|
@@ -8648,27 +8580,21 @@
|
|
|
8648
8580
|
return google.igv.tokenResponse.access_token
|
|
8649
8581
|
} else {
|
|
8650
8582
|
const tokenClient = google.igv.tokenClient;
|
|
8651
|
-
|
|
8652
|
-
|
|
8653
|
-
|
|
8654
|
-
|
|
8655
|
-
|
|
8656
|
-
|
|
8657
|
-
|
|
8658
|
-
|
|
8659
|
-
|
|
8660
|
-
|
|
8661
|
-
|
|
8662
|
-
|
|
8663
|
-
|
|
8664
|
-
|
|
8665
|
-
|
|
8666
|
-
} catch (err) {
|
|
8667
|
-
console.log(err);
|
|
8668
|
-
}
|
|
8669
|
-
});
|
|
8670
|
-
}
|
|
8671
|
-
return promise
|
|
8583
|
+
return new Promise((resolve, reject) => {
|
|
8584
|
+
tokenClient.callback = (tokenResponse) => {
|
|
8585
|
+
if (tokenResponse.error !== undefined) {
|
|
8586
|
+
return reject(tokenResponse)
|
|
8587
|
+
}
|
|
8588
|
+
google.igv.tokenResponse = tokenResponse;
|
|
8589
|
+
google.igv.tokenExpiresAt = Date.now() + tokenResponse.expires_in * 1000;
|
|
8590
|
+
resolve(tokenResponse.access_token);
|
|
8591
|
+
};
|
|
8592
|
+
try {
|
|
8593
|
+
tokenClient.requestAccessToken({scope});
|
|
8594
|
+
} catch (err) {
|
|
8595
|
+
reject(err);
|
|
8596
|
+
}
|
|
8597
|
+
})
|
|
8672
8598
|
}
|
|
8673
8599
|
}
|
|
8674
8600
|
|
|
@@ -8687,90 +8613,6 @@
|
|
|
8687
8613
|
}
|
|
8688
8614
|
}
|
|
8689
8615
|
|
|
8690
|
-
function getApiKey() {
|
|
8691
|
-
return google.igv.apiKey
|
|
8692
|
-
}
|
|
8693
|
-
|
|
8694
|
-
/**
|
|
8695
|
-
* Return information about a specific google drive URL
|
|
8696
|
-
*
|
|
8697
|
-
* @param googleDriveURL
|
|
8698
|
-
* @returns {Promise<any>}
|
|
8699
|
-
*/
|
|
8700
|
-
async function getDriveFileInfo(googleDriveURL) {
|
|
8701
|
-
|
|
8702
|
-
const id = getGoogleDriveFileID(googleDriveURL);
|
|
8703
|
-
let endPoint = "https://www.googleapis.com/drive/v3/files/" + id + "?supportsTeamDrives=true";
|
|
8704
|
-
const apiKey = getApiKey();
|
|
8705
|
-
if (apiKey) {
|
|
8706
|
-
endPoint += "&key=" + apiKey;
|
|
8707
|
-
}
|
|
8708
|
-
const response = await fetch(endPoint);
|
|
8709
|
-
let json = await response.json();
|
|
8710
|
-
if (json.error && json.error.code === 404) {
|
|
8711
|
-
let scope = "https://www.googleapis.com/auth/drive.readonly";
|
|
8712
|
-
const access_token = await getAccessToken(scope);
|
|
8713
|
-
if (access_token) {
|
|
8714
|
-
const response = await fetch(endPoint, {
|
|
8715
|
-
headers: {
|
|
8716
|
-
'Authorization': `Bearer ${access_token}`
|
|
8717
|
-
}
|
|
8718
|
-
});
|
|
8719
|
-
json = await response.json();
|
|
8720
|
-
if (json.error) {
|
|
8721
|
-
throw Error(json.error);
|
|
8722
|
-
}
|
|
8723
|
-
} else {
|
|
8724
|
-
throw Error(json.error);
|
|
8725
|
-
}
|
|
8726
|
-
}
|
|
8727
|
-
return json;
|
|
8728
|
-
}
|
|
8729
|
-
|
|
8730
|
-
|
|
8731
|
-
function getDriveDownloadURL(link) {
|
|
8732
|
-
// Return a google drive download url for the sharable link
|
|
8733
|
-
//https://drive.google.com/open?id=0B-lleX9c2pZFbDJ4VVRxakJzVGM
|
|
8734
|
-
//https://drive.google.com/file/d/1_FC4kCeO8E3V4dJ1yIW7A0sn1yURKIX-/view?usp=sharing
|
|
8735
|
-
var id = getGoogleDriveFileID(link);
|
|
8736
|
-
return id ? "https://www.googleapis.com/drive/v3/files/" + id + "?alt=media&supportsTeamDrives=true" : link;
|
|
8737
|
-
}
|
|
8738
|
-
|
|
8739
|
-
function getGoogleDriveFileID(link) {
|
|
8740
|
-
|
|
8741
|
-
//https://drive.google.com/file/d/1_FC4kCeO8E3V4dJ1yIW7A0sn1yURKIX-/view?usp=sharing
|
|
8742
|
-
//https://www.googleapis.com/drive/v3/files/1w-tvo6p1SH4p1OaQSVxpkV_EJgGIstWF?alt=media&supportsTeamDrives=true"
|
|
8743
|
-
|
|
8744
|
-
if (link.includes("/open?id=")) {
|
|
8745
|
-
const i1 = link.indexOf("/open?id=") + 9;
|
|
8746
|
-
const i2 = link.indexOf("&");
|
|
8747
|
-
if (i1 > 0 && i2 > i1) {
|
|
8748
|
-
return link.substring(i1, i2)
|
|
8749
|
-
} else if (i1 > 0) {
|
|
8750
|
-
return link.substring(i1);
|
|
8751
|
-
}
|
|
8752
|
-
|
|
8753
|
-
} else if (link.includes("/file/d/")) {
|
|
8754
|
-
const i1 = link.indexOf("/file/d/") + 8;
|
|
8755
|
-
const i2 = link.lastIndexOf("/");
|
|
8756
|
-
return link.substring(i1, i2);
|
|
8757
|
-
|
|
8758
|
-
} else if (link.startsWith("https://www.googleapis.com/drive")) {
|
|
8759
|
-
let i1 = link.indexOf("/files/");
|
|
8760
|
-
const i2 = link.indexOf("?");
|
|
8761
|
-
if (i1 > 0) {
|
|
8762
|
-
i1 += 7;
|
|
8763
|
-
return i2 > 0 ?
|
|
8764
|
-
link.substring(i1, i2) :
|
|
8765
|
-
link.substring(i1)
|
|
8766
|
-
}
|
|
8767
|
-
}
|
|
8768
|
-
|
|
8769
|
-
throw Error("Unknown Google Drive url format: " + link);
|
|
8770
|
-
|
|
8771
|
-
|
|
8772
|
-
}
|
|
8773
|
-
|
|
8774
8616
|
// The MIT License (MIT)
|
|
8775
8617
|
|
|
8776
8618
|
/**
|
|
@@ -8802,7 +8644,7 @@
|
|
|
8802
8644
|
asyncFunction: asyncFunction,
|
|
8803
8645
|
});
|
|
8804
8646
|
self.dequeue();
|
|
8805
|
-
})
|
|
8647
|
+
})
|
|
8806
8648
|
}
|
|
8807
8649
|
|
|
8808
8650
|
/**
|
|
@@ -8815,10 +8657,10 @@
|
|
|
8815
8657
|
*/
|
|
8816
8658
|
addAll(promises, options) {
|
|
8817
8659
|
var addedPromises = promises.map(function (promise) {
|
|
8818
|
-
return this.add(promise, options)
|
|
8660
|
+
return this.add(promise, options)
|
|
8819
8661
|
}.bind(this));
|
|
8820
8662
|
|
|
8821
|
-
return Promise.all(addedPromises)
|
|
8663
|
+
return Promise.all(addedPromises)
|
|
8822
8664
|
};
|
|
8823
8665
|
|
|
8824
8666
|
/**
|
|
@@ -8890,6 +8732,10 @@
|
|
|
8890
8732
|
|
|
8891
8733
|
class IGVXhr {
|
|
8892
8734
|
|
|
8735
|
+
UCSC_HOST = "hgdownload.soe.ucsc.edu"
|
|
8736
|
+
UCSC_BACKUP_HOST = "genome-browser.s3.us-east-1.amazonaws.com"
|
|
8737
|
+
|
|
8738
|
+
|
|
8893
8739
|
constructor() {
|
|
8894
8740
|
this.apiKey = undefined;
|
|
8895
8741
|
this.googleThrottle = new Throttle({
|
|
@@ -8897,6 +8743,7 @@
|
|
|
8897
8743
|
});
|
|
8898
8744
|
this.RANGE_WARNING_GIVEN = false;
|
|
8899
8745
|
this.oauth = new Oauth();
|
|
8746
|
+
this.corsProxy = undefined;
|
|
8900
8747
|
}
|
|
8901
8748
|
|
|
8902
8749
|
setApiKey(key) {
|
|
@@ -8921,7 +8768,7 @@
|
|
|
8921
8768
|
* @param options
|
|
8922
8769
|
* @returns {Promise<Uint8Array>}
|
|
8923
8770
|
*/
|
|
8924
|
-
|
|
8771
|
+
async loadByteArray(url, options) {
|
|
8925
8772
|
const arraybuffer = await this.loadArrayBuffer(url, options);
|
|
8926
8773
|
let plain;
|
|
8927
8774
|
if (isgzipped(arraybuffer)) {
|
|
@@ -8966,7 +8813,7 @@
|
|
|
8966
8813
|
|
|
8967
8814
|
if (isFile(url)) {
|
|
8968
8815
|
return this._loadFileSlice(url, options)
|
|
8969
|
-
} else if (
|
|
8816
|
+
} else if (isString$3(url)) {
|
|
8970
8817
|
if (url.startsWith("data:")) {
|
|
8971
8818
|
const buffer = decodeDataURI$1(url).buffer;
|
|
8972
8819
|
if (options.range) {
|
|
@@ -8976,9 +8823,6 @@
|
|
|
8976
8823
|
return buffer
|
|
8977
8824
|
}
|
|
8978
8825
|
} else {
|
|
8979
|
-
if (url.startsWith("https://drive.google.com")) {
|
|
8980
|
-
url = getDriveDownloadURL(url);
|
|
8981
|
-
}
|
|
8982
8826
|
if (isGoogleDriveURL(url) || url.startsWith("https://www.dropbox.com")) {
|
|
8983
8827
|
return this.googleThrottle.add(async () => {
|
|
8984
8828
|
return this._loadURL(url, options)
|
|
@@ -8996,14 +8840,21 @@
|
|
|
8996
8840
|
|
|
8997
8841
|
const self = this;
|
|
8998
8842
|
const _url = url; // The unmodified URL, needed in case of an oAuth retry
|
|
8843
|
+
const {host} = parseUri(_url);
|
|
8999
8844
|
|
|
9000
8845
|
url = mapUrl$1(url);
|
|
9001
8846
|
|
|
9002
8847
|
options = options || {};
|
|
9003
8848
|
|
|
9004
|
-
let oauthToken
|
|
9005
|
-
if (
|
|
9006
|
-
|
|
8849
|
+
let oauthToken;
|
|
8850
|
+
if (isGoogleDriveURL(url)) {
|
|
8851
|
+
// Google drive urls always require oAuth
|
|
8852
|
+
oauthToken = await getAccessToken("https://www.googleapis.com/auth/drive.file");
|
|
8853
|
+
} else {
|
|
8854
|
+
oauthToken = options.oauthToken || this.getOauthToken(url);
|
|
8855
|
+
if (oauthToken) {
|
|
8856
|
+
oauthToken = await (typeof oauthToken === 'function' ? oauthToken() : oauthToken);
|
|
8857
|
+
}
|
|
9007
8858
|
}
|
|
9008
8859
|
|
|
9009
8860
|
return new Promise(function (resolve, reject) {
|
|
@@ -9076,8 +8927,10 @@
|
|
|
9076
8927
|
|
|
9077
8928
|
xhr.onload = async function (event) {
|
|
9078
8929
|
|
|
8930
|
+
const isFileProtocol = url.toLowerCase().startsWith("file:");
|
|
8931
|
+
|
|
9079
8932
|
// when the url points to a local file, the status is 0
|
|
9080
|
-
if (xhr.status
|
|
8933
|
+
if ((xhr.status >= 200 && xhr.status <= 300) || (isFileProtocol && xhr.status === 0)) {
|
|
9081
8934
|
if ("HEAD" === options.method) {
|
|
9082
8935
|
// Support fetching specific headers. Attempting to fetch all headers can be problematic with CORS
|
|
9083
8936
|
const headers = options.requestedHeaders || ['content-length'];
|
|
@@ -9093,7 +8946,7 @@
|
|
|
9093
8946
|
// For small files a range starting at 0 can return the whole file => 200
|
|
9094
8947
|
// Provide just the slice we asked for, throw out the rest quietly
|
|
9095
8948
|
// If file is large warn user
|
|
9096
|
-
if (xhr.response.length >
|
|
8949
|
+
if (xhr.response.length > 1000000 && !self.RANGE_WARNING_GIVEN) {
|
|
9097
8950
|
alert(`Warning: Range header ignored for URL: ${url}. This can have severe performance impacts.`);
|
|
9098
8951
|
}
|
|
9099
8952
|
resolve(xhr.response.slice(range.start, range.start + range.size));
|
|
@@ -9110,20 +8963,29 @@
|
|
|
9110
8963
|
tryGoogleAuth();
|
|
9111
8964
|
|
|
9112
8965
|
} else {
|
|
8966
|
+
const error = new Error(`Error accessing resource: ${url} status: ${xhr.status}`);
|
|
9113
8967
|
if (xhr.status === 403) {
|
|
9114
8968
|
handleError("Access forbidden: " + url);
|
|
8969
|
+
} else if (host === self.UCSC_HOST) {
|
|
8970
|
+
tryUcscBackup(self.UCSC_HOST, self.UCSC_BACKUP_HOST, error);
|
|
8971
|
+
} else if (xhr.status === 0 && self.corsProxy && !options.corsProxyRetried) {
|
|
8972
|
+
tryCorsProxy(error);
|
|
9115
8973
|
} else {
|
|
9116
|
-
handleError(
|
|
8974
|
+
handleError(error);
|
|
9117
8975
|
}
|
|
9118
8976
|
}
|
|
9119
8977
|
};
|
|
9120
8978
|
|
|
9121
|
-
|
|
9122
8979
|
xhr.onerror = function (event) {
|
|
8980
|
+
const error = new Error(`Error accessing resource: ${url} status: ${xhr.status}`);
|
|
9123
8981
|
if (isGoogleURL(url) && !options.retries) {
|
|
9124
8982
|
tryGoogleAuth();
|
|
8983
|
+
} else if (host === self.UCSC_HOST) {
|
|
8984
|
+
tryUcscBackup(self.UCSC_HOST, self.UCSC_BACKUP_HOST, error);
|
|
8985
|
+
} else if (self.corsProxy && !options.corsProxyRetried) {
|
|
8986
|
+
tryCorsProxy(error);
|
|
9125
8987
|
} else {
|
|
9126
|
-
handleError(
|
|
8988
|
+
handleError(error);
|
|
9127
8989
|
}
|
|
9128
8990
|
};
|
|
9129
8991
|
|
|
@@ -9155,6 +9017,27 @@
|
|
|
9155
9017
|
}
|
|
9156
9018
|
}
|
|
9157
9019
|
|
|
9020
|
+
async function tryCorsProxy(error) {
|
|
9021
|
+
options.corsProxyRetried = true;
|
|
9022
|
+
const proxyUrl = self.corsProxy + (_url.includes("?") ? "&" : "?") + "url=" + encodeURIComponent(_url);
|
|
9023
|
+
try {
|
|
9024
|
+
const result = await self._loadURL(proxyUrl, options);
|
|
9025
|
+
resolve(result);
|
|
9026
|
+
} catch (e) {
|
|
9027
|
+
handleError(error);
|
|
9028
|
+
}
|
|
9029
|
+
}
|
|
9030
|
+
|
|
9031
|
+
async function tryUcscBackup(UCSC_HOST, UCSC_BACKUP_HOST, error) {
|
|
9032
|
+
const backupUrl = _url.replace(UCSC_HOST, UCSC_BACKUP_HOST);
|
|
9033
|
+
try {
|
|
9034
|
+
const result = await self._loadURL(backupUrl, options);
|
|
9035
|
+
resolve(result);
|
|
9036
|
+
} catch (e) {
|
|
9037
|
+
handleError(error);
|
|
9038
|
+
}
|
|
9039
|
+
}
|
|
9040
|
+
|
|
9158
9041
|
async function tryGoogleAuth() {
|
|
9159
9042
|
try {
|
|
9160
9043
|
const accessToken = await fetchGoogleAccessToken(_url);
|
|
@@ -9173,6 +9056,8 @@
|
|
|
9173
9056
|
}
|
|
9174
9057
|
}
|
|
9175
9058
|
}
|
|
9059
|
+
|
|
9060
|
+
|
|
9176
9061
|
})
|
|
9177
9062
|
|
|
9178
9063
|
}
|
|
@@ -9245,20 +9130,29 @@
|
|
|
9245
9130
|
}
|
|
9246
9131
|
|
|
9247
9132
|
/**
|
|
9248
|
-
*
|
|
9249
|
-
*
|
|
9250
|
-
*
|
|
9133
|
+
* Return the content length of the file at the given URL. This is not guaranteed to succeed, some servers
|
|
9134
|
+
* do not support or allow the content-length header.
|
|
9135
|
+
*
|
|
9251
9136
|
* @param url
|
|
9252
9137
|
* @param options
|
|
9253
9138
|
* @returns {Promise<unknown>}
|
|
9254
9139
|
*/
|
|
9255
9140
|
async getContentLength(url, options) {
|
|
9256
|
-
|
|
9257
|
-
|
|
9258
|
-
|
|
9259
|
-
|
|
9260
|
-
|
|
9261
|
-
|
|
9141
|
+
if (isFile(url)) {
|
|
9142
|
+
return url.size
|
|
9143
|
+
} else {
|
|
9144
|
+
try {
|
|
9145
|
+
options = options || {};
|
|
9146
|
+
options.method = 'HEAD';
|
|
9147
|
+
options.requestedHeaders = ['content-length'];
|
|
9148
|
+
const headerMap = await this._loadURL(url, options);
|
|
9149
|
+
const contentLengthString = headerMap['content-length'];
|
|
9150
|
+
return contentLengthString ? Number.parseInt(contentLengthString) : 0
|
|
9151
|
+
} catch (e) {
|
|
9152
|
+
console.error(e);
|
|
9153
|
+
return -1
|
|
9154
|
+
}
|
|
9155
|
+
}
|
|
9262
9156
|
}
|
|
9263
9157
|
|
|
9264
9158
|
}
|
|
@@ -9321,8 +9215,10 @@
|
|
|
9321
9215
|
}
|
|
9322
9216
|
|
|
9323
9217
|
function addTeamDrive(url) {
|
|
9324
|
-
if (url.includes("
|
|
9218
|
+
if (url.includes("supportsAllDrives")) {
|
|
9325
9219
|
return url
|
|
9220
|
+
} else if (url.includes("supportsTeamDrives")) {
|
|
9221
|
+
return url.replaceAll("supportsTeamDrives", "supportsAllDrives")
|
|
9326
9222
|
} else {
|
|
9327
9223
|
const paramSeparator = url.includes("?") ? "&" : "?";
|
|
9328
9224
|
url = url + paramSeparator + "supportsTeamDrive=true";
|
|
@@ -9337,8 +9233,6 @@
|
|
|
9337
9233
|
|
|
9338
9234
|
if (url.startsWith("https://www.dropbox.com")) {
|
|
9339
9235
|
return url.replace("//www.dropbox.com", "//dl.dropboxusercontent.com")
|
|
9340
|
-
} else if (url.startsWith("https://drive.google.com")) {
|
|
9341
|
-
return getDriveDownloadURL(url)
|
|
9342
9236
|
} else if (url.includes("//www.broadinstitute.org/igvdata")) {
|
|
9343
9237
|
return url.replace("//www.broadinstitute.org/igvdata", "//data.broadinstitute.org/igvdata")
|
|
9344
9238
|
} else if (url.includes("//igvdata.broadinstitute.org")) {
|
|
@@ -9534,17 +9428,17 @@
|
|
|
9534
9428
|
|
|
9535
9429
|
var searchInterval = new Interval$1(start, end, 0);
|
|
9536
9430
|
|
|
9537
|
-
if (this.root === NIL$1) return []
|
|
9431
|
+
if (this.root === NIL$1) return []
|
|
9538
9432
|
|
|
9539
9433
|
var intervals = searchAll$1.call(this, searchInterval, this.root, []);
|
|
9540
9434
|
|
|
9541
9435
|
if (intervals.length > 1) {
|
|
9542
9436
|
intervals.sort(function (i1, i2) {
|
|
9543
|
-
return i1.low - i2.low
|
|
9437
|
+
return i1.low - i2.low
|
|
9544
9438
|
});
|
|
9545
9439
|
}
|
|
9546
9440
|
|
|
9547
|
-
return intervals
|
|
9441
|
+
return intervals
|
|
9548
9442
|
}
|
|
9549
9443
|
|
|
9550
9444
|
/**
|
|
@@ -9629,7 +9523,7 @@
|
|
|
9629
9523
|
searchAll$1.call(this, interval, node.right, results);
|
|
9630
9524
|
}
|
|
9631
9525
|
|
|
9632
|
-
return results
|
|
9526
|
+
return results
|
|
9633
9527
|
}
|
|
9634
9528
|
|
|
9635
9529
|
function leftRotate$1(x) {
|
|
@@ -9708,35 +9602,35 @@
|
|
|
9708
9602
|
|
|
9709
9603
|
equals(other) {
|
|
9710
9604
|
if (!other) {
|
|
9711
|
-
return false
|
|
9605
|
+
return false
|
|
9712
9606
|
}
|
|
9713
9607
|
if (this === other) {
|
|
9714
|
-
return true
|
|
9608
|
+
return true
|
|
9715
9609
|
}
|
|
9716
9610
|
return (this.low === other.low &&
|
|
9717
|
-
this.high === other.high)
|
|
9611
|
+
this.high === other.high)
|
|
9718
9612
|
|
|
9719
9613
|
}
|
|
9720
9614
|
|
|
9721
9615
|
compareTo(other) {
|
|
9722
9616
|
if (this.low < other.low)
|
|
9723
|
-
return -1
|
|
9617
|
+
return -1
|
|
9724
9618
|
if (this.low > other.low)
|
|
9725
|
-
return 1
|
|
9619
|
+
return 1
|
|
9726
9620
|
|
|
9727
9621
|
if (this.high < other.high)
|
|
9728
|
-
return -1
|
|
9622
|
+
return -1
|
|
9729
9623
|
if (this.high > other.high)
|
|
9730
|
-
return 1
|
|
9624
|
+
return 1
|
|
9731
9625
|
|
|
9732
|
-
return 0
|
|
9626
|
+
return 0
|
|
9733
9627
|
}
|
|
9734
9628
|
|
|
9735
9629
|
/**
|
|
9736
9630
|
* Returns true if this interval overlaps the other.
|
|
9737
9631
|
*/
|
|
9738
9632
|
overlaps(other) {
|
|
9739
|
-
|
|
9633
|
+
return (this.low <= other.high && other.low <= this.high)
|
|
9740
9634
|
}
|
|
9741
9635
|
}
|
|
9742
9636
|
|
|
@@ -9781,19 +9675,19 @@
|
|
|
9781
9675
|
var start;
|
|
9782
9676
|
var end;
|
|
9783
9677
|
|
|
9784
|
-
if (!features) return
|
|
9678
|
+
if (!features) return
|
|
9785
9679
|
|
|
9786
9680
|
maxRows = maxRows || 10000;
|
|
9787
9681
|
|
|
9788
9682
|
if (!sorted) {
|
|
9789
9683
|
features.sort(function (a, b) {
|
|
9790
|
-
return a.start - b.start
|
|
9684
|
+
return a.start - b.start
|
|
9791
9685
|
});
|
|
9792
9686
|
}
|
|
9793
9687
|
|
|
9794
9688
|
|
|
9795
9689
|
if (features.length === 0) {
|
|
9796
|
-
return []
|
|
9690
|
+
return []
|
|
9797
9691
|
|
|
9798
9692
|
} else {
|
|
9799
9693
|
|
|
@@ -9846,7 +9740,7 @@
|
|
|
9846
9740
|
} // while (bucket)
|
|
9847
9741
|
|
|
9848
9742
|
if (!bucket) {
|
|
9849
|
-
break
|
|
9743
|
+
break
|
|
9850
9744
|
}
|
|
9851
9745
|
feature = bucket.pop();
|
|
9852
9746
|
if (0 === bucket.length) {
|
|
@@ -9863,7 +9757,7 @@
|
|
|
9863
9757
|
row++;
|
|
9864
9758
|
nextStart = bucketStart;
|
|
9865
9759
|
|
|
9866
|
-
if (allocatedCount === lastAllocatedCount) break
|
|
9760
|
+
if (allocatedCount === lastAllocatedCount) break // Protect from infinite loops
|
|
9867
9761
|
|
|
9868
9762
|
lastAllocatedCount = allocatedCount;
|
|
9869
9763
|
|
|
@@ -9885,13 +9779,13 @@
|
|
|
9885
9779
|
findOverlapping: function (featureList, start, end) {
|
|
9886
9780
|
|
|
9887
9781
|
if (!featureList || featureList.length === 0) {
|
|
9888
|
-
return []
|
|
9782
|
+
return []
|
|
9889
9783
|
} else {
|
|
9890
9784
|
const tree = buildIntervalTree$1(featureList);
|
|
9891
9785
|
const intervals = tree.findOverlapping(start, end);
|
|
9892
9786
|
|
|
9893
9787
|
if (intervals.length === 0) {
|
|
9894
|
-
return []
|
|
9788
|
+
return []
|
|
9895
9789
|
} else {
|
|
9896
9790
|
// Trim the list of features in the intervals to those
|
|
9897
9791
|
// overlapping the requested range.
|
|
@@ -9904,7 +9798,7 @@
|
|
|
9904
9798
|
const len = intervalFeatures.length;
|
|
9905
9799
|
for (let i = 0; i < len; i++) {
|
|
9906
9800
|
const feature = intervalFeatures[i];
|
|
9907
|
-
if (feature.start > end) break
|
|
9801
|
+
if (feature.start > end) break
|
|
9908
9802
|
else if (feature.end > start) {
|
|
9909
9803
|
featureList.push(feature);
|
|
9910
9804
|
}
|
|
@@ -9912,10 +9806,10 @@
|
|
|
9912
9806
|
});
|
|
9913
9807
|
|
|
9914
9808
|
featureList.sort(function (a, b) {
|
|
9915
|
-
return a.start - b.start
|
|
9809
|
+
return a.start - b.start
|
|
9916
9810
|
});
|
|
9917
9811
|
|
|
9918
|
-
return featureList
|
|
9812
|
+
return featureList
|
|
9919
9813
|
}
|
|
9920
9814
|
}
|
|
9921
9815
|
|
|
@@ -9936,7 +9830,7 @@
|
|
|
9936
9830
|
const chunkSize = Math.max(10, Math.round(len / 100));
|
|
9937
9831
|
|
|
9938
9832
|
featureList.sort(function (f1, f2) {
|
|
9939
|
-
return (f1.start === f2.start ? 0 : (f1.start > f2.start ? 1 : -1))
|
|
9833
|
+
return (f1.start === f2.start ? 0 : (f1.start > f2.start ? 1 : -1))
|
|
9940
9834
|
});
|
|
9941
9835
|
|
|
9942
9836
|
for (let i = 0; i < len; i += chunkSize) {
|
|
@@ -9950,7 +9844,7 @@
|
|
|
9950
9844
|
tree.insert(iStart, iEnd, subArray);
|
|
9951
9845
|
}
|
|
9952
9846
|
|
|
9953
|
-
return tree
|
|
9847
|
+
return tree
|
|
9954
9848
|
}
|
|
9955
9849
|
|
|
9956
9850
|
function hexToRGB(hex) {
|
|
@@ -10401,7 +10295,7 @@
|
|
|
10401
10295
|
min = Number.MAX_VALUE;
|
|
10402
10296
|
max = -Number.MAX_VALUE;
|
|
10403
10297
|
|
|
10404
|
-
for(let f of features) {
|
|
10298
|
+
for (let f of features) {
|
|
10405
10299
|
if (!Number.isNaN(f.value)) {
|
|
10406
10300
|
min = Math.min(min, f.value);
|
|
10407
10301
|
max = Math.max(max, f.value);
|
|
@@ -10475,19 +10369,6 @@
|
|
|
10475
10369
|
return false
|
|
10476
10370
|
};
|
|
10477
10371
|
|
|
10478
|
-
async function getFilename$1(url) {
|
|
10479
|
-
if (isString$3(url) && url.startsWith("https://drive.google.com")) {
|
|
10480
|
-
// This will fail if Google API key is not defined
|
|
10481
|
-
if (getApiKey() === undefined) {
|
|
10482
|
-
throw Error("Google drive is referenced, but API key is not defined. An API key is required for Google Drive access")
|
|
10483
|
-
}
|
|
10484
|
-
const json = await getDriveFileInfo(url);
|
|
10485
|
-
return json.originalFileName || json.name
|
|
10486
|
-
} else {
|
|
10487
|
-
return getFilename$2(url)
|
|
10488
|
-
}
|
|
10489
|
-
}
|
|
10490
|
-
|
|
10491
10372
|
function prettyBasePairNumber(raw) {
|
|
10492
10373
|
|
|
10493
10374
|
var denom,
|
|
@@ -10550,12 +10431,12 @@
|
|
|
10550
10431
|
const marginTop = parseInt(style.marginTop);
|
|
10551
10432
|
const marginBottom = parseInt(style.marginBottom);
|
|
10552
10433
|
|
|
10553
|
-
const {
|
|
10434
|
+
const {top, bottom, height} = element.getBoundingClientRect();
|
|
10554
10435
|
return {
|
|
10555
10436
|
top: Math.floor(top) - marginTop,
|
|
10556
10437
|
bottom: Math.floor(bottom) + marginBottom,
|
|
10557
10438
|
height: Math.floor(height) + marginTop + marginBottom
|
|
10558
|
-
}
|
|
10439
|
+
}
|
|
10559
10440
|
}
|
|
10560
10441
|
|
|
10561
10442
|
class Popover {
|
|
@@ -10745,7 +10626,7 @@
|
|
|
10745
10626
|
return list;
|
|
10746
10627
|
}
|
|
10747
10628
|
|
|
10748
|
-
/*! @license DOMPurify 3.
|
|
10629
|
+
/*! @license DOMPurify 3.3.0 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.3.0/LICENSE */
|
|
10749
10630
|
|
|
10750
10631
|
const {
|
|
10751
10632
|
entries,
|
|
@@ -10931,7 +10812,7 @@
|
|
|
10931
10812
|
}
|
|
10932
10813
|
|
|
10933
10814
|
const html$1 = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'search', 'section', 'select', 'shadow', 'slot', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']);
|
|
10934
|
-
const svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'enterkeyhint', 'exportparts', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'inputmode', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'part', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', '
|
|
10815
|
+
const svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'enterkeyhint', 'exportparts', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'inputmode', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'part', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']);
|
|
10935
10816
|
const svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feDropShadow', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']);
|
|
10936
10817
|
// List of SVG elements that are disallowed by default.
|
|
10937
10818
|
// We still need to know them so that we can do namespace
|
|
@@ -10945,7 +10826,7 @@
|
|
|
10945
10826
|
const text = freeze(['#text']);
|
|
10946
10827
|
|
|
10947
10828
|
const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'exportparts', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inert', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'part', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'slot', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns', 'slot']);
|
|
10948
|
-
const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'amplitude', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'exponent', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'intercept', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'slope', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'tablevalues', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
|
|
10829
|
+
const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'amplitude', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'exponent', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'intercept', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'mask-type', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'slope', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'tablevalues', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
|
|
10949
10830
|
const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lspace', 'lquote', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);
|
|
10950
10831
|
const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
|
|
10951
10832
|
|
|
@@ -11052,7 +10933,7 @@
|
|
|
11052
10933
|
function createDOMPurify() {
|
|
11053
10934
|
let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
|
|
11054
10935
|
const DOMPurify = root => createDOMPurify(root);
|
|
11055
|
-
DOMPurify.version = '3.
|
|
10936
|
+
DOMPurify.version = '3.3.0';
|
|
11056
10937
|
DOMPurify.removed = [];
|
|
11057
10938
|
if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
|
|
11058
10939
|
// Not running in a browser, provide a factory function
|
|
@@ -11163,6 +11044,21 @@
|
|
|
11163
11044
|
let FORBID_TAGS = null;
|
|
11164
11045
|
/* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
|
|
11165
11046
|
let FORBID_ATTR = null;
|
|
11047
|
+
/* Config object to store ADD_TAGS/ADD_ATTR functions (when used as functions) */
|
|
11048
|
+
const EXTRA_ELEMENT_HANDLING = Object.seal(create(null, {
|
|
11049
|
+
tagCheck: {
|
|
11050
|
+
writable: true,
|
|
11051
|
+
configurable: false,
|
|
11052
|
+
enumerable: true,
|
|
11053
|
+
value: null
|
|
11054
|
+
},
|
|
11055
|
+
attributeCheck: {
|
|
11056
|
+
writable: true,
|
|
11057
|
+
configurable: false,
|
|
11058
|
+
enumerable: true,
|
|
11059
|
+
value: null
|
|
11060
|
+
}
|
|
11061
|
+
}));
|
|
11166
11062
|
/* Decide if ARIA attributes are okay */
|
|
11167
11063
|
let ALLOW_ARIA_ATTR = true;
|
|
11168
11064
|
/* Decide if custom data attributes are okay */
|
|
@@ -11355,16 +11251,24 @@
|
|
|
11355
11251
|
}
|
|
11356
11252
|
/* Merge configuration parameters */
|
|
11357
11253
|
if (cfg.ADD_TAGS) {
|
|
11358
|
-
if (
|
|
11359
|
-
|
|
11254
|
+
if (typeof cfg.ADD_TAGS === 'function') {
|
|
11255
|
+
EXTRA_ELEMENT_HANDLING.tagCheck = cfg.ADD_TAGS;
|
|
11256
|
+
} else {
|
|
11257
|
+
if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
|
|
11258
|
+
ALLOWED_TAGS = clone(ALLOWED_TAGS);
|
|
11259
|
+
}
|
|
11260
|
+
addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
|
|
11360
11261
|
}
|
|
11361
|
-
addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
|
|
11362
11262
|
}
|
|
11363
11263
|
if (cfg.ADD_ATTR) {
|
|
11364
|
-
if (
|
|
11365
|
-
|
|
11264
|
+
if (typeof cfg.ADD_ATTR === 'function') {
|
|
11265
|
+
EXTRA_ELEMENT_HANDLING.attributeCheck = cfg.ADD_ATTR;
|
|
11266
|
+
} else {
|
|
11267
|
+
if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
|
|
11268
|
+
ALLOWED_ATTR = clone(ALLOWED_ATTR);
|
|
11269
|
+
}
|
|
11270
|
+
addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
|
|
11366
11271
|
}
|
|
11367
|
-
addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
|
|
11368
11272
|
}
|
|
11369
11273
|
if (cfg.ADD_URI_SAFE_ATTR) {
|
|
11370
11274
|
addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
|
|
@@ -11672,7 +11576,7 @@
|
|
|
11672
11576
|
return true;
|
|
11673
11577
|
}
|
|
11674
11578
|
/* Remove element if anything forbids its presence */
|
|
11675
|
-
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|
|
11579
|
+
if (!(EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function && EXTRA_ELEMENT_HANDLING.tagCheck(tagName)) && (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName])) {
|
|
11676
11580
|
/* Check if we have a custom element to handle */
|
|
11677
11581
|
if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {
|
|
11678
11582
|
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
|
|
@@ -11744,7 +11648,7 @@
|
|
|
11744
11648
|
(https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
|
|
11745
11649
|
XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
|
|
11746
11650
|
We don't need to check the value; it's always URI safe. */
|
|
11747
|
-
if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
|
|
11651
|
+
if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) ; else if (EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
|
|
11748
11652
|
if (
|
|
11749
11653
|
// First condition does a very basic check if a) it's basically a valid custom element tagname AND
|
|
11750
11654
|
// b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
|
|
@@ -17151,7 +17055,7 @@
|
|
|
17151
17055
|
} else if (isFile(config.url)) {
|
|
17152
17056
|
this.name = config.url.name;
|
|
17153
17057
|
} else if (isString$3(config.url) && !config.url.startsWith("data:")) {
|
|
17154
|
-
this.name = getFilename$
|
|
17058
|
+
this.name = getFilename$1(config.url);
|
|
17155
17059
|
}
|
|
17156
17060
|
|
|
17157
17061
|
this.url = config.url;
|
|
@@ -20670,6 +20574,7 @@
|
|
|
20670
20574
|
|
|
20671
20575
|
switch (config.format) {
|
|
20672
20576
|
case "vcf":
|
|
20577
|
+
case "vcftabix":
|
|
20673
20578
|
return new VcfParser(config)
|
|
20674
20579
|
case "seg" :
|
|
20675
20580
|
return new SegParser("seg")
|
|
@@ -21110,7 +21015,7 @@
|
|
|
21110
21015
|
config.format = format.toLowerCase();
|
|
21111
21016
|
config.sourceType = "htsget";
|
|
21112
21017
|
if (!config.name) {
|
|
21113
|
-
config.name =
|
|
21018
|
+
config.name = getFilename$1(config.url);
|
|
21114
21019
|
}
|
|
21115
21020
|
}
|
|
21116
21021
|
} catch (e) {
|
|
@@ -21281,6 +21186,7 @@
|
|
|
21281
21186
|
}
|
|
21282
21187
|
}
|
|
21283
21188
|
|
|
21189
|
+
// Base class for feature sources. Subclasses must implement getFeatures().
|
|
21284
21190
|
class BaseFeatureSource {
|
|
21285
21191
|
|
|
21286
21192
|
constructor(genome) {
|
|
@@ -21342,59 +21248,10 @@
|
|
|
21342
21248
|
}
|
|
21343
21249
|
}
|
|
21344
21250
|
|
|
21345
|
-
|
|
21346
|
-
|
|
21347
|
-
|
|
21348
|
-
let idx = chromosomeNames.indexOf(chr);
|
|
21349
|
-
if (idx < 0) return // This shouldn't happen
|
|
21350
|
-
|
|
21351
|
-
// Look ahead (or behind) in 10 kb intervals, but no further than visibilityWindow
|
|
21352
|
-
const window = Math.min(10000, visibilityWindow || 10000);
|
|
21353
|
-
let queryStart = direction ? position : Math.max(position - window, 0);
|
|
21354
|
-
while (idx < chromosomeNames.length && idx >= 0) {
|
|
21355
|
-
chr = chromosomeNames[idx];
|
|
21356
|
-
const chromosome = this.genome.getChromosome(chr);
|
|
21357
|
-
const chromosomeEnd = chromosome.bpLength;
|
|
21358
|
-
while (queryStart < chromosomeEnd && queryStart >= 0) {
|
|
21359
|
-
let queryEnd = Math.min(position, queryStart + window);
|
|
21360
|
-
const featureList = await this.getFeatures({chr, start: queryStart, end: queryEnd, visibilityWindow});
|
|
21361
|
-
if (featureList) {
|
|
21362
|
-
|
|
21363
|
-
const compare = (o1, o2) => o1.start - o2.start + o1.end - o2.end;
|
|
21364
|
-
const sortedList = Array.from(featureList);
|
|
21365
|
-
sortedList.sort(compare);
|
|
21366
|
-
|
|
21367
|
-
// Search for next or previous feature relative to centers. We use a linear search because the
|
|
21368
|
-
// feature is likely to be near the first or end of the list
|
|
21369
|
-
let idx = direction ? 0 : sortedList.length - 1;
|
|
21370
|
-
while(idx >= 0 && idx < sortedList.length) {
|
|
21371
|
-
const f = sortedList[idx];
|
|
21372
|
-
const center = (f.start + f.end) / 2;
|
|
21373
|
-
if(direction) {
|
|
21374
|
-
if(center > position) return f
|
|
21375
|
-
idx++;
|
|
21376
|
-
} else {
|
|
21377
|
-
if(center < position) return f
|
|
21378
|
-
idx--;
|
|
21379
|
-
}
|
|
21380
|
-
}
|
|
21381
|
-
}
|
|
21382
|
-
queryStart = direction ? queryEnd : queryStart - window;
|
|
21383
|
-
}
|
|
21384
|
-
if (direction) {
|
|
21385
|
-
idx++;
|
|
21386
|
-
queryStart = 0;
|
|
21387
|
-
position = 0;
|
|
21388
|
-
} else {
|
|
21389
|
-
idx--;
|
|
21390
|
-
if (idx < 0) break
|
|
21391
|
-
const prevChromosome = this.genome.getChromosome(chromosomeNames[idx]);
|
|
21392
|
-
position = prevChromosome.bpLength;
|
|
21393
|
-
queryStart = position - window;
|
|
21394
|
-
}
|
|
21395
|
-
}
|
|
21251
|
+
// Subclasses must implement
|
|
21252
|
+
async getFeatures({chr, start, end, bpPerPixel, visibilityWindow}) {
|
|
21253
|
+
throw new Error("getFeatures not implemented")
|
|
21396
21254
|
}
|
|
21397
|
-
|
|
21398
21255
|
}
|
|
21399
21256
|
|
|
21400
21257
|
const GZIP_FLAG = 0x1;
|
|
@@ -26533,6 +26390,88 @@
|
|
|
26533
26390
|
}
|
|
26534
26391
|
}
|
|
26535
26392
|
|
|
26393
|
+
/**
|
|
26394
|
+
* A feature source for a "list" file. A list file is a text file with two columns, chromosome and URL. It was
|
|
26395
|
+
* created for the 1KG genotype files, which are split by chromosome, and at the moment that is the only use case.
|
|
26396
|
+
*/
|
|
26397
|
+
|
|
26398
|
+
class ListFeatureSource extends BaseFeatureSource {
|
|
26399
|
+
|
|
26400
|
+
constructor(config, genome) {
|
|
26401
|
+
super(genome);
|
|
26402
|
+
this.config = config;
|
|
26403
|
+
this.featureSourceMap = null;
|
|
26404
|
+
this.header = null;
|
|
26405
|
+
}
|
|
26406
|
+
|
|
26407
|
+
async getHeader() {
|
|
26408
|
+
|
|
26409
|
+
if (!this.header) {
|
|
26410
|
+
|
|
26411
|
+
if (!this.featureSourceMap) {
|
|
26412
|
+
await this.init();
|
|
26413
|
+
}
|
|
26414
|
+
// Return the header from the first feature source. It is assumed that all sources have a common header.
|
|
26415
|
+
const firstFS = this.featureSourceMap.values().next().value;
|
|
26416
|
+
if (firstFS && firstFS.getHeader) {
|
|
26417
|
+
this.header = firstFS.getHeader();
|
|
26418
|
+
} else {
|
|
26419
|
+
this.header = Promise.resolve(undefined);
|
|
26420
|
+
}
|
|
26421
|
+
}
|
|
26422
|
+
|
|
26423
|
+
return this.header
|
|
26424
|
+
|
|
26425
|
+
}
|
|
26426
|
+
|
|
26427
|
+
async getFeatures({chr, start, end, bpPerPixel, visibilityWindow}) {
|
|
26428
|
+
|
|
26429
|
+
if (!this.featureSourceMap) {
|
|
26430
|
+
await this.init();
|
|
26431
|
+
}
|
|
26432
|
+
const fs = this.featureSourceMap.get(chr);
|
|
26433
|
+
if (fs) {
|
|
26434
|
+
return fs.getFeatures({chr, start, end, bpPerPixel, visibilityWindow})
|
|
26435
|
+
} else {
|
|
26436
|
+
return []
|
|
26437
|
+
}
|
|
26438
|
+
}
|
|
26439
|
+
|
|
26440
|
+
async init() {
|
|
26441
|
+
this.featureSourceMap = new Map();
|
|
26442
|
+
|
|
26443
|
+
const options = buildOptions(this.config);
|
|
26444
|
+
const data = await igvxhr.loadByteArray(this.config.url, options);
|
|
26445
|
+
const dataWrapper = getDataWrapper(data);
|
|
26446
|
+
|
|
26447
|
+
let line;
|
|
26448
|
+
while ((line = dataWrapper.nextLine()) !== undefined) {
|
|
26449
|
+
const trimmed = line.trim();
|
|
26450
|
+
if (!trimmed.startsWith('#')) {
|
|
26451
|
+
const tokens = trimmed.split(/\s+/);
|
|
26452
|
+
if (tokens.length > 1) {
|
|
26453
|
+
const chr = tokens[0];
|
|
26454
|
+
const path = tokens[1];
|
|
26455
|
+
const sourceConfig = Object.assign({}, this.config);
|
|
26456
|
+
sourceConfig.url = path;
|
|
26457
|
+
if (path.endsWith(".vcf.gz")) {
|
|
26458
|
+
sourceConfig.format = "vcf";
|
|
26459
|
+
sourceConfig.indexURL = path + ".tbi";
|
|
26460
|
+
}
|
|
26461
|
+
this.featureSourceMap.set(chr, FeatureSource(sourceConfig, this.genome));
|
|
26462
|
+
}
|
|
26463
|
+
}
|
|
26464
|
+
}
|
|
26465
|
+
}
|
|
26466
|
+
|
|
26467
|
+
supportWholeGenome() {
|
|
26468
|
+
return false
|
|
26469
|
+
}
|
|
26470
|
+
}
|
|
26471
|
+
|
|
26472
|
+
// chrY https://1000genomes.s3.amazonaws.com/release/20130502/ALL.chrY.phase3_integrated_v1b.20130502.genotypes.vcf.gz
|
|
26473
|
+
// chrX https://1000genomes.s3.amazonaws.com/release/20130502/ALL.chrX.phase3_shapeit2_mvncall_integrated_v1b.20130502.genotypes.vcf.gz
|
|
26474
|
+
|
|
26536
26475
|
const bbFormats = new Set(['bigwig', 'bw', 'bigbed', 'bb', 'biginteract', 'biggenepred', 'bignarrowpeak']);
|
|
26537
26476
|
|
|
26538
26477
|
function FeatureSource(config, genome) {
|
|
@@ -26547,6 +26486,9 @@
|
|
|
26547
26486
|
return new TDFSource(config, genome)
|
|
26548
26487
|
} else if ("gbk" === format) {
|
|
26549
26488
|
return new GenbankFeatureSource(config, genome)
|
|
26489
|
+
} else if ("vcf.list" === format) {
|
|
26490
|
+
// This is a text file with two columns: <chr> <url to vcf>
|
|
26491
|
+
return new ListFeatureSource(config, genome)
|
|
26550
26492
|
} else {
|
|
26551
26493
|
return new TextFeatureSource(config, genome)
|
|
26552
26494
|
}
|
|
@@ -30409,6 +30351,19 @@
|
|
|
30409
30351
|
const filterTracks = new Set(["cytoBandIdeo", "assembly", "gap", "gapOverlap", "allGaps",
|
|
30410
30352
|
"cpgIslandExtUnmasked", "windowMasker"]);
|
|
30411
30353
|
|
|
30354
|
+
const vizModeMap = new Map([
|
|
30355
|
+
["pack", "EXPANDED"],
|
|
30356
|
+
["full", "EXPANDED"],
|
|
30357
|
+
["squish", "SQUISHED"],
|
|
30358
|
+
["dense", "COLLAPSED"]
|
|
30359
|
+
]);
|
|
30360
|
+
const typeFormatMap = new Map([
|
|
30361
|
+
["vcftabix", "vcf"],
|
|
30362
|
+
["vcfphasedtrio", "vcf"],
|
|
30363
|
+
["bigdbsnp", "bigbed"],
|
|
30364
|
+
["genepred", "refgene"]
|
|
30365
|
+
]);
|
|
30366
|
+
|
|
30412
30367
|
class TrackDbHub {
|
|
30413
30368
|
|
|
30414
30369
|
constructor(trackStanzas, groupStanzas) {
|
|
@@ -30554,14 +30509,13 @@
|
|
|
30554
30509
|
*/
|
|
30555
30510
|
#getTrackConfig(t) {
|
|
30556
30511
|
|
|
30557
|
-
const format = t.format;
|
|
30512
|
+
const format = typeFormatMap.get(t.format) || t.format;
|
|
30558
30513
|
|
|
30559
30514
|
const config = {
|
|
30560
30515
|
"id": t.getProperty("track"),
|
|
30561
30516
|
"name": t.getProperty("shortLabel"),
|
|
30562
30517
|
"format": format,
|
|
30563
|
-
"url": t.getProperty("bigDataUrl")
|
|
30564
|
-
"displayMode": t.displayMode,
|
|
30518
|
+
"url": t.getProperty("bigDataUrl")
|
|
30565
30519
|
};
|
|
30566
30520
|
|
|
30567
30521
|
if ("vcfTabix" === format) {
|
|
@@ -30611,9 +30565,14 @@
|
|
|
30611
30565
|
|
|
30612
30566
|
}
|
|
30613
30567
|
if (t.hasProperty("itemRgb")) ;
|
|
30614
|
-
if
|
|
30615
|
-
|
|
30616
|
-
|
|
30568
|
+
if(t.hasProperty("visibility")) {
|
|
30569
|
+
if ("hide" === t.getProperty("visibility")) {
|
|
30570
|
+
// TODO -- this not supported yet
|
|
30571
|
+
config.visible = false;
|
|
30572
|
+
}
|
|
30573
|
+
else {
|
|
30574
|
+
config.displayMode = vizModeMap.get(t.getProperty("visibility")) || "COLLAPSED";
|
|
30575
|
+
}
|
|
30617
30576
|
}
|
|
30618
30577
|
if (t.hasProperty("url")) {
|
|
30619
30578
|
config.infoURL = t.getProperty("url");
|
|
@@ -31591,7 +31550,7 @@
|
|
|
31591
31550
|
|
|
31592
31551
|
this.overlayElement.style.top = `-${contentTop}px`;
|
|
31593
31552
|
|
|
31594
|
-
if(!this.checkZoomIn()) return
|
|
31553
|
+
if (!this.checkZoomIn()) return
|
|
31595
31554
|
|
|
31596
31555
|
if (!this.canvas) {
|
|
31597
31556
|
this.repaint();
|
|
@@ -32230,7 +32189,7 @@
|
|
|
32230
32189
|
|
|
32231
32190
|
popupTimerID = setTimeout(() => {
|
|
32232
32191
|
|
|
32233
|
-
const content = this.
|
|
32192
|
+
const content = this.handleTrackClick(event);
|
|
32234
32193
|
if (content) {
|
|
32235
32194
|
|
|
32236
32195
|
if (false === event.shiftKey) {
|
|
@@ -32395,7 +32354,7 @@
|
|
|
32395
32354
|
|
|
32396
32355
|
}
|
|
32397
32356
|
|
|
32398
|
-
|
|
32357
|
+
handleTrackClick(event) {
|
|
32399
32358
|
|
|
32400
32359
|
const clickState = this.createClickState(event);
|
|
32401
32360
|
|
|
@@ -37794,6 +37753,8 @@
|
|
|
37794
37753
|
case "tdf":
|
|
37795
37754
|
return "wig"
|
|
37796
37755
|
case "vcf":
|
|
37756
|
+
case "vcftabix":
|
|
37757
|
+
case "vcf.list":
|
|
37797
37758
|
return "variant"
|
|
37798
37759
|
case "seg":
|
|
37799
37760
|
return "seg"
|
|
@@ -37848,7 +37809,7 @@
|
|
|
37848
37809
|
} else if ("bam" === config.type) {
|
|
37849
37810
|
config.type = "alignment";
|
|
37850
37811
|
config.format = "bam";
|
|
37851
|
-
} else if ("vcf" === config.type) {
|
|
37812
|
+
} else if ("vcf" === config.type || "vcftabix" === config.type) {
|
|
37852
37813
|
config.type = "variant";
|
|
37853
37814
|
config.format = "vcf";
|
|
37854
37815
|
} else if ("t2d" === config.type) {
|
|
@@ -38128,7 +38089,7 @@
|
|
|
38128
38089
|
const groupIndeces = NULL_GROUP !== this.groupBy ?
|
|
38129
38090
|
this.sampleKeys.map(sample => this.getGroupIndex(sample)) : undefined;
|
|
38130
38091
|
return {
|
|
38131
|
-
names: this.sampleKeys,
|
|
38092
|
+
names: this.sampleKeys || [],
|
|
38132
38093
|
height: this.sampleHeight,
|
|
38133
38094
|
yOffset: 0,
|
|
38134
38095
|
groups: this.groups,
|
|
@@ -42541,7 +42502,7 @@
|
|
|
42541
42502
|
let format;
|
|
42542
42503
|
|
|
42543
42504
|
// First try determining format from file extension
|
|
42544
|
-
const filename = config.filename ||
|
|
42505
|
+
const filename = config.filename || getFilename$1(config.url);
|
|
42545
42506
|
if(filename) {
|
|
42546
42507
|
format = await inferFileFormatFromName(filename);
|
|
42547
42508
|
}
|
|
@@ -62825,7 +62786,8 @@ ${indent}columns: ${matrix.columns}
|
|
|
62825
62786
|
}
|
|
62826
62787
|
|
|
62827
62788
|
get supportsWholeGenome() {
|
|
62828
|
-
|
|
62789
|
+
const sourceSupportsWG = typeof this.featureSource.supportsWholeGenome === 'function' && this.featureSource.supportsWholeGenome();
|
|
62790
|
+
return sourceSupportsWG || this.config.supportsWholeGenome === true
|
|
62829
62791
|
}
|
|
62830
62792
|
|
|
62831
62793
|
get color() {
|
|
@@ -62898,7 +62860,7 @@ ${indent}columns: ${matrix.columns}
|
|
|
62898
62860
|
const yOffset = TOP_MARGIN + nVariantRows * (variantHeight + vGap);
|
|
62899
62861
|
|
|
62900
62862
|
return {
|
|
62901
|
-
names: this.sampleKeys,
|
|
62863
|
+
names: this.sampleKeys || [],
|
|
62902
62864
|
yOffset,
|
|
62903
62865
|
height,
|
|
62904
62866
|
// groups: this.groups,
|
|
@@ -67029,7 +66991,7 @@ ${indent}columns: ${matrix.columns}
|
|
|
67029
66991
|
})
|
|
67030
66992
|
}
|
|
67031
66993
|
|
|
67032
|
-
const _version = "3.5.
|
|
66994
|
+
const _version = "3.5.4";
|
|
67033
66995
|
function version() {
|
|
67034
66996
|
return _version
|
|
67035
66997
|
}
|
|
@@ -68933,7 +68895,7 @@ ${indent}columns: ${matrix.columns}
|
|
|
68933
68895
|
|
|
68934
68896
|
for (let config of configs) {
|
|
68935
68897
|
if (!config.name && config.url) {
|
|
68936
|
-
config.name =
|
|
68898
|
+
config.name = getFilename$1(config.url);
|
|
68937
68899
|
}
|
|
68938
68900
|
if (config.url && !config.format) {
|
|
68939
68901
|
config.format = await inferFileFormat(config);
|
|
@@ -73720,7 +73682,8 @@ ${indent}columns: ${matrix.columns}
|
|
|
73720
73682
|
return handler.apply(scope, args)
|
|
73721
73683
|
});
|
|
73722
73684
|
|
|
73723
|
-
return
|
|
73685
|
+
// The only event that uses the return value is "trackclick", which implicitly assumes a single handler
|
|
73686
|
+
return results[0]
|
|
73724
73687
|
}
|
|
73725
73688
|
}
|
|
73726
73689
|
|
|
@@ -74091,7 +74054,7 @@ ${indent}columns: ${matrix.columns}
|
|
|
74091
74054
|
} else {
|
|
74092
74055
|
let filename = options.filename;
|
|
74093
74056
|
if (!filename) {
|
|
74094
|
-
filename = (options.url ?
|
|
74057
|
+
filename = (options.url ? getFilename$1(options.url) : options.file.name);
|
|
74095
74058
|
}
|
|
74096
74059
|
|
|
74097
74060
|
if (filename.endsWith(".xml")) {
|
|
@@ -74105,10 +74068,8 @@ ${indent}columns: ${matrix.columns}
|
|
|
74105
74068
|
config = {
|
|
74106
74069
|
reference: genomeConfig
|
|
74107
74070
|
};
|
|
74108
|
-
} else
|
|
74071
|
+
} else {
|
|
74109
74072
|
config = await igvxhr.loadJson(urlOrFile);
|
|
74110
|
-
} else {
|
|
74111
|
-
throw Error("Unrecognized session file format:" + filename)
|
|
74112
74073
|
}
|
|
74113
74074
|
}
|
|
74114
74075
|
setDefaults(config, defaults);
|
|
@@ -74576,6 +74537,10 @@ ${indent}columns: ${matrix.columns}
|
|
|
74576
74537
|
config = JSON.parse(config);
|
|
74577
74538
|
}
|
|
74578
74539
|
|
|
74540
|
+
if(config.format && config.format.toLowerCase() === 'sampleinfo') {
|
|
74541
|
+
return this.loadSampleInfo(config)
|
|
74542
|
+
}
|
|
74543
|
+
|
|
74579
74544
|
let track;
|
|
74580
74545
|
try {
|
|
74581
74546
|
track = await this.createTrack(config);
|
|
@@ -76352,6 +76317,10 @@ ${indent}columns: ${matrix.columns}
|
|
|
76352
76317
|
return igvxhr.setOauthToken(accessToken, host)
|
|
76353
76318
|
}
|
|
76354
76319
|
|
|
76320
|
+
function setCORSProxy(proxyURL) {
|
|
76321
|
+
igvxhr.corsProxy = proxyURL;
|
|
76322
|
+
}
|
|
76323
|
+
|
|
76355
76324
|
// Backward compatibility
|
|
76356
76325
|
const oauth = igvxhr.oauth;
|
|
76357
76326
|
|
|
@@ -76368,6 +76337,7 @@ ${indent}columns: ${matrix.columns}
|
|
|
76368
76337
|
visibilityChange,
|
|
76369
76338
|
setGoogleOauthToken,
|
|
76370
76339
|
setOauthToken,
|
|
76340
|
+
setCORSProxy,
|
|
76371
76341
|
oauth,
|
|
76372
76342
|
version,
|
|
76373
76343
|
setApiKey,
|