icn3d 3.38.1 → 3.39.0

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/icn3d.js CHANGED
@@ -14252,7 +14252,7 @@ class SetDialog {
14252
14252
  html += me.htmlCls.divStr + "dl_collectionsMenu'>";
14253
14253
  html += '<b>Collection File</b>: <div style="width:20px; margin-top:6px; display:inline-block;"><span id="' + me.pre + 'dl_collection_file_expand" class="ui-icon ui-icon-plus icn3d-expand icn3d-link" style="display:none; width:15px;" title="Expand"></span><span id="' + me.pre + 'dl_collection_file_shrink" class="ui-icon ui-icon-minus icn3d-shrink icn3d-link" style="width:15px;" title="Shrink"></span></div><br>';
14254
14254
  html += me.htmlCls.divStr + "dl_collection_file' style=''>";
14255
- html += "You can load a collection of structures via a file. Here is <a href='https://github.com/ncbi/icn3d/blob/master/example/collection.json' target='_blank'>one example file</a><br><br>";
14255
+ html += "You can load a collection of structures via a file. Here are <a href='https://github.com/ncbi/icn3d/blob/master/example/collection/' target='_blank'>some example files</a><br><br>";
14256
14256
  html += "Collection file: " + me.htmlCls.inputFileStr + "id='" + me.pre + "collectionfile'><br/>";
14257
14257
  html += me.htmlCls.buttonStr + "reload_collectionfile' style='margin-top: 6px;'>Load</button>";
14258
14258
  html += "</div>";
@@ -14260,7 +14260,26 @@ class SetDialog {
14260
14260
  html += '<br/><b>Structures</b>: <div style="width:20px; margin-top:6px; display:inline-block;"><span id="' + me.pre + 'dl_collection_structures_expand" class="ui-icon ui-icon-plus icn3d-expand icn3d-link" style="width:15px;" title="Expand"></span><span id="' + me.pre + 'dl_collection_structures_shrink" class="ui-icon ui-icon-minus icn3d-shrink icn3d-link" style="display:none; width:15px;" title="Shrink"></span></div><br>';
14261
14261
  html += me.htmlCls.divStr + "dl_collection_structures' style='display: none'>";
14262
14262
  html += "<select id='" + me.pre + "collections_menu'multiple size='6' style='min-width:300px;'></select>";
14263
+ html += '<br/>';
14264
+ html += me.htmlCls.buttonStr + "opendl_export_collections'>Export</button>";
14263
14265
  html += "</div>";
14266
+ html += '<br/>';
14267
+ html += "</div>";
14268
+
14269
+ html += me.htmlCls.divStr + "dl_export_collections' class='" + dialogClass + "'>";
14270
+ html += this.addNotebookTitle('dl_export_collections', 'Export Collections');
14271
+ html += "<label for='dl_collectionTitle'>Collection Title: </label>";
14272
+ html += "<input type='text' id='dl_collectionTitle' name='collectionTitle' placeholder='Enter collection title' />";
14273
+ html += '<br/>';
14274
+ html += "<label for='dl_collectionDescription'>Collection Description: </label>";
14275
+ html += "<input type='text' id='dl_collectionDescription' name='collectionDescription' placeholder='Enter collection description' />";
14276
+ html += '<br/>';
14277
+ html += "<input type='radio' id='dl_collectionExportSelected' name='exportOption' value='selected' />";
14278
+ html += "<label for='dl_collectionExportSelected'>Selected</label>";
14279
+ html += "<input type='radio' id='dl_collectionExportAll' name='exportOption' value='all' />";
14280
+ html += "<label for='dl_collectionExportAll'>All</label>";
14281
+ html += '<br/>';
14282
+ html += me.htmlCls.buttonStr + "export_collections'>Export</button>";
14264
14283
  html += "</div>";
14265
14284
 
14266
14285
  html += me.htmlCls.divStr + "dl_menuloadpref' class='" + dialogClass + "'>";
@@ -15591,8 +15610,8 @@ class Events {
15591
15610
 
15592
15611
  saveHtml(id) { let me = this.icn3dui, ic = me.icn3d;
15593
15612
  let html = '';
15594
- html += '<link rel="stylesheet" href="https:///structure.ncbi.nlm.nih.gov/icn3d/lib/jquery-ui-1.13.2.min.css">\n';
15595
- html += '<link rel="stylesheet" href="https:///structure.ncbi.nlm.nih.gov/icn3d/icn3d_full_ui.css">\n';
15613
+ html += '<link rel="stylesheet" href="https://www.ncbi.nlm.nih.gov/Structure/icn3d/lib/jquery-ui-1.13.2.min.css">\n';
15614
+ html += '<link rel="stylesheet" href="https://www.ncbi.nlm.nih.gov/Structure/icn3d/icn3d_full_ui.css">\n';
15596
15615
  html += $("#" + id).html();
15597
15616
  let idArray = id.split('_');
15598
15617
  let idStr =(idArray.length > 2) ? idArray[2] : id;
@@ -16681,7 +16700,6 @@ class Events {
16681
16700
 
16682
16701
  urlTarget = '_blank';
16683
16702
 
16684
- console.log("smiles: " + $("#" + me.pre + "smiles").val() + " encode: " + encodeURIComponent($("#" + me.pre + "smiles").val()));
16685
16703
  window.open(hostUrl + '?smiles=' + encodeURIComponent($("#" + me.pre + "smiles").val()), urlTarget);
16686
16704
  });
16687
16705
 
@@ -16764,28 +16782,232 @@ class Events {
16764
16782
  $(".ui-dialog-content").dialog("close");
16765
16783
  } else {
16766
16784
  ic.resizeCanvasCls.closeDialogs();
16767
- }
16785
+ }
16786
+ ic.bInputfile = false;
16787
+ ic.pdbCollection = [];
16788
+ ic.allData = {};
16789
+ ic.allData['all'] = {
16790
+ 'atoms': {},
16791
+ 'proteins': {},
16792
+ 'nucleotides': {},
16793
+ 'chemicals': {},
16794
+ 'ions': {},
16795
+ 'water': {},
16796
+ 'structures': {}, // getSSExpandedAtoms
16797
+ 'ssbondpnts': {},
16798
+ 'residues': {}, // getSSExpandedAtoms
16799
+ 'chains': {},
16800
+ 'chainsSeq': {}, //Sequences and Annotation
16801
+ 'defNames2Atoms': {},
16802
+ 'defNames2Residues': {}
16803
+ };
16804
+ ic.allData['prev'] = {};
16805
+ ic.selectCollectionsCls.reset();
16806
+
16807
+ ic.dAtoms = me.hashUtilsCls.cloneHash(ic.atoms);
16808
+ ic.hAtoms = me.hashUtilsCls.cloneHash(ic.atoms);
16768
16809
  me.htmlCls.setHtmlCls.fileSupport();
16810
+
16811
+ let fileName = file.name;
16812
+ let fileExtension = fileName.split('.').pop().toLowerCase();
16813
+
16814
+ $("#" + ic.pre + "collections_menu").empty();
16815
+ $("#" + ic.pre + "collections_menu").off("change");
16816
+
16817
+ function parseJsonCollection(data) {
16818
+ let dataStr = JSON.parse(data);
16819
+ return dataStr["structures"].map(({ id, title, description, commands }) => {
16820
+ if (id && id.includes('.pdb')) {
16821
+ id = id.split('.pdb')[0];
16822
+ }
16823
+ return [id, title, description, commands, false];
16824
+ });
16825
+ }
16826
+
16827
+ function parsePdbCollection(data, description = '', commands = []) {
16828
+ let dataStr = data;
16829
+ let lines = dataStr.split('\n');
16830
+
16831
+ let sections = [];
16832
+ let currentSection = [];
16833
+
16834
+ lines.forEach(line => {
16835
+ if (line.startsWith('HEADER')) {
16836
+ currentSection = [];
16837
+ sections.push(currentSection);
16838
+ }
16839
+ currentSection.push(line);
16840
+ });
16841
+
16842
+ let ids = [];
16843
+ let titles = [];
16844
+
16845
+ sections.forEach((section) => {
16846
+ let headerLine = section[0];
16847
+ headerLine = headerLine.replace(/[\n\r]/g, '').trim();
16848
+ let header = headerLine.split(' ').filter(Boolean);
16849
+ let lastElement = header[header.length - 1];
16850
+ ids.push(lastElement);
16851
+ titles.push(section[1].startsWith('TITLE') ? section[1].split('TITLE').pop().trim() : lastElement);
16852
+ });
16853
+
16854
+ if (sections.length > 0) {
16855
+ ic.pdbCollection.push(...sections);
16856
+ }
16857
+
16858
+ return ids.map((id, index, description, commands) => [id, titles[index], description, commands, true]);
16859
+ }
16860
+
16861
+ let collection = [];
16862
+
16863
+ if (fileExtension === 'json' || fileExtension === 'pdb') {
16769
16864
  let reader = new FileReader();
16770
-
16771
16865
  reader.onload = async function (e) {
16772
- let dataStr = JSON.parse(e.target.result);
16773
- let collection = [dataStr["structures"].map(({ id }) => id), dataStr["structures"].map(({ title }) => title)];
16774
- let collectionHtml = ic.selectCollectionsCls.setAtomMenu(collection[0], collection[1]);
16866
+ if (fileExtension === 'json') {
16867
+ collection = parseJsonCollection(e.target.result);
16868
+ } else if (fileExtension === 'pdb') {
16869
+ ic.bInputfile = true;
16870
+ collection = parsePdbCollection(e.target.result);
16871
+ }
16775
16872
 
16776
- $("#" + ic.pre + "collections_menu").html(collectionHtml);
16777
- ic.selectCollectionsCls.clickStructure();
16778
-
16779
- $("#" + ic.pre + "collections_menu").trigger("change");
16780
-
16781
- me.htmlCls.clickMenuCls.setLogCmd(
16782
- "load collection file " +
16783
- $("#" + me.pre + "collectionfile").val(),
16784
- false
16785
- );
16786
-
16787
- };
16788
- reader.readAsText(file);
16873
+ let collectionHtml = await ic.selectCollectionsCls.setAtomMenu(collection);
16874
+
16875
+ $("#" + ic.pre + "collections_menu").html(collectionHtml);
16876
+ await ic.selectCollectionsCls.clickStructure(collection);
16877
+ $("#" + ic.pre + "collections_menu").trigger("change");
16878
+
16879
+ me.htmlCls.clickMenuCls.setLogCmd(
16880
+ "load collection file " +
16881
+ $("#" + me.pre + "collectionfile").val(),
16882
+ false
16883
+ );
16884
+ };
16885
+
16886
+ reader.readAsText(file);
16887
+ } else if (fileExtension === 'zip' || fileExtension === 'gz') {
16888
+ ic.bInputfile = true;
16889
+ let reader2 = new FileReader();
16890
+ reader2.onload = async function (e) {
16891
+ if (fileExtension === 'zip') {
16892
+ let url = './script/jszip.js';
16893
+ await me.getAjaxPromise(url, 'script');
16894
+
16895
+ let jszip = new JSZip();
16896
+ try {
16897
+ let data = await jszip.loadAsync(e.target.result);
16898
+
16899
+ let hasJson = false;
16900
+ let hasPdb = false;
16901
+ let hasGz = false;
16902
+ let jsonFiles = [];
16903
+ let pdbFiles = [];
16904
+ let gzFiles = [];
16905
+
16906
+ for (let fileName in data.files) {
16907
+ let file = data.files[fileName];
16908
+ if (!file.dir) {
16909
+ if (fileName.endsWith('.json')) {
16910
+ hasJson = true;
16911
+ jsonFiles.push(file);
16912
+ } else if (fileName.endsWith('.pdb')) {
16913
+ hasPdb = true;
16914
+ pdbFiles.push(file);
16915
+ } else if (fileName.endsWith('.gz')) {
16916
+ hasGz = true;
16917
+ gzFiles.push(file);
16918
+ }
16919
+ }
16920
+ }
16921
+
16922
+ if (hasJson && hasPdb) {
16923
+ let jsonCollection = [];
16924
+ for (const file of jsonFiles) {
16925
+ let fileData = await file.async('text');
16926
+ parseJsonCollection(fileData).forEach(element => {
16927
+ jsonCollection.push(element);
16928
+ });
16929
+ }
16930
+
16931
+ // For each JSON object, check if a corresponding PDB file exists
16932
+ for (const [id, title, description, commands, _] of jsonCollection) {
16933
+ let matchingPdbFile = pdbFiles.find(file => file.name.toLowerCase().includes(id.toLowerCase()));
16934
+ if (matchingPdbFile) {
16935
+ let pdbFileData = await matchingPdbFile.async('text');
16936
+ parsePdbCollection(pdbFileData, description, commands).forEach(element => {
16937
+ collection.push(element);
16938
+ });
16939
+ }
16940
+ }
16941
+
16942
+ } else if (hasJson) {
16943
+ // Do something if only JSON files are present
16944
+ jsonFiles.forEach(async file => {
16945
+ let fileData = await file.async('text');
16946
+ parseJsonCollection(fileData).forEach(element => {
16947
+ collection.push(element);
16948
+ });
16949
+ });
16950
+ } else if (hasPdb) {
16951
+ // Do something if only PDB files are present
16952
+ pdbFiles.forEach(async file => {
16953
+ let fileData = await file.async('text');
16954
+ parsePdbCollection(fileData).forEach(element => {
16955
+ collection.push(element);
16956
+ });
16957
+ });
16958
+ } else if (hasGz) {
16959
+ let url = './script/pako.js';
16960
+ await me.getAjaxPromise(url, 'script');
16961
+ try {
16962
+ for (const file of gzFiles) {
16963
+ let compressed = await file.async('uint8array');
16964
+ let decompressed = pako.inflate(compressed, { to: 'string' });
16965
+ parsePdbCollection(decompressed).forEach(element => {
16966
+ collection.push(element);
16967
+ });
16968
+ }
16969
+ } catch (error) {
16970
+ console.error('Error loading GZ file', error);
16971
+ }
16972
+ }
16973
+ } catch (error) {
16974
+ console.error('Error loading ZIP file', error);
16975
+ }
16976
+ } else if (fileExtension === 'gz') {
16977
+ let url = './script/pako.js';
16978
+ await me.getAjaxPromise(url, 'script');
16979
+
16980
+ try {
16981
+ const compressed = new Uint8Array(e.target.result);
16982
+ const decompressed = pako.inflate(compressed, { to: 'string' });
16983
+ collection = parsePdbCollection(decompressed);
16984
+ } catch (error) {
16985
+ console.error('Error loading GZ file', error);
16986
+ }
16987
+ }
16988
+
16989
+ let collectionHtml = await ic.selectCollectionsCls.setAtomMenu(collection);
16990
+
16991
+ $("#" + ic.pre + "collections_menu").html(collectionHtml);
16992
+ await ic.selectCollectionsCls.clickStructure(collection);
16993
+
16994
+ $("#" + ic.pre + "collections_menu").trigger("change");
16995
+
16996
+ me.htmlCls.clickMenuCls.setLogCmd(
16997
+ "load collection file " +
16998
+ $("#" + me.pre + "collectionfile").val(),
16999
+ false
17000
+ );
17001
+ };
17002
+
17003
+ reader2.onerror = function(error) {
17004
+ console.error('Error reading file', error);
17005
+ };
17006
+
17007
+ reader2.readAsArrayBuffer(file);
17008
+ } else {
17009
+ throw new Error('Invalid file type');
17010
+ }
16789
17011
 
16790
17012
  if (Object.keys(me.utilsCls.getStructures(ic.dAtoms))){
16791
17013
  $("#" + me.pre + "dl_collection_file").hide();
@@ -16808,6 +17030,90 @@ class Events {
16808
17030
  }
16809
17031
  });
16810
17032
 
17033
+ me.myEventCls.onIds("#" + me.pre + "opendl_export_collections", "click", function (e) {
17034
+ me.htmlCls.dialogCls.openDlg("dl_export_collections", "Export Collections");
17035
+ });
17036
+
17037
+ me.myEventCls.onIds("#" + me.pre + "export_collections", "click", function (e) {
17038
+ let ic = me.icn3d;
17039
+
17040
+ const selectElement = document.getElementById(me.pre + 'collections_menu');
17041
+
17042
+ // Array to store parsed results
17043
+ const structures = [];
17044
+
17045
+ const dl_collectionExportSelected = document.getElementById('dl_collectionExportSelected');
17046
+ const dl_collectionExportAll = document.getElementById('dl_collectionExportAll');
17047
+
17048
+ if (dl_collectionExportSelected.checked) {
17049
+
17050
+ // Iterate over each <option> element
17051
+ Array.from(selectElement.options)
17052
+ .filter(option => option.selected)
17053
+ .forEach(option => {
17054
+ const name = option.value;
17055
+ const title = option.textContent.trim();
17056
+ const description = option.getAttribute('data-description');
17057
+
17058
+ // Push the extracted data into the array
17059
+ structures.push({
17060
+ id: name,
17061
+ title: title,
17062
+ description: description || '',
17063
+ commands: (ic.allData[name] && ic.allData[name].commands) ? ic.allData[name].commands : []
17064
+ });
17065
+ });
17066
+ } else if (dl_collectionExportAll.checked) {
17067
+ // Iterate over each <option> element
17068
+ Array.from(selectElement.options)
17069
+ .forEach(option => {
17070
+ const name = option.value;
17071
+ const title = option.textContent.trim();
17072
+ const description = option.getAttribute('data-description');
17073
+
17074
+ // Push the extracted data into the array
17075
+ structures.push({
17076
+ name: name,
17077
+ title: title,
17078
+ description: description || '',
17079
+ commands: (ic.allData[name] && ic.allData[name].commands) ? ic.allData[name].commands : []
17080
+ });
17081
+ });
17082
+ }
17083
+
17084
+
17085
+ const now = new Date();
17086
+ const month = now.getMonth() + 1; // Months are zero-based
17087
+ const day = now.getDate();
17088
+ const year = now.getFullYear();
17089
+ const formattedDate = `${month}_${day}_${year}`;
17090
+
17091
+ const collection = {
17092
+ collectionTitle: document.getElementById('dl_collectionTitle').value,
17093
+ collectionDescription: document.getElementById('dl_collectionDescription').value,
17094
+ structures: structures
17095
+ };
17096
+
17097
+ const filename = `${collection.collectionTitle.replace(/\s+/g, '_')}_${formattedDate}.json`;
17098
+
17099
+ const jsonString = JSON.stringify(collection, null, 2);
17100
+
17101
+ // Create a Blob with the JSON data
17102
+ const blob = new Blob([jsonString], { type: 'application/json' });
17103
+ const url = URL.createObjectURL(blob);
17104
+
17105
+ // Create a temporary link element to trigger download
17106
+ const a = document.createElement('a');
17107
+ a.href = url;
17108
+ a.download = filename;
17109
+ document.body.appendChild(a);
17110
+ a.click();
17111
+ document.body.removeChild(a);
17112
+
17113
+ // Revoke the object URL after download
17114
+ URL.revokeObjectURL(url);
17115
+ });
17116
+
16811
17117
  me.myEventCls.onIds("#" + me.pre + "reload_dsn6file2fofc", "click", function(e) { let ic = me.icn3d;
16812
17118
  e.preventDefault();
16813
17119
  //if(!me.cfg.notebook) dialog.dialog( "close" );
@@ -19647,7 +19953,7 @@ class Html {
19647
19953
  this.force = 4;
19648
19954
  this.simulation = undefined;
19649
19955
 
19650
- //this.baseUrl = "https://structure.ncbi.nlm.nih.gov/";
19956
+ //this.baseUrl = "https://www.ncbi.nlm.nih.gov/Structure/";
19651
19957
  this.baseUrl = (window && window.location && window.location.hostname == 'structure.ncbi.nlm.nih.gov')
19652
19958
  ? "https://structure.ncbi.nlm.nih.gov/Structure/" : "https://www.ncbi.nlm.nih.gov/Structure/";
19653
19959
 
@@ -44688,8 +44994,9 @@ class Domain3d {
44688
44994
 
44689
44995
  // if(fromPos >= start && toPos <= end) {
44690
44996
  if(ssCnt > 0) jsonStr += ', ';
44691
- jsonStr += '[' + sstype + ',' + fromPos + ',' + toPos + ',' + substruct[k].x1.toFixed(2) + ',' + substruct[k].y1.toFixed(2) + ','
44692
- + substruct[k].z1.toFixed(2) + ',' + substruct[k].x2.toFixed(2) + ',' + substruct[k].y2.toFixed(2) + ',' + substruct[k].z2.toFixed(2) + ']';
44997
+ jsonStr += '[' + sstype + ',' + fromPos + ',' + toPos + ',' + substruct[k].x1.toFixed(2) + ',' + substruct[k].y1.toFixed(2) + ',';
44998
+ // jsonStr += '[' + sstype + ',' + residFrom.split('_')[2] + ',' + residTo.split('_')[2] + ',' + substruct[k].x1.toFixed(2) + ',' + substruct[k].y1.toFixed(2) + ',';
44999
+ jsonStr += substruct[k].z1.toFixed(2) + ',' + substruct[k].x2.toFixed(2) + ',' + substruct[k].y2.toFixed(2) + ',' + substruct[k].z2.toFixed(2) + ']';
44693
45000
  ++ssCnt;
44694
45001
  // }
44695
45002
  }
@@ -44705,6 +45012,7 @@ class Domain3d {
44705
45012
  for(let j = startAll; j <= endAll; ++j) {
44706
45013
  let ncbiResid = chnid + '_' + j;
44707
45014
  let resid = ic.ncbi2resid[ncbiResid];
45015
+ resid.split('_')[2];
44708
45016
 
44709
45017
  let pos = j;
44710
45018
 
@@ -44712,6 +45020,7 @@ class Domain3d {
44712
45020
 
44713
45021
  if(!residueHash.hasOwnProperty(resid)) {
44714
45022
  jsonStr += '[' + pos + ',' + 0 + ',' + fakeCoord + ',' + fakeCoord + ',' + fakeCoord + ']';
45023
+ // jsonStr += '[' + resi + ',' + 0 + ',' + fakeCoord + ',' + fakeCoord + ',' + fakeCoord + ']';
44715
45024
  }
44716
45025
  else {
44717
45026
  let atom = ic.firstAtomObjCls.getFirstCalphaAtomObj(ic.residues[resid]);
@@ -44720,6 +45029,7 @@ class Domain3d {
44720
45029
  let restype = (me.parasCls.resn2restype[atom.resn]) ? me.parasCls.resn2restype[atom.resn] : 0;
44721
45030
 
44722
45031
  jsonStr += '[' + pos + ',' + restype + ',' + atom.coord.x.toFixed(2) + ',' + atom.coord.y.toFixed(2) + ',' + atom.coord.z.toFixed(2) + ']';
45032
+ // jsonStr += '[' + resi + ',' + restype + ',' + atom.coord.x.toFixed(2) + ',' + atom.coord.y.toFixed(2) + ',' + atom.coord.z.toFixed(2) + ']';
44723
45033
  }
44724
45034
 
44725
45035
  ++domainCnt;
@@ -53373,7 +53683,7 @@ class ChainalignParser {
53373
53683
  let urlalign = me.htmlCls.baseUrl + "vastdyn/vastdyn.cgi";
53374
53684
  let urltmalign = me.htmlCls.baseUrl + "tmalign/tmalign.cgi";
53375
53685
 
53376
- let resRangeArray = (me.cfg.resrange) ? me.cfg.resrange.split(',') : [];
53686
+ let resRangeArray = (me.cfg.resrange) ? decodeURIComponent(me.cfg.resrange).split(' | ') : [];
53377
53687
 
53378
53688
  for(let index in ic.afChainIndexHash) {
53379
53689
  let idArray = ic.afChainIndexHash[index].split('_');
@@ -53398,9 +53708,10 @@ class ChainalignParser {
53398
53708
  let urlalign = me.htmlCls.baseUrl + "vastdyn/vastdyn.cgi";
53399
53709
  let urltmalign = me.htmlCls.baseUrl + "tmalign/tmalign.cgi";
53400
53710
 
53401
- let resRangeArray = (me.cfg.resrange) ? me.cfg.resrange.split(',') : [];
53711
+ let resRangeArray = (me.cfg.resrange) ? decodeURIComponent(me.cfg.resrange).split(' | ') : [];
53402
53712
 
53403
53713
  // dynamically align pairs in all chainids
53714
+ // the resrange from VASTSrv or VAST search uses NCBI residue numbers!!!
53404
53715
  let atomSet_t = (me.cfg.resrange) ? ic.realignParserCls.getSeqCoorResid([resRangeArray[0]], chainidArray[0], true).hAtoms : ic.chains[chainidArray[0]];
53405
53716
  for(let index = 1, indexl = chainidArray.length; index < indexl; ++index) {
53406
53717
  let atomSet_q = (me.cfg.resrange) ? ic.realignParserCls.getSeqCoorResid([resRangeArray[index]], chainidArray[index], true).hAtoms : ic.chains[chainidArray[index]];
@@ -53575,7 +53886,8 @@ class ChainalignParser {
53575
53886
  if(!bFoundAlignment) {
53576
53887
  // sometimes VAST align works for the reversed pair
53577
53888
  if(!bReverse) {
53578
- ic.realignParserCls.realignOnStructAlign(true);
53889
+ let bVastsearch = true;
53890
+ ic.realignParserCls.realignOnStructAlign(true, bVastsearch);
53579
53891
  return;
53580
53892
  }
53581
53893
  else {
@@ -54331,7 +54643,8 @@ class ChainalignParser {
54331
54643
  // await ic.realignParserCls.realignChainOnSeqAlign(undefined, ic.chainidArray, bRealign, bPredefined);
54332
54644
 
54333
54645
  ic.hAtoms = ic.definedSetsCls.getAtomsFromNameArray(ic.chainidArray);
54334
- await ic.realignParserCls.realignOnStructAlign();
54646
+ let bVastsearch = true;
54647
+ await ic.realignParserCls.realignOnStructAlign(undefined, bVastsearch);
54335
54648
 
54336
54649
  // reset annotations
54337
54650
  $("#" + ic.pre + "dl_annotations").html("");
@@ -57843,16 +58156,14 @@ class SdfParser {
57843
58156
  }
57844
58157
 
57845
58158
  async downloadSmiles(smiles) { let ic = this.icn3d, me = ic.icn3dui;
57846
- let urlSmiles = me.htmlCls.baseUrl + "openbabel/openbabel.cgi?smiles2pdb=" + smiles;
57847
- let pdbStr = await me.getAjaxPromise(urlSmiles, 'text');
58159
+ let urlSmiles = me.htmlCls.baseUrl + "openbabel/openbabel.cgi?smiles2sdf=" + smiles;
58160
+ let sdfStr = await me.getAjaxPromise(urlSmiles, 'text');
57848
58161
 
57849
58162
  ic.init();
57850
-
57851
58163
  ic.bInputfile = true;
57852
- ic.InputfileType = 'pdb';
57853
- ic.InputfileData = (ic.InputfileData) ? ic.InputfileData + '\nENDMDL\n' + pdbStr : pdbStr;
57854
-
57855
- await ic.pdbParserCls.loadPdbData(pdbStr);
58164
+ ic.InputfileData = (ic.InputfileData) ? ic.InputfileData + '\nENDMDL\n' + sdfStr : sdfStr;
58165
+ ic.InputfileType = 'sdf';
58166
+ await ic.sdfParserCls.loadSdfData(sdfStr);
57856
58167
  }
57857
58168
 
57858
58169
  async loadSdfData(data) { let ic = this.icn3d, me = ic.icn3dui;
@@ -58569,76 +58880,114 @@ class RealignParser {
58569
58880
  await this.realignChainOnSeqAlign(undefined, chainidArray, bRealign);
58570
58881
  }
58571
58882
 
58572
- async realignOnStructAlign(bReverse) { let ic = this.icn3d, me = ic.icn3dui;
58883
+ async realignOnStructAlign(bReverse, bVastsearch) { let ic = this.icn3d, me = ic.icn3dui;
58573
58884
  // each 3D domain should have at least 3 secondary structures
58574
58885
  let minSseCnt = (me.cfg.aligntool != 'tmalign') ? 3 : 0;
58575
58886
 
58576
- let struct2domain = {};
58577
- for(let struct in ic.structures) {
58578
- struct2domain[struct] = {};
58579
- let chainidArray = ic.structures[struct];
58580
- for(let i = 0, il = chainidArray.length; i < il; ++i) {
58581
- let chainid = chainidArray[i];
58582
- let atoms = me.hashUtilsCls.intHash(ic.hAtoms, ic.chains[chainid]);
58583
- let sseCnt = 0;
58584
- for(let serial in atoms) {
58585
- if(ic.atoms[serial].ssbegin) ++sseCnt;
58586
- if(sseCnt > minSseCnt) {
58587
- struct2domain[struct][chainid] = atoms;
58588
- break;
58589
- }
58590
- }
58591
- }
58592
- }
58887
+ /*
58888
+ let resRangeArray = (me.cfg.resrange) ? decodeURIComponent(me.cfg.resrange).split(' | ') : [];
58593
58889
 
58890
+ let atomSet_t = (me.cfg.resrange) ? ic.realignParserCls.getSeqCoorResid([resRangeArray[0]], ic.chainidArray[0], true).hAtoms : ic.chains[chainidArray[0]];
58891
+ for(let index = 1, indexl = chainidArray.length; index < indexl; ++index) {
58892
+ let atomSet_q = (me.cfg.resrange) ? ic.realignParserCls.getSeqCoorResid([resRangeArray[index]], ic.chainidArray[index], true).hAtoms : ic.chains[chainidArray[index]];
58893
+ // end of new version to be done for VASTsrv ==============
58894
+ */
58594
58895
  let ajaxArray = [], chainidPairArray = [];
58595
58896
  let urlalign = me.htmlCls.baseUrl + "vastdyn/vastdyn.cgi";
58596
58897
  let urltmalign = me.htmlCls.baseUrl + "tmalign/tmalign.cgi";
58597
58898
 
58598
- //let cnt = 0;
58599
- let structArray = Object.keys(struct2domain);
58600
- if(bReverse) structArray = structArray.reverse();
58899
+ let struct2domain = {};
58900
+ if(bVastsearch && me.cfg.resrange) {
58901
+ let resRangeArray = decodeURIComponent(me.cfg.resrange).split(' | ');
58601
58902
 
58602
- for(let s = 0, sl = structArray.length; s < sl; ++s) {
58603
- let struct1 = structArray[s];
58903
+ let atomSet_t = ic.realignParserCls.getSeqCoorResid([resRangeArray[0]], ic.chainidArray[0], true).hAtoms;
58904
+ for(let index = 1, indexl = ic.chainidArray.length; index < indexl; ++index) {
58905
+ let atomSet_q = ic.realignParserCls.getSeqCoorResid([resRangeArray[index]], ic.chainidArray[index], true).hAtoms;
58604
58906
 
58605
- let chainidArray1 = Object.keys(struct2domain[struct1]);
58606
- if(chainidArray1.length == 0) continue;
58907
+ let alignAjax;
58908
+ if(me.cfg.aligntool != 'tmalign') {
58909
+ let jsonStr_q = ic.domain3dCls.getDomainJsonForAlign(atomSet_q);
58910
+ let jsonStr_t = ic.domain3dCls.getDomainJsonForAlign(atomSet_t);
58911
+
58912
+ let dataObj = {'domains1': jsonStr_q, 'domains2': jsonStr_t};
58913
+ alignAjax = me.getAjaxPostPromise(urlalign, dataObj);
58914
+ }
58915
+ else {
58916
+ let pdb_query = ic.saveFileCls.getAtomPDB(atomSet_q);
58917
+ let pdb_target= ic.saveFileCls.getAtomPDB(atomSet_t);
58918
+
58919
+ let dataObj = {'pdb_query': pdb_query, 'pdb_target': pdb_target};
58920
+ alignAjax = me.getAjaxPostPromise(urltmalign, dataObj);
58921
+ }
58922
+
58923
+ ajaxArray.push(alignAjax);
58924
+
58925
+ chainidPairArray.push(ic.chainidArray[0] + ',' + ic.chainidArray[index]);
58926
+ }
58927
+ }
58928
+ else {
58929
+ for(let struct in ic.structures) {
58930
+ struct2domain[struct] = {};
58931
+ let chainidArray = ic.structures[struct];
58932
+ for(let i = 0, il = chainidArray.length; i < il; ++i) {
58933
+ let chainid = chainidArray[i];
58934
+ let atoms = me.hashUtilsCls.intHash(ic.hAtoms, ic.chains[chainid]);
58935
+ let sseCnt = 0;
58936
+ for(let serial in atoms) {
58937
+ if(ic.atoms[serial].ssbegin) ++sseCnt;
58938
+ if(sseCnt > minSseCnt) {
58939
+ struct2domain[struct][chainid] = atoms;
58940
+ break;
58941
+ }
58942
+ }
58943
+ }
58944
+ }
58607
58945
 
58608
- for(let i = 0, il = chainidArray1.length; i < il; ++i) {
58609
- let chainid1 = chainidArray1[i];
58610
- let jsonStr_t = ic.domain3dCls.getDomainJsonForAlign(struct2domain[struct1][chainid1]);
58946
+ //let cnt = 0;
58947
+ let structArray = Object.keys(struct2domain);
58948
+ if(bReverse) structArray = structArray.reverse();
58611
58949
 
58612
- for(let t = s+1, tl = structArray.length; t < tl; ++t) {
58613
- let struct2 = structArray[t];
58950
+ for(let s = 0, sl = structArray.length; s < sl; ++s) {
58951
+ let struct1 = structArray[s];
58614
58952
 
58615
- let chainidArray2 = Object.keys(struct2domain[struct2]);
58616
- if(chainidArray2.length == 0) continue;
58953
+ let chainidArray1 = Object.keys(struct2domain[struct1]);
58954
+ if(chainidArray1.length == 0) continue;
58617
58955
 
58618
- for(let j = 0, jl = chainidArray2.length; j < jl; ++j) {
58619
- let chainid2 = chainidArray2[j];
58956
+ for(let i = 0, il = chainidArray1.length; i < il; ++i) {
58957
+ let chainid1 = chainidArray1[i];
58958
+ let jsonStr_t = ic.domain3dCls.getDomainJsonForAlign(struct2domain[struct1][chainid1]);
58620
58959
 
58621
- let alignAjax;
58622
- if(me.cfg.aligntool != 'tmalign') {
58623
- let jsonStr_q = ic.domain3dCls.getDomainJsonForAlign(struct2domain[struct2][chainid2]);
58624
-
58625
- let dataObj = {'domains1': jsonStr_q, 'domains2': jsonStr_t};
58626
- alignAjax = me.getAjaxPostPromise(urlalign, dataObj);
58627
- }
58628
- else {
58629
- let pdb_target = ic.saveFileCls.getAtomPDB(struct2domain[struct1][chainid1], undefined, undefined, undefined, undefined, struct1);
58630
- let pdb_query = ic.saveFileCls.getAtomPDB(struct2domain[struct2][chainid2], undefined, undefined, undefined, undefined, struct2);
58631
-
58632
- // let pdb_target = ic.saveFileCls.getAtomPDB(ic.chains[chainid1], undefined, undefined, undefined, undefined, struct1);
58633
- // let pdb_query = ic.saveFileCls.getAtomPDB(ic.chains[chainid2], undefined, undefined, undefined, undefined, struct2);
58960
+ for(let t = s+1, tl = structArray.length; t < tl; ++t) {
58961
+ let struct2 = structArray[t];
58962
+
58963
+ let chainidArray2 = Object.keys(struct2domain[struct2]);
58964
+ if(chainidArray2.length == 0) continue;
58965
+
58966
+ for(let j = 0, jl = chainidArray2.length; j < jl; ++j) {
58967
+ let chainid2 = chainidArray2[j];
58968
+
58969
+ let alignAjax;
58970
+ if(me.cfg.aligntool != 'tmalign') {
58971
+ let jsonStr_q = ic.domain3dCls.getDomainJsonForAlign(struct2domain[struct2][chainid2]);
58972
+
58973
+ let dataObj = {'domains1': jsonStr_q, 'domains2': jsonStr_t};
58974
+ alignAjax = me.getAjaxPostPromise(urlalign, dataObj);
58975
+ }
58976
+ else {
58977
+ let pdb_target = ic.saveFileCls.getAtomPDB(struct2domain[struct1][chainid1], undefined, undefined, undefined, undefined, struct1);
58978
+ let pdb_query = ic.saveFileCls.getAtomPDB(struct2domain[struct2][chainid2], undefined, undefined, undefined, undefined, struct2);
58634
58979
 
58635
- let dataObj = {'pdb_query': pdb_query, 'pdb_target': pdb_target};
58636
- alignAjax = me.getAjaxPostPromise(urltmalign, dataObj);
58637
- }
58980
+ // let pdb_target = ic.saveFileCls.getAtomPDB(ic.chains[chainid1], undefined, undefined, undefined, undefined, struct1);
58981
+ // let pdb_query = ic.saveFileCls.getAtomPDB(ic.chains[chainid2], undefined, undefined, undefined, undefined, struct2);
58982
+
58983
+ let dataObj = {'pdb_query': pdb_query, 'pdb_target': pdb_target};
58984
+ alignAjax = me.getAjaxPostPromise(urltmalign, dataObj);
58985
+ }
58638
58986
 
58639
- ajaxArray.push(alignAjax);
58640
- chainidPairArray.push(chainid1 + ',' + chainid2);
58641
- //++cnt;
58987
+ ajaxArray.push(alignAjax);
58988
+ chainidPairArray.push(chainid1 + ',' + chainid2);
58989
+ //++cnt;
58990
+ }
58642
58991
  }
58643
58992
  }
58644
58993
  }
@@ -58754,7 +59103,7 @@ class RealignParser {
58754
59103
  let predefinedResArray, predefinedResPair;
58755
59104
 
58756
59105
  if(bPredefined) {
58757
- predefinedResArray = me.cfg.resdef.trim().replace(/\+/gi, ' ').split(': ');
59106
+ predefinedResArray = decodeURIComponent(me.cfg.resdef).trim().replace(/\+/gi, ' ').split(': ');
58758
59107
 
58759
59108
  if(predefinedResArray.length != chainidArray.length - 1) {
58760
59109
  var aaa = 1; //alert("Please make sure the number of chains and the lines of predefined residues are the same...");
@@ -58943,7 +59292,7 @@ class RealignParser {
58943
59292
  }
58944
59293
  }
58945
59294
 
58946
- getSeqCoorResid(resiArray, chainid, bNCBI) { let ic = this.icn3d, me = ic.icn3dui;
59295
+ getSeqCoorResid(resiArray, chainid, bNCBIResi) { let ic = this.icn3d, me = ic.icn3dui;
58947
59296
  let seq = '', coorArray = [], residArray = [];
58948
59297
  let hAtoms = {};
58949
59298
 
@@ -58951,16 +59300,17 @@ class RealignParser {
58951
59300
  if(resiArray[j].indexOf('-') != -1) {
58952
59301
  let startEnd = resiArray[j].split('-');
58953
59302
  for(let k = parseInt(startEnd[0]); k <= parseInt(startEnd[1]); ++k) {
58954
- let seqIndex = (bNCBI) ? k : ic.setSeqAlignCls.getPosFromResi(chainid, k);
59303
+ let seqIndex = (bNCBIResi) ? k : ic.setSeqAlignCls.getPosFromResi(chainid, k);
58955
59304
 
58956
59305
  // don't align solvent or chemicals
58957
59306
  if(!ic.chainsSeq[chainid] || !ic.chainsSeq[chainid][seqIndex] || me.parasCls.b62ResArray.indexOf(ic.chainsSeq[chainid][seqIndex].name.toUpperCase()) == -1) continue;
58958
59307
 
58959
59308
  seq += ic.chainsSeq[chainid][seqIndex].name.toUpperCase();
58960
59309
 
58961
- coorArray = coorArray.concat(this.getResCoorArray(chainid + '_' + k));
59310
+ let resid = (bNCBIResi) ? ic.ncbi2resid[chainid + '_' + k] : chainid + '_' + k;
59311
+ coorArray = coorArray.concat(this.getResCoorArray(resid));
58962
59312
 
58963
- residArray.push(chainid + '_' + k);
59313
+ residArray.push(resid);
58964
59314
  }
58965
59315
  }
58966
59316
  else if(resiArray[j] == 0) { // 0 means the whole chain
@@ -58970,18 +59320,19 @@ class RealignParser {
58970
59320
  else { // one residue
58971
59321
  let k = resiArray[j];
58972
59322
 
58973
- let seqIndex = (bNCBI) ? k : ic.setSeqAlignCls.getPosFromResi(chainid, k);
59323
+ let seqIndex = (bNCBIResi) ? k : ic.setSeqAlignCls.getPosFromResi(chainid, k);
58974
59324
 
58975
59325
  if(!ic.chainsSeq[chainid][seqIndex]) continue;
58976
59326
 
58977
- let resCoorArray = this.getResCoorArray(chainid + '_' + k);
59327
+ let resid = (bNCBIResi) ? ic.ncbi2resid[chainid + '_' + k] : chainid + '_' + k;
59328
+ let resCoorArray = this.getResCoorArray(resid);
58978
59329
  //if(resCoorArray.length == 1 && resCoorArray[0] === undefined) continue;
58979
59330
 
58980
59331
  seq += ic.chainsSeq[chainid][seqIndex].name.toUpperCase();
58981
59332
 
58982
59333
  coorArray = coorArray.concat(resCoorArray);
58983
59334
 
58984
- residArray.push(chainid + '_' + k);
59335
+ residArray.push(resid);
58985
59336
  }
58986
59337
  }
58987
59338
 
@@ -63245,7 +63596,9 @@ class LoadPDB {
63245
63596
  structure = this.getStructureId(id, moleculeNum, bMutation, bNMR);
63246
63597
 
63247
63598
  ic.molTitle = '';
63248
- ic.molTitleHash = {};
63599
+ if (ic.allData === undefined) {
63600
+ ic.molTitleHash = {};
63601
+ }
63249
63602
 
63250
63603
  bHeader = true; // read the first header if there are multiple
63251
63604
  } else if (record === 'TITLE ') {
@@ -68269,15 +68622,15 @@ class SelectCollections {
68269
68622
  }
68270
68623
 
68271
68624
  //Set the menu of defined sets with an array of defined names "commandnameArray".
68272
- setAtomMenu(nameArray, titleArray) {
68625
+ setAtomMenu(nameArray) {
68273
68626
  let ic = this.icn3d;
68274
68627
  ic.icn3dui;
68275
68628
  let html = "";
68276
- let commandnameArray = [nameArray[0]];
68277
68629
  //for(let i in ic.defNames2Atoms) {
68278
68630
  for (let i = 0, il = nameArray.length; i < il; ++i) {
68279
- let name = nameArray[i];
68280
- let title = titleArray[i];
68631
+ let name = nameArray[i][0];
68632
+ let title = nameArray[i][1];
68633
+ let description = nameArray[i][2];
68281
68634
 
68282
68635
  let atomHash;
68283
68636
  if (
@@ -68300,16 +68653,11 @@ class SelectCollections {
68300
68653
  }
68301
68654
  }
68302
68655
 
68303
- if (commandnameArray.indexOf(name) != -1) {
68304
- html +=
68305
- "<option value='" +
68306
- name +
68307
- "' selected='selected'>" +
68308
- title +
68309
- "</option>";
68310
- } else {
68311
- html += "<option value='" + name + "'>" + title + "</option>";
68312
- }
68656
+ if (i == 0) {
68657
+ html += "<option value='" + nameArray[0][0] + "' selected='selected' data-description='" + description + "'>" + title + "</option>";
68658
+ } else {
68659
+ html += "<option value='" + name + "' data-description='" + description + "'>" + title + "</option>";
68660
+ }
68313
68661
  }
68314
68662
 
68315
68663
  return html;
@@ -68350,49 +68698,33 @@ class SelectCollections {
68350
68698
  }
68351
68699
 
68352
68700
  return difference;
68353
- }
68701
+ }
68354
68702
 
68355
- clickStructure() {
68703
+ clickStructure(collection) {
68356
68704
  let ic = this.icn3d,
68357
68705
  me = ic.icn3dui;
68358
68706
  let thisClass = this;
68359
68707
 
68360
- if (ic.allData == undefined) {
68361
- ic.allData = {};
68362
- ic.allData['all'] = {
68363
- 'atoms': {},
68364
- 'proteins': {},
68365
- 'nucleotides': {},
68366
- 'chemicals': {},
68367
- 'ions': {},
68368
- 'water': {},
68369
- 'structures': {},
68370
- 'ssbondpnts': {},
68371
- 'residues': {},
68372
- 'chains': {},
68373
- 'chainsSeq': {}, //Sequences and Annotation
68374
- 'defNames2Atoms': {},
68375
- 'defNames2Residues': {}
68376
- };
68377
- ic.allData['prev'] = {};
68378
- }
68379
-
68380
68708
  //me.myEventCls.onIds("#" + ic.pre + "atomsCustom", "change", function(e) { let ic = thisClass.icn3d;
68381
- $("#" + ic.pre + "collections_menu").change(async function (e) {
68709
+ $("#" + ic.pre + "collections_menu").on("change", async function (e) {
68382
68710
  let ic = thisClass.icn3d;
68383
68711
 
68384
68712
  let nameArray = $(this).val();
68385
68713
  let nameStructure = $(this).find("option:selected").text();
68714
+ let selectedIndices = Array.from(this.selectedOptions).map(option => option.index);
68715
+ let selectedIndicesMap = nameArray.reduce((map, name, i) => {
68716
+ map[name] = selectedIndices[i];
68717
+ return map;
68718
+ }, {});
68386
68719
 
68387
68720
  ic.nameArray = nameArray;
68388
- if (nameArray !== null) {
68389
- // let chainIdHash = {};
68390
68721
 
68722
+ if (nameArray !== null) {
68391
68723
  let bNoDuplicate = true;
68392
68724
  thisClass.reset();
68393
68725
  for (const name of nameArray) {
68394
68726
  if (!(name in ic.allData)) {
68395
- ic.allData['prev'] = JSON.parse(JSON.stringify(ic.allData['all']));//me.hashUtilsCls.cloneHash(ic.allData['all']);
68727
+ ic.allData['prev'] = JSON.parse(JSON.stringify(ic.allData['all']));
68396
68728
 
68397
68729
  ic.atoms = ic.allData['all']['atoms'];
68398
68730
 
@@ -68409,7 +68741,21 @@ class SelectCollections {
68409
68741
  ic.chainsSeq = ic.allData['all']['chainsSeq'];
68410
68742
  ic.defalls2Atoms = ic.allData['all']['defalls2Atoms'];
68411
68743
  ic.defalls2Residues = ic.allData['all']['defalls2Residues'];
68412
- await ic.chainalignParserCls.downloadMmdbAf(name, undefined, undefined, bNoDuplicate).then(() => {
68744
+
68745
+ async function loadStructure(pdb) {
68746
+ await ic.resetConfig();
68747
+ if (pdb) {
68748
+ let bAppend = true;
68749
+ if (Object.keys(ic.structures).length == 0) {
68750
+ bAppend = false;
68751
+ }
68752
+ await ic.pdbParserCls.loadPdbData(ic.pdbCollection[selectedIndicesMap[name]].join('\n'), undefined, undefined, bAppend);
68753
+ } else {
68754
+ await ic.chainalignParserCls.downloadMmdbAf(name, undefined, undefined, bNoDuplicate);
68755
+ }
68756
+ }
68757
+
68758
+ await loadStructure(collection[selectedIndicesMap[name]][4]).then(() => {
68413
68759
  ic.allData['all'] = {
68414
68760
  'atoms': ic.atoms,
68415
68761
  'proteins': ic.proteins,
@@ -68417,9 +68763,9 @@ class SelectCollections {
68417
68763
  'chemicals': ic.chemicals,
68418
68764
  'ions': ic.ions,
68419
68765
  'water': ic.water,
68420
- 'structures': ic.structures,
68766
+ 'structures': ic.structures, // getSSExpandedAtoms
68421
68767
  'ssbondpnts': ic.ssbondpnts,
68422
- 'residues': ic.residues,
68768
+ 'residues': ic.residues, // getSSExpandedAtoms
68423
68769
  'chains': ic.chains,
68424
68770
  'chainsSeq': ic.chainsSeq, //Sequences and Annotation
68425
68771
  'defNames2Atoms': ic.defNames2Atoms,
@@ -68427,26 +68773,27 @@ class SelectCollections {
68427
68773
  };
68428
68774
 
68429
68775
  ic.allData[name] = {
68776
+ 'title': ic.molTitle,
68430
68777
  'atoms': thisClass.dictionaryDifference(ic.allData['prev']['atoms'], ic.atoms),
68431
68778
  'proteins': thisClass.dictionaryDifference(ic.allData['prev']['proteins'], ic.proteins),
68432
68779
  'nucleotides': thisClass.dictionaryDifference(ic.allData['prev']['nucleotides'], ic.nucleotides),
68433
68780
  'chemicals': thisClass.dictionaryDifference(ic.allData['prev']['chemicals'], ic.chemicals),
68434
68781
  'ions': thisClass.dictionaryDifference(ic.allData['prev']['ions'], ic.ions),
68435
68782
  'water': thisClass.dictionaryDifference(ic.allData['prev']['water'], ic.water),
68436
- 'structures': thisClass.dictionaryDifference(ic.allData['prev']['structures'], ic.structures),
68783
+ 'structures': thisClass.dictionaryDifference(ic.allData['prev']['structures'], ic.structures), // getSSExpandedAtoms
68437
68784
  'ssbondpnts': thisClass.dictionaryDifference(ic.allData['prev']['ssbondpnts'], ic.ssbondpnts),
68438
- 'residues': thisClass.dictionaryDifference(ic.allData['prev']['residues'], ic.residues),
68785
+ 'residues': thisClass.dictionaryDifference(ic.allData['prev']['residues'], ic.residues), // getSSExpandedAtoms
68439
68786
  'chains': thisClass.dictionaryDifference(ic.allData['prev']['chains'], ic.chains),
68440
68787
  'chainsSeq': thisClass.dictionaryDifference(ic.allData['prev']['chainsSeq'], ic.chainsSeq), //Sequences and Annotation
68441
68788
  'defNames2Atoms': thisClass.dictionaryDifference(ic.allData['prev']['defNames2Atoms'], ic.defNames2Atoms),
68442
68789
  'defNames2Residues': thisClass.dictionaryDifference(ic.allData['prev']['defNames2Residues'], ic.defNames2Residues)
68443
68790
  };
68444
68791
 
68445
- // ic.atoms = Object.assign(ic.atoms, ic.atomsTemp);
68446
68792
  thisClass.reset();
68447
68793
  });
68448
68794
  }
68449
68795
  }
68796
+
68450
68797
  for (const name of nameArray) {
68451
68798
  ic.atoms = Object.assign(ic.atoms, ic.allData[name]['atoms']);
68452
68799
 
@@ -68465,10 +68812,26 @@ class SelectCollections {
68465
68812
  ic.defNames2Residues = Object.assign(ic.defNames2Residues, ic.allData[name]['defNames2Residues']);
68466
68813
  ic.dAtoms = me.hashUtilsCls.cloneHash(ic.atoms);
68467
68814
  ic.hAtoms = me.hashUtilsCls.cloneHash(ic.atoms);
68468
- }
68815
+
68816
+ ic.molTitle = ic.allData[name]['title'];
68469
68817
 
68818
+ if (collection[selectedIndicesMap[name]][3] !== undefined && collection[selectedIndicesMap[name]][3].length > 0) {
68819
+ if (ic.allData[name]['commands'] == undefined) {
68820
+ let commands = collection[selectedIndicesMap[name]][3];
68821
+ ic.allData[name]['commands'] = commands;
68822
+ }
68823
+ }
68824
+
68825
+ if (ic.allData[name]['commands'] !== undefined) {
68826
+ for (const command of ic.allData[name]['commands']) {
68827
+ me.htmlCls.clickMenuCls.setLogCmd(command, true);
68828
+ await ic.applyCommandCls.applyCommand(command);
68829
+ }
68830
+ }
68831
+
68832
+ }
68833
+
68470
68834
  ic.opts["color"] = (Object.keys(ic.structures).length == 1) ? "chain" : "structure";
68471
- // ic.setStyleCls.setAtomStyleByOptions();
68472
68835
  ic.setColorCls.setColorByOptions(ic.opts, ic.atoms);
68473
68836
 
68474
68837
  ic.transformCls.zoominSelection();
@@ -68482,14 +68845,12 @@ class SelectCollections {
68482
68845
  // show selected chains in annotation window
68483
68846
  ic.annotationCls.showAnnoSelectedChains();
68484
68847
  }
68485
-
68848
+
68486
68849
  await ic.drawCls.draw();
68487
68850
  ic.saveFileCls.showTitle();
68488
68851
 
68489
- me.htmlCls.clickMenuCls.setLogCmd(
68490
- "select structure " + "[" + nameStructure + "]",
68491
- true
68492
- );
68852
+ me.htmlCls.clickMenuCls.setLogCmd("select structure " + "[" + nameStructure + "]", false);
68853
+ me.htmlCls.clickMenuCls.setLogCmd('load mmdbaf1 ' + nameArray, true);
68493
68854
  }
68494
68855
  });
68495
68856
 
@@ -69401,7 +69762,7 @@ class LoadScript {
69401
69762
  if(steps === 1
69402
69763
  || (ic.hAtoms && ic.atoms && Object.keys(ic.hAtoms).length === Object.keys(ic.atoms).length)
69403
69764
  || (ic.optsHistory[steps - 1] !== undefined && ic.optsHistory[steps - 1].hasOwnProperty('hlatomcount') && ic.optsHistory[steps - 1].hlatomcount === Object.keys(ic.atoms).length) ) {
69404
- // the following code caused problem for many links,e.g., https://structure.ncbi.nlm.nih.gov/icn3d/share.html?17g3r1JDvZ7ZL39e6
69765
+ // the following code caused problem for many links,e.g., https://www.ncbi.nlm.nih.gov/Structure/icn3d/share.html?17g3r1JDvZ7ZL39e6
69405
69766
  // if(steps === 1) {
69406
69767
  // assign styles and color using the options at that stage
69407
69768
  // ic.setStyleCls.setAtomStyleByOptions(ic.optsHistory[steps - 1]);
@@ -69423,7 +69784,7 @@ class LoadScript {
69423
69784
  ic.pk = 3;
69424
69785
  }
69425
69786
 
69426
- // the following code caused problem for many links,e.g., https://structure.ncbi.nlm.nih.gov/icn3d/share.html?17g3r1JDvZ7ZL39e6
69787
+ // the following code caused problem for many links,e.g., https://www.ncbi.nlm.nih.gov/Structure/icn3d/share.html?17g3r1JDvZ7ZL39e6
69427
69788
  // if(steps === 1) {
69428
69789
  // ic.setColorCls.applyOriginalColor();
69429
69790
  // }
@@ -70489,6 +70850,10 @@ class Selection {
70489
70850
  selectOneResid(idStr, bUnchecked) {var ic = this.icn3d; ic.icn3dui;
70490
70851
  //var idStr = idArray[i]; // TYR $1KQ2.B:56@OH, $1KQ2.B:40 ASP
70491
70852
  //change to: let idStr = idArray[i]; // TYR $1KQ2.B:56@OH, or ASP $1KQ2.B:40
70853
+ //change to: let idStr = idArray[i]; // TYR $1KQ2.B:56@OH, or ASP $1KQ2.B:40, or $1KQ2.B:56@OH 130, or ASP $1KQ2.B:40 144
70854
+ let idArray = idStr.split(' ');
70855
+ idStr = idArray[1];
70856
+
70492
70857
  let posStructure = idStr.indexOf('$');
70493
70858
  let posChain = idStr.indexOf('.');
70494
70859
  let posRes = idStr.indexOf(':');
@@ -79301,7 +79666,7 @@ class ShareLink {
79301
79666
  let shortName = strArray[strArray.length - 1];
79302
79667
  ic.saveFileCls.saveFile(inputid + '-' + shortName + '.png', 'png');
79303
79668
  let text = '<div style="float:left; border: solid 1px #0000ff; padding: 5px; margin: 10px; text-align:center;">';
79304
- text += '<a href="https://structure.ncbi.nlm.nih.gov/icn3d/share.html?' + shortName + '" target="_blank">';
79669
+ text += '<a href="https://www.ncbi.nlm.nih.gov/Structure/icn3d/share.html?' + shortName + '" target="_blank">';
79305
79670
  text += '<img style="height:300px" src ="' + inputid + '-' + shortName + '.png"><br>\n';
79306
79671
  text += '<!--Start of your comments==================-->\n';
79307
79672
  let yournote =(ic.yournote) ? ': ' + ic.yournote.replace(/\n/g, "<br>").replace(/; /g, ", ") : '';
@@ -79320,9 +79685,9 @@ class ShareLink {
79320
79685
  //shorturl: https://icn3d.page.link/NvbAh1Vmiwc4bgX87
79321
79686
  let urlArray = shorturl.split('page.link/');
79322
79687
  //if(urlArray.length == 2) shorturl = me.htmlCls.baseUrl + 'icn3d/share.html?' + urlArray[1];
79323
- // When the baseURL is structure.ncbi.nlm.nih.gov, mmcifparser.cgi has a problem to past posted data in Mac/iphone
79688
+ // When the baseURL is structure.ncbi.nlm.nih.gov, mmcifparser.cgi has a problem to pass posted data in Mac/iphone
79324
79689
  // So the base URL is still www.ncbi.nlm.nih.gov/Structure,just use short URL here
79325
- if(urlArray.length == 2) shorturl = 'https://structure.ncbi.nlm.nih.gov/icn3d/share.html?' + urlArray[1];
79690
+ if(urlArray.length == 2) shorturl = 'https://www.ncbi.nlm.nih.gov/Structure/icn3d/share.html?' + urlArray[1];
79326
79691
 
79327
79692
  $("#" + ic.pre + "short_url").val(shorturl);
79328
79693
  $("#" + ic.pre + "short_url_title").val(shorturl + '&t=' + ic.yournote);
@@ -82479,7 +82844,7 @@ class iCn3DUI {
82479
82844
  //even when multiple iCn3D viewers are shown together.
82480
82845
  this.pre = this.cfg.divid + "_";
82481
82846
 
82482
- this.REVISION = '3.38.0';
82847
+ this.REVISION = '3.39.0';
82483
82848
 
82484
82849
  // In nodejs, iCn3D defines "window = {navigator: {}}"
82485
82850
  this.bNode = (Object.keys(window).length < 2) ? true : false;
@@ -82654,6 +83019,9 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
82654
83019
 
82655
83020
  await ic.pdbParserCls.loadPdbData(pdbStr);
82656
83021
 
83022
+ // // use NCBI residue numbers if using VAST
83023
+ // me.icn3d.bUsePdbNum = 0;
83024
+
82657
83025
  if(me.cfg.resdef !== undefined && me.cfg.chains !== undefined) {
82658
83026
  let structureArray = Object.keys(ic.structures);
82659
83027
  let chainArray = me.cfg.chains.split(' | ');
@@ -82929,7 +83297,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
82929
83297
 
82930
83298
  ic.bChainAlign = true;
82931
83299
  ic.inputid = me.cfg.chainalign;
82932
- let resrangeStr = (me.cfg.resrange) ? ' | resrange ' + me.cfg.resrange : '';
83300
+ let resrangeStr = (me.cfg.resrange) ? ' | resrange ' + decodeURIComponent(me.cfg.resrange) : '';
82933
83301
  let resdef = (me.cfg.resdef) ? me.cfg.resdef : '';
82934
83302
  ic.loadCmd = 'load chainalignment ' + me.cfg.chainalign + ' | resnum ' + me.cfg.resnum + ' | resdef ' + resdef + ' | aligntool ' + me.cfg.aligntool + ' | parameters ' + me.cfg.inpara + resrangeStr;
82935
83303
  me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);