icn3d 3.38.2 → 3.39.1

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;
@@ -51741,7 +52051,10 @@ class ViewInterPairs {
51741
52051
  cntHbond += result.cnt;
51742
52052
  svgHtmlNode += result.svgHtmlNode;
51743
52053
  svgHtmlLine += result.svgHtmlLine;
51744
- if(result.cnt > 0) residname2List += residname2 + ":hbond_" + result.cnt + " ";
52054
+ // if(result.cnt > 0) residname2List += residname2 + ":hbond_" + result.cnt + " ";
52055
+ // add hydrogen bond between main or side chains. result.mainside has value such as main,side,side,side
52056
+ // for two hydrogens between main and side, and side and side chains
52057
+ if(result.cnt > 0) residname2List += residname2 + ":hbond_" + result.cnt + ":type_" + result.mainside + " ";
51745
52058
 
51746
52059
  labels2dist = ic.resids2inter[resids]['ionic'];
51747
52060
  result = this.getInteractionPairDetails(labels2dist, type, 'ionic', index2xy, xlen, ylen, xcenter, ycenter);
@@ -51749,7 +52062,7 @@ class ViewInterPairs {
51749
52062
  cntIonic += result.cnt;
51750
52063
  svgHtmlNode += result.svgHtmlNode;
51751
52064
  svgHtmlLine += result.svgHtmlLine;
51752
- if(result.cnt > 0) residname2List += residname2 + ":ionic_" + result.cnt + " ";
52065
+ if(result.cnt > 0) residname2List += residname2 + ":ionic_" + result.cnt + ":type_" + result.mainside + " ";
51753
52066
 
51754
52067
  labels2dist = ic.resids2inter[resids]['halogen'];
51755
52068
  result = this.getInteractionPairDetails(labels2dist, type, 'halogen', index2xy, xlen, ylen, xcenter, ycenter);
@@ -51757,7 +52070,7 @@ class ViewInterPairs {
51757
52070
  cntHalegen += result.cnt;
51758
52071
  svgHtmlNode += result.svgHtmlNode;
51759
52072
  svgHtmlLine += result.svgHtmlLine;
51760
- if(result.cnt > 0) residname2List += residname2 + ":halogen_" + result.cnt + " ";
52073
+ if(result.cnt > 0) residname2List += residname2 + ":halogen_" + result.cnt + ":type_" + result.mainside + " ";
51761
52074
 
51762
52075
  labels2dist = ic.resids2inter[resids]['pi-cation'];
51763
52076
  result = this.getInteractionPairDetails(labels2dist, type, 'pi-cation', index2xy, xlen, ylen, xcenter, ycenter);
@@ -51765,7 +52078,7 @@ class ViewInterPairs {
51765
52078
  cntPication += result.cnt;
51766
52079
  svgHtmlNode += result.svgHtmlNode;
51767
52080
  svgHtmlLine += result.svgHtmlLine;
51768
- if(result.cnt > 0) residname2List += residname2 + ":pi-cation_" + result.cnt + " ";
52081
+ if(result.cnt > 0) residname2List += residname2 + ":pi-cation_" + result.cnt + ":type_" + result.mainside + " ";
51769
52082
 
51770
52083
  labels2dist = ic.resids2inter[resids]['pi-stacking'];
51771
52084
  result = this.getInteractionPairDetails(labels2dist, type, 'pi-stacking', index2xy, xlen, ylen, xcenter, ycenter);
@@ -51773,7 +52086,7 @@ class ViewInterPairs {
51773
52086
  cntPistacking += result.cnt;
51774
52087
  svgHtmlNode += result.svgHtmlNode;
51775
52088
  svgHtmlLine += result.svgHtmlLine;
51776
- if(result.cnt > 0) residname2List += residname2 + ":pi-stacking_" + result.cnt + " ";
52089
+ if(result.cnt > 0) residname2List += residname2 + ":pi-stacking_" + result.cnt + ":type_" + result.mainside + " ";
51777
52090
 
51778
52091
  // put contact as the last one since contact will use the same node as other interactions in ligand-protein interactoin
51779
52092
  labels2dist = ic.resids2inter[resids]['contact'];
@@ -51827,7 +52140,7 @@ class ViewInterPairs {
51827
52140
  return tmpText;
51828
52141
  }
51829
52142
  getInteractionPairDetails(labels2dist, type, interactionType, index2xy, xlen, ylen, xcenter, ycenter) { let ic = this.icn3d; ic.icn3dui;
51830
- let svgHtmlNode = '', svgHtmlLine = '', tmpText = '', cnt = 0;
52143
+ let svgHtmlNode = '', svgHtmlLine = '', tmpText = '', cnt = 0, mainside= '';
51831
52144
  let colorText1 = ' <span style="background-color:#';
51832
52145
  let colorText2 = '">&nbsp;&nbsp;&nbsp;</span>';
51833
52146
  if(labels2dist !== undefined) {
@@ -51844,6 +52157,12 @@ class ViewInterPairs {
51844
52157
  let resid1 = resid1Ori.substr(0, pos1);
51845
52158
  let resid2 = resid2Ori.substr(0, pos2);
51846
52159
 
52160
+ let atomName1 = resid1.substr(resid1.indexOf('@') + 1);
52161
+ resid2.substr(resid2.indexOf('@') + 1);
52162
+ let atomType1 = (atomName1 === "N" || atomName1 === "C" || atomName1 === "O" || atomName1 === "CA") ? 'main' : 'side';
52163
+ if(mainside) mainside += ';';
52164
+ mainside += atomType1 + ',' + atomType1;
52165
+
51847
52166
  let resid1Real = ic.getGraphCls.convertLabel2Resid(resid1);
51848
52167
  let atom1 = ic.firstAtomObjCls.getFirstAtomObj(ic.residues[resid1Real]);
51849
52168
  let color1 = (atom1.color) ? atom1.color.getHexString() : '';
@@ -51865,7 +52184,7 @@ class ViewInterPairs {
51865
52184
  }
51866
52185
  }
51867
52186
  }
51868
- return {html: tmpText, cnt: cnt, svgHtmlNode: svgHtmlNode, svgHtmlLine: svgHtmlLine}
52187
+ return {html: tmpText, cnt: cnt, svgHtmlNode: svgHtmlNode, svgHtmlLine: svgHtmlLine, mainside: mainside}
51869
52188
  }
51870
52189
 
51871
52190
  getContactPairDetails(labels2dist, type, interactionType, index2xy, xlen, ylen, xcenter, ycenter) { let ic = this.icn3d; ic.icn3dui;
@@ -53373,7 +53692,7 @@ class ChainalignParser {
53373
53692
  let urlalign = me.htmlCls.baseUrl + "vastdyn/vastdyn.cgi";
53374
53693
  let urltmalign = me.htmlCls.baseUrl + "tmalign/tmalign.cgi";
53375
53694
 
53376
- let resRangeArray = (me.cfg.resrange) ? me.cfg.resrange.split(',') : [];
53695
+ let resRangeArray = (me.cfg.resrange) ? decodeURIComponent(me.cfg.resrange).split(' | ') : [];
53377
53696
 
53378
53697
  for(let index in ic.afChainIndexHash) {
53379
53698
  let idArray = ic.afChainIndexHash[index].split('_');
@@ -53398,9 +53717,10 @@ class ChainalignParser {
53398
53717
  let urlalign = me.htmlCls.baseUrl + "vastdyn/vastdyn.cgi";
53399
53718
  let urltmalign = me.htmlCls.baseUrl + "tmalign/tmalign.cgi";
53400
53719
 
53401
- let resRangeArray = (me.cfg.resrange) ? me.cfg.resrange.split(',') : [];
53720
+ let resRangeArray = (me.cfg.resrange) ? decodeURIComponent(me.cfg.resrange).split(' | ') : [];
53402
53721
 
53403
53722
  // dynamically align pairs in all chainids
53723
+ // the resrange from VASTSrv or VAST search uses NCBI residue numbers!!!
53404
53724
  let atomSet_t = (me.cfg.resrange) ? ic.realignParserCls.getSeqCoorResid([resRangeArray[0]], chainidArray[0], true).hAtoms : ic.chains[chainidArray[0]];
53405
53725
  for(let index = 1, indexl = chainidArray.length; index < indexl; ++index) {
53406
53726
  let atomSet_q = (me.cfg.resrange) ? ic.realignParserCls.getSeqCoorResid([resRangeArray[index]], chainidArray[index], true).hAtoms : ic.chains[chainidArray[index]];
@@ -53575,7 +53895,8 @@ class ChainalignParser {
53575
53895
  if(!bFoundAlignment) {
53576
53896
  // sometimes VAST align works for the reversed pair
53577
53897
  if(!bReverse) {
53578
- ic.realignParserCls.realignOnStructAlign(true);
53898
+ let bVastsearch = true;
53899
+ ic.realignParserCls.realignOnStructAlign(true, bVastsearch);
53579
53900
  return;
53580
53901
  }
53581
53902
  else {
@@ -54331,7 +54652,8 @@ class ChainalignParser {
54331
54652
  // await ic.realignParserCls.realignChainOnSeqAlign(undefined, ic.chainidArray, bRealign, bPredefined);
54332
54653
 
54333
54654
  ic.hAtoms = ic.definedSetsCls.getAtomsFromNameArray(ic.chainidArray);
54334
- await ic.realignParserCls.realignOnStructAlign();
54655
+ let bVastsearch = true;
54656
+ await ic.realignParserCls.realignOnStructAlign(undefined, bVastsearch);
54335
54657
 
54336
54658
  // reset annotations
54337
54659
  $("#" + ic.pre + "dl_annotations").html("");
@@ -58567,76 +58889,114 @@ class RealignParser {
58567
58889
  await this.realignChainOnSeqAlign(undefined, chainidArray, bRealign);
58568
58890
  }
58569
58891
 
58570
- async realignOnStructAlign(bReverse) { let ic = this.icn3d, me = ic.icn3dui;
58892
+ async realignOnStructAlign(bReverse, bVastsearch) { let ic = this.icn3d, me = ic.icn3dui;
58571
58893
  // each 3D domain should have at least 3 secondary structures
58572
58894
  let minSseCnt = (me.cfg.aligntool != 'tmalign') ? 3 : 0;
58573
58895
 
58574
- let struct2domain = {};
58575
- for(let struct in ic.structures) {
58576
- struct2domain[struct] = {};
58577
- let chainidArray = ic.structures[struct];
58578
- for(let i = 0, il = chainidArray.length; i < il; ++i) {
58579
- let chainid = chainidArray[i];
58580
- let atoms = me.hashUtilsCls.intHash(ic.hAtoms, ic.chains[chainid]);
58581
- let sseCnt = 0;
58582
- for(let serial in atoms) {
58583
- if(ic.atoms[serial].ssbegin) ++sseCnt;
58584
- if(sseCnt > minSseCnt) {
58585
- struct2domain[struct][chainid] = atoms;
58586
- break;
58587
- }
58588
- }
58589
- }
58590
- }
58896
+ /*
58897
+ let resRangeArray = (me.cfg.resrange) ? decodeURIComponent(me.cfg.resrange).split(' | ') : [];
58591
58898
 
58899
+ let atomSet_t = (me.cfg.resrange) ? ic.realignParserCls.getSeqCoorResid([resRangeArray[0]], ic.chainidArray[0], true).hAtoms : ic.chains[chainidArray[0]];
58900
+ for(let index = 1, indexl = chainidArray.length; index < indexl; ++index) {
58901
+ let atomSet_q = (me.cfg.resrange) ? ic.realignParserCls.getSeqCoorResid([resRangeArray[index]], ic.chainidArray[index], true).hAtoms : ic.chains[chainidArray[index]];
58902
+ // end of new version to be done for VASTsrv ==============
58903
+ */
58592
58904
  let ajaxArray = [], chainidPairArray = [];
58593
58905
  let urlalign = me.htmlCls.baseUrl + "vastdyn/vastdyn.cgi";
58594
58906
  let urltmalign = me.htmlCls.baseUrl + "tmalign/tmalign.cgi";
58595
58907
 
58596
- //let cnt = 0;
58597
- let structArray = Object.keys(struct2domain);
58598
- if(bReverse) structArray = structArray.reverse();
58908
+ let struct2domain = {};
58909
+ if(bVastsearch && me.cfg.resrange) {
58910
+ let resRangeArray = decodeURIComponent(me.cfg.resrange).split(' | ');
58599
58911
 
58600
- for(let s = 0, sl = structArray.length; s < sl; ++s) {
58601
- let struct1 = structArray[s];
58912
+ let atomSet_t = ic.realignParserCls.getSeqCoorResid([resRangeArray[0]], ic.chainidArray[0], true).hAtoms;
58913
+ for(let index = 1, indexl = ic.chainidArray.length; index < indexl; ++index) {
58914
+ let atomSet_q = ic.realignParserCls.getSeqCoorResid([resRangeArray[index]], ic.chainidArray[index], true).hAtoms;
58602
58915
 
58603
- let chainidArray1 = Object.keys(struct2domain[struct1]);
58604
- if(chainidArray1.length == 0) continue;
58916
+ let alignAjax;
58917
+ if(me.cfg.aligntool != 'tmalign') {
58918
+ let jsonStr_q = ic.domain3dCls.getDomainJsonForAlign(atomSet_q);
58919
+ let jsonStr_t = ic.domain3dCls.getDomainJsonForAlign(atomSet_t);
58920
+
58921
+ let dataObj = {'domains1': jsonStr_q, 'domains2': jsonStr_t};
58922
+ alignAjax = me.getAjaxPostPromise(urlalign, dataObj);
58923
+ }
58924
+ else {
58925
+ let pdb_query = ic.saveFileCls.getAtomPDB(atomSet_q);
58926
+ let pdb_target= ic.saveFileCls.getAtomPDB(atomSet_t);
58605
58927
 
58606
- for(let i = 0, il = chainidArray1.length; i < il; ++i) {
58607
- let chainid1 = chainidArray1[i];
58608
- let jsonStr_t = ic.domain3dCls.getDomainJsonForAlign(struct2domain[struct1][chainid1]);
58928
+ let dataObj = {'pdb_query': pdb_query, 'pdb_target': pdb_target};
58929
+ alignAjax = me.getAjaxPostPromise(urltmalign, dataObj);
58930
+ }
58609
58931
 
58610
- for(let t = s+1, tl = structArray.length; t < tl; ++t) {
58611
- let struct2 = structArray[t];
58932
+ ajaxArray.push(alignAjax);
58933
+
58934
+ chainidPairArray.push(ic.chainidArray[0] + ',' + ic.chainidArray[index]);
58935
+ }
58936
+ }
58937
+ else {
58938
+ for(let struct in ic.structures) {
58939
+ struct2domain[struct] = {};
58940
+ let chainidArray = ic.structures[struct];
58941
+ for(let i = 0, il = chainidArray.length; i < il; ++i) {
58942
+ let chainid = chainidArray[i];
58943
+ let atoms = me.hashUtilsCls.intHash(ic.hAtoms, ic.chains[chainid]);
58944
+ let sseCnt = 0;
58945
+ for(let serial in atoms) {
58946
+ if(ic.atoms[serial].ssbegin) ++sseCnt;
58947
+ if(sseCnt > minSseCnt) {
58948
+ struct2domain[struct][chainid] = atoms;
58949
+ break;
58950
+ }
58951
+ }
58952
+ }
58953
+ }
58612
58954
 
58613
- let chainidArray2 = Object.keys(struct2domain[struct2]);
58614
- if(chainidArray2.length == 0) continue;
58955
+ //let cnt = 0;
58956
+ let structArray = Object.keys(struct2domain);
58957
+ if(bReverse) structArray = structArray.reverse();
58615
58958
 
58616
- for(let j = 0, jl = chainidArray2.length; j < jl; ++j) {
58617
- let chainid2 = chainidArray2[j];
58959
+ for(let s = 0, sl = structArray.length; s < sl; ++s) {
58960
+ let struct1 = structArray[s];
58618
58961
 
58619
- let alignAjax;
58620
- if(me.cfg.aligntool != 'tmalign') {
58621
- let jsonStr_q = ic.domain3dCls.getDomainJsonForAlign(struct2domain[struct2][chainid2]);
58622
-
58623
- let dataObj = {'domains1': jsonStr_q, 'domains2': jsonStr_t};
58624
- alignAjax = me.getAjaxPostPromise(urlalign, dataObj);
58625
- }
58626
- else {
58627
- let pdb_target = ic.saveFileCls.getAtomPDB(struct2domain[struct1][chainid1], undefined, undefined, undefined, undefined, struct1);
58628
- let pdb_query = ic.saveFileCls.getAtomPDB(struct2domain[struct2][chainid2], undefined, undefined, undefined, undefined, struct2);
58629
-
58630
- // let pdb_target = ic.saveFileCls.getAtomPDB(ic.chains[chainid1], undefined, undefined, undefined, undefined, struct1);
58631
- // let pdb_query = ic.saveFileCls.getAtomPDB(ic.chains[chainid2], undefined, undefined, undefined, undefined, struct2);
58962
+ let chainidArray1 = Object.keys(struct2domain[struct1]);
58963
+ if(chainidArray1.length == 0) continue;
58964
+
58965
+ for(let i = 0, il = chainidArray1.length; i < il; ++i) {
58966
+ let chainid1 = chainidArray1[i];
58967
+ let jsonStr_t = ic.domain3dCls.getDomainJsonForAlign(struct2domain[struct1][chainid1]);
58968
+
58969
+ for(let t = s+1, tl = structArray.length; t < tl; ++t) {
58970
+ let struct2 = structArray[t];
58971
+
58972
+ let chainidArray2 = Object.keys(struct2domain[struct2]);
58973
+ if(chainidArray2.length == 0) continue;
58974
+
58975
+ for(let j = 0, jl = chainidArray2.length; j < jl; ++j) {
58976
+ let chainid2 = chainidArray2[j];
58977
+
58978
+ let alignAjax;
58979
+ if(me.cfg.aligntool != 'tmalign') {
58980
+ let jsonStr_q = ic.domain3dCls.getDomainJsonForAlign(struct2domain[struct2][chainid2]);
58981
+
58982
+ let dataObj = {'domains1': jsonStr_q, 'domains2': jsonStr_t};
58983
+ alignAjax = me.getAjaxPostPromise(urlalign, dataObj);
58984
+ }
58985
+ else {
58986
+ let pdb_target = ic.saveFileCls.getAtomPDB(struct2domain[struct1][chainid1], undefined, undefined, undefined, undefined, struct1);
58987
+ let pdb_query = ic.saveFileCls.getAtomPDB(struct2domain[struct2][chainid2], undefined, undefined, undefined, undefined, struct2);
58632
58988
 
58633
- let dataObj = {'pdb_query': pdb_query, 'pdb_target': pdb_target};
58634
- alignAjax = me.getAjaxPostPromise(urltmalign, dataObj);
58635
- }
58989
+ // let pdb_target = ic.saveFileCls.getAtomPDB(ic.chains[chainid1], undefined, undefined, undefined, undefined, struct1);
58990
+ // let pdb_query = ic.saveFileCls.getAtomPDB(ic.chains[chainid2], undefined, undefined, undefined, undefined, struct2);
58991
+
58992
+ let dataObj = {'pdb_query': pdb_query, 'pdb_target': pdb_target};
58993
+ alignAjax = me.getAjaxPostPromise(urltmalign, dataObj);
58994
+ }
58636
58995
 
58637
- ajaxArray.push(alignAjax);
58638
- chainidPairArray.push(chainid1 + ',' + chainid2);
58639
- //++cnt;
58996
+ ajaxArray.push(alignAjax);
58997
+ chainidPairArray.push(chainid1 + ',' + chainid2);
58998
+ //++cnt;
58999
+ }
58640
59000
  }
58641
59001
  }
58642
59002
  }
@@ -58752,7 +59112,7 @@ class RealignParser {
58752
59112
  let predefinedResArray, predefinedResPair;
58753
59113
 
58754
59114
  if(bPredefined) {
58755
- predefinedResArray = me.cfg.resdef.trim().replace(/\+/gi, ' ').split(': ');
59115
+ predefinedResArray = decodeURIComponent(me.cfg.resdef).trim().replace(/\+/gi, ' ').split(': ');
58756
59116
 
58757
59117
  if(predefinedResArray.length != chainidArray.length - 1) {
58758
59118
  var aaa = 1; //alert("Please make sure the number of chains and the lines of predefined residues are the same...");
@@ -58941,7 +59301,7 @@ class RealignParser {
58941
59301
  }
58942
59302
  }
58943
59303
 
58944
- getSeqCoorResid(resiArray, chainid, bNCBI) { let ic = this.icn3d, me = ic.icn3dui;
59304
+ getSeqCoorResid(resiArray, chainid, bNCBIResi) { let ic = this.icn3d, me = ic.icn3dui;
58945
59305
  let seq = '', coorArray = [], residArray = [];
58946
59306
  let hAtoms = {};
58947
59307
 
@@ -58949,16 +59309,17 @@ class RealignParser {
58949
59309
  if(resiArray[j].indexOf('-') != -1) {
58950
59310
  let startEnd = resiArray[j].split('-');
58951
59311
  for(let k = parseInt(startEnd[0]); k <= parseInt(startEnd[1]); ++k) {
58952
- let seqIndex = (bNCBI) ? k : ic.setSeqAlignCls.getPosFromResi(chainid, k);
59312
+ let seqIndex = (bNCBIResi) ? k : ic.setSeqAlignCls.getPosFromResi(chainid, k);
58953
59313
 
58954
59314
  // don't align solvent or chemicals
58955
59315
  if(!ic.chainsSeq[chainid] || !ic.chainsSeq[chainid][seqIndex] || me.parasCls.b62ResArray.indexOf(ic.chainsSeq[chainid][seqIndex].name.toUpperCase()) == -1) continue;
58956
59316
 
58957
59317
  seq += ic.chainsSeq[chainid][seqIndex].name.toUpperCase();
58958
59318
 
58959
- coorArray = coorArray.concat(this.getResCoorArray(chainid + '_' + k));
59319
+ let resid = (bNCBIResi) ? ic.ncbi2resid[chainid + '_' + k] : chainid + '_' + k;
59320
+ coorArray = coorArray.concat(this.getResCoorArray(resid));
58960
59321
 
58961
- residArray.push(chainid + '_' + k);
59322
+ residArray.push(resid);
58962
59323
  }
58963
59324
  }
58964
59325
  else if(resiArray[j] == 0) { // 0 means the whole chain
@@ -58968,18 +59329,19 @@ class RealignParser {
58968
59329
  else { // one residue
58969
59330
  let k = resiArray[j];
58970
59331
 
58971
- let seqIndex = (bNCBI) ? k : ic.setSeqAlignCls.getPosFromResi(chainid, k);
59332
+ let seqIndex = (bNCBIResi) ? k : ic.setSeqAlignCls.getPosFromResi(chainid, k);
58972
59333
 
58973
59334
  if(!ic.chainsSeq[chainid][seqIndex]) continue;
58974
59335
 
58975
- let resCoorArray = this.getResCoorArray(chainid + '_' + k);
59336
+ let resid = (bNCBIResi) ? ic.ncbi2resid[chainid + '_' + k] : chainid + '_' + k;
59337
+ let resCoorArray = this.getResCoorArray(resid);
58976
59338
  //if(resCoorArray.length == 1 && resCoorArray[0] === undefined) continue;
58977
59339
 
58978
59340
  seq += ic.chainsSeq[chainid][seqIndex].name.toUpperCase();
58979
59341
 
58980
59342
  coorArray = coorArray.concat(resCoorArray);
58981
59343
 
58982
- residArray.push(chainid + '_' + k);
59344
+ residArray.push(resid);
58983
59345
  }
58984
59346
  }
58985
59347
 
@@ -63228,6 +63590,9 @@ class LoadPDB {
63228
63590
 
63229
63591
  ///id = line.substr(62, 4).trim();
63230
63592
  id = line.substr(62).trim();
63593
+ // remove "_" in the id
63594
+ id = id.replace(/_/g, '-');
63595
+
63231
63596
  oriId = id;
63232
63597
 
63233
63598
  if(id == '') {
@@ -63243,7 +63608,9 @@ class LoadPDB {
63243
63608
  structure = this.getStructureId(id, moleculeNum, bMutation, bNMR);
63244
63609
 
63245
63610
  ic.molTitle = '';
63246
- ic.molTitleHash = {};
63611
+ if (ic.allData === undefined) {
63612
+ ic.molTitleHash = {};
63613
+ }
63247
63614
 
63248
63615
  bHeader = true; // read the first header if there are multiple
63249
63616
  } else if (record === 'TITLE ') {
@@ -64136,6 +64503,8 @@ class LoadCIF {
64136
64503
 
64137
64504
  if(block.getCategory("_entry")) {
64138
64505
  id = block.getCategory("_entry").getColumn("id").getString(0);
64506
+ // remove "_" in the id
64507
+ id = id.replace(/_/g, '-');
64139
64508
 
64140
64509
  if(id == '') {
64141
64510
  if(bAppend) {
@@ -68267,15 +68636,15 @@ class SelectCollections {
68267
68636
  }
68268
68637
 
68269
68638
  //Set the menu of defined sets with an array of defined names "commandnameArray".
68270
- setAtomMenu(nameArray, titleArray) {
68639
+ setAtomMenu(nameArray) {
68271
68640
  let ic = this.icn3d;
68272
68641
  ic.icn3dui;
68273
68642
  let html = "";
68274
- let commandnameArray = [nameArray[0]];
68275
68643
  //for(let i in ic.defNames2Atoms) {
68276
68644
  for (let i = 0, il = nameArray.length; i < il; ++i) {
68277
- let name = nameArray[i];
68278
- let title = titleArray[i];
68645
+ let name = nameArray[i][0];
68646
+ let title = nameArray[i][1];
68647
+ let description = nameArray[i][2];
68279
68648
 
68280
68649
  let atomHash;
68281
68650
  if (
@@ -68298,16 +68667,11 @@ class SelectCollections {
68298
68667
  }
68299
68668
  }
68300
68669
 
68301
- if (commandnameArray.indexOf(name) != -1) {
68302
- html +=
68303
- "<option value='" +
68304
- name +
68305
- "' selected='selected'>" +
68306
- title +
68307
- "</option>";
68308
- } else {
68309
- html += "<option value='" + name + "'>" + title + "</option>";
68310
- }
68670
+ if (i == 0) {
68671
+ html += "<option value='" + nameArray[0][0] + "' selected='selected' data-description='" + description + "'>" + title + "</option>";
68672
+ } else {
68673
+ html += "<option value='" + name + "' data-description='" + description + "'>" + title + "</option>";
68674
+ }
68311
68675
  }
68312
68676
 
68313
68677
  return html;
@@ -68348,49 +68712,33 @@ class SelectCollections {
68348
68712
  }
68349
68713
 
68350
68714
  return difference;
68351
- }
68715
+ }
68352
68716
 
68353
- clickStructure() {
68717
+ clickStructure(collection) {
68354
68718
  let ic = this.icn3d,
68355
68719
  me = ic.icn3dui;
68356
68720
  let thisClass = this;
68357
68721
 
68358
- if (ic.allData == undefined) {
68359
- ic.allData = {};
68360
- ic.allData['all'] = {
68361
- 'atoms': {},
68362
- 'proteins': {},
68363
- 'nucleotides': {},
68364
- 'chemicals': {},
68365
- 'ions': {},
68366
- 'water': {},
68367
- 'structures': {},
68368
- 'ssbondpnts': {},
68369
- 'residues': {},
68370
- 'chains': {},
68371
- 'chainsSeq': {}, //Sequences and Annotation
68372
- 'defNames2Atoms': {},
68373
- 'defNames2Residues': {}
68374
- };
68375
- ic.allData['prev'] = {};
68376
- }
68377
-
68378
68722
  //me.myEventCls.onIds("#" + ic.pre + "atomsCustom", "change", function(e) { let ic = thisClass.icn3d;
68379
- $("#" + ic.pre + "collections_menu").change(async function (e) {
68723
+ $("#" + ic.pre + "collections_menu").on("change", async function (e) {
68380
68724
  let ic = thisClass.icn3d;
68381
68725
 
68382
68726
  let nameArray = $(this).val();
68383
68727
  let nameStructure = $(this).find("option:selected").text();
68728
+ let selectedIndices = Array.from(this.selectedOptions).map(option => option.index);
68729
+ let selectedIndicesMap = nameArray.reduce((map, name, i) => {
68730
+ map[name] = selectedIndices[i];
68731
+ return map;
68732
+ }, {});
68384
68733
 
68385
68734
  ic.nameArray = nameArray;
68386
- if (nameArray !== null) {
68387
- // let chainIdHash = {};
68388
68735
 
68736
+ if (nameArray !== null) {
68389
68737
  let bNoDuplicate = true;
68390
68738
  thisClass.reset();
68391
68739
  for (const name of nameArray) {
68392
68740
  if (!(name in ic.allData)) {
68393
- ic.allData['prev'] = JSON.parse(JSON.stringify(ic.allData['all']));//me.hashUtilsCls.cloneHash(ic.allData['all']);
68741
+ ic.allData['prev'] = JSON.parse(JSON.stringify(ic.allData['all']));
68394
68742
 
68395
68743
  ic.atoms = ic.allData['all']['atoms'];
68396
68744
 
@@ -68407,7 +68755,21 @@ class SelectCollections {
68407
68755
  ic.chainsSeq = ic.allData['all']['chainsSeq'];
68408
68756
  ic.defalls2Atoms = ic.allData['all']['defalls2Atoms'];
68409
68757
  ic.defalls2Residues = ic.allData['all']['defalls2Residues'];
68410
- await ic.chainalignParserCls.downloadMmdbAf(name, undefined, undefined, bNoDuplicate).then(() => {
68758
+
68759
+ async function loadStructure(pdb) {
68760
+ await ic.resetConfig();
68761
+ if (pdb) {
68762
+ let bAppend = true;
68763
+ if (Object.keys(ic.structures).length == 0) {
68764
+ bAppend = false;
68765
+ }
68766
+ await ic.pdbParserCls.loadPdbData(ic.pdbCollection[selectedIndicesMap[name]].join('\n'), undefined, undefined, bAppend);
68767
+ } else {
68768
+ await ic.chainalignParserCls.downloadMmdbAf(name, undefined, undefined, bNoDuplicate);
68769
+ }
68770
+ }
68771
+
68772
+ await loadStructure(collection[selectedIndicesMap[name]][4]).then(() => {
68411
68773
  ic.allData['all'] = {
68412
68774
  'atoms': ic.atoms,
68413
68775
  'proteins': ic.proteins,
@@ -68415,9 +68777,9 @@ class SelectCollections {
68415
68777
  'chemicals': ic.chemicals,
68416
68778
  'ions': ic.ions,
68417
68779
  'water': ic.water,
68418
- 'structures': ic.structures,
68780
+ 'structures': ic.structures, // getSSExpandedAtoms
68419
68781
  'ssbondpnts': ic.ssbondpnts,
68420
- 'residues': ic.residues,
68782
+ 'residues': ic.residues, // getSSExpandedAtoms
68421
68783
  'chains': ic.chains,
68422
68784
  'chainsSeq': ic.chainsSeq, //Sequences and Annotation
68423
68785
  'defNames2Atoms': ic.defNames2Atoms,
@@ -68425,26 +68787,27 @@ class SelectCollections {
68425
68787
  };
68426
68788
 
68427
68789
  ic.allData[name] = {
68790
+ 'title': ic.molTitle,
68428
68791
  'atoms': thisClass.dictionaryDifference(ic.allData['prev']['atoms'], ic.atoms),
68429
68792
  'proteins': thisClass.dictionaryDifference(ic.allData['prev']['proteins'], ic.proteins),
68430
68793
  'nucleotides': thisClass.dictionaryDifference(ic.allData['prev']['nucleotides'], ic.nucleotides),
68431
68794
  'chemicals': thisClass.dictionaryDifference(ic.allData['prev']['chemicals'], ic.chemicals),
68432
68795
  'ions': thisClass.dictionaryDifference(ic.allData['prev']['ions'], ic.ions),
68433
68796
  'water': thisClass.dictionaryDifference(ic.allData['prev']['water'], ic.water),
68434
- 'structures': thisClass.dictionaryDifference(ic.allData['prev']['structures'], ic.structures),
68797
+ 'structures': thisClass.dictionaryDifference(ic.allData['prev']['structures'], ic.structures), // getSSExpandedAtoms
68435
68798
  'ssbondpnts': thisClass.dictionaryDifference(ic.allData['prev']['ssbondpnts'], ic.ssbondpnts),
68436
- 'residues': thisClass.dictionaryDifference(ic.allData['prev']['residues'], ic.residues),
68799
+ 'residues': thisClass.dictionaryDifference(ic.allData['prev']['residues'], ic.residues), // getSSExpandedAtoms
68437
68800
  'chains': thisClass.dictionaryDifference(ic.allData['prev']['chains'], ic.chains),
68438
68801
  'chainsSeq': thisClass.dictionaryDifference(ic.allData['prev']['chainsSeq'], ic.chainsSeq), //Sequences and Annotation
68439
68802
  'defNames2Atoms': thisClass.dictionaryDifference(ic.allData['prev']['defNames2Atoms'], ic.defNames2Atoms),
68440
68803
  'defNames2Residues': thisClass.dictionaryDifference(ic.allData['prev']['defNames2Residues'], ic.defNames2Residues)
68441
68804
  };
68442
68805
 
68443
- // ic.atoms = Object.assign(ic.atoms, ic.atomsTemp);
68444
68806
  thisClass.reset();
68445
68807
  });
68446
68808
  }
68447
68809
  }
68810
+
68448
68811
  for (const name of nameArray) {
68449
68812
  ic.atoms = Object.assign(ic.atoms, ic.allData[name]['atoms']);
68450
68813
 
@@ -68463,10 +68826,26 @@ class SelectCollections {
68463
68826
  ic.defNames2Residues = Object.assign(ic.defNames2Residues, ic.allData[name]['defNames2Residues']);
68464
68827
  ic.dAtoms = me.hashUtilsCls.cloneHash(ic.atoms);
68465
68828
  ic.hAtoms = me.hashUtilsCls.cloneHash(ic.atoms);
68466
- }
68829
+
68830
+ ic.molTitle = ic.allData[name]['title'];
68467
68831
 
68832
+ if (collection[selectedIndicesMap[name]][3] !== undefined && collection[selectedIndicesMap[name]][3].length > 0) {
68833
+ if (ic.allData[name]['commands'] == undefined) {
68834
+ let commands = collection[selectedIndicesMap[name]][3];
68835
+ ic.allData[name]['commands'] = commands;
68836
+ }
68837
+ }
68838
+
68839
+ if (ic.allData[name]['commands'] !== undefined) {
68840
+ for (const command of ic.allData[name]['commands']) {
68841
+ me.htmlCls.clickMenuCls.setLogCmd(command, true);
68842
+ await ic.applyCommandCls.applyCommand(command);
68843
+ }
68844
+ }
68845
+
68846
+ }
68847
+
68468
68848
  ic.opts["color"] = (Object.keys(ic.structures).length == 1) ? "chain" : "structure";
68469
- // ic.setStyleCls.setAtomStyleByOptions();
68470
68849
  ic.setColorCls.setColorByOptions(ic.opts, ic.atoms);
68471
68850
 
68472
68851
  ic.transformCls.zoominSelection();
@@ -68480,14 +68859,12 @@ class SelectCollections {
68480
68859
  // show selected chains in annotation window
68481
68860
  ic.annotationCls.showAnnoSelectedChains();
68482
68861
  }
68483
-
68862
+
68484
68863
  await ic.drawCls.draw();
68485
68864
  ic.saveFileCls.showTitle();
68486
68865
 
68487
- me.htmlCls.clickMenuCls.setLogCmd(
68488
- "select structure " + "[" + nameStructure + "]",
68489
- true
68490
- );
68866
+ me.htmlCls.clickMenuCls.setLogCmd("select structure " + "[" + nameStructure + "]", false);
68867
+ me.htmlCls.clickMenuCls.setLogCmd('load mmdbaf1 ' + nameArray, true);
68491
68868
  }
68492
68869
  });
68493
68870
 
@@ -69399,7 +69776,7 @@ class LoadScript {
69399
69776
  if(steps === 1
69400
69777
  || (ic.hAtoms && ic.atoms && Object.keys(ic.hAtoms).length === Object.keys(ic.atoms).length)
69401
69778
  || (ic.optsHistory[steps - 1] !== undefined && ic.optsHistory[steps - 1].hasOwnProperty('hlatomcount') && ic.optsHistory[steps - 1].hlatomcount === Object.keys(ic.atoms).length) ) {
69402
- // the following code caused problem for many links,e.g., https://structure.ncbi.nlm.nih.gov/icn3d/share.html?17g3r1JDvZ7ZL39e6
69779
+ // the following code caused problem for many links,e.g., https://www.ncbi.nlm.nih.gov/Structure/icn3d/share.html?17g3r1JDvZ7ZL39e6
69403
69780
  // if(steps === 1) {
69404
69781
  // assign styles and color using the options at that stage
69405
69782
  // ic.setStyleCls.setAtomStyleByOptions(ic.optsHistory[steps - 1]);
@@ -69421,7 +69798,7 @@ class LoadScript {
69421
69798
  ic.pk = 3;
69422
69799
  }
69423
69800
 
69424
- // the following code caused problem for many links,e.g., https://structure.ncbi.nlm.nih.gov/icn3d/share.html?17g3r1JDvZ7ZL39e6
69801
+ // the following code caused problem for many links,e.g., https://www.ncbi.nlm.nih.gov/Structure/icn3d/share.html?17g3r1JDvZ7ZL39e6
69425
69802
  // if(steps === 1) {
69426
69803
  // ic.setColorCls.applyOriginalColor();
69427
69804
  // }
@@ -70487,6 +70864,10 @@ class Selection {
70487
70864
  selectOneResid(idStr, bUnchecked) {var ic = this.icn3d; ic.icn3dui;
70488
70865
  //var idStr = idArray[i]; // TYR $1KQ2.B:56@OH, $1KQ2.B:40 ASP
70489
70866
  //change to: let idStr = idArray[i]; // TYR $1KQ2.B:56@OH, or ASP $1KQ2.B:40
70867
+ //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
70868
+ let idArray = idStr.split(' ');
70869
+ idStr = idArray[1];
70870
+
70490
70871
  let posStructure = idStr.indexOf('$');
70491
70872
  let posChain = idStr.indexOf('.');
70492
70873
  let posRes = idStr.indexOf(':');
@@ -71846,7 +72227,6 @@ class Dssp {
71846
72227
  if(ssHash !== undefined && JSON.stringify(ssHash).indexOf('Oops there was a problem') === -1) {
71847
72228
  for(let chainNum in ic.chainsSeq) {
71848
72229
  let pos = chainNum.indexOf('_');
71849
-
71850
72230
  // one structure at a time
71851
72231
  if(chainNum.substr(0, pos) != struArray[index]) continue;
71852
72232
 
@@ -79058,6 +79438,11 @@ class SaveFile {
79058
79438
 
79059
79439
  $("#" + ic.pre + "title").html("PubChem CID <a id='" + ic.pre + "titlelink' href='" + url + "' style='color:" + titlelinkColor + "' target='_blank'>" + ic.inputid.toUpperCase() + "</a>: " + title);
79060
79440
  }
79441
+ else if(me.cfg.smiles !== undefined) {
79442
+ let text = decodeURIComponent(me.cfg.smiles);
79443
+ if(text.length > 60) text = text.substr(0, 60) + "...";
79444
+ $("#" + ic.pre + "title").html("SMILES: " + text);
79445
+ }
79061
79446
  else if(me.cfg.align !== undefined) {
79062
79447
  title = 'VAST+ alignment of ' + Object.keys(ic.structures);
79063
79448
 
@@ -79299,7 +79684,7 @@ class ShareLink {
79299
79684
  let shortName = strArray[strArray.length - 1];
79300
79685
  ic.saveFileCls.saveFile(inputid + '-' + shortName + '.png', 'png');
79301
79686
  let text = '<div style="float:left; border: solid 1px #0000ff; padding: 5px; margin: 10px; text-align:center;">';
79302
- text += '<a href="https://structure.ncbi.nlm.nih.gov/icn3d/share.html?' + shortName + '" target="_blank">';
79687
+ text += '<a href="https://www.ncbi.nlm.nih.gov/Structure/icn3d/share.html?' + shortName + '" target="_blank">';
79303
79688
  text += '<img style="height:300px" src ="' + inputid + '-' + shortName + '.png"><br>\n';
79304
79689
  text += '<!--Start of your comments==================-->\n';
79305
79690
  let yournote =(ic.yournote) ? ': ' + ic.yournote.replace(/\n/g, "<br>").replace(/; /g, ", ") : '';
@@ -79318,9 +79703,9 @@ class ShareLink {
79318
79703
  //shorturl: https://icn3d.page.link/NvbAh1Vmiwc4bgX87
79319
79704
  let urlArray = shorturl.split('page.link/');
79320
79705
  //if(urlArray.length == 2) shorturl = me.htmlCls.baseUrl + 'icn3d/share.html?' + urlArray[1];
79321
- // When the baseURL is structure.ncbi.nlm.nih.gov, mmcifparser.cgi has a problem to past posted data in Mac/iphone
79706
+ // When the baseURL is structure.ncbi.nlm.nih.gov, mmcifparser.cgi has a problem to pass posted data in Mac/iphone
79322
79707
  // So the base URL is still www.ncbi.nlm.nih.gov/Structure,just use short URL here
79323
- if(urlArray.length == 2) shorturl = 'https://structure.ncbi.nlm.nih.gov/icn3d/share.html?' + urlArray[1];
79708
+ if(urlArray.length == 2) shorturl = 'https://www.ncbi.nlm.nih.gov/Structure/icn3d/share.html?' + urlArray[1];
79324
79709
 
79325
79710
  $("#" + ic.pre + "short_url").val(shorturl);
79326
79711
  $("#" + ic.pre + "short_url_title").val(shorturl + '&t=' + ic.yournote);
@@ -82477,7 +82862,7 @@ class iCn3DUI {
82477
82862
  //even when multiple iCn3D viewers are shown together.
82478
82863
  this.pre = this.cfg.divid + "_";
82479
82864
 
82480
- this.REVISION = '3.38.1';
82865
+ this.REVISION = '3.39.0';
82481
82866
 
82482
82867
  // In nodejs, iCn3D defines "window = {navigator: {}}"
82483
82868
  this.bNode = (Object.keys(window).length < 2) ? true : false;
@@ -82652,6 +83037,9 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
82652
83037
 
82653
83038
  await ic.pdbParserCls.loadPdbData(pdbStr);
82654
83039
 
83040
+ // // use NCBI residue numbers if using VAST
83041
+ // me.icn3d.bUsePdbNum = 0;
83042
+
82655
83043
  if(me.cfg.resdef !== undefined && me.cfg.chains !== undefined) {
82656
83044
  let structureArray = Object.keys(ic.structures);
82657
83045
  let chainArray = me.cfg.chains.split(' | ');
@@ -82927,7 +83315,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
82927
83315
 
82928
83316
  ic.bChainAlign = true;
82929
83317
  ic.inputid = me.cfg.chainalign;
82930
- let resrangeStr = (me.cfg.resrange) ? ' | resrange ' + me.cfg.resrange : '';
83318
+ let resrangeStr = (me.cfg.resrange) ? ' | resrange ' + decodeURIComponent(me.cfg.resrange) : '';
82931
83319
  let resdef = (me.cfg.resdef) ? me.cfg.resdef : '';
82932
83320
  ic.loadCmd = 'load chainalignment ' + me.cfg.chainalign + ' | resnum ' + me.cfg.resnum + ' | resdef ' + resdef + ' | aligntool ' + me.cfg.aligntool + ' | parameters ' + me.cfg.inpara + resrangeStr;
82933
83321
  me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);