@datagrok/helm 2.0.2 → 2.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/package.ts CHANGED
@@ -2,45 +2,45 @@
2
2
  import * as grok from 'datagrok-api/grok';
3
3
  import * as ui from 'datagrok-api/ui';
4
4
  import * as DG from 'datagrok-api/dg';
5
- //import {lru} from '../../Bio/src/utils/cell-renderer';
6
- import {NotationConverter} from '@datagrok-libraries/bio/src/utils/notation-converter';
7
- import {NOTATION} from '@datagrok-libraries/bio/src/utils/units-handler';
8
- import {WebLogo} from '@datagrok-libraries/bio/src/viewers/web-logo';
5
+ import * as bio from '@datagrok-libraries/bio';
6
+
9
7
  import {createJsonMonomerLibFromSdf} from './utils';
10
8
  import {MONOMER_MANAGER_MAP, RGROUPS, RGROUP_CAP_GROUP_NAME, RGROUP_LABEL, SMILES} from './constants';
11
- //import {ConverterFunc, DfReaderFunc} from '../../Bio/src/tests/types';
9
+ import {delay} from '@datagrok-libraries/utils/src/test';
12
10
 
13
11
  export const _package = new DG.Package();
14
12
 
15
- const lru = new DG.LruCache<any, any>();
16
13
  const STORAGE_NAME = 'Libraries';
17
- let i = 0;
18
14
  const LIB_PATH = 'libraries/';
19
15
 
20
16
 
21
17
  //tags: init
22
18
  export async function initHelm(): Promise<void> {
23
- let grid = grok.shell.tv.grid;
24
- for (let j = 0; j <= i; j++) {
25
- await monomerManager(await grok.dapi.userDataStorage.getValue(STORAGE_NAME, j.toString(), true));
26
- }
27
- grid.invalidate();
19
+ return new Promise(async (resolve, reject) => {
20
+ // @ts-ignore
21
+ dojo.ready(function() { resolve(null); });
22
+ await loadLibraries();
23
+ });
28
24
  }
29
25
 
30
- //name: initHelp
31
- export function initHelp() {
32
- return;
26
+ async function loadLibraries() {
27
+ let uploadedLibraries: string[] = Object.values(await grok.dapi.userDataStorage.get(STORAGE_NAME, true));
28
+ for (let i = 0; i < uploadedLibraries.length; ++i) {
29
+ await monomerManager(await grok.dapi.userDataStorage.getValue(STORAGE_NAME, uploadedLibraries[i], true));
30
+ }
33
31
  }
34
32
 
35
- //name: getLru
36
- export async function getLru() {
37
- return await grok.functions.call('Bio:Lru');
33
+ //name: helmCellRenderer
34
+ //tags: cellRenderer
35
+ //meta.cellType: helm
36
+ //meta.columnTags: units=helm
37
+ //output: grid_cell_renderer result
38
+ export function helmCellRenderer(): HelmCellRenderer {
39
+ return new HelmCellRenderer();
38
40
  }
39
41
 
40
- //tags: cellEditor
41
- //description: Macromolecule
42
- //input: grid_cell cell
43
- export function editMoleculeCell(cell: DG.GridCell): void {
42
+
43
+ function webEditor(cell?: DG.GridCell, value?: string) {
44
44
  let view = ui.div();
45
45
  org.helm.webeditor.MolViewer.molscale = 0.8;
46
46
  let app = new scil.helm.App(view, {
@@ -65,101 +65,106 @@ export function editMoleculeCell(cell: DG.GridCell): void {
65
65
  scil.apply(app.properties.parent.style, s);
66
66
  app.structureview.resize(sizes.rightwidth, sizes.bottomheight + app.toolbarheight);
67
67
  app.mex.resize(sizes.topheight - 80);
68
- if (cell.gridColumn.column.tags[DG.TAGS.UNITS] === 'HELM') {
69
- setTimeout(function() {
68
+ setTimeout(function() {
69
+ if (typeof cell !== 'undefined') {
70
70
  app.canvas.helm.setSequence(cell.cell.value, 'HELM');
71
- }, 200);
72
- //@ts-ignore
73
- ui.dialog({showHeader: false, showFooter: true})
74
- .add(view)
75
- .onOK(() => {
76
- const val = app.canvas.getHelm(true).replace(/<\/span>/g, '').replace(/<span style='background:#bbf;'>/g, '');
77
- cell.cell.value = val;
78
- }).show({modal: true, fullScreen: true});
79
- } else if (cell.gridColumn.column.tags[DG.TAGS.UNITS] === 'fasta:SEQ:PT') {
80
- const converter = new NotationConverter(cell.gridColumn.column);
81
- const resStr = converter.convertStringToHelm(cell.cell.value, '-');
82
- setTimeout(function() {
83
- app.canvas.helm.setSequence(resStr, 'HELM');
84
- }, 200);
85
- //@ts-ignore
86
- ui.dialog({showHeader: false, showFooter: true})
87
- .add(view)
88
- .onOK(() => {
89
- cell.cell.value;
90
- }).show({modal: true, fullScreen: true});
71
+ } else {
72
+ app.canvas.helm.setSequence(value, 'HELM');
73
+ }
74
+ }, 200);
75
+ //@ts-ignore
76
+ ui.dialog({showHeader: false, showFooter: true})
77
+ .add(view)
78
+ .onOK(() => {
79
+ if (typeof cell !== 'undefined') {
80
+ cell.cell.value = app.canvas.getHelm(true).replace(/<\/span>/g, '').replace(/<span style='background:#bbf;'>/g, '');
81
+ }
82
+ }).show({modal: true, fullScreen: true});
83
+ }
84
+
85
+
86
+ //tags: cellEditor
87
+ //description: Macromolecule
88
+ //input: grid_cell cell
89
+ export function editMoleculeCell(cell: DG.GridCell): void {
90
+ if (cell.gridColumn.column.tags[DG.TAGS.UNITS] === 'helm') {
91
+ webEditor(cell);
91
92
  }
92
93
  }
93
94
 
94
- //name: Details
95
+ //name: Open Helm Web Editor
96
+ //description: Adds editor
97
+ //meta.action: Open Helm Web Editor
98
+ //input: string mol { semType: Macromolecule }
99
+ export function openEditor(mol: string): void {
100
+ let df = grok.shell.tv.grid.dataFrame;
101
+ let converter = new bio.NotationConverter(df.columns.bySemType('Macromolecule'));
102
+ const resStr = converter.convertStringToHelm(mol, '/');
103
+ webEditor(undefined, resStr);
104
+ }
105
+
106
+ //name: Properties
95
107
  //tags: panel, widgets
96
108
  //input: string helmString {semType: Macromolecule}
97
109
  //output: widget result
98
- export async function detailsPanel(helmString: string) {
99
- const lru = await getLru();
100
- const result = lru.get(helmString).split(',');
110
+ export async function propertiesPanel(helmString: string) {
111
+ let grid = grok.shell.tv.grid;
112
+ let parent = grid.root.parentElement;
113
+ const host = ui.div([]);
114
+ parent.appendChild(host);
115
+ let editor = new JSDraw2.Editor(host, {viewonly: true});
116
+ host.style.width = '0px';
117
+ host.style.height = '0px';
118
+ editor.setHelm(helmString);
119
+ let formula = editor.getFormula(true);
120
+ let molWeight = Math.round(editor.getMolWeight() * 100) / 100;
121
+ let coef = Math.round(editor.getExtinctionCoefficient(true) * 100) / 100;
122
+ parent.lastChild.remove();
101
123
  return new DG.Widget(
102
124
  ui.tableFromMap({
103
- 'formula': result[0].replace(/<sub>/g, '').replace(/<\/sub>/g, ''),
104
- 'molecular weight': result[1],
105
- 'extinction coefficient': result[2],
106
- 'molfile': result[3],
107
- 'fasta': ui.wait(async () => ui.divText(await helmToFasta(helmString))),
108
- 'rna analogue sequence': ui.wait(async () => ui.divText(await helmToRNA(helmString))),
109
- 'smiles': ui.wait(async () => ui.divText(await helmToSmiles(helmString))),
110
- //'peptide analogue sequence': ui.wait(async () => ui.divText(await helmToPeptide(helmString))),
125
+ 'formula': formula.replace(/<sub>/g, '').replace(/<\/sub>/g, ''),
126
+ 'molecular weight': molWeight,
127
+ 'extinction coefficient': coef,
111
128
  })
112
129
  );
113
130
  }
114
131
 
115
132
 
116
- async function loadDialog() {
117
- let res = (await _package.files.list(`${LIB_PATH}`, false, '')).map(it => it.fileName);
118
- let FilesList = await ui.choiceInput('Monomer Libraries', ' ', res);
119
- let grid = grok.shell.tv.grid;
120
- ui.dialog('Load library from file')
121
- .add(FilesList)
122
- .onOK(async () => {
123
- await monomerManager(FilesList.value);
124
- grok.dapi.userDataStorage.postValue(STORAGE_NAME, i.toString(), FilesList.value, true);
125
- i += 1;
126
- grid.invalidate();
127
- }).show();
128
- };
129
-
130
133
  //name: Manage Libraries
131
134
  //tags: panel, widgets
132
135
  //input: column helmColumn {semType: Macromolecule}
133
136
  //output: widget result
134
- export async function libraryPanel(helmColumn: DG.Column) {
137
+ export async function libraryPanel(helmColumn: DG.Column): Promise<DG.Widget> {
135
138
  //@ts-ignore
136
- let loadButton = ui.button('Load Library');
137
- loadButton.addEventListener('click', loadDialog);
138
- //@ts-ignore
139
- let filesButton = ui.button('Manage');
140
- filesButton.addEventListener('click', manageFiles);
141
- let list = (await _package.files.list(`${LIB_PATH}`, false, '')).map(it => it.fileName);
142
- let usedLibraries = [];
143
- for (let j = 0; j <= i; j++) {
144
- usedLibraries.push(await grok.dapi.userDataStorage.getValue(STORAGE_NAME, j.toString(), true));
139
+ let filesButton: HTMLButtonElement = ui.button('Manage', manageFiles);
140
+ let divInputs: HTMLDivElement = ui.div();
141
+ let librariesList: string[] = (await _package.files.list(`${LIB_PATH}`, false, '')).map(it => it.fileName);
142
+ let uploadedLibraries: string[] = Object.values(await grok.dapi.userDataStorage.get(STORAGE_NAME, true));
143
+ for (let i = 0; i < uploadedLibraries.length; ++i) {
144
+ let libraryName: string = uploadedLibraries[i];
145
+ divInputs.append(ui.boolInput(libraryName, true, async v => {
146
+ org.helm.webeditor.Monomers.clear();
147
+ grok.dapi.userDataStorage.remove(STORAGE_NAME, libraryName, true);
148
+ await loadLibraries();
149
+ grok.shell.tv.grid.invalidate();
150
+ }).root);
151
+ }
152
+ let unusedLibraries: string[] = librariesList.filter(x => !uploadedLibraries.includes(x));
153
+ for (let i = 0; i < unusedLibraries.length; ++i) {
154
+ let libraryName: string = unusedLibraries[i];
155
+ divInputs.append(ui.boolInput(libraryName, false, v => {
156
+ monomerManager(libraryName);
157
+ grok.dapi.userDataStorage.postValue(STORAGE_NAME, libraryName, libraryName, true);
158
+ }).root);
145
159
  }
146
- let unusedLibraries = list.filter(x => !usedLibraries.includes(x));
147
160
  return new DG.Widget(ui.splitV([
148
- ui.splitH([
149
- ui.tableFromMap({
150
- 'Uploaded libraries': ui.divText(usedLibraries.toString()),
151
- 'Not used libraries': ui.divText(unusedLibraries.toString()),
152
- })
153
- ]),
154
- ui.splitH([
155
- ui.divH([loadButton]),
156
- ui.divH([filesButton]),
157
- ])
161
+ divInputs,
162
+ ui.divV([filesButton])
158
163
  ]));
159
164
  }
160
165
 
161
166
  //name: manageFiles
162
- function manageFiles() {
167
+ export async function manageFiles() {
163
168
  const a = ui.dialog({title: 'Manage files'})
164
169
  //@ts-ignore
165
170
  .add(ui.fileBrowser({path: 'System:AppData/Helm/libraries'}).root)
@@ -167,6 +172,7 @@ function manageFiles() {
167
172
  .show();
168
173
  }
169
174
 
175
+
170
176
  async function accessServer(url: string, key: string) {
171
177
  const params: RequestInit = {
172
178
  method: 'GET',
@@ -238,12 +244,22 @@ function getRS(smiles: string) {
238
244
  return res;
239
245
  }
240
246
 
241
- async function monomerManager(value: string) {
247
+ //name: monomerManager
248
+ //input: string value
249
+ export async function monomerManager(value: string) {
242
250
  let df: any[];
251
+ let file;
252
+ let dfSdf;
243
253
  if (value.endsWith('.sdf')) {
244
- const file = await _package.files.readAsBytes(`${LIB_PATH}${value}`);
245
- const dfSdf = await grok.functions.call('Chem:importSdf', {bytes: file});
246
- df = createJsonMonomerLibFromSdf(dfSdf[0]);
254
+ const funcList: DG.Func[] = DG.Func.find({package: 'Chem', name: 'importSdf'});
255
+ console.debug(`Helm: initHelm() funcList.length = ${funcList.length}`);
256
+ if (funcList.length === 1) {
257
+ file = await _package.files.readAsBytes(`${LIB_PATH}${value}`);
258
+ dfSdf = await grok.functions.call('Chem:importSdf', {bytes: file});
259
+ df = createJsonMonomerLibFromSdf(dfSdf[0]);
260
+ } else {
261
+ grok.shell.warning('Chem package is not installed');
262
+ }
247
263
  } else {
248
264
  const file = await _package.files.readAsText(`${LIB_PATH}${value}`);
249
265
  df = JSON.parse(file);
@@ -267,6 +283,8 @@ async function monomerManager(value: string) {
267
283
  }
268
284
  org.helm.webeditor.Monomers.addOneMonomer(m);
269
285
  });
286
+ let grid: DG.Grid = grok.shell.tv.grid;
287
+ grid.invalidate();
270
288
  }
271
289
 
272
290
  //name: helmColumnToSmiles
@@ -275,48 +293,290 @@ export function helmColumnToSmiles(helmColumn: DG.Column) {
275
293
  //todo: add column with smiles to col.dataFrame.
276
294
  }
277
295
 
296
+
297
+ function split(s: string, sep: string) {
298
+ var ret = [];
299
+ var frag = '';
300
+ var parentheses = 0;
301
+ var bracket = 0;
302
+ var braces = 0;
303
+ var quote = 0;
304
+ for (var i = 0; i < s.length; ++i) {
305
+ var c = s.substring(i, i + 1);
306
+ if (c == sep && bracket == 0 && parentheses == 0 && braces == 0 && quote == 0) {
307
+ ret.push(frag);
308
+ frag = '';
309
+ } else {
310
+ frag += c;
311
+ if (quote > 0) {
312
+ if (c == '\\' && i + 1 < s.length) {
313
+ ++i;
314
+ var c2 = s.substring(i, i + 1);
315
+ frag += c2;
316
+ c += c2;
317
+ }
318
+ }
319
+ if (c == '\"') {
320
+ if (!(i > 0 && s.substring(i - 1, i) == '\\'))
321
+ quote = quote == 0 ? 1 : 0;
322
+ } else if (c == '[')
323
+ ++bracket;
324
+ else if (c == ']')
325
+ --bracket;
326
+ else if (c == '(')
327
+ ++parentheses;
328
+ else if (c == ')')
329
+ --parentheses;
330
+ else if (c == '{')
331
+ ++braces;
332
+ else if (c == '}')
333
+ --braces;
334
+ }
335
+ }
336
+ ret.push(frag);
337
+ return ret;
338
+ }
339
+
340
+ function detachAnnotation(s: string) {
341
+ var ret = _detachAppendix(s, '\"');
342
+ if (ret.tag != null)
343
+ return ret;
344
+
345
+ var r = _detachAppendix(s, '\'');
346
+ return {tag: ret.tag, repeat: r.tag, str: r.str};
347
+ }
348
+
349
+ function _detachAppendix(s: string, c: string) {
350
+ var tag = null;
351
+ //@ts-ignore
352
+ if (scil.Utils.endswith(s, c)) {
353
+ var p = s.length - 1;
354
+ while (p > 0) {
355
+ p = s.lastIndexOf(c, p - 1);
356
+ if (p <= 0 || s.substring(p - 1, p) != '\\')
357
+ break;
358
+ }
359
+
360
+ if (p > 0 && p < s.length - 1) {
361
+ tag = s.substring(p + 1, s.length - 1);
362
+ s = s.substring(0, p);
363
+ }
364
+ }
365
+ if (tag != null)
366
+ tag = tag.replace(new RegExp('\\' + c, 'g'), c);
367
+ return {tag: unescape(tag), str: s};
368
+ }
369
+
370
+ function unescape(s: string) {
371
+ //@ts-ignore
372
+ if (scil.Utils.isNullOrEmpty(s))
373
+ return s;
374
+
375
+ return s.replace(/[\\]./g, function(m) {
376
+ switch (m) {
377
+ case '\\r':
378
+ return '\r';
379
+ case '\\n':
380
+ return '\n';
381
+ case '\\t':
382
+ return '\t';
383
+ default:
384
+ return m.substring(1);
385
+ }
386
+ });
387
+ }
388
+
389
+ //name: parseHelm
390
+ //input: string s
391
+ export function parseHelm(s: string) {
392
+ var sections = split(s, '$');
393
+ s = sections[0];
394
+ var monomers = [];
395
+ //@ts-ignore
396
+ if (!scil.Utils.isNullOrEmpty(s)) {
397
+ var seqs = split(s, '|');
398
+ for (var i = 0; i < seqs.length; ++i) {
399
+ var e = detachAnnotation(seqs[i]);
400
+ s = e.str;
401
+
402
+ var p = s.indexOf('{');
403
+
404
+ s = s.substring(p + 1);
405
+ p = s.indexOf('}');
406
+ s = s.substring(0, p);
407
+
408
+ var ss = split(s, '.');
409
+ for (var monomer of ss) {
410
+ if (monomer.includes('(') && monomer.includes(')')) {
411
+ var elements = monomer.replace(/[()]/g, '').split('');
412
+ for (var el of elements) {
413
+ monomers.push(el);
414
+ }
415
+ } else if (monomer.includes('[') && monomer.includes(']')) {
416
+ var element = monomer.match(/(?<=\[).*?(?=\])/g, '');
417
+ monomers.push(element[0]);
418
+ } else {
419
+ monomers.push(monomer);
420
+ }
421
+ }
422
+ }
423
+ }
424
+ return monomers;
425
+ }
426
+
278
427
  //name: findMonomers
279
- //input: string helmString { semType: Macromolecule }
280
- export async function findMonomers(helmString: string) {
428
+ //input: string helmString
429
+ export function findMonomers(helmString: string) {
430
+ //@ts-ignore
281
431
  const types = Object.keys(org.helm.webeditor.monomerTypeList());
282
- const monomers = [];
283
- const monomerNames = [];
284
- for (let i = 0; i < types.length; i++) {
285
- // Synonym to overcome eslint error
286
- const GetMonomerSet = scil.helm.Monomers.getMonomerSet;
287
- monomers.push(new GetMonomerSet(types[i]));
288
- Object.keys(monomers[i]).forEach((k) => {
289
- monomerNames.push(monomers[i][k].id);
432
+ const monomers: any = [];
433
+ const monomer_names: any = [];
434
+ for (var i = 0; i < types.length; i++) {
435
+ //@ts-ignore
436
+ monomers.push(new scil.helm.Monomers.getMonomerSet(types[i]));
437
+ Object.keys(monomers[i]).forEach(k => {
438
+ monomer_names.push(monomers[i][k].id);
290
439
  });
291
440
  }
292
- const splitString = WebLogo.splitterAsHelm(helmString);
293
- return new Set(splitString.filter((val) => !monomerNames.includes(val)));
441
+ const split_string = parseHelm(helmString);
442
+ return new Set(split_string.filter(val => !monomer_names.includes(val)));
443
+ }
444
+
445
+ //name: getMolfiles
446
+ //input: column col {semType: Macromolecule}
447
+ //output: column res
448
+ export function getMolfiles(col: DG.Column): DG.Column {
449
+ let grid = grok.shell.tv.grid;
450
+ let parent = grid.root.parentElement;
451
+ let res = DG.Column.string('mols', col.length);
452
+ const host = ui.div([]);
453
+ parent.appendChild(host);
454
+ let editor = new JSDraw2.Editor(host, {viewonly: true});
455
+ host.style.width = '0px';
456
+ host.style.height = '0px';
457
+ res.init((i) => {
458
+ editor.setHelm(col.get(i));
459
+ let mol = editor.getMolfile();
460
+ return mol;
461
+ });
462
+ parent.lastChild.remove();
463
+ return res;
464
+ }
465
+
466
+ function getParts(subParts: string[], s: string): string[] {
467
+ let j = 0;
468
+ let allParts: string[] = [];
469
+ for (let k = 0; k < subParts.length; ++k) {
470
+ let indexOfMonomer = s.indexOf(subParts[k]);
471
+ let helmBeforeMonomer = s.slice(j, indexOfMonomer);
472
+ allParts.push(helmBeforeMonomer);
473
+ allParts.push(subParts[k]);
474
+ s = s.substring(indexOfMonomer + subParts[k].length);
475
+ }
476
+ allParts.push(s);
477
+ return allParts;
294
478
  }
295
479
 
296
480
  class HelmCellRenderer extends DG.GridCellRenderer {
297
- get name() { return 'macromolecule'; }
481
+ get name() { return 'helm'; }
298
482
 
299
- get cellType() { return 'macromolecule'; }
483
+ get cellType() { return 'helm'; }
300
484
 
301
485
  get defaultWidth(): number | null { return 400; }
302
486
 
303
487
  get defaultHeight(): number | null { return 100; }
304
488
 
489
+ onMouseMove(gridCell: DG.GridCell, e: MouseEvent): void {
490
+ const maxLengthWordsSum = gridCell.cell.column.temp['helm-sum-maxLengthWords'];
491
+ const maxIndex = Object.values(gridCell.cell.column.temp['helm-maxLengthWords']).length - 1;
492
+ const argsX = e.offsetX - gridCell.gridColumn.left + (gridCell.gridColumn.left - gridCell.bounds.x);
493
+ let left = 0;
494
+ let right = maxIndex;
495
+ let found = false;
496
+ maxLengthWordsSum[maxIndex + 1] = argsX + 1;
497
+ let mid = 0;
498
+ if (argsX > maxLengthWordsSum[0]) {
499
+ while (!found) {
500
+ mid = Math.floor((right + left) / 2);
501
+ if (argsX >= maxLengthWordsSum[mid] && argsX <= maxLengthWordsSum[mid + 1]) {
502
+ left = mid;
503
+ found = true;
504
+ } else if (argsX < maxLengthWordsSum[mid]) {
505
+ right = mid - 1;
506
+ } else if (argsX > maxLengthWordsSum[mid + 1]) {
507
+ left = mid + 1;
508
+ }
509
+ if (left == right) {
510
+ found = true;
511
+ }
512
+ }
513
+ }
514
+ left = (argsX >= maxLengthWordsSum[left]) ? left + 1 : left;
515
+ const monomers = findMonomers(gridCell.cell.value);
516
+ let s: string = gridCell.cell.value ?? '';
517
+ let subParts: string[] = parseHelm(s);
518
+ let allParts: string[] = getParts(subParts, s);
519
+ let tooltipMessage: HTMLElement[] = [];
520
+ for (let i = 0; i < allParts.length; ++i) {
521
+ if (monomers.has(allParts[i]))
522
+ tooltipMessage[i] = ui.divV([
523
+ ui.divText(`Monomer ${allParts[i]} not found.`),
524
+ ui.divText('Open the Property Panel, then expand Manage Libraries')
525
+ ]);
526
+ }
527
+ (((tooltipMessage[left]?.childNodes.length ?? 0) > 0))
528
+ ? ui.tooltip.show(ui.div(tooltipMessage[left]), e.x + 16, e.y + 16)
529
+ : ui.tooltip.hide();
530
+ }
531
+
305
532
  render(g: CanvasRenderingContext2D, x: number, y: number, w: number, h: number,
306
533
  gridCell: DG.GridCell, cellStyle: DG.GridCellStyle
307
534
  ) {
308
- const host = ui.div([], {style: {width: `${w}px`, height: `${h}px`}});
309
- host.setAttribute('dataformat', 'helm');
310
- host.setAttribute('data', gridCell.cell.value);
311
-
312
- gridCell.element = host;
313
- const canvas = new JSDraw2.Editor(host, {width: w, height: h, skin: 'w8', viewonly: true});
314
- const formula = canvas.getFormula(true);
315
- const molWeight = Math.round(canvas.getMolWeight() * 100) / 100;
316
- const coef = Math.round(canvas.getExtinctionCoefficient(true) * 100) / 100;
317
- const molfile = canvas.getMolfile();
318
- const result = formula + ', ' + molWeight + ', ' + coef + ', ' + molfile;
319
- lru.set(gridCell.cell.value, result);
535
+ const grid = gridCell.gridRow !== -1 ? gridCell.grid : undefined;
536
+ const undefinedColor = 'rgb(100,100,100)';
537
+ const grayColor = '#808080';
538
+ const monomers = findMonomers(gridCell.cell.value);
539
+ let s: string = gridCell.cell.value ?? '';
540
+ let subParts: string[] = parseHelm(s);
541
+ if (monomers.size == 0) {
542
+ const host = ui.div([], {style: {width: `${w}px`, height: `${h}px`}});
543
+ host.setAttribute('dataformat', 'helm');
544
+ host.setAttribute('data', gridCell.cell.value);
545
+ gridCell.element = host;
546
+ //@ts-ignore
547
+ const canvas = new JSDraw2.Editor(host, {width: w, height: h, skin: 'w8', viewonly: true});
548
+ return;
549
+ }
550
+ if (monomers.size > 0) {
551
+ w = grid ? Math.min(grid.canvas.width - x, w) : g.canvas.width - x;
552
+ g.save();
553
+ g.beginPath();
554
+ g.rect(x, y, w, h);
555
+ g.clip();
556
+ g.font = '12px monospace';
557
+ g.textBaseline = 'top';
558
+ let x1 = x;
559
+ let maxLengthWords: any = {};
560
+ let maxLengthWordSum: any = {};
561
+ let allParts: string[] = getParts(subParts, s);
562
+ for (let i = 0; i < allParts.length; ++i) {
563
+ maxLengthWords[i] = allParts[i].length * 7;
564
+ let color = monomers.has(allParts[i]) ? 'red' : grayColor;
565
+ g.fillStyle = undefinedColor;
566
+ x1 = bio.printLeftOrCentered(x1, y, w, h, g, allParts[i], color, 0, true, 1.0);
567
+ }
568
+
569
+ maxLengthWordSum[0] = maxLengthWords[0];
570
+ for (let i = 1; i < allParts.length; i++) {
571
+ maxLengthWordSum[i] = maxLengthWordSum[i - 1] + maxLengthWords[i];
572
+ }
573
+ gridCell.cell.column.temp = {
574
+ 'helm-sum-maxLengthWords': maxLengthWordSum,
575
+ 'helm-maxLengthWords': maxLengthWords
576
+ };
577
+ g.restore();
578
+ return;
579
+ }
320
580
  }
321
581
  }
322
582
 
@@ -1,13 +1,13 @@
1
- import {before, category, expect, test} from '@datagrok-libraries/utils/src/test';
2
- import {helmToFasta, helmToPeptide, helmToRNA} from '../package';
1
+ import {after, before, category, delay, expect, test} from '@datagrok-libraries/utils/src/test';
2
+ //import {findMonomers, helmToFasta, helmToPeptide, helmToRNA, initHelm} from '../package';
3
3
  import {_package} from '../package-test';
4
+ import {manageFiles, parseHelm} from '../package';
4
5
  import * as DG from 'datagrok-api/dg';
5
6
  import * as grok from 'datagrok-api/grok';
6
7
 
7
8
 
8
9
  category('Helm', () => {
9
-
10
- // These tests require webservice that is not present on test stand
10
+ //These tests require webservice that is not present on test stand
11
11
  // test('helmToFasta', async () => {
12
12
  // expect(await helmToFasta('RNA1{R(U)P.R(T)P.R(G)P.R(C)P.R(A)}$$$$'), '>RNA1UTGCA');
13
13
  // expect(await helmToFasta('RNA1{P.R(U).P.R(T)}$$$$'), '>RNA1UT');
@@ -45,4 +45,50 @@ category('Helm', () => {
45
45
  // await grok.data.detectSemanticTypes(df);
46
46
  // expect(col.tags[DG.TAGS.UNITS], 'HELM');
47
47
  // });
48
+
49
+ test('manageFiles', async () => {
50
+ return await manageFiles();
51
+ });
52
+
53
+
54
+ test('monomerManager', async() => {
55
+ const df: DG.DataFrame = DG.DataFrame.fromCsv(await _package.files.readAsText('tests/test.csv'));
56
+ grok.shell.addTableView(df);
57
+ await grok.functions.call('Helm:monomerManager', {value: 'HELMCoreLibrary.json'});
58
+ const checkName = '2-Chloroadenine';
59
+ let flag = false;
60
+ const types = Object.keys(org.helm.webeditor.monomerTypeList());
61
+ const monomers: any = [];
62
+ for (var i = 0; i < types.length; i++) {
63
+ //@ts-ignore
64
+ monomers.push(new scil.helm.Monomers.getMonomerSet(types[i]));
65
+ Object.keys(monomers[i]).forEach(k => {
66
+ if (monomers[i][k].n == checkName){
67
+ flag = true;
68
+ }
69
+ });
70
+ }
71
+ expect(flag, true);
72
+ });
73
+
74
+ test('parseHelm', async() => {
75
+ const expectedResults = [
76
+ ['meI', 'hHis', 'Aca', 'N', 'T', 'dK', 'Thr_PO3H2', 'D-Tyr_Et', 'Aze', 'dV', 'E', 'Phe_4Me'],
77
+ ['A', 'C', 'T', 'G', 'W', 'E', 'Q'],
78
+ ['R', 'U', 'P', 'T', 'A'],
79
+ ['A', '*', 'G', 'C']
80
+ ];
81
+ const helmStrings = [
82
+ 'PEPTIDE1{meI.hHis.Aca.N.T.dK.Thr_PO3H2.Aca.D-Tyr_Et.Aze.dV.E.N.dV.Phe_4Me}$$$',
83
+ 'PEPTIDE1{A.C.T.G.C.T.W.G.T.W.E.C.W.C.Q.W}|PEPTIDE2{A.C.T.G.C.T.W.G.T.W.E.Q}$PEPTIDE1,PEPTIDE1,5:R3-14:R3|PEPTIDE2,PEPTIDE1,2:R3-12:R3$$$',
84
+ 'RNA1{R(U)P.R(T)P}|RNA2{P.R(A)P.R(A)}$RNA1,RNA2,2:pair-6:pair|RNA1,RNA2,5:pair-3:pair$$$',
85
+ 'PEPTIDE1{A.*.G.C}$$$$V2.0'
86
+ ];
87
+ for (let idx = 0; idx < helmStrings.length; ++idx) {
88
+ let monomerSet = new Set(parseHelm(helmStrings[idx]));
89
+ let monomerArray = Array.from(monomerSet);
90
+ expect(JSON.stringify(monomerArray), JSON.stringify(expectedResults[idx]));
91
+ }
92
+ });
93
+
48
94
  });